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