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