]>
Commit | Line | Data |
---|---|---|
0fa91a0a | 1 | /* |
2 | * $Source$ | |
3 | * $Author$ | |
4 | * $Header$ | |
5 | * | |
6 | * Copyright (C) 1987 by the Massachusetts Institute of Technology | |
c801de4c | 7 | * For copying and distribution information, please see the file |
8 | * <mit-copyright.h>. | |
0fa91a0a | 9 | * |
d548a4e7 | 10 | * MOIRA server process. |
0fa91a0a | 11 | * |
12 | * Most of this is stolen from ../gdb/tsr.c | |
13 | * | |
14 | * You are in a maze of twisty little finite automata, all different. | |
15 | * Let the reader beware. | |
5eaef520 | 16 | * |
0fa91a0a | 17 | */ |
18 | ||
d548a4e7 | 19 | static char *rcsid_mr_main_c = "$Header$"; |
0fa91a0a | 20 | |
c801de4c | 21 | #include <mit-copyright.h> |
03c05291 | 22 | #include <string.h> |
23 | #include <stdio.h> | |
589993be | 24 | #include <sys/types.h> |
70d54e43 | 25 | #include <sys/errno.h> |
70d54e43 | 26 | #include <sys/signal.h> |
554776b1 | 27 | #include <sys/wait.h> |
589993be | 28 | #include <sys/stat.h> |
03c05291 | 29 | #include <unistd.h> |
30 | #include <signal.h> | |
d548a4e7 | 31 | #include "mr_server.h" |
40165bd0 | 32 | #include <krb_et.h> |
03c05291 | 33 | #include <gdss_et.h> |
34 | #include <arpa/inet.h> | |
70d54e43 | 35 | |
0ec57336 | 36 | extern CONNECTION newconn, listencon; |
0fa91a0a | 37 | |
0ec57336 | 38 | extern int nclients; |
39 | extern client **clients, *cur_client; | |
0fa91a0a | 40 | |
0ec57336 | 41 | extern OPERATION listenop; |
42 | extern LIST_OF_OPERATIONS op_list; | |
0fa91a0a | 43 | |
0ec57336 | 44 | extern struct sockaddr_in client_addr; |
45 | extern int client_addrlen; | |
46 | extern TUPLE client_tuple; | |
0fa91a0a | 47 | |
0ec57336 | 48 | extern char *whoami; |
49 | extern char buf1[BUFSIZ]; | |
50 | extern char *takedown; | |
51 | extern int errno; | |
2f4ff9cd | 52 | extern FILE *journal; |
70d54e43 | 53 | |
0eb9f52f | 54 | extern time_t now; |
55 | ||
3d0d0f07 | 56 | char hostbuf[BUFSIZ], *host; |
57 | ||
03c05291 | 58 | int do_listen(char *port); |
59 | void do_reset_listen(void); | |
60 | void clist_append(client *cp); | |
61 | void oplist_append(LIST_OF_OPERATIONS *oplp, OPERATION op); | |
62 | void oplist_delete(LIST_OF_OPERATIONS oplp, OPERATION op); | |
63 | void mr_setup_signals(void); | |
64 | int new_connection(void); | |
e448f08d | 65 | |
0ec57336 | 66 | /* |
d548a4e7 | 67 | * Main MOIRA server loop. |
0ec57336 | 68 | * |
69 | * Initialize the world, then start accepting connections and | |
70 | * making progress on current connections. | |
71 | */ | |
0fa91a0a | 72 | |
5eaef520 | 73 | int main(int argc, char **argv) |
0fa91a0a | 74 | { |
5eaef520 | 75 | int status, i; |
76 | time_t tardy; | |
77 | char *port, *p; | |
78 | extern char *database; | |
79 | struct stat stbuf; | |
80 | ||
81 | whoami = argv[0]; | |
82 | /* | |
83 | * Error handler init. | |
84 | */ | |
85 | initialize_sms_error_table(); | |
86 | initialize_krb_error_table(); | |
87 | initialize_gdss_error_table(); | |
88 | set_com_err_hook(mr_com_err); | |
89 | setvbuf(stderr, NULL, _IOLBF, BUFSIZ); | |
90 | ||
91 | port = strchr(MOIRA_SERVER, ':') + 1; | |
92 | ||
93 | for (i = 1; i < argc; i++) | |
94 | { | |
95 | if (!strcmp(argv[i], "-db") && i + 1 < argc) | |
96 | { | |
97 | database = argv[i + 1]; | |
98 | i++; | |
5dbd09a0 | 99 | } |
5eaef520 | 100 | else if (!strcmp(argv[i], "-p") && i + 1 < argc) |
101 | { | |
102 | port = argv[i + 1]; | |
103 | i++; | |
f6cc38de | 104 | } |
5eaef520 | 105 | else |
106 | { | |
107 | com_err(whoami, 0, "Usage: moirad [-db database][-p port]"); | |
3d0d0f07 | 108 | exit(1); |
109 | } | |
5eaef520 | 110 | } |
111 | ||
112 | /* | |
113 | * GDB initialization. | |
114 | */ | |
115 | if (gdb_init() != 0) | |
116 | { | |
117 | com_err(whoami, 0, "GDB initialization failed."); | |
118 | exit(1); | |
119 | } | |
120 | gdb_debug(0); /* this can be patched, if necessary, to enable */ | |
121 | /* GDB level debugging .. */ | |
122 | krb_realm = malloc(REALM_SZ); | |
123 | krb_get_lrealm(krb_realm, 1); | |
124 | ||
125 | /* | |
126 | * Database initialization. Only init if database should be open. | |
127 | */ | |
128 | ||
129 | if (stat(MOIRA_MOTD_FILE, &stbuf) != 0) | |
130 | { | |
131 | if ((status = mr_open_database())) | |
132 | { | |
133 | com_err(whoami, status, " when trying to open database."); | |
134 | exit(1); | |
2f4ff9cd | 135 | } |
5eaef520 | 136 | sanity_check_database(); |
137 | } | |
138 | else | |
139 | { | |
140 | dormant = ASLEEP; | |
141 | com_err(whoami, 0, "sleeping, not opening database"); | |
142 | } | |
2f4ff9cd | 143 | |
5eaef520 | 144 | sanity_check_queries(); |
145 | ||
146 | /* | |
147 | * Get moira server hostname for authentication | |
148 | */ | |
149 | if (gethostname(hostbuf, sizeof(hostbuf)) < 0) | |
150 | { | |
151 | com_err(whoami, errno, "Unable to get local hostname"); | |
152 | exit(1); | |
153 | } | |
154 | host = canonicalize_hostname(strsave(hostbuf)); | |
155 | for (p = host; *p && *p != '.'; p++) | |
156 | { | |
157 | if (isupper(*p)) | |
158 | *p = tolower(*p); | |
159 | } | |
160 | *p = '\0'; | |
161 | ||
162 | /* | |
163 | * Set up client array handler. | |
164 | */ | |
165 | nclients = 0; | |
166 | clients = malloc(0); | |
167 | ||
168 | mr_setup_signals(); | |
169 | ||
170 | journal = fopen(JOURNAL, "a"); | |
171 | if (!journal) | |
172 | { | |
173 | com_err(whoami, errno, " while opening journal file"); | |
174 | exit(1); | |
175 | } | |
176 | ||
177 | /* | |
178 | * Establish template connection. | |
179 | */ | |
180 | if ((status = do_listen(port))) | |
181 | { | |
182 | com_err(whoami, status, " while trying to create listening connection"); | |
183 | exit(1); | |
184 | } | |
185 | ||
186 | op_list = create_list_of_operations(1, listenop); | |
187 | ||
188 | com_err(whoami, 0, "started (pid %d)", getpid()); | |
189 | com_err(whoami, 0, rcsid_mr_main_c); | |
190 | if (dormant != ASLEEP) | |
191 | send_zgram("MOIRA", "server started"); | |
192 | else | |
193 | send_zgram("MOIRA", "server started, but database closed"); | |
194 | ||
195 | /* | |
196 | * Run until shut down. | |
197 | */ | |
198 | while (!takedown) | |
199 | { | |
44d12d58 | 200 | int i; |
5eaef520 | 201 | /* |
202 | * Block until something happens. | |
203 | */ | |
204 | if (dormant == SLEEPY) | |
205 | { | |
206 | mr_close_database(); | |
207 | com_err(whoami, 0, "database closed"); | |
208 | mr_setup_signals(); | |
209 | send_zgram("MOIRA", "database closed"); | |
210 | dormant = ASLEEP; | |
211 | } | |
212 | else if (dormant == GROGGY) | |
213 | { | |
214 | mr_open_database(); | |
215 | com_err(whoami, 0, "database open"); | |
216 | mr_setup_signals(); | |
217 | send_zgram("MOIRA", "database open again"); | |
218 | dormant = AWAKE; | |
0ec57336 | 219 | } |
589993be | 220 | |
5eaef520 | 221 | errno = 0; |
222 | status = op_select_any(op_list, 0, NULL, NULL, NULL, NULL); | |
223 | if (status == -1) | |
224 | { | |
225 | if (errno != EINTR) | |
226 | com_err(whoami, errno, " error from op_select"); | |
227 | if (!inc_running || now - inc_started > INC_TIMEOUT) | |
228 | next_incremental(); | |
229 | continue; | |
230 | } | |
231 | else if (status != -2) | |
232 | { | |
233 | com_err(whoami, 0, " wrong return from op_select_any"); | |
234 | continue; | |
235 | } | |
236 | if (takedown) | |
237 | break; | |
238 | time(&now); | |
239 | if (!inc_running || now - inc_started > INC_TIMEOUT) | |
240 | next_incremental(); | |
241 | ||
242 | /* | |
243 | * Handle any new connections; this comes first so | |
244 | * errno isn't tromped on. | |
245 | */ | |
246 | if (OP_DONE(listenop)) | |
247 | { | |
248 | if (OP_STATUS(listenop) == OP_CANCELLED) | |
249 | { | |
250 | if (errno == EWOULDBLOCK) | |
251 | do_reset_listen(); | |
252 | else | |
253 | { | |
254 | static int count = 0; | |
255 | com_err(whoami, errno, " error (%d) on listen", count); | |
256 | if (count++ > 10) | |
257 | exit(1); | |
0fa91a0a | 258 | } |
5eaef520 | 259 | } |
260 | else if ((status = new_connection())) | |
261 | { | |
262 | com_err(whoami, errno, " Error on listening operation."); | |
263 | /* | |
264 | * Sleep here to prevent hosing? | |
265 | */ | |
266 | } | |
267 | /* if the new connection is our only connection, | |
268 | * and the server is supposed to be down, then go | |
269 | * down now. | |
270 | */ | |
271 | if ((dormant == AWAKE) && (nclients == 1) && | |
272 | (stat(MOIRA_MOTD_FILE, &stbuf) == 0)) | |
273 | { | |
274 | com_err(whoami, 0, "motd file exists, slumbertime"); | |
275 | dormant = SLEEPY; | |
276 | } | |
277 | /* on new connection, if we are no longer supposed | |
278 | * to be down, then wake up. | |
279 | */ | |
280 | if ((dormant == ASLEEP) && (stat(MOIRA_MOTD_FILE, &stbuf) == -1) && | |
281 | (errno == ENOENT)) | |
282 | { | |
283 | com_err(whoami, 0, "motd file no longer exists, waking up"); | |
284 | dormant = GROGGY; | |
285 | } | |
0fa91a0a | 286 | } |
5eaef520 | 287 | /* |
288 | * Handle any existing connections. | |
289 | */ | |
290 | tardy = now - 30 * 60; | |
291 | ||
292 | for (i = 0; i < nclients; i++) | |
293 | { | |
294 | cur_client = clients[i]; | |
295 | if (OP_DONE(clients[i]->pending_op)) | |
296 | { | |
297 | cur_client->last_time_used = now; | |
298 | do_client(cur_client); | |
299 | } | |
300 | else if (clients[i]->last_time_used < tardy) | |
301 | { | |
302 | com_err(whoami, 0, "Shutting down connection due to inactivity"); | |
303 | shutdown(cur_client->con->in.fd, 2); | |
304 | } | |
305 | cur_client = NULL; | |
306 | if (takedown) | |
307 | break; | |
308 | } | |
309 | } | |
310 | com_err(whoami, 0, "%s", takedown); | |
311 | if (dormant != ASLEEP) | |
312 | mr_close_database(); | |
313 | send_zgram("MOIRA", takedown); | |
314 | return 0; | |
70d54e43 | 315 | } |
316 | ||
0ec57336 | 317 | /* |
318 | * Set up the template connection and queue the first accept. | |
319 | */ | |
320 | ||
5eaef520 | 321 | int do_listen(char *port) |
70d54e43 | 322 | { |
5eaef520 | 323 | listencon = create_listening_connection(port); |
0ec57336 | 324 | |
5eaef520 | 325 | if (!listencon) |
326 | return errno; | |
0ec57336 | 327 | |
5eaef520 | 328 | listenop = create_operation(); |
329 | client_addrlen = sizeof(client_addr); | |
0ec57336 | 330 | |
5eaef520 | 331 | start_accepting_client(listencon, listenop, &newconn, (char *)&client_addr, |
332 | &client_addrlen, &client_tuple); | |
333 | return 0; | |
0fa91a0a | 334 | } |
335 | ||
b4182127 | 336 | |
03c05291 | 337 | void do_reset_listen(void) |
b4182127 | 338 | { |
5eaef520 | 339 | client_addrlen = sizeof(client_addr); |
340 | start_accepting_client(listencon, listenop, &newconn, (char *)&client_addr, | |
341 | &client_addrlen, &client_tuple); | |
b4182127 | 342 | } |
343 | ||
0ec57336 | 344 | /* |
345 | * This routine is called when a new connection comes in. | |
346 | * | |
347 | * It sets up a new client and adds it to the list of currently active clients. | |
348 | */ | |
03c05291 | 349 | int new_connection(void) |
0fa91a0a | 350 | { |
44d12d58 | 351 | client *cp; |
5eaef520 | 352 | static counter = 0; |
353 | ||
354 | /* | |
355 | * Make sure there's been no error | |
356 | */ | |
357 | if (OP_STATUS(listenop) != OP_COMPLETE) | |
358 | return errno; | |
359 | ||
360 | if (!newconn) | |
361 | return MR_NOT_CONNECTED; | |
362 | ||
363 | /* | |
364 | * Set up the new connection and reply to the client | |
365 | */ | |
366 | cp = malloc(sizeof(client)); | |
367 | memset(cp, 0, sizeof(*cp)); | |
368 | cp->action = CL_ACCEPT; | |
369 | cp->con = newconn; | |
370 | cp->id = counter++; | |
371 | cp->args = NULL; | |
372 | cp->clname[0] = NULL; | |
373 | cp->reply.mr_argv = NULL; | |
374 | cp->first = NULL; | |
375 | cp->last = NULL; | |
376 | cp->last_time_used = now; | |
377 | newconn = NULL; | |
378 | ||
379 | cp->pending_op = create_operation(); | |
380 | reset_operation(cp->pending_op); | |
381 | oplist_append(&op_list, cp->pending_op); | |
382 | cur_client = cp; | |
383 | ||
384 | /* | |
385 | * Add a new client to the array.. | |
386 | */ | |
387 | clist_append(cp); | |
388 | ||
389 | /* | |
390 | * Let him know we heard him. | |
391 | */ | |
392 | start_replying_to_client(cp->pending_op, cp->con, GDB_ACCEPTED, "", ""); | |
393 | ||
394 | cp->haddr = client_addr; | |
395 | ||
396 | /* | |
397 | * Log new connection. | |
398 | */ | |
399 | com_err(whoami, 0, "New connection from %s port %d (now %d client%s)", | |
400 | inet_ntoa(cp->haddr.sin_addr), (int)ntohs(cp->haddr.sin_port), | |
401 | nclients, nclients != 1 ? "s" : ""); | |
402 | ||
403 | /* | |
404 | * Get ready to accept the next connection. | |
405 | */ | |
406 | reset_operation(listenop); | |
407 | client_addrlen = sizeof(client_addr); | |
408 | ||
409 | start_accepting_client(listencon, listenop, &newconn, (char *)&client_addr, | |
410 | &client_addrlen, &client_tuple); | |
411 | return 0; | |
0fa91a0a | 412 | } |
413 | ||
0fa91a0a | 414 | /* |
415 | * Add a new client to the known clients. | |
416 | */ | |
5eaef520 | 417 | void clist_append(client *cp) |
418 | { | |
419 | client **clients_n; | |
420 | ||
421 | nclients++; | |
422 | clients_n = malloc(nclients * sizeof(client *)); | |
423 | memcpy(clients_n, clients, (nclients - 1) * sizeof(cp)); | |
424 | clients_n[nclients - 1] = cp; | |
425 | free(clients); | |
426 | clients = clients_n; | |
427 | clients_n = NULL; | |
0fa91a0a | 428 | } |
429 | ||
5eaef520 | 430 | |
431 | void clist_delete(client *cp) | |
70d54e43 | 432 | { |
5eaef520 | 433 | client **clients_n, **scpp, **dcpp; /* source and dest client ptr ptr */ |
434 | ||
435 | int found_it = 0; | |
436 | ||
437 | clients_n = malloc((nclients - 1) * sizeof(client *)); | |
438 | for (scpp = clients, dcpp = clients_n; scpp < clients + nclients; ) | |
439 | { | |
440 | if (*scpp != cp) | |
441 | *dcpp++ = *scpp++; | |
442 | else | |
443 | { | |
444 | scpp++; | |
445 | if (found_it) | |
446 | abort(); | |
447 | found_it = 1; | |
70d54e43 | 448 | } |
5eaef520 | 449 | } |
450 | --nclients; | |
451 | free(clients); | |
452 | clients = clients_n; | |
453 | clients_n = NULL; | |
454 | oplist_delete(op_list, cp->pending_op); | |
455 | reset_operation(cp->pending_op); | |
456 | delete_operation(cp->pending_op); | |
457 | sever_connection(cp->con); | |
458 | free(cp); | |
70d54e43 | 459 | } |
0ec57336 | 460 | |
0fa91a0a | 461 | /* |
0ec57336 | 462 | * Add a new operation to a list of operations. |
463 | * | |
464 | * This should be rewritten to use realloc instead, since in most | |
465 | * cases it won't have to copy the array. | |
0fa91a0a | 466 | */ |
467 | ||
5eaef520 | 468 | void oplist_append(LIST_OF_OPERATIONS *oplp, OPERATION op) |
0fa91a0a | 469 | { |
5eaef520 | 470 | int count = (*oplp)->count + 1; |
471 | LIST_OF_OPERATIONS newlist = (LIST_OF_OPERATIONS) | |
472 | db_alloc(size_of_list_of_operations(count)); | |
473 | memcpy(newlist, *oplp, size_of_list_of_operations((*oplp)->count)); | |
474 | newlist->count++; | |
475 | newlist->op[count - 1] = op; | |
476 | db_free(*oplp, size_of_list_of_operations(count - 1)); | |
477 | *oplp = newlist; | |
0fa91a0a | 478 | } |
479 | ||
5eaef520 | 480 | void oplist_delete(LIST_OF_OPERATIONS oplp, OPERATION op) |
c27b3454 | 481 | { |
44d12d58 | 482 | OPERATION *s; |
483 | int c; | |
5eaef520 | 484 | |
485 | for (s = oplp->op, c = oplp->count; c; --c, ++s) | |
486 | { | |
487 | if (*s == op) | |
488 | { | |
489 | while (c > 0) | |
490 | { | |
491 | *s = *(s + 1); | |
492 | ++s; | |
493 | --c; | |
494 | } | |
495 | oplp->count--; | |
496 | return; | |
c27b3454 | 497 | } |
5eaef520 | 498 | } |
499 | abort(); | |
c27b3454 | 500 | } |
554776b1 | 501 | |
502 | ||
5eaef520 | 503 | void reapchild(int x) |
554776b1 | 504 | { |
5eaef520 | 505 | int status, pid; |
506 | ||
507 | while ((pid = waitpid(-1, &status, WNOHANG)) > 0) | |
508 | { | |
509 | if (pid == inc_pid) | |
510 | inc_running = 0; | |
511 | if (!takedown && (WTERMSIG(status) != 0 || WEXITSTATUS(status) != 0)) | |
512 | com_err(whoami, 0, "%d: child exits with signal %d status %d", | |
513 | pid, WTERMSIG(status), WEXITSTATUS(status)); | |
554776b1 | 514 | } |
515 | } | |
589993be | 516 | |
517 | ||
5eaef520 | 518 | void godormant(int x) |
589993be | 519 | { |
5eaef520 | 520 | switch (dormant) |
521 | { | |
589993be | 522 | case AWAKE: |
523 | case GROGGY: | |
5eaef520 | 524 | com_err(whoami, 0, "requested to go dormant"); |
525 | break; | |
589993be | 526 | case ASLEEP: |
5eaef520 | 527 | com_err(whoami, 0, "already asleep"); |
528 | break; | |
589993be | 529 | case SLEEPY: |
5eaef520 | 530 | break; |
589993be | 531 | } |
5eaef520 | 532 | dormant = SLEEPY; |
589993be | 533 | } |
534 | ||
535 | ||
5eaef520 | 536 | void gowakeup(int x) |
589993be | 537 | { |
5eaef520 | 538 | switch (dormant) |
539 | { | |
589993be | 540 | case ASLEEP: |
541 | case SLEEPY: | |
5eaef520 | 542 | com_err(whoami, 0, "Good morning"); |
543 | break; | |
589993be | 544 | case AWAKE: |
5eaef520 | 545 | com_err(whoami, 0, "already awake"); |
546 | break; | |
589993be | 547 | case GROGGY: |
5eaef520 | 548 | break; |
589993be | 549 | } |
5eaef520 | 550 | dormant = GROGGY; |
589993be | 551 | } |
083a6e94 | 552 | |
5eaef520 | 553 | |
03c05291 | 554 | void mr_setup_signals(void) |
083a6e94 | 555 | { |
5eaef520 | 556 | struct sigaction action; |
557 | ||
558 | action.sa_flags = 0; | |
559 | sigemptyset(&action.sa_mask); | |
03c05291 | 560 | |
5eaef520 | 561 | /* There should probably be a few more of these. */ |
03c05291 | 562 | |
5eaef520 | 563 | action.sa_handler = sigshut; |
564 | if ((sigaction(SIGTERM, &action, NULL) < 0) || | |
565 | (sigaction(SIGINT, &action, NULL) < 0) || | |
566 | (sigaction(SIGHUP, &action, NULL) < 0)) | |
567 | { | |
03c05291 | 568 | com_err(whoami, errno, "Unable to establish signal handlers."); |
569 | exit(1); | |
083a6e94 | 570 | } |
e448f08d | 571 | |
5eaef520 | 572 | action.sa_handler = godormant; |
573 | if (sigaction(SIGUSR1, &action, NULL) < 0) | |
574 | { | |
03c05291 | 575 | com_err(whoami, errno, "Unable to establish signal handlers."); |
576 | exit(1); | |
577 | } | |
e448f08d | 578 | |
5eaef520 | 579 | action.sa_handler = gowakeup; |
580 | if (sigaction(SIGUSR2, &action, NULL) < 0) | |
581 | { | |
03c05291 | 582 | com_err(whoami, errno, "Unable to establish signal handlers."); |
583 | exit(1); | |
584 | } | |
e448f08d | 585 | |
5eaef520 | 586 | action.sa_handler = reapchild; |
587 | sigaddset(&action.sa_mask, SIGCHLD); | |
588 | if (sigaction(SIGCHLD, &action, NULL) < 0) | |
589 | { | |
03c05291 | 590 | com_err(whoami, errno, "Unable to establish signal handlers."); |
591 | exit(1); | |
592 | } | |
593 | } |