]> andersk Git - moira.git/blob - server/mr_scall.c
punt mrgdb
[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 int nclients;
30 extern client **clients;
31 extern char *whoami;
32
33 extern int dbms_errno, mr_errcode;
34
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);
42
43 /* Put this in a variable so that we can patch it if necessary */
44 int max_row_count = 4096;
45
46 char *procnames[] = {
47   "noop",
48   "auth",
49   "shutdown",
50   "query",
51   "access",
52   "dcm",
53   "motd",
54 };
55
56 int newqueries;
57
58 void client_read(client *cl)
59 {
60   mr_params req;
61   int status, pn;
62
63   status = mr_receive(cl->con, &req);
64   if (status != MR_SUCCESS)
65     {
66       cl->done = 1;
67       if (status != MR_NOT_CONNECTED)
68         com_err(whoami, status, "while reading from socket");
69       return;
70     }
71
72   pn = req.u.mr_procno;
73   if (pn < 0 || pn > MR_MAX_PROC)
74     {
75       com_err(whoami, 0, "procno out of range");
76       client_reply(cl, MR_UNKNOWN_PROC);
77       return;
78     }
79   log_args(procnames[pn], 2, req.mr_argc, req.mr_argv);
80
81   if (dormant == ASLEEP && pn != MR_NOOP && pn != MR_MOTD)
82     {
83       client_reply(cl, MR_DOWN);
84       com_err(whoami, MR_DOWN, "(query refused)");
85       return;
86     }
87
88   /* make sure this gets cleared before every operation */
89   dbms_errno = 0;
90
91   switch (pn)
92     {
93     case MR_NOOP:
94       client_reply(cl, MR_SUCCESS);
95       return;
96
97     case MR_AUTH:
98       do_auth(cl, req);
99       return;
100
101     case MR_QUERY:
102       do_retr(cl, req);
103       return;
104
105     case MR_ACCESS:
106       do_access(cl, req);
107       return;
108
109     case MR_SHUTDOWN:
110       do_shutdown(cl);
111       return;
112
113     case MR_DO_UPDATE:
114       client_reply(cl, MR_PERM);
115       return;
116
117     case MR_MOTD:
118       get_motd(cl);
119       return;
120     }
121 }
122
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)
126 {
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;
131   cl->ntuples++;
132 }
133
134 void client_return_tuple(client *cl, int argc, char **argv)
135 {
136   if (cl->done || dbms_errno)
137     return;
138
139   if (cl->ntuples == max_row_count)
140     {
141       dbms_errno = mr_errcode = MR_NO_MEM;
142       return;
143     }
144
145   if (cl->ntuples == cl->tuplessize - 1)
146     {
147       int newsize = (cl->tuplessize + 4) * 2;
148       mr_params *newtuples;
149
150       newtuples = realloc(cl->tuples, newsize * sizeof(mr_params));
151       if (!newtuples)
152         {
153           free_rtn_tuples(cl);
154           dbms_errno = mr_errcode = MR_NO_MEM;
155           return;
156         }
157       cl->tuplessize = newsize;
158       cl->tuples = newtuples;
159     }
160
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);
165   cl->ntuples++;
166 }
167
168 void client_write(client *cl)
169 {
170   int status;
171
172   status = mr_send(cl->con, &cl->tuples[cl->nexttuple]);
173   if (status)
174     {
175       com_err(whoami, status, "writing to socket");
176       cl->done = 1;
177     }
178   else
179     {
180       cl->nexttuple++;
181       if (cl->nexttuple == cl->ntuples)
182         free_rtn_tuples(cl);
183     }
184 }
185
186 void free_rtn_tuples(client *cl)
187 {
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);
191   free(cl->tuples);
192
193   cl->tuples = xmalloc(sizeof(mr_params));
194   cl->tuplessize = 1;
195   cl->ntuples = cl->nexttuple = 0;
196 }
197
198 void do_retr(client *cl, mr_params req)
199 {
200   char *queryname;
201   int status;
202
203   if (req.mr_argc < 1)
204     {
205       client_reply(cl, MR_ARGS);
206       com_err(whoami, MR_ARGS, "got nameless query");
207       return;
208     }
209   queryname = req.mr_argv[0];
210   newqueries++;
211
212   if (!strcmp(queryname, "_list_users"))
213     status = list_users(cl);
214   else
215     status = mr_process_query(cl, queryname, req.mr_argc - 1, req.mr_argv + 1,
216                               retr_callback, cl);
217
218   client_reply(cl, status);
219
220   if (cl->ntuples >= max_row_count)
221     {
222       critical_alert("moirad", "attempted query %s with too many rows\n",
223                      queryname);
224     }
225
226   com_err(whoami, 0, "Query complete.");
227 }
228
229 int retr_callback(int argc, char **argv, void *p_cl)
230 {
231   client *cl = p_cl;
232
233   mr_trim_args(argc, argv);
234   client_return_tuple(cl, argc, argv);
235 }
236
237 void do_access(client *cl, mr_params req)
238 {
239   int status;
240
241   if (req.mr_argc < 1)
242     {
243       client_reply(cl, MR_ARGS);
244       com_err(whoami, MR_ARGS, "got nameless access");
245       return;
246     }
247
248   status = mr_check_access(cl, req.mr_argv[0], req. mr_argc - 1,
249                            req.mr_argv + 1);
250   client_reply(cl, status);
251
252   com_err(whoami, 0, "Access check complete.");
253 }
254
255 void get_motd(client *cl)
256 {
257   int motd;
258   char *buffer;
259   struct stat statb;
260
261   if (stat(MOIRA_MOTD_FILE, &statb) == -1)
262     {
263       client_reply(cl, MR_SUCCESS);
264       return;
265     }
266   
267   buffer = malloc(statb.st_size + 1);
268   if (!buffer)
269     {
270       client_reply(cl, MR_NO_MEM);
271       return;
272     }
273
274   motd = open(MOIRA_MOTD_FILE, 0, O_RDONLY);
275   if (motd)
276     {
277       read(motd, buffer, statb.st_size);
278       close(motd);
279       buffer[statb.st_size] = '\0';
280       client_return_tuple(cl, 1, &buffer);
281       client_reply(cl, MR_SUCCESS);
282     }
283   else
284     client_reply(cl, errno);
285
286   free(buffer);
287 }
288
289 int list_users(client *cl)
290 {
291   char *argv[5];
292   char buf[30];
293   char buf1[30];
294   int i;
295   char *cp;
296
297   for (i = 0; i < nclients; i++)
298     {
299       client *c = clients[i];
300       argv[0] = c->clname;
301       argv[1] = inet_ntoa(c->haddr.sin_addr);
302       argv[2] = buf;
303       sprintf(buf, "port %d", ntohs(c->haddr.sin_port));
304       argv[3] = ctime(&c->last_time_used);
305       cp = strchr(argv[3], '\n');
306       if (cp)
307         *cp = '\0';
308       argv[4] = buf1;
309       sprintf(buf1, "[#%d]", c->id);
310       client_return_tuple(cl, 5, argv);
311     }
312   return MR_SUCCESS;
313 }
314
This page took 0.097402 seconds and 5 git commands to generate.