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