]> andersk Git - moira.git/blob - server/mr_main.c
Say "accounts consultant", not "administrator"
[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                                         static int count = 0;
217                                         com_err(whoami, errno,
218                                                 " error (%d) on listen", count);
219                                         if (count++ > 10)
220                                           exit(1);
221                                 }
222                         } else if ((status = new_connection()) != 0) {
223                                 com_err(whoami, errno,
224                                         " Error on listening operation.");
225                                 /*
226                                  * Sleep here to prevent hosing?
227                                  */
228                         }
229                         /* if the new connection is our only connection,
230                          * and the server is supposed to be down, then go
231                          * down now.
232                          */
233                         if ((dormant == AWAKE) && (nclients == 1) &&
234                             (stat(MOIRA_MOTD_FILE, &stbuf) == 0)) {
235                             com_err(whoami, 0, "motd file exists, slumbertime");
236                             dormant = SLEEPY;
237                         }
238                         /* on new connection, if we are no longer supposed
239                          * to be down, then wake up.
240                          */
241                         if ((dormant == ASLEEP) &&
242                             (stat(MOIRA_MOTD_FILE, &stbuf) == -1) &&
243                             (errno == ENOENT)) {
244                             com_err(whoami, 0, "motd file no longer exists, waking up");
245                             dormant = GROGGY;
246                         }
247                           
248                 }
249                 /*
250                  * Handle any existing connections.
251                  */
252                 tardy = now - 30*60;
253                 
254                 for (i=0; i<nclients; i++) {
255                         cur_client = clients[i];
256                         if (OP_DONE(clients[i]->pending_op)) {
257                                 cur_client->last_time_used = now;
258                                 do_client(cur_client);
259                         } else if (clients[i]->last_time_used < tardy) {
260                                 com_err(whoami, 0, "Shutting down connection due to inactivity");
261                                 shutdown(cur_client->con->in.fd, 0);
262                         }
263                         cur_client = NULL;
264                         if (takedown) break;
265                 }
266         }
267         com_err(whoami, 0, "%s", takedown);
268         mr_close_database();
269         send_zgram("MOIRA", takedown);
270         return 0;
271 }
272
273 /*
274  * Set up the template connection and queue the first accept.
275  */
276
277 int
278 do_listen()
279 {
280         char *service = index(MOIRA_SERVER, ':') + 1;
281
282         listencon = create_listening_connection(service);
283
284         if (listencon == NULL)
285                 return errno;
286
287         listenop = create_operation();
288         client_addrlen = sizeof(client_addr);
289
290         start_accepting_client(listencon, listenop, &newconn,
291                                (char *)&client_addr,
292                                &client_addrlen, &client_tuple);
293         return 0;
294 }
295
296
297 do_reset_listen()
298 {
299         client_addrlen = sizeof(client_addr);
300         start_accepting_client(listencon, listenop, &newconn,
301                                (char *)&client_addr,
302                                &client_addrlen, &client_tuple);
303 }
304
305 /*
306  * This routine is called when a new connection comes in.
307  *
308  * It sets up a new client and adds it to the list of currently active clients.
309  */
310 int
311 new_connection()
312 {
313         register client *cp;
314         static counter = 0;
315         
316         /*
317          * Make sure there's been no error
318          */
319         if(OP_STATUS(listenop) != OP_COMPLETE) {
320                 return errno;
321         }
322         
323         if (newconn == NULL) {
324                 return MR_NOT_CONNECTED;
325         }
326
327         /*
328          * Set up the new connection and reply to the client
329          */
330         cp = (client *)malloc(sizeof *cp);
331         bzero(cp, sizeof(*cp));
332         cp->action = CL_ACCEPT;
333         cp->con = newconn;
334         cp->id = counter++;
335         cp->args = NULL;
336         cp->clname[0] = NULL;
337         cp->reply.mr_argv = NULL;
338         cp->first = NULL;
339         cp->last = NULL;
340         cp->last_time_used = now;
341         newconn = NULL;
342         
343         cp->pending_op = create_operation();
344         reset_operation(cp->pending_op);
345         oplist_append(&op_list, cp->pending_op);
346         cur_client = cp;
347         
348         /*
349          * Add a new client to the array..
350          */
351         clist_append(cp);
352         
353         /*
354          * Let him know we heard him.
355          */
356         start_replying_to_client(cp->pending_op, cp->con, GDB_ACCEPTED,
357                                  "", "");
358
359         cp->haddr = client_addr;
360         
361         /*
362          * Log new connection.
363          */
364         
365         com_err(whoami, 0, "New connection from %s port %d (now %d client%s)",
366                 inet_ntoa(cp->haddr.sin_addr),
367                 (int)ntohs(cp->haddr.sin_port),
368                 nclients,
369                 nclients!=1?"s":"");
370         
371         /*
372          * Get ready to accept the next connection.
373          */
374         reset_operation(listenop);
375         client_addrlen = sizeof(client_addr);
376
377         start_accepting_client(listencon, listenop, &newconn,
378                                (char *)&client_addr,
379                                &client_addrlen, &client_tuple);
380         return 0;
381 }
382
383 /*
384  * Add a new client to the known clients.
385  */
386 void
387 clist_append(cp)
388         client *cp;
389 {               
390         client **clients_n;
391         
392         nclients++;
393         clients_n = (client **)malloc
394                 ((unsigned)(nclients * sizeof(client *)));
395         bcopy((char *)clients, (char *)clients_n, (nclients-1)*sizeof(cp));
396         clients_n[nclients-1] = cp;
397         free((char *)clients);
398         clients = clients_n;
399         clients_n = NULL;
400 }
401
402                 
403 void
404 clist_delete(cp)
405         client *cp;
406 {
407         client **clients_n, **scpp, **dcpp; /* source and dest client */
408                                             /* ptr ptr */
409         
410         int found_it = 0;
411         
412         clients_n = (client **)malloc
413                 ((unsigned)((nclients - 1)* sizeof(client *)));
414         for (scpp = clients, dcpp = clients_n; scpp < clients+nclients; ) {
415                 if (*scpp != cp) {
416                         *dcpp++ = *scpp++;
417                 } else {
418                         scpp++;
419                         if (found_it) abort();
420                         found_it = 1;
421                 }                       
422         }
423         --nclients;     
424         free((char *)clients);
425         clients = clients_n;
426         clients_n = NULL;
427         oplist_delete(op_list, cp->pending_op);
428         reset_operation(cp->pending_op);
429         delete_operation(cp->pending_op);
430         sever_connection(cp->con);
431         free((char *)cp);
432 }
433
434 /*
435  * Add a new operation to a list of operations.
436  *
437  * This should be rewritten to use realloc instead, since in most
438  * cases it won't have to copy the array.
439  */
440
441 void
442 oplist_append(oplp, op)
443         LIST_OF_OPERATIONS *oplp;
444         OPERATION op;
445 {
446         int count = (*oplp)->count+1;
447         LIST_OF_OPERATIONS newlist = (LIST_OF_OPERATIONS)
448                 db_alloc(size_of_list_of_operations(count));
449         bcopy((char *)(*oplp), (char *)newlist,
450               size_of_list_of_operations((*oplp)->count));
451         newlist->count++;
452         newlist->op[count-1] = op;
453         db_free((char *)(*oplp), size_of_list_of_operations(count-1));
454         (*oplp) = newlist;
455 }
456
457
458 oplist_delete(oplp, op)
459         LIST_OF_OPERATIONS oplp;
460         register OPERATION op;
461 {
462         register OPERATION *s;
463         register int c;
464         
465         for (s = oplp->op, c=oplp->count; c; --c, ++s) {
466                 if (*s == op) {
467                         while (c > 0) {
468                                 *s = *(s+1);
469                                 ++s;
470                                 --c;
471                         }
472                         oplp->count--;
473                         return;
474                 }
475         }
476         abort();
477 }
478
479
480 void reapchild()
481 {
482     union wait status;
483     int pid;
484
485     while ((pid = wait3(&status, WNOHANG, (struct rusage *)0)) > 0) {
486         if (pid == inc_pid)
487           inc_running = 0;
488         if  (!takedown && (status.w_termsig != 0 || status.w_retcode != 0))
489           com_err(whoami, 0, "%d: child exits with signal %d status %d",
490                   pid, status.w_termsig, status.w_retcode);
491     }
492 }
493
494
495 void godormant()
496 {
497     switch (dormant) {
498     case AWAKE:
499     case GROGGY:
500         com_err(whoami, 0, "requested to go dormant");
501         break;
502     case ASLEEP:
503         com_err(whoami, 0, "already asleep");
504         break;
505     case SLEEPY:
506         break;
507     }
508     dormant = SLEEPY;
509 }
510
511
512 void gowakeup()
513 {
514     switch (dormant) {
515     case ASLEEP:
516     case SLEEPY:
517         com_err(whoami, 0, "Good morning");
518         break;
519     case AWAKE:
520         com_err(whoami, 0, "already awake");
521         break;
522     case GROGGY:
523         break;
524     }
525     dormant = GROGGY;
526 }
527
528         
529 mr_setup_signals()
530 {
531     /* There should probably be a few more of these. */
532         
533     if ((((int)signal (SIGTERM, sigshut)) < 0) ||
534         (((int)signal (SIGCHLD, reapchild)) < 0) ||
535         (((int)signal (SIGUSR1, godormant)) < 0) ||
536         (((int)signal (SIGUSR2, gowakeup)) < 0) ||
537         (((int)signal (SIGHUP, sigshut)) < 0)) {
538         com_err(whoami, errno, " Unable to establish signal handlers.");
539         exit(1);
540     }
541 }
This page took 0.098218 seconds and 5 git commands to generate.