]> asedeno.scripts.mit.edu Git - 1ts-debian.git/blob - zephyr/server/client.c
r4275@bucket (orig r265): kcr | 2008-01-21 02:57:32 -0500
[1ts-debian.git] / zephyr / server / client.c
1 /* This file is part of the Project Athena Zephyr Notification System.
2  * It contains functions for the Client Manager subsystem of the Zephyr server.
3  *
4  *      Created by:     John T. Kohl
5  *
6  *      $Id$
7  *
8  *      Copyright (c) 1987,1988,1991 by the Massachusetts Institute of Technology.
9  *      For copying and distribution information, see the file
10  *      "mit-copyright.h". 
11  */
12
13 #include <zephyr/mit-copyright.h>
14 #include "zserver.h"
15 #include <sys/socket.h>
16
17 #if !defined (lint) && !defined (SABER)
18 static const char rcsid_client_c[] =
19 "$Id$";
20 #endif
21
22 /*
23  * External functions:
24  *
25  * Code_t client_register(notice, who, client, server, wantdefaults)
26  *      ZNotice_t *notice;
27  *      struct sockaddr_in *who;
28  *      Client **client; (RETURN)
29  *      Server *server;
30  *      int wantdefaults;
31  *
32  * Code_t client_deregister(client, host, flush)
33  *      Client *client;
34  *      Host *host;
35  *      int flush;
36  *
37  * Client *client_find(who, unsigned int port)
38  *      struct in_addr *host;
39  *      unsigned int port;
40  *
41  * void client_dump_clients(fp, clist)
42  *      FILE *fp;
43  *      Client *clist;
44  */
45
46 /*
47  * a client: allocate space, find or insert the address in the
48  *      server's list of hosts, initialize and insert the client into
49  *      the host's list of clients.
50  *
51  * This routine assumes that the client has not been registered yet.
52  * The caller should check by calling client_find.
53  */
54
55 #define HASHSIZE 1024
56 static Client *client_bucket[HASHSIZE];
57
58 #define INET_HASH(host, port) ((htonl((host)->s_addr) + \
59                                 htons((unsigned short) (port))) % HASHSIZE)
60
61 Code_t
62 client_register(ZNotice_t *notice,
63                 struct in_addr *host,
64                 Client **client_p,
65                 int wantdefaults)
66 {
67     Client *client;
68
69     /* chain the client's host onto this server's host list */
70
71 #if 1
72     zdbug((LOG_DEBUG, "client_register: adding %s at %s/%d",
73            notice->z_sender, inet_ntoa(*host), ntohs(notice->z_port)));
74 #endif
75
76     if (!notice->z_port)
77         return ZSRV_BADSUBPORT;
78
79     *client_p = client = client_find(host, notice->z_port);
80     if (!client) {
81         *client_p = client = (Client *) malloc(sizeof(Client));
82         if (!client)
83             return ENOMEM;
84         memset(&client->addr, 0, sizeof(struct sockaddr_in));
85 #ifdef HAVE_KRB5
86         client->session_keyblock = NULL;
87 #else
88 #ifdef HAVE_KRB4
89         memset(&client->session_key, 0, sizeof(client->session_key));
90 #endif
91 #endif
92         client->last_send = 0;
93         client->last_ack = NOW;
94         client->addr.sin_family = AF_INET;
95         client->addr.sin_addr.s_addr = host->s_addr;
96         client->addr.sin_port = notice->z_port;
97         client->subs = NULL;
98         client->realm = NULL;
99         client->principal = make_string(notice->z_sender, 0);
100         Client_insert(&client_bucket[INET_HASH(&client->addr.sin_addr,
101                                                notice->z_port)], client);
102     }
103
104     /* Add default subscriptions only if this is not resulting from a brain
105      * dump, AND this request wants defaults. */
106     if (!bdumping && wantdefaults)
107         return subscr_def_subs(client);
108     else
109         return ZERR_NONE;
110 }
111
112 /*
113  * Deregister the client, freeing resources.  
114  * Remove any packets in the nack queue, release subscriptions, release
115  * locations, and dequeue him from the host.
116  */
117
118 void
119 client_deregister(Client *client,
120                   int flush)
121 {
122     Client_delete(client);
123     nack_release(client);
124     subscr_cancel_client(client);
125     free_string(client->principal);
126 #ifdef HAVE_KRB5
127     if (client->session_keyblock)
128          krb5_free_keyblock(Z_krb5_ctx, client->session_keyblock);
129 #endif
130     if (flush)
131         uloc_flush_client(&client->addr);
132     free(client);
133 }
134
135 void
136 client_flush_host(struct in_addr *host)
137 {
138     int i;
139     Client *client, *next;
140
141     for (i = 0; i < HASHSIZE; i++) {
142         for (client = client_bucket[i]; client; client = next) {
143             next = client->next;
144             if (client->addr.sin_addr.s_addr == host->s_addr)
145                 client_deregister(client, 1);
146         }
147     }
148     uloc_hflush(host);
149 }
150
151 Code_t
152 client_send_clients(void)
153 {
154     int i;
155     Client *client;
156     Code_t retval;
157
158     for (i = 0; i < HASHSIZE; i++) {
159         /* Allow packets to be processed between rows of the hash table. */
160         if (packets_waiting()) {
161             bdumping = 0;
162             bdump_concurrent = 1;
163             handle_packet();
164             bdump_concurrent = 0;
165             bdumping = 1;
166         }
167         for (client = client_bucket[i]; client; client = client->next) {
168             if (client->subs) {
169                 retval = subscr_send_subs(client);
170                 if (retval != ZERR_NONE)
171                     return retval;
172             }
173         }
174     }
175     return ZERR_NONE;
176 }
177
178 /*
179  * dump info about clients in this clist onto the fp.
180  * assumed to be called with SIGFPE blocked
181  * (true if called from signal handler)
182  */
183
184 void
185 client_dump_clients(FILE *fp)
186 {
187     Client *client;
188     int i;
189
190     for (i = 0; i < HASHSIZE; i++) {
191         for (client = client_bucket[i]; client; client = client->next) {
192             fprintf(fp, "%s/%d (%s):\n", inet_ntoa(client->addr.sin_addr),
193                     ntohs(client->addr.sin_port), client->principal->string);
194             subscr_dump_subs(fp, client->subs);
195         }
196     }
197 }
198
199 /*
200  * find a client by host and port
201  */
202
203 Client *
204 client_find(struct in_addr *host,
205             unsigned int port)
206 {
207     Client *client;
208     long hashval;
209
210     hashval = INET_HASH(host, port);
211     for (client = client_bucket[hashval]; client; client = client->next) {
212         if (client->addr.sin_addr.s_addr == host->s_addr
213             && client->addr.sin_port == port)
214             return client;
215     }
216     return NULL;
217 }
218