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