source: trunk/third/moira/server/mr_scall.c @ 24319

Revision 24319, 6.8 KB checked in by broder, 14 years ago (diff)
New Moira snapshot from SVN.
Line 
1/* $Id: mr_scall.c 3956 2010-01-05 20:56:56Z zacheiss $
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 <time.h>
26#include <unistd.h>
27
28RCSID("$HeadURL: svn+ssh://svn.mit.edu/moira/trunk/moira/server/mr_scall.c $ $Id: mr_scall.c 3956 2010-01-05 20:56:56Z zacheiss $");
29
30extern int nclients;
31extern client **clients;
32extern char *whoami;
33
34extern int dbms_errno, mr_errcode;
35
36int max_version;
37
38void do_call(client *cl);
39void free_rtn_tuples(client *cp);
40int retr_callback(int argc, char **argv, void *p_cl);
41int list_users(client *cl);
42void do_retr(client *cl);
43void do_access(client *cl);
44void get_motd(client *cl);
45void do_version(client *cl);
46
47char *procnames[] = {
48  "noop",
49  "auth",
50  "shutdown",
51  "query",
52  "access",
53  "dcm",
54  "motd",
55  "proxy",
56  "version",
57  "auth_krb5",
58};
59
60int newqueries;
61
62void client_read(client *cl)
63{
64  int status, pn;
65
66  status = mr_cont_receive(cl->con, &cl->req);
67  if (status == -1)
68    return;
69  else if (status != MR_SUCCESS)
70    {
71      cl->state = CL_CLOSING;
72      if (status != MR_NOT_CONNECTED)
73        com_err(whoami, status, "while reading from socket");
74      return;
75    }
76
77  pn = cl->req.u.mr_procno;
78  if (pn < 0 || pn > MR_MAX_PROC)
79    {
80      com_err(whoami, 0, "procno out of range");
81      client_reply(cl, MR_UNKNOWN_PROC);
82      goto out;
83    }
84  log_args(procnames[pn], 2, cl->req.mr_argc, cl->req.mr_argv);
85
86  if (dormant == ASLEEP && pn != MR_NOOP && pn != MR_MOTD)
87    {
88      client_reply(cl, MR_DOWN);
89      com_err(whoami, MR_DOWN, "(query refused)");
90      goto out;
91    }
92
93  /* make sure this gets cleared before every operation */
94  dbms_errno = 0;
95
96  switch (pn)
97    {
98    case MR_NOOP:
99      client_reply(cl, MR_SUCCESS);
100      break;
101
102    case MR_AUTH:
103      do_auth(cl);
104      break;
105
106    case MR_QUERY:
107      do_retr(cl);
108      break;
109
110    case MR_ACCESS:
111      do_access(cl);
112      break;
113
114    case MR_SHUTDOWN:
115      do_shutdown(cl);
116      break;
117
118    case MR_DO_UPDATE:
119      client_reply(cl, MR_PERM);
120      break;
121
122    case MR_MOTD:
123      get_motd(cl);
124      break;
125
126    case MR_PROXY:
127      do_proxy(cl);
128      break;
129
130    case MR_SETVERSION:
131      do_version(cl);
132      break;
133
134    case MR_KRB5_AUTH:
135      do_krb5_auth(cl);
136      break;
137
138    }
139
140out:
141  mr_destroy_reply(cl->req);
142  memset(&cl->req, 0, sizeof(mr_params));
143}
144
145/* Set the final return status for a query. We always keep one more
146   free slot in cl->tuples[] than we're using so that this can't fail */
147void client_reply(client *cl, long status)
148{
149  cl->tuples[cl->ntuples].u.mr_status = status;
150  cl->tuples[cl->ntuples].mr_argc = 0;
151  cl->tuples[cl->ntuples].mr_argl = NULL;
152  cl->tuples[cl->ntuples].mr_argv = NULL;
153  cl->ntuples++;
154}
155
156void client_return_tuple(client *cl, int argc, char **argv)
157{
158  if (cl->state == CL_CLOSING || dbms_errno)
159    return;
160
161  if (cl->ntuples == cl->tuplessize - 1)
162    {
163      int newsize = (cl->tuplessize + 4) * 2;
164      mr_params *newtuples;
165
166      newtuples = realloc(cl->tuples, newsize * sizeof(mr_params));
167      if (!newtuples)
168        {
169          free_rtn_tuples(cl);
170          dbms_errno = mr_errcode = MR_NO_MEM;
171          return;
172        }
173      cl->tuplessize = newsize;
174      cl->tuples = newtuples;
175    }
176
177  cl->tuples[cl->ntuples].u.mr_status = MR_MORE_DATA;
178  cl->tuples[cl->ntuples].mr_argc = argc;
179  cl->tuples[cl->ntuples].mr_argl = NULL;
180  cl->tuples[cl->ntuples].mr_argv = mr_copy_args(argv, argc);
181  cl->ntuples++;
182}
183
184void client_write(client *cl)
185{
186  int status;
187
188  status = mr_send(cl->con, &cl->tuples[cl->nexttuple]);
189  if (status)
190    {
191      com_err(whoami, status, "writing to socket");
192      cl->state = CL_CLOSING;
193    }
194  else
195    {
196      cl->nexttuple++;
197      if (cl->nexttuple == cl->ntuples)
198        free_rtn_tuples(cl);
199    }
200}
201
202void free_rtn_tuples(client *cl)
203{
204  for (cl->ntuples--; cl->ntuples >= 0; cl->ntuples--)
205    free_argv(cl->tuples[cl->ntuples].mr_argv,
206              cl->tuples[cl->ntuples].mr_argc);
207  free(cl->tuples);
208
209  cl->tuples = xmalloc(sizeof(mr_params));
210  cl->tuplessize = 1;
211  cl->ntuples = cl->nexttuple = 0;
212}
213
214void do_retr(client *cl)
215{
216  char *queryname;
217  int status;
218
219  if (cl->req.mr_argc < 1)
220    {
221      client_reply(cl, MR_ARGS);
222      com_err(whoami, MR_ARGS, "got nameless query");
223      return;
224    }
225  queryname = cl->req.mr_argv[0];
226  newqueries++;
227
228  if (!strcmp(queryname, "_list_users"))
229    status = list_users(cl);
230  else
231    status = mr_process_query(cl, queryname, cl->req.mr_argc - 1,
232                              cl->req.mr_argv + 1, retr_callback, cl);
233
234  client_reply(cl, status);
235
236  com_err(whoami, 0, "Query complete.");
237}
238
239int retr_callback(int argc, char **argv, void *p_cl)
240{
241  client *cl = p_cl;
242
243  mr_trim_args(argc, argv);
244  client_return_tuple(cl, argc, argv);
245}
246
247void do_access(client *cl)
248{
249  int status;
250
251  if (cl->req.mr_argc < 1)
252    {
253      client_reply(cl, MR_ARGS);
254      com_err(whoami, MR_ARGS, "got nameless access");
255      return;
256    }
257
258  status = mr_check_access(cl, cl->req.mr_argv[0], cl->req.mr_argc - 1,
259                           cl->req.mr_argv + 1);
260  client_reply(cl, status);
261
262  com_err(whoami, 0, "Access check complete.");
263}
264
265void do_version(client *cl)
266{
267  if (cl->req.mr_argc != 1)
268    {
269      client_reply(cl, MR_ARGS);
270      com_err(whoami, MR_ARGS, "incorrect number of arguments");
271      return;
272    }
273
274  cl->version = atoi(cl->req.mr_argv[0]);
275  if (cl->version == -1)
276    cl->version = max_version;
277
278  client_reply(cl, cl->version == max_version ? MR_SUCCESS :
279               cl->version < max_version ? MR_VERSION_LOW : MR_VERSION_HIGH);
280}
281
282void get_motd(client *cl)
283{
284  int motd;
285  char *buffer;
286  struct stat statb;
287
288  if (stat(MOIRA_MOTD_FILE, &statb) == -1)
289    {
290      client_reply(cl, MR_SUCCESS);
291      return;
292    }
293 
294  buffer = malloc(statb.st_size + 1);
295  if (!buffer)
296    {
297      client_reply(cl, MR_NO_MEM);
298      return;
299    }
300
301  motd = open(MOIRA_MOTD_FILE, 0, O_RDONLY);
302  if (motd)
303    {
304      read(motd, buffer, statb.st_size);
305      close(motd);
306      buffer[statb.st_size] = '\0';
307      client_return_tuple(cl, 1, &buffer);
308      client_reply(cl, MR_SUCCESS);
309    }
310  else
311    client_reply(cl, errno);
312
313  free(buffer);
314}
315
316int list_users(client *cl)
317{
318  char *argv[5];
319  char buf[30];
320  char buf1[30];
321  int i;
322  char *cp;
323
324  for (i = 0; i < nclients; i++)
325    {
326      client *c = clients[i];
327      argv[0] = c->clname;
328      argv[1] = inet_ntoa(c->haddr.sin_addr);
329      argv[2] = buf;
330      sprintf(buf, "port %d", ntohs(c->haddr.sin_port));
331      argv[3] = ctime(&c->last_time_used);
332      cp = strchr(argv[3], '\n');
333      if (cp)
334        *cp = '\0';
335      argv[4] = buf1;
336      sprintf(buf1, "[#%d]", c->id);
337      client_return_tuple(cl, 5, argv);
338    }
339  return MR_SUCCESS;
340}
341
Note: See TracBrowser for help on using the repository browser.