/* 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,1988,1991 by the Massachusetts Institute of Technology. * For copying and distribution information, see the file * "mit-copyright.h". */ #include #include "zserver.h" #include #if !defined (lint) && !defined (SABER) static const char rcsid_client_c[] = "$Id$"; #endif /* * External functions: * * Code_t client_register(notice, who, client, server, wantdefaults) * ZNotice_t *notice; * struct sockaddr_in *who; * Client **client; (RETURN) * Server *server; * int wantdefaults; * * Code_t client_deregister(client, host, flush) * Client *client; * Host *host; * int flush; * * Client *client_which_client(who, notice) * struct sockaddr_in *who; * ZNotice_t *notice; * * void client_dump_clients(fp, clist) * FILE *fp; * Client *clist; */ /* * 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 */ #define HASHSIZE 1024 static Client *client_bucket[HASHSIZE]; #define INET_HASH(host, port) ((htonl((host)->s_addr) + \ htons((unsigned short) (port))) % HASHSIZE) static Client *client_find __P((struct in_addr *host, unsigned int port)); Code_t client_register(notice, host, client_p, wantdefaults) ZNotice_t *notice; struct in_addr *host; Client **client_p; int wantdefaults; { Client *client; Code_t retval; /* chain the client's host onto this server's host list */ #if 1 zdbug((LOG_DEBUG, "client_register: adding %s at %s/%d", notice->z_sender, inet_ntoa(*host), ntohs(notice->z_port))); #endif if (!notice->z_port) return ZSRV_BADSUBPORT; *client_p = client = client_find(host, notice->z_port); if (!client) { *client_p = client = (Client *) malloc(sizeof(Client)); if (!client) return ENOMEM; memset(&client->addr, 0, sizeof(struct sockaddr_in)); #ifdef KERBEROS memset(&client->session_key, 0, sizeof(client->session_key)); #endif client->last_msg = 0; client->last_send = 0; client->addr.sin_family = AF_INET; client->addr.sin_addr.s_addr = host->s_addr; client->addr.sin_port = notice->z_port; client->subs = NULL; client->realm = NULL; client->principal = make_string(notice->z_sender, 0); LIST_INSERT(&client_bucket[INET_HASH(&client->addr.sin_addr, notice->z_port)], client); } /* Add default subscriptions only if this is not resulting from a brain * dump, AND this request wants defaults. */ if (!bdumping && wantdefaults) return subscr_def_subs(client); else return ZERR_NONE; } /* * Deregister the client, freeing resources. * Remove any packets in the nack queue, release subscriptions, release * locations, and dequeue him from the host. */ void client_deregister(client, flush) Client *client; int flush; { LIST_DELETE(client); nack_release(client); subscr_cancel_client(client); free_string(client->principal); if (flush) uloc_flush_client(&client->addr); free(client); } void client_flush_host(host) struct in_addr *host; { int i; Client *client, *next; for (i = 0; i < HASHSIZE; i++) { for (client = client_bucket[i]; client; client = next) { next = client->next; if (client->addr.sin_addr.s_addr == host->s_addr) client_deregister(client, 1); } } uloc_hflush(host); } /* * find the client which sent the notice */ Client * client_which_client(host, notice) struct in_addr *host; ZNotice_t *notice; { return client_find(host, notice->z_port); } Code_t client_send_clients() { int i; Client *client; Code_t retval; for (i = 0; i < HASHSIZE; i++) { /* Allow packets to be processed between rows of the hash table. */ if (packets_waiting()) { bdumping = 0; bdump_concurrent = 1; handle_packet(); bdump_concurrent = 0; bdumping = 1; } for (client = client_bucket[i]; client; client = client->next) { if (client->subs) { retval = subscr_send_subs(client); if (retval != ZERR_NONE) return retval; } } } return ZERR_NONE; } /* * dump info about clients in this clist onto the fp. * assumed to be called with SIGFPE blocked * (true if called from signal handler) */ void client_dump_clients(fp) FILE *fp; { Client *client; int i; for (i = 0; i < HASHSIZE; i++) { for (client = client_bucket[i]; client; client = client->next) { fprintf(fp, "\t%d (%s):\n", ntohs(client->addr.sin_port), client->principal->string); subscr_dump_subs(fp, client->subs); } } } static Client * client_find(host, port) struct in_addr *host; unsigned int port; { Client *client; long hashval; hashval = INET_HASH(host, port); for (client = client_bucket[hashval]; client; client = client->next) { if (client->addr.sin_addr.s_addr == host->s_addr && client->addr.sin_port == port) return client; } return NULL; }