summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar John Kohl <jtkohl@mit.edu>1987-06-19 06:29:53 +0000
committerGravatar John Kohl <jtkohl@mit.edu>1987-06-19 06:29:53 +0000
commitff687ceff9d00d35f0d9df0c86f2fee5b111059d (patch)
tree7066993d388bfa4280008eed76228354da7a5792
parent0543936bef46ef47a12601373a1cf16f0301d808 (diff)
Initial revision
-rw-r--r--server/access.c41
-rw-r--r--server/bdump.c32
-rw-r--r--server/client.c126
-rw-r--r--server/dispatch.c247
-rw-r--r--server/main.c346
-rw-r--r--server/server.c237
-rw-r--r--server/subscr.c389
7 files changed, 1418 insertions, 0 deletions
diff --git a/server/access.c b/server/access.c
new file mode 100644
index 0000000..ab45146
--- /dev/null
+++ b/server/access.c
@@ -0,0 +1,41 @@
+/* This file is part of the Project Athena Zephyr Notification System.
+ * It contains functions for dealing with acl's.
+ *
+ * Created by: John T. Kohl
+ *
+ * $Source$
+ * $Author$
+ *
+ * Copyright (c) 1987 by the Massachusetts Institute of Technology.
+ * For copying and distribution information, see the file
+ * "mit-copyright.h".
+ */
+
+#include <zephyr/mit-copyright.h>
+
+#ifndef lint
+static char rcsid_acl_s_c[] = "$Header$";
+#endif lint
+
+/*
+ *
+ * External routines:
+ *
+ * int access_check(notice, acltype)
+ * ZNotice_t *notice;
+ * ZAclType acltype;
+ */
+
+#include "zserver.h"
+
+/*
+ * check access. return 1 if ok, 0 if not ok.
+ */
+
+int
+access_check(notice, acltype)
+ZNotice_t *notice;
+ZAclType acltype;
+{
+ return(1);
+}
diff --git a/server/bdump.c b/server/bdump.c
new file mode 100644
index 0000000..0eb34dc
--- /dev/null
+++ b/server/bdump.c
@@ -0,0 +1,32 @@
+/* This file is part of the Project Athena Zephyr Notification System.
+ * It contains functions for dumping server state between servers.
+ *
+ * Created by: John T. Kohl
+ *
+ * $Source$
+ * $Author$
+ *
+ * Copyright (c) 1987 by the Massachusetts Institute of Technology.
+ * For copying and distribution information, see the file
+ * "mit-copyright.h".
+ */
+
+#include <zephyr/mit-copyright.h>
+
+#ifndef lint
+static char rcsid_brain_dump_c[] = "$Header$";
+#endif lint
+
+#include "zserver.h"
+
+void
+get_brain_dump(who)
+struct sockaddr_in *who;
+{
+}
+
+void
+send_brain_dump(who)
+struct sockaddr_in *who;
+{
+}
diff --git a/server/client.c b/server/client.c
new file mode 100644
index 0000000..27acda4
--- /dev/null
+++ b/server/client.c
@@ -0,0 +1,126 @@
+/* This file is part of the Project Athena Zephyr Notification System.
+ * It contains functions for the Client Manager subsystem of the Zephyr server.
+ *
+ * Created by: John T. Kohl
+ *
+ * $Source$
+ * $Author$
+ *
+ * Copyright (c) 1987 by the Massachusetts Institute of Technology.
+ * For copying and distribution information, see the file
+ * "mit-copyright.h".
+ */
+
+#include <zephyr/mit-copyright.h>
+
+#ifndef lint
+static char rcsid_client_s_c[] = "$Header$";
+#endif lint
+/*
+ * External functions:
+ *
+ * Code_t client_register(notice, client, server)
+ * ZNotice_t *notice;
+ * ZClient_t **client; (RETURN)
+ * ZServerDesc_t *server;
+ *
+ * Code_t client_deregister(client)
+ * ZClient_t *client;
+ *
+ * ZClient_t *client_which_client(notice)
+ * ZNotice_t *notice;
+ */
+
+#include "zserver.h"
+
+/*
+ * register a client: allocate space, find or insert the address in the
+ * server's list of hosts, initialize and insert the client into
+ * the host's list of clients.
+ *
+ * This routine assumes that the client has not been registered yet.
+ * The caller should check by calling client_which_client
+ */
+Code_t
+client_register(notice, client, server)
+ZNotice_t *notice;
+register ZClient_t **client; /* RETURN */
+ZServerDesc_t *server;
+{
+ register ZHostList_t *hlp = server->zs_hosts;
+ register ZHostList_t *hlp2;
+ register ZClientList_t *clist, *clist2;
+
+ /* allocate a client struct */
+ if ((*client = (ZClient_t *) malloc(sizeof(ZClient_t))) == NULLZCNT)
+ return(ENOMEM);
+
+ /* chain the client's host onto this server's host list */
+
+ if (!hlp) /* bad host list */
+ return(EINVAL);
+
+ for (hlp2 = hlp->q_forw; hlp2 != hlp; hlp2 = hlp2->q_forw) {
+ if (bcmp(&hlp2->zh_addr, &notice->z_sender_addr, sizeof(struct in_addr)))
+ /* already here */
+ break;
+ }
+ if (hlp2 == hlp) { /* not here */
+ if (!(hlp2 = (ZHostList_t *) malloc(sizeof(ZHostList_t)))) {
+ free(*client);
+ return(ENOMEM);
+ }
+ hlp2->zh_addr = notice->z_sender_addr;
+ hlp2->zh_clients = NULLZCLT;
+ insque(hlp2, hlp);
+ }
+
+ /* hlp2 is now pointing to the client's host's address struct */
+
+ if ((clist = hlp2->zh_clients) == NULLZCLT) {
+ /* doesn't already have a client on this ip addr */
+ if ((clist2 = (ZClientList_t *)malloc(sizeof(ZClientList_t))) == NULLZCLT) {
+ free(*client);
+ return(ENOMEM);
+ }
+ clist2->q_forw = clist2->q_back = clist;
+
+ hlp2->zh_clients = clist2;
+ }
+
+ if ((clist = (ZClientList_t *)malloc(sizeof(ZClientList_t))) == NULLZCLT) {
+ free(*client);
+ return(ENOMEM);
+ }
+
+ clist->q_forw = clist->q_back = clist;
+ clist->zclt_client = *client;
+
+ /* initialize the struct */
+ bzero(&(*client)->zct_sin, sizeof(struct sockaddr_in));
+ (*client)->zct_sin.sin_port = notice->z_port;
+ (*client)->zct_sin.sin_addr = notice->z_sender_addr;
+ (*client)->zct_subs = NULLZST;
+
+ /* chain him in */
+
+ insque(clist2, clist);
+
+ return(ZERR_NONE);
+}
+
+/*
+ * Deregister the client, freeing resources.
+ */
+
+Code_t
+client_deregister(client)
+ZClient_t *client;
+{
+}
+
+ZClient_t *
+client_which_client(notice)
+ZNotice_t *notice;
+{
+}
diff --git a/server/dispatch.c b/server/dispatch.c
new file mode 100644
index 0000000..520ec02
--- /dev/null
+++ b/server/dispatch.c
@@ -0,0 +1,247 @@
+/* This file is part of the Project Athena Zephyr Notification System.
+ * It contains functions for dispatching a notice.
+ *
+ * Created by: John T. Kohl
+ *
+ * $Source$
+ * $Author$
+ *
+ * Copyright (c) 1987 by the Massachusetts Institute of Technology.
+ * For copying and distribution information, see the file
+ * "mit-copyright.h".
+ */
+
+#include <zephyr/mit-copyright.h>
+
+#ifndef lint
+static char rcsid_dispatch_c[] = "$Header$";
+#endif lint
+
+#include "zserver.h"
+
+/*
+ *
+ * External Routines:
+ *
+ * void dispatch(notice, auth)
+ * ZNotice_t *notice;
+ * int auth;
+ *
+ * void clt_ack(notice, who, sent)
+ * ZNotice_t *notice;
+ * struct sockaddr_in *who;
+ * ZSentType sent;
+ *
+ */
+
+static void xmit(), rexmit();
+static int is_server();
+
+int num_rexmits = NUM_REXMITS; /* patchable... */
+long rexmit_secs = REXMIT_SECS;
+
+/*
+ * Dispatch a notice.
+ */
+void
+dispatch(notice, auth, who)
+ZNotice_t *notice;
+int auth;
+struct sockaddr_in *who;
+{
+ register ZClientList_t *clientlist, *ptr;
+ int acked = 0;
+
+ if (is_server(who)) {
+ server_dispatch(notice, auth, who);
+ return;
+ }
+ if (class_is_control(notice)) {
+ control_handle(notice, auth, who);
+ return;
+ } else if (class_is_admin(notice)) {
+ /* this had better be a HELLO message--start of acquisition
+ protocol */
+ syslog(LOG_INFO, "disp: new server?");
+ if (server_register(notice, who) != ZERR_NONE)
+ syslog(LOG_INFO, "new server failed");
+ else
+ syslog(LOG_INFO, "new server %s, %d",
+ inet_ntoa(who->sin_addr),
+ ntohs(who->sin_port));
+ return;
+ } else if (class_is_restricted(notice) &&
+ !access_check(notice, XMIT)) {
+ syslog(LOG_WARNING, "disp unauthorized %s", notice->z_class);
+ return;
+ }
+
+ /* oh well, do the dirty work */
+ if ((clientlist = subscr_match_list(notice)) == NULLZCLT) {
+ clt_ack(notice, who, NOT_SENT);
+ return;
+ }
+ for (ptr = clientlist->q_forw; ptr != clientlist; ptr = ptr->q_forw) {
+ /* for each client who gets this notice,
+ send it along */
+ xmit(notice, ptr->zclt_client);
+ if (!acked) {
+ acked = 1;
+ clt_ack(notice, who, SENT);
+ }
+ }
+ if (!acked)
+ clt_ack(notice, who, NOT_SENT);
+}
+
+/*
+ * Is this from a server?
+ */
+static int
+is_server(who)
+struct sockaddr_in *who;
+{
+ register ZServerDesc_t *servs;
+ register int num;
+
+ if (who->sin_port != sock_sin.sin_port)
+ return(0);
+
+ /* just look over the server list */
+ for (servs = otherservers, num = 0; num < nservers; num++, servs++)
+ if (!bcmp(&servs->zs_addr.sin_addr, who->sin_addr,
+ sizeof(struct in_addr)))
+ return(1);
+ return(0);
+}
+/*
+ * Send the notice to the client. After transmitting, put it onto the
+ * not ack'ed list.
+ */
+
+static void
+xmit(notice, client)
+register ZNotice_t *notice;
+ZClient_t *client;
+{
+ ZPacket_t *noticepack;
+ register ZNotAcked_t *nack;
+ int packlen;
+ Code_t retval;
+
+ if ((noticepack = (ZPacket_t *) malloc(sizeof(ZPacket_t))) == NULLZPT){
+ syslog(LOG_ERR, "xmit malloc");
+ return; /* DON'T put on nack list */
+ }
+
+ packlen = sizeof(ZPacket_t);
+
+ if ((retval = ZFormatNotice(notice, noticepack, packlen, &packlen)) != ZERR_NONE) {
+ syslog(LOG_ERR, "xmit format: %s", error_message(retval));
+ return; /* DON'T put on nack list */
+ }
+ if ((retval = ZSetDestAddr(&client->zct_sin)) != ZERR_NONE) {
+ syslog(LOG_WARNING, "xmit set addr: %s",
+ error_message(retval));
+ return;
+ }
+ if ((retval = ZSendPacket(noticepack, packlen)) != ZERR_NONE) {
+ syslog(LOG_WARNING, "xmit xmit: %s", error_message(retval));
+ return;
+ }
+
+ /* now we've sent it, mark it as not ack'ed */
+
+ if ((nack = (ZNotAcked_t *)malloc(sizeof(ZNotAcked_t))) == NULLZNAT) {
+ /* no space: just punt */
+ syslog(LOG_WARNING, "xmit nack malloc");
+ return;
+ }
+
+ nack->na_rexmits = 0;
+ nack->na_packet = noticepack;
+ nack->na_client = client;
+
+ /* chain in */
+ insque(nacklist, nack);
+
+ /* set a timer */
+ nack->na_timer = timer_set_rel (rexmit_secs, rexmit, (caddr_t) nack);
+}
+
+static void
+rexmit(nackpacket)
+register ZNotAcked_t *nackpacket;
+{
+ ZClient_t *client;
+ int retval;
+
+ if (++(nackpacket->na_rexmits) > num_rexmits) {
+ /* possibly dead client */
+ /* remove timer */
+ timer_reset(nackpacket->na_timer);
+ /* unlink & free packet */
+ remque(nackpacket);
+ free(nackpacket->na_packet);
+ client = nackpacket->na_client;
+ free(nackpacket);
+
+ /* initiate recovery */
+ server_recover(client);
+ return;
+ }
+
+ /* retransmit the packet */
+
+ if ((retval = ZSetDestAddr(&nackpacket->na_client->zct_sin)) != ZERR_NONE) {
+ syslog(LOG_WARNING, "rexmit set addr: %s",
+ error_message(retval));
+ return;
+ }
+ if ((retval = ZSendPacket(nackpacket->na_packet,
+ nackpacket->na_packsz)) != ZERR_NONE)
+ syslog(LOG_WARNING, "rexmit xmit: %s", error_message(retval));
+
+ return;
+
+}
+
+void
+clt_ack(notice, who, sent)
+ZNotice_t *notice;
+struct sockaddr_in *who;
+ZSentType sent;
+{
+ ZNotice_t acknotice;
+ ZPacket_t ackpack;
+ int packlen;
+ Code_t retval;
+
+ acknotice = *notice;
+
+ acknotice.z_kind = SERVACK;
+ if (sent == SENT)
+ acknotice.z_message = ZSRVACK_SENT;
+ else
+ acknotice.z_message = ZSRVACK_NOTSENT;
+
+ /* Don't forget room for the null */
+ acknotice.z_message_len = strlen(acknotice.z_message) + 1;
+
+ packlen = sizeof(ackpack);
+
+ if ((retval = ZFormatRawNotice(&acknotice, ackpack, packlen, &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)) != ZERR_NONE) {
+ syslog(LOG_WARNING, "clt_ack xmit: %s", error_message(retval));
+ return;
+ }
+ return;
+}
diff --git a/server/main.c b/server/main.c
new file mode 100644
index 0000000..f891246
--- /dev/null
+++ b/server/main.c
@@ -0,0 +1,346 @@
+/* This file is part of the Project Athena Zephyr Notification System.
+ * It contains the main loop of the Zephyr server
+ *
+ * Created by: John T. Kohl
+ *
+ * $Source$
+ * $Author$
+ *
+ * Copyright (c) 1987 by the Massachusetts Institute of Technology.
+ * For copying and distribution information, see the file
+ * "mit-copyright.h".
+ */
+
+#include <zephyr/mit-copyright.h>
+
+#ifndef lint
+static char rcsid_main_c[] = "$Header$";
+static char copyright[] = "Copyright (c) 1987 Massachusetts Institute of Technology. Portions Copyright (c) 1986 Student Information Processing Board, Massachusetts Institute of Technology\n";
+#endif lint
+
+/*
+ * Server loop for Zephyr.
+ */
+
+#include "zserver.h" /* which includes
+ zephyr/zephyr.h
+ <errno.h>
+ <sys/types.h>
+ <netinet/in.h>
+ <sys/time.h>
+ <stdio.h>
+ <syslog.h>
+ timer.h
+ */
+
+#include <netdb.h>
+#include <sys/socket.h>
+#include <sys/param.h>
+#include <sys/ioctl.h>
+
+#define EVER (;;) /* don't stop looping */
+#define max(a,b) ((a) > (b) ? (a) : (b))
+
+static int do_net_setup(), initialize();
+static struct in_addr *get_server_addrs();
+static void usage();
+struct in_addr *get_server_addrs();
+char *rindex();
+
+int srv_socket; /* dgram socket for clients
+ and other servers */
+struct sockaddr_in sock_sin;
+struct in_addr my_addr;
+struct timeval nexthost_tv = {0, 0}; /* time till next host keepalive
+ initialize to zero so select doesn't
+ timeout */
+
+int nservers; /* number of other servers */
+ZServerDesc_t *otherservers; /* points to an array of the known
+ servers */
+ZServerDesc_t *me_server; /* pointer to my entry in the array */
+ZNotAcked_t *nacklist; /* list of packets waiting for ack's */
+
+char *programname; /* set to the last element of argv[0] */
+char myname[MAXHOSTNAMELEN]; /* my host name */
+
+int zdebug = 0;
+
+main(argc,argv)
+int argc;
+char **argv;
+{
+ int nfound; /* #fildes ready on select */
+ int nfildes; /* number to look at in select() */
+ int packetsize; /* size of packet received */
+ int authentic; /* authentic flag for ZParseNotice */
+ Code_t status;
+ ZPacket_t new_packet; /* from the network */
+ ZNotice_t new_notice; /* parsed from new_packet */
+ fd_set readable, interesting;
+ struct timeval *tvp;
+ struct sockaddr_in whoisit; /* for holding peer's address */
+
+ int optchar; /* option processing */
+ extern char *optarg;
+ extern int optind;
+
+ /* set name */
+ if (programname = rindex(argv[0],'/'))
+ programname++;
+ else programname = argv[0];
+
+ /* process arguments */
+
+ argv++, argc--;
+
+ while ((optchar = getopt(argc, argv, "d")) != EOF) {
+ switch(optchar) {
+ case 'd':
+ zdebug = 1;
+ case '?':
+ default:
+ usage();
+ /*NOTREACHED*/
+ }
+ }
+
+ /* open log */
+ /* XXX eventually make this LOG_DAEMON */
+ openlog(programname, LOG_PID, LOG_LOCAL6);
+
+ /* set up sockets & my_addr and myname,
+ find other servers and set up server table, initialize queues
+ for retransmits, initialize error tables,
+ set up restricted classes */
+ if (initialize())
+ exit(1);
+
+ FD_ZERO(&interesting);
+ FD_SET(srv_socket, &interesting);
+
+ nfildes = srv_socket + 1;
+
+
+ /* GO! */
+ syslog(LOG_INFO, "Ready for action");
+
+ for EVER {
+ tvp = &nexthost_tv;
+ if (nexttimo != 0L) {
+ nexthost_tv.tv_sec = nexttimo - NOW;
+ nexthost_tv.tv_usec = 0;
+ if (nexthost_tv.tv_sec < 0) { /* timeout has passed! */
+ /* so we process one timeout, then pop to
+ select, polling for input. This way we get
+ work done even if swamped with many
+ timeouts */
+ /* this will reset nexttimo */
+ (void) timer_process();
+ nexthost_tv.tv_sec = 0;
+ }
+ } else { /* no timeouts to process */
+ tvp = (struct timeval *) NULL;
+ }
+ readable = interesting;
+ nfound = select(nfildes, &readable, (fd_set *) NULL,
+ (fd_set *) NULL, tvp);
+ if (nfound < 0) {
+ syslog(LOG_WARNING, "select error: %m");
+ continue;
+ }
+ if (nfound == 0)
+ /* either we timed out for keepalive or we were just
+ polling for input. Either way we want to continue
+ the loop, and process the next timeout */
+ continue;
+ else {
+ if (FD_ISSET(srv_socket, &readable)) {
+ /* handle traffic */
+
+ if (status = ZReceiveNotice(new_packet,
+ sizeof(new_packet),
+ &new_notice,
+ &authentic,
+ &whoisit)) {
+ syslog(LOG_ERR,
+ "bad notice receive: %s",
+ error_message(status));
+ continue;
+ }
+ dispatch(&new_notice, authentic, &whoisit);
+ } else
+ syslog(LOG_ERR, "select weird?!?!");
+ }
+ }
+}
+
+/* Initialize net stuff.
+ Contact Hesiod to find all the other servers, allocate space for the
+ structure, initialize them all to SERV_DEAD with expired timeouts.
+ Initialize the packet ack queues to be empty.
+ Initialize the error tables.
+ */
+
+static int
+initialize()
+{
+ register int i;
+ struct in_addr *serv_addr, *hes_addrs;
+
+ if (do_net_setup())
+ return(1);
+
+ /* talk to hesiod here, set nservers */
+ if ((hes_addrs = get_server_addrs(&nservers)) ==
+ (struct in_addr *) NULL) {
+ syslog(LOG_ERR, "No servers?!?");
+ exit(1);
+ }
+
+ otherservers = (ZServerDesc_t *) malloc(nservers *
+ sizeof(ZServerDesc_t));
+ for (serv_addr = hes_addrs, i = 0; serv_addr; serv_addr++, i++) {
+ if (!bcmp(serv_addr, &my_addr, sizeof(struct sockaddr_in)))
+ me_server = &otherservers[i];
+ otherservers[i].zs_state = SERV_DEAD;
+ otherservers[i].zs_timeout = 0; /* he's due NOW */
+ otherservers[i].zs_numsent = 0;
+ otherservers[i].zs_addr.sin_family = AF_INET;
+ /* he listens to the same port we do */
+ otherservers[i].zs_addr.sin_port = sock_sin.sin_port;
+ otherservers[i].zs_addr.sin_addr = *serv_addr;
+
+ /* set up a timer for this server */
+ otherservers[i].zs_timer =
+ timer_set_rel(0L,
+ server_timo,
+ (caddr_t) &otherservers[i]);
+ if ((otherservers[i].zs_hosts =
+ (ZHostList_t *) malloc(sizeof(ZHostList_t))) == NULLZHLT)
+ {
+ /* unrecoverable */
+ syslog(LOG_CRIT, "zs_host malloc");
+ abort();
+ }
+ }
+ free(hes_addrs);
+ if ((nacklist = (ZNotAcked_t *) malloc(sizeof(ZNotAcked_t))) ==
+ (ZNotAcked_t *) NULL)
+ {
+ /* unrecoverable */
+ syslog(LOG_CRIT, "nacklist malloc");
+ abort();
+ }
+ nacklist->q_forw = nacklist->q_back = NULL;
+
+ nexttimo = 1L; /* trigger the timers when we hit
+ the FOR loop */
+
+ ZInitialize(); /* set up the library */
+ init_zsrv_err_tbl(); /* set up err table */
+
+ ZSetFD(srv_socket); /* set up the socket as the
+ input fildes */
+
+ return;
+}
+
+/*
+ * Set up the server and client sockets, and initialize my_addr and myname
+ */
+
+static int
+do_net_setup()
+{
+ struct servent *sp;
+ struct hostent *hp;
+ char hostname[MAXHOSTNAMELEN+1];
+ int on = 1;
+
+ if (gethostname(hostname, MAXHOSTNAMELEN+1)) {
+ syslog(LOG_ERR, "no hostname: %m");
+ return(1);
+ }
+ if ((hp = gethostbyname(hostname)) == (struct hostent *) NULL) {
+ syslog(LOG_ERR, "no gethostbyname repsonse");
+ strncpy(myname, hostname, MAXHOSTNAMELEN);
+ return(1);
+ }
+ strncpy(myname, hp->h_name, MAXHOSTNAMELEN);
+ bcopy(hp->h_addr, &my_addr, sizeof(hp->h_addr));
+
+ /* note that getservbyname may actually ask hesiod and not
+ /etc/services */
+ (void) setservent(1); /* keep file/connection open */
+
+ if ((sp = getservbyname("zephyr-clt", "udp")) ==
+ (struct servent *) NULL) {
+ syslog(LOG_ERR, "zephyr-clt/udp unknown");
+ return(1);
+ }
+ bzero(sock_sin, sizeof(sock_sin));
+ bcopy(&sock_sin.sin_port, sp->s_port, sizeof(sp->s_port));
+
+ (void) endservent();
+
+ if ((srv_socket = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+ syslog(LOG_ERR, "client_sock failed: %m");
+ return(1);
+ }
+ if (bind (srv_socket, (struct sockaddr *) &sock_sin,
+ sizeof(sock_sin)) < 0) {
+ syslog(LOG_ERR, "client bind failed: %m");
+ return(1);
+ }
+
+ /* set not-blocking */
+ (void) ioctl(srv_socket, FIONBIO, &on);
+
+ return(0);
+}
+
+
+/* get a list of server addresses, from Hesiod. Return a pointer to an
+ array of allocated storage. This storage is freed by the caller.
+ */
+static struct in_addr *
+get_server_addrs(number)
+int *number; /* RETURN */
+{
+ register int i;
+ char **hes_resolve();
+ char **server_hosts;
+ register char **cpp;
+ struct in_addr *addrs;
+ register struct in_addr *addr;
+ register struct hostent *hp;
+
+ /* get the names from Hesiod */
+ if ((server_hosts = hes_resolve("*","ZEPHYR-SERVER")) == (char **)NULL)
+ return((struct in_addr *)NULL);
+
+ /* count up */
+ for (cpp = server_hosts, i = 0; *cpp; cpp++, i++);
+
+ addrs = (struct in_addr *) malloc(i * sizeof(struct in_addr));
+
+ /* Convert to in_addr's */
+ for (cpp = server_hosts, addr = addrs, i = 0; *cpp; cpp++) {
+ hp = gethostbyname(*cpp);
+ if (hp) {
+ bcopy(hp->h_addr, addr, sizeof(struct in_addr));
+ addr++, i++;
+ } else
+ syslog(LOG_WARNING, "hostname failed, %s",*cpp);
+ }
+ *number = i;
+ return(addrs);
+}
+
+static void
+usage()
+{
+ fprintf(stderr,"Usage: %s [-d]\n",programname);
+ exit(2);
+}
diff --git a/server/server.c b/server/server.c
new file mode 100644
index 0000000..c3b94ef
--- /dev/null
+++ b/server/server.c
@@ -0,0 +1,237 @@
+/* This file is part of the Project Athena Zephyr Notification System.
+ * It contains functions for communication with other servers.
+ *
+ * Created by: John T. Kohl
+ *
+ * $Source$
+ * $Author$
+ *
+ * Copyright (c) 1987 by the Massachusetts Institute of Technology.
+ * For copying and distribution information, see the file
+ * "mit-copyright.h".
+ */
+
+#include <zephyr/mit-copyright.h>
+
+#ifndef lint
+static char rcsid_server_s_c[] = "$Header$";
+#endif lint
+
+#include "zserver.h"
+
+/*
+ * Server manager. Deal with traffic to and from other servers.
+ *
+ * void server_timo(which)
+ * ZServerDesc_t *which;
+ *
+ * void server_dispatch(notice, auth, who)
+ * ZNotice_t *notice;
+ * int auth;
+ * struct sockaddr_in *who;
+ *
+ * Code_t server_register(notice, who)
+ * ZNotice_t *notice;
+ * struct sockaddr_in *who;
+ *
+ * ZServerDesc_t *server_owner(who)
+ * struct sockaddl_in *who;
+ *
+ */
+
+static void server_hello(), server_flush(), admin_handle();
+
+/*
+ * A server timout has expired. If enough hello's have been unanswered,
+ * change state and act accordingly. Send a "hello" and reset the timer,
+ * incrementing the number of hello's sent.
+ *
+ * See the FSM in the Zephyr document for a better picture of what's
+ * happening here.
+ */
+
+void
+server_timo(which)
+ZServerDesc_t *which;
+{
+ /* change state and reset if appropriate */
+ switch(which->zs_state) {
+ case SERV_DEAD: /* leave him dead */
+ server_flush(which);
+ break;
+ case SERV_UP: /* he's now tardy */
+ which->zs_state = SERV_TARDY;
+ which->zs_numsent = 0;
+ which->zs_timeout = TIMO_TARDY;
+ break;
+ case SERV_TARDY:
+ case SERV_STARTING:
+ if (which->zs_numsent >= ((which->zs_state == SERV_TARDY) ?
+ H_NUM_TARDY :
+ H_NUM_STARTING)) {
+ /* he hasn't answered, assume DEAD */
+ which->zs_state = SERV_DEAD;
+ which->zs_numsent = 0;
+ which->zs_timeout = TIMO_DEAD;
+ server_flush(which);
+ }
+ break;
+ default:
+ syslog(LOG_ERR,"Bad server state, server 0x%x\n",which);
+ abort();
+ }
+ /* now he's either TARDY, STARTING, or DEAD
+ We send a "hello," which increments the counter */
+ server_hello(which);
+ /* reschedule the timer */
+ which->zs_timer = timer_set_rel(which->zs_timeout, server_timo,
+ (caddr_t) which);
+}
+
+/*
+ * Deal with incoming data on the socket
+ */
+
+void
+server_dispatch(notice, auth, who)
+ZNotice_t *notice;
+int auth;
+struct sockaddr_in *who;
+{
+ struct sockaddr_in newwho;
+ if (class_is_admin(notice))
+ admin_handle(notice, auth);
+ else if (class_is_control(notice)) {
+ /* XXX set up a who for the real origin */
+ newwho.sin_family = AF_INET;
+ bcopy (&notice->z_sender_addr, &newwho.sin_addr, sizeof (struct in_addr));
+ newwho.sin_port = notice->z_port;
+ control_handle(notice, auth, &newwho);
+ } else
+ /* shouldn't come from another server */
+ syslog(LOG_WARNING, "srv_disp: pkt cls %s",notice->z_class);
+ return;
+}
+
+Code_t
+server_register(notice, who)
+ZNotice_t *notice;
+struct sockaddr_in *who;
+{
+ return(1);
+}
+
+ZServerDesc_t *
+server_owner(who)
+struct sockaddr_in *who;
+{
+ register ZServerDesc_t *servs;
+ register int i;
+ register ZHostList_t *hlt;
+
+ for (i = 0, servs = otherservers; i < nservers; i++, servs++ )
+ /* for each server */
+ for (hlt = servs->zs_hosts->q_forw;
+ hlt != servs->zs_hosts;
+ hlt = hlt->q_forw)
+ /* for each host */
+ if (!bcmp(&hlt->zh_addr, &who->sin_addr, sizeof(struct in_addr)))
+ return(servs);
+ /* unowned */
+ return(NULLZSDT);
+}
+
+/* flush all data associated with the server which */
+static void
+server_flush(which)
+register ZServerDesc_t *which;
+{
+ register ZHostList_t *hst;
+ register ZClientList_t *clist = NULLZCLT, *clt;
+ register int status;
+
+ if (which->zs_hosts == NULLZHLT) /* no data to flush */
+ return;
+
+ for (hst = which->zs_hosts->q_forw;
+ hst != which->zs_hosts;
+ hst = which->zs_hosts->q_forw) {
+ /* for each host, flush all data */
+
+ remque(hst); /* unlink */
+ hst->q_forw = hst->q_back = hst; /* clean up */
+
+ if ((status = subscr_cancel_host(&hst->zh_addr, which)) != ZERR_NONE)
+ syslog(LOG_WARNING, "srv_flush: host cancel %s: %s",
+ inet_ntoa(hst->zh_addr),
+ error_message());
+
+ clist = hst->zh_clients;
+
+ for (clt = clist->q_forw; clt != clist; clt = clt->q_forw)
+ /* client_deregister frees this client */
+ if ((status = client_deregister(clt)) != ZERR_NONE)
+ syslog(LOG_WARNING, "srv_flush: bad deregister: %s",
+ error_message(status));
+
+ }
+}
+
+/* send a hello to which, updating the count of hello's sent */
+
+static void
+server_hello(which)
+ZServerDesc_t *which;
+{
+ ZNotice_t hellonotice;
+ register ZNotice_t *phelonotice; /* speed hack */
+ ZPacket_t hellopack;
+ int packlen, tolen;
+ Code_t retval;
+
+ phelonotice = &hellonotice;
+
+ phelonotice->z_kind = ACKED;
+
+ phelonotice->z_checksum[0] = 0; /* filled in by the library */
+ phelonotice->z_checksum[1] = 0;
+
+ phelonotice->z_uid.zuid_addr = my_addr;
+ phelonotice->z_uid.tv.tv_sec = NOW;
+ phelonotice->z_uid.tv.tv_usec = 0;
+ phelonotice->z_port = sock_sin.sin_port;
+ phelonotice->z_class = ZEPHYR_ADMIN_CLASS;
+ phelonotice->z_class_inst = NULL;
+ phelonotice->z_opcode = "HELLO";
+ phelonotice->z_sender = myname; /* myname is the hostname */
+ phelonotice->z_recipient = NULL;
+ phelonotice->z_message = (caddr_t) NULL;
+ phelonotice->z_message_len = 0;
+
+ packlen = sizeof(hellopack);
+
+ if ((retval = ZFormatNotice(phelonotice, hellopack, packlen, &packlen)) != ZERR_NONE) {
+ syslog(LOG_WARNING, "hello format: %s", error_message(retval));
+ return;
+ }
+ if ((retval = ZSetDestAddr(&which->zs_addr)) != ZERR_NONE) {
+ syslog(LOG_WARNING, "hello set addr: %s",
+ error_message(retval));
+ return;
+ }
+ if ((retval = ZSendPacket(hellopack, packlen)) != ZERR_NONE) {
+ syslog(LOG_WARNING, "hello xmit: %s", error_message(retval));
+ return;
+ }
+ (which->zs_numsent)++;
+ return;
+}
+
+static void
+admin_handle(notice, auth)
+ZNotice_t *notice;
+int auth;
+{
+ syslog(LOG_INFO, "ADMIN received\n");
+ return;
+}
diff --git a/server/subscr.c b/server/subscr.c
new file mode 100644
index 0000000..2036f47
--- /dev/null
+++ b/server/subscr.c
@@ -0,0 +1,389 @@
+/* This file is part of the Project Athena Zephyr Notification System.
+ * It contains functions for managing subscription lists.
+ *
+ * Created by: John T. Kohl
+ *
+ * $Source$
+ * $Author$
+ *
+ * Copyright (c) 1987 by the Massachusetts Institute of Technology.
+ * For copying and distribution information, see the file
+ * "mit-copyright.h".
+ */
+
+#include <zephyr/mit-copyright.h>
+
+#ifndef lint
+static char rcsid_subscr_s_c[] = "$Header$";
+#endif lint
+
+/*
+ * The subscription manager.
+ *
+ * External functions:
+ *
+ * Code_t subscr_subscribe(notice)
+ * ZNotice_t *notice;
+ *
+ * Code_t subscr_cancel(notice)
+ * ZNotice_t *notice;
+ *
+ * Code_t subscr_cancel_client(client)
+ * ZClient_t *client;
+ *
+ * Code_t subscr_cancel_host(addr)
+ * struct in_addr *addr;
+ *
+ * ZClientList_t *subscr_match_list(notice)
+ * ZNotice_t *notice;
+ *
+ * void subscr_list_free(list)
+ * ZClientList_t *list;
+ *
+ */
+
+#include "zserver.h"
+
+extern char *re_comp(), *rindex(), *index();
+static ZSubscr_t *extract_subscriptions();
+static int subscr_equiv();
+static void free_subscriptions(), free_sub();
+
+Code_t
+subscr_subscribe(notice)
+ZNotice_t *notice;
+{
+ ZClient_t *who;
+ register ZSubscr_t *subs, *subs2, *newsubs, *subs3;
+ Code_t retval;
+
+ if ((who = client_which_client(notice)) == NULLZCNT)
+ return(ZSRV_NOCLT);
+
+ if (who->zct_subs == NULLZST) {
+ /* allocate a subscription head */
+ if ((subs = (ZSubscr_t *) malloc(sizeof(ZSubscr_t))) == NULLZST)
+ return(ENOMEM);
+ subs->q_forw = subs->q_back = subs;
+ who->zct_subs = subs;
+ }
+
+ if ((newsubs = extract_subscriptions(notice)) == NULLZST)
+ return(ZERR_NONE); /* no subscr -> no error */
+
+ for (subs = newsubs->q_forw;
+ subs != newsubs;
+ subs = subs->q_forw) {
+ /* for each new subscription */
+
+ for (subs2 = who->zct_subs->q_forw;
+ subs2 != who->zct_subs;
+ subs2 = subs2->q_forw) {
+ /* for each existing subscription */
+ if (subscr_equiv(subs, subs2)) /* duplicate? */
+ goto duplicate;
+ }
+
+ /* ok, we are a new subscription. register and chain on. */
+
+ if ((subs3 = (ZSubscr_t *) malloc(sizeof(ZSubscr_t))) == NULLZST) {
+ free_subscriptions(newsubs);
+ return(ENOMEM);
+ }
+
+ if ((retval = class_register(who, subs->zst_class)) != ZERR_NONE) {
+ free_subscriptions(newsubs);
+ return(retval);
+ }
+
+ subs3->zst_class = strsave(subs->zst_class);
+ subs3->zst_classinst = strsave(subs->zst_classinst);
+ subs3->zst_recipient = strsave(subs->zst_recipient);
+
+ insque(who->zct_subs, subs3);
+
+duplicate: ; /* just go on to the next */
+ }
+
+ free_subscriptions(newsubs);
+ return(ZERR_NONE);
+}
+
+/* are the subscriptions the same? 1=yes, 0=no */
+
+static int
+subscr_equiv(s1, s2)
+register ZSubscr_t *s1, *s2;
+{
+ if (strcmp(s1->zst_class,s2->zst_class))
+ return(0);
+ if (strcmp(s1->zst_classinst,s2->zst_classinst))
+ return(0);
+ if (strcmp(s1->zst_recipient,s2->zst_recipient))
+ return(0);
+ return(1);
+}
+
+static ZSubscr_t *
+extract_subscriptions(notice)
+register ZNotice_t *notice;
+{
+ register ZSubscr_t *subs = NULLZST, *subs2;
+ register int len = notice->z_message_len;
+ register char *recip, *class, *classinst;
+ register char *cp = notice->z_message;
+ char *buf;
+
+ /* parse the data area for the subscriptions */
+ while (cp < notice->z_message + notice->z_message_len) {
+ recip = buf = cp;
+ if ((cp = index(buf, ',')) == NULL) {
+ syslog(LOG_WARNING, "malformed subscription 1 %s",
+ buf);
+ return(subs);
+ }
+ *cp++ = '\0';
+ class = buf = cp;
+ if ((cp = index(buf, ',')) == NULL) {
+ syslog(LOG_WARNING, "malformed subscription 2 %s",
+ buf);
+ return(subs);
+ }
+ *cp++ = '\0';
+ classinst = cp;
+ cp += strlen(classinst);
+ if (subs == NULLZST) {
+ if ((subs = (ZSubscr_t *) malloc(sizeof(ZSubscr_t))) == NULLZST) {
+ syslog(LOG_WARNING, "ex_subs: no mem");
+ return(NULLZST);
+ }
+ subs->q_forw = subs->q_back = subs;
+ }
+ if ((subs2 = (ZSubscr_t *) malloc(sizeof(ZSubscr_t))) == NULLZST) {
+ syslog(LOG_WARNING, "ex_subs: no mem 2");
+ return(NULLZST);
+ }
+ subs2->zst_class = strsave(class);
+ subs2->zst_classinst = strsave(classinst);
+ subs2->zst_recipient = strsave(recip);
+
+ insque(subs, subs2);
+ }
+ return;
+}
+
+static void
+free_subscriptions(subs)
+register ZSubscr_t *subs;
+{
+ register ZSubscr_t *sub;
+
+ free(subs->zst_class);
+ free(subs->zst_classinst);
+ free(subs->zst_recipient);
+
+ for (sub = subs->q_forw; sub != subs; sub = subs->q_forw) {
+ free(sub->zst_class);
+ free(sub->zst_classinst);
+ free(sub->zst_recipient);
+ remque(sub);
+ free(sub);
+ }
+ free(subs);
+ return;
+}
+
+Code_t
+subscr_cancel(notice)
+ZNotice_t *notice;
+{
+ ZClient_t *who;
+ register ZSubscr_t *subs, *subs2;
+ Code_t retval;
+
+ if ((who = client_which_client(notice)) == NULLZCNT)
+ return(ZSRV_NOCLT);
+
+ if (who->zct_subs == NULLZST)
+ return(ZSRV_NOSUB);
+
+ if ((subs = extract_subscriptions(notice)) == NULLZST)
+ return(ZERR_NONE); /* no subscr -> no error */
+
+ for (subs2 = who->zct_subs->q_forw;
+ subs2 != who->zct_subs;
+ subs2 = subs2->q_forw) {
+ /* for each existing subscription */
+ if (subscr_equiv(subs, subs2)) { /* duplicate? */
+ remque(subs2);
+ if (class_deregister(who, subs2->zst_class) != ZERR_NONE) {
+ syslog(LOG_ERR, "subscr_cancel: not registered!");
+ abort();
+ /*NOTREACHED*/
+ }
+ free_sub(subs2);
+ return(ZERR_NONE);
+ }
+ }
+ return(ZSRV_NOSUB);
+}
+
+static void
+free_sub(sub)
+ZSubscr_t *sub;
+{
+ free(sub->zst_class);
+ free(sub->zst_classinst);
+ free(sub->zst_recipient);
+ free(sub);
+ return;
+}
+
+Code_t
+subscr_cancel_client(client)
+register ZClient_t *client;
+{
+ register ZSubscr_t *subs;
+
+ if (client->zct_subs == NULLZST)
+ return(ZERR_NONE);
+
+ for (subs = client->zct_subs->q_forw;
+ subs != client->zct_subs;
+ subs = client->zct_subs->q_forw) {
+ if (class_deregister(client, subs->zst_class) != ZERR_NONE) {
+ syslog(LOG_ERR, "sub_can_clt: not registered!");
+ abort();
+ /*NOTREACHED*/
+ }
+ remque(subs);
+ free_sub(subs);
+ }
+ return(ZERR_NONE);
+}
+
+Code_t
+subscr_cancel_host(addr, server)
+struct in_addr *addr;
+ZServerDesc_t *server;
+{
+ register ZHostList_t *hosts;
+ register ZClientList_t *clist = NULLZCLT, *clt;
+
+ /* find list of clients */
+ for (hosts = server->zs_hosts;
+ hosts != server->zs_hosts;
+ hosts = hosts->q_forw) {
+ if (!bcmp(*addr, hosts->zh_addr, sizeof (struct in_addr))) {
+ clist = hosts->zh_clients;
+ break;
+ }
+ }
+ if (hosts != server->zs_hosts)
+ return(ZSRV_WRONGSRV);
+
+ /* flush each one */
+ for (clt = clist->q_forw; clt != clist; clt = clt->q_forw)
+ (void) subscr_cancel_client(clt);
+ return(ZERR_NONE);
+}
+
+/*
+ * Here is the bulk of the work in the subscription manager.
+ * We grovel over the list of clients possibly interested in this
+ * notice, and copy into a list on a match.
+ */
+
+ZClientList_t *
+subscr_match_list(notice)
+ZNotice_t *notice;
+{
+ register ZClientList_t *hits, *clients, *clients2, *hit2;
+
+ if ((hits = (ZClientList_t *) malloc(sizeof(ZClientList_t))) == NULLZCLT)
+ return(NULLZCLT);
+ hits->q_forw = hits->q_back = hits;
+
+ if ((clients = class_lookup(notice->z_class)) == NULLZCLT)
+ return(NULLZCLT);
+
+ for (clients2 = clients->q_forw;
+ clients2 != clients;
+ clients2 = clients2->q_forw)
+ if (client_match(notice, clients2->zclt_client)) {
+ /* we hit */
+ if ((hit2 = (ZClientList_t *) malloc(sizeof(ZClientList_t))) == NULLZCLT) {
+ syslog(LOG_WARNING, "subscr_match: punting/no mem");
+ return(hits);
+ }
+ hit2->zclt_client = clients2->zclt_client;
+ insque(hits, hit2);
+ }
+
+
+ if (hits->q_forw == hits)
+ return(NULLZCLT);
+ return(hits);
+}
+
+void
+subscr_list_free(list)
+ZClientList_t *list;
+{
+ register ZClientList_t *lyst;
+
+ for (lyst = list->q_forw; lyst != list; lyst = list->q_forw) {
+ remque(lyst);
+ free(lyst);
+ }
+ free(list);
+ return;
+}
+
+#define ZCLASS_MATCHALL "ZMATCH_ALL"
+/*
+ * is this client listening to this notice? 1=yes, 0=no
+ */
+static int
+client_match(notice, client)
+register ZNotice_t *notice;
+register ZClient_t *client;
+{
+ register ZSubscr_t *subs;
+ char *reresult;
+
+ if (client->zct_subs == NULLZST) {
+ syslog(LOG_WARNING, "client_match w/ no subs");
+ return(0);
+ }
+
+ for (subs = client->zct_subs->q_forw;
+ subs != client->zct_subs;
+ subs = subs->q_forw) {
+ /* for each subscription, do regex matching */
+ /* we don't regex the class, since wildcard
+ matching on the class is disallowed. However,
+ we do check for the Magic Class */
+ if (strcmp(ZCLASS_MATCHALL, subs->zst_class) &&
+ strcmp(notice->z_class, subs->zst_class))
+ continue; /* no match */
+ if ((reresult = re_comp(subs->zst_classinst)) != NULL) {
+ syslog(LOG_WARNING, "re_comp error %s on '%s'",
+ reresult, subs->zst_classinst);
+ continue;
+ }
+ if (!re_exec(notice->z_class_inst))
+ continue;
+ if ((reresult = re_comp(subs->zst_recipient)) != NULL) {
+ syslog(LOG_WARNING, "re_comp error %s on '%s'",
+ reresult, subs->zst_recipient);
+ continue;
+ }
+ if (!re_exec(notice->z_recipient))
+ continue;
+ /* OK, we matched */
+ return(1);
+ }
+ /* fall through */
+ return(0);
+}