glitch in the license text detected by hyazinthe, thank you!
[oweals/gnunet.git] / src / core / gnunet-service-core.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2009, 2010, 2011, 2016 GNUnet e.V.
4
5      GNUnet is free software: you can redistribute it and/or modify it
6      under the terms of the GNU Affero General Public License as published
7      by the Free Software Foundation, either version 3 of the License,
8      or (at your 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      Affero General Public License for more details.
14 */
15
16 /**
17  * @file core/gnunet-service-core.c
18  * @brief high-level P2P messaging
19  * @author Christian Grothoff
20  */
21 #include "platform.h"
22 #include <gcrypt.h>
23 #include "gnunet_util_lib.h"
24 #include "gnunet-service-core.h"
25 #include "gnunet-service-core_kx.h"
26 #include "gnunet-service-core_sessions.h"
27 #include "gnunet-service-core_typemap.h"
28
29 /**
30  * How many messages do we queue up at most for any client? This can
31  * cause messages to be dropped if clients do not process them fast
32  * enough!  Note that this is a soft limit; we try
33  * to keep a few larger messages above the limit.
34  */
35 #define SOFT_MAX_QUEUE 128
36
37 /**
38  * How many messages do we queue up at most for any client? This can
39  * cause messages to be dropped if clients do not process them fast
40  * enough!  Note that this is the hard limit.
41  */
42 #define HARD_MAX_QUEUE 256
43
44
45 /**
46  * Data structure for each client connected to the CORE service.
47  */
48 struct 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_SERVICE_Client *client;
64
65   /**
66    * Message queue to talk to @e client.
67    */
68   struct GNUNET_MQ_Handle *mq;
69
70   /**
71    * Array of the types of messages this peer cares
72    * about (with @e tcnt entries).  Allocated as part
73    * of this client struct, do not free!
74    */
75   uint16_t *types;
76
77   /**
78    * Map of peer identities to active transmission requests of this
79    * client to the peer (of type `struct GSC_ClientActiveRequest`).
80    */
81   struct GNUNET_CONTAINER_MultiPeerMap *requests;
82
83   /**
84    * Map containing all peers that this client knows we're connected to.
85    */
86   struct GNUNET_CONTAINER_MultiPeerMap *connectmap;
87
88   /**
89    * Options for messages this client cares about,
90    * see GNUNET_CORE_OPTION_ values.
91    */
92   uint32_t options;
93
94   /**
95    * Have we gotten the #GNUNET_MESSAGE_TYPE_CORE_INIT message
96    * from this client already?
97    */
98   int got_init;
99
100   /**
101    * Number of types of incoming messages this client
102    * specifically cares about.  Size of the @e types array.
103    */
104   unsigned int tcnt;
105
106 };
107
108
109 /**
110  * Our identity.
111  */
112 struct GNUNET_PeerIdentity GSC_my_identity;
113
114 /**
115  * Our configuration.
116  */
117 const struct GNUNET_CONFIGURATION_Handle *GSC_cfg;
118
119 /**
120  * For creating statistics.
121  */
122 struct GNUNET_STATISTICS_Handle *GSC_stats;
123
124 /**
125  * Big "or" of all client options.
126  */
127 static uint32_t all_client_options;
128
129 /**
130  * Head of linked list of our clients.
131  */
132 static struct GSC_Client *client_head;
133
134 /**
135  * Tail of linked list of our clients.
136  */
137 static struct GSC_Client *client_tail;
138
139
140 /**
141  * Test if the client is interested in messages of the given type.
142  *
143  * @param type message type
144  * @param c client to test
145  * @return #GNUNET_YES if @a c is interested, #GNUNET_NO if not.
146  */
147 static int
148 type_match (uint16_t type,
149             struct GSC_Client *c)
150 {
151   if ( (0 == c->tcnt) &&
152        (0 != c->options) )
153     return GNUNET_YES;          /* peer without handlers and inbound/outbond
154                                    callbacks matches ALL */
155   if (NULL == c->types)
156     return GNUNET_NO;
157   for (unsigned int i = 0; i < c->tcnt; i++)
158     if (type == c->types[i])
159       return GNUNET_YES;
160   return GNUNET_NO;
161 }
162
163
164 /**
165  * Check #GNUNET_MESSAGE_TYPE_CORE_INIT request.
166  *
167  * @param cls client that sent #GNUNET_MESSAGE_TYPE_CORE_INIT
168  * @param im the `struct InitMessage`
169  * @return #GNUNET_OK if @a im is well-formed
170  */
171 static int
172 check_client_init (void *cls,
173                    const struct InitMessage *im)
174 {
175   return GNUNET_OK;
176 }
177
178
179 /**
180  * Handle #GNUNET_MESSAGE_TYPE_CORE_INIT request.
181  *
182  * @param cls client that sent #GNUNET_MESSAGE_TYPE_CORE_INIT
183  * @param im the `struct InitMessage`
184  */
185 static void
186 handle_client_init (void *cls,
187                     const struct InitMessage *im)
188 {
189   struct GSC_Client *c = cls;
190   struct GNUNET_MQ_Envelope *env;
191   struct InitReplyMessage *irm;
192   uint16_t msize;
193   const uint16_t *types;
194
195   /* check that we don't have an entry already */
196   msize = ntohs (im->header.size) - sizeof (struct InitMessage);
197   types = (const uint16_t *) &im[1];
198   c->tcnt = msize / sizeof (uint16_t);
199   c->options = ntohl (im->options);
200   c->got_init = GNUNET_YES;
201   all_client_options |= c->options;
202   c->types = GNUNET_malloc (msize);
203   GNUNET_assert (GNUNET_YES ==
204                  GNUNET_CONTAINER_multipeermap_put (c->connectmap,
205                                                     &GSC_my_identity,
206                                                     NULL,
207                                                     GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
208   for (unsigned int i = 0; i < c->tcnt; i++)
209     c->types[i] = ntohs (types[i]);
210   GSC_TYPEMAP_add (c->types,
211                    c->tcnt);
212   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
213               "Client connecting to core service is interested in %u message types\n",
214               (unsigned int) c->tcnt);
215   /* send init reply message */
216   env = GNUNET_MQ_msg (irm,
217                        GNUNET_MESSAGE_TYPE_CORE_INIT_REPLY);
218   irm->reserved = htonl (0);
219   irm->my_identity = GSC_my_identity;
220   GNUNET_MQ_send (c->mq,
221                   env);
222   GSC_SESSIONS_notify_client_about_sessions (c);
223   GNUNET_SERVICE_client_continue (c->client);
224 }
225
226
227 /**
228  * We will never be ready to transmit the given message in (disconnect
229  * or invalid request).  Frees resources associated with @a car.  We
230  * don't explicitly tell the client, he'll learn with the disconnect
231  * (or violated the protocol).
232  *
233  * @param car request that now permanently failed; the
234  *        responsibility for the handle is now returned
235  *        to CLIENTS (SESSIONS is done with it).
236  * @param drop_client #GNUNET_YES if the client violated the protocol
237  *        and we should thus drop the connection
238  */
239 void
240 GSC_CLIENTS_reject_request (struct GSC_ClientActiveRequest *car,
241                             int drop_client)
242 {
243   GNUNET_assert (GNUNET_YES ==
244                  GNUNET_CONTAINER_multipeermap_remove (car->
245                                                        client_handle->requests,
246                                                        &car->target,
247                                                        car));
248   if (GNUNET_YES == drop_client)
249     GNUNET_SERVICE_client_drop (car->client_handle->client);
250   GNUNET_free (car);
251 }
252
253
254 /**
255  * Tell a client that we are ready to receive the message.
256  *
257  * @param car request that is now ready; the responsibility
258  *        for the handle remains shared between CLIENTS
259  *        and SESSIONS after this call.
260  */
261 void
262 GSC_CLIENTS_solicit_request (struct GSC_ClientActiveRequest *car)
263 {
264   struct GSC_Client *c;
265   struct GNUNET_MQ_Envelope *env;
266   struct SendMessageReady *smr;
267   struct GNUNET_TIME_Relative delay;
268   struct GNUNET_TIME_Relative left;
269
270   c = car->client_handle;
271   if (GNUNET_YES !=
272       GNUNET_CONTAINER_multipeermap_contains (c->connectmap,
273                                               &car->target))
274   {
275     /* connection has gone down since, drop request */
276     GNUNET_assert (0 !=
277                    memcmp (&car->target,
278                            &GSC_my_identity,
279                            sizeof (struct GNUNET_PeerIdentity)));
280     GSC_SESSIONS_dequeue_request (car);
281     GSC_CLIENTS_reject_request (car,
282                                 GNUNET_NO);
283     return;
284   }
285   delay = GNUNET_TIME_absolute_get_duration (car->received_time);
286   left = GNUNET_TIME_absolute_get_duration (car->deadline);
287   if (delay.rel_value_us > GNUNET_CONSTANTS_LATENCY_WARN.rel_value_us)
288     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
289                 "Client waited %s for permission to transmit to `%s'%s (priority %u)\n",
290                 GNUNET_STRINGS_relative_time_to_string (delay,
291                                                         GNUNET_YES),
292                 GNUNET_i2s (&car->target),
293                 (0 == left.rel_value_us)
294                 ? " (past deadline)"
295                 : "",
296                 car->priority);
297   env = GNUNET_MQ_msg (smr,
298                        GNUNET_MESSAGE_TYPE_CORE_SEND_READY);
299   smr->size = htons (car->msize);
300   smr->smr_id = car->smr_id;
301   smr->peer = car->target;
302   GNUNET_MQ_send (c->mq,
303                   env);
304 }
305
306
307 /**
308  * Handle #GNUNET_MESSAGE_TYPE_CORE_SEND_REQUEST message.
309  *
310  * @param cls client that sent a #GNUNET_MESSAGE_TYPE_CORE_SEND_REQUEST
311  * @param req the `struct SendMessageRequest`
312  */
313 static void
314 handle_client_send_request (void *cls,
315                             const struct SendMessageRequest *req)
316 {
317   struct GSC_Client *c = cls;
318   struct GSC_ClientActiveRequest *car;
319   int is_loopback;
320
321   if (NULL == c->requests)
322     c->requests = GNUNET_CONTAINER_multipeermap_create (16,
323                                                         GNUNET_NO);
324   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
325               "Client asked for transmission to `%s'\n",
326               GNUNET_i2s (&req->peer));
327   is_loopback =
328       (0 ==
329        memcmp (&req->peer,
330                &GSC_my_identity,
331                sizeof (struct GNUNET_PeerIdentity)));
332   if ((! is_loopback) &&
333       (GNUNET_YES !=
334        GNUNET_CONTAINER_multipeermap_contains (c->connectmap,
335                                                &req->peer)))
336   {
337     /* neighbour must have disconnected since request was issued,
338      * ignore (client will realize it once it processes the
339      * disconnect notification) */
340     GNUNET_STATISTICS_update (GSC_stats,
341                               gettext_noop
342                               ("# send requests dropped (disconnected)"), 1,
343                               GNUNET_NO);
344     GNUNET_SERVICE_client_continue (c->client);
345     return;
346   }
347
348   car = GNUNET_CONTAINER_multipeermap_get (c->requests,
349                                            &req->peer);
350   if (NULL == car)
351   {
352     /* create new entry */
353     car = GNUNET_new (struct GSC_ClientActiveRequest);
354     GNUNET_assert (GNUNET_OK ==
355                    GNUNET_CONTAINER_multipeermap_put (c->requests,
356                                                       &req->peer,
357                                                       car,
358                                                       GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST));
359     car->client_handle = c;
360   }
361   else
362   {
363     /* dequeue and recycle memory from pending request, there can only
364        be at most one per client and peer */
365     GNUNET_STATISTICS_update (GSC_stats,
366                               gettext_noop ("# dequeuing CAR (duplicate request)"),
367                               1,
368                               GNUNET_NO);
369     GSC_SESSIONS_dequeue_request (car);
370     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
371                 "Transmission request to `%s' was a duplicate!\n",
372                 GNUNET_i2s (&req->peer));
373   }
374   car->target = req->peer;
375   car->received_time = GNUNET_TIME_absolute_get ();
376   car->deadline = GNUNET_TIME_absolute_ntoh (req->deadline);
377   car->priority = (enum GNUNET_CORE_Priority) ntohl (req->priority);
378   car->msize = ntohs (req->size);
379   car->smr_id = req->smr_id;
380   car->was_solicited = GNUNET_NO;
381   GNUNET_SERVICE_client_continue (c->client);
382   if (is_loopback)
383   {
384     /* loopback, satisfy immediately */
385     GSC_CLIENTS_solicit_request (car);
386     return;
387   }
388   GSC_SESSIONS_queue_request (car);
389 }
390
391
392 /**
393  * Closure for the #client_tokenizer_callback().
394  */
395 struct TokenizerContext
396 {
397
398   /**
399    * Active request handle for the message.
400    */
401   struct GSC_ClientActiveRequest *car;
402
403   /**
404    * How important is this message.
405    */
406   enum GNUNET_CORE_Priority priority;
407
408   /**
409    * Is corking allowed (set only once we have the real message).
410    */
411   int cork;
412
413 };
414
415
416 /**
417  * Functions with this signature are called whenever a complete
418  * message is received by the tokenizer.  Used by
419  * #handle_client_send() for dispatching messages from clients to
420  * either the SESSION subsystem or other CLIENT (for loopback).
421  *
422  * @param cls reservation request (`struct TokenizerContext`)
423  * @param message the actual message
424  * @return #GNUNET_OK on success,
425  *    #GNUNET_NO to stop further processing (no error)
426  *    #GNUNET_SYSERR to stop further processing with error
427  */
428 static int
429 tokenized_cb (void *cls,
430               const struct GNUNET_MessageHeader *message)
431 {
432   struct TokenizerContext *tc = cls;
433   struct GSC_ClientActiveRequest *car = tc->car;
434   char buf[92];
435
436   GNUNET_snprintf (buf,
437                    sizeof (buf),
438                    gettext_noop ("# bytes of messages of type %u received"),
439                    (unsigned int) ntohs (message->type));
440   GNUNET_STATISTICS_update (GSC_stats,
441                             buf,
442                             ntohs (message->size),
443                             GNUNET_NO);
444   if (0 ==
445       memcmp (&car->target,
446               &GSC_my_identity,
447               sizeof (struct GNUNET_PeerIdentity)))
448   {
449     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
450                 "Delivering message of type %u to myself\n",
451                 ntohs (message->type));
452     GSC_CLIENTS_deliver_message (&GSC_my_identity,
453                                  message,
454                                  ntohs (message->size),
455                                  GNUNET_CORE_OPTION_SEND_FULL_OUTBOUND);
456     GSC_CLIENTS_deliver_message (&GSC_my_identity,
457                                  message,
458                                  sizeof (struct GNUNET_MessageHeader),
459                                  GNUNET_CORE_OPTION_SEND_HDR_OUTBOUND);
460     GSC_CLIENTS_deliver_message (&GSC_my_identity,
461                                  message,
462                                  ntohs (message->size),
463                                  GNUNET_CORE_OPTION_SEND_FULL_INBOUND);
464     GSC_CLIENTS_deliver_message (&GSC_my_identity,
465                                  message,
466                                  sizeof (struct GNUNET_MessageHeader),
467                                  GNUNET_CORE_OPTION_SEND_HDR_INBOUND);
468   }
469   else
470   {
471     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
472                 "Delivering message of type %u and size %u to %s\n",
473                 ntohs (message->type),
474                 ntohs (message->size),
475                 GNUNET_i2s (&car->target));
476     GSC_CLIENTS_deliver_message (&car->target,
477                                  message,
478                                  ntohs (message->size),
479                                  GNUNET_CORE_OPTION_SEND_FULL_OUTBOUND);
480     GSC_CLIENTS_deliver_message (&car->target,
481                                  message,
482                                  sizeof (struct GNUNET_MessageHeader),
483                                  GNUNET_CORE_OPTION_SEND_HDR_OUTBOUND);
484     GSC_SESSIONS_transmit (car,
485                            message,
486                            tc->cork,
487                            tc->priority);
488   }
489   return GNUNET_OK;
490 }
491
492
493 /**
494  * Check #GNUNET_MESSAGE_TYPE_CORE_SEND request.
495  *
496  * @param cls the `struct GSC_Client`
497  * @param sm the `struct SendMessage`
498  * @return #GNUNET_OK if @a sm is well-formed
499  */
500 static int
501 check_client_send (void *cls,
502                    const struct SendMessage *sm)
503 {
504   return GNUNET_OK;
505 }
506
507
508 /**
509  * Handle #GNUNET_MESSAGE_TYPE_CORE_SEND request.
510  *
511  * @param cls the `struct GSC_Client`
512  * @param sm the `struct SendMessage`
513  */
514 static void
515 handle_client_send (void *cls,
516                     const struct SendMessage *sm)
517 {
518   struct GSC_Client *c = cls;
519   struct TokenizerContext tc;
520   uint16_t msize;
521   struct GNUNET_TIME_Relative delay;
522   struct GNUNET_MessageStreamTokenizer *mst;
523
524   msize = ntohs (sm->header.size) - sizeof (struct SendMessage);
525   GNUNET_break (0 == ntohl (sm->reserved));
526   tc.car = GNUNET_CONTAINER_multipeermap_get (c->requests,
527                                               &sm->peer);
528   if (NULL == tc.car)
529   {
530     /* Must have been that we first approved the request, then got disconnected
531      * (which triggered removal of the 'car') and now the client gives us a message
532      * just *before* the client learns about the disconnect.  Theoretically, we
533      * might also now be *again* connected.  So this can happen (but should be
534      * rare).  If it does happen, the message is discarded. */
535     GNUNET_STATISTICS_update (GSC_stats,
536                               gettext_noop ("# messages discarded (session disconnected)"),
537                               1,
538                               GNUNET_NO);
539     GNUNET_SERVICE_client_continue (c->client);
540     return;
541   }
542   delay = GNUNET_TIME_absolute_get_duration (tc.car->received_time);
543   tc.cork = ntohl (sm->cork);
544   tc.priority = (enum GNUNET_CORE_Priority) ntohl (sm->priority);
545   if (delay.rel_value_us > GNUNET_CONSTANTS_LATENCY_WARN.rel_value_us)
546     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
547                 "Client waited %s for transmission of %u bytes to `%s'%s\n",
548                 GNUNET_STRINGS_relative_time_to_string (delay,
549                                                         GNUNET_YES),
550                 msize,
551                 GNUNET_i2s (&sm->peer),
552                 tc.cork ? " (cork)" : " (uncorked)");
553   else
554     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
555                 "Client waited %s for transmission of %u bytes to `%s'%s\n",
556                 GNUNET_STRINGS_relative_time_to_string (delay,
557                                                         GNUNET_YES),
558                 msize,
559                 GNUNET_i2s (&sm->peer),
560                 tc.cork ? " (cork)" : " (uncorked)");
561
562   GNUNET_assert (GNUNET_YES ==
563                  GNUNET_CONTAINER_multipeermap_remove (c->requests,
564                                                        &sm->peer,
565                                                        tc.car));
566   mst = GNUNET_MST_create (&tokenized_cb,
567                            &tc);
568   GNUNET_MST_from_buffer (mst,
569                           (const char *) &sm[1],
570                           msize,
571                           GNUNET_YES,
572                           GNUNET_NO);
573   GNUNET_MST_destroy (mst);
574   GSC_SESSIONS_dequeue_request (tc.car);
575   GNUNET_free (tc.car);
576   GNUNET_SERVICE_client_continue (c->client);
577 }
578
579
580 /**
581  * Free client request records.
582  *
583  * @param cls NULL
584  * @param key identity of peer for which this is an active request
585  * @param value the `struct GSC_ClientActiveRequest` to free
586  * @return #GNUNET_YES (continue iteration)
587  */
588 static int
589 destroy_active_client_request (void *cls,
590                                const struct GNUNET_PeerIdentity *key,
591                                void *value)
592 {
593   struct GSC_ClientActiveRequest *car = value;
594
595   GNUNET_assert (GNUNET_YES ==
596                  GNUNET_CONTAINER_multipeermap_remove (car->
597                                                        client_handle->requests,
598                                                        &car->target,
599                                                        car));
600   GSC_SESSIONS_dequeue_request (car);
601   GNUNET_free (car);
602   return GNUNET_YES;
603 }
604
605
606 /**
607  * A client connected, set up.
608  *
609  * @param cls closure
610  * @param client identification of the client
611  * @param mq message queue to talk to @a client
612  * @return our client handle
613  */
614 static void *
615 client_connect_cb (void *cls,
616                    struct GNUNET_SERVICE_Client *client,
617                    struct GNUNET_MQ_Handle *mq)
618 {
619   struct GSC_Client *c;
620
621   c = GNUNET_new (struct GSC_Client);
622   c->client = client;
623   c->mq = mq;
624   c->connectmap = GNUNET_CONTAINER_multipeermap_create (16,
625                                                         GNUNET_NO);
626   GNUNET_CONTAINER_DLL_insert (client_head,
627                                client_tail,
628                                c);
629   return c;
630 }
631
632
633 /**
634  * A client disconnected, clean up.
635  *
636  * @param cls closure
637  * @param client identification of the client
638  * @param app_ctx our `struct GST_Client` for @a client
639  */
640 static void
641 client_disconnect_cb (void *cls,
642                       struct GNUNET_SERVICE_Client *client,
643                       void *app_ctx)
644 {
645   struct GSC_Client *c = app_ctx;
646
647   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
648               "Client %p has disconnected from core service.\n",
649               client);
650   GNUNET_CONTAINER_DLL_remove (client_head,
651                                client_tail,
652                                c);
653   if (NULL != c->requests)
654   {
655     GNUNET_CONTAINER_multipeermap_iterate (c->requests,
656                                            &destroy_active_client_request,
657                                            NULL);
658     GNUNET_CONTAINER_multipeermap_destroy (c->requests);
659   }
660   GNUNET_CONTAINER_multipeermap_destroy (c->connectmap);
661   c->connectmap = NULL;
662   if (NULL != c->types)
663   {
664     GSC_TYPEMAP_remove (c->types,
665                         c->tcnt);
666     GNUNET_free (c->types);
667   }
668   GNUNET_free (c);
669
670   /* recalculate 'all_client_options' */
671   all_client_options = 0;
672   for (c = client_head; NULL != c ; c = c->next)
673     all_client_options |= c->options;
674 }
675
676
677 /**
678  * Notify a particular client about a change to existing connection to
679  * one of our neighbours (check if the client is interested).  Called
680  * from #GSC_SESSIONS_notify_client_about_sessions().
681  *
682  * @param client client to notify
683  * @param neighbour identity of the neighbour that changed status
684  * @param tmap_old previous type map for the neighbour, NULL for connect
685  * @param tmap_new updated type map for the neighbour, NULL for disconnect
686  */
687 void
688 GSC_CLIENTS_notify_client_about_neighbour (struct GSC_Client *client,
689                                            const struct GNUNET_PeerIdentity *neighbour,
690                                            const struct GSC_TypeMap *tmap_old,
691                                            const struct GSC_TypeMap *tmap_new)
692 {
693   struct GNUNET_MQ_Envelope *env;
694   int old_match;
695   int new_match;
696
697   if (GNUNET_YES != client->got_init)
698     return;
699   old_match = GSC_TYPEMAP_test_match (tmap_old,
700                                       client->types,
701                                       client->tcnt);
702   new_match = GSC_TYPEMAP_test_match (tmap_new,
703                                       client->types,
704                                       client->tcnt);
705   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
706               "Notifying client about neighbour %s (%d/%d)\n",
707               GNUNET_i2s (neighbour),
708               old_match,
709               new_match);
710   if (old_match == new_match)
711   {
712     GNUNET_assert (old_match ==
713                    GNUNET_CONTAINER_multipeermap_contains (client->connectmap,
714                                                            neighbour));
715     return;                     /* no change */
716   }
717   if (GNUNET_NO == old_match)
718   {
719     struct ConnectNotifyMessage *cnm;
720
721     /* send connect */
722     GNUNET_assert (GNUNET_NO ==
723                    GNUNET_CONTAINER_multipeermap_contains (client->connectmap,
724                                                            neighbour));
725     GNUNET_assert (GNUNET_YES ==
726                    GNUNET_CONTAINER_multipeermap_put (client->connectmap,
727                                                       neighbour,
728                                                       NULL,
729                                                       GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
730     env = GNUNET_MQ_msg (cnm,
731                          GNUNET_MESSAGE_TYPE_CORE_NOTIFY_CONNECT);
732     cnm->reserved = htonl (0);
733     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
734                 "Sending NOTIFY_CONNECT message about peer %s to client.\n",
735                 GNUNET_i2s (neighbour));
736     cnm->peer = *neighbour;
737     GNUNET_MQ_send (client->mq,
738                     env);
739   }
740   else
741   {
742     struct DisconnectNotifyMessage *dcm;
743
744     /* send disconnect */
745     GNUNET_assert (GNUNET_YES ==
746                    GNUNET_CONTAINER_multipeermap_contains (client->connectmap,
747                                                            neighbour));
748     GNUNET_assert (GNUNET_YES ==
749                    GNUNET_CONTAINER_multipeermap_remove (client->connectmap,
750                                                          neighbour,
751                                                          NULL));
752     env = GNUNET_MQ_msg (dcm,
753                          GNUNET_MESSAGE_TYPE_CORE_NOTIFY_DISCONNECT);
754     dcm->reserved = htonl (0);
755     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
756                 "Sending NOTIFY_DISCONNECT message about peer %s to client.\n",
757                 GNUNET_i2s (neighbour));
758     dcm->peer = *neighbour;
759     GNUNET_MQ_send (client->mq,
760                     env);
761   }
762 }
763
764
765 /**
766  * Notify all clients about a change to existing session.
767  * Called from SESSIONS whenever there is a change in sessions
768  * or types processed by the respective peer.
769  *
770  * @param neighbour identity of the neighbour that changed status
771  * @param tmap_old previous type map for the neighbour, NULL for connect
772  * @param tmap_new updated type map for the neighbour, NULL for disconnect
773  */
774 void
775 GSC_CLIENTS_notify_clients_about_neighbour (const struct GNUNET_PeerIdentity *neighbour,
776                                             const struct GSC_TypeMap *tmap_old,
777                                             const struct GSC_TypeMap *tmap_new)
778 {
779   struct GSC_Client *c;
780
781   for (c = client_head; NULL != c; c = c->next)
782     GSC_CLIENTS_notify_client_about_neighbour (c,
783                                                neighbour,
784                                                tmap_old,
785                                                tmap_new);
786 }
787
788
789 /**
790  * Deliver P2P message to interested clients.  Caller must have checked
791  * that the sending peer actually lists the given message type as one
792  * of its types.
793  *
794  * @param sender peer who sent us the message
795  * @param msg the message
796  * @param msize number of bytes to transmit
797  * @param options options for checking which clients should
798  *        receive the message
799  */
800 void
801 GSC_CLIENTS_deliver_message (const struct GNUNET_PeerIdentity *sender,
802                              const struct GNUNET_MessageHeader *msg,
803                              uint16_t msize,
804                              uint32_t options)
805 {
806   size_t size = msize + sizeof (struct NotifyTrafficMessage);
807
808   if (size >= GNUNET_MAX_MESSAGE_SIZE)
809   {
810     GNUNET_break (0);
811     return;
812   }
813   if (! ( (0 != (all_client_options & options)) ||
814           (0 != (options & GNUNET_CORE_OPTION_SEND_FULL_INBOUND)) ))
815     return; /* no client cares about this message notification */
816   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
817               "Core service passes message from `%s' of type %u to client.\n",
818               GNUNET_i2s (sender),
819               (unsigned int) ntohs (msg->type));
820   GSC_SESSIONS_add_to_typemap (sender,
821                                ntohs (msg->type));
822
823   for (struct GSC_Client *c = client_head; NULL != c; c = c->next)
824   {
825     struct GNUNET_MQ_Envelope *env;
826     struct NotifyTrafficMessage *ntm;
827     uint16_t mtype;
828     unsigned int qlen;
829     int tm;
830
831     tm = type_match (ntohs (msg->type),
832                      c);
833     if (! ( (0 != (c->options & options)) ||
834             ( (0 != (options & GNUNET_CORE_OPTION_SEND_FULL_INBOUND)) &&
835               (GNUNET_YES == tm) ) ) )
836       continue;  /* neither options nor type match permit the message */
837     if ( (0 != (options & GNUNET_CORE_OPTION_SEND_HDR_INBOUND)) &&
838          ( (0 != (c->options & GNUNET_CORE_OPTION_SEND_FULL_INBOUND)) ||
839            (GNUNET_YES == tm) ) )
840       continue;
841     if ( (0 != (options & GNUNET_CORE_OPTION_SEND_HDR_OUTBOUND)) &&
842          (0 != (c->options & GNUNET_CORE_OPTION_SEND_FULL_OUTBOUND)) )
843       continue;
844
845     /* Drop messages if:
846        1) We are above the hard limit, or
847        2) We are above the soft limit, and a coin toss limited
848           to the message size (giving larger messages a
849           proportionally higher chance of being queued) falls
850           below the threshold. The threshold is based on where
851           we are between the soft and the hard limit, scaled
852           to match the range of message sizes we usually encounter
853           (i.e. up to 32k); so a 64k message has a 50% chance of
854           being kept if we are just barely below the hard max,
855           and a 99% chance of being kept if we are at the soft max.
856        The reason is to make it more likely to drop control traffic
857        (ACK, queries) which may be cummulative or highly redundant,
858        and cheap to drop than data traffic.  */
859     qlen = GNUNET_MQ_get_length (c->mq);
860     if ( (qlen >= HARD_MAX_QUEUE) ||
861          ( (qlen > SOFT_MAX_QUEUE) &&
862            ( (GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
863                                         ntohs (msg->size)) ) <
864              (qlen - SOFT_MAX_QUEUE) * 0x8000 /
865              (HARD_MAX_QUEUE - SOFT_MAX_QUEUE) ) ) )
866     {
867       char buf[1024];
868
869       GNUNET_log (GNUNET_ERROR_TYPE_INFO | GNUNET_ERROR_TYPE_BULK,
870                   "Dropping decrypted message of type %u as client is too busy (queue full)\n",
871                   (unsigned int) ntohs (msg->type));
872       GNUNET_snprintf (buf,
873                        sizeof (buf),
874                        gettext_noop ("# messages of type %u discarded (client busy)"),
875                        (unsigned int) ntohs (msg->type));
876       GNUNET_STATISTICS_update (GSC_stats,
877                                 buf,
878                                 1,
879                                 GNUNET_NO);
880       continue;
881     }
882
883     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
884                 "Sending %u message with %u bytes to client interested in messages of type %u.\n",
885                 options,
886                 ntohs (msg->size),
887                 (unsigned int) ntohs (msg->type));
888
889     if (0 != (options & (GNUNET_CORE_OPTION_SEND_FULL_INBOUND | GNUNET_CORE_OPTION_SEND_HDR_INBOUND)))
890       mtype = GNUNET_MESSAGE_TYPE_CORE_NOTIFY_INBOUND;
891     else
892       mtype = GNUNET_MESSAGE_TYPE_CORE_NOTIFY_OUTBOUND;
893     env = GNUNET_MQ_msg_extra (ntm,
894                                msize,
895                                mtype);
896     ntm->peer = *sender;
897     GNUNET_memcpy (&ntm[1],
898                    msg,
899                    msize);
900
901     GNUNET_assert ( (0 == (c->options & GNUNET_CORE_OPTION_SEND_FULL_INBOUND)) ||
902                     (GNUNET_YES != tm) ||
903                     (GNUNET_YES ==
904                      GNUNET_CONTAINER_multipeermap_contains (c->connectmap,
905                                                              sender)) );
906     GNUNET_MQ_send (c->mq,
907                     env);
908   }
909 }
910
911
912 /**
913  * Last task run during shutdown.  Disconnects us from
914  * the transport.
915  *
916  * @param cls NULL, unused
917  */
918 static void
919 shutdown_task (void *cls)
920 {
921   struct GSC_Client *c;
922
923   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
924               "Core service shutting down.\n");
925   while (NULL != (c = client_head))
926     GNUNET_SERVICE_client_drop (c->client);
927   GSC_SESSIONS_done ();
928   GSC_KX_done ();
929   GSC_TYPEMAP_done ();
930   if (NULL != GSC_stats)
931   {
932     GNUNET_STATISTICS_destroy (GSC_stats,
933                                GNUNET_NO);
934     GSC_stats = NULL;
935   }
936   GSC_cfg = NULL;
937 }
938
939
940 /**
941  * Handle #GNUNET_MESSAGE_TYPE_CORE_MONITOR_PEERS request.  For this
942  * request type, the client does not have to have transmitted an INIT
943  * request.  All current peers are returned, regardless of which
944  * message types they accept.
945  *
946  * @param cls client sending the iteration request
947  * @param message iteration request message
948  */
949 static void
950 handle_client_monitor_peers (void *cls,
951                              const struct GNUNET_MessageHeader *message)
952 {
953   struct GSC_Client *c = cls;
954
955   GNUNET_SERVICE_client_continue (c->client);
956   GSC_KX_handle_client_monitor_peers (c->mq);
957 }
958
959
960 /**
961  * Initiate core service.
962  *
963  * @param cls closure
964  * @param c configuration to use
965  * @param service the initialized service
966  */
967 static void
968 run (void *cls,
969      const struct GNUNET_CONFIGURATION_Handle *c,
970      struct GNUNET_SERVICE_Handle *service)
971 {
972   struct GNUNET_CRYPTO_EddsaPrivateKey *pk;
973   char *keyfile;
974
975   GSC_cfg = c;
976   if (GNUNET_OK !=
977       GNUNET_CONFIGURATION_get_value_filename (GSC_cfg,
978                                                "PEER",
979                                                "PRIVATE_KEY",
980                                                &keyfile))
981   {
982     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
983                 _("Core service is lacking HOSTKEY configuration setting.  Exiting.\n"));
984     GNUNET_SCHEDULER_shutdown ();
985     return;
986   }
987   GSC_stats = GNUNET_STATISTICS_create ("core",
988                                         GSC_cfg);
989   GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
990                                  NULL);
991   GNUNET_SERVICE_suspend (service);
992   GSC_TYPEMAP_init ();
993   pk = GNUNET_CRYPTO_eddsa_key_create_from_file (keyfile);
994   GNUNET_free (keyfile);
995   GNUNET_assert (NULL != pk);
996   if (GNUNET_OK != GSC_KX_init (pk))
997   {
998     GNUNET_SCHEDULER_shutdown ();
999     return;
1000   }
1001   GSC_SESSIONS_init ();
1002   GNUNET_SERVICE_resume (service);
1003   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1004               _("Core service of `%s' ready.\n"),
1005               GNUNET_i2s (&GSC_my_identity));
1006 }
1007
1008
1009 /**
1010  * Define "main" method using service macro.
1011  */
1012 GNUNET_SERVICE_MAIN
1013 ("core",
1014  GNUNET_SERVICE_OPTION_NONE,
1015  &run,
1016  &client_connect_cb,
1017  &client_disconnect_cb,
1018  NULL,
1019  GNUNET_MQ_hd_var_size (client_init,
1020                         GNUNET_MESSAGE_TYPE_CORE_INIT,
1021                         struct InitMessage,
1022                         NULL),
1023  GNUNET_MQ_hd_fixed_size (client_monitor_peers,
1024                           GNUNET_MESSAGE_TYPE_CORE_MONITOR_PEERS,
1025                           struct GNUNET_MessageHeader,
1026                           NULL),
1027  GNUNET_MQ_hd_fixed_size (client_send_request,
1028                           GNUNET_MESSAGE_TYPE_CORE_SEND_REQUEST,
1029                           struct SendMessageRequest,
1030                           NULL),
1031  GNUNET_MQ_hd_var_size (client_send,
1032                         GNUNET_MESSAGE_TYPE_CORE_SEND,
1033                         struct SendMessage,
1034                         NULL),
1035  GNUNET_MQ_handler_end ());
1036
1037
1038 /* end of gnunet-service-core.c */