]>
Commit | Line | Data |
---|---|---|
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 |