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>
30 extern client **clients;
33 extern int dbms_errno, mr_errcode;
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);
43 /* Put this in a variable so that we can patch it if necessary */
44 int max_row_count = 4096;
58 void client_read(client *cl)
63 status = mr_receive(cl->con, &req);
64 if (status != MR_SUCCESS)
67 if (status != MR_NOT_CONNECTED)
68 com_err(whoami, status, "while reading from socket");
73 if (pn < 0 || pn > MR_MAX_PROC)
75 com_err(whoami, 0, "procno out of range");
76 client_reply(cl, MR_UNKNOWN_PROC);
79 log_args(procnames[pn], 2, req.mr_argc, req.mr_argv);
81 if (dormant == ASLEEP && pn != MR_NOOP && pn != MR_MOTD)
83 client_reply(cl, MR_DOWN);
84 com_err(whoami, MR_DOWN, "(query refused)");
88 /* make sure this gets cleared before every operation */
94 client_reply(cl, MR_SUCCESS);
114 client_reply(cl, MR_PERM);
123 /* Set the final return status for a query. We always keep one more
124 free slot in cl->tuples[] than we're using so that this can't fail */
125 void client_reply(client *cl, long status)
127 cl->tuples[cl->ntuples].u.mr_status = status;
128 cl->tuples[cl->ntuples].mr_argc = 0;
129 cl->tuples[cl->ntuples].mr_argl = NULL;
130 cl->tuples[cl->ntuples].mr_argv = NULL;
134 void client_return_tuple(client *cl, int argc, char **argv)
136 if (cl->done || dbms_errno)
139 if (cl->ntuples == max_row_count)
141 dbms_errno = mr_errcode = MR_NO_MEM;
145 if (cl->ntuples == cl->tuplessize - 1)
147 int newsize = (cl->tuplessize + 4) * 2;
148 mr_params *newtuples;
150 newtuples = realloc(cl->tuples, newsize * sizeof(mr_params));
154 dbms_errno = mr_errcode = MR_NO_MEM;
157 cl->tuplessize = newsize;
158 cl->tuples = newtuples;
161 cl->tuples[cl->ntuples].u.mr_status = MR_MORE_DATA;
162 cl->tuples[cl->ntuples].mr_argc = argc;
163 cl->tuples[cl->ntuples].mr_argl = NULL;
164 cl->tuples[cl->ntuples].mr_argv = mr_copy_args(argv, argc);
168 void client_write(client *cl)
172 status = mr_send(cl->con, &cl->tuples[cl->nexttuple]);
175 com_err(whoami, status, "writing to socket");
181 if (cl->nexttuple == cl->ntuples)
186 void free_rtn_tuples(client *cl)
188 for (cl->ntuples--; cl->ntuples >= 0; cl->ntuples--)
189 free_argv(cl->tuples[cl->ntuples].mr_argv,
190 cl->tuples[cl->ntuples].mr_argc);
193 cl->tuples = xmalloc(sizeof(mr_params));
195 cl->ntuples = cl->nexttuple = 0;
198 void do_retr(client *cl, mr_params req)
205 client_reply(cl, MR_ARGS);
206 com_err(whoami, MR_ARGS, "got nameless query");
209 queryname = req.mr_argv[0];
212 if (!strcmp(queryname, "_list_users"))
213 status = list_users(cl);
215 status = mr_process_query(cl, queryname, req.mr_argc - 1, req.mr_argv + 1,
218 client_reply(cl, status);
220 if (cl->ntuples >= max_row_count)
222 critical_alert("moirad", "attempted query %s with too many rows\n",
226 com_err(whoami, 0, "Query complete.");
229 int retr_callback(int argc, char **argv, void *p_cl)
233 mr_trim_args(argc, argv);
234 client_return_tuple(cl, argc, argv);
237 void do_access(client *cl, mr_params req)
243 client_reply(cl, MR_ARGS);
244 com_err(whoami, MR_ARGS, "got nameless access");
248 status = mr_check_access(cl, req.mr_argv[0], req. mr_argc - 1,
250 client_reply(cl, status);
252 com_err(whoami, 0, "Access check complete.");
255 void get_motd(client *cl)
261 if (stat(MOIRA_MOTD_FILE, &statb) == -1)
263 client_reply(cl, MR_SUCCESS);
267 buffer = malloc(statb.st_size + 1);
270 client_reply(cl, MR_NO_MEM);
274 motd = open(MOIRA_MOTD_FILE, 0, O_RDONLY);
277 read(motd, buffer, statb.st_size);
279 buffer[statb.st_size] = '\0';
280 client_return_tuple(cl, 1, &buffer);
281 client_reply(cl, MR_SUCCESS);
284 client_reply(cl, errno);
289 int list_users(client *cl)
297 for (i = 0; i < nclients; i++)
299 client *c = clients[i];
301 argv[1] = inet_ntoa(c->haddr.sin_addr);
303 sprintf(buf, "port %d", ntohs(c->haddr.sin_port));
304 argv[3] = ctime(&c->last_time_used);
305 cp = strchr(argv[3], '\n');
309 sprintf(buf1, "[#%d]", c->id);
310 client_return_tuple(cl, 5, argv);