5 * Copyright (C) 1987-1998 by the Massachusetts Institute of Technology
6 * For copying and distribution information, please see the file
11 #include <mit-copyright.h>
12 #include "mr_server.h"
16 #include <sys/types.h>
18 #include <arpa/inet.h>
19 #include <netinet/in.h>
33 extern int dbms_errno, mr_errcode;
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);
44 /* Put this in a variable so that we can patch it if necessary */
45 int max_row_count = 4096;
48 * Welcome to the (finite state) machine (highest level).
50 void do_client(client *cp)
55 if (OP_STATUS(cp->pending_op) == OP_CANCELLED)
58 "Closed connection (now %d client%s, %d new queries, %d old)",
59 nclients - 1, nclients != 2 ? "s" : "", newqueries, oldqueries);
61 /* if we no longer have any clients, and we're supposed to
62 * go down, then go down now.
64 if ((dormant == AWAKE) && (nclients == 0) &&
65 (stat(MOIRA_MOTD_FILE, &stbuf) == 0))
67 com_err(whoami, 0, "motd file exists, slumbertime");
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;
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);
87 initialize_operation(cp->pending_op, mr_start_send,
88 (char *)&cp->reply, NULL);
89 queue_operation(cp->con, CON_OUTPUT, cp->pending_op);
106 void do_call(client *cl)
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))
114 com_err(whoami, 0, "procno out of range");
115 cl->reply.mr_status = MR_UNKNOWN_PROC;
118 if (log_flags & LOG_ARGS)
120 log_args(procnames[pn], cl->args->mr_version_no,
121 cl->args->mr_argc, cl->args->mr_argv);
123 else if (log_flags & LOG_REQUESTS)
124 com_err(whoami, 0, "%s", procnames[pn]);
126 if ((dormant == ASLEEP || dormant == GROGGY) &&
127 pn != MR_NOOP && pn != MR_MOTD)
129 cl->reply.mr_status = MR_DOWN;
130 if (log_flags & LOG_RES)
131 com_err(whoami, MR_DOWN, "(query refused)");
135 /* make sure this gets cleared before every operation */
141 cl->reply.mr_status = 0;
161 trigger_dcm(NULL, NULL, cl);
170 void free_rtn_tuples(client *cp)
172 returned_tuples *temp;
173 for (temp = cp->first; temp && OP_DONE(temp->op); )
175 returned_tuples *t1 = temp;
180 mr_destroy_reply(t1->retval);
181 delete_operation(t1->op);
187 int retr_callback(int argc, char **argv, void *p_cp)
196 if (row_count++ >= max_row_count)
198 dbms_errno = mr_errcode = MR_NO_MEM;
203 * This takes too much advantage of the fact that
204 * serialization of the data happens during the queue operation.
206 arg_tmp = malloc(sizeof(mr_params));
207 tp = malloc(sizeof(returned_tuples));
208 nargv = malloc(argc * sizeof(char *));
210 op_tmp = create_operation();
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);
218 tp->retval = arg_tmp;
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++)
227 int len = strlen(argv[i]) + 1;
228 nargv[i] = malloc(len);
229 memcpy(nargv[i], argv[i], len);
231 arg_tmp->mr_flattened = NULL;
232 arg_tmp->mr_argl = NULL;
239 cp->last = cp->first = tp;
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);
247 int list_users(int (*callbk)(int, char **, void *), char *callarg)
253 extern client **clients;
256 for (i = 0; i < nclients; i++)
258 client *cl = clients[i];
260 argv[0] = cl->clname;
261 else argv[0] = "unauthenticated";
263 argv[1] = inet_ntoa(cl->haddr.sin_addr);
265 sprintf(buf, "port %d", ntohs(cl->haddr.sin_port));
266 argv[3] = ctime(&cl->last_time_used);
267 cp = strchr(argv[3], '\n');
271 sprintf(buf1, "[#%d]", cl->id);
272 (*callbk)(5, argv, callarg);
277 void do_retr(client *cl)
281 cl->reply.mr_argc = 0;
282 cl->reply.mr_status = 0;
285 if (cl->args->mr_argc < 1)
287 cl->reply.mr_status = MR_ARGS;
288 com_err(whoami, MR_ARGS, "got nameless query");
291 queryname = cl->args->mr_argv[0];
293 if (cl->args->mr_version_no == MR_VERSION_2)
298 if (!strcmp(queryname, "_list_users"))
299 cl->reply.mr_status = list_users(retr_callback, (char *)cl);
302 cl->reply.mr_status = mr_process_query(cl, queryname,
303 cl->args->mr_argc - 1,
304 cl->args->mr_argv + 1,
307 if (row_count >= max_row_count)
309 critical_alert("moirad", "attempted query %s with %d rows\n",
310 queryname, row_count);
313 if (log_flags & LOG_RES)
314 com_err(whoami, 0, "Query complete.");
317 void do_access(client *cl)
319 if (cl->args->mr_argc < 1)
321 cl->reply.mr_status = MR_ARGS;
322 com_err(whoami, MR_ARGS, "got nameless access");
325 cl->reply.mr_argc = 0;
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);
331 com_err(whoami, 0, "Access check complete.");
335 /* trigger_dcm is also used as a followup routine to the
336 * set_server_host_override query, hence the two dummy arguments.
339 struct query pseudo_query = {
344 int trigger_dcm(struct query *q, char *argv[], client *cl)
349 cl->reply.mr_argc = 0;
351 if ((cl->reply.mr_status = check_query_access(&pseudo_query, 0, cl)))
352 return cl->reply.mr_status;
354 sprintf(prog, "%s/startdcm", BIN_DIR);
359 execl(prog, "startdcm", 0);
363 cl->reply.mr_status = errno;
372 void get_motd(client *cl)
379 cl->reply.mr_status = 0;
380 motd = open(MOIRA_MOTD_FILE, 0, O_RDONLY);
383 len = read(motd, buffer, sizeof(buffer) - 1);
387 retr_callback(1, arg, cl);
388 cl->reply.mr_status = 0;