diff options
author | John Kohl <jtkohl@mit.edu> | 1987-06-19 06:29:53 +0000 |
---|---|---|
committer | John Kohl <jtkohl@mit.edu> | 1987-06-19 06:29:53 +0000 |
commit | ff687ceff9d00d35f0d9df0c86f2fee5b111059d (patch) | |
tree | 7066993d388bfa4280008eed76228354da7a5792 | |
parent | 0543936bef46ef47a12601373a1cf16f0301d808 (diff) |
Initial revision
-rw-r--r-- | server/access.c | 41 | ||||
-rw-r--r-- | server/bdump.c | 32 | ||||
-rw-r--r-- | server/client.c | 126 | ||||
-rw-r--r-- | server/dispatch.c | 247 | ||||
-rw-r--r-- | server/main.c | 346 | ||||
-rw-r--r-- | server/server.c | 237 | ||||
-rw-r--r-- | server/subscr.c | 389 |
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, ¬ice->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 (¬ice->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); +} |