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