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