]> asedeno.scripts.mit.edu Git - 1ts-debian.git/blob - zephyr/server/client.c
r4262@bucket (orig r252): kcr | 2008-01-20 22:11:00 -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     Code_t retval;
69
70     /* chain the client's host onto this server's host list */
71
72 #if 1
73     zdbug((LOG_DEBUG, "client_register: adding %s at %s/%d",
74            notice->z_sender, inet_ntoa(*host), ntohs(notice->z_port)));
75 #endif
76
77     if (!notice->z_port)
78         return ZSRV_BADSUBPORT;
79
80     *client_p = client = client_find(host, notice->z_port);
81     if (!client) {
82         *client_p = client = (Client *) malloc(sizeof(Client));
83         if (!client)
84             return ENOMEM;
85         memset(&client->addr, 0, sizeof(struct sockaddr_in));
86 #ifdef HAVE_KRB5
87         client->session_keyblock = NULL;
88 #else
89 #ifdef HAVE_KRB4
90         memset(&client->session_key, 0, sizeof(client->session_key));
91 #endif
92 #endif
93         client->last_send = 0;
94         client->last_ack = NOW;
95         client->addr.sin_family = AF_INET;
96         client->addr.sin_addr.s_addr = host->s_addr;
97         client->addr.sin_port = notice->z_port;
98         client->subs = NULL;
99         client->realm = NULL;
100         client->principal = make_string(notice->z_sender, 0);
101         LIST_INSERT(&client_bucket[INET_HASH(&client->addr.sin_addr,
102                                              notice->z_port)], client);
103     }
104
105     /* Add default subscriptions only if this is not resulting from a brain
106      * dump, AND this request wants defaults. */
107     if (!bdumping && wantdefaults)
108         return subscr_def_subs(client);
109     else
110         return ZERR_NONE;
111 }
112
113 /*
114  * Deregister the client, freeing resources.  
115  * Remove any packets in the nack queue, release subscriptions, release
116  * locations, and dequeue him from the host.
117  */
118
119 void
120 client_deregister(Client *client,
121                   int flush)
122 {
123     LIST_DELETE(client);
124     nack_release(client);
125     subscr_cancel_client(client);
126     free_string(client->principal);
127 #ifdef HAVE_KRB5
128     if (client->session_keyblock)
129          krb5_free_keyblock(Z_krb5_ctx, client->session_keyblock);
130 #endif
131     if (flush)
132         uloc_flush_client(&client->addr);
133     free(client);
134 }
135
136 void
137 client_flush_host(struct in_addr *host)
138 {
139     int i;
140     Client *client, *next;
141
142     for (i = 0; i < HASHSIZE; i++) {
143         for (client = client_bucket[i]; client; client = next) {
144             next = client->next;
145             if (client->addr.sin_addr.s_addr == host->s_addr)
146                 client_deregister(client, 1);
147         }
148     }
149     uloc_hflush(host);
150 }
151
152 Code_t
153 client_send_clients(void)
154 {
155     int i;
156     Client *client;
157     Code_t retval;
158
159     for (i = 0; i < HASHSIZE; i++) {
160         /* Allow packets to be processed between rows of the hash table. */
161         if (packets_waiting()) {
162             bdumping = 0;
163             bdump_concurrent = 1;
164             handle_packet();
165             bdump_concurrent = 0;
166             bdumping = 1;
167         }
168         for (client = client_bucket[i]; client; client = client->next) {
169             if (client->subs) {
170                 retval = subscr_send_subs(client);
171                 if (retval != ZERR_NONE)
172                     return retval;
173             }
174         }
175     }
176     return ZERR_NONE;
177 }
178
179 /*
180  * dump info about clients in this clist onto the fp.
181  * assumed to be called with SIGFPE blocked
182  * (true if called from signal handler)
183  */
184
185 void
186 client_dump_clients(FILE *fp)
187 {
188     Client *client;
189     int i;
190
191     for (i = 0; i < HASHSIZE; i++) {
192         for (client = client_bucket[i]; client; client = client->next) {
193             fprintf(fp, "%s/%d (%s):\n", inet_ntoa(client->addr.sin_addr),
194                     ntohs(client->addr.sin_port), client->principal->string);
195             subscr_dump_subs(fp, client->subs);
196         }
197     }
198 }
199
200 /*
201  * find a client by host and port
202  */
203
204 Client *
205 client_find(struct in_addr *host,
206             unsigned int port)
207 {
208     Client *client;
209     long hashval;
210
211     hashval = INET_HASH(host, port);
212     for (client = client_bucket[hashval]; client; client = client->next) {
213         if (client->addr.sin_addr.s_addr == host->s_addr
214             && client->addr.sin_port == port)
215             return client;
216     }
217     return NULL;
218 }
219