-fix doxygen warnings
[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_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   struct GNUNET_TIME_Relative overdue;
466
467   msize = ntohs (message->size);
468   if (msize < sizeof (struct SendMessage))
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   overdue = GNUNET_TIME_absolute_get_duration (tc.car->deadline);
505   tc.cork = ntohl (sm->cork);
506   tc.priority = (enum GNUNET_CORE_Priority) ntohl (sm->priority);
507   if (overdue.rel_value_us > GNUNET_CONSTANTS_LATENCY_WARN.rel_value_us)
508     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
509                 "Client waited %s for transmission of %u bytes to `%s'%s, CORE queue is %u entries\n",
510                 GNUNET_STRINGS_relative_time_to_string (delay,
511                                                         GNUNET_YES),
512                 msize,
513                 GNUNET_i2s (&sm->peer),
514                 tc.cork ? "" : " (corked)",
515                 GSC_NEIGHBOURS_get_queue_size (&sm->peer));
516   else
517     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
518                 "Client waited %s for transmission of %u bytes to `%s'%s, CORE queue is %u entries\n",
519                 GNUNET_STRINGS_relative_time_to_string (delay,
520                                                         GNUNET_YES),
521                 msize,
522                 GNUNET_i2s (&sm->peer),
523                 tc.cork ? "" : " (corked)",
524                 GSC_NEIGHBOURS_get_queue_size (&sm->peer));
525
526   GNUNET_assert (GNUNET_YES ==
527                  GNUNET_CONTAINER_multipeermap_remove (c->requests,
528                                                        &sm->peer,
529                                                        tc.car));
530   GNUNET_SERVER_mst_receive (client_mst, &tc,
531                              (const char *) &sm[1],
532                              msize,
533                              GNUNET_YES,
534                              GNUNET_NO);
535   GSC_SESSIONS_dequeue_request (tc.car);
536   GNUNET_free (tc.car);
537   GNUNET_SERVER_receive_done (client,
538                               GNUNET_OK);
539 }
540
541
542 /**
543  * Functions with this signature are called whenever a complete
544  * message is received by the tokenizer.  Used by the 'client_mst' for
545  * dispatching messages from clients to either the SESSION subsystem
546  * or other CLIENT (for loopback).
547  *
548  * @param cls closure
549  * @param client reservation request (`struct GSC_ClientActiveRequest`)
550  * @param message the actual message
551  */
552 static int
553 client_tokenizer_callback (void *cls,
554                            void *client,
555                            const struct GNUNET_MessageHeader *message)
556 {
557   struct TokenizerContext *tc = client;
558   struct GSC_ClientActiveRequest *car = tc->car;
559   char buf[92];
560
561   GNUNET_snprintf (buf, sizeof (buf),
562                    gettext_noop ("# bytes of messages of type %u received"),
563                    (unsigned int) ntohs (message->type));
564   GNUNET_STATISTICS_update (GSC_stats,
565                             buf,
566                             ntohs (message->size),
567                             GNUNET_NO);
568   if (0 ==
569       memcmp (&car->target,
570               &GSC_my_identity,
571               sizeof (struct GNUNET_PeerIdentity)))
572   {
573     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
574                 "Delivering message of type %u to myself\n",
575                 ntohs (message->type));
576     GSC_CLIENTS_deliver_message (&GSC_my_identity, message,
577                                  ntohs (message->size),
578                                  GNUNET_CORE_OPTION_SEND_FULL_OUTBOUND);
579     GSC_CLIENTS_deliver_message (&GSC_my_identity, message,
580                                  sizeof (struct GNUNET_MessageHeader),
581                                  GNUNET_CORE_OPTION_SEND_HDR_OUTBOUND);
582     GSC_CLIENTS_deliver_message (&GSC_my_identity, message,
583                                  ntohs (message->size),
584                                  GNUNET_CORE_OPTION_SEND_FULL_INBOUND);
585     GSC_CLIENTS_deliver_message (&GSC_my_identity, message,
586                                  sizeof (struct GNUNET_MessageHeader),
587                                  GNUNET_CORE_OPTION_SEND_HDR_INBOUND);
588   }
589   else
590   {
591     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
592                 "Delivering message of type %u and size %u to %s\n",
593                 ntohs (message->type), ntohs (message->size),
594                 GNUNET_i2s (&car->target));
595     GSC_CLIENTS_deliver_message (&car->target, message,
596                                  ntohs (message->size),
597                                  GNUNET_CORE_OPTION_SEND_FULL_OUTBOUND);
598     GSC_CLIENTS_deliver_message (&car->target, message,
599                                  sizeof (struct GNUNET_MessageHeader),
600                                  GNUNET_CORE_OPTION_SEND_HDR_OUTBOUND);
601     GSC_SESSIONS_transmit (car,
602                            message,
603                            tc->cork,
604                            tc->priority);
605   }
606   return GNUNET_OK;
607 }
608
609
610 /**
611  * Free client request records.
612  *
613  * @param cls NULL
614  * @param key identity of peer for which this is an active request
615  * @param value the `struct GSC_ClientActiveRequest` to free
616  * @return #GNUNET_YES (continue iteration)
617  */
618 static int
619 destroy_active_client_request (void *cls,
620                                const struct GNUNET_PeerIdentity *key,
621                                void *value)
622 {
623   struct GSC_ClientActiveRequest *car = value;
624
625   GNUNET_assert (GNUNET_YES ==
626                  GNUNET_CONTAINER_multipeermap_remove (car->
627                                                        client_handle->requests,
628                                                        &car->target,
629                                                        car));
630   GSC_SESSIONS_dequeue_request (car);
631   GNUNET_free (car);
632   return GNUNET_YES;
633 }
634
635
636 /**
637  * A client disconnected, clean up.
638  *
639  * @param cls closure
640  * @param client identification of the client
641  */
642 static void
643 handle_client_disconnect (void *cls,
644                           struct GNUNET_SERVER_Client *client)
645 {
646   struct GSC_Client *c;
647
648   if (NULL == client)
649     return;
650   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
651               "Client %p has disconnected from core service.\n",
652               client);
653   c = find_client (client);
654   if (c == NULL)
655     return;                     /* client never sent INIT */
656   GNUNET_CONTAINER_DLL_remove (client_head, client_tail, c);
657   if (c->requests != NULL)
658   {
659     GNUNET_CONTAINER_multipeermap_iterate (c->requests,
660                                            &destroy_active_client_request,
661                                            NULL);
662     GNUNET_CONTAINER_multipeermap_destroy (c->requests);
663   }
664   GNUNET_CONTAINER_multipeermap_destroy (c->connectmap);
665   c->connectmap = NULL;
666   GSC_TYPEMAP_remove (c->types, c->tcnt);
667   GNUNET_free (c);
668
669   /* recalculate 'all_client_options' */
670   all_client_options = 0;
671   for (c = client_head; NULL != c ; c = c->next)
672     all_client_options |= c->options;
673 }
674
675
676 /**
677  * Tell a client that we are ready to receive the message.
678  *
679  * @param car request that is now ready; the responsibility
680  *        for the handle remains shared between CLIENTS
681  *        and SESSIONS after this call.
682  */
683 void
684 GSC_CLIENTS_solicit_request (struct GSC_ClientActiveRequest *car)
685 {
686   struct GSC_Client *c;
687   struct SendMessageReady smr;
688   struct GNUNET_TIME_Relative delay;
689   struct GNUNET_TIME_Relative left;
690
691   c = car->client_handle;
692   if (GNUNET_YES !=
693       GNUNET_CONTAINER_multipeermap_contains (c->connectmap,
694                                               &car->target))
695   {
696     /* connection has gone down since, drop request */
697     GNUNET_assert (0 !=
698                    memcmp (&car->target,
699                            &GSC_my_identity,
700                            sizeof (struct GNUNET_PeerIdentity)));
701     GSC_SESSIONS_dequeue_request (car);
702     GSC_CLIENTS_reject_request (car,
703                                 GNUNET_NO);
704     return;
705   }
706   delay = GNUNET_TIME_absolute_get_duration (car->received_time);
707   left = GNUNET_TIME_absolute_get_duration (car->deadline);
708   if (left.rel_value_us > GNUNET_CONSTANTS_LATENCY_WARN.rel_value_us)
709     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
710                 "Client waited %s for permission to transmit to `%s'%s (priority %u)\n",
711                 GNUNET_STRINGS_relative_time_to_string (delay,
712                                                         GNUNET_YES),
713                 GNUNET_i2s (&car->target),
714                 (0 == left.rel_value_us)
715                 ? " (past deadline)"
716                 : "",
717                 car->priority);
718   smr.header.size = htons (sizeof (struct SendMessageReady));
719   smr.header.type = htons (GNUNET_MESSAGE_TYPE_CORE_SEND_READY);
720   smr.size = htons (car->msize);
721   smr.smr_id = car->smr_id;
722   smr.peer = car->target;
723   send_to_client (c, &smr.header, GNUNET_NO);
724 }
725
726
727 /**
728  * We will never be ready to transmit the given message in (disconnect
729  * or invalid request).  Frees resources associated with @a car.  We
730  * don't explicitly tell the client, he'll learn with the disconnect
731  * (or violated the protocol).
732  *
733  * @param car request that now permanently failed; the
734  *        responsibility for the handle is now returned
735  *        to CLIENTS (SESSIONS is done with it).
736  * @param drop_client #GNUNET_YES if the client violated the protocol
737  *        and we should thus drop the connection
738  */
739 void
740 GSC_CLIENTS_reject_request (struct GSC_ClientActiveRequest *car,
741                             int drop_client)
742 {
743   GNUNET_assert (GNUNET_YES ==
744                  GNUNET_CONTAINER_multipeermap_remove (car->
745                                                        client_handle->requests,
746                                                        &car->target,
747                                                        car));
748   if (GNUNET_YES == drop_client)
749     GNUNET_SERVER_client_disconnect (car->client_handle->client_handle);
750   GNUNET_free (car);
751 }
752
753
754 /**
755  * Notify a particular client about a change to existing connection to
756  * one of our neighbours (check if the client is interested).  Called
757  * from 'GSC_SESSIONS_notify_client_about_sessions'.
758  *
759  * @param client client to notify
760  * @param neighbour identity of the neighbour that changed status
761  * @param tmap_old previous type map for the neighbour, NULL for connect
762  * @param tmap_new updated type map for the neighbour, NULL for disconnect
763  */
764 void
765 GSC_CLIENTS_notify_client_about_neighbour (struct GSC_Client *client,
766                                            const struct GNUNET_PeerIdentity *neighbour,
767                                            const struct GSC_TypeMap *tmap_old,
768                                            const struct GSC_TypeMap *tmap_new)
769 {
770   struct ConnectNotifyMessage *cnm;
771   size_t size;
772   char buf[GNUNET_SERVER_MAX_MESSAGE_SIZE - 1] GNUNET_ALIGN;
773   struct DisconnectNotifyMessage dcm;
774   int old_match;
775   int new_match;
776
777   old_match = GSC_TYPEMAP_test_match (tmap_old, client->types, client->tcnt);
778   new_match = GSC_TYPEMAP_test_match (tmap_new, client->types, client->tcnt);
779   if (old_match == new_match)
780   {
781     GNUNET_assert (old_match ==
782                    GNUNET_CONTAINER_multipeermap_contains (client->connectmap,
783                                                            neighbour));
784     return;                     /* no change */
785   }
786   if (old_match == GNUNET_NO)
787   {
788     /* send connect */
789     GNUNET_assert (GNUNET_NO ==
790                    GNUNET_CONTAINER_multipeermap_contains (client->connectmap,
791                                                            neighbour));
792     GNUNET_assert (GNUNET_YES ==
793                    GNUNET_CONTAINER_multipeermap_put (client->connectmap,
794                                                       neighbour,
795                                                       NULL,
796                                                       GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
797     size = sizeof (struct ConnectNotifyMessage);
798     cnm = (struct ConnectNotifyMessage *) buf;
799     cnm->header.size = htons (size);
800     cnm->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_NOTIFY_CONNECT);
801     cnm->reserved = htonl (0);
802     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
803                 "Sending `%s' message to client.\n",
804                 "NOTIFY_CONNECT");
805     cnm->peer = *neighbour;
806     send_to_client (client, &cnm->header, GNUNET_NO);
807   }
808   else
809   {
810     /* send disconnect */
811     GNUNET_assert (GNUNET_YES ==
812                    GNUNET_CONTAINER_multipeermap_contains (client->connectmap,
813                                                            neighbour));
814     GNUNET_assert (GNUNET_YES ==
815                    GNUNET_CONTAINER_multipeermap_remove (client->connectmap,
816                                                          neighbour,
817                                                          NULL));
818     dcm.header.size = htons (sizeof (struct DisconnectNotifyMessage));
819     dcm.header.type = htons (GNUNET_MESSAGE_TYPE_CORE_NOTIFY_DISCONNECT);
820     dcm.reserved = htonl (0);
821     dcm.peer = *neighbour;
822     send_to_client (client, &dcm.header, GNUNET_NO);
823   }
824 }
825
826
827 /**
828  * Notify all clients about a change to existing session.
829  * Called from SESSIONS whenever there is a change in sessions
830  * or types processed by the respective peer.
831  *
832  * @param neighbour identity of the neighbour that changed status
833  * @param tmap_old previous type map for the neighbour, NULL for connect
834  * @param tmap_new updated type map for the neighbour, NULL for disconnect
835  */
836 void
837 GSC_CLIENTS_notify_clients_about_neighbour (const struct GNUNET_PeerIdentity *neighbour,
838                                             const struct GSC_TypeMap *tmap_old,
839                                             const struct GSC_TypeMap *tmap_new)
840 {
841   struct GSC_Client *c;
842
843   for (c = client_head; NULL != c; c = c->next)
844     GSC_CLIENTS_notify_client_about_neighbour (c, neighbour,
845                                                tmap_old, tmap_new);
846 }
847
848
849 /**
850  * Deliver P2P message to interested clients.  Caller must have checked
851  * that the sending peer actually lists the given message type as one
852  * of its types.
853  *
854  * @param sender peer who sent us the message
855  * @param msg the message
856  * @param msize number of bytes to transmit
857  * @param options options for checking which clients should
858  *        receive the message
859  */
860 void
861 GSC_CLIENTS_deliver_message (const struct GNUNET_PeerIdentity *sender,
862                              const struct GNUNET_MessageHeader *msg,
863                              uint16_t msize,
864                              uint32_t options)
865 {
866   size_t size = msize + sizeof (struct NotifyTrafficMessage);
867   char buf[size] GNUNET_ALIGN;
868   struct NotifyTrafficMessage *ntm;
869
870   if (size >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
871   {
872     GNUNET_break (0);
873     /* recovery strategy: throw performance data away... */
874     size = msize + sizeof (struct NotifyTrafficMessage);
875   }
876   if (! ( (0 != (all_client_options & options)) ||
877           (0 != (options & GNUNET_CORE_OPTION_SEND_FULL_INBOUND)) ))
878     return; /* no client cares about this message notification */
879   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
880               "Core service passes message from `%4s' of type %u to client.\n",
881               GNUNET_i2s (sender),
882               (unsigned int) ntohs (msg->type));
883   GSC_SESSIONS_add_to_typemap (sender, ntohs (msg->type));
884   ntm = (struct NotifyTrafficMessage *) buf;
885   ntm->header.size = htons (size);
886   if (0 != (options & (GNUNET_CORE_OPTION_SEND_FULL_INBOUND | GNUNET_CORE_OPTION_SEND_HDR_INBOUND)))
887     ntm->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_NOTIFY_INBOUND);
888   else
889     ntm->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_NOTIFY_OUTBOUND);
890   ntm->peer = *sender;
891   memcpy (&ntm[1],
892           msg,
893           msize);
894   send_to_all_clients (sender,
895                        &ntm->header,
896                        GNUNET_YES,
897                        options,
898                        ntohs (msg->type));
899 }
900
901
902 /**
903  * Initialize clients subsystem.
904  *
905  * @param server handle to server clients connect to
906  */
907 void
908 GSC_CLIENTS_init (struct GNUNET_SERVER_Handle *server)
909 {
910   static const struct GNUNET_SERVER_MessageHandler handlers[] = {
911     {&handle_client_init, NULL,
912      GNUNET_MESSAGE_TYPE_CORE_INIT, 0},
913     {&GSC_KX_handle_client_monitor_peers, NULL,
914      GNUNET_MESSAGE_TYPE_CORE_MONITOR_PEERS,
915      sizeof (struct GNUNET_MessageHeader)},
916     {&handle_client_send_request, NULL,
917      GNUNET_MESSAGE_TYPE_CORE_SEND_REQUEST,
918      sizeof (struct SendMessageRequest)},
919     {&handle_client_send, NULL,
920      GNUNET_MESSAGE_TYPE_CORE_SEND, 0},
921     {NULL, NULL, 0, 0}
922   };
923
924   /* setup notification */
925   client_mst = GNUNET_SERVER_mst_create (&client_tokenizer_callback, NULL);
926   notifier =
927       GNUNET_SERVER_notification_context_create (server, MAX_NOTIFY_QUEUE);
928   GNUNET_SERVER_disconnect_notify (server,
929                                    &handle_client_disconnect, NULL);
930   GNUNET_SERVER_add_handlers (server, handlers);
931 }
932
933
934 /**
935  * Shutdown clients subsystem.
936  */
937 void
938 GSC_CLIENTS_done ()
939 {
940   struct GSC_Client *c;
941
942   while (NULL != (c = client_head))
943     handle_client_disconnect (NULL, c->client_handle);
944   if (NULL != notifier)
945   {
946     GNUNET_SERVER_notification_context_destroy (notifier);
947     notifier = NULL;
948   }
949   if (NULL != client_mst)
950   {
951     GNUNET_SERVER_mst_destroy (client_mst);
952     client_mst = NULL;
953   }
954 }
955
956 /* end of gnunet-service-core_clients.c */