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