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