X-Git-Url: http://andersk.mit.edu/gitweb/moira.git/blobdiff_plain/14e2d5ce48c0a3b3760cd010a95030b060c9a7ad..8e3761a291f20f12754477e7e05514e1117d2344:/server/mr_main.c diff --git a/server/mr_main.c b/server/mr_main.c index 479c1ae3..08b76128 100644 --- a/server/mr_main.c +++ b/server/mr_main.c @@ -1,541 +1,463 @@ -/* - * $Source$ - * $Author$ - * $Header$ - * - * Copyright (C) 1987 by the Massachusetts Institute of Technology - * For copying and distribution information, please see the file - * . +/* $Id$ * - * MOIRA server process. + * Moira server process. * - * Most of this is stolen from ../gdb/tsr.c + * Copyright (C) 1987-1998 by the Massachusetts Institute of Technology + * For copying and distribution information, please see the file + * . * - * You are in a maze of twisty little finite automata, all different. - * Let the reader beware. - * */ -static char *rcsid_mr_main_c = "$Header$"; - #include -#include +#include "mr_server.h" + +#include +#include #include -#include -#include +#include #include -#include -#include "mr_server.h" -#include -extern CONNECTION newconn, listencon; +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +RCSID("$Header$"); -extern int nclients; -extern client **clients, *cur_client; +client *cur_client; -extern OPERATION listenop; -extern LIST_OF_OPERATIONS op_list; +char *whoami; +char *takedown; +FILE *journal; -extern struct sockaddr_in client_addr; -extern int client_addrlen; -extern TUPLE client_tuple; +time_t now; -extern char *whoami; -extern char buf1[BUFSIZ]; -extern char *takedown; -extern int errno; -extern FILE *journal; +char *host; +char krb_realm[REALM_SZ]; -extern char *malloc(); -extern int free(); -extern char *inet_ntoa(); -extern void mr_com_err(); -extern void do_client(); +/* Client array and associated data. This needs to be global for _list_users */ +client **clients; +int nclients, clientssize; -extern int sigshut(); -void clist_append(); -void oplist_append(); -void reapchild(), godormant(), gowakeup(); +int dormant; -extern time_t now; +void reapchild(int x); +void godormant(int x); +void gowakeup(int x); +void clist_append(client *cp); +void mr_setup_signals(void); /* - * Main MOIRA server loop. + * Main Moira server loop. * * Initialize the world, then start accepting connections and * making progress on current connections. */ -/*ARGSUSED*/ -int -main(argc, argv) - int argc; - char **argv; +int main(int argc, char **argv) { - int status; - time_t tardy; - struct stat stbuf; - - whoami = argv[0]; - /* - * Error handler init. - */ - initialize_sms_error_table(); - initialize_krb_error_table(); - set_com_err_hook(mr_com_err); - setlinebuf(stderr); - - if (argc != 1) { - com_err(whoami, 0, "Usage: moirad"); - exit(1); - } - - /* Profiling implies that getting rid of one level of call - * indirection here wins us maybe 1% on the VAX. - */ - gdb_amv = malloc; - gdb_fmv = free; - - /* - * GDB initialization. - */ - if(gdb_init() != 0) { - com_err(whoami, 0, "GDB initialization failed."); - exit(1); + int status, i, listener; + time_t tardy; + char *port, *p; + extern char *database; + struct stat stbuf; + struct utsname uts; + fd_set readfds, writefds, xreadfds, xwritefds; + int nfds, counter = 0; + + whoami = argv[0]; + /* + * Error handler init. + */ + mr_init(); + set_com_err_hook(mr_com_err); + setvbuf(stderr, NULL, _IOLBF, BUFSIZ); + + port = strchr(MOIRA_SERVER, ':') + 1; + + for (i = 1; i < argc; i++) + { + if (!strcmp(argv[i], "-db") && i + 1 < argc) + { + database = argv[i + 1]; + i++; } - gdb_debug(0); /* this can be patched, if necessary, to enable */ - /* GDB level debugging .. */ - krb_realm = malloc(REALM_SZ); - krb_get_lrealm(krb_realm, 1); - - /* - * Database initialization. Only init if database should be open. - */ - - if (stat(MOIRA_MOTD_FILE, &stbuf) != 0) { - if ((status = mr_open_database()) != 0) { - com_err(whoami, status, " when trying to open database."); - exit(1); - } - sanity_check_database(); - } else { - dormant = ASLEEP; - com_err(whoami, 0, "sleeping, not opening database"); + else if (!strcmp(argv[i], "-p") && i + 1 < argc) + { + port = argv[i + 1]; + i++; } - - sanity_check_queries(); - - /* - * Set up client array handler. - */ - nclients = 0; - clients = (client **) malloc(0); - - mr_setup_signals(); - - journal = fopen(JOURNAL, "a"); - if (journal == NULL) { - com_err(whoami, errno, " while opening journal file"); - exit(1); + else + { + com_err(whoami, 0, "Usage: moirad [-db database][-p port]"); + exit(1); } + } - /* - * Establish template connection. - */ - if ((status = do_listen()) != 0) { - com_err(whoami, status, - " while trying to create listening connection"); - exit(1); - } - - op_list = create_list_of_operations(1, listenop); - - com_err(whoami, 0, "started (pid %d)", getpid()); - com_err(whoami, 0, rcsid_mr_main_c); - if (dormant != ASLEEP) - send_zgram("MOIRA", "server started"); - else - send_zgram("MOIRA", "server started, but database closed"); - - /* - * Run until shut down. - */ - while(!takedown) { - register int i; - /* - * Block until something happens. - */ -#ifdef notdef - com_err(whoami, 0, "tick"); -#endif notdef - if (dormant == SLEEPY) { - mr_close_database(); - com_err(whoami, 0, "database closed"); - mr_setup_signals(); - send_zgram("MOIRA", "database closed"); - dormant = ASLEEP; - } else if (dormant == GROGGY) { - mr_open_database(); - com_err(whoami, 0, "database open"); - mr_setup_signals(); - send_zgram("MOIRA", "database open again"); - dormant = AWAKE; - } + krb_get_lrealm(krb_realm, 1); - errno = 0; - status = op_select_any(op_list, 0, - (fd_set *)NULL, (fd_set *)NULL, - (fd_set *)NULL, (struct timeval *)NULL); - - if (status == -1) { - if (errno != EINTR) - com_err(whoami, errno, " error from op_select"); - if (!inc_running || now - inc_started > INC_TIMEOUT) - next_incremental(); - continue; - } else if (status != -2) { - com_err(whoami, 0, " wrong return from op_select_any"); - continue; - } - if (takedown) break; - time(&now); - if (!inc_running || now - inc_started > INC_TIMEOUT) - next_incremental(); -#ifdef notdef - fprintf(stderr, " tick\n"); -#endif notdef - /* - * Handle any new connections; this comes first so - * errno isn't tromped on. - */ - if (OP_DONE(listenop)) { - if (OP_STATUS(listenop) == OP_CANCELLED) { - if (errno == EWOULDBLOCK) { - do_reset_listen(); - } else { - static int count = 0; - com_err(whoami, errno, - " error (%d) on listen", count); - if (count++ > 10) - exit(1); - } - } else if ((status = new_connection()) != 0) { - com_err(whoami, errno, - " Error on listening operation."); - /* - * Sleep here to prevent hosing? - */ - } - /* if the new connection is our only connection, - * and the server is supposed to be down, then go - * down now. - */ - if ((dormant == AWAKE) && (nclients == 1) && - (stat(MOIRA_MOTD_FILE, &stbuf) == 0)) { - com_err(whoami, 0, "motd file exists, slumbertime"); - dormant = SLEEPY; - } - /* on new connection, if we are no longer supposed - * to be down, then wake up. - */ - if ((dormant == ASLEEP) && - (stat(MOIRA_MOTD_FILE, &stbuf) == -1) && - (errno == ENOENT)) { - com_err(whoami, 0, "motd file no longer exists, waking up"); - dormant = GROGGY; - } - - } - /* - * Handle any existing connections. - */ - tardy = now - 30*60; - - for (i=0; ipending_op)) { - cur_client->last_time_used = now; - do_client(cur_client); - } else if (clients[i]->last_time_used < tardy) { - com_err(whoami, 0, "Shutting down connection due to inactivity"); - shutdown(cur_client->con->in.fd, 0); - } - cur_client = NULL; - if (takedown) break; - } + /* + * Database initialization. Only init if database should be open. + */ + + if (stat(MOIRA_MOTD_FILE, &stbuf) != 0) + { + if ((status = mr_open_database())) + { + com_err(whoami, status, "trying to open database."); + exit(1); } - com_err(whoami, 0, "%s", takedown); - mr_close_database(); - send_zgram("MOIRA", takedown); - return 0; -} + sanity_check_database(); + } + else + { + dormant = ASLEEP; + com_err(whoami, 0, "sleeping, not opening database"); + } -/* - * Set up the template connection and queue the first accept. - */ + sanity_check_queries(); -int -do_listen() -{ - char *service = index(MOIRA_SERVER, ':') + 1; + /* + * Get moira server hostname for authentication + */ + if (uname(&uts) < 0) + { + com_err(whoami, errno, "Unable to get local hostname"); + exit(1); + } + host = canonicalize_hostname(xstrdup(uts.nodename)); + for (p = host; *p && *p != '.'; p++) + { + if (isupper(*p)) + *p = tolower(*p); + } + *p = '\0'; + + /* + * Set up client array handler. + */ + nclients = 0; + clientssize = 10; + clients = xmalloc(clientssize * sizeof(client *)); + + mr_setup_signals(); + + journal = fopen(JOURNAL, "a"); + if (!journal) + { + com_err(whoami, errno, "opening journal file"); + exit(1); + } - listencon = create_listening_connection(service); + /* + * Establish template connection. + */ + listener = mr_listen(port); + if (listener == -1) + { + com_err(whoami, MR_ABORTED, "trying to create listening connection"); + exit(1); + } + FD_ZERO(&xreadfds); + FD_ZERO(&xwritefds); + FD_SET(listener, &xreadfds); + nfds = listener + 1; + + com_err(whoami, 0, "started (pid %d)", getpid()); + com_err(whoami, 0, rcsid); + if (dormant != ASLEEP) + send_zgram("MOIRA", "server started"); + else + send_zgram("MOIRA", "server started, but database closed"); + + /* + * Run until shut down. + */ + while (!takedown) + { + int i; + struct timeval timeout = {60, 0}; /* 1 minute */ + + /* If we're supposed to go down and we can, do it */ + if (((dormant == AWAKE) && (nclients == 0) && + (stat(MOIRA_MOTD_FILE, &stbuf) == 0)) || + (dormant == SLEEPY)) + { + mr_close_database(); + com_err(whoami, 0, "database closed"); + mr_setup_signals(); + send_zgram("MOIRA", "database closed"); + dormant = ASLEEP; + } - if (listencon == NULL) - return errno; + /* Block until something happens. */ + memcpy(&readfds, &xreadfds, sizeof(readfds)); + memcpy(&writefds, &xwritefds, sizeof(writefds)); + if (select(nfds, &readfds, &writefds, NULL, &timeout) == -1) + { + if (errno != EINTR) + com_err(whoami, errno, "in select"); + if (!inc_running || now - inc_started > INC_TIMEOUT) + next_incremental(); + continue; + } - listenop = create_operation(); - client_addrlen = sizeof(client_addr); + if (takedown) + break; + time(&now); + if (!inc_running || now - inc_started > INC_TIMEOUT) + next_incremental(); + tardy = now - 30 * 60; + + /* If we're asleep and we should wake up, do it */ + if ((dormant == ASLEEP) && (stat(MOIRA_MOTD_FILE, &stbuf) == -1) && + (errno == ENOENT)) + { + mr_open_database(); + com_err(whoami, 0, "database open"); + mr_setup_signals(); + send_zgram("MOIRA", "database open again"); + dormant = AWAKE; + } - start_accepting_client(listencon, listenop, &newconn, - (char *)&client_addr, - &client_addrlen, &client_tuple); - return 0; -} + /* Handle any new connections */ + if (FD_ISSET(listener, &readfds)) + { + int newconn, addrlen = sizeof(struct sockaddr_in); + struct sockaddr_in addr; + client *cp; + + newconn = accept(listener, (struct sockaddr *)&addr, &addrlen); + if (newconn == -1) + com_err(whoami, errno, "accepting new connection"); + else if (newconn > 0) + { + if (newconn + 1 > nfds) + nfds = newconn + 1; + FD_SET(newconn, &xreadfds); + + /* Add a new client to the array */ + nclients++; + if (nclients > clientssize) + { + clientssize = 2 * clientssize; + clients = xrealloc(clients, clientssize * sizeof(client *)); + } + clients[nclients - 1] = cp = xmalloc(sizeof(client)); + memset(cp, 0, sizeof(client)); + cp->con = newconn; + cp->id = counter++; + cp->last_time_used = now; + cp->haddr = addr; + cp->tuplessize = 1; + cp->tuples = xmalloc(sizeof(mr_params)); + memset(cp->tuples, 0, sizeof(mr_params)); + cp->state = CL_ACCEPTING; + cp->version = 2; + + cur_client = cp; + com_err(whoami, 0, + "New connection from %s port %d (now %d client%s)", + inet_ntoa(cp->haddr.sin_addr), + (int)ntohs(cp->haddr.sin_port), + nclients, nclients != 1 ? "s" : ""); + } + } -do_reset_listen() -{ - client_addrlen = sizeof(client_addr); - start_accepting_client(listencon, listenop, &newconn, - (char *)&client_addr, - &client_addrlen, &client_tuple); -} + /* Handle any existing connections. */ + for (i = 0; i < nclients; i++) + { + cur_client = clients[i]; + + if (FD_ISSET(clients[i]->con, &writefds)) + { + client_write(clients[i]); + if (!clients[i]->ntuples) + { + FD_CLR(clients[i]->con, &xwritefds); + FD_SET(clients[i]->con, &xreadfds); + } + clients[i]->last_time_used = now; + } -/* - * This routine is called when a new connection comes in. - * - * It sets up a new client and adds it to the list of currently active clients. - */ -int -new_connection() -{ - register client *cp; - static counter = 0; - - /* - * Make sure there's been no error - */ - if(OP_STATUS(listenop) != OP_COMPLETE) { - return errno; - } - - if (newconn == NULL) { - return MR_NOT_CONNECTED; - } + if (FD_ISSET(clients[i]->con, &readfds)) + { + if (clients[i]->state == CL_ACCEPTING) + { + switch(mr_cont_accept(clients[i]->con, + &clients[i]->hsbuf, + &clients[i]->hslen)) + { + case -1: + break; + + case 0: + clients[i]->state = CL_CLOSING; + break; + + default: + clients[i]->state = CL_ACTIVE; + clients[i]->hsbuf = NULL; + break; + } + } + else + { + client_read(clients[i]); + if (clients[i]->ntuples) + { + FD_CLR(clients[i]->con, &xreadfds); + FD_SET(clients[i]->con, &xwritefds); + } + clients[i]->last_time_used = now; + } + } - /* - * Set up the new connection and reply to the client - */ - cp = (client *)malloc(sizeof *cp); - bzero(cp, sizeof(*cp)); - cp->action = CL_ACCEPT; - cp->con = newconn; - cp->id = counter++; - cp->args = NULL; - cp->clname[0] = NULL; - cp->reply.mr_argv = NULL; - cp->first = NULL; - cp->last = NULL; - cp->last_time_used = now; - newconn = NULL; - - cp->pending_op = create_operation(); - reset_operation(cp->pending_op); - oplist_append(&op_list, cp->pending_op); - cur_client = cp; - - /* - * Add a new client to the array.. - */ - clist_append(cp); - - /* - * Let him know we heard him. - */ - start_replying_to_client(cp->pending_op, cp->con, GDB_ACCEPTED, - "", ""); - - cp->haddr = client_addr; - - /* - * Log new connection. - */ - - com_err(whoami, 0, "New connection from %s port %d (now %d client%s)", - inet_ntoa(cp->haddr.sin_addr), - (int)ntohs(cp->haddr.sin_port), - nclients, - nclients!=1?"s":""); - - /* - * Get ready to accept the next connection. - */ - reset_operation(listenop); - client_addrlen = sizeof(client_addr); - - start_accepting_client(listencon, listenop, &newconn, - (char *)&client_addr, - &client_addrlen, &client_tuple); - return 0; -} + if (clients[i]->last_time_used < tardy) + { + com_err(whoami, 0, "Shutting down connection due to inactivity"); + clients[i]->state = CL_CLOSING; + } -/* - * Add a new client to the known clients. - */ -void -clist_append(cp) - client *cp; -{ - client **clients_n; - - nclients++; - clients_n = (client **)malloc - ((unsigned)(nclients * sizeof(client *))); - bcopy((char *)clients, (char *)clients_n, (nclients-1)*sizeof(cp)); - clients_n[nclients-1] = cp; - free((char *)clients); - clients = clients_n; - clients_n = NULL; -} + if (clients[i]->state == CL_CLOSING) + { + client *old; + + com_err(whoami, 0, "Closed connection (now %d client%s, " + "%d queries)", nclients - 1, nclients != 2 ? "s" : "", + newqueries); + + shutdown(clients[i]->con, 2); + close(clients[i]->con); + FD_CLR(clients[i]->con, &xreadfds); + FD_CLR(clients[i]->con, &xwritefds); + free_rtn_tuples(clients[i]); + free(clients[i]->tuples); + free(clients[i]->hsbuf); + old = clients[i]; + clients[i] = clients[--nclients]; + free(old); + } - -void -clist_delete(cp) - client *cp; -{ - client **clients_n, **scpp, **dcpp; /* source and dest client */ - /* ptr ptr */ - - int found_it = 0; - - clients_n = (client **)malloc - ((unsigned)((nclients - 1)* sizeof(client *))); - for (scpp = clients, dcpp = clients_n; scpp < clients+nclients; ) { - if (*scpp != cp) { - *dcpp++ = *scpp++; - } else { - scpp++; - if (found_it) abort(); - found_it = 1; - } + cur_client = NULL; + if (takedown) + break; } - --nclients; - free((char *)clients); - clients = clients_n; - clients_n = NULL; - oplist_delete(op_list, cp->pending_op); - reset_operation(cp->pending_op); - delete_operation(cp->pending_op); - sever_connection(cp->con); - free((char *)cp); -} - -/* - * Add a new operation to a list of operations. - * - * This should be rewritten to use realloc instead, since in most - * cases it won't have to copy the array. - */ + } -void -oplist_append(oplp, op) - LIST_OF_OPERATIONS *oplp; - OPERATION op; -{ - int count = (*oplp)->count+1; - LIST_OF_OPERATIONS newlist = (LIST_OF_OPERATIONS) - db_alloc(size_of_list_of_operations(count)); - bcopy((char *)(*oplp), (char *)newlist, - size_of_list_of_operations((*oplp)->count)); - newlist->count++; - newlist->op[count-1] = op; - db_free((char *)(*oplp), size_of_list_of_operations(count-1)); - (*oplp) = newlist; + com_err(whoami, 0, "%s", takedown); + if (dormant != ASLEEP) + mr_close_database(); + send_zgram("MOIRA", takedown); + return 0; } - -oplist_delete(oplp, op) - LIST_OF_OPERATIONS oplp; - register OPERATION op; +void reapchild(int x) { - register OPERATION *s; - register int c; - - for (s = oplp->op, c=oplp->count; c; --c, ++s) { - if (*s == op) { - while (c > 0) { - *s = *(s+1); - ++s; - --c; - } - oplp->count--; - return; - } + int status, pid; + + while ((pid = waitpid(-1, &status, WNOHANG)) > 0) + { + if (pid == inc_pid) + inc_running = 0; + if (!takedown && (WTERMSIG(status) != 0 || WEXITSTATUS(status) != 0)) + { + critical_alert("moirad", "%d: child exits with signal %d status %d", + pid, WTERMSIG(status), WEXITSTATUS(status)); } - abort(); -} - - -void reapchild() -{ - union wait status; - int pid; - - while ((pid = wait3(&status, WNOHANG, (struct rusage *)0)) > 0) { - if (pid == inc_pid) - inc_running = 0; - if (!takedown && (status.w_termsig != 0 || status.w_retcode != 0)) - com_err(whoami, 0, "%d: child exits with signal %d status %d", - pid, status.w_termsig, status.w_retcode); } } -void godormant() +void godormant(int x) { - switch (dormant) { + switch (dormant) + { case AWAKE: case GROGGY: - com_err(whoami, 0, "requested to go dormant"); - break; + com_err(whoami, 0, "requested to go dormant"); + break; case ASLEEP: - com_err(whoami, 0, "already asleep"); - break; + com_err(whoami, 0, "already asleep"); + break; case SLEEPY: - break; + break; } - dormant = SLEEPY; + dormant = SLEEPY; } -void gowakeup() +void gowakeup(int x) { - switch (dormant) { + switch (dormant) + { case ASLEEP: case SLEEPY: - com_err(whoami, 0, "Good morning"); - break; + com_err(whoami, 0, "Good morning"); + break; case AWAKE: - com_err(whoami, 0, "already awake"); - break; + com_err(whoami, 0, "already awake"); + break; case GROGGY: - break; + break; } - dormant = GROGGY; + dormant = GROGGY; } - -mr_setup_signals() + +void mr_setup_signals(void) { - /* There should probably be a few more of these. */ - - if ((((int)signal (SIGTERM, sigshut)) < 0) || - (((int)signal (SIGCHLD, reapchild)) < 0) || - (((int)signal (SIGUSR1, godormant)) < 0) || - (((int)signal (SIGUSR2, gowakeup)) < 0) || - (((int)signal (SIGHUP, sigshut)) < 0)) { - com_err(whoami, errno, " Unable to establish signal handlers."); - exit(1); + struct sigaction action; + + action.sa_flags = 0; + sigemptyset(&action.sa_mask); + + /* There should probably be a few more of these. */ + + action.sa_handler = sigshut; + if ((sigaction(SIGTERM, &action, NULL) < 0) || + (sigaction(SIGINT, &action, NULL) < 0) || + (sigaction(SIGHUP, &action, NULL) < 0)) + { + com_err(whoami, errno, "Unable to establish signal handlers."); + exit(1); + } + + action.sa_handler = godormant; + if (sigaction(SIGUSR1, &action, NULL) < 0) + { + com_err(whoami, errno, "Unable to establish signal handlers."); + exit(1); + } + + action.sa_handler = gowakeup; + if (sigaction(SIGUSR2, &action, NULL) < 0) + { + com_err(whoami, errno, "Unable to establish signal handlers."); + exit(1); + } + + action.sa_handler = SIG_IGN; + if (sigaction(SIGPIPE, &action, NULL) < 0) + { + com_err(whoami, errno, "Unable to establish signal handlers."); + exit(1); + } + + action.sa_handler = reapchild; + sigaddset(&action.sa_mask, SIGCHLD); + if (sigaction(SIGCHLD, &action, NULL) < 0) + { + com_err(whoami, errno, "Unable to establish signal handlers."); + exit(1); } }