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;
37 void do_call(client *cl);
38 void free_rtn_tuples(client *cp);
39 int retr_callback(int argc, char **argv, void *p_cl);
40 int list_users(client *cl);
41 void do_retr(client *cl);
42 void do_access(client *cl);
43 void get_motd(client *cl);
44 void do_version(client *cl);
60 void client_read(client *cl)
64 status = mr_cont_receive(cl->con, &cl->req);
67 else if (status != MR_SUCCESS)
69 cl->state = CL_CLOSING;
70 if (status != MR_NOT_CONNECTED)
71 com_err(whoami, status, "while reading from socket");
75 pn = cl->req.u.mr_procno;
76 if (pn < 0 || pn > MR_MAX_PROC)
78 com_err(whoami, 0, "procno out of range");
79 client_reply(cl, MR_UNKNOWN_PROC);
82 log_args(procnames[pn], 2, cl->req.mr_argc, cl->req.mr_argv);
84 if (dormant == ASLEEP && pn != MR_NOOP && pn != MR_MOTD)
86 client_reply(cl, MR_DOWN);
87 com_err(whoami, MR_DOWN, "(query refused)");
91 /* make sure this gets cleared before every operation */
97 client_reply(cl, MR_SUCCESS);
117 client_reply(cl, MR_PERM);
134 mr_destroy_reply(cl->req);
135 memset(&cl->req, 0, sizeof(mr_params));
138 /* Set the final return status for a query. We always keep one more
139 free slot in cl->tuples[] than we're using so that this can't fail */
140 void client_reply(client *cl, long status)
142 cl->tuples[cl->ntuples].u.mr_status = status;
143 cl->tuples[cl->ntuples].mr_argc = 0;
144 cl->tuples[cl->ntuples].mr_argl = NULL;
145 cl->tuples[cl->ntuples].mr_argv = NULL;
149 void client_return_tuple(client *cl, int argc, char **argv)
151 if (cl->state == CL_CLOSING || dbms_errno)
154 if (cl->ntuples == cl->tuplessize - 1)
156 int newsize = (cl->tuplessize + 4) * 2;
157 mr_params *newtuples;
159 newtuples = realloc(cl->tuples, newsize * sizeof(mr_params));
163 dbms_errno = mr_errcode = MR_NO_MEM;
166 cl->tuplessize = newsize;
167 cl->tuples = newtuples;
170 cl->tuples[cl->ntuples].u.mr_status = MR_MORE_DATA;
171 cl->tuples[cl->ntuples].mr_argc = argc;
172 cl->tuples[cl->ntuples].mr_argl = NULL;
173 cl->tuples[cl->ntuples].mr_argv = mr_copy_args(argv, argc);
177 void client_write(client *cl)
181 status = mr_send(cl->con, &cl->tuples[cl->nexttuple]);
184 com_err(whoami, status, "writing to socket");
185 cl->state = CL_CLOSING;
190 if (cl->nexttuple == cl->ntuples)
195 void free_rtn_tuples(client *cl)
197 for (cl->ntuples--; cl->ntuples >= 0; cl->ntuples--)
198 free_argv(cl->tuples[cl->ntuples].mr_argv,
199 cl->tuples[cl->ntuples].mr_argc);
202 cl->tuples = xmalloc(sizeof(mr_params));
204 cl->ntuples = cl->nexttuple = 0;
207 void do_retr(client *cl)
212 if (cl->req.mr_argc < 1)
214 client_reply(cl, MR_ARGS);
215 com_err(whoami, MR_ARGS, "got nameless query");
218 queryname = cl->req.mr_argv[0];
221 if (!strcmp(queryname, "_list_users"))
222 status = list_users(cl);
224 status = mr_process_query(cl, queryname, cl->req.mr_argc - 1,
225 cl->req.mr_argv + 1, retr_callback, cl);
227 client_reply(cl, status);
229 com_err(whoami, 0, "Query complete.");
232 int retr_callback(int argc, char **argv, void *p_cl)
236 mr_trim_args(argc, argv);
237 client_return_tuple(cl, argc, argv);
240 void do_access(client *cl)
244 if (cl->req.mr_argc < 1)
246 client_reply(cl, MR_ARGS);
247 com_err(whoami, MR_ARGS, "got nameless access");
251 status = mr_check_access(cl, cl->req.mr_argv[0], cl->req.mr_argc - 1,
252 cl->req.mr_argv + 1);
253 client_reply(cl, status);
255 com_err(whoami, 0, "Access check complete.");
258 void do_version(client *cl)
260 if (cl->req.mr_argc != 1)
262 client_reply(cl, MR_ARGS);
263 com_err(whoami, MR_ARGS, "incorrect number of arguments");
267 cl->version = atoi(cl->req.mr_argv[0]);
268 if (cl->version == -1)
269 cl->version = max_version;
271 client_reply(cl, cl->version == max_version ? MR_SUCCESS :
272 cl->version < max_version ? MR_VERSION_LOW : MR_VERSION_HIGH);
275 void get_motd(client *cl)
281 if (stat(MOIRA_MOTD_FILE, &statb) == -1)
283 client_reply(cl, MR_SUCCESS);
287 buffer = malloc(statb.st_size + 1);
290 client_reply(cl, MR_NO_MEM);
294 motd = open(MOIRA_MOTD_FILE, 0, O_RDONLY);
297 read(motd, buffer, statb.st_size);
299 buffer[statb.st_size] = '\0';
300 client_return_tuple(cl, 1, &buffer);
301 client_reply(cl, MR_SUCCESS);
304 client_reply(cl, errno);
309 int list_users(client *cl)
317 for (i = 0; i < nclients; i++)
319 client *c = clients[i];
321 argv[1] = inet_ntoa(c->haddr.sin_addr);
323 sprintf(buf, "port %d", ntohs(c->haddr.sin_port));
324 argv[3] = ctime(&c->last_time_used);
325 cp = strchr(argv[3], '\n');
329 sprintf(buf1, "[#%d]", c->id);
330 client_return_tuple(cl, 5, argv);