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