misc minor fixes
[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_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 && c->options != 0)
203     return GNUNET_YES;          /* peer without handlers and inbound/outbond
204                                    callbacks matches ALL */
205   for (i = 0; i < c->tcnt; i++)
206     if (type == c->types[i])
207       return GNUNET_YES;
208   return GNUNET_NO;
209 }
210
211
212 /**
213  * Send a message to all of our current clients that have the right
214  * options set.
215  *
216  * @param partner origin (or destination) of the message (used to check that this peer is
217  *        known to be connected to the respective client)
218  * @param msg message to multicast
219  * @param can_drop can this message be discarded if the queue is too long
220  * @param options mask to use
221  * @param type type of the embedded message, 0 for none
222  */
223 static void
224 send_to_all_clients (const struct GNUNET_PeerIdentity *partner,
225                      const struct GNUNET_MessageHeader *msg,
226                      int can_drop,
227                      uint32_t options,
228                      uint16_t type)
229 {
230   struct GSC_Client *c;
231   int tm;
232
233   for (c = client_head; NULL != c; c = c->next)
234   {
235     tm = type_match (type, c);
236     if (!  ( (0 != (c->options & options)) ||
237              ( (0 != (options & GNUNET_CORE_OPTION_SEND_FULL_INBOUND)) &&
238                (GNUNET_YES == tm) ) ) )
239       continue;  /* neither options nor type match permit the message */
240     if ( (0 != (options & GNUNET_CORE_OPTION_SEND_HDR_INBOUND)) &&
241          ( (0 != (c->options & GNUNET_CORE_OPTION_SEND_FULL_INBOUND)) ||
242            (GNUNET_YES == tm) ) )
243       continue;
244     if ( (0 != (options & GNUNET_CORE_OPTION_SEND_HDR_OUTBOUND)) &&
245          (0 != (c->options & GNUNET_CORE_OPTION_SEND_FULL_OUTBOUND)) )
246       continue;
247     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
248                 "Sending %u message with %u bytes to client interested in messages of type %u.\n",
249                 options,
250                 ntohs (msg->size),
251                 (unsigned int) type);
252     GNUNET_assert ( (0 == (c->options & GNUNET_CORE_OPTION_SEND_FULL_INBOUND)) ||
253                     (GNUNET_YES != tm) ||
254                     (GNUNET_YES ==
255                      GNUNET_CONTAINER_multipeermap_contains (c->connectmap,
256                                                              partner)) );
257     send_to_client (c, msg, can_drop);
258   }
259 }
260
261
262 /**
263  * Handle #GNUNET_MESSAGE_TYPE_CORE_INIT request.
264  *
265  * @param cls unused
266  * @param client new client that sent #GNUNET_MESSAGE_TYPE_CORE_INIT
267  * @param message the `struct InitMessage` (presumably)
268  */
269 static void
270 handle_client_init (void *cls,
271                     struct GNUNET_SERVER_Client *client,
272                     const struct GNUNET_MessageHeader *message)
273 {
274   const struct InitMessage *im;
275   struct InitReplyMessage irm;
276   struct GSC_Client *c;
277   uint16_t msize;
278   const uint16_t *types;
279   uint16_t *wtypes;
280   unsigned int i;
281
282   /* check that we don't have an entry already */
283   c = find_client (client);
284   if (NULL != c)
285   {
286     GNUNET_break (0);
287     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
288     return;
289   }
290   msize = ntohs (message->size);
291   if (msize < sizeof (struct InitMessage))
292   {
293     GNUNET_break (0);
294     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
295     return;
296   }
297   GNUNET_SERVER_notification_context_add (notifier, client);
298   im = (const struct InitMessage *) message;
299   types = (const uint16_t *) &im[1];
300   msize -= sizeof (struct InitMessage);
301   c = GNUNET_malloc (sizeof (struct GSC_Client) + msize);
302   c->client_handle = client;
303   c->tcnt = msize / sizeof (uint16_t);
304   c->options = ntohl (im->options);
305   all_client_options |= c->options;
306   c->types = (const uint16_t *) &c[1];
307   c->connectmap = GNUNET_CONTAINER_multipeermap_create (16, GNUNET_NO);
308   GNUNET_assert (GNUNET_YES ==
309                  GNUNET_CONTAINER_multipeermap_put (c->connectmap,
310                                                     &GSC_my_identity,
311                                                     NULL,
312                                                     GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
313   wtypes = (uint16_t *) & c[1];
314   for (i = 0; i < c->tcnt; i++)
315     wtypes[i] = ntohs (types[i]);
316   GSC_TYPEMAP_add (wtypes, c->tcnt);
317   GNUNET_CONTAINER_DLL_insert (client_head, client_tail, c);
318   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
319               "Client connecting to core service is interested in %u message types\n",
320               (unsigned int) c->tcnt);
321   /* send init reply message */
322   irm.header.size = htons (sizeof (struct InitReplyMessage));
323   irm.header.type = htons (GNUNET_MESSAGE_TYPE_CORE_INIT_REPLY);
324   irm.reserved = htonl (0);
325   irm.my_identity = GSC_my_identity;
326   send_to_client (c, &irm.header, GNUNET_NO);
327   GSC_SESSIONS_notify_client_about_sessions (c);
328   GNUNET_SERVER_receive_done (client, GNUNET_OK);
329 }
330
331
332 /**
333  * Handle #GNUNET_MESSAGE_TYPE_CORE_SEND_REQUEST message.
334  *
335  * @param cls unused
336  * @param client new client that sent a #GNUNET_MESSAGE_TYPE_CORE_SEND_REQUEST
337  * @param message the `struct SendMessageRequest` (presumably)
338  */
339 static void
340 handle_client_send_request (void *cls,
341                             struct GNUNET_SERVER_Client *client,
342                             const struct GNUNET_MessageHeader *message)
343 {
344   const struct SendMessageRequest *req;
345   struct GSC_Client *c;
346   struct GSC_ClientActiveRequest *car;
347   int is_loopback;
348
349   req = (const struct SendMessageRequest *) message;
350   c = find_client (client);
351   if (NULL == c)
352   {
353     /* client did not send INIT first! */
354     GNUNET_break (0);
355     GNUNET_SERVER_receive_done (client,
356                                 GNUNET_SYSERR);
357     return;
358   }
359   if (NULL == c->requests)
360     c->requests = GNUNET_CONTAINER_multipeermap_create (16,
361                                                         GNUNET_NO);
362   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
363               "Client asked for transmission to `%s'\n",
364               GNUNET_i2s (&req->peer));
365   is_loopback =
366       (0 ==
367        memcmp (&req->peer,
368                &GSC_my_identity,
369                sizeof (struct GNUNET_PeerIdentity)));
370   if ((! is_loopback) &&
371       (GNUNET_YES !=
372        GNUNET_CONTAINER_multipeermap_contains (c->connectmap,
373                                                &req->peer)))
374   {
375     /* neighbour must have disconnected since request was issued,
376      * ignore (client will realize it once it processes the
377      * disconnect notification) */
378     GNUNET_STATISTICS_update (GSC_stats,
379                               gettext_noop
380                               ("# send requests dropped (disconnected)"), 1,
381                               GNUNET_NO);
382     GNUNET_SERVER_receive_done (client,
383                                 GNUNET_OK);
384     return;
385   }
386
387   car = GNUNET_CONTAINER_multipeermap_get (c->requests,
388                                            &req->peer);
389   if (NULL == car)
390   {
391     /* create new entry */
392     car = GNUNET_new (struct GSC_ClientActiveRequest);
393     GNUNET_assert (GNUNET_OK ==
394                    GNUNET_CONTAINER_multipeermap_put (c->requests,
395                                                       &req->peer,
396                                                       car,
397                                                       GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST));
398     car->client_handle = c;
399   }
400   else
401   {
402     /* dequeue and recycle memory from pending request, there can only
403        be at most one per client and peer */
404     GNUNET_STATISTICS_update (GSC_stats,
405                               gettext_noop
406                               ("# dequeuing CAR (duplicate request)"), 1,
407                               GNUNET_NO);
408     GSC_SESSIONS_dequeue_request (car);
409     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
410                 "Transmission request to `%s' was a duplicate!\n",
411                 GNUNET_i2s (&req->peer));
412   }
413   car->target = req->peer;
414   car->received_time = GNUNET_TIME_absolute_get ();
415   car->deadline = GNUNET_TIME_absolute_ntoh (req->deadline);
416   car->priority = (enum GNUNET_CORE_Priority) ntohl (req->priority);
417   car->msize = ntohs (req->size);
418   car->smr_id = req->smr_id;
419   car->was_solicited = GNUNET_NO;
420   if (is_loopback)
421   {
422     /* loopback, satisfy immediately */
423     GSC_CLIENTS_solicit_request (car);
424     GNUNET_SERVER_receive_done (client, GNUNET_OK);
425     return;
426   }
427   GSC_SESSIONS_queue_request (car);
428   GNUNET_SERVER_receive_done (client, GNUNET_OK);
429 }
430
431
432 /**
433  * Closure for the #client_tokenizer_callback().
434  */
435 struct TokenizerContext
436 {
437
438   /**
439    * Active request handle for the message.
440    */
441   struct GSC_ClientActiveRequest *car;
442
443   /**
444    * How important is this message.
445    */
446   enum GNUNET_CORE_Priority priority;
447
448   /**
449    * Is corking allowed (set only once we have the real message).
450    */
451   int cork;
452
453 };
454
455
456 /**
457  * Handle #GNUNET_MESSAGE_TYPE_CORE_SEND request.
458  *
459  * @param cls unused
460  * @param client the client issuing the request
461  * @param message the `struct SendMessage`
462  */
463 static void
464 handle_client_send (void *cls,
465                     struct GNUNET_SERVER_Client *client,
466                     const struct GNUNET_MessageHeader *message)
467 {
468   const struct SendMessage *sm;
469   struct GSC_Client *c;
470   struct TokenizerContext tc;
471   uint16_t msize;
472   struct GNUNET_TIME_Relative delay;
473   struct GNUNET_TIME_Relative overdue;
474
475   msize = ntohs (message->size);
476   if (msize < sizeof (struct SendMessage))
477   {
478     GNUNET_break (0);
479     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
480     return;
481   }
482   sm = (const struct SendMessage *) message;
483   msize -= sizeof (struct SendMessage);
484   GNUNET_break (0 == ntohl (sm->reserved));
485   c = find_client (client);
486   if (NULL == c)
487   {
488     /* client did not send INIT first! */
489     GNUNET_break (0);
490     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
491     return;
492   }
493   tc.car
494     = GNUNET_CONTAINER_multipeermap_get (c->requests,
495                                          &sm->peer);
496   if (NULL == tc.car)
497   {
498     /* Must have been that we first approved the request, then got disconnected
499      * (which triggered removal of the 'car') and now the client gives us a message
500      * just *before* the client learns about the disconnect.  Theoretically, we
501      * might also now be *again* connected.  So this can happen (but should be
502      * rare).  If it does happen, the message is discarded. */
503     GNUNET_STATISTICS_update (GSC_stats,
504                               gettext_noop
505                               ("# messages discarded (session disconnected)"),
506                               1, GNUNET_NO);
507     GNUNET_SERVER_receive_done (client,
508                                 GNUNET_OK);
509     return;
510   }
511   delay = GNUNET_TIME_absolute_get_duration (tc.car->received_time);
512   overdue = GNUNET_TIME_absolute_get_duration (tc.car->deadline);
513   tc.cork = ntohl (sm->cork);
514   tc.priority = (enum GNUNET_CORE_Priority) ntohl (sm->priority);
515   if (overdue.rel_value_us > GNUNET_CONSTANTS_LATENCY_WARN.rel_value_us)
516     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
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   else
524     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
525                 "Client waited %s for transmission of %u bytes to `%s'%s\n",
526                 GNUNET_STRINGS_relative_time_to_string (delay,
527                                                         GNUNET_YES),
528                 msize,
529                 GNUNET_i2s (&sm->peer),
530                 tc.cork ? "" : " (corked)");
531
532   GNUNET_assert (GNUNET_YES ==
533                  GNUNET_CONTAINER_multipeermap_remove (c->requests,
534                                                        &sm->peer,
535                                                        tc.car));
536   GNUNET_SERVER_mst_receive (client_mst, &tc,
537                              (const char *) &sm[1],
538                              msize,
539                              GNUNET_YES,
540                              GNUNET_NO);
541   GSC_SESSIONS_dequeue_request (tc.car);
542   GNUNET_free (tc.car);
543   GNUNET_SERVER_receive_done (client,
544                               GNUNET_OK);
545 }
546
547
548 /**
549  * Functions with this signature are called whenever a complete
550  * message is received by the tokenizer.  Used by the 'client_mst' for
551  * dispatching messages from clients to either the SESSION subsystem
552  * or other CLIENT (for loopback).
553  *
554  * @param cls closure
555  * @param client reservation request (`struct GSC_ClientActiveRequest`)
556  * @param message the actual message
557  */
558 static int
559 client_tokenizer_callback (void *cls,
560                            void *client,
561                            const struct GNUNET_MessageHeader *message)
562 {
563   struct TokenizerContext *tc = client;
564   struct GSC_ClientActiveRequest *car = tc->car;
565   char buf[92];
566
567   GNUNET_snprintf (buf, sizeof (buf),
568                    gettext_noop ("# bytes of messages of type %u received"),
569                    (unsigned int) ntohs (message->type));
570   GNUNET_STATISTICS_update (GSC_stats,
571                             buf,
572                             ntohs (message->size),
573                             GNUNET_NO);
574   if (0 ==
575       memcmp (&car->target,
576               &GSC_my_identity,
577               sizeof (struct GNUNET_PeerIdentity)))
578   {
579     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
580                 "Delivering message of type %u to myself\n",
581                 ntohs (message->type));
582     GSC_CLIENTS_deliver_message (&GSC_my_identity, message,
583                                  ntohs (message->size),
584                                  GNUNET_CORE_OPTION_SEND_FULL_OUTBOUND);
585     GSC_CLIENTS_deliver_message (&GSC_my_identity, message,
586                                  sizeof (struct GNUNET_MessageHeader),
587                                  GNUNET_CORE_OPTION_SEND_HDR_OUTBOUND);
588     GSC_CLIENTS_deliver_message (&GSC_my_identity, message,
589                                  ntohs (message->size),
590                                  GNUNET_CORE_OPTION_SEND_FULL_INBOUND);
591     GSC_CLIENTS_deliver_message (&GSC_my_identity, message,
592                                  sizeof (struct GNUNET_MessageHeader),
593                                  GNUNET_CORE_OPTION_SEND_HDR_INBOUND);
594   }
595   else
596   {
597     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
598                 "Delivering message of type %u and size %u to %s\n",
599                 ntohs (message->type), ntohs (message->size),
600                 GNUNET_i2s (&car->target));
601     GSC_CLIENTS_deliver_message (&car->target, message,
602                                  ntohs (message->size),
603                                  GNUNET_CORE_OPTION_SEND_FULL_OUTBOUND);
604     GSC_CLIENTS_deliver_message (&car->target, message,
605                                  sizeof (struct GNUNET_MessageHeader),
606                                  GNUNET_CORE_OPTION_SEND_HDR_OUTBOUND);
607     GSC_SESSIONS_transmit (car,
608                            message,
609                            tc->cork,
610                            tc->priority);
611   }
612   return GNUNET_OK;
613 }
614
615
616 /**
617  * Free client request records.
618  *
619  * @param cls NULL
620  * @param key identity of peer for which this is an active request
621  * @param value the `struct GSC_ClientActiveRequest` to free
622  * @return #GNUNET_YES (continue iteration)
623  */
624 static int
625 destroy_active_client_request (void *cls,
626                                const struct GNUNET_PeerIdentity *key,
627                                void *value)
628 {
629   struct GSC_ClientActiveRequest *car = value;
630
631   GNUNET_assert (GNUNET_YES ==
632                  GNUNET_CONTAINER_multipeermap_remove (car->
633                                                        client_handle->requests,
634                                                        &car->target,
635                                                        car));
636   GSC_SESSIONS_dequeue_request (car);
637   GNUNET_free (car);
638   return GNUNET_YES;
639 }
640
641
642 /**
643  * A client disconnected, clean up.
644  *
645  * @param cls closure
646  * @param client identification of the client
647  */
648 static void
649 handle_client_disconnect (void *cls,
650                           struct GNUNET_SERVER_Client *client)
651 {
652   struct GSC_Client *c;
653
654   if (NULL == client)
655     return;
656   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
657               "Client %p has disconnected from core service.\n",
658               client);
659   c = find_client (client);
660   if (c == NULL)
661     return;                     /* client never sent INIT */
662   GNUNET_CONTAINER_DLL_remove (client_head, client_tail, c);
663   if (c->requests != NULL)
664   {
665     GNUNET_CONTAINER_multipeermap_iterate (c->requests,
666                                            &destroy_active_client_request,
667                                            NULL);
668     GNUNET_CONTAINER_multipeermap_destroy (c->requests);
669   }
670   GNUNET_CONTAINER_multipeermap_destroy (c->connectmap);
671   c->connectmap = NULL;
672   GSC_TYPEMAP_remove (c->types, c->tcnt);
673   GNUNET_free (c);
674
675   /* recalculate 'all_client_options' */
676   all_client_options = 0;
677   for (c = client_head; NULL != c ; c = c->next)
678     all_client_options |= c->options;
679 }
680
681
682 /**
683  * Tell a client that we are ready to receive the message.
684  *
685  * @param car request that is now ready; the responsibility
686  *        for the handle remains shared between CLIENTS
687  *        and SESSIONS after this call.
688  */
689 void
690 GSC_CLIENTS_solicit_request (struct GSC_ClientActiveRequest *car)
691 {
692   struct GSC_Client *c;
693   struct SendMessageReady smr;
694   struct GNUNET_TIME_Relative delay;
695   struct GNUNET_TIME_Relative left;
696
697   c = car->client_handle;
698   if (GNUNET_YES !=
699       GNUNET_CONTAINER_multipeermap_contains (c->connectmap,
700                                               &car->target))
701   {
702     /* connection has gone down since, drop request */
703     GNUNET_assert (0 !=
704                    memcmp (&car->target,
705                            &GSC_my_identity,
706                            sizeof (struct GNUNET_PeerIdentity)));
707     GSC_SESSIONS_dequeue_request (car);
708     GSC_CLIENTS_reject_request (car,
709                                 GNUNET_NO);
710     return;
711   }
712   delay = GNUNET_TIME_absolute_get_duration (car->received_time);
713   left = GNUNET_TIME_absolute_get_duration (car->deadline);
714   if (left.rel_value_us > GNUNET_CONSTANTS_LATENCY_WARN.rel_value_us)
715     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
716                 "Client waited %s for permission to transmit to `%s'%s (priority %u)\n",
717                 GNUNET_STRINGS_relative_time_to_string (delay,
718                                                         GNUNET_YES),
719                 GNUNET_i2s (&car->target),
720                 (0 == left.rel_value_us)
721                 ? " (past deadline)"
722                 : "",
723                 car->priority);
724   smr.header.size = htons (sizeof (struct SendMessageReady));
725   smr.header.type = htons (GNUNET_MESSAGE_TYPE_CORE_SEND_READY);
726   smr.size = htons (car->msize);
727   smr.smr_id = car->smr_id;
728   smr.peer = car->target;
729   send_to_client (c, &smr.header, GNUNET_NO);
730 }
731
732
733 /**
734  * We will never be ready to transmit the given message in (disconnect
735  * or invalid request).  Frees resources associated with @a car.  We
736  * don't explicitly tell the client, he'll learn with the disconnect
737  * (or violated the protocol).
738  *
739  * @param car request that now permanently failed; the
740  *        responsibility for the handle is now returned
741  *        to CLIENTS (SESSIONS is done with it).
742  * @param drop_client #GNUNET_YES if the client violated the protocol
743  *        and we should thus drop the connection
744  */
745 void
746 GSC_CLIENTS_reject_request (struct GSC_ClientActiveRequest *car,
747                             int drop_client)
748 {
749   GNUNET_assert (GNUNET_YES ==
750                  GNUNET_CONTAINER_multipeermap_remove (car->
751                                                        client_handle->requests,
752                                                        &car->target,
753                                                        car));
754   if (GNUNET_YES == drop_client)
755     GNUNET_SERVER_client_disconnect (car->client_handle->client_handle);
756   GNUNET_free (car);
757 }
758
759
760 /**
761  * Notify a particular client about a change to existing connection to
762  * one of our neighbours (check if the client is interested).  Called
763  * from 'GSC_SESSIONS_notify_client_about_sessions'.
764  *
765  * @param client client to notify
766  * @param neighbour identity of the neighbour that changed status
767  * @param tmap_old previous type map for the neighbour, NULL for connect
768  * @param tmap_new updated type map for the neighbour, NULL for disconnect
769  */
770 void
771 GSC_CLIENTS_notify_client_about_neighbour (struct GSC_Client *client,
772                                            const struct GNUNET_PeerIdentity *neighbour,
773                                            const struct GSC_TypeMap *tmap_old,
774                                            const struct GSC_TypeMap *tmap_new)
775 {
776   struct ConnectNotifyMessage *cnm;
777   size_t size;
778   char buf[GNUNET_SERVER_MAX_MESSAGE_SIZE - 1] GNUNET_ALIGN;
779   struct DisconnectNotifyMessage dcm;
780   int old_match;
781   int new_match;
782
783   old_match = GSC_TYPEMAP_test_match (tmap_old, client->types, client->tcnt);
784   new_match = GSC_TYPEMAP_test_match (tmap_new, client->types, client->tcnt);
785   if (old_match == new_match)
786   {
787     GNUNET_assert (old_match ==
788                    GNUNET_CONTAINER_multipeermap_contains (client->connectmap,
789                                                            neighbour));
790     return;                     /* no change */
791   }
792   if (old_match == GNUNET_NO)
793   {
794     /* send connect */
795     GNUNET_assert (GNUNET_NO ==
796                    GNUNET_CONTAINER_multipeermap_contains (client->connectmap,
797                                                            neighbour));
798     GNUNET_assert (GNUNET_YES ==
799                    GNUNET_CONTAINER_multipeermap_put (client->connectmap,
800                                                       neighbour,
801                                                       NULL,
802                                                       GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
803     size = sizeof (struct ConnectNotifyMessage);
804     cnm = (struct ConnectNotifyMessage *) buf;
805     cnm->header.size = htons (size);
806     cnm->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_NOTIFY_CONNECT);
807     cnm->reserved = htonl (0);
808     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
809                 "Sending `%s' message to client.\n",
810                 "NOTIFY_CONNECT");
811     cnm->peer = *neighbour;
812     send_to_client (client, &cnm->header, GNUNET_NO);
813   }
814   else
815   {
816     /* send disconnect */
817     GNUNET_assert (GNUNET_YES ==
818                    GNUNET_CONTAINER_multipeermap_contains (client->connectmap,
819                                                            neighbour));
820     GNUNET_assert (GNUNET_YES ==
821                    GNUNET_CONTAINER_multipeermap_remove (client->connectmap,
822                                                          neighbour,
823                                                          NULL));
824     dcm.header.size = htons (sizeof (struct DisconnectNotifyMessage));
825     dcm.header.type = htons (GNUNET_MESSAGE_TYPE_CORE_NOTIFY_DISCONNECT);
826     dcm.reserved = htonl (0);
827     dcm.peer = *neighbour;
828     send_to_client (client, &dcm.header, GNUNET_NO);
829   }
830 }
831
832
833 /**
834  * Notify all clients about a change to existing session.
835  * Called from SESSIONS whenever there is a change in sessions
836  * or types processed by the respective peer.
837  *
838  * @param neighbour identity of the neighbour that changed status
839  * @param tmap_old previous type map for the neighbour, NULL for connect
840  * @param tmap_new updated type map for the neighbour, NULL for disconnect
841  */
842 void
843 GSC_CLIENTS_notify_clients_about_neighbour (const struct GNUNET_PeerIdentity *neighbour,
844                                             const struct GSC_TypeMap *tmap_old,
845                                             const struct GSC_TypeMap *tmap_new)
846 {
847   struct GSC_Client *c;
848
849   for (c = client_head; NULL != c; c = c->next)
850     GSC_CLIENTS_notify_client_about_neighbour (c, neighbour,
851                                                tmap_old, tmap_new);
852 }
853
854
855 /**
856  * Deliver P2P message to interested clients.  Caller must have checked
857  * that the sending peer actually lists the given message type as one
858  * of its types.
859  *
860  * @param sender peer who sent us the message
861  * @param msg the message
862  * @param msize number of bytes to transmit
863  * @param options options for checking which clients should
864  *        receive the message
865  */
866 void
867 GSC_CLIENTS_deliver_message (const struct GNUNET_PeerIdentity *sender,
868                              const struct GNUNET_MessageHeader *msg,
869                              uint16_t msize,
870                              uint32_t options)
871 {
872   size_t size = msize + sizeof (struct NotifyTrafficMessage);
873   char buf[size] GNUNET_ALIGN;
874   struct NotifyTrafficMessage *ntm;
875
876   if (size >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
877   {
878     GNUNET_break (0);
879     /* recovery strategy: throw performance data away... */
880     size = msize + sizeof (struct NotifyTrafficMessage);
881   }
882   if (! ( (0 != (all_client_options & options)) ||
883           (0 != (options & GNUNET_CORE_OPTION_SEND_FULL_INBOUND)) ))
884     return; /* no client cares about this message notification */
885   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
886               "Core service passes message from `%s' of type %u to client.\n",
887               GNUNET_i2s (sender),
888               (unsigned int) ntohs (msg->type));
889   GSC_SESSIONS_add_to_typemap (sender, ntohs (msg->type));
890   ntm = (struct NotifyTrafficMessage *) buf;
891   ntm->header.size = htons (size);
892   if (0 != (options & (GNUNET_CORE_OPTION_SEND_FULL_INBOUND | GNUNET_CORE_OPTION_SEND_HDR_INBOUND)))
893     ntm->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_NOTIFY_INBOUND);
894   else
895     ntm->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_NOTIFY_OUTBOUND);
896   ntm->peer = *sender;
897   memcpy (&ntm[1],
898           msg,
899           msize);
900   send_to_all_clients (sender,
901                        &ntm->header,
902                        GNUNET_YES,
903                        options,
904                        ntohs (msg->type));
905 }
906
907
908 /**
909  * Initialize clients subsystem.
910  *
911  * @param server handle to server clients connect to
912  */
913 void
914 GSC_CLIENTS_init (struct GNUNET_SERVER_Handle *server)
915 {
916   static const struct GNUNET_SERVER_MessageHandler handlers[] = {
917     {&handle_client_init, NULL,
918      GNUNET_MESSAGE_TYPE_CORE_INIT, 0},
919     {&GSC_KX_handle_client_monitor_peers, NULL,
920      GNUNET_MESSAGE_TYPE_CORE_MONITOR_PEERS,
921      sizeof (struct GNUNET_MessageHeader)},
922     {&handle_client_send_request, NULL,
923      GNUNET_MESSAGE_TYPE_CORE_SEND_REQUEST,
924      sizeof (struct SendMessageRequest)},
925     {&handle_client_send, NULL,
926      GNUNET_MESSAGE_TYPE_CORE_SEND, 0},
927     {NULL, NULL, 0, 0}
928   };
929
930   /* setup notification */
931   client_mst = GNUNET_SERVER_mst_create (&client_tokenizer_callback, NULL);
932   notifier =
933       GNUNET_SERVER_notification_context_create (server, MAX_NOTIFY_QUEUE);
934   GNUNET_SERVER_disconnect_notify (server,
935                                    &handle_client_disconnect, NULL);
936   GNUNET_SERVER_add_handlers (server, handlers);
937 }
938
939
940 /**
941  * Shutdown clients subsystem.
942  */
943 void
944 GSC_CLIENTS_done ()
945 {
946   struct GSC_Client *c;
947
948   while (NULL != (c = client_head))
949     handle_client_disconnect (NULL, c->client_handle);
950   if (NULL != notifier)
951   {
952     GNUNET_SERVER_notification_context_destroy (notifier);
953     notifier = NULL;
954   }
955   if (NULL != client_mst)
956   {
957     GNUNET_SERVER_mst_destroy (client_mst);
958     client_mst = NULL;
959   }
960 }
961
962 /* end of gnunet-service-core_clients.c */