1 /* This file is part of the Project Athena Zephyr Notification System.
2 * It contains functions for dispatching a notice.
4 * Created by: John T. Kohl
6 * $Source: /afs/dev.mit.edu/source/repository/athena/lib/zephyr/server/dispatch.c,v $
9 * Copyright (c) 1987, 1991 by the Massachusetts Institute of Technology.
10 * For copying and distribution information, see the file
14 #include <zephyr/mit-copyright.h>
16 #include <sys/socket.h>
20 static const char rcsid_dispatch_c[] =
21 "$Id: dispatch.c,v 1.63 2001/04/10 23:28:19 ghudson Exp $";
25 #define NACKTAB_HASHSIZE 1023
26 #define NACKTAB_HASHVAL(sockaddr, uid) (((sockaddr).sin_addr.s_addr ^ \
27 (sockaddr).sin_port ^ \
28 (uid).zuid_addr.s_addr ^ \
30 (uid).tv.tv_usec) % NACKTAB_HASHSIZE)
31 #define HOSTS_SIZE_INIT 256
34 ZCONST char *ZNoticeKinds[9] = {"UNSAFE", "UNACKED", "ACKED", "HMACK",
35 "HMCTL", "SERVACK", "SERVNAK", "CLIENTACK",
42 * void dispatch(notice, auth, who)
45 * struct sockaddr_in *who;
47 * void clt_ack(notice, who, sent)
49 * struct sockaddr_in *who;
52 * void nack_release(client)
55 * void sendit(notice, auth, who, external)
58 * struct sockaddr_in *who;
61 * void xmit(notice, dest, auth, client)
63 * struct sockaddr_in *dest;
69 String *class_control, *class_admin, *class_hm, *class_ulogin, *class_ulocate;
71 int rexmit_times[] = REXMIT_TIMES;
73 static void nack_cancel __P((ZNotice_t *, struct sockaddr_in *));
74 static void dispatch __P((ZNotice_t *, int, struct sockaddr_in *, int));
75 static int send_to_dest __P((ZNotice_t *, int, Destination *dest, int, int));
76 static void hostm_deathgram __P((struct sockaddr_in *, Server *));
77 static char *hm_recipient __P((void));
79 Statistic realm_notices = {0, "inter-realm notices"};
80 Statistic interserver_notices = {0, "inter-server notices"};
81 Statistic hm_packets = {0, "hostmanager packets"};
82 Statistic control_notices = {0, "client control notices"};
83 Statistic message_notices = {0, "message notices"};
84 Statistic login_notices = {0, "login notices"};
85 Statistic i_s_ctls = {0, "inter-server control notices"};
86 Statistic i_s_logins = {0, "inter-server login notices"};
87 Statistic i_s_admins = {0, "inter-server admin notices"};
88 Statistic i_s_locates = {0, "inter-server locate notices"};
89 Statistic locate_notices = {0, "locate notices"};
90 Statistic admin_notices = {0, "admin notices"};
92 static Unacked *nacktab[NACKTAB_HASHSIZE];
93 static struct in_addr *hosts;
94 static int hosts_size = 0, num_hosts = 0;
100 syslog(LOG_INFO, "stats: %s: %d", hm_packets.str, hm_packets.val);
101 syslog(LOG_INFO, "stats: %s: %d", control_notices.str,
102 control_notices.val);
103 syslog(LOG_INFO, "stats: %s: %d", message_notices.str,
104 message_notices.val);
105 syslog(LOG_INFO, "stats: %s: %d", login_notices.str, login_notices.val);
106 syslog(LOG_INFO, "stats: %s: %d", locate_notices.str, locate_notices.val);
107 syslog(LOG_INFO, "stats: %s: %d", admin_notices.str, admin_notices.val);
108 syslog(LOG_INFO, "stats: %s: %d", realm_notices.str, realm_notices.val);
109 syslog(LOG_INFO, "stats: %s: %d", interserver_notices.str,
110 interserver_notices.val);
111 syslog(LOG_INFO, "stats: %s: %d", i_s_ctls.str, i_s_ctls.val);
112 syslog(LOG_INFO, "stats: %s: %d", i_s_logins.str, i_s_logins.val);
113 syslog(LOG_INFO, "stats: %s: %d", i_s_admins.str, i_s_admins.val);
114 syslog(LOG_INFO, "stats: %s: %d", i_s_locates.str, i_s_locates.val);
116 /* log stuff once an hour */
117 timer_set_rel ((long) 6*60*60, dump_stats, arg);
121 * Handle an input packet.
122 * Warning: this function may be called from within a brain dump.
129 ZPacket_t input_packet; /* from the network */
130 ZNotice_t new_notice; /* parsed from input_packet */
131 int input_len; /* len of packet */
132 struct sockaddr_in input_sin; /* Zconstructed for authent */
133 struct sockaddr_in whoisit; /* for holding peer's address */
134 int authentic; /* authentic flag */
135 Pending *pending; /* pending packet */
136 int from_server; /* packet is from another server */
137 ZRealm *realm; /* foreign realm ptr */
139 static int first_time = 1;
143 /* Dump statistics five minutes after startup */
146 timer_set_rel(5*60, dump_stats, NULL);
151 if (otherservers[me_server_idx].queue) {
152 /* something here for me; take care of it */
154 zdbug((LOG_DEBUG, "internal queue process"));
157 pending = server_dequeue(me_server);
159 status = ZParseNotice(pending->packet, pending->len, &new_notice);
160 if (status != ZERR_NONE) {
161 syslog(LOG_ERR, "bad notice parse (%s): %s",
162 inet_ntoa(pending->who.sin_addr), error_message(status));
164 dispatch(&new_notice, pending->auth, &pending->who, 1);
166 server_pending_free(pending);
171 * nothing in internal queue, go to the external library
174 status = ZReceivePacket(input_packet, &input_len, &whoisit);
175 if (status != ZERR_NONE) {
176 syslog(LOG_ERR, "bad packet receive: %s from %s",
177 error_message(status), inet_ntoa(whoisit.sin_addr));
181 status = ZParseNotice(input_packet, input_len, &new_notice);
182 if (status != ZERR_NONE) {
183 syslog(LOG_ERR, "bad notice parse (%s): %s",
184 inet_ntoa(whoisit.sin_addr), error_message(status));
187 if (server_which_server(&whoisit)) {
188 /* we need to parse twice--once to get
189 the source addr, second to check
191 memset(&input_sin, 0, sizeof(input_sin));
192 input_sin.sin_addr.s_addr = new_notice.z_sender_addr.s_addr;
193 input_sin.sin_port = new_notice.z_port;
194 input_sin.sin_family = AF_INET;
195 /* Should check to see if packet is from another realm's server,
197 /* Clients don't check auth of acks, nor do we make it so they
198 can in general, so this is safe. */
199 if (new_notice.z_kind == SERVACK || new_notice.z_kind == SERVNAK) {
200 authentic = ZAUTH_YES;
202 if (realm = realm_which_realm(&input_sin)) {
203 authentic = ZCheckRealmAuthentication(&new_notice,
207 authentic = ZCheckAuthentication(&new_notice, &input_sin);
212 /* Clients don't check auth of acks, nor do we make it so they
213 can in general, so this is safe. */
214 if (new_notice.z_kind == SERVACK || new_notice.z_kind == SERVNAK) {
215 authentic = ZAUTH_YES;
217 if (realm = realm_which_realm(&whoisit)) {
218 authentic = ZCheckRealmAuthentication(&new_notice,
222 authentic = ZCheckAuthentication(&new_notice, &whoisit);
227 if (whoisit.sin_port != hm_port && whoisit.sin_port != hm_srv_port &&
228 strcasecmp(new_notice.z_class, ZEPHYR_ADMIN_CLASS) != 0 &&
229 whoisit.sin_port != srv_addr.sin_port &&
230 new_notice.z_kind != CLIENTACK) {
231 syslog(LOG_ERR, "bad port %s/%d", inet_ntoa(whoisit.sin_addr),
232 ntohs(whoisit.sin_port));
237 message_notices.val++;
238 dispatch(&new_notice, authentic, &whoisit, from_server);
246 dispatch(notice, auth, who, from_server)
249 struct sockaddr_in *who;
253 String *notice_class;
254 struct sockaddr_in who2;
259 char dbg_buf[BUFSIZ];
262 authflag = (auth == ZAUTH_YES);
264 if ((int) notice->z_kind < (int) UNSAFE ||
265 (int) notice->z_kind > (int) CLIENTACK) {
266 syslog(LOG_NOTICE, "bad notice kind 0x%x from %s", notice->z_kind,
267 inet_ntoa(who->sin_addr));
273 "disp:%s '%s' '%s' '%s' notice to '%s' from '%s' %s/%d/%d",
274 ZNoticeKinds[(int) notice->z_kind], notice->z_class,
275 notice->z_class_inst, notice->z_opcode, notice->z_recipient,
276 notice->z_sender, inet_ntoa(who->sin_addr),
277 ntohs(who->sin_port), ntohs(notice->z_port));
281 if (notice->z_kind == CLIENTACK) {
282 nack_cancel(notice, who);
288 if (0 && from_server) {
289 /* incorporate server_dispatch here */
292 notice_class = make_string(notice->z_class,1);
295 interserver_notices.val++;
296 status = server_dispatch(notice, authflag, who);
297 } else if (class_is_hm(notice_class)) {
299 status = hostm_dispatch(notice, authflag, who, me_server);
300 } else if (realm_which_realm(who) && !(class_is_admin(notice_class))) {
302 status = realm_dispatch(notice, authflag, who, me_server);
303 } else if (class_is_control(notice_class)) {
304 control_notices.val++;
305 status = control_dispatch(notice, authflag, who, me_server);
306 } else if (class_is_ulogin(notice_class)) {
308 status = ulogin_dispatch(notice, authflag, who, me_server);
309 } else if (class_is_ulocate(notice_class)) {
310 locate_notices.val++;
311 status = ulocate_dispatch(notice, authflag, who, me_server);
312 } else if (class_is_admin(notice_class)) {
314 status = server_adispatch(notice, authflag, who, me_server);
316 if (!realm_bound_for_realm(ZGetRealm(), notice->z_recipient)) {
317 cp = strchr(notice->z_recipient, '@');
319 !(realm = realm_get_realm_by_name(cp + 1))) {
320 /* Foreign user, local realm */
321 sendit(notice, authflag, who, 0);
323 realm_handoff(notice, authflag, who, realm, 1);
325 if (notice->z_recipient[0] == '@')
326 notice->z_recipient = "";
327 sendit(notice, authflag, who, 1);
329 free_string(notice_class);
333 if (status == ZSRV_REQUEUE)
334 server_self_queue(notice, authflag, who);
335 free_string(notice_class);
339 * Send a notice off to those clients who have subscribed to it.
343 sendit(notice, auth, who, external)
346 struct sockaddr_in *who;
349 static int send_counter = 0;
350 char recipbuf[ANAME_SZ + INST_SZ + REALM_SZ + 3], *recipp;
356 class = make_string(notice->z_class, 1);
357 if (realm_bound_for_realm(ZGetRealm(), notice->z_recipient)) {
360 acl = class_get_acl(class);
362 /* if controlled and not auth, fail */
364 syslog(LOG_WARNING, "sendit unauthentic %s from %s",
365 notice->z_class, notice->z_sender);
366 clt_ack(notice, who, AUTH_FAILED);
370 /* if from foreign realm server, disallow if not realm of sender */
371 rlm = realm_which_realm(who);
373 if (!realm_sender_in_realm(rlm->name, notice->z_sender)) {
374 syslog(LOG_WARNING, "sendit auth not verifiable %s (%s) from %s",
375 notice->z_class, rlm->name, notice->z_sender);
376 clt_ack(notice, who, AUTH_FAILED);
381 /* if not auth to transmit, fail */
382 if (!access_check(notice->z_sender, acl, TRANSMIT)) {
383 syslog(LOG_WARNING, "sendit unauthorized %s from %s",
384 notice->z_class, notice->z_sender);
385 clt_ack(notice, who, AUTH_FAILED);
389 /* sender != inst and not auth to send to others --> fail */
390 if (strcmp(notice->z_sender, notice->z_class_inst) != 0 &&
391 !access_check(notice->z_sender, acl, INSTUID)) {
392 syslog(LOG_WARNING, "sendit unauth uid %s %s.%s", notice->z_sender,
393 notice->z_class, notice->z_class_inst);
394 clt_ack(notice, who, AUTH_FAILED);
400 if (!realm_which_realm(who)) {
401 if (memcmp(¬ice->z_sender_addr.s_addr, &who->sin_addr.s_addr,
402 sizeof(notice->z_sender_addr.s_addr))) {
403 /* someone is playing games... */
404 /* inet_ntoa returns pointer to static area */
405 /* max size is 255.255.255.255 */
407 strcpy(buffer, inet_ntoa(who->sin_addr));
410 "sendit unauthentic fake packet: claimed %s, real %s",
411 inet_ntoa(notice->z_sender_addr), buffer);
412 clt_ack(notice, who, AUTH_FAILED);
416 if (ntohl(notice->z_sender_addr.s_addr) != 0) {
418 "sendit invalid address: claimed %s, real %s",
419 inet_ntoa(notice->z_sender_addr), buffer);
420 clt_ack(notice, who, AUTH_FAILED);
424 syslog(LOG_WARNING, "sendit addr mismatch: claimed %s, real %s",
425 inet_ntoa(notice->z_sender_addr), buffer);
429 /* Increment the send counter, used to prevent duplicate sends to
430 * clients. On the off-chance that we wrap around to 0, skip over
431 * it to prevent missing clients which have never had a packet
434 if (send_counter == 0)
437 /* Send to clients subscribed to the triplet itself. */
438 dest.classname = class;
439 dest.inst = make_string(notice->z_class_inst, 1);
440 if (realm_bound_for_realm(ZGetRealm(), notice->z_recipient) &&
441 *notice->z_recipient == '@')
442 dest.recip = make_string("", 0);
444 strncpy(recipbuf, notice->z_recipient, sizeof(recipbuf));
445 recipp = strrchr(recipbuf, '@');
447 sprintf(recipp + 1, "%s", realm_expand_realm(recipp + 1));
448 dest.recip = make_string(recipbuf, 0);
451 if (send_to_dest(notice, auth, &dest, send_counter, external))
454 /* Send to clients subscribed to the triplet with the instance
455 * substituted with the wildcard instance. */
456 free_string(dest.inst);
457 dest.inst = wildcard_instance;
458 if (send_to_dest(notice, auth, &dest, send_counter, external))
462 free_string(dest.recip);
470 * Send to each client in the list. Avoid duplicates by setting
471 * last_send on each client to send_counter, a nonce which is updated
476 send_to_dest(notice, auth, dest, send_counter, external)
486 clientp = triplet_lookup(dest);
490 for (; *clientp; clientp++) {
491 if ((*clientp)->last_send == send_counter)
493 (*clientp)->last_send = send_counter;
494 if ((*clientp)->realm) {
496 realm_handoff(notice, auth, &clientp[0]->addr, clientp[0]->realm,
501 xmit(notice, &((*clientp)->addr), auth, *clientp);
510 * Release anything destined for the client in the not-yet-acked table.
518 Unacked *nacked, *next;
520 for (i = 0; i < NACKTAB_HASHSIZE; i++) {
521 for (nacked = nacktab[i]; nacked; nacked = next) {
523 if (nacked->client == client) {
524 timer_reset(nacked->timer);
526 free(nacked->packet);
534 * Send one packet of a fragmented message to a client. After transmitting,
535 * put it onto the not ack'ed list.
538 /* the arguments must be the same as the arguments to Z_XmitFragment */
541 xmit_frag(notice, buf, len, waitforack)
547 struct sockaddr_in sin;
551 int hashval, sendfail = 0;
553 retval = ZSendPacket(buf, len, 0);
554 if (retval != ZERR_NONE) {
555 syslog(LOG_WARNING, "xmit_frag send: %s", error_message(retval));
556 if (retval != EAGAIN && retval != ENOBUFS)
561 /* now we've sent it, mark it as not ack'ed */
562 nacked = (Unacked *) malloc(sizeof(Unacked));
564 /* no space: just punt */
565 syslog(LOG_WARNING, "xmit_frag nack malloc");
569 savebuf = (char *) malloc(len);
571 /* no space: just punt */
572 syslog(LOG_WARNING, "xmit_frag pack malloc");
577 memcpy(savebuf, buf, len);
579 sin = ZGetDestAddr();
580 nacked->client = NULL;
581 nacked->rexmits = (sendfail) ? -1 : 0;
582 nacked->packet = savebuf;
583 nacked->dest.addr = sin;
584 nacked->packsz = len;
585 nacked->uid = notice->z_uid;
586 nacked->timer = timer_set_rel(rexmit_times[0], rexmit, nacked);
587 LIST_INSERT(&nacktab[NACKTAB_HASHVAL(sin, nacked->uid)], nacked);
592 * Send the notice to the client. After transmitting, put it onto the
597 xmit(notice, dest, auth, client)
599 struct sockaddr_in *dest;
605 int packlen, sendfail = 0;
609 zdbug((LOG_DEBUG,"xmit"));
612 noticepack = (char *) malloc(sizeof(ZPacket_t));
614 syslog(LOG_ERR, "xmit malloc");
615 return; /* DON'T put on nack list */
618 packlen = sizeof(ZPacket_t);
620 if (auth && client) { /*
621 we are distributing authentic and
622 we have a pointer to auth info
625 retval = ZFormatAuthenticNotice(notice, noticepack, packlen, &packlen,
626 client->session_key);
627 if (retval != ZERR_NONE) {
628 syslog(LOG_ERR, "xmit auth format: %s", error_message(retval));
632 #else /* !HAVE_KRB4 */
634 retval = ZFormatSmallRawNotice(notice, noticepack, &packlen);
635 if (retval != ZERR_NONE) {
636 syslog(LOG_ERR, "xmit auth/raw format: %s", error_message(retval));
640 #endif /* HAVE_KRB4 */
643 notice->z_authent_len = 0;
644 notice->z_ascii_authent = (char *)"";
645 retval = ZFormatSmallRawNotice(notice, noticepack, &packlen);
646 /* This code is needed because a Zephyr can "grow" when a remote
647 * realm name is inserted into the Zephyr before being resent out
648 * locally. It essentially matches the code in realm.c to do the
649 * same thing with authentic Zephyrs.
651 if (retval == ZERR_PKTLEN) {
652 ZNotice_t partnotice, newnotice;
655 int buffer_len, hdrlen, offset, fragsize, ret_len, message_len;
656 int origoffset, origlen;
660 retval = ZSetDestAddr(dest);
661 if (retval != ZERR_NONE) {
662 syslog(LOG_WARNING, "xmit set addr: %s", error_message(retval));
666 partnotice = *notice;
668 partnotice.z_auth = 0;
669 partnotice.z_authent_len = 0;
670 partnotice.z_ascii_authent = (char *)"";
672 origoffset = offset = fragsize = 0;
673 origlen = notice->z_message_len;
675 buffer = (char *) malloc(sizeof(ZPacket_t));
677 syslog(LOG_ERR, "xmit unauth refrag malloc");
678 return; /* DON'T put on nack list */
680 buffer_len = sizeof(ZPacket_t);
682 retval = Z_FormatRawHeader(&partnotice, buffer, buffer_len,
683 &hdrlen, NULL, NULL);
684 if (retval != ZERR_NONE) {
685 syslog(LOG_ERR, "xmit unauth refrag fmt: failed");
690 if (notice->z_multinotice && strcmp(notice->z_multinotice, ""))
691 if (sscanf(notice->z_multinotice, "%d/%d", &origoffset, &origlen)
694 syslog(LOG_WARNING, "xmit unauth refrag: parse failed");
699 fragsize = Z_MAXPKTLEN-hdrlen-Z_FRAGFUDGE;
701 while (offset < notice->z_message_len || !notice->z_message_len) {
702 (void) sprintf(multi, "%d/%d", offset+origoffset, origlen);
703 partnotice.z_multinotice = multi;
705 (void) gettimeofday(&partnotice.z_uid.tv, (struct timezone *)0);
706 partnotice.z_uid.tv.tv_sec = htonl((u_long)
707 partnotice.z_uid.tv.tv_sec);
708 partnotice.z_uid.tv.tv_usec = htonl((u_long)
709 partnotice.z_uid.tv.tv_usec);
710 (void) memcpy((char *)&partnotice.z_uid.zuid_addr, &__My_addr,
713 partnotice.z_message = notice->z_message+offset;
714 message_len = min(notice->z_message_len-offset, fragsize);
715 partnotice.z_message_len = message_len;
717 retval = Z_FormatRawHeader(&partnotice, buffer, buffer_len,
718 &hdrlen, &ptr, NULL);
719 if (retval != ZERR_NONE) {
720 syslog(LOG_WARNING, "xmit unauth refrag raw: %s",
721 error_message(retval));
728 (void) memcpy(ptr, partnotice.z_message, partnotice.z_message_len);
730 buffer_len = hdrlen+partnotice.z_message_len;
732 xmit_frag(&partnotice, buffer, buffer_len, 0);
736 if (!notice->z_message_len)
742 /* End of refrag code */
744 if (retval != ZERR_NONE) {
745 syslog(LOG_ERR, "xmit format: %s", error_message(retval));
747 return; /* DON'T put on nack list */
751 zdbug((LOG_DEBUG," to %s/%d", inet_ntoa(dest->sin_addr),
752 ntohs(dest->sin_port)));
754 retval = ZSetDestAddr(dest);
755 if (retval != ZERR_NONE) {
756 syslog(LOG_WARNING, "xmit set addr: %s", error_message(retval));
760 retval = ZSendPacket(noticepack, packlen, 0);
761 if (retval != ZERR_NONE) {
762 syslog(LOG_WARNING, "xmit xmit: (%s/%d) %s", inet_ntoa(dest->sin_addr),
763 ntohs(dest->sin_port), error_message(retval));
764 if (retval != EAGAIN && retval != ENOBUFS) {
771 /* now we've sent it, mark it as not ack'ed */
773 nacked = (Unacked *) malloc(sizeof(Unacked));
775 /* no space: just punt */
776 syslog(LOG_WARNING, "xmit nack malloc");
781 nacked->client = client;
782 nacked->rexmits = (sendfail) ? -1 : 0;
783 nacked->packet = noticepack;
784 nacked->dest.addr = *dest;
785 nacked->packsz = packlen;
786 nacked->uid = notice->z_uid;
787 nacked->timer = timer_set_rel(rexmit_times[0], rexmit, nacked);
788 LIST_INSERT(&nacktab[NACKTAB_HASHVAL(*dest, nacked->uid)], nacked);
792 * Retransmit the packet specified. If we have timed out or retransmitted
793 * too many times, punt the packet and initiate the host recovery algorithm
794 * Else, increment the count and re-send the notice packet.
801 Unacked *nacked = (Unacked *) arg;
805 syslog(LOG_DEBUG, "rexmit %s/%d #%d time %d",
806 inet_ntoa(nacked->dest.addr.sin_addr),
807 ntohs(nacked->dest.addr.sin_port), nacked->rexmits + 1, NOW);
811 if (rexmit_times[nacked->rexmits] == -1) {
813 || NOW - nacked->client->last_ack >= CLIENT_GIVEUP_MIN) {
814 /* The client (if there was one) has been unresponsive.
815 * Give up sending this packet, and kill the client if
816 * there was one. (Make sure to remove nacked from the
817 * nack list before calling client_deregister(), which
818 * scans the nack list.)
821 if (nacked->client) {
822 server_kill_clt(nacked->client);
823 client_deregister(nacked->client, 1);
825 free(nacked->packet);
829 /* The client has sent us an ack recently. Retry with the maximum
830 * retransmit time. */
835 /* retransmit the packet */
837 zdbug((LOG_DEBUG," to %s/%d", inet_ntoa(nacked->dest.addr.sin_addr),
838 ntohs(nacked->dest.addr.sin_port)));
840 retval = ZSetDestAddr(&nacked->dest.addr);
841 if (retval != ZERR_NONE) {
842 syslog(LOG_WARNING, "rexmit set addr: %s", error_message(retval));
844 retval = ZSendPacket(nacked->packet, nacked->packsz, 0);
845 if (retval != ZERR_NONE)
846 syslog(LOG_WARNING, "rexmit xmit: %s", error_message(retval));
847 if (retval == EAGAIN || retval == ENOBUFS)
851 /* reset the timer */
852 nacked->timer = timer_set_rel(rexmit_times[nacked->rexmits], rexmit,
858 * Send an acknowledgement to the sending client, by sending back the
859 * header from the original notice with the z_kind field changed to either
860 * SERVACK or SERVNAK, and the contents of the message either SENT or
861 * NOT_SENT, depending on the value of the sent argument.
865 clt_ack(notice, who, sent)
867 struct sockaddr_in *who;
877 if (bdumping) { /* don't ack while dumping */
879 zdbug((LOG_DEBUG,"bdumping, no ack"));
886 acknotice.z_kind = SERVACK;
889 acknotice.z_message = ZSRVACK_SENT;
893 acknotice.z_message = ZSRVACK_FAIL;
894 acknotice.z_kind = SERVNAK;
898 acknotice.z_kind = SERVNAK;
899 acknotice.z_message = ZSRVACK_NOTSENT;
900 sent_name = "nak/not_sent";
903 acknotice.z_message = ZSRVACK_NOTSENT;
904 sent_name = "not_sent";
911 zdbug((LOG_DEBUG,"clt_ack type %s for %d to %s/%d", sent_name,
912 ntohs(notice->z_port), inet_ntoa(who->sin_addr),
913 ntohs(who->sin_port)));
916 acknotice.z_multinotice = "";
918 /* leave room for the trailing null */
919 acknotice.z_message_len = strlen(acknotice.z_message) + 1;
921 packlen = sizeof(ackpack);
923 retval = ZFormatSmallRawNotice(&acknotice, ackpack, &packlen);
925 if (retval == ZERR_HEADERLEN) {
926 /* Since an ack header can be larger than a message header... (crock) */
927 acknotice.z_opcode = "";
928 acknotice.z_class = "";
929 acknotice.z_class_inst = "";
930 acknotice.z_opcode = "";
931 acknotice.z_default_format = "";
933 retval = ZFormatSmallRawNotice(&acknotice, ackpack, &packlen);
936 if (retval != ZERR_NONE) {
937 syslog(LOG_ERR, "clt_ack format: %s", error_message(retval));
940 retval = ZSetDestAddr(who);
941 if (retval != ZERR_NONE) {
942 syslog(LOG_WARNING, "clt_ack set addr: %s", error_message(retval));
945 retval = ZSendPacket(ackpack, packlen, 0);
946 if (retval != ZERR_NONE) {
947 syslog(LOG_WARNING, "clt_ack xmit: %s", error_message(retval));
950 zdbug((LOG_DEBUG, "packet sent"));
956 * An ack has arrived.
957 * remove the packet matching this notice from the not-yet-acked queue
961 nack_cancel(notice, who)
963 struct sockaddr_in *who;
968 /* search the not-yet-acked table for this packet, and flush it. */
970 zdbug((LOG_DEBUG, "nack_cancel: %s:%08X,%08X",
971 inet_ntoa(notice->z_uid.zuid_addr),
972 notice->z_uid.tv.tv_sec, notice->z_uid.tv.tv_usec));
974 hashval = NACKTAB_HASHVAL(*who, notice->z_uid);
975 for (nacked = nacktab[hashval]; nacked; nacked = nacked->next) {
976 if (nacked->dest.addr.sin_addr.s_addr == who->sin_addr.s_addr
977 && nacked->dest.addr.sin_port == who->sin_port
978 && ZCompareUID(&nacked->uid, ¬ice->z_uid)) {
980 nacked->client->last_ack = NOW;
981 timer_reset(nacked->timer);
982 free(nacked->packet);
990 zdbug((LOG_DEBUG,"nack_cancel: nack not found %s:%08X,%08X",
991 inet_ntoa (notice->z_uid.zuid_addr),
992 notice->z_uid.tv.tv_sec, notice->z_uid.tv.tv_usec));
996 /* for compatibility when sending subscription information to old clients */
998 #define OLD_ZEPHYR_VERSION "ZEPH0.0"
999 #endif /* OLD_COMPAT */
1001 /* Dispatch an HM_CTL notice. */
1004 hostm_dispatch(notice, auth, who, server)
1007 struct sockaddr_in *who;
1011 char *opcode = notice->z_opcode;
1013 int i, add = 0, remove = 0;
1016 zdbug((LOG_DEBUG,"hm_disp"));
1019 if (notice->z_kind == HMACK) {
1022 } else if (notice->z_kind != HMCTL) {
1024 zdbug((LOG_DEBUG, "bogus HM packet"));
1026 clt_ack(notice, who, AUTH_FAILED);
1027 } else if (strcmp(opcode, HM_FLUSH) == 0) {
1028 client_flush_host(&who->sin_addr);
1029 if (server == me_server)
1030 server_forward(notice, auth, who);
1031 } else if (strcmp(opcode, HM_BOOT) == 0) {
1032 client_flush_host(&who->sin_addr);
1033 if (server == me_server) {
1034 server_forward(notice, auth, who);
1038 } else if (strcmp(opcode, HM_ATTACH) == 0) {
1039 if (server == me_server) {
1040 server_forward(notice, auth, who);
1046 } else if (strcmp(opcode, HM_DETACH) == 0) {
1049 syslog(LOG_WARNING, "hm_dispatch: unknown opcode %s", opcode);
1053 for (i = 0; i < num_hosts; i++) {
1054 if (hosts[i].s_addr == who->sin_addr.s_addr)
1057 if (i == num_hosts) {
1058 if (hosts_size == 0) {
1059 hosts = (struct in_addr *) malloc(HOSTS_SIZE_INIT *
1060 sizeof(struct in_addr));
1063 hosts_size = HOSTS_SIZE_INIT;
1064 } else if (num_hosts == hosts_size) {
1065 hosts = (struct in_addr *) realloc(hosts, hosts_size * 2 *
1066 sizeof(struct in_addr));
1071 hosts[num_hosts++] = who->sin_addr;
1073 } else if (remove) {
1074 for (i = 0; i < num_hosts; i++) {
1075 if (hosts[i].s_addr == who->sin_addr.s_addr) {
1076 memmove(&hosts[i], &hosts[i + 1], num_hosts - (i + 1));
1086 * Dispatch a ZEPHYR_CTL notice.
1090 control_dispatch(notice, auth, who, server)
1093 struct sockaddr_in *who;
1096 char *opcode = notice->z_opcode;
1101 struct sockaddr_in newwho;
1104 * ZEPHYR_CTL Opcodes expected are:
1105 * BOOT (inst HM): host has booted; flush data.
1106 * CLIENT_SUBSCRIBE: process with the subscription mananger.
1107 * CLIENT_UNSUBSCRIBE: ""
1108 * CLIENT_CANCELSUB: ""
1111 zdbug((LOG_DEBUG, "ctl_disp: opc=%s", opcode));
1113 newwho.sin_addr.s_addr = notice->z_sender_addr.s_addr;
1114 newwho.sin_port = notice->z_port;
1115 realm = realm_which_realm(&newwho);
1117 return(realm_control_dispatch(notice, auth, who, server, realm));
1119 if (strcasecmp(notice->z_class_inst, ZEPHYR_CTL_HM) == 0) {
1120 return hostm_dispatch(notice, auth, who, server);
1121 } else if (strcmp(opcode, CLIENT_GIMMESUBS) == 0 ||
1122 strcmp(opcode, CLIENT_GIMMEDEFS) == 0) {
1123 /* this special case is before the auth check so that
1124 someone who has no subscriptions does NOT get a SERVNAK
1125 but rather an empty list. Note we must therefore
1126 check authentication inside subscr_sendlist */
1128 /* only acknowledge if *not* old version; the old version
1129 acknowledges the packet with the reply */
1130 if (strcmp(notice->z_version, OLD_ZEPHYR_VERSION) != 0)
1132 #else /* !OLD_COMPAT */
1134 #endif /* OLD_COMPAT */
1135 subscr_sendlist(notice, auth, who);
1139 zdbug((LOG_DEBUG,"unauth ctrl_disp"));
1141 if (server == me_server)
1142 clt_ack(notice, who, AUTH_FAILED);
1146 wantdefs = strcmp(opcode, CLIENT_SUBSCRIBE_NODEFS);
1147 if (!wantdefs || strcmp(opcode, CLIENT_SUBSCRIBE) == 0) {
1148 /* subscription notice */
1149 retval = client_register(notice, &who->sin_addr, &client, wantdefs);
1150 if (retval != ZERR_NONE) {
1151 syslog(LOG_NOTICE, "subscr %s/%s/%d failed: %s",
1152 notice->z_sender, inet_ntoa(who->sin_addr),
1153 ntohs(notice->z_port), error_message(retval));
1154 if (server == me_server) {
1155 if (retval == ZSRV_BADSUBPORT)
1156 clt_ack(notice, who, AUTH_FAILED);
1162 if (strcmp(client->principal->string, notice->z_sender) != 0) {
1163 /* you may only subscribe for your own clients */
1164 if (server == me_server)
1165 clt_ack(notice, who, AUTH_FAILED);
1169 /* in case it's changed */
1170 memcpy(client->session_key, ZGetSession(), sizeof(C_Block));
1172 retval = subscr_subscribe(client, notice, server);
1173 if (retval != ZERR_NONE) {
1174 syslog(LOG_WARNING, "subscr failed: %s", error_message(retval));
1175 if (server == me_server)
1179 } else if (strcmp(opcode, CLIENT_UNSUBSCRIBE) == 0) {
1180 client = client_find(&who->sin_addr, notice->z_port);
1181 if (client != NULL) {
1182 if (strcmp(client->principal->string, notice->z_sender) != 0) {
1183 /* you may only cancel for your own clients */
1184 if (server == me_server)
1185 clt_ack(notice, who, AUTH_FAILED);
1190 if (server == me_server) {
1191 syslog(LOG_DEBUG, "subscription cancel for %s/%d\n",
1192 inet_ntoa(who->sin_addr), ntohs(who->sin_port));
1195 "subscription cancel for %s/%d from %s\n",
1196 inet_ntoa(who->sin_addr), ntohs(who->sin_port),
1201 subscr_cancel(who, notice);
1206 } else if (strcmp(opcode, CLIENT_CANCELSUB) == 0) {
1207 /* canceling subscriptions implies I can punt info about this client */
1208 client = client_find(&who->sin_addr, notice->z_port);
1209 if (client == NULL) {
1211 zdbug((LOG_DEBUG,"can_sub not found client"));
1213 if (server == me_server)
1217 if (strcmp(client->principal->string, notice->z_sender) != 0) {
1218 /* you may only cancel for your own clients */
1219 if (server == me_server)
1220 clt_ack(notice, who, AUTH_FAILED);
1223 /* don't flush locations here, let him do it explicitly */
1225 zdbug((LOG_DEBUG, "cancelsub clt_dereg %s/%d",
1226 inet_ntoa(who->sin_addr), ntohs(who->sin_port)));
1228 client_deregister(client, 0);
1230 syslog(LOG_WARNING, "unknown ctl opcode %s", opcode);
1231 if (server == me_server) {
1232 if (strcmp(notice->z_class_inst, ZEPHYR_CTL_REALM) != 0)
1238 if (server == me_server) {
1240 server_forward(notice, auth, who);
1248 int i, s, newserver;
1249 struct sockaddr_in sin;
1251 for (i = 0; i < nservers; i++) {
1252 if (i != me_server_idx && otherservers[i].state == SERV_UP)
1255 newserver = (i < nservers);
1256 for (i = 0; i < num_hosts; i++) {
1257 sin.sin_addr = hosts[i];
1258 sin.sin_port = hm_port;
1261 s = (random() % (nservers - 1)) + 1;
1262 if (otherservers[s].state == SERV_UP)
1265 hostm_deathgram(&sin, &otherservers[s]);
1267 hostm_deathgram(&sin, NULL);
1275 int i, s, newserver;
1276 struct sockaddr_in sin;
1278 for (i = 0; i < nservers; i++) {
1279 if (i != me_server_idx && otherservers[i].state == SERV_UP)
1282 zdbug((LOG_DEBUG, "rlm_shutdown"));
1284 newserver = (i < nservers);
1287 s = (random() % (nservers - 1)) + 1;
1288 if (otherservers[s].state == SERV_UP)
1291 realm_deathgram(&otherservers[s]);
1293 realm_deathgram(NULL);
1298 hostm_deathgram(sin, server)
1299 struct sockaddr_in *sin;
1304 ZNotice_t shutnotice;
1307 memset (&shutnotice, 0, sizeof(shutnotice));
1309 shutnotice.z_kind = HMCTL;
1310 shutnotice.z_port = sin->sin_port; /* we are sending it */
1311 shutnotice.z_class = HM_CTL_CLASS;
1312 shutnotice.z_class_inst = HM_CTL_SERVER;
1313 shutnotice.z_opcode = SERVER_SHUTDOWN;
1314 shutnotice.z_sender = HM_CTL_SERVER;
1315 shutnotice.z_recipient = hm_recipient();
1316 shutnotice.z_default_format = "";
1317 shutnotice.z_num_other_fields = 0;
1318 shutnotice.z_message = (server) ? server->addr_str : NULL;
1319 shutnotice.z_message_len = (server) ? strlen(server->addr_str) + 1 : 0;
1321 retval = ZFormatNotice(&shutnotice, &shutpack, &shutlen, ZNOAUTH);
1322 if (retval != ZERR_NONE) {
1323 syslog(LOG_ERR, "hm_shut format: %s",error_message(retval));
1326 retval = ZSetDestAddr(sin);
1327 if (retval != ZERR_NONE) {
1328 syslog(LOG_WARNING, "hm_shut set addr: %s", error_message(retval));
1332 retval = ZSendPacket(shutpack, shutlen, 0);
1333 if (retval != ZERR_NONE)
1334 syslog(LOG_WARNING, "hm_shut xmit: %s", error_message(retval));
1341 static char *recipient;
1347 realm = ZGetRealm();
1350 recipient = (char *) malloc(strlen(realm) + 4);
1351 strcpy (recipient, "hm@");
1352 strcat (recipient, realm);