]> andersk Git - moira.git/blob - server/mr_scall.c
Add queries for manipulating the listsids and usersids tables.
[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 int max_version;
36
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);
45
46 char *procnames[] = {
47   "noop",
48   "auth",
49   "shutdown",
50   "query",
51   "access",
52   "dcm",
53   "motd",
54   "proxy",
55   "version",
56 };
57
58 int newqueries;
59
60 void client_read(client *cl)
61 {
62   int status, pn;
63
64   status = mr_cont_receive(cl->con, &cl->req);
65   if (status == -1)
66     return;
67   else if (status != MR_SUCCESS)
68     {
69       cl->state = CL_CLOSING;
70       if (status != MR_NOT_CONNECTED)
71         com_err(whoami, status, "while reading from socket");
72       return;
73     }
74
75   pn = cl->req.u.mr_procno;
76   if (pn < 0 || pn > MR_MAX_PROC)
77     {
78       com_err(whoami, 0, "procno out of range");
79       client_reply(cl, MR_UNKNOWN_PROC);
80       goto out;
81     }
82   log_args(procnames[pn], 2, cl->req.mr_argc, cl->req.mr_argv);
83
84   if (dormant == ASLEEP && pn != MR_NOOP && pn != MR_MOTD)
85     {
86       client_reply(cl, MR_DOWN);
87       com_err(whoami, MR_DOWN, "(query refused)");
88       goto out;
89     }
90
91   /* make sure this gets cleared before every operation */
92   dbms_errno = 0;
93
94   switch (pn)
95     {
96     case MR_NOOP:
97       client_reply(cl, MR_SUCCESS);
98       break;
99
100     case MR_AUTH:
101       do_auth(cl);
102       break;
103
104     case MR_QUERY:
105       do_retr(cl);
106       break;
107
108     case MR_ACCESS:
109       do_access(cl);
110       break;
111
112     case MR_SHUTDOWN:
113       do_shutdown(cl);
114       break;
115
116     case MR_DO_UPDATE:
117       client_reply(cl, MR_PERM);
118       break;
119
120     case MR_MOTD:
121       get_motd(cl);
122       break;
123
124     case MR_PROXY:
125       do_proxy(cl);
126       break;
127
128     case MR_SETVERSION:
129       do_version(cl);
130       break;
131     }
132
133 out:
134   mr_destroy_reply(cl->req);
135   memset(&cl->req, 0, sizeof(mr_params));
136 }
137
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)
141 {
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;
146   cl->ntuples++;
147 }
148
149 void client_return_tuple(client *cl, int argc, char **argv)
150 {
151   if (cl->state == CL_CLOSING || dbms_errno)
152     return;
153
154   if (cl->ntuples == cl->tuplessize - 1)
155     {
156       int newsize = (cl->tuplessize + 4) * 2;
157       mr_params *newtuples;
158
159       newtuples = realloc(cl->tuples, newsize * sizeof(mr_params));
160       if (!newtuples)
161         {
162           free_rtn_tuples(cl);
163           dbms_errno = mr_errcode = MR_NO_MEM;
164           return;
165         }
166       cl->tuplessize = newsize;
167       cl->tuples = newtuples;
168     }
169
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);
174   cl->ntuples++;
175 }
176
177 void client_write(client *cl)
178 {
179   int status;
180
181   status = mr_send(cl->con, &cl->tuples[cl->nexttuple]);
182   if (status)
183     {
184       com_err(whoami, status, "writing to socket");
185       cl->state = CL_CLOSING;
186     }
187   else
188     {
189       cl->nexttuple++;
190       if (cl->nexttuple == cl->ntuples)
191         free_rtn_tuples(cl);
192     }
193 }
194
195 void free_rtn_tuples(client *cl)
196 {
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);
200   free(cl->tuples);
201
202   cl->tuples = xmalloc(sizeof(mr_params));
203   cl->tuplessize = 1;
204   cl->ntuples = cl->nexttuple = 0;
205 }
206
207 void do_retr(client *cl)
208 {
209   char *queryname;
210   int status;
211
212   if (cl->req.mr_argc < 1)
213     {
214       client_reply(cl, MR_ARGS);
215       com_err(whoami, MR_ARGS, "got nameless query");
216       return;
217     }
218   queryname = cl->req.mr_argv[0];
219   newqueries++;
220
221   if (!strcmp(queryname, "_list_users"))
222     status = list_users(cl);
223   else
224     status = mr_process_query(cl, queryname, cl->req.mr_argc - 1,
225                               cl->req.mr_argv + 1, retr_callback, cl);
226
227   client_reply(cl, status);
228
229   com_err(whoami, 0, "Query complete.");
230 }
231
232 int retr_callback(int argc, char **argv, void *p_cl)
233 {
234   client *cl = p_cl;
235
236   mr_trim_args(argc, argv);
237   client_return_tuple(cl, argc, argv);
238 }
239
240 void do_access(client *cl)
241 {
242   int status;
243
244   if (cl->req.mr_argc < 1)
245     {
246       client_reply(cl, MR_ARGS);
247       com_err(whoami, MR_ARGS, "got nameless access");
248       return;
249     }
250
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);
254
255   com_err(whoami, 0, "Access check complete.");
256 }
257
258 void do_version(client *cl)
259 {
260   if (cl->req.mr_argc != 1)
261     {
262       client_reply(cl, MR_ARGS);
263       com_err(whoami, MR_ARGS, "incorrect number of arguments");
264       return;
265     }
266
267   cl->version = atoi(cl->req.mr_argv[0]);
268   if (cl->version == -1)
269     cl->version = max_version;
270
271   client_reply(cl, cl->version == max_version ? MR_SUCCESS :
272                cl->version < max_version ? MR_VERSION_LOW : MR_VERSION_HIGH);
273 }
274
275 void get_motd(client *cl)
276 {
277   int motd;
278   char *buffer;
279   struct stat statb;
280
281   if (stat(MOIRA_MOTD_FILE, &statb) == -1)
282     {
283       client_reply(cl, MR_SUCCESS);
284       return;
285     }
286   
287   buffer = malloc(statb.st_size + 1);
288   if (!buffer)
289     {
290       client_reply(cl, MR_NO_MEM);
291       return;
292     }
293
294   motd = open(MOIRA_MOTD_FILE, 0, O_RDONLY);
295   if (motd)
296     {
297       read(motd, buffer, statb.st_size);
298       close(motd);
299       buffer[statb.st_size] = '\0';
300       client_return_tuple(cl, 1, &buffer);
301       client_reply(cl, MR_SUCCESS);
302     }
303   else
304     client_reply(cl, errno);
305
306   free(buffer);
307 }
308
309 int list_users(client *cl)
310 {
311   char *argv[5];
312   char buf[30];
313   char buf1[30];
314   int i;
315   char *cp;
316
317   for (i = 0; i < nclients; i++)
318     {
319       client *c = clients[i];
320       argv[0] = c->clname;
321       argv[1] = inet_ntoa(c->haddr.sin_addr);
322       argv[2] = buf;
323       sprintf(buf, "port %d", ntohs(c->haddr.sin_port));
324       argv[3] = ctime(&c->last_time_used);
325       cp = strchr(argv[3], '\n');
326       if (cp)
327         *cp = '\0';
328       argv[4] = buf1;
329       sprintf(buf1, "[#%d]", c->id);
330       client_return_tuple(cl, 5, argv);
331     }
332   return MR_SUCCESS;
333 }
334
This page took 0.061354 seconds and 5 git commands to generate.