aboutsummaryrefslogtreecommitdiff
path: root/src/core
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2016-09-20 15:14:05 +0000
committerChristian Grothoff <christian@grothoff.org>2016-09-20 15:14:05 +0000
commit5663ca18885242fca4dd209898ffda9cbe675c58 (patch)
treeeba7a80df59830aefd927a5a5383e47b353d5a09 /src/core
parent7e835e78aa82869715c9aee96a73ba40aad3f39f (diff)
downloadgnunet-5663ca18885242fca4dd209898ffda9cbe675c58.tar.gz
gnunet-5663ca18885242fca4dd209898ffda9cbe675c58.zip
converting core service to new service API
Diffstat (limited to 'src/core')
-rw-r--r--src/core/Makefile.am1
-rw-r--r--src/core/core_api.c7
-rw-r--r--src/core/gnunet-service-core.c881
-rw-r--r--src/core/gnunet-service-core.h80
-rw-r--r--src/core/gnunet-service-core_clients.c960
-rw-r--r--src/core/gnunet-service-core_clients.h142
-rw-r--r--src/core/gnunet-service-core_kx.c94
-rw-r--r--src/core/gnunet-service-core_kx.h12
-rw-r--r--src/core/gnunet-service-core_sessions.c1
9 files changed, 975 insertions, 1203 deletions
diff --git a/src/core/Makefile.am b/src/core/Makefile.am
index a99f74af6..aea64fa34 100644
--- a/src/core/Makefile.am
+++ b/src/core/Makefile.am
@@ -41,7 +41,6 @@ bin_PROGRAMS = \
41 41
42gnunet_service_core_SOURCES = \ 42gnunet_service_core_SOURCES = \
43 gnunet-service-core.c gnunet-service-core.h \ 43 gnunet-service-core.c gnunet-service-core.h \
44 gnunet-service-core_clients.c gnunet-service-core_clients.h \
45 gnunet-service-core_kx.c gnunet-service-core_kx.h \ 44 gnunet-service-core_kx.c gnunet-service-core_kx.h \
46 gnunet-service-core_sessions.c gnunet-service-core_sessions.h \ 45 gnunet-service-core_sessions.c gnunet-service-core_sessions.h \
47 gnunet-service-core_typemap.c gnunet-service-core_typemap.h 46 gnunet-service-core_typemap.c gnunet-service-core_typemap.h
diff --git a/src/core/core_api.c b/src/core/core_api.c
index 6055b99c1..67f17352d 100644
--- a/src/core/core_api.c
+++ b/src/core/core_api.c
@@ -541,11 +541,12 @@ handle_notify_inbound (void *cls,
541 uint16_t et; 541 uint16_t et;
542 542
543 GNUNET_break (GNUNET_NO == h->currently_down); 543 GNUNET_break (GNUNET_NO == h->currently_down);
544 LOG (GNUNET_ERROR_TYPE_DEBUG,
545 "Received inbound message from `%s'.\n",
546 GNUNET_i2s (&ntm->peer));
547 em = (const struct GNUNET_MessageHeader *) &ntm[1]; 544 em = (const struct GNUNET_MessageHeader *) &ntm[1];
548 et = ntohs (em->type); 545 et = ntohs (em->type);
546 LOG (GNUNET_ERROR_TYPE_DEBUG,
547 "Received inbound message of type %d from `%s'.\n",
548 (int) et,
549 GNUNET_i2s (&ntm->peer));
549 for (unsigned int hpos = 0; NULL != h->handlers[hpos].callback; hpos++) 550 for (unsigned int hpos = 0; NULL != h->handlers[hpos].callback; hpos++)
550 { 551 {
551 const struct GNUNET_CORE_MessageHandler *mh; 552 const struct GNUNET_CORE_MessageHandler *mh;
diff --git a/src/core/gnunet-service-core.c b/src/core/gnunet-service-core.c
index f9391e616..acaa10092 100644
--- a/src/core/gnunet-service-core.c
+++ b/src/core/gnunet-service-core.c
@@ -1,6 +1,6 @@
1/* 1/*
2 This file is part of GNUnet. 2 This file is part of GNUnet.
3 Copyright (C) 2009, 2010, 2011 GNUnet e.V. 3 Copyright (C) 2009, 2010, 2011, 2016 GNUnet e.V.
4 4
5 GNUnet is free software; you can redistribute it and/or modify 5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published 6 it under the terms of the GNU General Public License as published
@@ -27,11 +27,75 @@
27#include <gcrypt.h> 27#include <gcrypt.h>
28#include "gnunet_util_lib.h" 28#include "gnunet_util_lib.h"
29#include "gnunet-service-core.h" 29#include "gnunet-service-core.h"
30#include "gnunet-service-core_clients.h"
31#include "gnunet-service-core_kx.h" 30#include "gnunet-service-core_kx.h"
32#include "gnunet-service-core_sessions.h" 31#include "gnunet-service-core_sessions.h"
33#include "gnunet-service-core_typemap.h" 32#include "gnunet-service-core_typemap.h"
34 33
34/**
35 * How many messages do we queue up at most for optional
36 * notifications to a client? (this can cause notifications
37 * about outgoing messages to be dropped).
38 */
39#define MAX_NOTIFY_QUEUE 1024
40
41
42/**
43 * Data structure for each client connected to the CORE service.
44 */
45struct GSC_Client
46{
47 /**
48 * Clients are kept in a linked list.
49 */
50 struct GSC_Client *next;
51
52 /**
53 * Clients are kept in a linked list.
54 */
55 struct GSC_Client *prev;
56
57 /**
58 * Handle for the client with the server API.
59 */
60 struct GNUNET_SERVICE_Client *client;
61
62 /**
63 * Message queue to talk to @e client.
64 */
65 struct GNUNET_MQ_Handle *mq;
66
67 /**
68 * Array of the types of messages this peer cares
69 * about (with @e tcnt entries). Allocated as part
70 * of this client struct, do not free!
71 */
72 uint16_t *types;
73
74 /**
75 * Map of peer identities to active transmission requests of this
76 * client to the peer (of type `struct GSC_ClientActiveRequest`).
77 */
78 struct GNUNET_CONTAINER_MultiPeerMap *requests;
79
80 /**
81 * Map containing all peers that this client knows we're connected to.
82 */
83 struct GNUNET_CONTAINER_MultiPeerMap *connectmap;
84
85 /**
86 * Options for messages this client cares about,
87 * see GNUNET_CORE_OPTION_ values.
88 */
89 uint32_t options;
90
91 /**
92 * Number of types of incoming messages this client
93 * specifically cares about. Size of the @e types array.
94 */
95 unsigned int tcnt;
96
97};
98
35 99
36/** 100/**
37 * Our identity. 101 * Our identity.
@@ -49,9 +113,739 @@ const struct GNUNET_CONFIGURATION_Handle *GSC_cfg;
49struct GNUNET_STATISTICS_Handle *GSC_stats; 113struct GNUNET_STATISTICS_Handle *GSC_stats;
50 114
51/** 115/**
52 * Handle to the server of the core service. 116 * Big "or" of all client options.
117 */
118static uint32_t all_client_options;
119
120/**
121 * Head of linked list of our clients.
122 */
123static struct GSC_Client *client_head;
124
125/**
126 * Tail of linked list of our clients.
127 */
128static struct GSC_Client *client_tail;
129
130
131/**
132 * Test if the client is interested in messages of the given type.
133 *
134 * @param type message type
135 * @param c client to test
136 * @return #GNUNET_YES if @a c is interested, #GNUNET_NO if not.
137 */
138static int
139type_match (uint16_t type,
140 struct GSC_Client *c)
141{
142 if ( (0 == c->tcnt) &&
143 (0 != c->options) )
144 return GNUNET_YES; /* peer without handlers and inbound/outbond
145 callbacks matches ALL */
146 if (NULL == c->types)
147 return GNUNET_NO;
148 for (unsigned int i = 0; i < c->tcnt; i++)
149 if (type == c->types[i])
150 return GNUNET_YES;
151 return GNUNET_NO;
152}
153
154
155/**
156 * Check #GNUNET_MESSAGE_TYPE_CORE_INIT request.
157 *
158 * @param cls client that sent #GNUNET_MESSAGE_TYPE_CORE_INIT
159 * @param im the `struct InitMessage`
160 * @return #GNUNET_OK if @a im is well-formed
53 */ 161 */
54static struct GNUNET_SERVER_Handle *GSC_server; 162static int
163check_client_init (void *cls,
164 const struct InitMessage *im)
165{
166 return GNUNET_OK;
167}
168
169
170/**
171 * Handle #GNUNET_MESSAGE_TYPE_CORE_INIT request.
172 *
173 * @param cls client that sent #GNUNET_MESSAGE_TYPE_CORE_INIT
174 * @param im the `struct InitMessage`
175 */
176static void
177handle_client_init (void *cls,
178 const struct InitMessage *im)
179{
180 struct GSC_Client *c = cls;
181 struct GNUNET_MQ_Envelope *env;
182 struct InitReplyMessage *irm;
183 uint16_t msize;
184 const uint16_t *types;
185
186 /* check that we don't have an entry already */
187 msize = ntohs (im->header.size) - sizeof (struct InitMessage);
188 types = (const uint16_t *) &im[1];
189 c->tcnt = msize / sizeof (uint16_t);
190 c->options = ntohl (im->options);
191 all_client_options |= c->options;
192 c->types = GNUNET_malloc (msize);
193 c->connectmap = GNUNET_CONTAINER_multipeermap_create (16,
194 GNUNET_NO);
195 GNUNET_assert (GNUNET_YES ==
196 GNUNET_CONTAINER_multipeermap_put (c->connectmap,
197 &GSC_my_identity,
198 NULL,
199 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
200 for (unsigned int i = 0; i < c->tcnt; i++)
201 c->types[i] = ntohs (types[i]);
202 GSC_TYPEMAP_add (c->types,
203 c->tcnt);
204 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
205 "Client connecting to core service is interested in %u message types\n",
206 (unsigned int) c->tcnt);
207 /* send init reply message */
208 env = GNUNET_MQ_msg (irm,
209 GNUNET_MESSAGE_TYPE_CORE_INIT_REPLY);
210 irm->reserved = htonl (0);
211 irm->my_identity = GSC_my_identity;
212 GNUNET_MQ_send (c->mq,
213 env);
214 GSC_SESSIONS_notify_client_about_sessions (c);
215 GNUNET_SERVICE_client_continue (c->client);
216}
217
218
219/**
220 * We will never be ready to transmit the given message in (disconnect
221 * or invalid request). Frees resources associated with @a car. We
222 * don't explicitly tell the client, he'll learn with the disconnect
223 * (or violated the protocol).
224 *
225 * @param car request that now permanently failed; the
226 * responsibility for the handle is now returned
227 * to CLIENTS (SESSIONS is done with it).
228 * @param drop_client #GNUNET_YES if the client violated the protocol
229 * and we should thus drop the connection
230 */
231void
232GSC_CLIENTS_reject_request (struct GSC_ClientActiveRequest *car,
233 int drop_client)
234{
235 GNUNET_assert (GNUNET_YES ==
236 GNUNET_CONTAINER_multipeermap_remove (car->
237 client_handle->requests,
238 &car->target,
239 car));
240 if (GNUNET_YES == drop_client)
241 GNUNET_SERVICE_client_drop (car->client_handle->client);
242 GNUNET_free (car);
243}
244
245
246/**
247 * Tell a client that we are ready to receive the message.
248 *
249 * @param car request that is now ready; the responsibility
250 * for the handle remains shared between CLIENTS
251 * and SESSIONS after this call.
252 */
253void
254GSC_CLIENTS_solicit_request (struct GSC_ClientActiveRequest *car)
255{
256 struct GSC_Client *c;
257 struct GNUNET_MQ_Envelope *env;
258 struct SendMessageReady *smr;
259 struct GNUNET_TIME_Relative delay;
260 struct GNUNET_TIME_Relative left;
261
262 c = car->client_handle;
263 if (GNUNET_YES !=
264 GNUNET_CONTAINER_multipeermap_contains (c->connectmap,
265 &car->target))
266 {
267 /* connection has gone down since, drop request */
268 GNUNET_assert (0 !=
269 memcmp (&car->target,
270 &GSC_my_identity,
271 sizeof (struct GNUNET_PeerIdentity)));
272 GSC_SESSIONS_dequeue_request (car);
273 GSC_CLIENTS_reject_request (car,
274 GNUNET_NO);
275 return;
276 }
277 delay = GNUNET_TIME_absolute_get_duration (car->received_time);
278 left = GNUNET_TIME_absolute_get_duration (car->deadline);
279 if (delay.rel_value_us > GNUNET_CONSTANTS_LATENCY_WARN.rel_value_us)
280 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
281 "Client waited %s for permission to transmit to `%s'%s (priority %u)\n",
282 GNUNET_STRINGS_relative_time_to_string (delay,
283 GNUNET_YES),
284 GNUNET_i2s (&car->target),
285 (0 == left.rel_value_us)
286 ? " (past deadline)"
287 : "",
288 car->priority);
289 env = GNUNET_MQ_msg (smr,
290 GNUNET_MESSAGE_TYPE_CORE_SEND_READY);
291 smr->size = htons (car->msize);
292 smr->smr_id = car->smr_id;
293 smr->peer = car->target;
294 GNUNET_MQ_send (c->mq,
295 env);
296}
297
298
299/**
300 * Handle #GNUNET_MESSAGE_TYPE_CORE_SEND_REQUEST message.
301 *
302 * @param cls client that sent a #GNUNET_MESSAGE_TYPE_CORE_SEND_REQUEST
303 * @param req the `struct SendMessageRequest`
304 */
305static void
306handle_client_send_request (void *cls,
307 const struct SendMessageRequest *req)
308{
309 struct GSC_Client *c = cls;
310 struct GSC_ClientActiveRequest *car;
311 int is_loopback;
312
313 if (NULL == c->requests)
314 c->requests = GNUNET_CONTAINER_multipeermap_create (16,
315 GNUNET_NO);
316 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
317 "Client asked for transmission to `%s'\n",
318 GNUNET_i2s (&req->peer));
319 is_loopback =
320 (0 ==
321 memcmp (&req->peer,
322 &GSC_my_identity,
323 sizeof (struct GNUNET_PeerIdentity)));
324 if ((! is_loopback) &&
325 (GNUNET_YES !=
326 GNUNET_CONTAINER_multipeermap_contains (c->connectmap,
327 &req->peer)))
328 {
329 /* neighbour must have disconnected since request was issued,
330 * ignore (client will realize it once it processes the
331 * disconnect notification) */
332 GNUNET_STATISTICS_update (GSC_stats,
333 gettext_noop
334 ("# send requests dropped (disconnected)"), 1,
335 GNUNET_NO);
336 GNUNET_SERVICE_client_continue (c->client);
337 return;
338 }
339
340 car = GNUNET_CONTAINER_multipeermap_get (c->requests,
341 &req->peer);
342 if (NULL == car)
343 {
344 /* create new entry */
345 car = GNUNET_new (struct GSC_ClientActiveRequest);
346 GNUNET_assert (GNUNET_OK ==
347 GNUNET_CONTAINER_multipeermap_put (c->requests,
348 &req->peer,
349 car,
350 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST));
351 car->client_handle = c;
352 }
353 else
354 {
355 /* dequeue and recycle memory from pending request, there can only
356 be at most one per client and peer */
357 GNUNET_STATISTICS_update (GSC_stats,
358 gettext_noop ("# dequeuing CAR (duplicate request)"),
359 1,
360 GNUNET_NO);
361 GSC_SESSIONS_dequeue_request (car);
362 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
363 "Transmission request to `%s' was a duplicate!\n",
364 GNUNET_i2s (&req->peer));
365 }
366 car->target = req->peer;
367 car->received_time = GNUNET_TIME_absolute_get ();
368 car->deadline = GNUNET_TIME_absolute_ntoh (req->deadline);
369 car->priority = (enum GNUNET_CORE_Priority) ntohl (req->priority);
370 car->msize = ntohs (req->size);
371 car->smr_id = req->smr_id;
372 car->was_solicited = GNUNET_NO;
373 GNUNET_SERVICE_client_continue (c->client);
374 if (is_loopback)
375 {
376 /* loopback, satisfy immediately */
377 GSC_CLIENTS_solicit_request (car);
378 return;
379 }
380 GSC_SESSIONS_queue_request (car);
381}
382
383
384/**
385 * Closure for the #client_tokenizer_callback().
386 */
387struct TokenizerContext
388{
389
390 /**
391 * Active request handle for the message.
392 */
393 struct GSC_ClientActiveRequest *car;
394
395 /**
396 * How important is this message.
397 */
398 enum GNUNET_CORE_Priority priority;
399
400 /**
401 * Is corking allowed (set only once we have the real message).
402 */
403 int cork;
404
405};
406
407
408/**
409 * Functions with this signature are called whenever a complete
410 * message is received by the tokenizer. Used by
411 * #handle_client_send() for dispatching messages from clients to
412 * either the SESSION subsystem or other CLIENT (for loopback).
413 *
414 * @param cls reservation request (`struct TokenizerContext`)
415 * @param message the actual message
416 */
417static int
418tokenized_cb (void *cls,
419 const struct GNUNET_MessageHeader *message)
420{
421 struct TokenizerContext *tc = cls;
422 struct GSC_ClientActiveRequest *car = tc->car;
423 char buf[92];
424
425 GNUNET_snprintf (buf,
426 sizeof (buf),
427 gettext_noop ("# bytes of messages of type %u received"),
428 (unsigned int) ntohs (message->type));
429 GNUNET_STATISTICS_update (GSC_stats,
430 buf,
431 ntohs (message->size),
432 GNUNET_NO);
433 if (0 ==
434 memcmp (&car->target,
435 &GSC_my_identity,
436 sizeof (struct GNUNET_PeerIdentity)))
437 {
438 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
439 "Delivering message of type %u to myself\n",
440 ntohs (message->type));
441 GSC_CLIENTS_deliver_message (&GSC_my_identity,
442 message,
443 ntohs (message->size),
444 GNUNET_CORE_OPTION_SEND_FULL_OUTBOUND);
445 GSC_CLIENTS_deliver_message (&GSC_my_identity,
446 message,
447 sizeof (struct GNUNET_MessageHeader),
448 GNUNET_CORE_OPTION_SEND_HDR_OUTBOUND);
449 GSC_CLIENTS_deliver_message (&GSC_my_identity,
450 message,
451 ntohs (message->size),
452 GNUNET_CORE_OPTION_SEND_FULL_INBOUND);
453 GSC_CLIENTS_deliver_message (&GSC_my_identity,
454 message,
455 sizeof (struct GNUNET_MessageHeader),
456 GNUNET_CORE_OPTION_SEND_HDR_INBOUND);
457 }
458 else
459 {
460 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
461 "Delivering message of type %u and size %u to %s\n",
462 ntohs (message->type),
463 ntohs (message->size),
464 GNUNET_i2s (&car->target));
465 GSC_CLIENTS_deliver_message (&car->target,
466 message,
467 ntohs (message->size),
468 GNUNET_CORE_OPTION_SEND_FULL_OUTBOUND);
469 GSC_CLIENTS_deliver_message (&car->target,
470 message,
471 sizeof (struct GNUNET_MessageHeader),
472 GNUNET_CORE_OPTION_SEND_HDR_OUTBOUND);
473 GSC_SESSIONS_transmit (car,
474 message,
475 tc->cork,
476 tc->priority);
477 }
478 return GNUNET_OK;
479}
480
481
482/**
483 * Check #GNUNET_MESSAGE_TYPE_CORE_SEND request.
484 *
485 * @param cls the `struct GSC_Client`
486 * @param sm the `struct SendMessage`
487 * @return #GNUNET_OK if @a sm is well-formed
488 */
489static int
490check_client_send (void *cls,
491 const struct SendMessage *sm)
492{
493 return GNUNET_OK;
494}
495
496
497/**
498 * Handle #GNUNET_MESSAGE_TYPE_CORE_SEND request.
499 *
500 * @param cls the `struct GSC_Client`
501 * @param sm the `struct SendMessage`
502 */
503static void
504handle_client_send (void *cls,
505 const struct SendMessage *sm)
506{
507 struct GSC_Client *c = cls;
508 struct TokenizerContext tc;
509 uint16_t msize;
510 struct GNUNET_TIME_Relative delay;
511 struct GNUNET_MessageStreamTokenizer *mst;
512
513 msize = ntohs (sm->header.size) - sizeof (struct SendMessage);
514 GNUNET_break (0 == ntohl (sm->reserved));
515 tc.car = GNUNET_CONTAINER_multipeermap_get (c->requests,
516 &sm->peer);
517 if (NULL == tc.car)
518 {
519 /* Must have been that we first approved the request, then got disconnected
520 * (which triggered removal of the 'car') and now the client gives us a message
521 * just *before* the client learns about the disconnect. Theoretically, we
522 * might also now be *again* connected. So this can happen (but should be
523 * rare). If it does happen, the message is discarded. */
524 GNUNET_STATISTICS_update (GSC_stats,
525 gettext_noop ("# messages discarded (session disconnected)"),
526 1,
527 GNUNET_NO);
528 GNUNET_SERVICE_client_continue (c->client);
529 return;
530 }
531 delay = GNUNET_TIME_absolute_get_duration (tc.car->received_time);
532 tc.cork = ntohl (sm->cork);
533 tc.priority = (enum GNUNET_CORE_Priority) ntohl (sm->priority);
534 if (delay.rel_value_us > GNUNET_CONSTANTS_LATENCY_WARN.rel_value_us)
535 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
536 "Client waited %s for transmission of %u bytes to `%s'%s\n",
537 GNUNET_STRINGS_relative_time_to_string (delay,
538 GNUNET_YES),
539 msize,
540 GNUNET_i2s (&sm->peer),
541 tc.cork ? " (cork)" : " (uncorked)");
542 else
543 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
544 "Client waited %s for transmission of %u bytes to `%s'%s\n",
545 GNUNET_STRINGS_relative_time_to_string (delay,
546 GNUNET_YES),
547 msize,
548 GNUNET_i2s (&sm->peer),
549 tc.cork ? " (cork)" : " (uncorked)");
550
551 GNUNET_assert (GNUNET_YES ==
552 GNUNET_CONTAINER_multipeermap_remove (c->requests,
553 &sm->peer,
554 tc.car));
555 mst = GNUNET_MST_create (&tokenized_cb,
556 &tc);
557 GNUNET_MST_from_buffer (mst,
558 (const char *) &sm[1],
559 msize,
560 GNUNET_YES,
561 GNUNET_NO);
562 GNUNET_MST_destroy (mst);
563 GSC_SESSIONS_dequeue_request (tc.car);
564 GNUNET_free (tc.car);
565 GNUNET_SERVICE_client_continue (c->client);
566}
567
568
569/**
570 * Free client request records.
571 *
572 * @param cls NULL
573 * @param key identity of peer for which this is an active request
574 * @param value the `struct GSC_ClientActiveRequest` to free
575 * @return #GNUNET_YES (continue iteration)
576 */
577static int
578destroy_active_client_request (void *cls,
579 const struct GNUNET_PeerIdentity *key,
580 void *value)
581{
582 struct GSC_ClientActiveRequest *car = value;
583
584 GNUNET_assert (GNUNET_YES ==
585 GNUNET_CONTAINER_multipeermap_remove (car->
586 client_handle->requests,
587 &car->target,
588 car));
589 GSC_SESSIONS_dequeue_request (car);
590 GNUNET_free (car);
591 return GNUNET_YES;
592}
593
594
595/**
596 * A client connected, set up.
597 *
598 * @param cls closure
599 * @param client identification of the client
600 * @param mq message queue to talk to @a client
601 * @return our client handle
602 */
603static void *
604client_connect_cb (void *cls,
605 struct GNUNET_SERVICE_Client *client,
606 struct GNUNET_MQ_Handle *mq)
607{
608 struct GSC_Client *c;
609
610 c = GNUNET_new (struct GSC_Client);
611 c->client = client;
612 c->mq = mq;
613 GNUNET_CONTAINER_DLL_insert (client_head,
614 client_tail,
615 c);
616 return c;
617}
618
619
620/**
621 * A client disconnected, clean up.
622 *
623 * @param cls closure
624 * @param client identification of the client
625 * @param app_ctx our `struct GST_Client` for @a client
626 */
627static void
628client_disconnect_cb (void *cls,
629 struct GNUNET_SERVICE_Client *client,
630 void *app_ctx)
631{
632 struct GSC_Client *c = app_ctx;
633
634 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
635 "Client %p has disconnected from core service.\n",
636 client);
637 GNUNET_CONTAINER_DLL_remove (client_head,
638 client_tail,
639 c);
640 if (NULL != c->requests)
641 {
642 GNUNET_CONTAINER_multipeermap_iterate (c->requests,
643 &destroy_active_client_request,
644 NULL);
645 GNUNET_CONTAINER_multipeermap_destroy (c->requests);
646 }
647 if (NULL != c->connectmap)
648 {
649 GNUNET_CONTAINER_multipeermap_destroy (c->connectmap);
650 c->connectmap = NULL;
651 }
652 if (NULL != c->types)
653 {
654 GSC_TYPEMAP_remove (c->types,
655 c->tcnt);
656 GNUNET_free (c->types);
657 }
658 GNUNET_free (c);
659
660 /* recalculate 'all_client_options' */
661 all_client_options = 0;
662 for (c = client_head; NULL != c ; c = c->next)
663 all_client_options |= c->options;
664}
665
666
667/**
668 * Notify a particular client about a change to existing connection to
669 * one of our neighbours (check if the client is interested). Called
670 * from #GSC_SESSIONS_notify_client_about_sessions().
671 *
672 * @param client client to notify
673 * @param neighbour identity of the neighbour that changed status
674 * @param tmap_old previous type map for the neighbour, NULL for connect
675 * @param tmap_new updated type map for the neighbour, NULL for disconnect
676 */
677void
678GSC_CLIENTS_notify_client_about_neighbour (struct GSC_Client *client,
679 const struct GNUNET_PeerIdentity *neighbour,
680 const struct GSC_TypeMap *tmap_old,
681 const struct GSC_TypeMap *tmap_new)
682{
683 struct GNUNET_MQ_Envelope *env;
684 int old_match;
685 int new_match;
686
687 old_match = GSC_TYPEMAP_test_match (tmap_old,
688 client->types,
689 client->tcnt);
690 new_match = GSC_TYPEMAP_test_match (tmap_new,
691 client->types,
692 client->tcnt);
693 if (old_match == new_match)
694 {
695 GNUNET_assert (old_match ==
696 GNUNET_CONTAINER_multipeermap_contains (client->connectmap,
697 neighbour));
698 return; /* no change */
699 }
700 if (GNUNET_NO == old_match)
701 {
702 struct ConnectNotifyMessage *cnm;
703
704 /* send connect */
705 GNUNET_assert (GNUNET_NO ==
706 GNUNET_CONTAINER_multipeermap_contains (client->connectmap,
707 neighbour));
708 GNUNET_assert (GNUNET_YES ==
709 GNUNET_CONTAINER_multipeermap_put (client->connectmap,
710 neighbour,
711 NULL,
712 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
713 env = GNUNET_MQ_msg (cnm,
714 GNUNET_MESSAGE_TYPE_CORE_NOTIFY_CONNECT);
715 cnm->reserved = htonl (0);
716 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
717 "Sending NOTIFY_CONNECT message to client.\n");
718 cnm->peer = *neighbour;
719 GNUNET_MQ_send (client->mq,
720 env);
721 }
722 else
723 {
724 struct DisconnectNotifyMessage *dcm;
725
726 /* send disconnect */
727 GNUNET_assert (GNUNET_YES ==
728 GNUNET_CONTAINER_multipeermap_contains (client->connectmap,
729 neighbour));
730 GNUNET_assert (GNUNET_YES ==
731 GNUNET_CONTAINER_multipeermap_remove (client->connectmap,
732 neighbour,
733 NULL));
734 env = GNUNET_MQ_msg (dcm,
735 GNUNET_MESSAGE_TYPE_CORE_NOTIFY_DISCONNECT);
736 dcm->reserved = htonl (0);
737 dcm->peer = *neighbour;
738 GNUNET_MQ_send (client->mq,
739 env);
740 }
741}
742
743
744/**
745 * Notify all clients about a change to existing session.
746 * Called from SESSIONS whenever there is a change in sessions
747 * or types processed by the respective peer.
748 *
749 * @param neighbour identity of the neighbour that changed status
750 * @param tmap_old previous type map for the neighbour, NULL for connect
751 * @param tmap_new updated type map for the neighbour, NULL for disconnect
752 */
753void
754GSC_CLIENTS_notify_clients_about_neighbour (const struct GNUNET_PeerIdentity *neighbour,
755 const struct GSC_TypeMap *tmap_old,
756 const struct GSC_TypeMap *tmap_new)
757{
758 struct GSC_Client *c;
759
760 for (c = client_head; NULL != c; c = c->next)
761 GSC_CLIENTS_notify_client_about_neighbour (c,
762 neighbour,
763 tmap_old,
764 tmap_new);
765}
766
767
768/**
769 * Deliver P2P message to interested clients. Caller must have checked
770 * that the sending peer actually lists the given message type as one
771 * of its types.
772 *
773 * @param sender peer who sent us the message
774 * @param msg the message
775 * @param msize number of bytes to transmit
776 * @param options options for checking which clients should
777 * receive the message
778 */
779void
780GSC_CLIENTS_deliver_message (const struct GNUNET_PeerIdentity *sender,
781 const struct GNUNET_MessageHeader *msg,
782 uint16_t msize,
783 uint32_t options)
784{
785 size_t size = msize + sizeof (struct NotifyTrafficMessage);
786
787 if (size >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
788 {
789 GNUNET_break (0);
790 return;
791 }
792 if (! ( (0 != (all_client_options & options)) ||
793 (0 != (options & GNUNET_CORE_OPTION_SEND_FULL_INBOUND)) ))
794 return; /* no client cares about this message notification */
795 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
796 "Core service passes message from `%s' of type %u to client.\n",
797 GNUNET_i2s (sender),
798 (unsigned int) ntohs (msg->type));
799 GSC_SESSIONS_add_to_typemap (sender,
800 ntohs (msg->type));
801
802 for (struct GSC_Client *c = client_head; NULL != c; c = c->next)
803 {
804 struct GNUNET_MQ_Envelope *env;
805 struct NotifyTrafficMessage *ntm;
806 uint16_t mtype;
807 int tm;
808
809 tm = type_match (ntohs (msg->type),
810 c);
811 if (! ( (0 != (c->options & options)) ||
812 ( (0 != (options & GNUNET_CORE_OPTION_SEND_FULL_INBOUND)) &&
813 (GNUNET_YES == tm) ) ) )
814 continue; /* neither options nor type match permit the message */
815 if ( (0 != (options & GNUNET_CORE_OPTION_SEND_HDR_INBOUND)) &&
816 ( (0 != (c->options & GNUNET_CORE_OPTION_SEND_FULL_INBOUND)) ||
817 (GNUNET_YES == tm) ) )
818 continue;
819 if ( (0 != (options & GNUNET_CORE_OPTION_SEND_HDR_OUTBOUND)) &&
820 (0 != (c->options & GNUNET_CORE_OPTION_SEND_FULL_OUTBOUND)) )
821 continue;
822 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
823 "Sending %u message with %u bytes to client interested in messages of type %u.\n",
824 options,
825 ntohs (msg->size),
826 (unsigned int) ntohs (msg->type));
827
828 if (0 != (options & (GNUNET_CORE_OPTION_SEND_FULL_INBOUND | GNUNET_CORE_OPTION_SEND_HDR_INBOUND)))
829 mtype = GNUNET_MESSAGE_TYPE_CORE_NOTIFY_INBOUND;
830 else
831 mtype = GNUNET_MESSAGE_TYPE_CORE_NOTIFY_OUTBOUND;
832 env = GNUNET_MQ_msg_extra (ntm,
833 msize,
834 mtype);
835 ntm->peer = *sender;
836 GNUNET_memcpy (&ntm[1],
837 msg,
838 msize);
839
840 GNUNET_assert ( (0 == (c->options & GNUNET_CORE_OPTION_SEND_FULL_INBOUND)) ||
841 (GNUNET_YES != tm) ||
842 (GNUNET_YES ==
843 GNUNET_CONTAINER_multipeermap_contains (c->connectmap,
844 sender)) );
845 GNUNET_MQ_send (c->mq,
846 env);
847 }
848}
55 849
56 850
57/** 851/**
@@ -63,9 +857,12 @@ static struct GNUNET_SERVER_Handle *GSC_server;
63static void 857static void
64shutdown_task (void *cls) 858shutdown_task (void *cls)
65{ 859{
860 struct GSC_Client *c;
861
66 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 862 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
67 "Core service shutting down.\n"); 863 "Core service shutting down.\n");
68 GSC_CLIENTS_done (); 864 while (NULL != (c = client_head))
865 GNUNET_SERVICE_client_drop (c->client);
69 GSC_SESSIONS_done (); 866 GSC_SESSIONS_done ();
70 GSC_KX_done (); 867 GSC_KX_done ();
71 GSC_TYPEMAP_done (); 868 GSC_TYPEMAP_done ();
@@ -80,22 +877,41 @@ shutdown_task (void *cls)
80 877
81 878
82/** 879/**
880 * Handle #GNUNET_MESSAGE_TYPE_CORE_MONITOR_PEERS request. For this
881 * request type, the client does not have to have transmitted an INIT
882 * request. All current peers are returned, regardless of which
883 * message types they accept.
884 *
885 * @param cls client sending the iteration request
886 * @param message iteration request message
887 */
888static void
889handle_client_monitor_peers (void *cls,
890 const struct GNUNET_MessageHeader *message)
891{
892 struct GSC_Client *c = cls;
893
894 GNUNET_SERVICE_client_continue (c->client);
895 GSC_KX_handle_client_monitor_peers (c->mq);
896}
897
898
899/**
83 * Initiate core service. 900 * Initiate core service.
84 * 901 *
85 * @param cls closure 902 * @param cls closure
86 * @param server the initialized server
87 * @param c configuration to use 903 * @param c configuration to use
904 * @param service the initialized service
88 */ 905 */
89static void 906static void
90run (void *cls, 907run (void *cls,
91 struct GNUNET_SERVER_Handle *server, 908 const struct GNUNET_CONFIGURATION_Handle *c,
92 const struct GNUNET_CONFIGURATION_Handle *c) 909 struct GNUNET_SERVICE_Handle *service)
93{ 910{
94 struct GNUNET_CRYPTO_EddsaPrivateKey *pk; 911 struct GNUNET_CRYPTO_EddsaPrivateKey *pk;
95 char *keyfile; 912 char *keyfile;
96 913
97 GSC_cfg = c; 914 GSC_cfg = c;
98 GSC_server = server;
99 if (GNUNET_OK != 915 if (GNUNET_OK !=
100 GNUNET_CONFIGURATION_get_value_filename (GSC_cfg, 916 GNUNET_CONFIGURATION_get_value_filename (GSC_cfg,
101 "PEER", 917 "PEER",
@@ -111,20 +927,18 @@ run (void *cls,
111 GSC_cfg); 927 GSC_cfg);
112 GNUNET_SCHEDULER_add_shutdown (&shutdown_task, 928 GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
113 NULL); 929 NULL);
114 GNUNET_SERVER_suspend (server); 930 GNUNET_SERVICE_suspend (service);
115 GSC_TYPEMAP_init (); 931 GSC_TYPEMAP_init ();
116 pk = GNUNET_CRYPTO_eddsa_key_create_from_file (keyfile); 932 pk = GNUNET_CRYPTO_eddsa_key_create_from_file (keyfile);
117 GNUNET_free (keyfile); 933 GNUNET_free (keyfile);
118 GNUNET_assert (NULL != pk); 934 GNUNET_assert (NULL != pk);
119 if (GNUNET_OK != GSC_KX_init (pk, 935 if (GNUNET_OK != GSC_KX_init (pk))
120 server))
121 { 936 {
122 GNUNET_SCHEDULER_shutdown (); 937 GNUNET_SCHEDULER_shutdown ();
123 return; 938 return;
124 } 939 }
125 GSC_SESSIONS_init (); 940 GSC_SESSIONS_init ();
126 GSC_CLIENTS_init (GSC_server); 941 GNUNET_SERVICE_resume (service);
127 GNUNET_SERVER_resume (GSC_server);
128 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 942 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
129 _("Core service of `%s' ready.\n"), 943 _("Core service of `%s' ready.\n"),
130 GNUNET_i2s (&GSC_my_identity)); 944 GNUNET_i2s (&GSC_my_identity));
@@ -132,19 +946,32 @@ run (void *cls,
132 946
133 947
134/** 948/**
135 * The main function for the transport service. 949 * Define "main" method using service macro.
136 *
137 * @param argc number of arguments from the command line
138 * @param argv command line arguments
139 * @return 0 ok, 1 on error
140 */ 950 */
141int 951GNUNET_SERVICE_MAIN
142main (int argc, char *const *argv) 952("core",
143{ 953 GNUNET_SERVICE_OPTION_NONE,
144 return (GNUNET_OK == 954 &run,
145 GNUNET_SERVICE_run (argc, argv, "core", 955 &client_connect_cb,
146 GNUNET_SERVICE_OPTION_NONE, 956 &client_disconnect_cb,
147 &run, NULL)) ? 0 : 1; 957 NULL,
148} 958 GNUNET_MQ_hd_var_size (client_init,
959 GNUNET_MESSAGE_TYPE_CORE_INIT,
960 struct InitMessage,
961 NULL),
962 GNUNET_MQ_hd_fixed_size (client_monitor_peers,
963 GNUNET_MESSAGE_TYPE_CORE_MONITOR_PEERS,
964 struct GNUNET_MessageHeader,
965 NULL),
966 GNUNET_MQ_hd_fixed_size (client_send_request,
967 GNUNET_MESSAGE_TYPE_CORE_SEND_REQUEST,
968 struct SendMessageRequest,
969 NULL),
970 GNUNET_MQ_hd_var_size (client_send,
971 GNUNET_MESSAGE_TYPE_CORE_SEND,
972 struct SendMessage,
973 NULL),
974 GNUNET_MQ_handler_end ());
975
149 976
150/* end of gnunet-service-core.c */ 977/* end of gnunet-service-core.c */
diff --git a/src/core/gnunet-service-core.h b/src/core/gnunet-service-core.h
index 068a2f84f..86ac333b5 100644
--- a/src/core/gnunet-service-core.h
+++ b/src/core/gnunet-service-core.h
@@ -29,6 +29,8 @@
29#include "gnunet_statistics_service.h" 29#include "gnunet_statistics_service.h"
30#include "gnunet_core_service.h" 30#include "gnunet_core_service.h"
31#include "core.h" 31#include "core.h"
32#include "gnunet-service-core_typemap.h"
33
32 34
33/** 35/**
34 * Opaque handle to a client. 36 * Opaque handle to a client.
@@ -100,6 +102,84 @@ struct GSC_ClientActiveRequest
100 102
101 103
102/** 104/**
105 * Tell a client that we are ready to receive the message.
106 *
107 * @param car request that is now ready; the responsibility
108 * for the handle remains shared between CLIENTS
109 * and SESSIONS after this call.
110 */
111void
112GSC_CLIENTS_solicit_request (struct GSC_ClientActiveRequest *car);
113
114
115/**
116 * We will never be ready to transmit the given message in (disconnect
117 * or invalid request). Frees resources associated with @a car. We
118 * don't explicitly tell the client, he'll learn with the disconnect
119 * (or violated the protocol).
120 *
121 * @param car request that now permanently failed; the
122 * responsibility for the handle is now returned
123 * to CLIENTS (SESSIONS is done with it).
124 * @param drop_client #GNUNET_YES if the client violated the protocol
125 * and we should thus drop the connection
126 */
127void
128GSC_CLIENTS_reject_request (struct GSC_ClientActiveRequest *car,
129 int drop_client);
130
131
132/**
133 * Notify a particular client about a change to existing connection to
134 * one of our neighbours (check if the client is interested). Called
135 * from #GSC_SESSIONS_notify_client_about_sessions().
136 *
137 * @param client client to notify
138 * @param neighbour identity of the neighbour that changed status
139 * @param tmap_old previous type map for the neighbour, NULL for connect
140 * @param tmap_new updated type map for the neighbour, NULL for disconnect
141 */
142void
143GSC_CLIENTS_notify_client_about_neighbour (struct GSC_Client *client,
144 const struct GNUNET_PeerIdentity *neighbour,
145 const struct GSC_TypeMap *tmap_old,
146 const struct GSC_TypeMap *tmap_new);
147
148
149/**
150 * Deliver P2P message to interested clients. Caller must have checked
151 * that the sending peer actually lists the given message type as one
152 * of its types.
153 *
154 * @param sender peer who sent us the message
155 * @param msg the message
156 * @param msize number of bytes to transmit
157 * @param options options for checking which clients should
158 * receive the message
159 */
160void
161GSC_CLIENTS_deliver_message (const struct GNUNET_PeerIdentity *sender,
162 const struct GNUNET_MessageHeader *msg,
163 uint16_t msize,
164 uint32_t options);
165
166
167/**
168 * Notify all clients about a change to existing session.
169 * Called from SESSIONS whenever there is a change in sessions
170 * or types processed by the respective peer.
171 *
172 * @param neighbour identity of the neighbour that changed status
173 * @param tmap_old previous type map for the neighbour, NULL for connect
174 * @param tmap_new updated type map for the neighbour, NULL for disconnect
175 */
176void
177GSC_CLIENTS_notify_clients_about_neighbour (const struct GNUNET_PeerIdentity *neighbour,
178 const struct GSC_TypeMap *tmap_old,
179 const struct GSC_TypeMap *tmap_new);
180
181
182/**
103 * Our configuration. 183 * Our configuration.
104 */ 184 */
105extern const struct GNUNET_CONFIGURATION_Handle *GSC_cfg; 185extern const struct GNUNET_CONFIGURATION_Handle *GSC_cfg;
diff --git a/src/core/gnunet-service-core_clients.c b/src/core/gnunet-service-core_clients.c
deleted file mode 100644
index 5db33f04b..000000000
--- a/src/core/gnunet-service-core_clients.c
+++ /dev/null
@@ -1,960 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009, 2010, 2011 GNUnet e.V.
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
19*/
20
21/**
22 * @file core/gnunet-service-core_clients.c
23 * @brief code for managing interactions with clients of core service
24 * @author Christian Grothoff
25 */
26#include "platform.h"
27#include "gnunet_util_lib.h"
28#include "gnunet_statistics_service.h"
29#include "gnunet_transport_service.h"
30#include "gnunet-service-core.h"
31#include "gnunet-service-core_clients.h"
32#include "gnunet-service-core_sessions.h"
33#include "gnunet-service-core_typemap.h"
34#include "core.h"
35
36
37/**
38 * How many messages do we queue up at most for optional
39 * notifications to a client? (this can cause notifications
40 * about outgoing messages to be dropped).
41 */
42#define MAX_NOTIFY_QUEUE 1024
43
44
45/**
46 * Data structure for each client connected to the CORE service.
47 */
48struct GSC_Client
49{
50 /**
51 * Clients are kept in a linked list.
52 */
53 struct GSC_Client *next;
54
55 /**
56 * Clients are kept in a linked list.
57 */
58 struct GSC_Client *prev;
59
60 /**
61 * Handle for the client with the server API.
62 */
63 struct GNUNET_SERVER_Client *client_handle;
64
65 /**
66 * Array of the types of messages this peer cares
67 * about (with @e tcnt entries). Allocated as part
68 * of this client struct, do not free!
69 */
70 const uint16_t *types;
71
72 /**
73 * Map of peer identities to active transmission requests of this
74 * client to the peer (of type `struct GSC_ClientActiveRequest`).
75 */
76 struct GNUNET_CONTAINER_MultiPeerMap *requests;
77
78 /**
79 * Map containing all peers that this client knows we're connected to.
80 */
81 struct GNUNET_CONTAINER_MultiPeerMap *connectmap;
82
83 /**
84 * Options for messages this client cares about,
85 * see GNUNET_CORE_OPTION_ values.
86 */
87 uint32_t options;
88
89 /**
90 * Number of types of incoming messages this client
91 * specifically cares about. Size of the @e types array.
92 */
93 unsigned int tcnt;
94
95};
96
97
98/**
99 * Big "or" of all client options.
100 */
101static uint32_t all_client_options;
102
103/**
104 * Head of linked list of our clients.
105 */
106static struct GSC_Client *client_head;
107
108/**
109 * Tail of linked list of our clients.
110 */
111static struct GSC_Client *client_tail;
112
113/**
114 * Context for notifications we need to send to our clients.
115 */
116static struct GNUNET_SERVER_NotificationContext *notifier;
117
118/**
119 * Tokenizer for messages received from clients.
120 */
121static struct GNUNET_SERVER_MessageStreamTokenizer *client_mst;
122
123
124/**
125 * Lookup our client struct given the server's client handle.
126 *
127 * @param client server client handle to look up
128 * @return our client handle for the client
129 */
130static struct GSC_Client *
131find_client (struct GNUNET_SERVER_Client *client)
132{
133 struct GSC_Client *c;
134
135 c = client_head;
136 while ((c != NULL) && (c->client_handle != client))
137 c = c->next;
138 return c;
139}
140
141
142/**
143 * Send a message to one of our clients.
144 *
145 * @param client target for the message
146 * @param msg message to transmit
147 * @param can_drop could this message be dropped if the
148 * client's queue is getting too large?
149 */
150static void
151send_to_client (struct GSC_Client *client,
152 const struct GNUNET_MessageHeader *msg,
153 int can_drop)
154{
155 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
156 "Preparing to send %u bytes of message of type %u to client.\n",
157 (unsigned int) ntohs (msg->size),
158 (unsigned int) ntohs (msg->type));
159 GNUNET_SERVER_notification_context_unicast (notifier, client->client_handle,
160 msg, can_drop);
161}
162
163
164/**
165 * Send a message to one of our clients.
166 *
167 * @param client target for the message
168 * @param msg message to transmit
169 * @param can_drop could this message be dropped if the
170 * client's queue is getting too large?
171 */
172void
173GSC_CLIENTS_send_to_client (struct GNUNET_SERVER_Client *client,
174 const struct GNUNET_MessageHeader *msg,
175 int can_drop)
176{
177 struct GSC_Client *c;
178
179 c = find_client (client);
180 if (NULL == c)
181 {
182 GNUNET_break (0);
183 return;
184 }
185 send_to_client (c, msg, can_drop);
186}
187
188
189/**
190 * Test if the client is interested in messages of the given type.
191 *
192 * @param type message type
193 * @param c client to test
194 * @return #GNUNET_YES if @a c is interested, #GNUNET_NO if not.
195 */
196static int
197type_match (uint16_t type, struct GSC_Client *c)
198{
199 unsigned int i;
200
201 if (c->tcnt == 0 && c->options != 0)
202 return GNUNET_YES; /* peer without handlers and inbound/outbond
203 callbacks matches ALL */
204 for (i = 0; i < c->tcnt; i++)
205 if (type == c->types[i])
206 return GNUNET_YES;
207 return GNUNET_NO;
208}
209
210
211/**
212 * Send a message to all of our current clients that have the right
213 * options set.
214 *
215 * @param partner origin (or destination) of the message (used to check that this peer is
216 * known to be connected to the respective client)
217 * @param msg message to multicast
218 * @param can_drop can this message be discarded if the queue is too long
219 * @param options mask to use
220 * @param type type of the embedded message, 0 for none
221 */
222static void
223send_to_all_clients (const struct GNUNET_PeerIdentity *partner,
224 const struct GNUNET_MessageHeader *msg,
225 int can_drop,
226 uint32_t options,
227 uint16_t type)
228{
229 struct GSC_Client *c;
230 int tm;
231
232 for (c = client_head; NULL != c; c = c->next)
233 {
234 tm = type_match (type, c);
235 if (! ( (0 != (c->options & options)) ||
236 ( (0 != (options & GNUNET_CORE_OPTION_SEND_FULL_INBOUND)) &&
237 (GNUNET_YES == tm) ) ) )
238 continue; /* neither options nor type match permit the message */
239 if ( (0 != (options & GNUNET_CORE_OPTION_SEND_HDR_INBOUND)) &&
240 ( (0 != (c->options & GNUNET_CORE_OPTION_SEND_FULL_INBOUND)) ||
241 (GNUNET_YES == tm) ) )
242 continue;
243 if ( (0 != (options & GNUNET_CORE_OPTION_SEND_HDR_OUTBOUND)) &&
244 (0 != (c->options & GNUNET_CORE_OPTION_SEND_FULL_OUTBOUND)) )
245 continue;
246 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
247 "Sending %u message with %u bytes to client interested in messages of type %u.\n",
248 options,
249 ntohs (msg->size),
250 (unsigned int) type);
251 GNUNET_assert ( (0 == (c->options & GNUNET_CORE_OPTION_SEND_FULL_INBOUND)) ||
252 (GNUNET_YES != tm) ||
253 (GNUNET_YES ==
254 GNUNET_CONTAINER_multipeermap_contains (c->connectmap,
255 partner)) );
256 send_to_client (c, msg, can_drop);
257 }
258}
259
260
261/**
262 * Handle #GNUNET_MESSAGE_TYPE_CORE_INIT request.
263 *
264 * @param cls unused
265 * @param client new client that sent #GNUNET_MESSAGE_TYPE_CORE_INIT
266 * @param message the `struct InitMessage` (presumably)
267 */
268static void
269handle_client_init (void *cls,
270 struct GNUNET_SERVER_Client *client,
271 const struct GNUNET_MessageHeader *message)
272{
273 const struct InitMessage *im;
274 struct InitReplyMessage irm;
275 struct GSC_Client *c;
276 uint16_t msize;
277 const uint16_t *types;
278 uint16_t *wtypes;
279 unsigned int i;
280
281 /* check that we don't have an entry already */
282 c = find_client (client);
283 if (NULL != c)
284 {
285 GNUNET_break (0);
286 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
287 return;
288 }
289 msize = ntohs (message->size);
290 if (msize < sizeof (struct InitMessage))
291 {
292 GNUNET_break (0);
293 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
294 return;
295 }
296 GNUNET_SERVER_notification_context_add (notifier, client);
297 im = (const struct InitMessage *) message;
298 types = (const uint16_t *) &im[1];
299 msize -= sizeof (struct InitMessage);
300 c = GNUNET_malloc (sizeof (struct GSC_Client) + msize);
301 c->client_handle = client;
302 c->tcnt = msize / sizeof (uint16_t);
303 c->options = ntohl (im->options);
304 all_client_options |= c->options;
305 c->types = (const uint16_t *) &c[1];
306 c->connectmap = GNUNET_CONTAINER_multipeermap_create (16, GNUNET_NO);
307 GNUNET_assert (GNUNET_YES ==
308 GNUNET_CONTAINER_multipeermap_put (c->connectmap,
309 &GSC_my_identity,
310 NULL,
311 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
312 wtypes = (uint16_t *) & c[1];
313 for (i = 0; i < c->tcnt; i++)
314 wtypes[i] = ntohs (types[i]);
315 GSC_TYPEMAP_add (wtypes, c->tcnt);
316 GNUNET_CONTAINER_DLL_insert (client_head, client_tail, c);
317 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
318 "Client connecting to core service is interested in %u message types\n",
319 (unsigned int) c->tcnt);
320 /* send init reply message */
321 irm.header.size = htons (sizeof (struct InitReplyMessage));
322 irm.header.type = htons (GNUNET_MESSAGE_TYPE_CORE_INIT_REPLY);
323 irm.reserved = htonl (0);
324 irm.my_identity = GSC_my_identity;
325 send_to_client (c, &irm.header, GNUNET_NO);
326 GSC_SESSIONS_notify_client_about_sessions (c);
327 GNUNET_SERVER_receive_done (client, GNUNET_OK);
328}
329
330
331/**
332 * Handle #GNUNET_MESSAGE_TYPE_CORE_SEND_REQUEST message.
333 *
334 * @param cls unused
335 * @param client new client that sent a #GNUNET_MESSAGE_TYPE_CORE_SEND_REQUEST
336 * @param message the `struct SendMessageRequest` (presumably)
337 */
338static void
339handle_client_send_request (void *cls,
340 struct GNUNET_SERVER_Client *client,
341 const struct GNUNET_MessageHeader *message)
342{
343 const struct SendMessageRequest *req;
344 struct GSC_Client *c;
345 struct GSC_ClientActiveRequest *car;
346 int is_loopback;
347
348 req = (const struct SendMessageRequest *) message;
349 c = find_client (client);
350 if (NULL == c)
351 {
352 /* client did not send INIT first! */
353 GNUNET_break (0);
354 GNUNET_SERVER_receive_done (client,
355 GNUNET_SYSERR);
356 return;
357 }
358 if (NULL == c->requests)
359 c->requests = GNUNET_CONTAINER_multipeermap_create (16,
360 GNUNET_NO);
361 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
362 "Client asked for transmission to `%s'\n",
363 GNUNET_i2s (&req->peer));
364 is_loopback =
365 (0 ==
366 memcmp (&req->peer,
367 &GSC_my_identity,
368 sizeof (struct GNUNET_PeerIdentity)));
369 if ((! is_loopback) &&
370 (GNUNET_YES !=
371 GNUNET_CONTAINER_multipeermap_contains (c->connectmap,
372 &req->peer)))
373 {
374 /* neighbour must have disconnected since request was issued,
375 * ignore (client will realize it once it processes the
376 * disconnect notification) */
377 GNUNET_STATISTICS_update (GSC_stats,
378 gettext_noop
379 ("# send requests dropped (disconnected)"), 1,
380 GNUNET_NO);
381 GNUNET_SERVER_receive_done (client,
382 GNUNET_OK);
383 return;
384 }
385
386 car = GNUNET_CONTAINER_multipeermap_get (c->requests,
387 &req->peer);
388 if (NULL == car)
389 {
390 /* create new entry */
391 car = GNUNET_new (struct GSC_ClientActiveRequest);
392 GNUNET_assert (GNUNET_OK ==
393 GNUNET_CONTAINER_multipeermap_put (c->requests,
394 &req->peer,
395 car,
396 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST));
397 car->client_handle = c;
398 }
399 else
400 {
401 /* dequeue and recycle memory from pending request, there can only
402 be at most one per client and peer */
403 GNUNET_STATISTICS_update (GSC_stats,
404 gettext_noop ("# dequeuing CAR (duplicate request)"),
405 1,
406 GNUNET_NO);
407 GSC_SESSIONS_dequeue_request (car);
408 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
409 "Transmission request to `%s' was a duplicate!\n",
410 GNUNET_i2s (&req->peer));
411 }
412 car->target = req->peer;
413 car->received_time = GNUNET_TIME_absolute_get ();
414 car->deadline = GNUNET_TIME_absolute_ntoh (req->deadline);
415 car->priority = (enum GNUNET_CORE_Priority) ntohl (req->priority);
416 car->msize = ntohs (req->size);
417 car->smr_id = req->smr_id;
418 car->was_solicited = GNUNET_NO;
419 if (is_loopback)
420 {
421 /* loopback, satisfy immediately */
422 GSC_CLIENTS_solicit_request (car);
423 GNUNET_SERVER_receive_done (client, GNUNET_OK);
424 return;
425 }
426 GSC_SESSIONS_queue_request (car);
427 GNUNET_SERVER_receive_done (client, GNUNET_OK);
428}
429
430
431/**
432 * Closure for the #client_tokenizer_callback().
433 */
434struct TokenizerContext
435{
436
437 /**
438 * Active request handle for the message.
439 */
440 struct GSC_ClientActiveRequest *car;
441
442 /**
443 * How important is this message.
444 */
445 enum GNUNET_CORE_Priority priority;
446
447 /**
448 * Is corking allowed (set only once we have the real message).
449 */
450 int cork;
451
452};
453
454
455/**
456 * Handle #GNUNET_MESSAGE_TYPE_CORE_SEND request.
457 *
458 * @param cls unused
459 * @param client the client issuing the request
460 * @param message the `struct SendMessage`
461 */
462static void
463handle_client_send (void *cls,
464 struct GNUNET_SERVER_Client *client,
465 const struct GNUNET_MessageHeader *message)
466{
467 const struct SendMessage *sm;
468 struct GSC_Client *c;
469 struct TokenizerContext tc;
470 uint16_t msize;
471 struct GNUNET_TIME_Relative delay;
472
473 msize = ntohs (message->size);
474 if (msize < sizeof (struct SendMessage))
475 {
476 GNUNET_break (0);
477 GNUNET_SERVER_receive_done (client,
478 GNUNET_SYSERR);
479 return;
480 }
481 sm = (const struct SendMessage *) message;
482 msize -= sizeof (struct SendMessage);
483 GNUNET_break (0 == ntohl (sm->reserved));
484 c = find_client (client);
485 if (NULL == c)
486 {
487 /* client did not send INIT first! */
488 GNUNET_break (0);
489 GNUNET_SERVER_receive_done (client,
490 GNUNET_SYSERR);
491 return;
492 }
493 tc.car = GNUNET_CONTAINER_multipeermap_get (c->requests,
494 &sm->peer);
495 if (NULL == tc.car)
496 {
497 /* Must have been that we first approved the request, then got disconnected
498 * (which triggered removal of the 'car') and now the client gives us a message
499 * just *before* the client learns about the disconnect. Theoretically, we
500 * might also now be *again* connected. So this can happen (but should be
501 * rare). If it does happen, the message is discarded. */
502 GNUNET_STATISTICS_update (GSC_stats,
503 gettext_noop ("# messages discarded (session disconnected)"),
504 1,
505 GNUNET_NO);
506 GNUNET_SERVER_receive_done (client,
507 GNUNET_OK);
508 return;
509 }
510 delay = GNUNET_TIME_absolute_get_duration (tc.car->received_time);
511 tc.cork = ntohl (sm->cork);
512 tc.priority = (enum GNUNET_CORE_Priority) ntohl (sm->priority);
513 if (delay.rel_value_us > GNUNET_CONSTANTS_LATENCY_WARN.rel_value_us)
514 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
515 "Client waited %s for transmission of %u bytes to `%s'%s\n",
516 GNUNET_STRINGS_relative_time_to_string (delay,
517 GNUNET_YES),
518 msize,
519 GNUNET_i2s (&sm->peer),
520 tc.cork ? " (cork)" : " (uncorked)");
521 else
522 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
523 "Client waited %s for transmission of %u bytes to `%s'%s\n",
524 GNUNET_STRINGS_relative_time_to_string (delay,
525 GNUNET_YES),
526 msize,
527 GNUNET_i2s (&sm->peer),
528 tc.cork ? " (cork)" : " (uncorked)");
529
530 GNUNET_assert (GNUNET_YES ==
531 GNUNET_CONTAINER_multipeermap_remove (c->requests,
532 &sm->peer,
533 tc.car));
534 GNUNET_SERVER_mst_receive (client_mst, &tc,
535 (const char *) &sm[1],
536 msize,
537 GNUNET_YES,
538 GNUNET_NO);
539 GSC_SESSIONS_dequeue_request (tc.car);
540 GNUNET_free (tc.car);
541 GNUNET_SERVER_receive_done (client,
542 GNUNET_OK);
543}
544
545
546/**
547 * Functions with this signature are called whenever a complete
548 * message is received by the tokenizer. Used by the 'client_mst' for
549 * dispatching messages from clients to either the SESSION subsystem
550 * or other CLIENT (for loopback).
551 *
552 * @param cls closure
553 * @param client reservation request (`struct GSC_ClientActiveRequest`)
554 * @param message the actual message
555 */
556static int
557client_tokenizer_callback (void *cls,
558 void *client,
559 const struct GNUNET_MessageHeader *message)
560{
561 struct TokenizerContext *tc = client;
562 struct GSC_ClientActiveRequest *car = tc->car;
563 char buf[92];
564
565 GNUNET_snprintf (buf, sizeof (buf),
566 gettext_noop ("# bytes of messages of type %u received"),
567 (unsigned int) ntohs (message->type));
568 GNUNET_STATISTICS_update (GSC_stats,
569 buf,
570 ntohs (message->size),
571 GNUNET_NO);
572 if (0 ==
573 memcmp (&car->target,
574 &GSC_my_identity,
575 sizeof (struct GNUNET_PeerIdentity)))
576 {
577 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
578 "Delivering message of type %u to myself\n",
579 ntohs (message->type));
580 GSC_CLIENTS_deliver_message (&GSC_my_identity, message,
581 ntohs (message->size),
582 GNUNET_CORE_OPTION_SEND_FULL_OUTBOUND);
583 GSC_CLIENTS_deliver_message (&GSC_my_identity, message,
584 sizeof (struct GNUNET_MessageHeader),
585 GNUNET_CORE_OPTION_SEND_HDR_OUTBOUND);
586 GSC_CLIENTS_deliver_message (&GSC_my_identity, message,
587 ntohs (message->size),
588 GNUNET_CORE_OPTION_SEND_FULL_INBOUND);
589 GSC_CLIENTS_deliver_message (&GSC_my_identity, message,
590 sizeof (struct GNUNET_MessageHeader),
591 GNUNET_CORE_OPTION_SEND_HDR_INBOUND);
592 }
593 else
594 {
595 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
596 "Delivering message of type %u and size %u to %s\n",
597 ntohs (message->type), ntohs (message->size),
598 GNUNET_i2s (&car->target));
599 GSC_CLIENTS_deliver_message (&car->target, message,
600 ntohs (message->size),
601 GNUNET_CORE_OPTION_SEND_FULL_OUTBOUND);
602 GSC_CLIENTS_deliver_message (&car->target, message,
603 sizeof (struct GNUNET_MessageHeader),
604 GNUNET_CORE_OPTION_SEND_HDR_OUTBOUND);
605 GSC_SESSIONS_transmit (car,
606 message,
607 tc->cork,
608 tc->priority);
609 }
610 return GNUNET_OK;
611}
612
613
614/**
615 * Free client request records.
616 *
617 * @param cls NULL
618 * @param key identity of peer for which this is an active request
619 * @param value the `struct GSC_ClientActiveRequest` to free
620 * @return #GNUNET_YES (continue iteration)
621 */
622static int
623destroy_active_client_request (void *cls,
624 const struct GNUNET_PeerIdentity *key,
625 void *value)
626{
627 struct GSC_ClientActiveRequest *car = value;
628
629 GNUNET_assert (GNUNET_YES ==
630 GNUNET_CONTAINER_multipeermap_remove (car->
631 client_handle->requests,
632 &car->target,
633 car));
634 GSC_SESSIONS_dequeue_request (car);
635 GNUNET_free (car);
636 return GNUNET_YES;
637}
638
639
640/**
641 * A client disconnected, clean up.
642 *
643 * @param cls closure
644 * @param client identification of the client
645 */
646static void
647handle_client_disconnect (void *cls,
648 struct GNUNET_SERVER_Client *client)
649{
650 struct GSC_Client *c;
651
652 if (NULL == client)
653 return;
654 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
655 "Client %p has disconnected from core service.\n",
656 client);
657 c = find_client (client);
658 if (c == NULL)
659 return; /* client never sent INIT */
660 GNUNET_CONTAINER_DLL_remove (client_head, client_tail, c);
661 if (c->requests != NULL)
662 {
663 GNUNET_CONTAINER_multipeermap_iterate (c->requests,
664 &destroy_active_client_request,
665 NULL);
666 GNUNET_CONTAINER_multipeermap_destroy (c->requests);
667 }
668 GNUNET_CONTAINER_multipeermap_destroy (c->connectmap);
669 c->connectmap = NULL;
670 GSC_TYPEMAP_remove (c->types, c->tcnt);
671 GNUNET_free (c);
672
673 /* recalculate 'all_client_options' */
674 all_client_options = 0;
675 for (c = client_head; NULL != c ; c = c->next)
676 all_client_options |= c->options;
677}
678
679
680/**
681 * Tell a client that we are ready to receive the message.
682 *
683 * @param car request that is now ready; the responsibility
684 * for the handle remains shared between CLIENTS
685 * and SESSIONS after this call.
686 */
687void
688GSC_CLIENTS_solicit_request (struct GSC_ClientActiveRequest *car)
689{
690 struct GSC_Client *c;
691 struct SendMessageReady smr;
692 struct GNUNET_TIME_Relative delay;
693 struct GNUNET_TIME_Relative left;
694
695 c = car->client_handle;
696 if (GNUNET_YES !=
697 GNUNET_CONTAINER_multipeermap_contains (c->connectmap,
698 &car->target))
699 {
700 /* connection has gone down since, drop request */
701 GNUNET_assert (0 !=
702 memcmp (&car->target,
703 &GSC_my_identity,
704 sizeof (struct GNUNET_PeerIdentity)));
705 GSC_SESSIONS_dequeue_request (car);
706 GSC_CLIENTS_reject_request (car,
707 GNUNET_NO);
708 return;
709 }
710 delay = GNUNET_TIME_absolute_get_duration (car->received_time);
711 left = GNUNET_TIME_absolute_get_duration (car->deadline);
712 if (delay.rel_value_us > GNUNET_CONSTANTS_LATENCY_WARN.rel_value_us)
713 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
714 "Client waited %s for permission to transmit to `%s'%s (priority %u)\n",
715 GNUNET_STRINGS_relative_time_to_string (delay,
716 GNUNET_YES),
717 GNUNET_i2s (&car->target),
718 (0 == left.rel_value_us)
719 ? " (past deadline)"
720 : "",
721 car->priority);
722 smr.header.size = htons (sizeof (struct SendMessageReady));
723 smr.header.type = htons (GNUNET_MESSAGE_TYPE_CORE_SEND_READY);
724 smr.size = htons (car->msize);
725 smr.smr_id = car->smr_id;
726 smr.peer = car->target;
727 send_to_client (c, &smr.header, GNUNET_NO);
728}
729
730
731/**
732 * We will never be ready to transmit the given message in (disconnect
733 * or invalid request). Frees resources associated with @a car. We
734 * don't explicitly tell the client, he'll learn with the disconnect
735 * (or violated the protocol).
736 *
737 * @param car request that now permanently failed; the
738 * responsibility for the handle is now returned
739 * to CLIENTS (SESSIONS is done with it).
740 * @param drop_client #GNUNET_YES if the client violated the protocol
741 * and we should thus drop the connection
742 */
743void
744GSC_CLIENTS_reject_request (struct GSC_ClientActiveRequest *car,
745 int drop_client)
746{
747 GNUNET_assert (GNUNET_YES ==
748 GNUNET_CONTAINER_multipeermap_remove (car->
749 client_handle->requests,
750 &car->target,
751 car));
752 if (GNUNET_YES == drop_client)
753 GNUNET_SERVER_client_disconnect (car->client_handle->client_handle);
754 GNUNET_free (car);
755}
756
757
758/**
759 * Notify a particular client about a change to existing connection to
760 * one of our neighbours (check if the client is interested). Called
761 * from 'GSC_SESSIONS_notify_client_about_sessions'.
762 *
763 * @param client client to notify
764 * @param neighbour identity of the neighbour that changed status
765 * @param tmap_old previous type map for the neighbour, NULL for connect
766 * @param tmap_new updated type map for the neighbour, NULL for disconnect
767 */
768void
769GSC_CLIENTS_notify_client_about_neighbour (struct GSC_Client *client,
770 const struct GNUNET_PeerIdentity *neighbour,
771 const struct GSC_TypeMap *tmap_old,
772 const struct GSC_TypeMap *tmap_new)
773{
774 struct ConnectNotifyMessage *cnm;
775 size_t size;
776 char buf[GNUNET_SERVER_MAX_MESSAGE_SIZE - 1] GNUNET_ALIGN;
777 struct DisconnectNotifyMessage dcm;
778 int old_match;
779 int new_match;
780
781 old_match = GSC_TYPEMAP_test_match (tmap_old, client->types, client->tcnt);
782 new_match = GSC_TYPEMAP_test_match (tmap_new, client->types, client->tcnt);
783 if (old_match == new_match)
784 {
785 GNUNET_assert (old_match ==
786 GNUNET_CONTAINER_multipeermap_contains (client->connectmap,
787 neighbour));
788 return; /* no change */
789 }
790 if (old_match == GNUNET_NO)
791 {
792 /* send connect */
793 GNUNET_assert (GNUNET_NO ==
794 GNUNET_CONTAINER_multipeermap_contains (client->connectmap,
795 neighbour));
796 GNUNET_assert (GNUNET_YES ==
797 GNUNET_CONTAINER_multipeermap_put (client->connectmap,
798 neighbour,
799 NULL,
800 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
801 size = sizeof (struct ConnectNotifyMessage);
802 cnm = (struct ConnectNotifyMessage *) buf;
803 cnm->header.size = htons (size);
804 cnm->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_NOTIFY_CONNECT);
805 cnm->reserved = htonl (0);
806 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
807 "Sending `%s' message to client.\n",
808 "NOTIFY_CONNECT");
809 cnm->peer = *neighbour;
810 send_to_client (client, &cnm->header, GNUNET_NO);
811 }
812 else
813 {
814 /* send disconnect */
815 GNUNET_assert (GNUNET_YES ==
816 GNUNET_CONTAINER_multipeermap_contains (client->connectmap,
817 neighbour));
818 GNUNET_assert (GNUNET_YES ==
819 GNUNET_CONTAINER_multipeermap_remove (client->connectmap,
820 neighbour,
821 NULL));
822 dcm.header.size = htons (sizeof (struct DisconnectNotifyMessage));
823 dcm.header.type = htons (GNUNET_MESSAGE_TYPE_CORE_NOTIFY_DISCONNECT);
824 dcm.reserved = htonl (0);
825 dcm.peer = *neighbour;
826 send_to_client (client, &dcm.header, GNUNET_NO);
827 }
828}
829
830
831/**
832 * Notify all clients about a change to existing session.
833 * Called from SESSIONS whenever there is a change in sessions
834 * or types processed by the respective peer.
835 *
836 * @param neighbour identity of the neighbour that changed status
837 * @param tmap_old previous type map for the neighbour, NULL for connect
838 * @param tmap_new updated type map for the neighbour, NULL for disconnect
839 */
840void
841GSC_CLIENTS_notify_clients_about_neighbour (const struct GNUNET_PeerIdentity *neighbour,
842 const struct GSC_TypeMap *tmap_old,
843 const struct GSC_TypeMap *tmap_new)
844{
845 struct GSC_Client *c;
846
847 for (c = client_head; NULL != c; c = c->next)
848 GSC_CLIENTS_notify_client_about_neighbour (c, neighbour,
849 tmap_old, tmap_new);
850}
851
852
853/**
854 * Deliver P2P message to interested clients. Caller must have checked
855 * that the sending peer actually lists the given message type as one
856 * of its types.
857 *
858 * @param sender peer who sent us the message
859 * @param msg the message
860 * @param msize number of bytes to transmit
861 * @param options options for checking which clients should
862 * receive the message
863 */
864void
865GSC_CLIENTS_deliver_message (const struct GNUNET_PeerIdentity *sender,
866 const struct GNUNET_MessageHeader *msg,
867 uint16_t msize,
868 uint32_t options)
869{
870 size_t size = msize + sizeof (struct NotifyTrafficMessage);
871 char buf[size] GNUNET_ALIGN;
872 struct NotifyTrafficMessage *ntm;
873
874 if (size >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
875 {
876 GNUNET_break (0);
877 /* recovery strategy: throw performance data away... */
878 size = msize + sizeof (struct NotifyTrafficMessage);
879 }
880 if (! ( (0 != (all_client_options & options)) ||
881 (0 != (options & GNUNET_CORE_OPTION_SEND_FULL_INBOUND)) ))
882 return; /* no client cares about this message notification */
883 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
884 "Core service passes message from `%s' of type %u to client.\n",
885 GNUNET_i2s (sender),
886 (unsigned int) ntohs (msg->type));
887 GSC_SESSIONS_add_to_typemap (sender, ntohs (msg->type));
888 ntm = (struct NotifyTrafficMessage *) buf;
889 ntm->header.size = htons (size);
890 if (0 != (options & (GNUNET_CORE_OPTION_SEND_FULL_INBOUND | GNUNET_CORE_OPTION_SEND_HDR_INBOUND)))
891 ntm->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_NOTIFY_INBOUND);
892 else
893 ntm->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_NOTIFY_OUTBOUND);
894 ntm->peer = *sender;
895 GNUNET_memcpy (&ntm[1],
896 msg,
897 msize);
898 send_to_all_clients (sender,
899 &ntm->header,
900 GNUNET_YES,
901 options,
902 ntohs (msg->type));
903}
904
905
906/**
907 * Initialize clients subsystem.
908 *
909 * @param server handle to server clients connect to
910 */
911void
912GSC_CLIENTS_init (struct GNUNET_SERVER_Handle *server)
913{
914 static const struct GNUNET_SERVER_MessageHandler handlers[] = {
915 {&handle_client_init, NULL,
916 GNUNET_MESSAGE_TYPE_CORE_INIT, 0},
917 {&GSC_KX_handle_client_monitor_peers, NULL,
918 GNUNET_MESSAGE_TYPE_CORE_MONITOR_PEERS,
919 sizeof (struct GNUNET_MessageHeader)},
920 {&handle_client_send_request, NULL,
921 GNUNET_MESSAGE_TYPE_CORE_SEND_REQUEST,
922 sizeof (struct SendMessageRequest)},
923 {&handle_client_send, NULL,
924 GNUNET_MESSAGE_TYPE_CORE_SEND, 0},
925 {NULL, NULL, 0, 0}
926 };
927
928 /* setup notification */
929 client_mst = GNUNET_SERVER_mst_create (&client_tokenizer_callback, NULL);
930 notifier =
931 GNUNET_SERVER_notification_context_create (server, MAX_NOTIFY_QUEUE);
932 GNUNET_SERVER_disconnect_notify (server,
933 &handle_client_disconnect, NULL);
934 GNUNET_SERVER_add_handlers (server, handlers);
935}
936
937
938/**
939 * Shutdown clients subsystem.
940 */
941void
942GSC_CLIENTS_done ()
943{
944 struct GSC_Client *c;
945
946 while (NULL != (c = client_head))
947 handle_client_disconnect (NULL, c->client_handle);
948 if (NULL != notifier)
949 {
950 GNUNET_SERVER_notification_context_destroy (notifier);
951 notifier = NULL;
952 }
953 if (NULL != client_mst)
954 {
955 GNUNET_SERVER_mst_destroy (client_mst);
956 client_mst = NULL;
957 }
958}
959
960/* end of gnunet-service-core_clients.c */
diff --git a/src/core/gnunet-service-core_clients.h b/src/core/gnunet-service-core_clients.h
deleted file mode 100644
index 4947f337c..000000000
--- a/src/core/gnunet-service-core_clients.h
+++ /dev/null
@@ -1,142 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009, 2010, 2011 GNUnet e.V.
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
19*/
20
21/**
22 * @file core/gnunet-service-core_clients.h
23 * @brief code for managing interactions with clients of core service
24 * @author Christian Grothoff
25 */
26#ifndef GNUNET_SERVICE_CORE_CLIENTS_H
27#define GNUNET_SERVICE_CORE_CLIENTS_H
28
29#include "gnunet_util_lib.h"
30#include "gnunet-service-core.h"
31#include "gnunet-service-core_typemap.h"
32
33
34/**
35 * Send a message to one of our clients.
36 *
37 * @param client target for the message
38 * @param msg message to transmit
39 * @param can_drop could this message be dropped if the
40 * client's queue is getting too large?
41 */
42void
43GSC_CLIENTS_send_to_client (struct GNUNET_SERVER_Client *client,
44 const struct GNUNET_MessageHeader *msg,
45 int can_drop);
46
47
48/**
49 * Notify a particular client about a change to existing connection to
50 * one of our neighbours (check if the client is interested). Called
51 * from 'GSC_SESSIONS_notify_client_about_sessions'.
52 *
53 * @param client client to notify
54 * @param neighbour identity of the neighbour that changed status
55 * @param tmap_old previous type map for the neighbour, NULL for disconnect
56 * @param tmap_new updated type map for the neighbour, NULL for disconnect
57 */
58void
59GSC_CLIENTS_notify_client_about_neighbour (struct GSC_Client *client,
60 const struct GNUNET_PeerIdentity *neighbour,
61 const struct GSC_TypeMap *tmap_old,
62 const struct GSC_TypeMap *tmap_new);
63
64
65/**
66 * Notify all clients about a change to existing session.
67 * Called from SESSIONS whenever there is a change in sessions
68 * or types processed by the respective peer.
69 *
70 * @param neighbour identity of the neighbour that changed status
71 * @param tmap_old previous type map for the neighbour, NULL for disconnect
72 * @param tmap_new updated type map for the neighbour, NULL for disconnect
73 */
74void
75GSC_CLIENTS_notify_clients_about_neighbour (const struct GNUNET_PeerIdentity *neighbour,
76 const struct GSC_TypeMap *tmap_old,
77 const struct GSC_TypeMap *tmap_new);
78
79
80/**
81 * Deliver P2P message to interested clients. Caller must have checked
82 * that the sending peer actually lists the given message type as one
83 * of its types.
84 *
85 * @param sender peer who sent us the message
86 * @param msg the message
87 * @param msize number of bytes to transmit
88 * @param options options for checking which clients should
89 * receive the message
90 */
91void
92GSC_CLIENTS_deliver_message (const struct GNUNET_PeerIdentity *sender,
93 const struct GNUNET_MessageHeader *msg,
94 uint16_t msize,
95 uint32_t options);
96
97
98/**
99 * Tell a client that we are ready to receive the message.
100 *
101 * @param car request that is now ready; the responsibility
102 * for the handle remains shared between CLIENTS
103 * and SESSIONS after this call.
104 */
105void
106GSC_CLIENTS_solicit_request (struct GSC_ClientActiveRequest *car);
107
108
109/**
110 * We will never be ready to transmit the given message in (disconnect
111 * or invalid request). Frees resources associated with @a car. We
112 * don't explicitly tell the client, he'll learn with the disconnect
113 * (or violated the protocol).
114 *
115 * @param car request that now permanently failed; the
116 * responsibility for the handle is now returned
117 * to CLIENTS (SESSIONS is done with it).
118 * @param drop_client #GNUNET_YES if the client violated the protocol
119 * and we should thus drop the connection
120 */
121void
122GSC_CLIENTS_reject_request (struct GSC_ClientActiveRequest *car,
123 int drop_client);
124
125
126/**
127 * Initialize clients subsystem.
128 *
129 * @param server handle to server clients connect to
130 */
131void
132GSC_CLIENTS_init (struct GNUNET_SERVER_Handle *server);
133
134
135/**
136 * Shutdown clients subsystem.
137 */
138void
139GSC_CLIENTS_done (void);
140
141#endif
142/* end of gnunet-service-core_clients.h */
diff --git a/src/core/gnunet-service-core_kx.c b/src/core/gnunet-service-core_kx.c
index 6f6786d89..6743ce215 100644
--- a/src/core/gnunet-service-core_kx.c
+++ b/src/core/gnunet-service-core_kx.c
@@ -26,7 +26,6 @@
26#include "platform.h" 26#include "platform.h"
27#include "gnunet-service-core_kx.h" 27#include "gnunet-service-core_kx.h"
28#include "gnunet-service-core.h" 28#include "gnunet-service-core.h"
29#include "gnunet-service-core_clients.h"
30#include "gnunet-service-core_sessions.h" 29#include "gnunet-service-core_sessions.h"
31#include "gnunet_statistics_service.h" 30#include "gnunet_statistics_service.h"
32#include "gnunet_transport_core_service.h" 31#include "gnunet_transport_core_service.h"
@@ -392,34 +391,9 @@ static struct GSC_KeyExchangeInfo *kx_tail;
392static struct GNUNET_SCHEDULER_Task *rekey_task; 391static struct GNUNET_SCHEDULER_Task *rekey_task;
393 392
394/** 393/**
395 * Notification context for all monitors. 394 * Notification context for broadcasting to monitors.
396 */ 395 */
397static struct GNUNET_SERVER_NotificationContext *nc; 396static struct GNUNET_NotificationContext *nc;
398
399
400/**
401 * Inform the given monitor about the KX state of
402 * the given peer.
403 *
404 * @param client client to inform
405 * @param kx key exchange state to inform about
406 */
407static void
408monitor_notify (struct GNUNET_SERVER_Client *client,
409 struct GSC_KeyExchangeInfo *kx)
410{
411 struct MonitorNotifyMessage msg;
412
413 msg.header.type = htons (GNUNET_MESSAGE_TYPE_CORE_MONITOR_NOTIFY);
414 msg.header.size = htons (sizeof (msg));
415 msg.state = htonl ((uint32_t) kx->status);
416 msg.peer = *kx->peer;
417 msg.timeout = GNUNET_TIME_absolute_hton (kx->timeout);
418 GNUNET_SERVER_notification_context_unicast (nc,
419 client,
420 &msg.header,
421 GNUNET_NO);
422}
423 397
424 398
425/** 399/**
@@ -453,9 +427,9 @@ monitor_notify_all (struct GSC_KeyExchangeInfo *kx)
453 msg.state = htonl ((uint32_t) kx->status); 427 msg.state = htonl ((uint32_t) kx->status);
454 msg.peer = *kx->peer; 428 msg.peer = *kx->peer;
455 msg.timeout = GNUNET_TIME_absolute_hton (kx->timeout); 429 msg.timeout = GNUNET_TIME_absolute_hton (kx->timeout);
456 GNUNET_SERVER_notification_context_broadcast (nc, 430 GNUNET_notification_context_broadcast (nc,
457 &msg.header, 431 &msg.header,
458 GNUNET_NO); 432 GNUNET_NO);
459 kx->last_notify_timeout = kx->timeout; 433 kx->last_notify_timeout = kx->timeout;
460} 434}
461 435
@@ -1807,12 +1781,10 @@ do_rekey (void *cls)
1807 * Initialize KX subsystem. 1781 * Initialize KX subsystem.
1808 * 1782 *
1809 * @param pk private key to use for the peer 1783 * @param pk private key to use for the peer
1810 * @param server the server of the CORE service
1811 * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure 1784 * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure
1812 */ 1785 */
1813int 1786int
1814GSC_KX_init (struct GNUNET_CRYPTO_EddsaPrivateKey *pk, 1787GSC_KX_init (struct GNUNET_CRYPTO_EddsaPrivateKey *pk)
1815 struct GNUNET_SERVER_Handle *server)
1816{ 1788{
1817 struct GNUNET_MQ_MessageHandler handlers[] = { 1789 struct GNUNET_MQ_MessageHandler handlers[] = {
1818 GNUNET_MQ_hd_fixed_size (ephemeral_key, 1790 GNUNET_MQ_hd_fixed_size (ephemeral_key,
@@ -1834,8 +1806,6 @@ GSC_KX_init (struct GNUNET_CRYPTO_EddsaPrivateKey *pk,
1834 GNUNET_MQ_handler_end() 1806 GNUNET_MQ_handler_end()
1835 }; 1807 };
1836 1808
1837 nc = GNUNET_SERVER_notification_context_create (server,
1838 1);
1839 my_private_key = pk; 1809 my_private_key = pk;
1840 GNUNET_CRYPTO_eddsa_key_get_public (my_private_key, 1810 GNUNET_CRYPTO_eddsa_key_get_public (my_private_key,
1841 &GSC_my_identity.public_key); 1811 &GSC_my_identity.public_key);
@@ -1848,10 +1818,12 @@ GSC_KX_init (struct GNUNET_CRYPTO_EddsaPrivateKey *pk,
1848 return GNUNET_SYSERR; 1818 return GNUNET_SYSERR;
1849 } 1819 }
1850 sign_ephemeral_key (); 1820 sign_ephemeral_key ();
1821 nc = GNUNET_notification_context_create (1);
1851 rekey_task = GNUNET_SCHEDULER_add_delayed (REKEY_FREQUENCY, 1822 rekey_task = GNUNET_SCHEDULER_add_delayed (REKEY_FREQUENCY,
1852 &do_rekey, 1823 &do_rekey,
1853 NULL); 1824 NULL);
1854 mst = GNUNET_SERVER_mst_create (&deliver_message, NULL); 1825 mst = GNUNET_SERVER_mst_create (&deliver_message,
1826 NULL);
1855 transport 1827 transport
1856 = GNUNET_TRANSPORT_core_connect (GSC_cfg, 1828 = GNUNET_TRANSPORT_core_connect (GSC_cfg,
1857 &GSC_my_identity, 1829 &GSC_my_identity,
@@ -1902,7 +1874,7 @@ GSC_KX_done ()
1902 } 1874 }
1903 if (NULL != nc) 1875 if (NULL != nc)
1904 { 1876 {
1905 GNUNET_SERVER_notification_context_destroy (nc); 1877 GNUNET_notification_context_destroy (nc);
1906 nc = NULL; 1878 nc = NULL;
1907 } 1879 }
1908} 1880}
@@ -1940,34 +1912,36 @@ GSC_NEIGHBOURS_check_excess_bandwidth (const struct GSC_KeyExchangeInfo *kxinfo)
1940 * request. All current peers are returned, regardless of which 1912 * request. All current peers are returned, regardless of which
1941 * message types they accept. 1913 * message types they accept.
1942 * 1914 *
1943 * @param cls unused 1915 * @param mq message queue to add for monitoring
1944 * @param client client sending the iteration request
1945 * @param message iteration request message
1946 */ 1916 */
1947void 1917void
1948GSC_KX_handle_client_monitor_peers (void *cls, 1918GSC_KX_handle_client_monitor_peers (struct GNUNET_MQ_Handle *mq)
1949 struct GNUNET_SERVER_Client *client,
1950 const struct GNUNET_MessageHeader *message)
1951{ 1919{
1952 struct MonitorNotifyMessage done_msg; 1920 struct GNUNET_MQ_Envelope *env;
1921 struct MonitorNotifyMessage *done_msg;
1953 struct GSC_KeyExchangeInfo *kx; 1922 struct GSC_KeyExchangeInfo *kx;
1954 1923
1955 GNUNET_SERVER_receive_done (client, GNUNET_OK); 1924 GNUNET_notification_context_add (nc,
1956 GNUNET_SERVER_notification_context_add (nc, 1925 mq);
1957 client);
1958 for (kx = kx_head; NULL != kx; kx = kx->next) 1926 for (kx = kx_head; NULL != kx; kx = kx->next)
1959 monitor_notify (client, kx); 1927 {
1960 done_msg.header.size = htons (sizeof (struct MonitorNotifyMessage)); 1928 struct GNUNET_MQ_Envelope *env;
1961 done_msg.header.type = htons (GNUNET_MESSAGE_TYPE_CORE_MONITOR_NOTIFY); 1929 struct MonitorNotifyMessage *msg;
1962 done_msg.state = htonl ((uint32_t) GNUNET_CORE_KX_ITERATION_FINISHED); 1930
1963 memset (&done_msg.peer, 1931 env = GNUNET_MQ_msg (msg,
1964 0, 1932 GNUNET_MESSAGE_TYPE_CORE_MONITOR_NOTIFY);
1965 sizeof (struct GNUNET_PeerIdentity)); 1933 msg->state = htonl ((uint32_t) kx->status);
1966 done_msg.timeout = GNUNET_TIME_absolute_hton (GNUNET_TIME_UNIT_FOREVER_ABS); 1934 msg->peer = *kx->peer;
1967 GNUNET_SERVER_notification_context_unicast (nc, 1935 msg->timeout = GNUNET_TIME_absolute_hton (kx->timeout);
1968 client, 1936 GNUNET_MQ_send (mq,
1969 &done_msg.header, 1937 env);
1970 GNUNET_NO); 1938 }
1939 env = GNUNET_MQ_msg (done_msg,
1940 GNUNET_MESSAGE_TYPE_CORE_MONITOR_NOTIFY);
1941 done_msg->state = htonl ((uint32_t) GNUNET_CORE_KX_ITERATION_FINISHED);
1942 done_msg->timeout = GNUNET_TIME_absolute_hton (GNUNET_TIME_UNIT_FOREVER_ABS);
1943 GNUNET_MQ_send (mq,
1944 env);
1971} 1945}
1972 1946
1973 1947
diff --git a/src/core/gnunet-service-core_kx.h b/src/core/gnunet-service-core_kx.h
index 8614f090f..28293e607 100644
--- a/src/core/gnunet-service-core_kx.h
+++ b/src/core/gnunet-service-core_kx.h
@@ -53,12 +53,10 @@ GSC_KX_encrypt_and_transmit (struct GSC_KeyExchangeInfo *kx,
53 * Initialize KX subsystem. 53 * Initialize KX subsystem.
54 * 54 *
55 * @param pk private key to use for the peer 55 * @param pk private key to use for the peer
56 * @param server the server of the CORE service
57 * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure 56 * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure
58 */ 57 */
59int 58int
60GSC_KX_init (struct GNUNET_CRYPTO_EddsaPrivateKey *pk, 59GSC_KX_init (struct GNUNET_CRYPTO_EddsaPrivateKey *pk);
61 struct GNUNET_SERVER_Handle *server);
62 60
63 61
64/** 62/**
@@ -94,14 +92,10 @@ GSC_NEIGHBOURS_get_queue_length (const struct GSC_KeyExchangeInfo *target);
94 * request. All current peers are returned, regardless of which 92 * request. All current peers are returned, regardless of which
95 * message types they accept. 93 * message types they accept.
96 * 94 *
97 * @param cls unused 95 * @param mq message queue to add for monitoring
98 * @param client client sending the iteration request
99 * @param message iteration request message
100 */ 96 */
101void 97void
102GSC_KX_handle_client_monitor_peers (void *cls, 98GSC_KX_handle_client_monitor_peers (struct GNUNET_MQ_Handle *mq);
103 struct GNUNET_SERVER_Client *client,
104 const struct GNUNET_MessageHeader *message);
105 99
106 100
107#endif 101#endif
diff --git a/src/core/gnunet-service-core_sessions.c b/src/core/gnunet-service-core_sessions.c
index ef5285b45..036fd1425 100644
--- a/src/core/gnunet-service-core_sessions.c
+++ b/src/core/gnunet-service-core_sessions.c
@@ -28,7 +28,6 @@
28#include "gnunet-service-core_kx.h" 28#include "gnunet-service-core_kx.h"
29#include "gnunet-service-core_typemap.h" 29#include "gnunet-service-core_typemap.h"
30#include "gnunet-service-core_sessions.h" 30#include "gnunet-service-core_sessions.h"
31#include "gnunet-service-core_clients.h"
32#include "gnunet_constants.h" 31#include "gnunet_constants.h"
33#include "core.h" 32#include "core.h"
34 33