aboutsummaryrefslogtreecommitdiff
path: root/src/core/gnunet-service-core_clients.c
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2011-10-06 13:19:16 +0000
committerChristian Grothoff <christian@grothoff.org>2011-10-06 13:19:16 +0000
commit4a5fc4b938bc98a2edc71d4875779619d0cebeec (patch)
treea816afcf4e6d7c25e0ea8217dc89d810b8fa1eac /src/core/gnunet-service-core_clients.c
parent2fb1bb841a5a7ce3783d84cea68938a8202928aa (diff)
downloadgnunet-4a5fc4b938bc98a2edc71d4875779619d0cebeec.tar.gz
gnunet-4a5fc4b938bc98a2edc71d4875779619d0cebeec.zip
stuff
Diffstat (limited to 'src/core/gnunet-service-core_clients.c')
-rw-r--r--src/core/gnunet-service-core_clients.c739
1 files changed, 319 insertions, 420 deletions
diff --git a/src/core/gnunet-service-core_clients.c b/src/core/gnunet-service-core_clients.c
index 791e9f5f9..a0d5da65c 100644
--- a/src/core/gnunet-service-core_clients.c
+++ b/src/core/gnunet-service-core_clients.c
@@ -29,6 +29,8 @@
29#include "gnunet_service_core.h" 29#include "gnunet_service_core.h"
30#include "gnunet_service_core_clients.h" 30#include "gnunet_service_core_clients.h"
31#include "gnunet_service_core_sessions.h" 31#include "gnunet_service_core_sessions.h"
32#include "gnunet_service_core_typemap.h"
33
32 34
33 35
34/** 36/**
@@ -80,74 +82,42 @@ struct Client
80 82
81 83
82/** 84/**
83 * Record kept for each request for transmission issued by a 85 * Head of linked list of our clients.
84 * client that is still pending.
85 */ 86 */
86struct ClientActiveRequest 87static struct Client *client_head;
87{
88
89 /**
90 * Active requests are kept in a doubly-linked list of
91 * the respective target peer.
92 */
93 struct ClientActiveRequest *next;
94
95 /**
96 * Active requests are kept in a doubly-linked list of
97 * the respective target peer.
98 */
99 struct ClientActiveRequest *prev;
100
101 /**
102 * Handle to the client.
103 */
104 struct Client *client;
105
106 /**
107 * By what time would the client want to see this message out?
108 */
109 struct GNUNET_TIME_Absolute deadline;
110
111 /**
112 * How important is this request.
113 */
114 uint32_t priority;
115
116 /**
117 * How many more requests does this client have?
118 */
119 uint32_t queue_size;
120
121 /**
122 * How many bytes does the client intend to send?
123 */
124 uint16_t msize;
125
126 /**
127 * Unique request ID (in big endian).
128 */
129 uint16_t smr_id;
130
131};
132
133
134 88
135/** 89/**
136 * Linked list of our clients. 90 * Tail of linked list of our clients.
137 */ 91 */
138static struct Client *clients; 92static struct Client *client_tail;
139 93
140/** 94/**
141 * Context for notifications we need to send to our clients. 95 * Context for notifications we need to send to our clients.
142 */ 96 */
143static struct GNUNET_SERVER_NotificationContext *notifier; 97static struct GNUNET_SERVER_NotificationContext *notifier;
144 98
99/**
100 * Tokenizer for messages received from clients.
101 */
102static struct GNUNET_SERVER_MessageStreamTokenizer *client_mst;
103
145 104
146/** 105/**
147 * Our message stream tokenizer (for encrypted payload). 106 * Lookup our client struct given the server's client handle.
107 *
108 * @param client server client handle to look up
109 * @return our client handle for the client
148 */ 110 */
149static struct GNUNET_SERVER_MessageStreamTokenizer *mst; 111static struct Client *
112find_client (struct GNUNET_SERVER_Client *client)
113{
114 struct Client *c;
150 115
116 c = client_head;
117 while ((c != NULL) && (c->client_handle != client))
118 c = c->next;
119 return c;
120}
151 121
152 122
153/** 123/**
@@ -159,7 +129,8 @@ static struct GNUNET_SERVER_MessageStreamTokenizer *mst;
159 * client's queue is getting too large? 129 * client's queue is getting too large?
160 */ 130 */
161static void 131static void
162send_to_client (struct Client *client, const struct GNUNET_MessageHeader *msg, 132send_to_client (struct Client *client,
133 const struct GNUNET_MessageHeader *msg,
163 int can_drop) 134 int can_drop)
164{ 135{
165#if DEBUG_CORE_CLIENT 136#if DEBUG_CORE_CLIENT
@@ -173,79 +144,142 @@ send_to_client (struct Client *client, const struct GNUNET_MessageHeader *msg,
173} 144}
174 145
175 146
147/**
148 * Test if the client is interested in messages of the given type.
149 *
150 * @param type message type
151 * @param c client to test
152 * @return GNUNET_YES if 'c' is interested, GNUNET_NO if not.
153 */
154static int
155type_match (uint16_t type,
156 struct Client *c)
157{
158 unsigned int i;
176 159
160 for (i=0;i<c->tcnt;i++)
161 if (type == c->types[i])
162 return GNUNET_YES;
163 return GNUNET_NO;
164}
177 165
178 166
179/** 167/**
180 * Send a message to all of our current clients that have 168 * Send a message to all of our current clients that have the right
181 * the right options set. 169 * options set.
182 * 170 *
183 * @param msg message to multicast 171 * @param msg message to multicast
184 * @param can_drop can this message be discarded if the queue is too long 172 * @param can_drop can this message be discarded if the queue is too long
185 * @param options mask to use 173 * @param options mask to use
174 * @param type type of the embedded message, 0 for none
186 */ 175 */
187static void 176static void
188send_to_all_clients (const struct GNUNET_MessageHeader *msg, int can_drop, 177send_to_all_clients (const struct GNUNET_MessageHeader *msg,
189 int options) 178 int can_drop,
179 int options,
180 uint16_t type)
190{ 181{
191 struct Client *c; 182 struct Client *c;
192 183
193 c = clients; 184 for (c = client_head; c != NULL; c = c->next)
194 while (c != NULL)
195 { 185 {
196 if (0 != (c->options & options)) 186 if ( (0 == (c->options & options)) &&
197 { 187 (GNUNET_YES != type_match (type, c)) )
188 continue;
198#if DEBUG_CORE_CLIENT > 1 189#if DEBUG_CORE_CLIENT > 1
199 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 190 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
200 "Sending message of type %u to client.\n", 191 "Sending message of type %u to client.\n",
201 (unsigned int) ntohs (msg->type)); 192 (unsigned int) ntohs (msg->type));
202#endif 193#endif
203 send_to_client (c, msg, can_drop); 194 send_to_client (c, msg, can_drop);
204 }
205 c = c->next;
206 } 195 }
207} 196}
208 197
209 198
199/**
200 * Handle CORE_INIT request.
201 *
202 * @param cls unused
203 * @param client new client that sent INIT
204 * @param message the 'struct InitMessage' (presumably)
205 */
206static void
207handle_client_init (void *cls, struct GNUNET_SERVER_Client *client,
208 const struct GNUNET_MessageHeader *message)
209{
210 const struct InitMessage *im;
211 struct InitReplyMessage irm;
212 struct Client *c;
213 uint16_t msize;
214 const uint16_t *types;
215 uint16_t *wtypes;
216 unsigned int i;
217
218 /* check that we don't have an entry already */
219 c = find_client (client);
220 if (NULL != c)
221 {
222 GNUNET_break (0);
223 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
224 return;
225 }
226 msize = ntohs (message->size);
227 if (msize < sizeof (struct InitMessage))
228 {
229 GNUNET_break (0);
230 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
231 return;
232 }
233 GNUNET_SERVER_notification_context_add (notifier, client);
234 im = (const struct InitMessage *) message;
235 types = (const uint16_t *) &im[1];
236 msize -= sizeof (struct InitMessage);
237 c = GNUNET_malloc (sizeof (struct Client) + msize);
238 c->client_handle = client;
239 c->tcnt = msize / sizeof (uint16_t);
240 c->options = ntohl (im->options);
241 c->types = (const uint16_t *) &c[1];
242 wtypes = (uint16_t *) & c[1];
243 for (i = 0; i < c->tcnt; i++)
244 wtypes[i] = ntohs (types[i]);
245 GSC_TYPEMAP_add (wtypes, c->tcnt);
246 GNUNET_CONTAINER_DLL_insert (client_head,
247 client_tail,
248 c);
249#if DEBUG_CORE_CLIENT
250 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
251 "Client connecting to core service is interested in %u message types\n",
252 (unsigned int) c->tcnt);
253#endif
254 /* send init reply message */
255 irm.header.size = htons (sizeof (struct InitReplyMessage));
256 irm.header.type = htons (GNUNET_MESSAGE_TYPE_CORE_INIT_REPLY);
257 irm.reserved = htonl (0);
258 irm.publicKey = GSC_my_public_key;
259 send_to_client (c, &irm.header, GNUNET_NO);
260 if (0 != (c->options & GNUNET_CORE_OPTION_SEND_CONNECT))
261 GSC_SESSIONS_notify_client_about_sessions (c);
262 GNUNET_SERVER_receive_done (client, GNUNET_OK);
263}
264
210 265
211/** 266/**
212 * Handle CORE_SEND_REQUEST message. 267 * Handle CORE_SEND_REQUEST message.
268 *
269 * @param cls unused
270 * @param client new client that sent CORE_SEND_REQUEST
271 * @param message the 'struct InitMessage' (presumably)
213 */ 272 */
214static void 273static void
215handle_client_send_request (void *cls, struct GNUNET_SERVER_Client *client, 274handle_client_send_request (void *cls, struct GNUNET_SERVER_Client *client,
216 const struct GNUNET_MessageHeader *message) 275 const struct GNUNET_MessageHeader *message)
217{ 276{
218 const struct SendMessageRequest *req; 277 const struct SendMessageRequest *req;
219 struct Neighbour *n;
220 struct Client *c; 278 struct Client *c;
221 struct ClientActiveRequest *car; 279 struct ClientActiveRequest *car;
222 280
223 req = (const struct SendMessageRequest *) message; 281 req = (const struct SendMessageRequest *) message;
224 if (0 == 282 c = find_client (client);
225 memcmp (&req->peer, &my_identity, sizeof (struct GNUNET_PeerIdentity)))
226 n = &self;
227 else
228 n = find_neighbour (&req->peer);
229 if ((n == NULL) || (GNUNET_YES != n->is_connected) ||
230 (n->status != PEER_STATE_KEY_CONFIRMED))
231 {
232 /* neighbour must have disconnected since request was issued,
233 * ignore (client will realize it once it processes the
234 * disconnect notification) */
235#if DEBUG_CORE_CLIENT
236 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
237 "Dropped client request for transmission (am disconnected)\n");
238#endif
239 GNUNET_STATISTICS_update (stats,
240 gettext_noop
241 ("# send requests dropped (disconnected)"), 1,
242 GNUNET_NO);
243 GNUNET_SERVER_receive_done (client, GNUNET_OK);
244 return;
245 }
246 c = clients;
247 while ((c != NULL) && (c->client_handle != client))
248 c = c->next;
249 if (c == NULL) 283 if (c == NULL)
250 { 284 {
251 /* client did not send INIT first! */ 285 /* client did not send INIT first! */
@@ -255,10 +289,6 @@ handle_client_send_request (void *cls, struct GNUNET_SERVER_Client *client,
255 } 289 }
256 if (c->requests == NULL) 290 if (c->requests == NULL)
257 c->requests = GNUNET_CONTAINER_multihashmap_create (16); 291 c->requests = GNUNET_CONTAINER_multihashmap_create (16);
258#if DEBUG_CORE_CLIENT
259 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
260 "Received client transmission request. queueing\n");
261#endif
262 car = GNUNET_CONTAINER_multihashmap_get (c->requests, &req->peer.hashPubKey); 292 car = GNUNET_CONTAINER_multihashmap_get (c->requests, &req->peer.hashPubKey);
263 if (car == NULL) 293 if (car == NULL)
264 { 294 {
@@ -269,153 +299,109 @@ handle_client_send_request (void *cls, struct GNUNET_SERVER_Client *client,
269 &req->peer.hashPubKey, 299 &req->peer.hashPubKey,
270 car, 300 car,
271 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST)); 301 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST));
272 GNUNET_CONTAINER_DLL_insert (n->active_client_request_head,
273 n->active_client_request_tail, car);
274 car->client = c; 302 car->client = c;
275 } 303 }
304 car->target = req->peer;
305 GNUNET_SERVER_client_keep (client);
306 car->client_handle = client;
276 car->deadline = GNUNET_TIME_absolute_ntoh (req->deadline); 307 car->deadline = GNUNET_TIME_absolute_ntoh (req->deadline);
277 car->priority = ntohl (req->priority); 308 car->priority = ntohl (req->priority);
278 car->queue_size = ntohl (req->queue_size);
279 car->msize = ntohs (req->size); 309 car->msize = ntohs (req->size);
280 car->smr_id = req->smr_id; 310 car->smr_id = req->smr_id;
281 schedule_peer_messages (n); 311 if (0 ==
312 memcmp (&req->peer, &GSC_my_identity, sizeof (struct GNUNET_PeerIdentity)))
313 GSC_CLIENTS_solicit_request (car);
314 else
315 GSC_SESSIONS_queue_request (car);
282 GNUNET_SERVER_receive_done (client, GNUNET_OK); 316 GNUNET_SERVER_receive_done (client, GNUNET_OK);
283} 317}
284 318
285 319
286/** 320/**
287 * Notify client about an existing connection to one of our neighbours. 321 * Handle CORE_SEND request.
288 */ 322 *
289static int 323 * @param cls unused
290notify_client_about_neighbour (void *cls, const GNUNET_HashCode * key, 324 * @param client the client issuing the request
291 void *value) 325 * @param message the "struct SendMessage"
292{
293 struct Client *c = cls;
294 struct Neighbour *n = value;
295 size_t size;
296 char buf[GNUNET_SERVER_MAX_MESSAGE_SIZE - 1];
297 struct GNUNET_TRANSPORT_ATS_Information *ats;
298 struct ConnectNotifyMessage *cnm;
299
300 size =
301 sizeof (struct ConnectNotifyMessage) +
302 (n->ats_count) * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
303 if (size >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
304 {
305 GNUNET_break (0);
306 /* recovery strategy: throw away performance data */
307 GNUNET_array_grow (n->ats, n->ats_count, 0);
308 size =
309 sizeof (struct ConnectNotifyMessage) +
310 (n->ats_count) * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
311 }
312 cnm = (struct ConnectNotifyMessage *) buf;
313 cnm->header.size = htons (size);
314 cnm->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_NOTIFY_CONNECT);
315 cnm->ats_count = htonl (n->ats_count);
316 ats = &cnm->ats;
317 memcpy (ats, n->ats,
318 sizeof (struct GNUNET_TRANSPORT_ATS_Information) * n->ats_count);
319 ats[n->ats_count].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
320 ats[n->ats_count].value = htonl (0);
321 if (n->status == PEER_STATE_KEY_CONFIRMED)
322 {
323#if DEBUG_CORE_CLIENT
324 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending `%s' message to client.\n",
325 "NOTIFY_CONNECT");
326#endif
327 cnm->peer = n->peer;
328 send_to_client (c, &cnm->header, GNUNET_NO);
329 }
330 return GNUNET_OK;
331}
332
333
334
335/**
336 * Handle CORE_INIT request.
337 */ 326 */
338static void 327static void
339handle_client_init (void *cls, struct GNUNET_SERVER_Client *client, 328handle_client_send (void *cls, struct GNUNET_SERVER_Client *client,
340 const struct GNUNET_MessageHeader *message) 329 const struct GNUNET_MessageHeader *message)
341{ 330{
342 const struct InitMessage *im; 331 const struct SendMessage *sm;
343 struct InitReplyMessage irm;
344 struct Client *c; 332 struct Client *c;
333 struct ClientActiveRequest *car;
345 uint16_t msize; 334 uint16_t msize;
346 const uint16_t *types;
347 uint16_t *wtypes;
348 unsigned int i;
349 335
350#if DEBUG_CORE_CLIENT
351 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
352 "Client connecting to core service with `%s' message\n", "INIT");
353#endif
354 /* check that we don't have an entry already */
355 c = clients;
356 while (c != NULL)
357 {
358 if (client == c->client_handle)
359 {
360 GNUNET_break (0);
361 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
362 return;
363 }
364 c = c->next;
365 }
366 msize = ntohs (message->size); 336 msize = ntohs (message->size);
367 if (msize < sizeof (struct InitMessage)) 337 if (msize <
338 sizeof (struct SendMessage) + sizeof (struct GNUNET_MessageHeader))
368 { 339 {
369 GNUNET_break (0); 340 GNUNET_break (0);
370 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); 341 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
371 return; 342 return;
372 } 343 }
373 GNUNET_SERVER_notification_context_add (notifier, client); 344 sm = (const struct SendMessage *) message;
374 im = (const struct InitMessage *) message; 345 msize -= sizeof (struct SendMessage);
375 types = (const uint16_t *) &im[1]; 346 GNUNET_break (0 == ntohl (sm->reserved));
376 msize -= sizeof (struct InitMessage); 347 c = find_client (client);
377 c = GNUNET_malloc (sizeof (struct Client) + msize); 348 if (c == NULL)
378 c->client_handle = client;
379 c->next = clients;
380 clients = c;
381 c->tcnt = msize / sizeof (uint16_t);
382 c->types = (const uint16_t *) &c[1];
383 wtypes = (uint16_t *) & c[1];
384 for (i = 0; i < c->tcnt; i++)
385 { 349 {
386 wtypes[i] = ntohs (types[i]); 350 /* client did not send INIT first! */
387 my_type_map[wtypes[i] / 32] |= (1 << (wtypes[i] % 32)); 351 GNUNET_break (0);
352 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
353 return;
388 } 354 }
389 if (c->tcnt > 0) 355 car = GNUNET_CONTAINER_multihashmap_get (c->requests, &sm->peer.hashPubKey);
390 broadcast_my_type_map (); 356 if (NULL == car)
391 c->options = ntohl (im->options);
392#if DEBUG_CORE_CLIENT
393 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
394 "Client %p is interested in %u message types\n", c,
395 (unsigned int) c->tcnt);
396#endif
397 /* send init reply message */
398 irm.header.size = htons (sizeof (struct InitReplyMessage));
399 irm.header.type = htons (GNUNET_MESSAGE_TYPE_CORE_INIT_REPLY);
400 irm.reserved = htonl (0);
401 memcpy (&irm.publicKey, &my_public_key,
402 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
403#if DEBUG_CORE_CLIENT
404 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending `%s' message to client.\n",
405 "INIT_REPLY");
406#endif
407 send_to_client (c, &irm.header, GNUNET_NO);
408 if (0 != (c->options & GNUNET_CORE_OPTION_SEND_CONNECT))
409 { 357 {
410 /* notify new client about existing neighbours */ 358 /* client did not request transmission first! */
411 GNUNET_CONTAINER_multihashmap_iterate (neighbours, 359 GNUNET_break (0);
412 &notify_client_about_neighbour, c); 360 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
361 return;
413 } 362 }
363 GNUNET_assert (GNUNET_YES ==
364 GNUNET_CONTAINER_multihashmap_remove (c->requests,
365 &sm->peer.hashPubKey,
366 car));
367 GNUNET_SERVER_mst_receive (client_mst,
368 car,
369 &sm[1], msize,
370 GNUNET_YES,
371 GNUNET_NO);
372 if (0 !=
373 memcmp (&car->peer, &GSC_my_identity, sizeof (struct GNUNET_PeerIdentity)))
374 GSC_SESSIONS_dequeue_request (car);
375 GNUNET_free (car);
414 GNUNET_SERVER_receive_done (client, GNUNET_OK); 376 GNUNET_SERVER_receive_done (client, GNUNET_OK);
415} 377}
416 378
417 379
418/** 380/**
381 * Functions with this signature are called whenever a complete
382 * message is received by the tokenizer. Used by the 'client_mst' for
383 * dispatching messages from clients to either the SESSION subsystem
384 * or other CLIENT (for loopback).
385 *
386 * @param cls closure
387 * @param client reservation request ('struct ClientActiveRequest')
388 * @param message the actual message
389 */
390static void
391client_tokenizer_callback (void *cls, void *client,
392 const struct GNUNET_MessageHeader *message)
393{
394 struct ClientActiveRequest *car = client;
395
396 if (0 ==
397 memcmp (&car->peer, &GSC_my_identity, sizeof (struct GNUNET_PeerIdentity)))
398 GDS_CLIENTS_deliver_message (&GSC_my_identity, &payload->header);
399 else
400 GSC_SESSIONS_transmit (car, &payload->header);
401}
402
403
404/**
419 * Free client request records. 405 * Free client request records.
420 * 406 *
421 * @param cls NULL 407 * @param cls NULL
@@ -428,14 +414,8 @@ destroy_active_client_request (void *cls, const GNUNET_HashCode * key,
428 void *value) 414 void *value)
429{ 415{
430 struct ClientActiveRequest *car = value; 416 struct ClientActiveRequest *car = value;
431 struct Neighbour *n;
432 struct GNUNET_PeerIdentity peer;
433 417
434 peer.hashPubKey = *key; 418 GSC_SESSIONS_dequeue_request (car);
435 n = find_neighbour (&peer);
436 GNUNET_assert (NULL != n);
437 GNUNET_CONTAINER_DLL_remove (n->active_client_request_head,
438 n->active_client_request_tail, car);
439 GNUNET_free (car); 419 GNUNET_free (car);
440 return GNUNET_YES; 420 return GNUNET_YES;
441} 421}
@@ -448,12 +428,10 @@ destroy_active_client_request (void *cls, const GNUNET_HashCode * key,
448 * @param client identification of the client 428 * @param client identification of the client
449 */ 429 */
450static void 430static void
451handle_client_disconnect (void *cls, struct GNUNET_SERVER_Client *client) 431handle_client_disconnect (void *cls,
432 struct GNUNET_SERVER_Client *client)
452{ 433{
453 struct Client *pos; 434 struct Client *c;
454 struct Client *prev;
455 unsigned int i;
456 const uint16_t *wtypes;
457 435
458 if (client == NULL) 436 if (client == NULL)
459 return; 437 return;
@@ -461,214 +439,110 @@ handle_client_disconnect (void *cls, struct GNUNET_SERVER_Client *client)
461 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 439 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
462 "Client %p has disconnected from core service.\n", client); 440 "Client %p has disconnected from core service.\n", client);
463#endif 441#endif
464 prev = NULL; 442 c = find_client (client);
465 pos = clients; 443 if (c == NULL)
466 while (pos != NULL) 444 return; /* client never sent INIT */
467 { 445 GNUNET_CONTAINER_DLL_remove (client_head,
468 if (client == pos->client_handle) 446 client_tail,
469 break; 447 c);
470 prev = pos; 448 if (c->requests != NULL)
471 pos = pos->next;
472 }
473 if (pos == NULL)
474 {
475 /* client never sent INIT */
476 return;
477 }
478 if (prev == NULL)
479 clients = pos->next;
480 else
481 prev->next = pos->next;
482 if (pos->requests != NULL)
483 { 449 {
484 GNUNET_CONTAINER_multihashmap_iterate (pos->requests, 450 GNUNET_CONTAINER_multihashmap_iterate (c->requests,
485 &destroy_active_client_request, 451 &destroy_active_client_request,
486 NULL); 452 NULL);
487 GNUNET_CONTAINER_multihashmap_destroy (pos->requests); 453 GNUNET_CONTAINER_multihashmap_destroy (c->requests);
488 }
489 GNUNET_free (pos);
490
491 /* rebuild my_type_map */
492 memset (my_type_map, 0, sizeof (my_type_map));
493 for (pos = clients; NULL != pos; pos = pos->next)
494 {
495 wtypes = (const uint16_t *) &pos[1];
496 for (i = 0; i < pos->tcnt; i++)
497 my_type_map[wtypes[i] / 32] |= (1 << (wtypes[i] % 32));
498 } 454 }
499 broadcast_my_type_map (); 455 GSC_TYPEMAP_remove (c->types, c->tcnt);
456 GNUNET_free (c);
500} 457}
501 458
502 459
503 460
504 461
505 462
463
464// FIXME from here.......................................
465
466
467
506/** 468/**
507 * Handle CORE_SEND request. 469 * Tell a client that we are ready to receive the message.
508 * 470 *
509 * @param cls unused 471 * @param car request that is now ready; the responsibility
510 * @param client the client issuing the request 472 * for the handle remains shared between CLIENTS
511 * @param message the "struct SendMessage" 473 * and SESSIONS after this call.
512 */ 474 */
513static void 475void
514handle_client_send (void *cls, struct GNUNET_SERVER_Client *client, 476GSC_CLIENTS_solicit_request (struct GSC_ClientActiveRequest *car)
515 const struct GNUNET_MessageHeader *message)
516{ 477{
517 const struct SendMessage *sm; 478}
518 struct Neighbour *n;
519 struct MessageEntry *prev;
520 struct MessageEntry *pos;
521 struct MessageEntry *e;
522 struct MessageEntry *min_prio_entry;
523 struct MessageEntry *min_prio_prev;
524 unsigned int min_prio;
525 unsigned int queue_size;
526 uint16_t msize;
527 479
528 msize = ntohs (message->size); 480
529 if (msize < 481/**
530 sizeof (struct SendMessage) + sizeof (struct GNUNET_MessageHeader)) 482 * Tell a client that we will never be ready to receive the
483 * given message in time (disconnect or timeout).
484 *
485 * @param car request that now permanently failed; the
486 * responsibility for the handle is now returned
487 * to CLIENTS (SESSIONS is done with it).
488 */
489void
490GSC_CLIENTS_reject_request (struct GSC_ClientActiveRequest *car)
491{
492}
493
494
495
496
497/**
498 * Notify client about an existing connection to one of our neighbours.
499 */
500static int
501notify_client_about_neighbour (void *cls, const GNUNET_HashCode * key,
502 void *value)
503{
504 struct Client *c = cls;
505 struct Neighbour *n = value;
506 size_t size;
507 char buf[GNUNET_SERVER_MAX_MESSAGE_SIZE - 1];
508 struct GNUNET_TRANSPORT_ATS_Information *ats;
509 struct ConnectNotifyMessage *cnm;
510
511 size =
512 sizeof (struct ConnectNotifyMessage) +
513 (n->ats_count) * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
514 if (size >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
531 { 515 {
532 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
533 "msize is %u, should be at least %u (in %s:%d)\n", msize,
534 sizeof (struct SendMessage) +
535 sizeof (struct GNUNET_MessageHeader), __FILE__, __LINE__);
536 GNUNET_break (0); 516 GNUNET_break (0);
537 if (client != NULL) 517 /* recovery strategy: throw away performance data */
538 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); 518 GNUNET_array_grow (n->ats, n->ats_count, 0);
539 return; 519 size =
540 } 520 sizeof (struct ConnectNotifyMessage) +
541 sm = (const struct SendMessage *) message; 521 (n->ats_count) * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
542 msize -= sizeof (struct SendMessage);
543 if (0 ==
544 memcmp (&sm->peer, &my_identity, sizeof (struct GNUNET_PeerIdentity)))
545 {
546 /* loopback */
547 GNUNET_SERVER_mst_receive (mst, &self, (const char *) &sm[1], msize,
548 GNUNET_YES, GNUNET_NO);
549 if (client != NULL)
550 GNUNET_SERVER_receive_done (client, GNUNET_OK);
551 return;
552 }
553 n = find_neighbour (&sm->peer);
554 if ((n == NULL) || (GNUNET_YES != n->is_connected) ||
555 (n->status != PEER_STATE_KEY_CONFIRMED))
556 {
557 /* attempt to send message to peer that is not connected anymore
558 * (can happen due to asynchrony) */
559 GNUNET_STATISTICS_update (stats,
560 gettext_noop
561 ("# messages discarded (disconnected)"), 1,
562 GNUNET_NO);
563 if (client != NULL)
564 GNUNET_SERVER_receive_done (client, GNUNET_OK);
565 return;
566 }
567#if DEBUG_CORE
568 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
569 "Core received `%s' request, queueing %u bytes of plaintext data for transmission to `%4s'.\n",
570 "SEND", (unsigned int) msize, GNUNET_i2s (&sm->peer));
571#endif
572 discard_expired_messages (n);
573 /* bound queue size */
574 /* NOTE: this entire block to bound the queue size should be
575 * obsolete with the new client-request code and the
576 * 'schedule_peer_messages' mechanism; we still have this code in
577 * here for now as a sanity check for the new mechanmism;
578 * ultimately, we should probably simply reject SEND messages that
579 * are not 'approved' (or provide a new core API for very unreliable
580 * delivery that always sends with priority 0). Food for thought. */
581 min_prio = UINT32_MAX;
582 min_prio_entry = NULL;
583 min_prio_prev = NULL;
584 queue_size = 0;
585 prev = NULL;
586 pos = n->messages;
587 while (pos != NULL)
588 {
589 if (pos->priority <= min_prio)
590 {
591 min_prio_entry = pos;
592 min_prio_prev = prev;
593 min_prio = pos->priority;
594 }
595 queue_size++;
596 prev = pos;
597 pos = pos->next;
598 } 522 }
599 if (queue_size >= MAX_PEER_QUEUE_SIZE) 523 cnm = (struct ConnectNotifyMessage *) buf;
524 cnm->header.size = htons (size);
525 cnm->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_NOTIFY_CONNECT);
526 cnm->ats_count = htonl (n->ats_count);
527 ats = &cnm->ats;
528 memcpy (ats, n->ats,
529 sizeof (struct GNUNET_TRANSPORT_ATS_Information) * n->ats_count);
530 ats[n->ats_count].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
531 ats[n->ats_count].value = htonl (0);
532 if (n->status == PEER_STATE_KEY_CONFIRMED)
600 { 533 {
601 /* queue full */ 534#if DEBUG_CORE_CLIENT
602 if (ntohl (sm->priority) <= min_prio) 535 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending `%s' message to client.\n",
603 { 536 "NOTIFY_CONNECT");
604 /* discard new entry; this should no longer happen! */
605 GNUNET_break (0);
606#if DEBUG_CORE
607 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
608 "Queue full (%u/%u), discarding new request (%u bytes of type %u)\n",
609 queue_size, (unsigned int) MAX_PEER_QUEUE_SIZE,
610 (unsigned int) msize, (unsigned int) ntohs (message->type));
611#endif
612 GNUNET_STATISTICS_update (stats,
613 gettext_noop ("# discarded CORE_SEND requests"),
614 1, GNUNET_NO);
615
616 if (client != NULL)
617 GNUNET_SERVER_receive_done (client, GNUNET_OK);
618 return;
619 }
620 GNUNET_assert (min_prio_entry != NULL);
621 /* discard "min_prio_entry" */
622#if DEBUG_CORE
623 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
624 "Queue full, discarding existing older request\n");
625#endif
626 GNUNET_STATISTICS_update (stats,
627 gettext_noop
628 ("# discarded lower priority CORE_SEND requests"),
629 1, GNUNET_NO);
630 if (min_prio_prev == NULL)
631 n->messages = min_prio_entry->next;
632 else
633 min_prio_prev->next = min_prio_entry->next;
634 GNUNET_free (min_prio_entry);
635 }
636
637#if DEBUG_CORE
638 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
639 "Adding transmission request for `%4s' of size %u to queue\n",
640 GNUNET_i2s (&sm->peer), (unsigned int) msize);
641#endif 537#endif
642 GNUNET_break (0 == ntohl (sm->reserved)); 538 cnm->peer = n->peer;
643 e = GNUNET_malloc (sizeof (struct MessageEntry) + msize); 539 send_to_client (c, &cnm->header, GNUNET_NO);
644 e->deadline = GNUNET_TIME_absolute_ntoh (sm->deadline);
645 e->priority = ntohl (sm->priority);
646 e->size = msize;
647 if (GNUNET_YES != (int) ntohl (sm->cork))
648 e->got_slack = GNUNET_YES;
649 memcpy (&e[1], &sm[1], msize);
650
651 /* insert, keep list sorted by deadline */
652 prev = NULL;
653 pos = n->messages;
654 while ((pos != NULL) && (pos->deadline.abs_value < e->deadline.abs_value))
655 {
656 prev = pos;
657 pos = pos->next;
658 } 540 }
659 if (prev == NULL) 541 return GNUNET_OK;
660 n->messages = e;
661 else
662 prev->next = e;
663 e->next = pos;
664
665 /* consider scheduling now */
666 process_plaintext_neighbour_queue (n);
667 if (client != NULL)
668 GNUNET_SERVER_receive_done (client, GNUNET_OK);
669} 542}
670 543
671 544
545
672/** 546/**
673 * Helper function for handle_client_iterate_peers. 547 * Helper function for handle_client_iterate_peers.
674 * 548 *
@@ -956,16 +830,36 @@ send_p2p_message_to_client (struct Neighbour *sender, struct Client *client,
956 830
957 831
958 832
833/**
834 * Notify a particular client about a change to existing connection to
835 * one of our neighbours (check if the client is interested). Called
836 * from 'GSC_SESSIONS_notify_client_about_sessions'.
837 *
838 * @param client client to notify
839 * @param neighbour identity of the neighbour that changed status
840 * @param tmap_old previous type map for the neighbour, NULL for disconnect
841 * @param tmap_new updated type map for the neighbour, NULL for disconnect
842 */
843void
844GDS_CLIENTS_notify_client_about_neighbour (struct GSC_Client *client,
845 const struct GNUNET_PeerIdentity *neighbour,
846 const struct GSC_TypeMap *tmap_old,
847 const struct GSC_TypeMap *tmap_new)
848{
849}
850
959 851
960/** 852/**
961 * Notify client about a change to existing connection to one of our neighbours. 853 * Notify client about a change to existing connection to one of our neighbours.
962 * 854 *
963 * @param neighbour identity of the neighbour that changed status 855 * @param neighbour identity of the neighbour that changed status
964 * @param tmap updated type map for the neighbour, NULL for disconnect 856 * @param tmap_old previous type map for the neighbour, NULL for disconnect
857 * @param tmap_new updated type map for the neighbour, NULL for disconnect
965 */ 858 */
966void 859void
967GDS_CLIENTS_notify_clients_about_neighbour (const struct GNUNET_PeerIdentity *neighbour, 860GDS_CLIENTS_notify_clients_about_neighbour (const struct GNUNET_PeerIdentity *neighbour,
968 const struct GSC_TypeMap *tmap) 861 const struct GSC_TypeMap *tmap_old,
862 const struct GSC_TypeMap *tmap_new)
969{ 863{
970} 864}
971 865
@@ -1050,7 +944,11 @@ GSC_CLIENTS_deliver_message (const struct GNUNET_PeerIdentity *sender,
1050} 944}
1051 945
1052 946
1053 947/**
948 * Initialize clients subsystem.
949 *
950 * @param server handle to server clients connect to
951 */
1054void 952void
1055GSC_CLIENTS_init (struct GNUNET_SERVER_Handle *server) 953GSC_CLIENTS_init (struct GNUNET_SERVER_Handle *server)
1056{ 954{
@@ -1076,27 +974,28 @@ GSC_CLIENTS_init (struct GNUNET_SERVER_Handle *server)
1076 }; 974 };
1077 975
1078 /* setup notification */ 976 /* setup notification */
977 client_mst = GNUNET_SERVER_mst_create (&client_tokenizer_callback, NULL);
1079 notifier = 978 notifier =
1080 GNUNET_SERVER_notification_context_create (server, MAX_NOTIFY_QUEUE); 979 GNUNET_SERVER_notification_context_create (server, MAX_NOTIFY_QUEUE);
1081 GNUNET_SERVER_disconnect_notify (server, &handle_client_disconnect, NULL); 980 GNUNET_SERVER_disconnect_notify (server, &handle_client_disconnect, NULL);
1082 GNUNET_SERVER_add_handlers (server, handlers); 981 GNUNET_SERVER_add_handlers (server, handlers);
1083 mst = GNUNET_SERVER_mst_create (&deliver_message, NULL);
1084} 982}
1085 983
1086 984
985/**
986 * Shutdown clients subsystem.
987 */
1087void 988void
1088GSC_CLIENTS_done () 989GSC_CLIENTS_done ()
1089{ 990{
1090 struct Client *c; 991 struct Client *c;
1091 992
1092 while (NULL != (c = clients)) 993 while (NULL != (c = client_head))
1093 handle_client_disconnect (NULL, c->client_handle); 994 handle_client_disconnect (NULL, c->client_handle);
1094 GNUNET_SERVER_notification_context_destroy (notifier); 995 GNUNET_SERVER_notification_context_destroy (notifier);
1095 notifier = NULL; 996 notifier = NULL;
1096 if (mst != NULL) 997 GNUNET_SERVER_MST_destroy (client_mst);
1097 { 998 client_mst = NULL;
1098 GNUNET_SERVER_mst_destroy (mst);
1099 mst = NULL;
1100 }
1101
1102} 999}
1000
1001/* end of gnunet-service-core_clients.c */