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