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