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