]> andersk Git - moira.git/blob - server/mr_main.c
sync'ing files for RCS->CVS migration
[moira.git] / server / mr_main.c
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
19 static 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
31 extern CONNECTION newconn, listencon;
32
33 extern int nclients;
34 extern client **clients, *cur_client;
35
36 extern OPERATION listenop;
37 extern LIST_OF_OPERATIONS op_list;
38
39 extern struct sockaddr_in client_addr;
40 extern int client_addrlen;
41 extern TUPLE client_tuple;
42
43 extern char *whoami;
44 extern char buf1[BUFSIZ];
45 extern char *takedown;
46 extern int errno;
47 extern FILE *journal;
48
49 extern char *inet_ntoa();
50 extern void mr_com_err();
51 extern void do_client();
52
53 extern int sigshut();
54 void clist_append();
55 void oplist_append();
56 void reapchild(), godormant(), gowakeup();
57
58 extern time_t now;
59
60 #ifdef _DEBUG_MALLOC_INC
61 static char *dbg_malloc();
62 static 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*/
73 int
74 main(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
299 int
300 do_listen(port)
301 char *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
318 do_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  */
331 int
332 new_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  */
407 void
408 clist_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                 
424 void
425 clist_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
462 void
463 oplist_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
479 oplist_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
501 void 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
516 void 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
533 void 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         
550 mr_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
565 static char *dbg_malloc(size)
566         SIZETYPE        size;
567 {
568         return( debug_malloc("somewhere in the gdb code",1,size) );
569 }
570
571 static 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.082792 seconds and 5 git commands to generate.