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