diff options
Diffstat (limited to 'zhm/zhm_server.c')
-rw-r--r-- | zhm/zhm_server.c | 412 |
1 files changed, 227 insertions, 185 deletions
diff --git a/zhm/zhm_server.c b/zhm/zhm_server.c index 9d515d5..50fa04f 100644 --- a/zhm/zhm_server.c +++ b/zhm/zhm_server.c @@ -18,15 +18,30 @@ static char rcsid_hm_server_c[] = "$Id$"; #endif /* SABER */ #endif /* lint */ -static void send_back __P((galaxy_info *, ZNotice_t *)); static void boot_timeout __P((void *)); +static int get_serv_timeout __P((void)); -extern int hmdebug; -extern u_short cli_port; +static Timer *boot_timer = NULL; +static int serv_rexmit_times[] = { 5, 10, 20, 40 }; +static int serv_timeouts = 0; -static void send_hmctl_notice(gi, op) - galaxy_info *gi; - char *op; +int serv_loop = 0; +extern u_short cli_port; +extern struct sockaddr_in serv_sin, from; +extern int timeout_type, hmdebug, nservchang, booting, nserv, no_server; +extern int deactivated, rebootflag; +extern int numserv; +extern char **serv_list; +extern char cur_serv[], prim_serv[]; +extern void die_gracefully(); + +void hm_control(), send_back(), new_server(); + +/* Argument is whether we are actually booting, or just attaching + * after a server switch */ +void +send_boot_notice(op) +char *op; { ZNotice_t notice; Code_t ret; @@ -40,244 +55,271 @@ static void send_hmctl_notice(gi, op) notice.z_sender = "HM"; notice.z_recipient = ""; notice.z_default_format = ""; - notice.z_dest_galaxy = ""; notice.z_num_other_fields = 0; notice.z_message_len = 0; - if ((ret = ZSetDestAddr(&gi->sin)) != ZERR_NONE) { + /* Notify server that this host is here */ + if ((ret = ZSetDestAddr(&serv_sin)) != ZERR_NONE) { Zperr(ret); com_err("hm", ret, "setting destination"); } if ((ret = ZSendNotice(¬ice, ZNOAUTH)) != ZERR_NONE) { Zperr(ret); - com_err("hm", ret, "sending hmctl notice %s", op); + com_err("hm", ret, "sending startup notice"); } + boot_timer = timer_set_rel(get_serv_timeout(), boot_timeout, NULL); } -static int choose_next_server(gi) - galaxy_info *gi; +/* Argument is whether we are detaching or really going down */ +void +send_flush_notice(op) +char *op; { - int new_server; + ZNotice_t notice; + Code_t ret; + + /* Set up server notice */ + notice.z_kind = HMCTL; + notice.z_port = cli_port; + notice.z_class = ZEPHYR_CTL_CLASS; + notice.z_class_inst = ZEPHYR_CTL_HM; + notice.z_opcode = op; + notice.z_sender = "HM"; + notice.z_recipient = ""; + notice.z_default_format = ""; + notice.z_num_other_fields = 0; + notice.z_message_len = 0; - if (gi->current_server < 0) { - new_server = random() % gi->galaxy_config.nservers; - } else if (gi->galaxy_config.nservers == 1) { - new_server = NO_SERVER; - } else if ((new_server = (random() % (gi->galaxy_config.nservers - 1))) == - gi->current_server) { - new_server = gi->galaxy_config.nservers - 1; + /* Tell server to lose us */ + if ((ret = ZSetDestAddr(&serv_sin)) != ZERR_NONE) { + Zperr(ret); + com_err("hm", ret, "setting destination"); + } + if ((ret = ZSendNotice(¬ice, ZNOAUTH)) != ZERR_NONE) { + Zperr(ret); + com_err("hm", ret, "sending flush notice"); } - - return(new_server); } -void server_manager(notice, from) - ZNotice_t *notice; - struct sockaddr_in *from; +void +find_next_server(sugg_serv) +char *sugg_serv; { - int i; - galaxy_info *gi; + struct hostent *hp; + int done = 0; + char **parse = serv_list; + char *new_serv; + + if (sugg_serv) { + do { + if (!strcmp(*parse, sugg_serv)) + done = 1; + } while ((done == 0) && (*++parse != NULL)); + } + if (done) { + if ((hp = gethostbyname(sugg_serv)) != NULL) { + DPR2 ("Server = %s\n", sugg_serv); + (void)strncpy(cur_serv, sugg_serv, MAXHOSTNAMELEN); + cur_serv[MAXHOSTNAMELEN - 1] = '\0'; + if (hmdebug) + syslog(LOG_DEBUG, "Suggested server: %s\n", sugg_serv); + } else { + done = 0; + } + } + while (!done) { + if ((++serv_loop > 3) && (strcmp(cur_serv, prim_serv))) { + serv_loop = 0; + if ((hp = gethostbyname(prim_serv)) != NULL) { + DPR2 ("Server = %s\n", prim_serv); + (void)strncpy(cur_serv, prim_serv, MAXHOSTNAMELEN); + cur_serv[MAXHOSTNAMELEN - 1] = '\0'; + done = 1; + break; + } + } + + switch (numserv) { + case 1: + if ((hp = gethostbyname(*serv_list)) != NULL) { + DPR2 ("Server = %s\n", *serv_list); + (void)strncpy(cur_serv, *serv_list, MAXHOSTNAMELEN); + cur_serv[MAXHOSTNAMELEN - 1] = '\0'; + done = 1; + break; + } + /* fall through */ + case 0: + if (rebootflag) + die_gracefully(); + else + sleep(1); + break; + default: + do { + new_serv = serv_list[random() % numserv]; + } while (!strcmp(new_serv, cur_serv)); + + if ((hp = gethostbyname(new_serv)) != NULL) { + DPR2 ("Server = %s\n", new_serv); + (void)strncpy(cur_serv, new_serv, MAXHOSTNAMELEN); + cur_serv[MAXHOSTNAMELEN - 1] = '\0'; + done = 1; + } else + sleep(1); + + break; + } + } + (void) memcpy((char *)&serv_sin.sin_addr, hp->h_addr, 4); + nservchang++; +} - for (i=0; i<ngalaxies; i++) - if ((memcmp((char *)&galaxy_list[i].sin.sin_addr, - (char *)&from->sin_addr, 4) == 0) && - (galaxy_list[i].sin.sin_port == from->sin_port)) { - gi = &galaxy_list[i]; +void +server_manager(notice) +ZNotice_t *notice; +{ + if (memcmp((char *)&serv_sin.sin_addr, (char *)&from.sin_addr, 4) || + (serv_sin.sin_port != from.sin_port)) { + syslog (LOG_INFO, "Bad notice from port %u.", notice->z_port); + } else { + /* This is our server, handle the notice */ + booting = 0; + serv_timeouts = 0; + if (boot_timer) { + timer_reset(boot_timer); + boot_timer = NULL; + } + DPR ("A notice came in from the server.\n"); + nserv++; + switch(notice->z_kind) { + case HMCTL: + hm_control(notice); + break; + case SERVNAK: + case SERVACK: + send_back(notice); + break; + default: + syslog (LOG_INFO, "Bad notice kind!?"); break; } - - if (!gi) { - syslog(LOG_INFO, "Bad server notice from %s:%u.", - inet_ntoa(from->sin_addr), from->sin_port); - return; - } - - DPR ("A notice came in from the server.\n"); - - if (gi->boot_timer) { - timer_reset(gi->boot_timer); - gi->boot_timer = NULL; - } - - gi->nsrvpkts++; - - switch (gi->state) { - case NEED_SERVER: - /* there's a server which thinks it cares about us. it's - wrong. reboot the hm. */ - send_hmctl_notice(gi, HM_BOOT); - - gi->state = BOOTING; - gi->boot_timer = timer_set_rel(BOOT_TIMEOUT, boot_timeout, gi); - - return; - case DEAD_SERVER: - /* the server is back from the dead. reanimate the queue and - pretend it never went away */ - /* fall through */ - case BOOTING: - /* got the ack. */ - retransmit_galaxy(gi); - gi->state = ATTACHED; - break; - } - - switch(notice->z_kind) { - case HMCTL: - hm_control(gi, notice); - break; - case SERVNAK: - case SERVACK: - send_back(gi, notice); - break; - default: - syslog (LOG_INFO, "Bad notice kind %d", notice->z_kind); - break; } } -void hm_control(gi, notice) - galaxy_info *gi; - ZNotice_t *notice; +void +hm_control(notice) +ZNotice_t *notice; { Code_t ret; struct hostent *hp; - char suggested_server[64]; - struct in_addr addr; + char suggested_server[MAXHOSTNAMELEN]; + unsigned long addr; DPR("Control message!\n"); if (!strcmp(notice->z_opcode, SERVER_SHUTDOWN)) { if (notice->z_message_len) { - addr.s_addr = inet_addr(notice->z_message); - galaxy_new_server(gi, &addr); + addr = inet_addr(notice->z_message); + hp = gethostbyaddr((char *) &addr, sizeof(addr), AF_INET); + if (hp != NULL) { + strncpy(suggested_server, hp->h_name, sizeof(suggested_server)); + suggested_server[sizeof(suggested_server) - 1] = '\0'; + new_server(suggested_server); + } else { + new_server(NULL); + } } else { - galaxy_new_server(gi, NULL); + new_server((char *)NULL); } } else if (!strcmp(notice->z_opcode, SERVER_PING)) { notice->z_kind = HMACK; - if ((ret = send_outgoing(&gi->sin, notice)) != ZERR_NONE) { + if ((ret = ZSetDestAddr(&serv_sin)) != ZERR_NONE) { + Zperr(ret); + com_err("hm", ret, "setting destination"); + } + if ((ret = send_outgoing(notice)) != ZERR_NONE) { Zperr(ret); com_err("hm", ret, "sending ACK"); } + if (no_server) { + no_server = 0; + retransmit_queue(&serv_sin); + } } else { syslog (LOG_INFO, "Bad control message."); } } -static void send_back(gi, notice) - galaxy_info *gi; - ZNotice_t *notice; +void +send_back(notice) +ZNotice_t *notice; { ZNotice_Kind_t kind; struct sockaddr_in repl; Code_t ret; - if ((strcmp(notice->z_opcode, HM_BOOT) == 0) || - (strcmp(notice->z_opcode, HM_ATTACH) == 0)) - return; - - if (remove_notice_from_galaxy(gi, notice, &kind, &repl) != ZERR_NONE) { - syslog (LOG_INFO, "Hey! This packet isn't in my queue!"); - return; - } - - /* check if client wants an ACK, and send it */ - if (kind == ACKED) { - DPR2 ("Client ACK port: %u\n", ntohs(repl.sin_port)); - if ((ret = send_outgoing(&repl, notice)) != ZERR_NONE) { - Zperr(ret); - com_err("hm", ret, "sending ACK"); + if (!strcmp(notice->z_opcode, HM_BOOT) || + !strcmp(notice->z_opcode, HM_ATTACH)) { + /* ignore message, just an ack from boot, but exit if we + * are rebooting. + */ + if (rebootflag) + die_gracefully(); + } else { + if (remove_notice_from_queue(notice, &kind, &repl) != ZERR_NONE) { + syslog (LOG_INFO, "Hey! This packet isn't in my queue!"); + } else { + /* check if client wants an ACK, and send it */ + if (kind == ACKED) { + DPR2 ("Client ACK port: %u\n", ntohs(repl.sin_port)); + if ((ret = ZSetDestAddr(&repl)) != ZERR_NONE) { + Zperr(ret); + com_err("hm", ret, "setting destination"); + } + if ((ret = send_outgoing(notice)) != ZERR_NONE) { + Zperr(ret); + com_err("hm", ret, "sending ACK"); + } + } } } -} - -void galaxy_new_server(gi, addr) - galaxy_info *gi; - struct in_addr *addr; -{ - int i; - int new_server; - - if (gi->state == ATTACHED) { - disable_galaxy_retransmits(gi); - gi->nchange++; - syslog(LOG_INFO, "Server went down, finding new server."); - } - - if (gi->current_server != NO_SERVER) - send_hmctl_notice(gi, HM_DETACH); - - if (gi->boot_timer) { - timer_reset(gi->boot_timer); - gi->boot_timer = 0; + if (no_server) { + no_server = 0; + retransmit_queue(&serv_sin); } - - if (addr) { - gi->current_server = EXCEPTION_SERVER; - gi->sin.sin_addr = *addr; - - for (i=0; i<gi->galaxy_config.nservers; i++) - if (gi->galaxy_config.server_list[i].addr.s_addr == - gi->sin.sin_addr.s_addr) { - gi->current_server = i; - break; - } - - gi->state = ATTACHING; - } else if ((new_server = choose_next_server(gi)) == NO_SERVER) { - /* the only server went away. Set a boot timer, try again - later */ - - gi->current_server = NO_SERVER; - - gi->state = (gi->state == BOOTING)?NEED_SERVER:DEAD_SERVER; - gi->boot_timer = timer_set_rel(DEAD_TIMEOUT, boot_timeout, gi); - - return; - } else { - gi->current_server = new_server; - gi->sin.sin_addr = - gi->galaxy_config.server_list[gi->current_server].addr; - - gi->state = (gi->state == NEED_SERVER)?BOOTING:ATTACHING; - } - - send_hmctl_notice(gi, (gi->state == BOOTING)?HM_BOOT:HM_ATTACH); - gi->boot_timer = timer_set_rel(BOOT_TIMEOUT, boot_timeout, gi); } -void galaxy_flush(gi) - galaxy_info *gi; +void +new_server(sugg_serv) +char *sugg_serv; { - init_galaxy_queue(gi); - - /* to flush, actually do a boot, because this causes an ACK to - come back when it completes */ - - if (gi->state == ATTACHED) { - send_hmctl_notice(gi, HM_BOOT); - - gi->state = BOOTING; - gi->boot_timer = timer_set_rel(BOOT_TIMEOUT, boot_timeout, gi); + no_server = 1; + syslog (LOG_INFO, "Server went down, finding new server."); + send_flush_notice(HM_DETACH); + find_next_server(sugg_serv); + if (booting) { + send_boot_notice(HM_BOOT); + deactivated = 0; } else { - gi->state = NEED_SERVER; + send_boot_notice(HM_ATTACH); } -} - -void galaxy_reset(gi) - galaxy_info *gi; -{ - gi->current_server = NO_SERVER; - gi->nchange = 0; - gi->nsrvpkts = 0; - gi->ncltpkts = 0; - - galaxy_flush(gi); + disable_queue_retransmits(); } static void boot_timeout(arg) void *arg; { - galaxy_new_server((galaxy_info *) arg, NULL); + serv_timeouts++; + new_server(NULL); } +static int get_serv_timeout(void) +{ + int ind, ntimeouts; + + ind = (numserv == 0) ? serv_timeouts : serv_timeouts / numserv; + ntimeouts = sizeof(serv_rexmit_times) / sizeof(*serv_rexmit_times); + if (ind >= ntimeouts) + ind = ntimeouts - 1; + return serv_rexmit_times[ind]; +} |