diff options
author | John Kohl <jtkohl@mit.edu> | 1987-07-09 01:51:04 +0000 |
---|---|---|
committer | John Kohl <jtkohl@mit.edu> | 1987-07-09 01:51:04 +0000 |
commit | 1dda16bcb0d91f90375878b0e446d27ba4fa4164 (patch) | |
tree | 0461a52c11f989953d7f1c4080ca71928a100960 /server/server.c | |
parent | 80d0d769ecfd1bda5e5c4732f8d47b93015b607a (diff) |
lots of new stuff for dealing with multiple servers
Diffstat (limited to 'server/server.c')
-rw-r--r-- | server/server.c | 511 |
1 files changed, 459 insertions, 52 deletions
diff --git a/server/server.c b/server/server.c index b7c01c1..594b195 100644 --- a/server/server.c +++ b/server/server.c @@ -21,10 +21,16 @@ static char rcsid_server_s_c[] = "$Header$"; #include "zserver.h" #include <sys/socket.h> /* for AF_INET */ +#include <netdb.h> /* for gethostbyname */ /* * Server manager. Deal with traffic to and from other servers. * + * void server_init() + * + * + * void server_shutdown() + * * void server_timo(which) * ZServerDesc_t *which; * @@ -45,16 +51,106 @@ static char rcsid_server_s_c[] = "$Header$"; * int auth; * struct sockaddr_in *who; * + * void server_forward(notice, auth, who) + * ZNotice_t *notice; + * int auth; + * struct sockaddr_in *who; + * */ -static void server_hello(), server_flush(), admin_handle(); +static void server_hello(), server_flush(), admin_handle(), setup_server(); +static void hello_respond(), hello_input(), send_msg(); + static Code_t server_register(); +static struct in_addr *get_server_addrs(); +static ZServerDesc_t *which_server(); + +ZServerDesc_t *otherservers; /* points to an array of the known + servers */ +int nservers; /* number of other servers */ +int me_server_idx; /* # of my entry in the array */ /* parameters controlling the transitions of the FSM's--patchable with adb */ int timo_up = TIMO_UP; int timo_tardy = TIMO_TARDY; int timo_dead = TIMO_DEAD; +/* + * Initialize the array of servers. The `limbo' server goes in the first + * slot (otherservers[0]). + * Contact Hesiod to find all the other servers, allocate space for the + * structure, initialize them all to SERV_DEAD with expired timeouts. + */ + +void +server_init() +{ + register int i; + struct in_addr *serv_addr, *hes_addrs, limbo_addr; + + /* talk to hesiod here, set nservers */ + if (!(hes_addrs = get_server_addrs(&nservers))) { + syslog(LOG_ERR, "No servers?!?"); + exit(1); + } + + /* increment servers to make room for 'limbo' */ + nservers++; + + otherservers = (ZServerDesc_t *) xmalloc(nservers * + sizeof(ZServerDesc_t)); + me_server_idx = -1; + + /* set up limbo */ + limbo_addr.s_addr = (unsigned long) 0; + setup_server(otherservers, &limbo_addr); + timer_reset(otherservers[0].zs_timer); + otherservers[0].zs_timer = (timer) NULL; + + for (serv_addr = hes_addrs, i = 1; i < nservers; serv_addr++, i++) { + setup_server(&otherservers[i], serv_addr); + /* is this me? */ + if (serv_addr->s_addr == my_addr.s_addr) { + me_server_idx = i; + otherservers[i].zs_state = SERV_UP; + timer_reset(otherservers[i].zs_timer); + otherservers[i].zs_timer = (timer) NULL; + zdbug((LOG_DEBUG,"found myself")); + } + } + + /* free up the addresses */ + xfree(hes_addrs); + + if (me_server_idx == -1) { + ZServerDesc_t *temp; + syslog(LOG_WARNING, "I'm a renegade server!"); + temp = (ZServerDesc_t *)realloc((caddr_t) otherservers, (unsigned) (++nservers * sizeof(ZServerDesc_t))); + if (!temp) { + syslog(LOG_CRIT, "renegade realloc"); + abort(); + } + otherservers = temp; + setup_server(&otherservers[nservers - 1], &my_addr); + /* we are up. */ + otherservers[nservers - 1].zs_state = SERV_UP; + + /* I don't send hello's to myself--cancel the timer */ + timer_reset(otherservers[nservers - 1].zs_timer); + otherservers[nservers - 1].zs_timer = (timer) NULL; + + /* cancel and reschedule all the timers--pointers need + adjusting */ + /* don't reschedule limbo's timer, so start i=1 */ + for (i = 1; i < nservers - 2; i++) { + timer_reset(otherservers[i].zs_timer); + /* all the HELLO's are due now */ + otherservers[i].zs_timer = timer_set_rel(0L, server_timo, (caddr_t) &otherservers[i]); + } + me_server_idx = nservers - 1; + } +} + /* * A server timout has expired. If enough hello's have been unanswered, * change state and act accordingly. Send a "hello" and reset the timer, @@ -68,16 +164,20 @@ void server_timo(which) ZServerDesc_t *which; { + int auth; + zdbug((LOG_DEBUG,"srv_timo: %s", inet_ntoa(which->zs_addr.sin_addr))); /* change state and reset if appropriate */ switch(which->zs_state) { case SERV_DEAD: /* leave him dead */ server_flush(which); + auth = 1; break; case SERV_UP: /* he's now tardy */ which->zs_state = SERV_TARDY; which->zs_numsent = 0; which->zs_timeout = timo_tardy; + auth = 0; break; case SERV_TARDY: case SERV_STARTING: @@ -90,6 +190,7 @@ ZServerDesc_t *which; which->zs_timeout = timo_dead; server_flush(which); } + auth = 0; break; default: syslog(LOG_ERR,"Bad server state, server 0x%x\n",which); @@ -97,7 +198,9 @@ ZServerDesc_t *which; } /* now he's either TARDY, STARTING, or DEAD We send a "hello," which increments the counter */ - server_hello(which); + zdbug((LOG_DEBUG, "srv %s is %d",inet_ntoa(which->zs_addr.sin_addr), + (int) which->zs_state)); + server_hello(which, auth); /* reschedule the timer */ which->zs_timer = timer_set_rel(which->zs_timeout, server_timo, (caddr_t) which); @@ -114,16 +217,28 @@ ZNotice_t *notice; int auth; struct sockaddr_in *who; { + ZServerDesc_t *server; struct sockaddr_in newwho; + + zdbug((LOG_DEBUG, "server_dispatch")); + + /* XXX set up a who for the real origin */ + bzero((caddr_t) &newwho, sizeof(newwho)); + newwho.sin_family = AF_INET; + newwho.sin_addr.s_addr = notice->z_sender_addr.s_addr; + newwho.sin_port = notice->z_port; + + server = which_server(who); + if (class_is_admin(notice)) - admin_handle(notice, auth, who); - else if (class_is_control(notice)) { - /* XXX set up a who for the real origin */ - newwho.sin_family = AF_INET; - newwho.sin_addr.s_addr = notice->z_sender_addr.s_addr; - newwho.sin_port = notice->z_port; - control_dispatch(notice, auth, &newwho); - } else + admin_handle(notice, auth, who, server); + else if (class_is_control(notice)) + control_dispatch(notice, auth, &newwho, server); + else if (class_is_ulogin(notice)) + ulogin_dispatch(notice, auth, &newwho, server); + else if (class_is_ulocate(notice)) + ulocate_dispatch(notice, auth, &newwho, server); + else /* shouldn't come from another server */ syslog(LOG_WARNING, "srv_disp: pkt cls %s",notice->z_class); return; @@ -140,7 +255,47 @@ ZNotice_t *notice; int auth; struct sockaddr_in *who; { - return(1); + ZServerDesc_t *temp; + register int i; + long timerval; + + if (who->sin_port != sock_sin.sin_port) { + zdbug((LOG_DEBUG, "srv_register wrong port %d", + ntohs(who->sin_port))); + return(1); + } + /* Not yet... talk to ken about authenticators */ +#ifdef notdef + if (!auth) { + zdbug((LOG_DEBUG, "srv_register unauth")); + return(1); + } +#endif notdef + /* OK, go ahead and set him up. */ + temp = (ZServerDesc_t *)malloc((unsigned) ((nservers + 1) * sizeof(ZServerDesc_t))); + if (!temp) { + syslog(LOG_CRIT, "srv_reg malloc"); + return(1); + } + bcopy((caddr_t) otherservers, (caddr_t) temp, nservers * sizeof(ZServerDesc_t)); + xfree(otherservers); + otherservers = temp; + /* don't reschedule limbo's timer, so start i=1 */ + for (i = 1; i < nservers - 1; i++) { + if (i == me_server_idx) /* don't reset myself */ + continue; + /* reschedule the timers--we moved otherservers */ + timerval = timer_when(otherservers[i].zs_timer); + timer_reset(otherservers[i].zs_timer); + otherservers[i].zs_timer = timer_set_abs(timerval, server_timo, (caddr_t) &otherservers[i]); + } + setup_server(&otherservers[nservers], &who->sin_addr); + otherservers[nservers].zs_state = SERV_STARTING; + otherservers[nservers].zs_timeout = timo_tardy; + nservers++; + get_brain_dump(who); + + return(0); } /* @@ -188,47 +343,15 @@ register ZServerDesc_t *which; /* * send a hello to which, updating the count of hello's sent + * Authenticate if auth is set. */ static void -server_hello(which) +server_hello(which, auth) ZServerDesc_t *which; +int auth; { - ZNotice_t hellonotice; - register ZNotice_t *phelonotice; /* speed hack */ - ZPacket_t hellopack; - int packlen; - Code_t retval; - - phelonotice = &hellonotice; - - phelonotice->z_kind = ACKED; - - phelonotice->z_port = sock_sin.sin_port; - phelonotice->z_class = ZEPHYR_ADMIN_CLASS; - phelonotice->z_class_inst = "RUthere"; - phelonotice->z_opcode = "HELLO"; - phelonotice->z_sender = myname; /* myname is the hostname */ - phelonotice->z_recipient = "you@ATHENA.MIT.EDU"; - phelonotice->z_message = (caddr_t) NULL; - phelonotice->z_message_len = 0; - - packlen = sizeof(hellopack); - - /* hello's are not authenticated (overhead not needed) */ - if ((retval = ZFormatNotice(phelonotice, hellopack, packlen, &packlen, ZNOAUTH)) != ZERR_NONE) { - syslog(LOG_WARNING, "hello format: %s", error_message(retval)); - return; - } - if ((retval = ZSetDestAddr(&which->zs_addr)) != ZERR_NONE) { - syslog(LOG_WARNING, "hello set addr: %s", - error_message(retval)); - return; - } - if ((retval = ZSendPacket(hellopack, packlen)) != ZERR_NONE) { - syslog(LOG_WARNING, "hello xmit: %s", error_message(retval)); - return; - } + send_msg(&which->zs_addr, ADMIN_HELLO, 0); (which->zs_numsent)++; return; } @@ -239,13 +362,42 @@ ZServerDesc_t *which; /*ARGSUSED*/ static void -admin_handle(notice, auth, who) +admin_handle(notice, auth, who, server) ZNotice_t *notice; int auth; struct sockaddr_in *who; +ZServerDesc_t *server; { - syslog(LOG_INFO, "ADMIN received\n"); - return; + register char *opcode = notice->z_opcode; + register ZHostList_t *host, *hishost;; + + zdbug((LOG_DEBUG, "ADMIN received")); + + if (!strcmp(opcode, ADMIN_HELLO)) { + hello_respond(who); +#ifdef notdef + if ((him = which_server(who))) { + /* XXX take a hint here that the other guy is up */ + } +#endif notdef + } else if (!strcmp(opcode, ADMIN_IMHERE)) { + hello_input(notice, auth, who); + } else if (!strcmp(opcode, ADMIN_SHUTDOWN)) { + zdbug((LOG_DEBUG, "server shutdown")); + /* we need to transfer all of its hosts to limbo */ + if (server) { + hishost = server->zs_hosts; + for (host = hishost->q_forw; + host != hishost; + host = hishost->q_forw) + /* hostm transfer remque's the host and + attaches it to the new server */ + hostm_transfer(host, limbo_server); + + } + } else + syslog(LOG_WARNING, "ADMIN unknown opcode %s",opcode); + return; } @@ -256,19 +408,274 @@ struct sockaddr_in *who; */ void -server_adispatch(notice, auth, who) +server_adispatch(notice, auth, who, server) ZNotice_t *notice; int auth; struct sockaddr_in *who; +ZServerDesc_t *server; { + /* this had better be a HELLO message--start of acquisition protocol */ syslog(LOG_INFO, "disp: new server?"); if (server_register(notice, auth, who) != ZERR_NONE) syslog(LOG_INFO, "new server failed"); - else + else { syslog(LOG_INFO, "new server %s, %d", inet_ntoa(who->sin_addr), ntohs(who->sin_port)); + hello_respond(who); + } + return; +} + +/* + * get a list of server addresses, from Hesiod. Return a pointer to an + * array of allocated storage. This storage is freed by the caller. + */ + +static struct in_addr * +get_server_addrs(number) +int *number; /* RETURN */ +{ + register int i; + char **hes_resolve(); + char **server_hosts; + register char **cpp; + struct in_addr *addrs; + register struct in_addr *addr; + register struct hostent *hp; + + /* get the names from Hesiod */ + if (!(server_hosts = hes_resolve("zephyr","sloc"))) + return((struct in_addr *)NULL); + + /* count up */ + for (cpp = server_hosts, i = 0; *cpp; cpp++, i++); + + addrs = (struct in_addr *) xmalloc(i * sizeof(struct in_addr)); + + /* Convert to in_addr's */ + for (cpp = server_hosts, addr = addrs, i = 0; *cpp; cpp++) { + hp = gethostbyname(*cpp); + if (hp) { + bcopy((caddr_t)hp->h_addr, + (caddr_t) addr, + sizeof(struct in_addr)); + addr++, i++; + } else + syslog(LOG_WARNING, "hostname failed, %s",*cpp); + } + *number = i; + return(addrs); +} + +/* + * initialize the server structure for address addr, and set a timer + * to go off immediately to send hello's to other servers. + */ + +static void +setup_server(server, addr) +register ZServerDesc_t *server; +struct in_addr *addr; +{ + register ZHostList_t *host; + extern int timo_dead; + + server->zs_state = SERV_DEAD; + server->zs_timeout = timo_dead; + server->zs_numsent = 0; + server->zs_addr.sin_family = AF_INET; + /* he listens to the same port we do */ + server->zs_addr.sin_port = sock_sin.sin_port; + server->zs_addr.sin_addr = *addr; + + /* set up a timer for this server */ + server->zs_timer = timer_set_rel(0L, server_timo, (caddr_t) server); + if (!(host = (ZHostList_t *) xmalloc(sizeof(ZHostList_t)))) { + /* unrecoverable */ + syslog(LOG_CRIT, "zs_host malloc"); + abort(); + } + host->q_forw = host->q_back = host; + server->zs_hosts = host; + return; +} + +/* + * Someone sent us a hello message, respond to them. + */ + +static void +hello_respond(who) +struct sockaddr_in *who; +{ + + send_msg(who, ADMIN_IMHERE, 0); + return; +} + +/* + * return the server descriptor for server at who + */ + +static ZServerDesc_t * +which_server(who) +struct sockaddr_in *who; +{ + register ZServerDesc_t *server; + register int i; + + /* don't check limbo */ + for (server = &otherservers[1], i = 1; i < nservers; i++, server++) { + if (server->zs_addr.sin_addr.s_addr == who->sin_addr.s_addr) + return(server); + } + return(NULLZSDT); +} + +/* + * We received a response to a hello packet. Adjust server state + * appropriately. + */ +static void +hello_input(notice, auth, who) +ZNotice_t *notice; +int auth; +struct sockaddr_in *who; +{ + register ZServerDesc_t *which = which_server(who); + + if (!which) { + syslog(LOG_ERR, "hello input from non-server?!"); + return; + } + + switch (which->zs_state) { + case SERV_DEAD: + /* he responded, we thought he was dead. mark as starting + and negotiate */ + which->zs_state = SERV_STARTING; + + case SERV_STARTING: + /* XXX here we negotiate and set up a braindump */ + + /* fall through */ + case SERV_TARDY: + which->zs_state = SERV_UP; + case SERV_UP: + /* reset the timer and counts */ + which->zs_numsent = 0; + which->zs_timeout = timo_up; + timer_reset(which->zs_timer); + which->zs_timer = timer_set_rel(which->zs_timeout, server_timo, + (caddr_t) which); + break; + } + return; +} + +/* + * Send each of the other servers a shutdown message. + */ + +void +server_shutdown() +{ + register int i; + + /* don't tell limbo to go away, start at 1*/ + for (i = 1; i < nservers; i++) { + send_msg(&otherservers[i].zs_addr, ADMIN_SHUTDOWN, 0); + } + return; +} + +/* + * send a message to who with admin class and opcode as specified. + * auth is set if we want to send authenticated + */ + +static void +send_msg(who, opcode, auth) +struct sockaddr_in *who; +char *opcode; +int auth; +{ + ZNotice_t notice; + register ZNotice_t *pnotice; /* speed hack */ + ZPacket_t pack; + int packlen; + Code_t retval; + + pnotice = ¬ice; + + pnotice->z_kind = ACKED; + + pnotice->z_port = sock_sin.sin_port; + pnotice->z_class = ZEPHYR_ADMIN_CLASS; + pnotice->z_class_inst = ""; + pnotice->z_opcode = opcode; + pnotice->z_sender = myname; /* myname is the hostname */ + pnotice->z_recipient = ""; + pnotice->z_message = (caddr_t) NULL; + pnotice->z_message_len = 0; + + packlen = sizeof(pack); + + if ((retval = ZFormatNotice(pnotice, pack, packlen, &packlen, auth ? ZAUTH : ZNOAUTH)) != ZERR_NONE) { + syslog(LOG_WARNING, "snd_msg format: %s", error_message(retval)); + return; + } + if ((retval = ZSetDestAddr(who)) != ZERR_NONE) { + syslog(LOG_WARNING, "snd_msg set addr: %s", + error_message(retval)); + return; + } + if ((retval = ZSendPacket(pack, packlen)) != ZERR_NONE) { + syslog(LOG_WARNING, "snd_msg xmit: %s", error_message(retval)); + return; + } + return; +} + +/* + * Forward the notice to the other servers + */ +void +server_forward(notice, auth, who) +ZNotice_t *notice; +int auth; +struct sockaddr_in *who; +{ + register int i; + ZPacket_t pack; + int packlen; + Code_t retval; + + + zdbug((LOG_DEBUG, "srv_forw")); + /* don't send to limbo */ + for (i = 1; i < nservers; i++) { + if (i == me_server_idx) /* don't xmit to myself */ + continue; + + packlen = sizeof(pack); + if ((retval = ZFormatRawNotice(notice, pack, packlen, &packlen)) != ZERR_NONE) { + syslog(LOG_WARNING, "srv_fwd format: %s", + error_message(retval)); + continue; + } + if ((retval = ZSetDestAddr(&otherservers[i].zs_addr)) != ZERR_NONE) { + syslog(LOG_WARNING, "srv_fwd set addr: %s", + error_message(retval)); + continue; + } + if ((retval = ZSendPacket(pack, packlen)) != ZERR_NONE) { + syslog(LOG_WARNING, "srv_fwd xmit: %s", error_message(retval)); + continue; + } + } return; } |