]> andersk Git - moira.git/blame - server/mr_main.c
added support for server going dormant
[moira.git] / server / mr_main.c
CommitLineData
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 *
10 * SMS server process.
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.
16 *
0fa91a0a 17 */
18
0fa91a0a 19static char *rcsid_sms_main_c = "$Header$";
0fa91a0a 20
c801de4c 21#include <mit-copyright.h>
70d54e43 22#include <strings.h>
589993be 23#include <sys/types.h>
70d54e43 24#include <sys/errno.h>
70d54e43 25#include <sys/signal.h>
554776b1 26#include <sys/wait.h>
589993be 27#include <sys/stat.h>
0fa91a0a 28#include "sms_server.h"
40165bd0 29#include <krb_et.h>
70d54e43 30
0ec57336 31extern CONNECTION newconn, listencon;
0fa91a0a 32
0ec57336 33extern int nclients;
34extern client **clients, *cur_client;
0fa91a0a 35
0ec57336 36extern OPERATION listenop;
37extern LIST_OF_OPERATIONS op_list;
0fa91a0a 38
0ec57336 39extern struct sockaddr_in client_addr;
40extern int client_addrlen;
41extern TUPLE client_tuple;
0fa91a0a 42
0ec57336 43extern char *whoami;
44extern char buf1[BUFSIZ];
45extern char *takedown;
46extern int errno;
2f4ff9cd 47extern FILE *journal;
48#define JOURNAL "/u1/sms/journal"
70d54e43 49
0ec57336 50extern char *malloc();
f5c72293 51extern int free();
0ec57336 52extern char *inet_ntoa();
53extern void sms_com_err();
54extern void do_client();
70d54e43 55
0ec57336 56extern int sigshut();
57void clist_append();
58void oplist_append();
589993be 59void reapchild(), godormant(), gowakeup();
0fa91a0a 60
0eb9f52f 61extern time_t now;
62
0ec57336 63/*
64 * Main SMS server loop.
65 *
66 * Initialize the world, then start accepting connections and
67 * making progress on current connections.
68 */
0fa91a0a 69
0ec57336 70/*ARGSUSED*/
71int
0fa91a0a 72main(argc, argv)
70d54e43 73 int argc;
74 char **argv;
0fa91a0a 75{
0ec57336 76 int status;
0eb9f52f 77 time_t tardy;
589993be 78 struct stat stbuf;
0ec57336 79
80 whoami = argv[0];
81 /*
82 * Error handler init.
83 */
40165bd0 84 initialize_sms_error_table();
85 initialize_krb_error_table();
0ec57336 86 set_com_err_hook(sms_com_err);
b4182127 87 setlinebuf(stderr);
88
0ec57336 89 if (argc != 1) {
90 com_err(whoami, 0, "Usage: smsd");
91 exit(1);
92 }
f5c72293 93
94 /* Profiling implies that getting rid of one level of call
95 * indirection here wins us maybe 1% on the VAX.
96 */
97 gdb_amv = malloc;
98 gdb_fmv = free;
0ec57336 99
100 /*
101 * GDB initialization.
102 */
5dbd09a0 103 if(gdb_init() != 0) {
104 com_err(whoami, 0, "GDB initialization failed.");
105 exit(1);
106 }
7f024a70 107 gdb_debug(0); /* this can be patched, if necessary, to enable */
108 /* GDB level debugging .. */
4a06eb54 109 krb_realm = malloc(REALM_SZ);
110 get_krbrlm(krb_realm, 1);
7f024a70 111
f6cc38de 112 /*
113 * Database initialization.
114 */
115
116 if ((status = sms_open_database()) != 0) {
2f4ff9cd 117 com_err(whoami, status, " when trying to open database.");
f6cc38de 118 exit(1);
119 }
120
2f4ff9cd 121 sanity_check_queries();
122 sanity_check_database();
123
0ec57336 124 /*
125 * Set up client array handler.
126 */
0fa91a0a 127 nclients = 0;
128 clients = (client **) malloc(0);
70d54e43 129
0ec57336 130 /*
131 * Signal handlers
589993be 132 * There should probably be a few more of these. This is
133 * duplicated on the next page, be sure to also add any
134 * additional handlers there.
0ec57336 135 */
70d54e43 136
0ec57336 137 if ((((int)signal (SIGTERM, sigshut)) < 0) ||
ce81c728 138 (((int)signal (SIGCHLD, reapchild)) < 0) ||
589993be 139 (((int)signal (SIGUSR1, godormant)) < 0) ||
140 (((int)signal (SIGUSR2, gowakeup)) < 0) ||
0ec57336 141 (((int)signal (SIGHUP, sigshut)) < 0)) {
589993be 142 com_err(whoami, errno, " Unable to establish signal handlers.");
0ec57336 143 exit(1);
144 }
145
2f4ff9cd 146 journal = fopen(JOURNAL, "a");
147 if (journal == NULL) {
148 com_err(whoami, errno, " while opening journal file");
149 exit(1);
150 }
151
0ec57336 152 /*
153 * Establish template connection.
154 */
155 if ((status = do_listen()) != 0) {
156 com_err(whoami, status,
2f4ff9cd 157 " while trying to create listening connection");
0ec57336 158 exit(1);
159 }
0fa91a0a 160
0fa91a0a 161 op_list = create_list_of_operations(1, listenop);
0fa91a0a 162
b4182127 163 com_err(whoami, 0, "started (pid %d)", getpid());
0ec57336 164 com_err(whoami, 0, rcsid_sms_main_c);
49700f8b 165 send_zgram("SMS", "server started");
0ec57336 166
167 /*
168 * Run until shut down.
169 */
70d54e43 170 while(!takedown) {
0ec57336 171 register int i;
172 /*
173 * Block until something happens.
174 */
5dbd09a0 175#ifdef notdef
176 com_err(whoami, 0, "tick");
177#endif notdef
589993be 178 if (dormant == SLEEPY) {
179 sms_close_database();
180 com_err(whoami, 0, "database closed");
181 send_zgram("SMS", "database closed");
182 dormant = ASLEEP;
183 } else if (dormant == GROGGY) {
184 sms_open_database();
185 com_err(whoami, 0, "database open");
186 if ((((int)signal (SIGTERM, sigshut)) < 0) ||
187 (((int)signal (SIGCHLD, reapchild)) < 0) ||
188 (((int)signal (SIGUSR1, godormant)) < 0) ||
189 (((int)signal (SIGUSR2, gowakeup)) < 0) ||
190 (((int)signal (SIGHUP, sigshut)) < 0)) {
191 com_err(whoami, errno,
192 " Unable to reestablish signal handlers.");
193 exit(1);
194 }
195 send_zgram("SMS", "database open again");
196 dormant = AWAKE;
197 }
198
5dbd09a0 199 errno = 0;
200 status = op_select_any(op_list, 0,
201 (fd_set *)NULL, (fd_set *)NULL,
202 (fd_set *)NULL, (struct timeval *)NULL);
203
204 if (status == -1) {
589993be 205 com_err(whoami, errno, " error from op_select");
5dbd09a0 206 continue;
207 } else if (status != -2) {
2f4ff9cd 208 com_err(whoami, 0, " wrong return from op_select_any");
5dbd09a0 209 continue;
210 }
70d54e43 211 if (takedown) break;
0eb9f52f 212 time(&now);
70d54e43 213#ifdef notdef
214 fprintf(stderr, " tick\n");
215#endif notdef
b4182127 216 /*
217 * Handle any new connections; this comes first so
218 * errno isn't tromped on.
219 */
220 if (OP_DONE(listenop)) {
221 if (OP_STATUS(listenop) == OP_CANCELLED) {
222 if (errno == EWOULDBLOCK) {
223 do_reset_listen();
224 } else {
225 com_err(whoami, errno,
2f4ff9cd 226 " error on listen");
b4182127 227 exit(1);
228 }
229 } else if ((status = new_connection()) != 0) {
230 com_err(whoami, errno,
2f4ff9cd 231 " Error on listening operation.");
b4182127 232 /*
233 * Sleep here to prevent hosing?
234 */
235 }
589993be 236 /* if the new connection is our only connection,
237 * and the server is supposed to be down, then go
238 * down now.
239 */
240 if ((dormant == AWAKE) && (nclients == 1) &&
241 (stat(SMS_MOTD_FILE, &stbuf) == 0)) {
242 com_err(whoami, 0, "motd file exists, slumbertime");
243 dormant = SLEEPY;
244 }
245 /* on new connection, if we are no longer supposed
246 * to be down, then wake up.
247 */
248 if ((dormant == ASLEEP) &&
249 (stat(SMS_MOTD_FILE, &stbuf) == -1) &&
250 (errno == ENOENT)) {
251 com_err(whoami, 0, "motd file no longer exists, waking up");
252 dormant = GROGGY;
253 }
254
b4182127 255 }
0ec57336 256 /*
257 * Handle any existing connections.
258 */
0eb9f52f 259 tardy = now - 30*60;
260
0fa91a0a 261 for (i=0; i<nclients; i++) {
0eb9f52f 262 cur_client = clients[i];
0fa91a0a 263 if (OP_DONE(clients[i]->pending_op)) {
0eb9f52f 264 cur_client->last_time_used = now;
70d54e43 265 do_client(cur_client);
0eb9f52f 266 } else if (clients[i]->last_time_used < tardy) {
267 com_err(whoami, 0, "Shutting down connection due to inactivity");
268 shutdown(cur_client->con->in.fd, 0);
0fa91a0a 269 }
0eb9f52f 270 cur_client = NULL;
271 if (takedown) break;
0fa91a0a 272 }
0fa91a0a 273 }
b4182127 274 com_err(whoami, 0, "%s", takedown);
f6cc38de 275 sms_close_database();
49700f8b 276 send_zgram("SMS", takedown);
0ec57336 277 return 0;
70d54e43 278}
279
0ec57336 280/*
281 * Set up the template connection and queue the first accept.
282 */
283
284int
285do_listen()
70d54e43 286{
0ec57336 287 char *service = index(SMS_GDB_SERV, ':') + 1;
288
289 listencon = create_listening_connection(service);
290
291 if (listencon == NULL)
292 return errno;
293
294 listenop = create_operation();
295 client_addrlen = sizeof(client_addr);
296
297 start_accepting_client(listencon, listenop, &newconn,
298 (char *)&client_addr,
299 &client_addrlen, &client_tuple);
300 return 0;
0fa91a0a 301}
302
b4182127 303
304do_reset_listen()
305{
306 client_addrlen = sizeof(client_addr);
307 start_accepting_client(listencon, listenop, &newconn,
308 (char *)&client_addr,
309 &client_addrlen, &client_tuple);
310}
311
0ec57336 312/*
313 * This routine is called when a new connection comes in.
314 *
315 * It sets up a new client and adds it to the list of currently active clients.
316 */
317int
5dbd09a0 318new_connection()
0fa91a0a 319{
7f024a70 320 register client *cp;
70d54e43 321 static counter = 0;
0fa91a0a 322
0fa91a0a 323 /*
324 * Make sure there's been no error
325 */
c27b3454 326 if(OP_STATUS(listenop) != OP_COMPLETE) {
0ec57336 327 return errno;
c27b3454 328 }
329
330 if (newconn == NULL) {
331 return SMS_NOT_CONNECTED;
0fa91a0a 332 }
333
0fa91a0a 334 /*
335 * Set up the new connection and reply to the client
336 */
7f024a70 337 cp = (client *)malloc(sizeof *cp);
23e476e8 338 bzero(cp, sizeof(*cp));
0fa91a0a 339 cp->action = CL_ACCEPT;
340 cp->con = newconn;
70d54e43 341 cp->id = counter++;
0ec57336 342 cp->args = NULL;
343 cp->clname = NULL;
344 cp->reply.sms_argv = NULL;
4a06eb54 345 cp->first = NULL;
346 cp->last = NULL;
0eb9f52f 347 cp->last_time_used = now;
0fa91a0a 348 newconn = NULL;
349
350 cp->pending_op = create_operation();
351 reset_operation(cp->pending_op);
352 oplist_append(&op_list, cp->pending_op);
70d54e43 353 cur_client = cp;
354
0ec57336 355 /*
356 * Add a new client to the array..
357 */
358 clist_append(cp);
359
360 /*
361 * Let him know we heard him.
362 */
0fa91a0a 363 start_replying_to_client(cp->pending_op, cp->con, GDB_ACCEPTED,
364 "", "");
0ec57336 365
366 cp->haddr = client_addr;
367
368 /*
369 * Log new connection.
370 */
371
b4182127 372 com_err(whoami, 0, "New connection from %s port %d (now %d client%s)",
373 inet_ntoa(cp->haddr.sin_addr),
374 (int)ntohs(cp->haddr.sin_port),
375 nclients,
376 nclients!=1?"s":"");
0fa91a0a 377
378 /*
0ec57336 379 * Get ready to accept the next connection.
0fa91a0a 380 */
381 reset_operation(listenop);
0ec57336 382 client_addrlen = sizeof(client_addr);
0fa91a0a 383
384 start_accepting_client(listencon, listenop, &newconn,
0ec57336 385 (char *)&client_addr,
386 &client_addrlen, &client_tuple);
387 return 0;
0fa91a0a 388}
389
0fa91a0a 390/*
391 * Add a new client to the known clients.
392 */
0ec57336 393void
0fa91a0a 394clist_append(cp)
395 client *cp;
396{
397 client **clients_n;
398
399 nclients++;
0ec57336 400 clients_n = (client **)malloc
401 ((unsigned)(nclients * sizeof(client *)));
0fa91a0a 402 bcopy((char *)clients, (char *)clients_n, (nclients-1)*sizeof(cp));
403 clients_n[nclients-1] = cp;
404 free((char *)clients);
405 clients = clients_n;
406 clients_n = NULL;
407}
408
70d54e43 409
0ec57336 410void
70d54e43 411clist_delete(cp)
412 client *cp;
413{
70d54e43 414 client **clients_n, **scpp, **dcpp; /* source and dest client */
415 /* ptr ptr */
416
70d54e43 417 int found_it = 0;
418
0ec57336 419 clients_n = (client **)malloc
420 ((unsigned)((nclients - 1)* sizeof(client *)));
70d54e43 421 for (scpp = clients, dcpp = clients_n; scpp < clients+nclients; ) {
422 if (*scpp != cp) {
423 *dcpp++ = *scpp++;
424 } else {
425 scpp++;
426 if (found_it) abort();
427 found_it = 1;
428 }
429 }
430 --nclients;
431 free((char *)clients);
432 clients = clients_n;
433 clients_n = NULL;
c27b3454 434 oplist_delete(op_list, cp->pending_op);
70d54e43 435 reset_operation(cp->pending_op);
436 delete_operation(cp->pending_op);
7f024a70 437 sever_connection(cp->con);
0ec57336 438 free((char *)cp);
70d54e43 439}
0ec57336 440
0fa91a0a 441/*
0ec57336 442 * Add a new operation to a list of operations.
443 *
444 * This should be rewritten to use realloc instead, since in most
445 * cases it won't have to copy the array.
0fa91a0a 446 */
447
0ec57336 448void
0fa91a0a 449oplist_append(oplp, op)
450 LIST_OF_OPERATIONS *oplp;
451 OPERATION op;
452{
453 int count = (*oplp)->count+1;
454 LIST_OF_OPERATIONS newlist = (LIST_OF_OPERATIONS)
455 db_alloc(size_of_list_of_operations(count));
456 bcopy((char *)(*oplp), (char *)newlist,
457 size_of_list_of_operations((*oplp)->count));
0fa91a0a 458 newlist->count++;
459 newlist->op[count-1] = op;
467f5982 460 db_free((char *)(*oplp), size_of_list_of_operations(count-1));
0fa91a0a 461 (*oplp) = newlist;
462}
463
c27b3454 464
465oplist_delete(oplp, op)
466 LIST_OF_OPERATIONS oplp;
467 register OPERATION op;
468{
469 register OPERATION *s;
470 register int c;
471
472 for (s = oplp->op, c=oplp->count; c; --c, ++s) {
473 if (*s == op) {
474 while (c > 0) {
475 *s = *(s+1);
476 ++s;
477 --c;
478 }
479 oplp->count--;
480 return;
481 }
482 }
483 abort();
484}
554776b1 485
486
487void reapchild()
488{
489 union wait status;
490 int pid;
491
589993be 492 if (takedown || dormant == ASLEEP)
beebc379 493 return;
554776b1 494 while ((pid = wait3(&status, WNOHANG, (struct rusage *)0)) > 0) {
495 if (status.w_termsig == 0 && status.w_retcode == 0)
589993be 496 com_err(whoami, 0, "child exited successfully");
554776b1 497 else
589993be 498 com_err(whoami, 0, "%d: child exits with signal %d status %d",
554776b1 499 pid, status.w_termsig, status.w_retcode);
500 }
501}
589993be 502
503
504void godormant()
505{
506 switch (dormant) {
507 case AWAKE:
508 case GROGGY:
509 com_err(whoami, 0, "requested to go dormant");
510 break;
511 case ASLEEP:
512 com_err(whoami, 0, "already asleep");
513 break;
514 case SLEEPY:
515 break;
516 }
517 dormant = SLEEPY;
518}
519
520
521void gowakeup()
522{
523 switch (dormant) {
524 case ASLEEP:
525 case SLEEPY:
526 com_err(whoami, 0, "Good morning");
527 break;
528 case AWAKE:
529 com_err(whoami, 0, "already awake");
530 break;
531 case GROGGY:
532 break;
533 }
534 dormant = GROGGY;
535}
This page took 0.1383 seconds and 5 git commands to generate.