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