-rps doxygen
[oweals/gnunet.git] / src / core / gnunet-service-core_clients.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2009, 2010, 2011 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_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_sessions.h"
33 #include "gnunet-service-core_typemap.h"
34 #include "core.h"
35
36
37 /**
38  * How many messages do we queue up at most for optional
39  * notifications to a client?  (this can cause notifications
40  * about outgoing messages to be dropped).
41  */
42 #define MAX_NOTIFY_QUEUE 1024
43
44
45 /**
46  * Data structure for each client connected to the CORE service.
47  */
48 struct GSC_Client
49 {
50   /**
51    * Clients are kept in a linked list.
52    */
53   struct GSC_Client *next;
54
55   /**
56    * Clients are kept in a linked list.
57    */
58   struct GSC_Client *prev;
59
60   /**
61    * Handle for the client with the server API.
62    */
63   struct GNUNET_SERVER_Client *client_handle;
64
65   /**
66    * Array of the types of messages this peer cares
67    * about (with @e tcnt entries).  Allocated as part
68    * of this client struct, do not free!
69    */
70   const uint16_t *types;
71
72   /**
73    * Map of peer identities to active transmission requests of this
74    * client to the peer (of type `struct GSC_ClientActiveRequest`).
75    */
76   struct GNUNET_CONTAINER_MultiPeerMap *requests;
77
78   /**
79    * Map containing all peers that this client knows we're connected to.
80    */
81   struct GNUNET_CONTAINER_MultiPeerMap *connectmap;
82
83   /**
84    * Options for messages this client cares about,
85    * see GNUNET_CORE_OPTION_ values.
86    */
87   uint32_t options;
88
89   /**
90    * Number of types of incoming messages this client
91    * specifically cares about.  Size of the @e types array.
92    */
93   unsigned int tcnt;
94
95 };
96
97
98 /**
99  * Big "or" of all client options.
100  */
101 static uint32_t all_client_options;
102
103 /**
104  * Head of linked list of our clients.
105  */
106 static struct GSC_Client *client_head;
107
108 /**
109  * Tail of linked list of our clients.
110  */
111 static struct GSC_Client *client_tail;
112
113 /**
114  * Context for notifications we need to send to our clients.
115  */
116 static struct GNUNET_SERVER_NotificationContext *notifier;
117
118 /**
119  * Tokenizer for messages received from clients.
120  */
121 static struct GNUNET_SERVER_MessageStreamTokenizer *client_mst;
122
123
124 /**
125  * Lookup our client struct given the server's client handle.
126  *
127  * @param client server client handle to look up
128  * @return our client handle for the client
129  */
130 static struct GSC_Client *
131 find_client (struct GNUNET_SERVER_Client *client)
132 {
133   struct GSC_Client *c;
134
135   c = client_head;
136   while ((c != NULL) && (c->client_handle != client))
137     c = c->next;
138   return c;
139 }
140
141
142 /**
143  * Send a message to one of our clients.
144  *
145  * @param client target for the message
146  * @param msg message to transmit
147  * @param can_drop could this message be dropped if the
148  *        client's queue is getting too large?
149  */
150 static void
151 send_to_client (struct GSC_Client *client,
152                 const struct GNUNET_MessageHeader *msg,
153                 int can_drop)
154 {
155   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
156               "Preparing to send %u bytes of message of type %u to client.\n",
157               (unsigned int) ntohs (msg->size),
158               (unsigned int) ntohs (msg->type));
159   GNUNET_SERVER_notification_context_unicast (notifier, client->client_handle,
160                                               msg, can_drop);
161 }
162
163
164 /**
165  * Send a message to one of our clients.
166  *
167  * @param client target for the message
168  * @param msg message to transmit
169  * @param can_drop could this message be dropped if the
170  *        client's queue is getting too large?
171  */
172 void
173 GSC_CLIENTS_send_to_client (struct GNUNET_SERVER_Client *client,
174                             const struct GNUNET_MessageHeader *msg,
175                             int can_drop)
176 {
177   struct GSC_Client *c;
178
179   c = find_client (client);
180   if (NULL == c)
181   {
182     GNUNET_break (0);
183     return;
184   }
185   send_to_client (c, msg, can_drop);
186 }
187
188
189 /**
190  * Test if the client is interested in messages of the given type.
191  *
192  * @param type message type
193  * @param c client to test
194  * @return #GNUNET_YES if @a c is interested, #GNUNET_NO if not.
195  */
196 static int
197 type_match (uint16_t type, struct GSC_Client *c)
198 {
199   unsigned int i;
200
201   if (c->tcnt == 0 && c->options != 0)
202     return GNUNET_YES;          /* peer without handlers and inbound/outbond
203                                    callbacks 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     GNUNET_STATISTICS_update (GSC_stats,
404                               gettext_noop ("# dequeuing CAR (duplicate request)"),
405                               1,
406                               GNUNET_NO);
407     GSC_SESSIONS_dequeue_request (car);
408     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
409                 "Transmission request to `%s' was a duplicate!\n",
410                 GNUNET_i2s (&req->peer));
411   }
412   car->target = req->peer;
413   car->received_time = GNUNET_TIME_absolute_get ();
414   car->deadline = GNUNET_TIME_absolute_ntoh (req->deadline);
415   car->priority = (enum GNUNET_CORE_Priority) ntohl (req->priority);
416   car->msize = ntohs (req->size);
417   car->smr_id = req->smr_id;
418   car->was_solicited = GNUNET_NO;
419   if (is_loopback)
420   {
421     /* loopback, satisfy immediately */
422     GSC_CLIENTS_solicit_request (car);
423     GNUNET_SERVER_receive_done (client, GNUNET_OK);
424     return;
425   }
426   GSC_SESSIONS_queue_request (car);
427   GNUNET_SERVER_receive_done (client, GNUNET_OK);
428 }
429
430
431 /**
432  * Closure for the #client_tokenizer_callback().
433  */
434 struct TokenizerContext
435 {
436
437   /**
438    * Active request handle for the message.
439    */
440   struct GSC_ClientActiveRequest *car;
441
442   /**
443    * How important is this message.
444    */
445   enum GNUNET_CORE_Priority priority;
446
447   /**
448    * Is corking allowed (set only once we have the real message).
449    */
450   int cork;
451
452 };
453
454
455 /**
456  * Handle #GNUNET_MESSAGE_TYPE_CORE_SEND request.
457  *
458  * @param cls unused
459  * @param client the client issuing the request
460  * @param message the `struct SendMessage`
461  */
462 static void
463 handle_client_send (void *cls,
464                     struct GNUNET_SERVER_Client *client,
465                     const struct GNUNET_MessageHeader *message)
466 {
467   const struct SendMessage *sm;
468   struct GSC_Client *c;
469   struct TokenizerContext tc;
470   uint16_t msize;
471   struct GNUNET_TIME_Relative delay;
472
473   msize = ntohs (message->size);
474   if (msize < sizeof (struct SendMessage))
475   {
476     GNUNET_break (0);
477     GNUNET_SERVER_receive_done (client,
478                                 GNUNET_SYSERR);
479     return;
480   }
481   sm = (const struct SendMessage *) message;
482   msize -= sizeof (struct SendMessage);
483   GNUNET_break (0 == ntohl (sm->reserved));
484   c = find_client (client);
485   if (NULL == c)
486   {
487     /* client did not send INIT first! */
488     GNUNET_break (0);
489     GNUNET_SERVER_receive_done (client,
490                                 GNUNET_SYSERR);
491     return;
492   }
493   tc.car = GNUNET_CONTAINER_multipeermap_get (c->requests,
494                                               &sm->peer);
495   if (NULL == tc.car)
496   {
497     /* Must have been that we first approved the request, then got disconnected
498      * (which triggered removal of the 'car') and now the client gives us a message
499      * just *before* the client learns about the disconnect.  Theoretically, we
500      * might also now be *again* connected.  So this can happen (but should be
501      * rare).  If it does happen, the message is discarded. */
502     GNUNET_STATISTICS_update (GSC_stats,
503                               gettext_noop ("# messages discarded (session disconnected)"),
504                               1,
505                               GNUNET_NO);
506     GNUNET_SERVER_receive_done (client,
507                                 GNUNET_OK);
508     return;
509   }
510   delay = GNUNET_TIME_absolute_get_duration (tc.car->received_time);
511   tc.cork = ntohl (sm->cork);
512   tc.priority = (enum GNUNET_CORE_Priority) ntohl (sm->priority);
513   if (delay.rel_value_us > GNUNET_CONSTANTS_LATENCY_WARN.rel_value_us)
514     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
515                 "Client waited %s for transmission of %u bytes to `%s'%s\n",
516                 GNUNET_STRINGS_relative_time_to_string (delay,
517                                                         GNUNET_YES),
518                 msize,
519                 GNUNET_i2s (&sm->peer),
520                 tc.cork ? " (cork)" : " (uncorked)");
521   else
522     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
523                 "Client waited %s for transmission of %u bytes to `%s'%s\n",
524                 GNUNET_STRINGS_relative_time_to_string (delay,
525                                                         GNUNET_YES),
526                 msize,
527                 GNUNET_i2s (&sm->peer),
528                 tc.cork ? " (cork)" : " (uncorked)");
529
530   GNUNET_assert (GNUNET_YES ==
531                  GNUNET_CONTAINER_multipeermap_remove (c->requests,
532                                                        &sm->peer,
533                                                        tc.car));
534   GNUNET_SERVER_mst_receive (client_mst, &tc,
535                              (const char *) &sm[1],
536                              msize,
537                              GNUNET_YES,
538                              GNUNET_NO);
539   GSC_SESSIONS_dequeue_request (tc.car);
540   GNUNET_free (tc.car);
541   GNUNET_SERVER_receive_done (client,
542                               GNUNET_OK);
543 }
544
545
546 /**
547  * Functions with this signature are called whenever a complete
548  * message is received by the tokenizer.  Used by the 'client_mst' for
549  * dispatching messages from clients to either the SESSION subsystem
550  * or other CLIENT (for loopback).
551  *
552  * @param cls closure
553  * @param client reservation request (`struct GSC_ClientActiveRequest`)
554  * @param message the actual message
555  */
556 static int
557 client_tokenizer_callback (void *cls,
558                            void *client,
559                            const struct GNUNET_MessageHeader *message)
560 {
561   struct TokenizerContext *tc = client;
562   struct GSC_ClientActiveRequest *car = tc->car;
563   char buf[92];
564
565   GNUNET_snprintf (buf, sizeof (buf),
566                    gettext_noop ("# bytes of messages of type %u received"),
567                    (unsigned int) ntohs (message->type));
568   GNUNET_STATISTICS_update (GSC_stats,
569                             buf,
570                             ntohs (message->size),
571                             GNUNET_NO);
572   if (0 ==
573       memcmp (&car->target,
574               &GSC_my_identity,
575               sizeof (struct GNUNET_PeerIdentity)))
576   {
577     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
578                 "Delivering message of type %u to myself\n",
579                 ntohs (message->type));
580     GSC_CLIENTS_deliver_message (&GSC_my_identity, message,
581                                  ntohs (message->size),
582                                  GNUNET_CORE_OPTION_SEND_FULL_OUTBOUND);
583     GSC_CLIENTS_deliver_message (&GSC_my_identity, message,
584                                  sizeof (struct GNUNET_MessageHeader),
585                                  GNUNET_CORE_OPTION_SEND_HDR_OUTBOUND);
586     GSC_CLIENTS_deliver_message (&GSC_my_identity, message,
587                                  ntohs (message->size),
588                                  GNUNET_CORE_OPTION_SEND_FULL_INBOUND);
589     GSC_CLIENTS_deliver_message (&GSC_my_identity, message,
590                                  sizeof (struct GNUNET_MessageHeader),
591                                  GNUNET_CORE_OPTION_SEND_HDR_INBOUND);
592   }
593   else
594   {
595     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
596                 "Delivering message of type %u and size %u to %s\n",
597                 ntohs (message->type), ntohs (message->size),
598                 GNUNET_i2s (&car->target));
599     GSC_CLIENTS_deliver_message (&car->target, message,
600                                  ntohs (message->size),
601                                  GNUNET_CORE_OPTION_SEND_FULL_OUTBOUND);
602     GSC_CLIENTS_deliver_message (&car->target, message,
603                                  sizeof (struct GNUNET_MessageHeader),
604                                  GNUNET_CORE_OPTION_SEND_HDR_OUTBOUND);
605     GSC_SESSIONS_transmit (car,
606                            message,
607                            tc->cork,
608                            tc->priority);
609   }
610   return GNUNET_OK;
611 }
612
613
614 /**
615  * Free client request records.
616  *
617  * @param cls NULL
618  * @param key identity of peer for which this is an active request
619  * @param value the `struct GSC_ClientActiveRequest` to free
620  * @return #GNUNET_YES (continue iteration)
621  */
622 static int
623 destroy_active_client_request (void *cls,
624                                const struct GNUNET_PeerIdentity *key,
625                                void *value)
626 {
627   struct GSC_ClientActiveRequest *car = value;
628
629   GNUNET_assert (GNUNET_YES ==
630                  GNUNET_CONTAINER_multipeermap_remove (car->
631                                                        client_handle->requests,
632                                                        &car->target,
633                                                        car));
634   GSC_SESSIONS_dequeue_request (car);
635   GNUNET_free (car);
636   return GNUNET_YES;
637 }
638
639
640 /**
641  * A client disconnected, clean up.
642  *
643  * @param cls closure
644  * @param client identification of the client
645  */
646 static void
647 handle_client_disconnect (void *cls,
648                           struct GNUNET_SERVER_Client *client)
649 {
650   struct GSC_Client *c;
651
652   if (NULL == client)
653     return;
654   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
655               "Client %p has disconnected from core service.\n",
656               client);
657   c = find_client (client);
658   if (c == NULL)
659     return;                     /* client never sent INIT */
660   GNUNET_CONTAINER_DLL_remove (client_head, client_tail, c);
661   if (c->requests != NULL)
662   {
663     GNUNET_CONTAINER_multipeermap_iterate (c->requests,
664                                            &destroy_active_client_request,
665                                            NULL);
666     GNUNET_CONTAINER_multipeermap_destroy (c->requests);
667   }
668   GNUNET_CONTAINER_multipeermap_destroy (c->connectmap);
669   c->connectmap = NULL;
670   GSC_TYPEMAP_remove (c->types, c->tcnt);
671   GNUNET_free (c);
672
673   /* recalculate 'all_client_options' */
674   all_client_options = 0;
675   for (c = client_head; NULL != c ; c = c->next)
676     all_client_options |= c->options;
677 }
678
679
680 /**
681  * Tell a client that we are ready to receive the message.
682  *
683  * @param car request that is now ready; the responsibility
684  *        for the handle remains shared between CLIENTS
685  *        and SESSIONS after this call.
686  */
687 void
688 GSC_CLIENTS_solicit_request (struct GSC_ClientActiveRequest *car)
689 {
690   struct GSC_Client *c;
691   struct SendMessageReady smr;
692   struct GNUNET_TIME_Relative delay;
693   struct GNUNET_TIME_Relative left;
694
695   c = car->client_handle;
696   if (GNUNET_YES !=
697       GNUNET_CONTAINER_multipeermap_contains (c->connectmap,
698                                               &car->target))
699   {
700     /* connection has gone down since, drop request */
701     GNUNET_assert (0 !=
702                    memcmp (&car->target,
703                            &GSC_my_identity,
704                            sizeof (struct GNUNET_PeerIdentity)));
705     GSC_SESSIONS_dequeue_request (car);
706     GSC_CLIENTS_reject_request (car,
707                                 GNUNET_NO);
708     return;
709   }
710   delay = GNUNET_TIME_absolute_get_duration (car->received_time);
711   left = GNUNET_TIME_absolute_get_duration (car->deadline);
712   if (delay.rel_value_us > GNUNET_CONSTANTS_LATENCY_WARN.rel_value_us)
713     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
714                 "Client waited %s for permission to transmit to `%s'%s (priority %u)\n",
715                 GNUNET_STRINGS_relative_time_to_string (delay,
716                                                         GNUNET_YES),
717                 GNUNET_i2s (&car->target),
718                 (0 == left.rel_value_us)
719                 ? " (past deadline)"
720                 : "",
721                 car->priority);
722   smr.header.size = htons (sizeof (struct SendMessageReady));
723   smr.header.type = htons (GNUNET_MESSAGE_TYPE_CORE_SEND_READY);
724   smr.size = htons (car->msize);
725   smr.smr_id = car->smr_id;
726   smr.peer = car->target;
727   send_to_client (c, &smr.header, GNUNET_NO);
728 }
729
730
731 /**
732  * We will never be ready to transmit the given message in (disconnect
733  * or invalid request).  Frees resources associated with @a car.  We
734  * don't explicitly tell the client, he'll learn with the disconnect
735  * (or violated the protocol).
736  *
737  * @param car request that now permanently failed; the
738  *        responsibility for the handle is now returned
739  *        to CLIENTS (SESSIONS is done with it).
740  * @param drop_client #GNUNET_YES if the client violated the protocol
741  *        and we should thus drop the connection
742  */
743 void
744 GSC_CLIENTS_reject_request (struct GSC_ClientActiveRequest *car,
745                             int drop_client)
746 {
747   GNUNET_assert (GNUNET_YES ==
748                  GNUNET_CONTAINER_multipeermap_remove (car->
749                                                        client_handle->requests,
750                                                        &car->target,
751                                                        car));
752   if (GNUNET_YES == drop_client)
753     GNUNET_SERVER_client_disconnect (car->client_handle->client_handle);
754   GNUNET_free (car);
755 }
756
757
758 /**
759  * Notify a particular client about a change to existing connection to
760  * one of our neighbours (check if the client is interested).  Called
761  * from 'GSC_SESSIONS_notify_client_about_sessions'.
762  *
763  * @param client client to notify
764  * @param neighbour identity of the neighbour that changed status
765  * @param tmap_old previous type map for the neighbour, NULL for connect
766  * @param tmap_new updated type map for the neighbour, NULL for disconnect
767  */
768 void
769 GSC_CLIENTS_notify_client_about_neighbour (struct GSC_Client *client,
770                                            const struct GNUNET_PeerIdentity *neighbour,
771                                            const struct GSC_TypeMap *tmap_old,
772                                            const struct GSC_TypeMap *tmap_new)
773 {
774   struct ConnectNotifyMessage *cnm;
775   size_t size;
776   char buf[GNUNET_SERVER_MAX_MESSAGE_SIZE - 1] GNUNET_ALIGN;
777   struct DisconnectNotifyMessage dcm;
778   int old_match;
779   int new_match;
780
781   old_match = GSC_TYPEMAP_test_match (tmap_old, client->types, client->tcnt);
782   new_match = GSC_TYPEMAP_test_match (tmap_new, client->types, client->tcnt);
783   if (old_match == new_match)
784   {
785     GNUNET_assert (old_match ==
786                    GNUNET_CONTAINER_multipeermap_contains (client->connectmap,
787                                                            neighbour));
788     return;                     /* no change */
789   }
790   if (old_match == GNUNET_NO)
791   {
792     /* send connect */
793     GNUNET_assert (GNUNET_NO ==
794                    GNUNET_CONTAINER_multipeermap_contains (client->connectmap,
795                                                            neighbour));
796     GNUNET_assert (GNUNET_YES ==
797                    GNUNET_CONTAINER_multipeermap_put (client->connectmap,
798                                                       neighbour,
799                                                       NULL,
800                                                       GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
801     size = sizeof (struct ConnectNotifyMessage);
802     cnm = (struct ConnectNotifyMessage *) buf;
803     cnm->header.size = htons (size);
804     cnm->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_NOTIFY_CONNECT);
805     cnm->reserved = htonl (0);
806     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
807                 "Sending `%s' message to client.\n",
808                 "NOTIFY_CONNECT");
809     cnm->peer = *neighbour;
810     send_to_client (client, &cnm->header, GNUNET_NO);
811   }
812   else
813   {
814     /* send disconnect */
815     GNUNET_assert (GNUNET_YES ==
816                    GNUNET_CONTAINER_multipeermap_contains (client->connectmap,
817                                                            neighbour));
818     GNUNET_assert (GNUNET_YES ==
819                    GNUNET_CONTAINER_multipeermap_remove (client->connectmap,
820                                                          neighbour,
821                                                          NULL));
822     dcm.header.size = htons (sizeof (struct DisconnectNotifyMessage));
823     dcm.header.type = htons (GNUNET_MESSAGE_TYPE_CORE_NOTIFY_DISCONNECT);
824     dcm.reserved = htonl (0);
825     dcm.peer = *neighbour;
826     send_to_client (client, &dcm.header, GNUNET_NO);
827   }
828 }
829
830
831 /**
832  * Notify all clients about a change to existing session.
833  * Called from SESSIONS whenever there is a change in sessions
834  * or types processed by the respective peer.
835  *
836  * @param neighbour identity of the neighbour that changed status
837  * @param tmap_old previous type map for the neighbour, NULL for connect
838  * @param tmap_new updated type map for the neighbour, NULL for disconnect
839  */
840 void
841 GSC_CLIENTS_notify_clients_about_neighbour (const struct GNUNET_PeerIdentity *neighbour,
842                                             const struct GSC_TypeMap *tmap_old,
843                                             const struct GSC_TypeMap *tmap_new)
844 {
845   struct GSC_Client *c;
846
847   for (c = client_head; NULL != c; c = c->next)
848     GSC_CLIENTS_notify_client_about_neighbour (c, neighbour,
849                                                tmap_old, tmap_new);
850 }
851
852
853 /**
854  * Deliver P2P message to interested clients.  Caller must have checked
855  * that the sending peer actually lists the given message type as one
856  * of its types.
857  *
858  * @param sender peer who sent us the message
859  * @param msg the message
860  * @param msize number of bytes to transmit
861  * @param options options for checking which clients should
862  *        receive the message
863  */
864 void
865 GSC_CLIENTS_deliver_message (const struct GNUNET_PeerIdentity *sender,
866                              const struct GNUNET_MessageHeader *msg,
867                              uint16_t msize,
868                              uint32_t options)
869 {
870   size_t size = msize + sizeof (struct NotifyTrafficMessage);
871   char buf[size] GNUNET_ALIGN;
872   struct NotifyTrafficMessage *ntm;
873
874   if (size >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
875   {
876     GNUNET_break (0);
877     /* recovery strategy: throw performance data away... */
878     size = msize + sizeof (struct NotifyTrafficMessage);
879   }
880   if (! ( (0 != (all_client_options & options)) ||
881           (0 != (options & GNUNET_CORE_OPTION_SEND_FULL_INBOUND)) ))
882     return; /* no client cares about this message notification */
883   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
884               "Core service passes message from `%s' of type %u to client.\n",
885               GNUNET_i2s (sender),
886               (unsigned int) ntohs (msg->type));
887   GSC_SESSIONS_add_to_typemap (sender, ntohs (msg->type));
888   ntm = (struct NotifyTrafficMessage *) buf;
889   ntm->header.size = htons (size);
890   if (0 != (options & (GNUNET_CORE_OPTION_SEND_FULL_INBOUND | GNUNET_CORE_OPTION_SEND_HDR_INBOUND)))
891     ntm->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_NOTIFY_INBOUND);
892   else
893     ntm->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_NOTIFY_OUTBOUND);
894   ntm->peer = *sender;
895   GNUNET_memcpy (&ntm[1],
896           msg,
897           msize);
898   send_to_all_clients (sender,
899                        &ntm->header,
900                        GNUNET_YES,
901                        options,
902                        ntohs (msg->type));
903 }
904
905
906 /**
907  * Initialize clients subsystem.
908  *
909  * @param server handle to server clients connect to
910  */
911 void
912 GSC_CLIENTS_init (struct GNUNET_SERVER_Handle *server)
913 {
914   static const struct GNUNET_SERVER_MessageHandler handlers[] = {
915     {&handle_client_init, NULL,
916      GNUNET_MESSAGE_TYPE_CORE_INIT, 0},
917     {&GSC_KX_handle_client_monitor_peers, NULL,
918      GNUNET_MESSAGE_TYPE_CORE_MONITOR_PEERS,
919      sizeof (struct GNUNET_MessageHeader)},
920     {&handle_client_send_request, NULL,
921      GNUNET_MESSAGE_TYPE_CORE_SEND_REQUEST,
922      sizeof (struct SendMessageRequest)},
923     {&handle_client_send, NULL,
924      GNUNET_MESSAGE_TYPE_CORE_SEND, 0},
925     {NULL, NULL, 0, 0}
926   };
927
928   /* setup notification */
929   client_mst = GNUNET_SERVER_mst_create (&client_tokenizer_callback, NULL);
930   notifier =
931       GNUNET_SERVER_notification_context_create (server, MAX_NOTIFY_QUEUE);
932   GNUNET_SERVER_disconnect_notify (server,
933                                    &handle_client_disconnect, NULL);
934   GNUNET_SERVER_add_handlers (server, handlers);
935 }
936
937
938 /**
939  * Shutdown clients subsystem.
940  */
941 void
942 GSC_CLIENTS_done ()
943 {
944   struct GSC_Client *c;
945
946   while (NULL != (c = client_head))
947     handle_client_disconnect (NULL, c->client_handle);
948   if (NULL != notifier)
949   {
950     GNUNET_SERVER_notification_context_destroy (notifier);
951     notifier = NULL;
952   }
953   if (NULL != client_mst)
954   {
955     GNUNET_SERVER_mst_destroy (client_mst);
956     client_mst = NULL;
957   }
958 }
959
960 /* end of gnunet-service-core_clients.c */