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