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