]> andersk Git - moira.git/blob - server/mr_scall.c
second code style cleanup: void/void * usage, proper #includes. try to
[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 char buf1[];
30 extern int nclients;
31 extern char *whoami;
32
33 extern int dbms_errno, mr_errcode;
34 static int row_count;
35
36 void do_call(client *cl);
37 void free_rtn_tuples(client *cp);
38 int retr_callback(int argc, char **argv, void *p_cp);
39 int list_users(int (*callbk)(int, char **, void *), char *callarg);
40 void do_retr(client *cl);
41 void do_access(client *cl);
42 void get_motd(client *cl);
43
44 /* Put this in a variable so that we can patch it if necessary */
45 int max_row_count = 4096;
46
47 /*
48  * Welcome to the (finite state) machine (highest level).
49  */
50 void do_client(client *cp)
51 {
52   struct stat stbuf;
53
54   free_rtn_tuples(cp);
55   if (OP_STATUS(cp->pending_op) == OP_CANCELLED)
56     {
57       com_err(whoami, 0,
58               "Closed connection (now %d client%s, %d new queries, %d old)",
59               nclients - 1, nclients != 2 ? "s" : "", newqueries, oldqueries);
60       clist_delete(cp);
61       /* if we no longer have any clients, and we're supposed to
62        * go down, then go down now.
63        */
64       if ((dormant == AWAKE) && (nclients == 0) &&
65           (stat(MOIRA_MOTD_FILE, &stbuf) == 0))
66         {
67           com_err(whoami, 0, "motd file exists, slumbertime");
68           dormant = SLEEPY;
69         }
70       return;
71     }
72   switch (cp->action)
73     {
74     case CL_ACCEPT:
75     case CL_SEND:
76       /* Start recieving next request */
77       initialize_operation(cp->pending_op, mr_start_recv,
78                            (char *)&cp->args, NULL);
79       queue_operation(cp->con, CON_INPUT, cp->pending_op);
80       cp->action = CL_RECEIVE;
81       break;
82     case CL_RECEIVE:
83       /* Data is here. Process it & start it heading back */
84       do_call(cp); /* This may block for a while. */
85       mr_destroy_reply(cp->args);
86       cp->args = NULL;
87       initialize_operation(cp->pending_op, mr_start_send,
88                            (char *)&cp->reply, NULL);
89       queue_operation(cp->con, CON_OUTPUT, cp->pending_op);
90       cp->action = CL_SEND;
91       break;
92     }
93 }
94
95 char *procnames[] = {
96   "noop",
97   "auth",
98   "shutdown",
99   "query",
100   "access",
101   "dcm",
102   "motd",
103 };
104
105
106 void do_call(client *cl)
107 {
108   int pn;
109   cl->reply.mr_argc = 0;
110   cl->reply.mr_status = 0;
111   cl->reply.mr_version_no = cl->args->mr_version_no;
112   if (((pn = cl->args->mr_procno) < 0) || (pn > MR_MAX_PROC))
113     {
114       com_err(whoami, 0, "procno out of range");
115       cl->reply.mr_status = MR_UNKNOWN_PROC;
116       return;
117     }
118   if (log_flags & LOG_ARGS)
119     {
120       log_args(procnames[pn], cl->args->mr_version_no,
121                cl->args->mr_argc, cl->args->mr_argv);
122     }
123   else if (log_flags & LOG_REQUESTS)
124     com_err(whoami, 0, "%s", procnames[pn]);
125
126   if ((dormant == ASLEEP || dormant == GROGGY) &&
127       pn != MR_NOOP && pn != MR_MOTD)
128     {
129       cl->reply.mr_status = MR_DOWN;
130       if (log_flags & LOG_RES)
131         com_err(whoami, MR_DOWN, "(query refused)");
132       return;
133     }
134
135   /* make sure this gets cleared before every operation */
136   dbms_errno = 0;
137
138   switch (pn)
139     {
140     case MR_NOOP:
141       cl->reply.mr_status = 0;
142       return;
143
144     case MR_AUTH:
145       do_auth(cl);
146       return;
147
148     case MR_QUERY:
149       do_retr(cl);
150       return;
151
152     case MR_ACCESS:
153       do_access(cl);
154       return;
155
156     case MR_SHUTDOWN:
157       do_shutdown(cl);
158       return;
159
160     case MR_DO_UPDATE:
161       trigger_dcm(NULL, NULL, cl);
162       return;
163
164     case MR_MOTD:
165       get_motd(cl);
166       return;
167     }
168 }
169
170 void free_rtn_tuples(client *cp)
171 {
172   returned_tuples *temp;
173   for (temp = cp->first; temp && OP_DONE(temp->op); )
174     {
175       returned_tuples *t1 = temp;
176       temp = t1->next;
177       if (t1 == cp->last)
178         cp->last = NULL;
179
180       mr_destroy_reply(t1->retval);
181       delete_operation(t1->op);
182       free(t1);
183     }
184   cp->first = temp;
185 }
186
187 int retr_callback(int argc, char **argv, void *p_cp)
188 {
189   client *cp = p_cp;
190   mr_params *arg_tmp;
191   returned_tuples *tp;
192   OPERATION op_tmp;
193   char **nargv;
194   int i;
195
196   if (row_count++ >= max_row_count)
197     {
198       dbms_errno = mr_errcode = MR_NO_MEM;
199       return MR_ABORT;
200     }
201
202   /*
203    * This takes too much advantage of the fact that
204    * serialization of the data happens during the queue operation.
205    */
206   arg_tmp = malloc(sizeof(mr_params));
207   tp = malloc(sizeof(returned_tuples));
208   nargv = malloc(argc * sizeof(char *));
209
210   op_tmp = create_operation();
211
212   if (mr_trim_args(argc, argv) == MR_NO_MEM)
213     com_err(whoami, MR_NO_MEM, "while trimming args");
214   if (log_flags & LOG_RESP)
215     log_args("return: ", cp->args->mr_version_no, argc, argv);
216
217   tp->op = op_tmp;
218   tp->retval = arg_tmp;
219   tp->next = NULL;
220
221   arg_tmp->mr_status = MR_MORE_DATA;
222   arg_tmp->mr_version_no = cp->args->mr_version_no;
223   arg_tmp->mr_argc = argc;
224   arg_tmp->mr_argv = nargv;
225   for (i = 0; i < argc; i++)
226     {
227       int len = strlen(argv[i]) + 1;
228       nargv[i] = malloc(len);
229       memcpy(nargv[i], argv[i], len);
230     }
231   arg_tmp->mr_flattened = NULL;
232   arg_tmp->mr_argl = NULL;
233
234   if (cp->last)
235     {
236       cp->last->next = tp;
237       cp->last = tp;
238     } else
239       cp->last = cp->first = tp;
240
241   reset_operation(op_tmp);
242   initialize_operation(op_tmp, mr_start_send, (char *)arg_tmp, NULL);
243   queue_operation(cp->con, CON_OUTPUT, op_tmp);
244   return MR_CONT;
245 }
246
247 int list_users(int (*callbk)(int, char **, void *), char *callarg)
248 {
249   char *argv[6];
250   char buf[30];
251   char buf1[30];
252   int i;
253   extern client **clients;
254   char *cp;
255
256   for (i = 0; i < nclients; i++)
257     {
258       client *cl = clients[i];
259       if (cl->clname)
260         argv[0] = cl->clname;
261       else argv[0] = "unauthenticated";
262
263       argv[1] = inet_ntoa(cl->haddr.sin_addr);
264       argv[2] = buf;
265       sprintf(buf, "port %d", ntohs(cl->haddr.sin_port));
266       argv[3] = ctime(&cl->last_time_used);
267       cp = strchr(argv[3], '\n');
268       if (cp)
269         *cp = '\0';
270       argv[4] = buf1;
271       sprintf(buf1, "[#%d]", cl->id);
272       (*callbk)(5, argv, callarg);
273     }
274   return 0;
275 }
276
277 void do_retr(client *cl)
278 {
279   char *queryname;
280
281   cl->reply.mr_argc = 0;
282   cl->reply.mr_status = 0;
283   row_count = 0;
284
285   if (cl->args->mr_argc < 1)
286     {
287       cl->reply.mr_status = MR_ARGS;
288       com_err(whoami, MR_ARGS, "got nameless query");
289       return;
290     }
291   queryname = cl->args->mr_argv[0];
292
293   if (cl->args->mr_version_no == MR_VERSION_2)
294     newqueries++;
295   else
296     oldqueries++;
297
298   if (!strcmp(queryname, "_list_users"))
299     cl->reply.mr_status = list_users(retr_callback, (char *)cl);
300   else
301     {
302       cl->reply.mr_status = mr_process_query(cl, queryname,
303                                              cl->args->mr_argc - 1,
304                                              cl->args->mr_argv + 1,
305                                              retr_callback, cl);
306     }
307   if (row_count >= max_row_count)
308     {
309       critical_alert("moirad", "attempted query %s with %d rows\n",
310                      queryname, row_count);
311     }
312
313   if (log_flags & LOG_RES)
314     com_err(whoami, 0, "Query complete.");
315 }
316
317 void do_access(client *cl)
318 {
319   if (cl->args->mr_argc < 1)
320     {
321       cl->reply.mr_status = MR_ARGS;
322       com_err(whoami, MR_ARGS, "got nameless access");
323       return;
324     }
325   cl->reply.mr_argc = 0;
326
327   cl->reply.mr_status = mr_check_access(cl, cl->args->mr_argv[0],
328                                         cl->args->mr_argc - 1,
329                                         cl->args->mr_argv + 1);
330
331   com_err(whoami, 0, "Access check complete.");
332 }
333
334
335 /* trigger_dcm is also used as a followup routine to the
336  * set_server_host_override query, hence the two dummy arguments.
337  */
338
339 struct query pseudo_query = {
340   "trigger_dcm",
341   "tdcm",
342 };
343
344 int trigger_dcm(struct query *q, char *argv[], client *cl)
345 {
346   int pid;
347   char prog[128];
348
349   cl->reply.mr_argc = 0;
350
351   if ((cl->reply.mr_status = check_query_access(&pseudo_query, 0, cl)))
352     return cl->reply.mr_status;
353
354   sprintf(prog, "%s/startdcm", BIN_DIR);
355   pid = vfork();
356   switch (pid)
357     {
358     case 0:
359       execl(prog, "startdcm", 0);
360       exit(1);
361
362     case -1:
363       cl->reply.mr_status = errno;
364       return 0;
365
366     default:
367       return 0;
368     }
369 }
370
371
372 void get_motd(client *cl)
373 {
374   int motd, len;
375   char buffer[1024];
376   char *arg[1];
377
378   arg[0] = buffer;
379   cl->reply.mr_status = 0;
380   motd = open(MOIRA_MOTD_FILE, 0, O_RDONLY);
381   if (motd < 0)
382     return;
383   len = read(motd, buffer, sizeof(buffer) - 1);
384   close(motd);
385   buffer[len] = 0;
386   row_count = 0;
387   retr_callback(1, arg, cl);
388   cl->reply.mr_status = 0;
389 }
This page took 0.121802 seconds and 5 git commands to generate.