]> andersk Git - moira.git/blob - server/mr_main.c
Being on the membership acl should be sufficient to use tmol.
[moira.git] / server / mr_main.c
1 /* $Id$
2  *
3  * Moira server process.
4  *
5  * Copyright (C) 1987-1998 by the Massachusetts Institute of Technology
6  * For copying and distribution information, please see the file
7  * <mit-copyright.h>.
8  *
9  */
10
11 #include <mit-copyright.h>
12 #include "mr_server.h"
13
14 #include <sys/socket.h>
15 #include <sys/stat.h>
16 #include <sys/types.h>
17 #include <sys/utsname.h>
18 #include <sys/wait.h>
19
20 #include <netinet/in.h>
21 #include <arpa/inet.h>
22
23 #include <ctype.h>
24 #include <errno.h>
25 #include <signal.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <unistd.h>
30
31 #include <krb.h>
32
33 RCSID("$Header$");
34
35 client *cur_client;
36
37 char *whoami;
38 char *takedown;
39 FILE *journal;
40
41 time_t now;
42
43 char *host;
44 char krb_realm[REALM_SZ];
45
46 /* Client array and associated data. This needs to be global for _list_users */
47 client **clients;
48 int nclients, clientssize;
49
50 int dormant;
51
52 void reapchild(int x);
53 void godormant(int x);
54 void gowakeup(int x);
55 void clist_append(client *cp);
56 void mr_setup_signals(void);
57
58 /*
59  * Main Moira server loop.
60  *
61  * Initialize the world, then start accepting connections and
62  * making progress on current connections.
63  */
64
65 int main(int argc, char **argv)
66 {
67   int status, i, listener;
68   time_t tardy;
69   char *port, *p;
70   extern char *database;
71   struct stat stbuf;
72   struct utsname uts;
73   fd_set readfds, writefds, xreadfds, xwritefds;
74   int nfds, counter = 0;
75
76   whoami = argv[0];
77   /*
78    * Error handler init.
79    */
80   mr_init();
81   set_com_err_hook(mr_com_err);
82   setvbuf(stderr, NULL, _IOLBF, BUFSIZ);
83
84   port = strchr(MOIRA_SERVER, ':') + 1;
85
86   for (i = 1; i < argc; i++)
87     {
88       if (!strcmp(argv[i], "-db") && i + 1 < argc)
89         {
90           database = argv[i + 1];
91           i++;
92         }
93       else if (!strcmp(argv[i], "-p") && i + 1 < argc)
94         {
95           port = argv[i + 1];
96           i++;
97         }
98       else
99         {
100           com_err(whoami, 0, "Usage: moirad [-db database][-p port]");
101           exit(1);
102         }
103     }
104
105   krb_get_lrealm(krb_realm, 1);
106
107   /*
108    * Database initialization.  Only init if database should be open.
109    */
110
111   if (stat(MOIRA_MOTD_FILE, &stbuf) != 0)
112     {
113       if ((status = mr_open_database()))
114         {
115           com_err(whoami, status, "trying to open database.");
116           exit(1);
117         }
118       sanity_check_database();
119     }
120   else
121     {
122       dormant = ASLEEP;
123       com_err(whoami, 0, "sleeping, not opening database");
124     }
125
126   sanity_check_queries();
127
128   /*
129    * Get moira server hostname for authentication
130    */
131   if (uname(&uts) < 0)
132     {
133       com_err(whoami, errno, "Unable to get local hostname");
134       exit(1);
135     }
136   host = canonicalize_hostname(xstrdup(uts.nodename));
137   for (p = host; *p && *p != '.'; p++)
138     {
139       if (isupper(*p))
140         *p = tolower(*p);
141     }
142   *p = '\0';
143
144   /*
145    * Set up client array handler.
146    */
147   nclients = 0;
148   clientssize = 10;
149   clients = xmalloc(clientssize * sizeof(client *));
150
151   mr_setup_signals();
152
153   journal = fopen(JOURNAL, "a");
154   if (!journal)
155     {
156       com_err(whoami, errno, "opening journal file");
157       exit(1);
158     }
159
160   /*
161    * Establish template connection.
162    */
163   listener = mr_listen(port);
164   if (listener == -1)
165     {
166       com_err(whoami, status, "trying to create listening connection");
167       exit(1);
168     }
169   FD_ZERO(&xreadfds);
170   FD_ZERO(&xwritefds);
171   FD_SET(listener, &xreadfds);
172   nfds = listener + 1;
173
174   com_err(whoami, 0, "started (pid %d)", getpid());
175   com_err(whoami, 0, rcsid);
176   if (dormant != ASLEEP)
177     send_zgram("MOIRA", "server started");
178   else
179     send_zgram("MOIRA", "server started, but database closed");
180
181   /*
182    * Run until shut down.
183    */
184   while (!takedown)
185     {
186       int i;
187       struct timeval timeout = {60, 0}; /* 1 minute */
188
189       /* If we're supposed to go down and we can, do it */
190       if (((dormant == AWAKE) && (nclients == 0) &&
191            (stat(MOIRA_MOTD_FILE, &stbuf) == 0)) ||
192           (dormant == SLEEPY))
193         {
194           mr_close_database();
195           com_err(whoami, 0, "database closed");
196           mr_setup_signals();
197           send_zgram("MOIRA", "database closed");
198           dormant = ASLEEP;
199         }
200
201       /* Block until something happens. */
202       memcpy(&readfds, &xreadfds, sizeof(readfds));
203       memcpy(&writefds, &xwritefds, sizeof(writefds));
204       if (select(nfds, &readfds, &writefds, NULL, &timeout) == -1)
205         {
206           if (errno != EINTR)
207             com_err(whoami, errno, "in select");
208           if (!inc_running || now - inc_started > INC_TIMEOUT)
209             next_incremental();
210           continue;
211         }
212
213       if (takedown)
214         break;
215       time(&now);
216       if (!inc_running || now - inc_started > INC_TIMEOUT)
217         next_incremental();
218       tardy = now - 30 * 60;
219
220       /* If we're asleep and we should wake up, do it */
221       if ((dormant == ASLEEP) && (stat(MOIRA_MOTD_FILE, &stbuf) == -1) &&
222           (errno == ENOENT))
223         {
224           mr_open_database();
225           com_err(whoami, 0, "database open");
226           mr_setup_signals();
227           send_zgram("MOIRA", "database open again");
228           dormant = AWAKE;
229         }
230
231       /* Handle any new connections */
232       if (FD_ISSET(listener, &readfds))
233         {
234           int newconn, addrlen = sizeof(struct sockaddr_in);
235           struct sockaddr_in addr;
236           client *cp;
237
238           newconn = accept(listener, (struct sockaddr *)&addr, &addrlen);
239           if (newconn == -1)
240             com_err(whoami, errno, "accepting new connection");
241           else if (newconn > 0)
242             {
243               if (newconn + 1 > nfds)
244                 nfds = newconn + 1;
245               FD_SET(newconn, &xreadfds);
246
247               /* Add a new client to the array */
248               nclients++;
249               if (nclients > clientssize)
250                 {
251                   clientssize = 2 * clientssize;
252                   clients = xrealloc(clients, clientssize * sizeof(client *));
253                 }
254
255               clients[nclients - 1] = cp = xmalloc(sizeof(client));
256               memset(cp, 0, sizeof(client));
257               cp->con = newconn;
258               cp->id = counter++;
259               cp->last_time_used = now;
260               cp->haddr = addr;
261               cp->tuplessize = 1;
262               cp->tuples = xmalloc(sizeof(mr_params));
263               memset(cp->tuples, 0, sizeof(mr_params));
264               cp->state = CL_ACCEPTING;
265               cp->version = 2;
266
267               cur_client = cp;
268               com_err(whoami, 0,
269                       "New connection from %s port %d (now %d client%s)",
270                       inet_ntoa(cp->haddr.sin_addr),
271                       (int)ntohs(cp->haddr.sin_port),
272                       nclients, nclients != 1 ? "s" : "");
273             }
274         }
275
276       /* Handle any existing connections. */
277       for (i = 0; i < nclients; i++)
278         {
279           cur_client = clients[i];
280
281           if (FD_ISSET(clients[i]->con, &writefds))
282             {
283               client_write(clients[i]);
284               if (!clients[i]->ntuples)
285                 {
286                   FD_CLR(clients[i]->con, &xwritefds);
287                   FD_SET(clients[i]->con, &xreadfds);
288                 }
289               clients[i]->last_time_used = now;
290             }
291
292           if (FD_ISSET(clients[i]->con, &readfds))
293             {
294               if (clients[i]->state == CL_ACCEPTING)
295                 {
296                   switch(mr_cont_accept(clients[i]->con,
297                                         &clients[i]->hsbuf,
298                                         &clients[i]->hslen))
299                     {
300                     case -1:
301                       break;
302
303                     case 0:
304                       clients[i]->state = CL_CLOSING;
305                       break;
306
307                     default:
308                       clients[i]->state = CL_ACTIVE;
309                       clients[i]->hsbuf = NULL;
310                       break;
311                     }
312                 }
313               else
314                 {
315                   client_read(clients[i]);
316                   if (clients[i]->ntuples)
317                     {
318                       FD_CLR(clients[i]->con, &xreadfds);
319                       FD_SET(clients[i]->con, &xwritefds);
320                     }
321                   clients[i]->last_time_used = now;
322                 }
323             }
324
325           if (clients[i]->last_time_used < tardy)
326             {
327               com_err(whoami, 0, "Shutting down connection due to inactivity");
328               clients[i]->state = CL_CLOSING;
329             }
330
331           if (clients[i]->state == CL_CLOSING)
332             {
333               client *old;
334
335               com_err(whoami, 0, "Closed connection (now %d client%s, "
336                       "%d queries)", nclients - 1, nclients != 2 ? "s" : "",
337                       newqueries);
338
339               shutdown(clients[i]->con, 2);
340               close(clients[i]->con);
341               FD_CLR(clients[i]->con, &xreadfds);
342               FD_CLR(clients[i]->con, &xwritefds);
343               free_rtn_tuples(clients[i]);
344               free(clients[i]->tuples);
345               free(clients[i]->hsbuf);
346               old = clients[i];
347               clients[i] = clients[--nclients];
348               free(old);
349             }
350
351           cur_client = NULL;
352           if (takedown)
353             break;
354         }
355     }
356
357   com_err(whoami, 0, "%s", takedown);
358   if (dormant != ASLEEP)
359     mr_close_database();
360   send_zgram("MOIRA", takedown);
361   return 0;
362 }
363
364 void reapchild(int x)
365 {
366   int status, pid;
367
368   while ((pid = waitpid(-1, &status, WNOHANG)) > 0)
369     {
370       if (pid == inc_pid)
371         inc_running = 0;
372       if (!takedown && (WTERMSIG(status) != 0 || WEXITSTATUS(status) != 0))
373         {
374           critical_alert("moirad", "%d: child exits with signal %d status %d",
375                          pid, WTERMSIG(status), WEXITSTATUS(status));
376         }
377     }
378 }
379
380
381 void godormant(int x)
382 {
383   switch (dormant)
384     {
385     case AWAKE:
386     case GROGGY:
387       com_err(whoami, 0, "requested to go dormant");
388       break;
389     case ASLEEP:
390       com_err(whoami, 0, "already asleep");
391       break;
392     case SLEEPY:
393       break;
394     }
395   dormant = SLEEPY;
396 }
397
398
399 void gowakeup(int x)
400 {
401   switch (dormant)
402     {
403     case ASLEEP:
404     case SLEEPY:
405       com_err(whoami, 0, "Good morning");
406       break;
407     case AWAKE:
408       com_err(whoami, 0, "already awake");
409       break;
410     case GROGGY:
411       break;
412     }
413   dormant = GROGGY;
414 }
415
416
417 void mr_setup_signals(void)
418 {
419   struct sigaction action;
420
421   action.sa_flags = 0;
422   sigemptyset(&action.sa_mask);
423
424   /* There should probably be a few more of these. */
425
426   action.sa_handler = sigshut;
427   if ((sigaction(SIGTERM, &action, NULL) < 0) ||
428       (sigaction(SIGINT, &action, NULL) < 0) ||
429       (sigaction(SIGHUP, &action, NULL) < 0))
430     {
431       com_err(whoami, errno, "Unable to establish signal handlers.");
432       exit(1);
433     }
434
435   action.sa_handler = godormant;
436   if (sigaction(SIGUSR1, &action, NULL) < 0)
437     {
438       com_err(whoami, errno, "Unable to establish signal handlers.");
439       exit(1);
440     }
441
442   action.sa_handler = gowakeup;
443   if (sigaction(SIGUSR2, &action, NULL) < 0)
444     {
445       com_err(whoami, errno, "Unable to establish signal handlers.");
446       exit(1);
447     }
448
449   action.sa_handler = SIG_IGN;
450   if (sigaction(SIGPIPE, &action, NULL) < 0)
451     {
452       com_err(whoami, errno, "Unable to establish signal handlers.");
453       exit(1);
454     }
455
456   action.sa_handler = reapchild;
457   sigaddset(&action.sa_mask, SIGCHLD);
458   if (sigaction(SIGCHLD, &action, NULL) < 0)
459     {
460       com_err(whoami, errno, "Unable to establish signal handlers.");
461       exit(1);
462     }
463 }
This page took 0.075179 seconds and 5 git commands to generate.