diff options
author | Greg Hudson <ghudson@mit.edu> | 1997-09-14 17:50:06 +0000 |
---|---|---|
committer | Greg Hudson <ghudson@mit.edu> | 1997-09-14 17:50:06 +0000 |
commit | ac16f380e349fa39ec7e26bccb5456cb300006a5 (patch) | |
tree | c07ca88af97b4f6b77d28a2dc723d2e4621ed302 /server/dispatch.c | |
parent | d33e482744fad80d95cdd89ed380c5b8401e49bf (diff) |
Pull in sources from zephyr locker. See /mit/zephyr/repository for
detailed change information.
Diffstat (limited to 'server/dispatch.c')
-rw-r--r-- | server/dispatch.c | 1712 |
1 files changed, 914 insertions, 798 deletions
diff --git a/server/dispatch.c b/server/dispatch.c index 2c2fb16..fed2336 100644 --- a/server/dispatch.c +++ b/server/dispatch.c @@ -12,21 +12,28 @@ */ #include <zephyr/mit-copyright.h> +#include "zserver.h" +#include <sys/socket.h> #ifndef lint #ifndef SABER -static char rcsid_dispatch_c[] = - "$Id$"; +static const char rcsid_dispatch_c[] = +"$Id$"; #endif #endif -#include "zserver.h" -#include <sys/socket.h> +#define NACKTAB_HASHSIZE 1023 +#define NACKTAB_HASHVAL(sockaddr, uid) (((sockaddr).sin_addr.s_addr ^ \ + (sockaddr).sin_port ^ \ + (uid).zuid_addr.s_addr ^ \ + (uid).tv.tv_sec ^ \ + (uid).tv.tv_usec) % NACKTAB_HASHSIZE) +#define HOSTS_SIZE_INIT 256 #ifdef DEBUG -Zconst char *ZNoticeKinds[9] = {"UNSAFE", "UNACKED", "ACKED", "HMACK", - "HMCTL", "SERVACK", "SERVNAK", "CLIENTACK", - "STAT"}; +ZCONST char *ZNoticeKinds[9] = {"UNSAFE", "UNACKED", "ACKED", "HMACK", + "HMCTL", "SERVACK", "SERVNAK", "CLIENTACK", + "STAT"}; #endif /* * @@ -40,10 +47,10 @@ Zconst char *ZNoticeKinds[9] = {"UNSAFE", "UNACKED", "ACKED", "HMACK", * void clt_ack(notice, who, sent) * ZNotice_t *notice; * struct sockaddr_in *who; - * ZSentType sent; + * Sent_type sent; * * void nack_release(client) - * ZClient_t *client; + * Client *client; * * void sendit(notice, auth, who) * ZNotice_t *notice; @@ -54,69 +61,59 @@ Zconst char *ZNoticeKinds[9] = {"UNSAFE", "UNACKED", "ACKED", "HMACK", * ZNotice_t *notice; * struct sockaddr_in *dest; * int auth; - * ZClient_t *client; + * Client *client; */ -/* patchable magic numbers controlling the retransmission rate and count */ -int num_rexmits = NUM_REXMITS; -long rexmit_secs = REXMIT_SECS; -long abs_timo = REXMIT_SECS*NUM_REXMITS + 10; +String *class_control, *class_admin, *class_hm, *class_ulogin, *class_ulocate; -ZSTRING *class_control, *class_admin, *class_hm, *class_ulogin, - *class_ulocate; +int rexmit_times[] = REXMIT_TIMES; -#ifdef __STDC__ -# define P(s) s -#else -# define P(s) () -#endif - -static void nack_cancel P((register ZNotice_t *, struct sockaddr_in *)); -static void dispatch P((ZNotice_t *, int, struct sockaddr_in *, int)); -static int send_to_dest P((ZNotice_t *, int, ZDestination *dest, int)); +static void nack_cancel __P((ZNotice_t *, struct sockaddr_in *)); +static void dispatch __P((ZNotice_t *, int, struct sockaddr_in *, int)); +static int send_to_dest __P((ZNotice_t *, int, Destination *dest, int, int)); +static void hostm_deathgram __P((struct sockaddr_in *, Server *)); +static char *hm_recipient __P((void)); -#undef P +Statistic realm_notices = {0, "inter-realm notices"}; +Statistic interserver_notices = {0, "inter-server notices"}; +Statistic hm_packets = {0, "hostmanager packets"}; +Statistic control_notices = {0, "client control notices"}; +Statistic message_notices = {0, "message notices"}; +Statistic login_notices = {0, "login notices"}; +Statistic i_s_ctls = {0, "inter-server control notices"}; +Statistic i_s_logins = {0, "inter-server login notices"}; +Statistic i_s_admins = {0, "inter-server admin notices"}; +Statistic i_s_locates = {0, "inter-server locate notices"}; +Statistic locate_notices = {0, "locate notices"}; +Statistic admin_notices = {0, "admin notices"}; -ZStatistic interserver_notices = {0, "inter-server notices"}; -ZStatistic hm_packets = {0, "hostmanager packets"}; -ZStatistic control_notices = {0, "client control notices"}; -ZStatistic message_notices = {0, "message notices"}; -ZStatistic login_notices = {0, "login notices"}; -ZStatistic i_s_ctls = {0, "inter-server control notices"}; -ZStatistic i_s_logins = {0, "inter-server login notices"}; -ZStatistic i_s_admins = {0, "inter-server admin notices"}; -ZStatistic i_s_locates = {0, "inter-server locate notices"}; -ZStatistic locate_notices = {0, "locate notices"}; -ZStatistic admin_notices = {0, "admin notices"}; +static Unacked *nacktab[NACKTAB_HASHSIZE]; +static struct in_addr *hosts; +static int hosts_size = 0, num_hosts = 0; static void -#ifdef __STDC__ -dump_stats (void *arg) -#else dump_stats (arg) -void *arg; -#endif + void *arg; { - syslog(LOG_INFO, "stats: %s: %d", hm_packets.str, hm_packets.val); - syslog(LOG_INFO, "stats: %s: %d", control_notices.str, - control_notices.val); - syslog(LOG_INFO, "stats: %s: %d", message_notices.str, - message_notices.val); - syslog(LOG_INFO, "stats: %s: %d", login_notices.str, - login_notices.val); - syslog(LOG_INFO, "stats: %s: %d", locate_notices.str, - locate_notices.val); - syslog(LOG_INFO, "stats: %s: %d", admin_notices.str, - admin_notices.val); - syslog(LOG_INFO, "stats: %s: %d", interserver_notices.str, - interserver_notices.val); - syslog(LOG_INFO, "stats: %s: %d", i_s_ctls.str, i_s_ctls.val); - syslog(LOG_INFO, "stats: %s: %d", i_s_logins.str, i_s_logins.val); - syslog(LOG_INFO, "stats: %s: %d", i_s_admins.str, i_s_admins.val); - syslog(LOG_INFO, "stats: %s: %d", i_s_locates.str, i_s_locates.val); - /* log stuff once an hour */ - (void) timer_set_rel ((long) 6*60*60, dump_stats, arg); + syslog(LOG_INFO, "stats: %s: %d", hm_packets.str, hm_packets.val); + syslog(LOG_INFO, "stats: %s: %d", control_notices.str, + control_notices.val); + syslog(LOG_INFO, "stats: %s: %d", message_notices.str, + message_notices.val); + syslog(LOG_INFO, "stats: %s: %d", login_notices.str, login_notices.val); + syslog(LOG_INFO, "stats: %s: %d", locate_notices.str, locate_notices.val); + syslog(LOG_INFO, "stats: %s: %d", admin_notices.str, admin_notices.val); + syslog(LOG_INFO, "stats: %s: %d", realm_notices.str, realm_notices.val); + syslog(LOG_INFO, "stats: %s: %d", interserver_notices.str, + interserver_notices.val); + syslog(LOG_INFO, "stats: %s: %d", i_s_ctls.str, i_s_ctls.val); + syslog(LOG_INFO, "stats: %s: %d", i_s_logins.str, i_s_logins.val); + syslog(LOG_INFO, "stats: %s: %d", i_s_admins.str, i_s_admins.val); + syslog(LOG_INFO, "stats: %s: %d", i_s_locates.str, i_s_locates.val); + + /* log stuff once an hour */ + timer_set_rel ((long) 6*60*60, dump_stats, arg); } /* @@ -127,123 +124,104 @@ void *arg; void handle_packet() { - Code_t status; - ZPacket_t input_packet; /* from the network */ - ZNotice_t new_notice; /* parsed from input_packet */ - int input_len; /* len of packet */ - struct sockaddr_in input_sin; /* Zconstructed for authent */ - struct sockaddr_in whoisit; /* for holding peer's address */ - int authentic; /* authentic flag */ - ZSrvPending_t *pending; /* pending packet */ - ZHostList_t *host; /* host ptr */ - int from_server; /* packet is from another server */ + Code_t status; + ZPacket_t input_packet; /* from the network */ + ZNotice_t new_notice; /* parsed from input_packet */ + int input_len; /* len of packet */ + struct sockaddr_in input_sin; /* Zconstructed for authent */ + struct sockaddr_in whoisit; /* for holding peer's address */ + int authentic; /* authentic flag */ + Pending *pending; /* pending packet */ + int from_server; /* packet is from another server */ + Realm *realm; /* foreign realm ptr */ #ifdef DEBUG - static int first_time = 1; + static int first_time = 1; #endif #ifdef DEBUG - /* Dump statistics five minutes after startup */ - if (first_time) { - first_time = 0; - (void) timer_set_rel (5*60, dump_stats, (void *) 0); - } -#endif - /* handle traffic */ - - if (otherservers[me_server_idx].zs_update_queue) { - /* something here for me; take care of it */ -#if 1 - zdbug((LOG_DEBUG, "internal queue process")); + /* Dump statistics five minutes after startup */ + if (first_time) { + first_time = 0; + timer_set_rel(5*60, dump_stats, NULL); + } #endif + /* handle traffic */ - pending = otherservers[me_server_idx].zs_update_queue->q_forw; - host = hostm_find_host(&(pending->pend_who.sin_addr)); - if (host && host->zh_locked) { - /* can't deal with it now. to preserve ordering, - we can't process other packets, esp. since we - may block since we don't really know if there - are things in the real queue. */ + if (otherservers[me_server_idx].queue) { + /* something here for me; take care of it */ #if 1 - zdbug((LOG_DEBUG,"host %s is locked", - inet_ntoa(host->zh_addr.sin_addr))); + zdbug((LOG_DEBUG, "internal queue process")); #endif - return; - } - pending = server_dequeue(me_server); /* we can do it, remove */ - - if ((status = ZParseNotice(pending->pend_packet, - pending->pend_len, - &new_notice)) != ZERR_NONE) { - syslog(LOG_ERR, - "bad notice parse (%s): %s", - inet_ntoa(pending->pend_who.sin_addr), - error_message(status)); - } else - dispatch(&new_notice, pending->pend_auth, - &pending->pend_who, 1); - server_pending_free(pending); - return; - } - /* - * nothing in internal queue, go to the external library - * queue/socket - */ - if ((status = ZReceivePacket(input_packet, - &input_len, - &whoisit)) != ZERR_NONE) { - syslog(LOG_ERR, - "bad packet receive: %s from %s", - error_message(status), inet_ntoa(whoisit.sin_addr)); - return; - } - npackets++; - if ((status = ZParseNotice(input_packet, - input_len, - &new_notice)) != ZERR_NONE) { - syslog(LOG_ERR, - "bad notice parse (%s): %s", - inet_ntoa(whoisit.sin_addr), - error_message(status)); - return; - } - if (server_which_server(&whoisit)) { - /* we need to parse twice--once to get - the source addr, second to check - authentication */ - (void) memset((caddr_t) &input_sin, 0, - sizeof(input_sin)); - input_sin.sin_addr.s_addr = new_notice.z_sender_addr.s_addr; - input_sin.sin_port = new_notice.z_port; - input_sin.sin_family = AF_INET; - authentic = ZCheckAuthentication(&new_notice, &input_sin); - from_server = 1; + + pending = server_dequeue(me_server); + + status = ZParseNotice(pending->packet, pending->len, &new_notice); + if (status != ZERR_NONE) { + syslog(LOG_ERR, "bad notice parse (%s): %s", + inet_ntoa(pending->who.sin_addr), error_message(status)); } else { - from_server = 0; - authentic = ZCheckAuthentication(&new_notice, &whoisit); + dispatch(&new_notice, pending->auth, &pending->who, 1); } - switch (authentic) { - case ZAUTH_YES: - authentic = 1; - break; - case ZAUTH_FAILED: - case ZAUTH_NO: - default: - authentic = 0; - break; + server_pending_free(pending); + return; + } + + /* + * nothing in internal queue, go to the external library + * queue/socket + */ + status = ZReceivePacket(input_packet, &input_len, &whoisit); + if (status != ZERR_NONE) { + syslog(LOG_ERR, "bad packet receive: %s from %s", + error_message(status), inet_ntoa(whoisit.sin_addr)); + return; + } + npackets++; + status = ZParseNotice(input_packet, input_len, &new_notice); + if (status != ZERR_NONE) { + syslog(LOG_ERR, "bad notice parse (%s): %s", + inet_ntoa(whoisit.sin_addr), error_message(status)); + return; + } + if (server_which_server(&whoisit)) { + /* we need to parse twice--once to get + the source addr, second to check + authentication */ + memset(&input_sin, 0, sizeof(input_sin)); + input_sin.sin_addr.s_addr = new_notice.z_sender_addr.s_addr; + input_sin.sin_port = new_notice.z_port; + input_sin.sin_family = AF_INET; + realm = realm_which_realm(&input_sin); + if (realm) { + authentic = ZCheckRealmAuthentication(&new_notice, &input_sin, + realm->name); + } else { + authentic = ZCheckAuthentication(&new_notice, &input_sin); } - if (whoisit.sin_port != hm_port && - strcasecmp (new_notice.z_class,ZEPHYR_ADMIN_CLASS) && - whoisit.sin_port != sock_sin.sin_port && - new_notice.z_kind != CLIENTACK) { - syslog(LOG_ERR, - "bad port %s/%d", - inet_ntoa(whoisit.sin_addr), - ntohs(whoisit.sin_port)); - return; + from_server = 1; + } else { + from_server = 0; + realm = realm_which_realm(&whoisit); + if (realm) { + authentic = ZCheckRealmAuthentication(&new_notice, &whoisit, + realm->name); + } else { + authentic = ZCheckAuthentication(&new_notice, &whoisit); } - message_notices.val++; - dispatch(&new_notice, authentic, &whoisit, from_server); + } + + if (whoisit.sin_port != hm_port && whoisit.sin_port != hm_srv_port && + strcasecmp(new_notice.z_class, ZEPHYR_ADMIN_CLASS) != 0 && + whoisit.sin_port != srv_addr.sin_port && + new_notice.z_kind != CLIENTACK) { + syslog(LOG_ERR, "bad port %s/%d", inet_ntoa(whoisit.sin_addr), + ntohs(whoisit.sin_port)); return; + } + + message_notices.val++; + dispatch(&new_notice, authentic, &whoisit, from_server); + return; } /* * Dispatch a notice. @@ -251,88 +229,110 @@ handle_packet() static void dispatch(notice, auth, who, from_server) - ZNotice_t *notice; - int auth; - struct sockaddr_in *who; - int from_server; + ZNotice_t *notice; + int auth; + struct sockaddr_in *who; + int from_server; { - Code_t status; - ZSTRING *notice_class; - struct sockaddr_in who2; + Code_t status; + String *notice_class; + struct sockaddr_in who2; + int authflag; + Realm *realm; + char *cp; #ifdef DEBUG - char dbg_buf[BUFSIZ]; + char dbg_buf[BUFSIZ]; #endif - if ((int) notice->z_kind < (int) UNSAFE || - (int) notice->z_kind > (int) CLIENTACK) { - syslog(LOG_NOTICE, "bad notice kind 0x%x from %s", - (int) notice->z_kind, - inet_ntoa(who->sin_addr)); - return; - } + /* Set "authflag" to 1 or 0 for handler functions. Treat + * ZAUTH_CKSUM_FAILED as authentic except for sendit(), which is + * handled below. */ + switch (auth) { + case ZAUTH_YES: + case ZAUTH_CKSUM_FAILED: + authflag = 1; + break; + case ZAUTH_FAILED: + case ZAUTH_NO: + default: + authflag = 0; + break; + } + + if ((int) notice->z_kind < (int) UNSAFE || + (int) notice->z_kind > (int) CLIENTACK) { + syslog(LOG_NOTICE, "bad notice kind 0x%x from %s", notice->z_kind, + inet_ntoa(who->sin_addr)); + return; + } #if 0 - if (zdebug) { - (void) sprintf (dbg_buf, - "disp:%s '%s' '%s' '%s' notice to '%s' from '%s' %s/%d/%d", - ZNoticeKinds[(int) notice->z_kind], - notice->z_class, - notice->z_class_inst, - notice->z_opcode, - notice->z_recipient, - notice->z_sender, - inet_ntoa(who->sin_addr), - ntohs(who->sin_port), - ntohs(notice->z_port)); - syslog (LOG_DEBUG, "%s", dbg_buf); - } + if (zdebug) { + sprintf(dbg_buf, + "disp:%s '%s' '%s' '%s' notice to '%s' from '%s' %s/%d/%d", + ZNoticeKinds[(int) notice->z_kind], notice->z_class, + notice->z_class_inst, notice->z_opcode, notice->z_recipient, + notice->z_sender, inet_ntoa(who->sin_addr), + ntohs(who->sin_port), ntohs(notice->z_port)); + syslog(LOG_DEBUG, "%s", dbg_buf); + } #endif - if (notice->z_kind == CLIENTACK) { - nack_cancel(notice, who); - return; - } + if (notice->z_kind == CLIENTACK) { + nack_cancel(notice, who); + return; + } - who2 = *who; + who2 = *who; #if 0 - if (0 && from_server) { - /* incorporate server_dispatch here */ - } + if (0 && from_server) { + /* incorporate server_dispatch here */ + } #endif - notice_class = make_zstring(notice->z_class,1); - - if (from_server) { - interserver_notices.val++; - status = server_dispatch(notice, auth, who); - } else if (class_is_hm(notice_class)) { - hm_packets.val++; - status = hostm_dispatch(notice, auth, who, me_server); - } else if (class_is_control(notice_class)) { - control_notices.val++; - status = control_dispatch(notice, auth, who, me_server); - } else if (class_is_ulogin(notice_class)) { - login_notices.val++; - status = ulogin_dispatch(notice, auth, who, me_server); - } else if (class_is_ulocate(notice_class)) { - locate_notices.val++; - status = ulocate_dispatch(notice, auth, who, me_server); - } else if (class_is_admin(notice_class)) { - admin_notices.val++; - status = server_adispatch(notice, auth, who, me_server); + notice_class = make_string(notice->z_class,1); + + if (from_server) { + interserver_notices.val++; + status = server_dispatch(notice, authflag, who); + } else if (class_is_hm(notice_class)) { + hm_packets.val++; + status = hostm_dispatch(notice, authflag, who, me_server); + } else if (realm_which_realm(who) && !(class_is_admin(notice_class))) { + realm_notices.val++; + status = realm_dispatch(notice, authflag, who, me_server); + } else if (class_is_control(notice_class)) { + control_notices.val++; + status = control_dispatch(notice, authflag, who, me_server); + } else if (class_is_ulogin(notice_class)) { + login_notices.val++; + status = ulogin_dispatch(notice, authflag, who, me_server); + } else if (class_is_ulocate(notice_class)) { + locate_notices.val++; + status = ulocate_dispatch(notice, authflag, who, me_server); + } else if (class_is_admin(notice_class)) { + admin_notices.val++; + status = server_adispatch(notice, authflag, who, me_server); + } else { + if (auth == ZAUTH_CKSUM_FAILED) + authflag = 0; + if (!bound_for_local_realm(notice)) { + cp = strchr(notice->z_recipient, '@'); + if (!cp || + !(realm = realm_get_realm_by_name(realm_expand_realm(cp + 1)))) + sendit(notice, authflag, who, 0); + else + realm_handoff(notice, authflag, who, realm, 1); } else { - sendit (notice, auth, who); - free_zstring(notice_class); - return; + if (notice->z_recipient[0] == '@') + notice->z_recipient = ""; + sendit(notice, authflag, who, 1); } + free_string(notice_class); + return; + } - if (status == ZSRV_REQUEUE) { -#ifdef CONCURRENT - server_self_queue(notice, auth, who); -#else - syslog(LOG_ERR, "requeue while not concurr"); - abort(); -#endif - } - free_zstring(notice_class); + if (status == ZSRV_REQUEUE) + server_self_queue(notice, authflag, who); + free_string(notice_class); } /* @@ -340,101 +340,113 @@ dispatch(notice, auth, who, from_server) */ void -sendit(notice, auth, who) - ZNotice_t *notice; - int auth; - struct sockaddr_in *who; +sendit(notice, auth, who, external) + ZNotice_t *notice; + int auth; + struct sockaddr_in *who; + int external; { - static int send_counter = 0; - int any = 0; - ZAcl_t *acl; - ZDestination dest; - ZSTRING *class; - - class = make_zstring(notice->z_class,1); - if ((acl = class_get_acl(class)) != NULLZACLT) { - /* if controlled and not auth, fail */ - if (!auth) { - syslog(LOG_WARNING, "sendit unauthentic %s from %s", - notice->z_class, notice->z_sender); - clt_ack(notice, who, AUTH_FAILED); - free_zstring(class); - return; - } - /* if not auth to transmit, fail */ - if (!access_check(notice->z_sender, acl, TRANSMIT)) { - syslog(LOG_WARNING, "sendit unauthorized %s from %s", - notice->z_class, notice->z_sender); - clt_ack(notice, who, AUTH_FAILED); - free_zstring(class); - return; - } - /* sender != inst and not auth to send to others --> fail */ - if ((strcmp (notice->z_sender, notice->z_class_inst)) && - (!access_check(notice->z_sender, acl, INSTUID))) { - syslog(LOG_WARNING, - "sendit unauth uid %s %s.%s", - notice->z_sender, - notice->z_class, - notice->z_class_inst); + static int send_counter = 0; + char recipbuf[ANAME_SZ + INST_SZ + REALM_SZ + 3], *recipp; + int any = 0; + Acl *acl; + Destination dest; + String *class; + + class = make_string(notice->z_class, 1); + acl = class_get_acl(class); + if (acl != NULL) { + /* if controlled and not auth, fail */ + if (!auth) { + syslog(LOG_WARNING, "sendit unauthentic %s from %s", + notice->z_class, notice->z_sender); clt_ack(notice, who, AUTH_FAILED); - free_zstring(class); + free_string(class); return; - } } + /* if not auth to transmit, fail */ + if (!access_check(notice->z_sender, acl, TRANSMIT)) { + syslog(LOG_WARNING, "sendit unauthorized %s from %s", + notice->z_class, notice->z_sender); + clt_ack(notice, who, AUTH_FAILED); + free_string(class); + return; + } + /* sender != inst and not auth to send to others --> fail */ + if (strcmp(notice->z_sender, notice->z_class_inst) != 0 && + !access_check(notice->z_sender, acl, INSTUID)) { + syslog(LOG_WARNING, "sendit unauth uid %s %s.%s", notice->z_sender, + notice->z_class, notice->z_class_inst); + clt_ack(notice, who, AUTH_FAILED); + free_string(class); + return; + } + } + if (!realm_which_realm(who)) { if (memcmp(¬ice->z_sender_addr.s_addr, &who->sin_addr.s_addr, sizeof(notice->z_sender_addr.s_addr))) { /* someone is playing games... */ /* inet_ntoa returns pointer to static area */ /* max size is 255.255.255.255 */ char buffer[16]; - (void) strcpy(buffer, inet_ntoa(who->sin_addr)); + strcpy(buffer, inet_ntoa(who->sin_addr)); if (!auth) { - syslog(LOG_WARNING, "sendit unauthentic fake packet: claimed %s, real %s", + syslog(LOG_WARNING, + "sendit unauthentic fake packet: claimed %s, real %s", inet_ntoa(notice->z_sender_addr), buffer); clt_ack(notice, who, AUTH_FAILED); - free_zstring(class); + free_string(class); return; } if (ntohl(notice->z_sender_addr.s_addr) != 0) { - syslog(LOG_WARNING, "sendit invalid address: claimed %s, real %s", + syslog(LOG_WARNING, + "sendit invalid address: claimed %s, real %s", inet_ntoa(notice->z_sender_addr), buffer); clt_ack(notice, who, AUTH_FAILED); - free_zstring(class); + free_string(class); return; } syslog(LOG_WARNING, "sendit addr mismatch: claimed %s, real %s", inet_ntoa(notice->z_sender_addr), buffer); } - - /* Increment the send counter, used to prevent duplicate sends to - * clients. On the off-chance that we wrap around to 0, skip over - * it to prevent missing clients which have never had a packet - * sent to them. */ - send_counter++; - if (send_counter == 0) - send_counter = 1; - - /* Send to clients subscribed to the triplet itself. */ - dest.classname = class; - dest.inst = make_zstring(notice->z_class_inst, 1); - dest.recip = make_zstring(notice->z_recipient, 0); - if (send_to_dest(notice, auth, &dest, send_counter)) - any = 1; - - /* Send to clients subscribed to the triplet with the instance - * substituted with the wildcard instance. */ - free_zstring(dest.inst); - dest.inst = wildcard_instance; - if (send_to_dest(notice, auth, &dest, send_counter)) - any = 1; - - free_zstring(class); - free_zstring(dest.recip); - if (any) - ack(notice, who); - else - nack(notice, who); + } + + /* Increment the send counter, used to prevent duplicate sends to + * clients. On the off-chance that we wrap around to 0, skip over + * it to prevent missing clients which have never had a packet + * sent to them. */ + send_counter++; + if (send_counter == 0) + send_counter = 1; + + /* Send to clients subscribed to the triplet itself. */ + dest.classname = class; + dest.inst = make_string(notice->z_class_inst, 1); + if (bound_for_local_realm(notice) && *notice->z_recipient == '@') { + dest.recip = make_string("", 0); + } else { + strncpy(recipbuf, notice->z_recipient, sizeof(recipbuf)); + recipp = strrchr(&recipbuf, '@'); + if (recipp) + sprintf(recipp + 1, "%s", realm_expand_realm(recipp + 1)); + dest.recip = make_string(recipbuf, 0); + } + if (send_to_dest(notice, auth, &dest, send_counter, external)) + any = 1; + + /* Send to clients subscribed to the triplet with the instance + * substituted with the wildcard instance. */ + free_string(dest.inst); + dest.inst = wildcard_instance; + if (send_to_dest(notice, auth, &dest, send_counter, external)) + any = 1; + + free_string(class); + free_string(dest.recip); + if (any) + ack(notice, who); + else + nack(notice, who); } /* @@ -444,59 +456,59 @@ sendit(notice, auth, who) */ static int -send_to_dest(notice, auth, dest, send_counter) - ZNotice_t *notice; - int auth; - ZDestination *dest; - int send_counter; +send_to_dest(notice, auth, dest, send_counter, external) + ZNotice_t *notice; + int auth; + Destination *dest; + int send_counter; + int external; { - register ZClientList_t *list, *p; - register ZClient_t *client; - register int any = 0; - - list = triplet_lookup(dest); - if (list != NULLZCLT) { - for (p = list->q_forw; p != list; p = p->q_forw) { - client = p->zclt_client; - if (client->last_send == send_counter) - continue; - client->last_send = send_counter; - xmit(notice, &(client->zct_sin), auth, client); - any = 1; - } - } - return any; + Client **clientp; + int any = 0; + + clientp = triplet_lookup(dest); + if (!clientp) + return 0; + + for (; *clientp; clientp++) { + if ((*clientp)->last_send == send_counter) + continue; + (*clientp)->last_send = send_counter; + if ((*clientp)->realm && external) + realm_handoff(notice, auth, &clientp[0]->addr, clientp[0]->realm, + 1); + else + xmit(notice, &((*clientp)->addr), auth, *clientp); + any = 1; + } + + return any; } /* - * Clean up the not-yet-acked queue and release anything destined - * for the client. + * Release anything destined for the client in the not-yet-acked table. */ void nack_release(client) - ZClient_t *client; + Client *client; { - register ZNotAcked_t *nacked, *nack2; - - /* search the not-yet-acked list for anything destined to him, and - flush it. */ - for (nacked = nacklist->q_forw; - nacked != nacklist;) - if ((nacked->na_addr.sin_addr.s_addr == client->zct_sin.sin_addr.s_addr) && - (nacked->na_addr.sin_port == client->zct_sin.sin_port)) { - /* go back, since remque will change things */ - nack2 = nacked->q_back; - timer_reset(nacked->na_timer); - xremque(nacked); - xfree(nacked->na_packet); - xfree(nacked); - /* now that the remque adjusted the linked list, - we go forward again */ - nacked = nack2->q_forw; - } else - nacked = nacked->q_forw; - return; + int i; + Unacked *nacked, *next; + + for (i = 0; i < NACKTAB_HASHSIZE; i++) { + for (nacked = nacktab[i]; nacked; nacked = next) { + next = nacked->next; + if (nacked->dest.addr.sin_addr.s_addr == + client->addr.sin_addr.s_addr && + nacked->dest.addr.sin_port == client->addr.sin_port) { + timer_reset(nacked->timer); + LIST_DELETE(nacked); + free(nacked->packet); + free(nacked); + } + } + } } /* @@ -508,53 +520,50 @@ nack_release(client) /*ARGSUSED*/ Code_t xmit_frag(notice, buf, len, waitforack) - ZNotice_t *notice; - char *buf; - int len; - int waitforack; + ZNotice_t *notice; + char *buf; + int len; + int waitforack; { - char *savebuf; - register ZNotAcked_t *nacked; - Code_t retval; - - if ((retval = ZSendPacket(buf, len, 0)) != ZERR_NONE) { - syslog(LOG_WARNING, "xmit_frag send: %s", - error_message(retval)); - return(retval); - } - - /* now we've sent it, mark it as not ack'ed */ - - if (!(nacked = (ZNotAcked_t *)xmalloc(sizeof(ZNotAcked_t)))) { - /* no space: just punt */ - syslog(LOG_WARNING, "xmit_frag nack malloc"); - return(ENOMEM); - } - - if (!(savebuf = (char *)xmalloc(len))) { - /* no space: just punt */ - syslog(LOG_WARNING, "xmit_frag pack malloc"); - return(ENOMEM); - } - - (void) memcpy(savebuf, buf, len); - - nacked->na_rexmits = 0; - nacked->na_packet = savebuf; - nacked->na_srv_idx = 0; - nacked->na_addr = ZGetDestAddr(); - nacked->na_packsz = len; - nacked->na_uid = notice->z_uid; - nacked->q_forw = nacked->q_back = nacked; - nacked->na_abstimo = NOW + abs_timo; - - /* set a timer to retransmit when done */ - nacked->na_timer = timer_set_rel(rexmit_secs, - rexmit, - (void *) nacked); - /* chain in */ - xinsque(nacked, nacklist); - return(ZERR_NONE); + struct sockaddr_in sin; + char *savebuf; + Unacked *nacked; + Code_t retval; + int hashval; + + retval = ZSendPacket(buf, len, 0); + if (retval != ZERR_NONE) { + syslog(LOG_WARNING, "xmit_frag send: %s", error_message(retval)); + return retval; + } + + /* now we've sent it, mark it as not ack'ed */ + nacked = (Unacked *) malloc(sizeof(Unacked)); + if (!nacked) { + /* no space: just punt */ + syslog(LOG_WARNING, "xmit_frag nack malloc"); + return ENOMEM; + } + + savebuf = (char *) malloc(len); + if (!savebuf) { + /* no space: just punt */ + syslog(LOG_WARNING, "xmit_frag pack malloc"); + free(nacked); + return ENOMEM; + } + + memcpy(savebuf, buf, len); + + sin = ZGetDestAddr(); + nacked->rexmits = 0; + nacked->packet = savebuf; + nacked->dest.addr = sin; + nacked->packsz = len; + nacked->uid = notice->z_uid; + nacked->timer = timer_set_rel(rexmit_times[0], rexmit, nacked); + LIST_INSERT(&nacktab[NACKTAB_HASHVAL(sin, nacked->uid)], nacked); + return(ZERR_NONE); } /* @@ -564,115 +573,97 @@ xmit_frag(notice, buf, len, waitforack) void xmit(notice, dest, auth, client) - ZNotice_t *notice; - struct sockaddr_in *dest; - int auth; - ZClient_t *client; + ZNotice_t *notice; + struct sockaddr_in *dest; + int auth; + Client *client; { - caddr_t noticepack; - register ZNotAcked_t *nacked; - int packlen; - Code_t retval; + char *noticepack; + Unacked *nacked; + int packlen; + Code_t retval; #if 0 - zdbug((LOG_DEBUG,"xmit")); + zdbug((LOG_DEBUG,"xmit")); #endif - if (!(noticepack = (caddr_t) xmalloc(sizeof(ZPacket_t)))) { - syslog(LOG_ERR, "xmit malloc"); - return; /* DON'T put on nack list */ + noticepack = (char *) malloc(sizeof(ZPacket_t)); + if (!noticepack) { + syslog(LOG_ERR, "xmit malloc"); + return; /* DON'T put on nack list */ + } + + packlen = sizeof(ZPacket_t); + + if (auth && client) { /* + we are distributing authentic and + we have a pointer to auth info + */ +#ifdef ZEPHYR_USES_KERBEROS + retval = ZFormatAuthenticNotice(notice, noticepack, packlen, &packlen, + client->session_key); + if (retval != ZERR_NONE) { + syslog(LOG_ERR, "xmit auth format: %s", error_message(retval)); + free(noticepack); + return; } - - packlen = sizeof(ZPacket_t); - - if (auth && client) { /* - we are distributing authentic and - we have a pointer to auth info - */ -#ifdef KERBEROS - - if ((retval = ZFormatAuthenticNotice(notice, - noticepack, - packlen, - &packlen, - client->zct_cblock)) - != ZERR_NONE) { - syslog(LOG_ERR, "xmit auth format: %s", - error_message(retval)); - xfree(noticepack); - return; - } -#else /* !KERBEROS */ - notice->z_auth = 1; - if ((retval = ZFormatSmallRawNotice(notice, - noticepack, - &packlen)) - != ZERR_NONE) { - syslog(LOG_ERR, "xmit auth/raw format: %s", - error_message(retval)); - xfree(noticepack); - return; - } -#endif /* KERBEROS */ - } else { - notice->z_auth = 0; - notice->z_authent_len = 0; - notice->z_ascii_authent = (char *)""; - if ((retval = ZFormatSmallRawNotice(notice, - noticepack, - &packlen)) != ZERR_NONE) { - syslog(LOG_ERR, "xmit format: %s", - error_message(retval)); - xfree(noticepack); - return; /* DON'T put on nack list */ - } +#else /* !ZEPHYR_USES_KERBEROS */ + notice->z_auth = 1; + retval = ZFormatSmallRawNotice(notice, noticepack, &packlen); + if (retval != ZERR_NONE) { + syslog(LOG_ERR, "xmit auth/raw format: %s", error_message(retval)); + free(noticepack); + return; + } +#endif /* ZEPHYR_USES_KERBEROS */ + } else { + notice->z_auth = 0; + notice->z_authent_len = 0; + notice->z_ascii_authent = (char *)""; + retval = ZFormatSmallRawNotice(notice, noticepack, &packlen); + if (retval != ZERR_NONE) { + syslog(LOG_ERR, "xmit format: %s", error_message(retval)); + free(noticepack); + return; /* DON'T put on nack list */ } + } #if 0 - zdbug((LOG_DEBUG," to %s/%d",inet_ntoa(dest->sin_addr), - ntohs(dest->sin_port))); + zdbug((LOG_DEBUG," to %s/%d", inet_ntoa(dest->sin_addr), + ntohs(dest->sin_port))); #endif - if ((retval = ZSetDestAddr(dest)) != ZERR_NONE) { - syslog(LOG_WARNING, "xmit set addr: %s", - error_message(retval)); - xfree(noticepack); - return; - } - if ((retval = ZSendPacket(noticepack, packlen, 0)) != ZERR_NONE) { - syslog(LOG_WARNING, "xmit xmit: (%s/%d) %s", - inet_ntoa(dest->sin_addr), ntohs(dest->sin_port), - error_message(retval)); - xfree(noticepack); - return; - } - - /* now we've sent it, mark it as not ack'ed */ - - if (!(nacked = (ZNotAcked_t *)xmalloc(sizeof(ZNotAcked_t)))) { - /* no space: just punt */ - syslog(LOG_WARNING, "xmit nack malloc"); - xfree(noticepack); - return; - } + retval = ZSetDestAddr(dest); + if (retval != ZERR_NONE) { + syslog(LOG_WARNING, "xmit set addr: %s", error_message(retval)); + free(noticepack); + return; + } + retval = ZSendPacket(noticepack, packlen, 0); + if (retval != ZERR_NONE) { + syslog(LOG_WARNING, "xmit xmit: (%s/%d) %s", inet_ntoa(dest->sin_addr), + ntohs(dest->sin_port), error_message(retval)); + free(noticepack); + return; + } - nacked->na_rexmits = 0; - nacked->na_packet = noticepack; - nacked->na_srv_idx = 0; /* XXX */ - nacked->na_addr = *dest; - nacked->na_packsz = packlen; - nacked->na_uid = notice->z_uid; - nacked->q_forw = nacked->q_back = nacked; - nacked->na_abstimo = NOW + abs_timo; - - /* set a timer to retransmit when done */ - nacked->na_timer = timer_set_rel(rexmit_secs, - rexmit, - (void *) nacked); - /* chain in */ - xinsque(nacked, nacklist); + /* now we've sent it, mark it as not ack'ed */ + nacked = (Unacked *) malloc(sizeof(Unacked)); + if (!nacked) { + /* no space: just punt */ + syslog(LOG_WARNING, "xmit nack malloc"); + free(noticepack); + return; + } + + nacked->rexmits = 0; + nacked->packet = noticepack; + nacked->dest.addr = *dest; + nacked->packsz = packlen; + nacked->uid = notice->z_uid; + nacked->timer = timer_set_rel(rexmit_times[0], rexmit, nacked); + LIST_INSERT(&nacktab[NACKTAB_HASHVAL(*dest, nacked->uid)], nacked); } - /* * Retransmit the packet specified. If we have timed out or retransmitted * too many times, punt the packet and initiate the host recovery algorithm @@ -680,67 +671,59 @@ xmit(notice, dest, auth, client) */ void -#ifdef __STDC__ -rexmit(void *arg) -#else rexmit(arg) - void *arg; -#endif + void *arg; { - register ZNotAcked_t *nackpacket = (ZNotAcked_t*) arg; - int retval; - ZNotice_t dummy_notice; - register ZClient_t *client; + Unacked *nacked = (Unacked *) arg; + int retval; + ZNotice_t dummy_notice; + Client *client; #if 1 - zdbug((LOG_DEBUG,"rexmit")); + syslog(LOG_DEBUG, "rexmit %s/%d #%d time %d", + inet_ntoa(nacked->dest.addr.sin_addr), + ntohs(nacked->dest.addr.sin_port), nacked->rexmits + 1, NOW); #endif - if (++(nackpacket->na_rexmits) > num_rexmits || - NOW > nackpacket->na_abstimo) { - /* possibly dead client */ - - dummy_notice.z_port = nackpacket->na_addr.sin_port; - - client = client_which_client(&nackpacket->na_addr, - &dummy_notice); - - /* unlink & free packet */ - xremque(nackpacket); - xfree(nackpacket->na_packet); - xfree(nackpacket); - - /* initiate recovery */ - if (client) - server_recover(client); - return; + nacked->rexmits++; + if (rexmit_times[nacked->rexmits] == -1) { + /* Unresponsive client, find it in our database. */ + dummy_notice.z_port = nacked->dest.addr.sin_port; + client = client_which_client(&nacked->dest.addr.sin_addr, + &dummy_notice); + + /* unlink & free nacked */ + LIST_DELETE(nacked); + free(nacked->packet); + free(nacked); + + /* Kill the client. */ + if (client) { + server_kill_clt(client); + client_deregister(client, 1); } - /* retransmit the packet */ - -#if 0 - zdbug((LOG_DEBUG," to %s/%d", - inet_ntoa(nackpacket->na_addr.sin_addr), - ntohs(nackpacket->na_addr.sin_port))); -#endif - if ((retval = ZSetDestAddr(&nackpacket->na_addr)) - != ZERR_NONE) { - syslog(LOG_WARNING, "rexmit set addr: %s", - error_message(retval)); - goto requeue; - - } - if ((retval = ZSendPacket(nackpacket->na_packet, - nackpacket->na_packsz, 0)) != ZERR_NONE) - syslog(LOG_WARNING, "rexmit xmit: %s", error_message(retval)); - -requeue: - /* reset the timer */ - nackpacket->na_timer = timer_set_rel(rexmit_secs, - rexmit, - (void *) nackpacket); return; + } + /* retransmit the packet */ +#if 0 + zdbug((LOG_DEBUG," to %s/%d", inet_ntoa(nacked->dest.addr.sin_addr), + ntohs(nacked->dest.addr.sin_port))); +#endif + retval = ZSetDestAddr(&nacked->dest.addr); + if (retval != ZERR_NONE) { + syslog(LOG_WARNING, "rexmit set addr: %s", error_message(retval)); + } else { + retval = ZSendPacket(nacked->packet, nacked->packsz, 0); + if (retval != ZERR_NONE) + syslog(LOG_WARNING, "rexmit xmit: %s", error_message(retval)); + } + + /* reset the timer */ + nacked->timer = timer_set_rel(rexmit_times[nacked->rexmits], rexmit, + nacked); + return; } /* @@ -752,93 +735,81 @@ requeue: void clt_ack(notice, who, sent) - ZNotice_t *notice; - struct sockaddr_in *who; - ZSentType sent; + ZNotice_t *notice; + struct sockaddr_in *who; + Sent_type sent; { - ZNotice_t acknotice; - ZPacket_t ackpack; - int packlen; - int notme = 0; - char *sent_name; - Code_t retval; - - if (bdumping) { /* don't ack while dumping */ + ZNotice_t acknotice; + ZPacket_t ackpack; + int packlen; + int notme = 0; + char *sent_name; + Code_t retval; + + if (bdumping) { /* don't ack while dumping */ #if 1 - zdbug((LOG_DEBUG,"bdumping, no ack")); -#endif - return; - } - - acknotice = *notice; - - acknotice.z_kind = SERVACK; - switch (sent) { - case SENT: - acknotice.z_message = ZSRVACK_SENT; - sent_name = "sent"; - break; - case NOT_FOUND: - acknotice.z_message = ZSRVACK_FAIL; - acknotice.z_kind = SERVNAK; - sent_name = "fail"; - break; - case AUTH_FAILED: - acknotice.z_kind = SERVNAK; - acknotice.z_message = ZSRVACK_NOTSENT; - sent_name = "nak/not_sent"; - break; - case NOT_SENT: - acknotice.z_message = ZSRVACK_NOTSENT; - sent_name = "not_sent"; - break; - default: - abort (); - } - -#if 0 - zdbug((LOG_DEBUG,"clt_ack type %s for %d to %s/%d", - sent_name, - ntohs(notice->z_port), - inet_ntoa(who->sin_addr), - ntohs(who->sin_port))); + zdbug((LOG_DEBUG,"bdumping, no ack")); #endif + return; + } + + acknotice = *notice; + + acknotice.z_kind = SERVACK; + switch (sent) { + case SENT: + acknotice.z_message = ZSRVACK_SENT; + sent_name = "sent"; + break; + case NOT_FOUND: + acknotice.z_message = ZSRVACK_FAIL; + acknotice.z_kind = SERVNAK; + sent_name = "fail"; + break; + case AUTH_FAILED: + acknotice.z_kind = SERVNAK; + acknotice.z_message = ZSRVACK_NOTSENT; + sent_name = "nak/not_sent"; + break; + case NOT_SENT: + acknotice.z_message = ZSRVACK_NOTSENT; + sent_name = "not_sent"; + break; + default: + abort (); + } - if (!server_which_server(who) && - (hostm_find_server(&who->sin_addr) != me_server)) { #if 0 - zdbug((LOG_DEBUG,"not me")); + zdbug((LOG_DEBUG,"clt_ack type %s for %d to %s/%d", sent_name, + ntohs(notice->z_port), inet_ntoa(who->sin_addr), + ntohs(who->sin_port))); #endif - notme = 1; - } - acknotice.z_multinotice = ""; + acknotice.z_multinotice = ""; - /* leave room for the trailing null */ - acknotice.z_message_len = strlen(acknotice.z_message) + 1; + /* leave room for the trailing null */ + acknotice.z_message_len = strlen(acknotice.z_message) + 1; - packlen = sizeof(ackpack); + packlen = sizeof(ackpack); - if ((retval = ZFormatSmallRawNotice(&acknotice, - ackpack, - &packlen)) != ZERR_NONE) { - syslog(LOG_ERR, "clt_ack format: %s",error_message(retval)); - return; - } - if ((retval = ZSetDestAddr(who)) != ZERR_NONE) { - syslog(LOG_WARNING, "clt_ack set addr: %s", - error_message(retval)); - return; - } - if ((retval = ZSendPacket(ackpack, packlen, 0)) != ZERR_NONE) { - syslog(LOG_WARNING, "clt_ack xmit: %s", error_message(retval)); - return; - } - else - zdbug ((LOG_DEBUG, "packet sent")); - if (notme) - hostm_deathgram(who, me_server); + retval = ZFormatSmallRawNotice(&acknotice, ackpack, &packlen); + if (retval != ZERR_NONE) { + syslog(LOG_ERR, "clt_ack format: %s", error_message(retval)); return; + } + retval = ZSetDestAddr(who); + if (retval != ZERR_NONE) { + syslog(LOG_WARNING, "clt_ack set addr: %s", error_message(retval)); + return; + } + retval = ZSendPacket(ackpack, packlen, 0); + if (retval != ZERR_NONE) { + syslog(LOG_WARNING, "clt_ack xmit: %s", error_message(retval)); + return; + } else { + zdbug((LOG_DEBUG, "packet sent")); + } + return; } /* @@ -848,36 +819,36 @@ clt_ack(notice, who, sent) static void nack_cancel(notice, who) - register ZNotice_t *notice; - struct sockaddr_in *who; + ZNotice_t *notice; + struct sockaddr_in *who; { - register ZNotAcked_t *nacked; + Unacked *nacked; + int hashval; - /* search the not-yet-acked list for this packet, and - flush it. */ + /* search the not-yet-acked table for this packet, and flush it. */ #if 0 - zdbug((LOG_DEBUG, "nack_cancel: %s:%08X,%08X", - inet_ntoa (notice->z_uid.zuid_addr), - notice->z_uid.tv.tv_sec, notice->z_uid.tv.tv_usec)); + zdbug((LOG_DEBUG, "nack_cancel: %s:%08X,%08X", + inet_ntoa(notice->z_uid.zuid_addr), + notice->z_uid.tv.tv_sec, notice->z_uid.tv.tv_usec)); #endif - for (nacked = nacklist->q_forw; - nacked != nacklist; - nacked = nacked->q_forw) - if ((nacked->na_addr.sin_addr.s_addr == who->sin_addr.s_addr) && - (nacked->na_addr.sin_port == who->sin_port)) - if (ZCompareUID(&nacked->na_uid, ¬ice->z_uid)) { - timer_reset(nacked->na_timer); - xfree(nacked->na_packet); - xremque(nacked); - xfree(nacked); - return; - } + hashval = NACKTAB_HASHVAL(*who, notice->z_uid); + for (nacked = nacktab[hashval]; nacked; nacked = nacked->next) { + if (nacked->dest.addr.sin_addr.s_addr == who->sin_addr.s_addr + && nacked->dest.addr.sin_port == who->sin_port + && ZCompareUID(&nacked->uid, ¬ice->z_uid)) { + timer_reset(nacked->timer); + free(nacked->packet); + LIST_DELETE(nacked); + free(nacked); + return; + } + } + #if 1 - zdbug((LOG_DEBUG,"nack_cancel: nack not found %s:%08X,%08X", - inet_ntoa (notice->z_uid.zuid_addr), - notice->z_uid.tv.tv_sec, notice->z_uid.tv.tv_usec)); + zdbug((LOG_DEBUG,"nack_cancel: nack not found %s:%08X,%08X", + inet_ntoa (notice->z_uid.zuid_addr), + notice->z_uid.tv.tv_sec, notice->z_uid.tv.tv_usec)); #endif - return; } /* for compatibility when sending subscription information to old clients */ @@ -885,184 +856,329 @@ nack_cancel(notice, who) #define OLD_ZEPHYR_VERSION "ZEPH0.0" #endif /* OLD_COMPAT */ +/* Dispatch an HM_CTL notice. */ + +Code_t +hostm_dispatch(notice, auth, who, server) + ZNotice_t *notice; + int auth; + struct sockaddr_in *who; + Server *server; +{ + Server *owner; + char *opcode = notice->z_opcode; + Code_t retval; + int i, add = 0, remove = 0; + +#if 0 + zdbug((LOG_DEBUG,"hm_disp")); +#endif + + if (notice->z_kind == HMACK) { + /* Ignore. */ + ; + } else if (notice->z_kind != HMCTL) { +#if 0 + zdbug((LOG_DEBUG, "bogus HM packet")); +#endif + clt_ack(notice, who, AUTH_FAILED); + } else if (strcmp(opcode, HM_FLUSH) == 0) { + client_flush_host(&who->sin_addr); + if (server == me_server) + server_forward(notice, auth, who); + } else if (strcmp(opcode, HM_BOOT) == 0) { + client_flush_host(&who->sin_addr); + if (server == me_server) { + server_forward(notice, auth, who); + ack(notice, who); + add = 1; + } + } else if (strcmp(opcode, HM_ATTACH) == 0) { + if (server == me_server) { + server_forward(notice, auth, who); + ack(notice, who); + add = 1; + } else { + remove = 1; + } + } else if (strcmp(opcode, HM_DETACH) == 0) { + remove = 1; + } else { + syslog(LOG_WARNING, "hm_dispatch: unknown opcode %s", opcode); + } + + if (add) { + for (i = 0; i < num_hosts; i++) { + if (hosts[i].s_addr == who->sin_addr.s_addr) + break; + } + if (i == num_hosts) { + if (hosts_size == 0) { + hosts = (struct in_addr *) malloc(HOSTS_SIZE_INIT * + sizeof(struct in_addr)); + if (!hosts) + return ENOMEM; + hosts_size = HOSTS_SIZE_INIT; + } else if (num_hosts == hosts_size) { + hosts = (struct in_addr *) realloc(hosts, hosts_size * 2 * + sizeof(struct in_addr)); + if (!hosts) + return ENOMEM; + hosts_size *= 2; + } + hosts[num_hosts++] = who->sin_addr; + } + } else if (remove) { + for (i = 0; i < num_hosts; i++) { + if (hosts[i].s_addr == who->sin_addr.s_addr) { + memmove(&hosts[i], &hosts[i + 1], num_hosts - (i + 1)); + num_hosts--; + break; + } + } + } + return ZERR_NONE; +} + /* * Dispatch a ZEPHYR_CTL notice. */ Code_t control_dispatch(notice, auth, who, server) - ZNotice_t *notice; - int auth; - struct sockaddr_in *who; - ZServerDesc_t *server; + ZNotice_t *notice; + int auth; + struct sockaddr_in *who; + Server *server; { - register char *opcode = notice->z_opcode; - ZClient_t *client; - ZHostList_t *host; - Code_t retval; - int wantdefs; - - /* - * ZEPHYR_CTL Opcodes expected are: - * BOOT (inst HM): host has booted; flush data. - * CLIENT_SUBSCRIBE: process with the subscription mananger. - * CLIENT_UNSUBSCRIBE: "" - * CLIENT_CANCELSUB: "" - */ - - zdbug ((LOG_DEBUG, "ctl_disp: opc=%s", opcode)); - - if (!strcasecmp (notice->z_class_inst, ZEPHYR_CTL_HM)) - return(hostm_dispatch(notice, auth, who, server)); - else if (!strcmp (opcode, CLIENT_GIMMESUBS) || - !strcmp (opcode, CLIENT_GIMMEDEFS)) { - /* this special case is before the auth check so that - someone who has no subscriptions does NOT get a SERVNAK - but rather an empty list. Note we must therefore - check authentication inside subscr_sendlist */ + char *opcode = notice->z_opcode; + Client *client; + Code_t retval; + int wantdefs; + Realm *realm; + struct sockaddr_in newwho; + + /* + * ZEPHYR_CTL Opcodes expected are: + * BOOT (inst HM): host has booted; flush data. + * CLIENT_SUBSCRIBE: process with the subscription mananger. + * CLIENT_UNSUBSCRIBE: "" + * CLIENT_CANCELSUB: "" + */ + + zdbug((LOG_DEBUG, "ctl_disp: opc=%s", opcode)); + + newwho.sin_addr.s_addr = notice->z_sender_addr.s_addr; + newwho.sin_port = notice->z_port; + realm = realm_which_realm(&newwho); + if (realm) + return(realm_control_dispatch(notice, auth, who, server, realm)); + + if (strcasecmp(notice->z_class_inst, ZEPHYR_CTL_HM) == 0) { + return hostm_dispatch(notice, auth, who, server); + } else if (strcmp(opcode, CLIENT_GIMMESUBS) == 0 || + strcmp(opcode, CLIENT_GIMMEDEFS) == 0) { + /* this special case is before the auth check so that + someone who has no subscriptions does NOT get a SERVNAK + but rather an empty list. Note we must therefore + check authentication inside subscr_sendlist */ #ifdef OLD_COMPAT - /* only acknowledge if *not* old version; the old version - acknowledges the packet with the reply */ - if (strcmp (notice->z_version, OLD_ZEPHYR_VERSION)) - ack(notice, who); + /* only acknowledge if *not* old version; the old version + acknowledges the packet with the reply */ + if (strcmp(notice->z_version, OLD_ZEPHYR_VERSION) != 0) + ack(notice, who); #else /* !OLD_COMPAT */ - ack(notice, who); + ack(notice, who); #endif /* OLD_COMPAT */ - subscr_sendlist(notice, auth, who); - return(ZERR_NONE); - } else if (!auth) { + subscr_sendlist(notice, auth, who); + return ZERR_NONE; + } else if (!auth) { #if 0 - zdbug((LOG_DEBUG,"unauth ctrl_disp")); + zdbug((LOG_DEBUG,"unauth ctrl_disp")); #endif - if (server == me_server) - clt_ack(notice, who, AUTH_FAILED); - return(ZERR_NONE); + if (server == me_server) + clt_ack(notice, who, AUTH_FAILED); + return ZERR_NONE; + } + + wantdefs = strcmp(opcode, CLIENT_SUBSCRIBE_NODEFS); + if (!wantdefs || strcmp(opcode, CLIENT_SUBSCRIBE) == 0) { + /* subscription notice */ + retval = client_register(notice, &who->sin_addr, &client, wantdefs); + if (retval != ZERR_NONE) { + syslog(LOG_NOTICE, "subscr %s/%s/%d failed: %s", + notice->z_sender, inet_ntoa(who->sin_addr), + ntohs(notice->z_port), error_message(retval)); + if (server == me_server) { + if (retval == ZSRV_BADSUBPORT) + clt_ack(notice, who, AUTH_FAILED); + else + nack(notice, who); + } + return(ZERR_NONE); } - - /* the rest of the expected opcodes modify state; check for - unlocked host first */ - host = hostm_find_host(&who->sin_addr); - if (host && host->zh_locked) - return(ZSRV_REQUEUE); - - wantdefs = strcmp (opcode, CLIENT_SUBSCRIBE_NODEFS); - if (!wantdefs || !strcmp (opcode, CLIENT_SUBSCRIBE)) { - /* subscription notice */ - if (!(client = client_which_client(who, notice))) { - if ((retval = client_register(notice, - who, - &client, - server, - wantdefs)) != ZERR_NONE) - { - syslog(LOG_NOTICE, - "subscr. register %s/%s/%d failed: %s", - notice->z_sender, - inet_ntoa(who->sin_addr), - ntohs(notice->z_port), - error_message(retval)); - if (server == me_server) { - if (retval == ZSRV_BADSUBPORT) { - clt_ack(notice, who, AUTH_FAILED); - } else - hostm_deathgram(who, me_server); - } - return(ZERR_NONE); - } - if (!(client = client_which_client(who, notice))) { - syslog(LOG_CRIT, "subscr reg. failure"); - abort(); - } - } - if (strcmp (client->zct_principal->string, notice->z_sender)) { - /* you may only subscribe for your own clients */ - if (server == me_server) - clt_ack(notice, who, AUTH_FAILED); - return(ZERR_NONE); - } -#ifdef KERBEROS - /* in case it's changed */ - (void) memcpy((caddr_t) client->zct_cblock, (caddr_t) ZGetSession(), - sizeof(C_Block)); + if (strcmp(client->principal->string, notice->z_sender) != 0) { + /* you may only subscribe for your own clients */ + if (server == me_server) + clt_ack(notice, who, AUTH_FAILED); + return ZERR_NONE; + } +#ifdef ZEPHYR_USES_KERBEROS + /* in case it's changed */ + memcpy(client->session_key, ZGetSession(), sizeof(C_Block)); #endif - if ((retval = subscr_subscribe(client,notice)) != ZERR_NONE) { - syslog(LOG_WARNING, "subscr failed: %s", - error_message(retval)); - if (server == me_server) - nack(notice, who); - return(ZERR_NONE); - } - } else if (!strcmp(opcode, CLIENT_UNSUBSCRIBE)) { - if ((client = client_which_client(who,notice)) != NULLZCNT) { - if (strcmp(client->zct_principal->string, notice->z_sender)) { - /* you may only cancel for your own clients */ - if (server == me_server) - clt_ack(notice, who, AUTH_FAILED); - return(ZERR_NONE); - } + retval = subscr_subscribe(client, notice); + if (retval != ZERR_NONE) { + syslog(LOG_WARNING, "subscr failed: %s", error_message(retval)); + if (server == me_server) + nack(notice, who); + return ZERR_NONE; + } + } else if (strcmp(opcode, CLIENT_UNSUBSCRIBE) == 0) { + client = client_which_client(&who->sin_addr, notice); + if (client != NULL) { + if (strcmp(client->principal->string, notice->z_sender) != 0) { + /* you may only cancel for your own clients */ + if (server == me_server) + clt_ack(notice, who, AUTH_FAILED); + return ZERR_NONE; + } #if 0 - if (zdebug) { - if (server == me_server) - syslog (LOG_DEBUG, - "subscription cancel for %s/%d\n", - inet_ntoa (who->sin_addr), - ntohs (who->sin_port)); - else - syslog (LOG_DEBUG, - "subscription cancel for %s/%d from %s\n", - inet_ntoa (who->sin_addr), - ntohs (who->sin_port), - server->addr); - } -#endif - (void) subscr_cancel(who, notice); + if (zdebug) { + if (server == me_server) { + syslog(LOG_DEBUG, "subscription cancel for %s/%d\n", + inet_ntoa(who->sin_addr), ntohs(who->sin_port)); } else { - nack(notice, who); - return(ZERR_NONE); + syslog(LOG_DEBUG, + "subscription cancel for %s/%d from %s\n", + inet_ntoa(who->sin_addr), ntohs(who->sin_port), + server->addr_str); } - } else if (!strcmp(opcode, CLIENT_CANCELSUB)) { - /* canceling subscriptions implies I can punt info about - this client */ - if ((client = client_which_client(who,notice)) != NULLZCNT) { - if (strcmp(client->zct_principal->string, notice->z_sender)) { - /* you may only cancel for your own clients */ - if (server == me_server) - clt_ack(notice, who, AUTH_FAILED); - return(ZERR_NONE); - } - if (host) { - /* don't flush locations here, let him - do it explicitly */ + } +#endif + subscr_cancel(who, notice); + } else { + nack(notice, who); + return ZERR_NONE; + } + } else if (strcmp(opcode, CLIENT_CANCELSUB) == 0) { + /* canceling subscriptions implies I can punt info about this client */ + client = client_which_client(&who->sin_addr, notice); + if (client == NULL) { #if 0 - zdbug((LOG_DEBUG, "cancelsub clt_dereg %s/%d", - inet_ntoa (who->sin_addr), - ntohs (who->sin_port))); + zdbug((LOG_DEBUG,"can_sub not found client")); #endif - hostm_lose_ignore(client); - (void) client_deregister(client, host, 0); - } - - } - if (!client || !host) { + if (server == me_server) + nack(notice, who); + return ZERR_NONE; + } + if (strcmp(client->principal->string, notice->z_sender) != 0) { + /* you may only cancel for your own clients */ + if (server == me_server) + clt_ack(notice, who, AUTH_FAILED); + return ZERR_NONE; + } + /* don't flush locations here, let him do it explicitly */ #if 0 - zdbug((LOG_DEBUG,"can_sub not found client")); + zdbug((LOG_DEBUG, "cancelsub clt_dereg %s/%d", + inet_ntoa(who->sin_addr), ntohs(who->sin_port))); #endif - if (server == me_server) - nack(notice, who); - return(ZERR_NONE); - } + client_deregister(client, 0); + } else { + syslog(LOG_WARNING, "unknown ctl opcode %s", opcode); + if (server == me_server) + nack(notice, who); + return ZERR_NONE; + } + + if (server == me_server) { + ack(notice, who); + server_forward(notice, auth, who); + } + return ZERR_NONE; +} + +void +hostm_shutdown() +{ + int i, s, newserver; + struct sockaddr_in sin; + + for (i = 0; i < nservers; i++) { + if (i != me_server_idx && otherservers[i].state == SERV_UP) + break; + } + newserver = (i < nservers); + for (i = 0; i < num_hosts; i++) { + sin.sin_addr = hosts[i]; + sin.sin_port = hm_port; + if (newserver) { + while (1) { + s = (random() % (nservers - 1)) + 1; + if (otherservers[s].state == SERV_UP) + break; + } + hostm_deathgram(&sin, &otherservers[s]); } else { - syslog(LOG_WARNING, "unknown ctl opcode %s", opcode); - if (server == me_server) - nack(notice, who); - return(ZERR_NONE); + hostm_deathgram(&sin, NULL); } + } +} - if (server == me_server) { - ack(notice, who); - server_forward(notice, auth, who); - } - return(ZERR_NONE); +static void +hostm_deathgram(sin, server) + struct sockaddr_in *sin; + Server *server; +{ + Code_t retval; + int shutlen; + ZNotice_t shutnotice; + char *shutpack; + + shutnotice.z_kind = HMCTL; + shutnotice.z_port = sin->sin_port; /* we are sending it */ + shutnotice.z_class = HM_CTL_CLASS; + shutnotice.z_class_inst = HM_CTL_SERVER; + shutnotice.z_opcode = SERVER_SHUTDOWN; + shutnotice.z_sender = HM_CTL_SERVER; + shutnotice.z_recipient = hm_recipient(); + shutnotice.z_default_format = ""; + shutnotice.z_num_other_fields = 0; + shutnotice.z_message = (server) ? server->addr_str : NULL; + shutnotice.z_message_len = (server) ? strlen(server->addr_str) + 1 : 0; + + retval = ZFormatNotice(&shutnotice, &shutpack, &shutlen, ZNOAUTH); + if (retval != ZERR_NONE) { + syslog(LOG_ERR, "hm_shut format: %s",error_message(retval)); + return; + } + retval = ZSetDestAddr(sin); + if (retval != ZERR_NONE) { + syslog(LOG_WARNING, "hm_shut set addr: %s", error_message(retval)); + free(shutpack); + return; + } + retval = ZSendPacket(shutpack, shutlen, 0); + if (retval != ZERR_NONE) + syslog(LOG_WARNING, "hm_shut xmit: %s", error_message(retval)); + free(shutpack); +} + +static char * +hm_recipient() +{ + static char *recipient; + char *realm; + + if (recipient) + return recipient; + + realm = ZGetRealm(); + if (!realm) + realm = "???"; + recipient = (char *) malloc(strlen(realm) + 4); + strcpy (recipient, "hm@"); + strcat (recipient, realm); + return recipient; } - |