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