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