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