]> andersk Git - moira.git/blob - server/mr_scall.c
Use moira_schema.h
[moira.git] / server / mr_scall.c
1 /* $Id$
2  *
3  * Do RPC
4  *
5  * Copyright (C) 1987-1998 by the Massachusetts Institute of Technology
6  * For copying and distribution information, please see the file
7  * <mit-copyright.h>.
8  *
9  */
10
11 #include <mit-copyright.h>
12 #include "mr_server.h"
13 #include "query.h"
14
15 #include <sys/stat.h>
16 #include <sys/types.h>
17
18 #include <arpa/inet.h>
19 #include <netinet/in.h>
20
21 #include <errno.h>
22 #include <fcntl.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <unistd.h>
26
27 RCSID("$Header$");
28
29 extern int nclients;
30 extern client **clients;
31 extern char *whoami;
32
33 extern int dbms_errno, mr_errcode;
34
35 void do_call(client *cl);
36 void free_rtn_tuples(client *cp);
37 int retr_callback(int argc, char **argv, void *p_cl);
38 int list_users(client *cl);
39 void do_retr(client *cl, mr_params req);
40 void do_access(client *cl, mr_params req);
41 void get_motd(client *cl);
42
43 /* Put this in a variable so that we can patch it if necessary */
44 int max_row_count = 4096;
45
46 char *procnames[] = {
47   "noop",
48   "auth",
49   "shutdown",
50   "query",
51   "access",
52   "dcm",
53   "motd",
54 };
55
56 int newqueries;
57
58 void client_read(client *cl)
59 {
60   mr_params req;
61   int status, pn;
62
63   status = mr_receive(cl->con, &req);
64   if (status != MR_SUCCESS)
65     {
66       cl->done = 1;
67       if (status != MR_NOT_CONNECTED)
68         com_err(whoami, status, "while reading from socket");
69       return;
70     }
71
72   pn = req.u.mr_procno;
73   if (pn < 0 || pn > MR_MAX_PROC)
74     {
75       com_err(whoami, 0, "procno out of range");
76       client_reply(cl, MR_UNKNOWN_PROC);
77       mr_destroy_reply(req);
78       return;
79     }
80   log_args(procnames[pn], 2, req.mr_argc, req.mr_argv);
81
82   if (dormant == ASLEEP && pn != MR_NOOP && pn != MR_MOTD)
83     {
84       client_reply(cl, MR_DOWN);
85       com_err(whoami, MR_DOWN, "(query refused)");
86       mr_destroy_reply(req);
87       return;
88     }
89
90   /* make sure this gets cleared before every operation */
91   dbms_errno = 0;
92
93   switch (pn)
94     {
95     case MR_NOOP:
96       client_reply(cl, MR_SUCCESS);
97       break;
98
99     case MR_AUTH:
100       do_auth(cl, req);
101       break;
102
103     case MR_QUERY:
104       do_retr(cl, req);
105       break;
106
107     case MR_ACCESS:
108       do_access(cl, req);
109       break;
110
111     case MR_SHUTDOWN:
112       do_shutdown(cl);
113       break;
114
115     case MR_DO_UPDATE:
116       client_reply(cl, MR_PERM);
117       break;
118
119     case MR_MOTD:
120       get_motd(cl);
121       break;
122     }
123   mr_destroy_reply(req);
124 }
125
126 /* Set the final return status for a query. We always keep one more
127    free slot in cl->tuples[] than we're using so that this can't fail */
128 void client_reply(client *cl, long status)
129 {
130   cl->tuples[cl->ntuples].u.mr_status = status;
131   cl->tuples[cl->ntuples].mr_argc = 0;
132   cl->tuples[cl->ntuples].mr_argl = NULL;
133   cl->tuples[cl->ntuples].mr_argv = NULL;
134   cl->ntuples++;
135 }
136
137 void client_return_tuple(client *cl, int argc, char **argv)
138 {
139   if (cl->done || dbms_errno)
140     return;
141
142   if (cl->ntuples == max_row_count)
143     {
144       dbms_errno = mr_errcode = MR_NO_MEM;
145       return;
146     }
147
148   if (cl->ntuples == cl->tuplessize - 1)
149     {
150       int newsize = (cl->tuplessize + 4) * 2;
151       mr_params *newtuples;
152
153       newtuples = realloc(cl->tuples, newsize * sizeof(mr_params));
154       if (!newtuples)
155         {
156           free_rtn_tuples(cl);
157           dbms_errno = mr_errcode = MR_NO_MEM;
158           return;
159         }
160       cl->tuplessize = newsize;
161       cl->tuples = newtuples;
162     }
163
164   cl->tuples[cl->ntuples].u.mr_status = MR_MORE_DATA;
165   cl->tuples[cl->ntuples].mr_argc = argc;
166   cl->tuples[cl->ntuples].mr_argl = NULL;
167   cl->tuples[cl->ntuples].mr_argv = mr_copy_args(argv, argc);
168   cl->ntuples++;
169 }
170
171 void client_write(client *cl)
172 {
173   int status;
174
175   status = mr_send(cl->con, &cl->tuples[cl->nexttuple]);
176   if (status)
177     {
178       com_err(whoami, status, "writing to socket");
179       cl->done = 1;
180     }
181   else
182     {
183       cl->nexttuple++;
184       if (cl->nexttuple == cl->ntuples)
185         free_rtn_tuples(cl);
186     }
187 }
188
189 void free_rtn_tuples(client *cl)
190 {
191   for (cl->ntuples--; cl->ntuples >= 0; cl->ntuples--)
192     free_argv(cl->tuples[cl->ntuples].mr_argv,
193               cl->tuples[cl->ntuples].mr_argc);
194   free(cl->tuples);
195
196   cl->tuples = xmalloc(sizeof(mr_params));
197   cl->tuplessize = 1;
198   cl->ntuples = cl->nexttuple = 0;
199 }
200
201 void do_retr(client *cl, mr_params req)
202 {
203   char *queryname;
204   int status;
205
206   if (req.mr_argc < 1)
207     {
208       client_reply(cl, MR_ARGS);
209       com_err(whoami, MR_ARGS, "got nameless query");
210       return;
211     }
212   queryname = req.mr_argv[0];
213   newqueries++;
214
215   if (!strcmp(queryname, "_list_users"))
216     status = list_users(cl);
217   else
218     status = mr_process_query(cl, queryname, req.mr_argc - 1, req.mr_argv + 1,
219                               retr_callback, cl);
220
221   client_reply(cl, status);
222
223   if (cl->ntuples >= max_row_count)
224     {
225       critical_alert("moirad", "attempted query %s with too many rows\n",
226                      queryname);
227     }
228
229   com_err(whoami, 0, "Query complete.");
230 }
231
232 int retr_callback(int argc, char **argv, void *p_cl)
233 {
234   client *cl = p_cl;
235
236   mr_trim_args(argc, argv);
237   client_return_tuple(cl, argc, argv);
238 }
239
240 void do_access(client *cl, mr_params req)
241 {
242   int status;
243
244   if (req.mr_argc < 1)
245     {
246       client_reply(cl, MR_ARGS);
247       com_err(whoami, MR_ARGS, "got nameless access");
248       return;
249     }
250
251   status = mr_check_access(cl, req.mr_argv[0], req. mr_argc - 1,
252                            req.mr_argv + 1);
253   client_reply(cl, status);
254
255   com_err(whoami, 0, "Access check complete.");
256 }
257
258 void get_motd(client *cl)
259 {
260   int motd;
261   char *buffer;
262   struct stat statb;
263
264   if (stat(MOIRA_MOTD_FILE, &statb) == -1)
265     {
266       client_reply(cl, MR_SUCCESS);
267       return;
268     }
269   
270   buffer = malloc(statb.st_size + 1);
271   if (!buffer)
272     {
273       client_reply(cl, MR_NO_MEM);
274       return;
275     }
276
277   motd = open(MOIRA_MOTD_FILE, 0, O_RDONLY);
278   if (motd)
279     {
280       read(motd, buffer, statb.st_size);
281       close(motd);
282       buffer[statb.st_size] = '\0';
283       client_return_tuple(cl, 1, &buffer);
284       client_reply(cl, MR_SUCCESS);
285     }
286   else
287     client_reply(cl, errno);
288
289   free(buffer);
290 }
291
292 int list_users(client *cl)
293 {
294   char *argv[5];
295   char buf[30];
296   char buf1[30];
297   int i;
298   char *cp;
299
300   for (i = 0; i < nclients; i++)
301     {
302       client *c = clients[i];
303       argv[0] = c->clname;
304       argv[1] = inet_ntoa(c->haddr.sin_addr);
305       argv[2] = buf;
306       sprintf(buf, "port %d", ntohs(c->haddr.sin_port));
307       argv[3] = ctime(&c->last_time_used);
308       cp = strchr(argv[3], '\n');
309       if (cp)
310         *cp = '\0';
311       argv[4] = buf1;
312       sprintf(buf1, "[#%d]", c->id);
313       client_return_tuple(cl, 5, argv);
314     }
315   return MR_SUCCESS;
316 }
317
This page took 1.11405 seconds and 5 git commands to generate.