try to make sure to send connect on new neighbour even if tcnts are both empty
[oweals/gnunet.git] / src / core / gnunet-service-core_clients.c
1 /*
2      This file is part of GNUnet.
3      (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., 59 Temple Place - Suite 330,
18      Boston, MA 02111-1307, USA.
19 */
20
21 /**
22  * @file core/gnunet-service-core_clients.c
23  * @brief code for managing interactions with clients of core service
24  * @author Christian Grothoff
25  */
26 #include "platform.h"
27 #include "gnunet_util_lib.h"
28 #include "gnunet_statistics_service.h"
29 #include "gnunet_transport_service.h"
30 #include "gnunet-service-core.h"
31 #include "gnunet-service-core_clients.h"
32 #include "gnunet-service-core_sessions.h"
33 #include "gnunet-service-core_typemap.h"
34 #include "core.h"
35
36 /**
37  * How many messages do we queue up at most for optional
38  * notifications to a client?  (this can cause notifications
39  * about outgoing messages to be dropped).
40  */
41 #define MAX_NOTIFY_QUEUE 1024
42
43
44 /**
45  * Data structure for each client connected to the core service.
46  */
47 struct GSC_Client
48 {
49   /**
50    * Clients are kept in a linked list.
51    */
52   struct GSC_Client *next;
53
54   /**
55    * Clients are kept in a linked list.
56    */
57   struct GSC_Client *prev;
58
59   /**
60    * Handle for the client with the server API.
61    */
62   struct GNUNET_SERVER_Client *client_handle;
63
64   /**
65    * Array of the types of messages this peer cares
66    * about (with "tcnt" entries).  Allocated as part
67    * of this client struct, do not free!
68    */
69   const uint16_t *types;
70
71   /**
72    * Map of peer identities to active transmission requests of this
73    * client to the peer (of type 'struct GSC_ClientActiveRequest').
74    */
75   struct GNUNET_CONTAINER_MultiHashMap *requests;
76
77   /**
78    * Options for messages this client cares about,
79    * see GNUNET_CORE_OPTION_ values.
80    */
81   uint32_t options;
82
83   /**
84    * Number of types of incoming messages this client
85    * specifically cares about.  Size of the "types" array.
86    */
87   unsigned int tcnt;
88
89 };
90
91
92 /**
93  * Head of linked list of our clients.
94  */
95 static struct GSC_Client *client_head;
96
97 /**
98  * Tail of linked list of our clients.
99  */
100 static struct GSC_Client *client_tail;
101
102 /**
103  * Context for notifications we need to send to our clients.
104  */
105 static struct GNUNET_SERVER_NotificationContext *notifier;
106
107 /**
108  * Tokenizer for messages received from clients.
109  */
110 static struct GNUNET_SERVER_MessageStreamTokenizer *client_mst;
111
112
113 /**
114  * Lookup our client struct given the server's client handle.
115  *
116  * @param client server client handle to look up
117  * @return our client handle for the client
118  */
119 static struct GSC_Client *
120 find_client (struct GNUNET_SERVER_Client *client)
121 {
122   struct GSC_Client *c;
123
124   c = client_head;
125   while ((c != NULL) && (c->client_handle != client))
126     c = c->next;
127   return c;
128 }
129
130
131 /**
132  * Send a message to one of our clients.
133  *
134  * @param client target for the message
135  * @param msg message to transmit
136  * @param can_drop could this message be dropped if the
137  *        client's queue is getting too large?
138  */
139 static void
140 send_to_client (struct GSC_Client *client, 
141                 const struct GNUNET_MessageHeader *msg,
142                 int can_drop)
143 {
144 #if DEBUG_CORE
145   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
146               "Preparing to send %u bytes of message of type %u to client.\n",
147               (unsigned int) ntohs (msg->size),
148               (unsigned int) ntohs (msg->type));
149 #endif
150   GNUNET_SERVER_notification_context_unicast (notifier, client->client_handle,
151                                               msg, can_drop);
152 }
153
154
155 /**
156  * Send a message to one of our clients.
157  *
158  * @param client target for the message
159  * @param msg message to transmit
160  * @param can_drop could this message be dropped if the
161  *        client's queue is getting too large?
162  */
163 void
164 GSC_CLIENTS_send_to_client (struct GNUNET_SERVER_Client *client,
165                             const struct GNUNET_MessageHeader *msg,
166                             int can_drop)
167 {
168   struct GSC_Client *c;
169
170   c = find_client (client);
171   if (NULL == c)
172   {
173     GNUNET_break (0);
174     return;
175   }
176   send_to_client (c, msg, can_drop);
177 }
178
179
180 /**
181  * Test if the client is interested in messages of the given type.
182  *
183  * @param type message type
184  * @param c client to test
185  * @return GNUNET_YES if 'c' is interested, GNUNET_NO if not.
186  */
187 static int
188 type_match (uint16_t type,
189             struct GSC_Client *c)
190 {
191   unsigned int i;
192
193   if (c->tcnt == 0)
194     return GNUNET_YES; /* peer without handlers matches ALL */
195   for (i=0;i<c->tcnt;i++)
196     if (type == c->types[i])
197       return GNUNET_YES;
198   return GNUNET_NO;
199 }
200
201
202 /**
203  * Send a message to all of our current clients that have the right
204  * options set.
205  *
206  * @param msg message to multicast
207  * @param can_drop can this message be discarded if the queue is too long
208  * @param options mask to use
209  * @param type type of the embedded message, 0 for none
210  */
211 static void
212 send_to_all_clients (const struct GNUNET_MessageHeader *msg, 
213                      int can_drop,
214                      int options,
215                      uint16_t type)
216 {
217   struct GSC_Client *c;
218
219   for (c = client_head; c != NULL; c = c->next)
220   {
221     if ( (0 == (options & GNUNET_CORE_OPTION_SEND_FULL_INBOUND)) &&
222          (GNUNET_YES == type_match (type, c)) )
223       continue; /* not the full message, but we'd like the full one! */
224     if ( (0 == (c->options & options)) &&
225          (GNUNET_YES != type_match (type, c)) )
226       continue; /* neither options nor type match permit the message */
227 #if DEBUG_CORE
228     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
229                 "Sending message to client interested in messages of type %u.\n",
230                 (unsigned int) type);
231 #endif
232     send_to_client (c, msg, can_drop);
233   }
234 }
235
236
237 /**
238  * Handle CORE_INIT request.
239  *
240  * @param cls unused
241  * @param client new client that sent INIT
242  * @param message the 'struct InitMessage' (presumably)
243  */
244 static void
245 handle_client_init (void *cls, struct GNUNET_SERVER_Client *client,
246                     const struct GNUNET_MessageHeader *message)
247 {
248   const struct InitMessage *im;
249   struct InitReplyMessage irm;
250   struct GSC_Client *c;
251   uint16_t msize;
252   const uint16_t *types;
253   uint16_t *wtypes;
254   unsigned int i;
255
256   /* check that we don't have an entry already */
257   c = find_client (client);
258   if (NULL != c)
259   {
260     GNUNET_break (0);
261     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
262     return;
263   }
264   msize = ntohs (message->size);
265   if (msize < sizeof (struct InitMessage))
266   {
267     GNUNET_break (0);
268     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
269     return;
270   }
271   GNUNET_SERVER_notification_context_add (notifier, client);
272   im = (const struct InitMessage *) message;
273   types = (const uint16_t *) &im[1];
274   msize -= sizeof (struct InitMessage);
275   c = GNUNET_malloc (sizeof (struct GSC_Client) + msize);
276   c->client_handle = client;
277   c->tcnt = msize / sizeof (uint16_t);
278   c->options = ntohl (im->options);
279   c->types = (const uint16_t *) &c[1];
280   wtypes = (uint16_t *) & c[1];
281   for (i = 0; i < c->tcnt; i++)
282     wtypes[i] = ntohs (types[i]);
283   GSC_TYPEMAP_add (wtypes, c->tcnt);
284   GNUNET_CONTAINER_DLL_insert (client_head,
285                                client_tail,
286                                c);
287 #if DEBUG_CORE
288   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
289               "Client connecting to core service is interested in %u message types\n", 
290               (unsigned int) c->tcnt);
291 #endif
292   /* send init reply message */
293   irm.header.size = htons (sizeof (struct InitReplyMessage));
294   irm.header.type = htons (GNUNET_MESSAGE_TYPE_CORE_INIT_REPLY);
295   irm.reserved = htonl (0);
296   irm.my_identity = GSC_my_identity;
297   send_to_client (c, &irm.header, GNUNET_NO);
298   if (0 != (c->options & GNUNET_CORE_OPTION_SEND_CONNECT))
299     GSC_SESSIONS_notify_client_about_sessions (c);
300   GNUNET_SERVER_receive_done (client, GNUNET_OK);
301 }
302
303
304 /**
305  * Handle CORE_SEND_REQUEST message.
306  *
307  * @param cls unused
308  * @param client new client that sent CORE_SEND_REQUEST
309  * @param message the 'struct InitMessage' (presumably)
310  */
311 static void
312 handle_client_send_request (void *cls, struct GNUNET_SERVER_Client *client,
313                             const struct GNUNET_MessageHeader *message)
314 {
315   const struct SendMessageRequest *req;
316   struct GSC_Client *c;
317   struct GSC_ClientActiveRequest *car;
318
319   req = (const struct SendMessageRequest *) message;
320   c = find_client (client);
321   if (c == NULL)
322   {
323     /* client did not send INIT first! */
324     GNUNET_break (0);
325     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
326     return;
327   }
328   if (c->requests == NULL)
329     c->requests = GNUNET_CONTAINER_multihashmap_create (16);
330 #if DEBUG_CORE
331   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
332               "Client asked for transmission to `%s'\n",
333               GNUNET_i2s (&req->peer));
334 #endif
335   car = GNUNET_CONTAINER_multihashmap_get (c->requests, &req->peer.hashPubKey);
336   if (car == NULL)
337   {
338     /* create new entry */
339     car = GNUNET_malloc (sizeof (struct GSC_ClientActiveRequest));
340     GNUNET_assert (GNUNET_OK ==
341                    GNUNET_CONTAINER_multihashmap_put (c->requests,
342                                                       &req->peer.hashPubKey,
343                                                       car,
344                                                       GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST));
345     car->client_handle = c;
346   }
347   else
348   {
349     GSC_SESSIONS_dequeue_request (car);
350   }
351   car->target = req->peer;
352   car->deadline = GNUNET_TIME_absolute_ntoh (req->deadline);
353   car->priority = ntohl (req->priority);
354   car->msize = ntohs (req->size);
355   car->smr_id = req->smr_id;
356   car->was_solicited = GNUNET_NO;
357   if (0 ==
358       memcmp (&req->peer, &GSC_my_identity, sizeof (struct GNUNET_PeerIdentity)))
359     GSC_CLIENTS_solicit_request (car);
360   else
361     GSC_SESSIONS_queue_request (car);
362   GNUNET_SERVER_receive_done (client, GNUNET_OK);
363 }
364
365
366 /**
367  * Closure for the 'client_tokenizer_callback'.
368  */
369 struct TokenizerContext
370 {
371
372   /**
373    * Active request handle for the message.
374    */ 
375   struct GSC_ClientActiveRequest *car;
376
377   /**
378    * Is corking allowed (set only once we have the real message).
379    */
380   int cork;
381
382 };
383
384
385 /**
386  * Handle CORE_SEND request.
387  *
388  * @param cls unused
389  * @param client the client issuing the request
390  * @param message the "struct SendMessage"
391  */
392 static void
393 handle_client_send (void *cls, struct GNUNET_SERVER_Client *client,
394                     const struct GNUNET_MessageHeader *message)
395 {
396   const struct SendMessage *sm;
397   struct GSC_Client *c;
398   struct TokenizerContext tc;
399   uint16_t msize;
400
401   msize = ntohs (message->size);
402   if (msize <
403       sizeof (struct SendMessage) + sizeof (struct GNUNET_MessageHeader))
404   {
405     GNUNET_break (0);
406     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
407     return;
408   }
409   sm = (const struct SendMessage *) message;
410   msize -= sizeof (struct SendMessage);
411   GNUNET_break (0 == ntohl (sm->reserved));
412   c = find_client (client);
413   if (c == NULL)
414   {
415     /* client did not send INIT first! */
416     GNUNET_break (0);
417     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
418     return;
419   }
420   tc.car = GNUNET_CONTAINER_multihashmap_get (c->requests, &sm->peer.hashPubKey);
421   if (NULL == tc.car)
422   {
423     /* client did not request transmission first! */
424     GNUNET_break (0);
425     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
426     return;
427   }
428   GNUNET_assert (GNUNET_YES ==
429                  GNUNET_CONTAINER_multihashmap_remove (c->requests, 
430                                                        &sm->peer.hashPubKey,
431                                                        tc.car));
432   tc.cork = ntohl (sm->cork);
433 #if DEBUG_CORE
434   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
435               "Client asked for transmission of %u bytes to `%s' %s\n",
436               msize,
437               GNUNET_i2s (&sm->peer),
438               tc.cork ? "now" : "");
439 #endif
440   GNUNET_SERVER_mst_receive (client_mst,
441                              &tc, 
442                              (const char*) &sm[1], msize,
443                              GNUNET_YES,
444                              GNUNET_NO);
445   if (0 !=
446       memcmp (&tc.car->target, &GSC_my_identity, sizeof (struct GNUNET_PeerIdentity)))  
447     GSC_SESSIONS_dequeue_request (tc.car);
448   GNUNET_free (tc.car);  
449   GNUNET_SERVER_receive_done (client, GNUNET_OK);
450 }
451
452
453 /**
454  * Functions with this signature are called whenever a complete
455  * message is received by the tokenizer.  Used by the 'client_mst' for
456  * dispatching messages from clients to either the SESSION subsystem
457  * or other CLIENT (for loopback).
458  *
459  * @param cls closure
460  * @param client reservation request ('struct GSC_ClientActiveRequest')
461  * @param message the actual message
462  */
463 static void
464 client_tokenizer_callback (void *cls, void *client,
465                            const struct GNUNET_MessageHeader *message)
466 {
467   struct TokenizerContext *tc = client;
468   struct GSC_ClientActiveRequest *car = tc->car;
469
470   if (0 ==
471       memcmp (&car->target, &GSC_my_identity, sizeof (struct GNUNET_PeerIdentity)))  
472   {
473 #if DEBUG_CORE
474     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
475                 "Delivering message of type %u to myself\n",
476                 ntohs (message->type));
477 #endif
478     GSC_CLIENTS_deliver_message (&GSC_my_identity, 
479                                  NULL, 0,
480                                  message,
481                                  ntohs (message->size),
482                                  GNUNET_CORE_OPTION_SEND_FULL_INBOUND | GNUNET_CORE_OPTION_SEND_FULL_OUTBOUND);  
483     GSC_CLIENTS_deliver_message (&GSC_my_identity, 
484                                  NULL, 0,
485                                  message,
486                                  sizeof (struct GNUNET_MessageHeader),
487                                  GNUNET_CORE_OPTION_SEND_HDR_INBOUND | GNUNET_CORE_OPTION_SEND_HDR_OUTBOUND);  
488   }
489   else
490   {
491 #if DEBUG_CORE
492     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
493                 "Delivering message of type %u to %s\n",
494                 ntohs (message->type),
495                 GNUNET_i2s (&car->target));
496 #endif
497     GSC_SESSIONS_transmit (car, message, tc->cork);
498   }
499 }
500
501
502 /**
503  * Free client request records.
504  *
505  * @param cls NULL
506  * @param key identity of peer for which this is an active request
507  * @param value the 'struct GSC_ClientActiveRequest' to free
508  * @return GNUNET_YES (continue iteration)
509  */
510 static int
511 destroy_active_client_request (void *cls, const GNUNET_HashCode * key,
512                                void *value)
513 {
514   struct GSC_ClientActiveRequest *car = value;
515
516   GNUNET_assert (GNUNET_YES ==
517                  GNUNET_CONTAINER_multihashmap_remove (car->client_handle->requests,
518                                                        &car->target.hashPubKey,
519                                                        car));
520   GSC_SESSIONS_dequeue_request (car);
521   GNUNET_free (car);
522   return GNUNET_YES;
523 }
524
525
526 /**
527  * A client disconnected, clean up.
528  *
529  * @param cls closure
530  * @param client identification of the client
531  */
532 static void
533 handle_client_disconnect (void *cls,
534                           struct GNUNET_SERVER_Client *client)
535 {
536   struct GSC_Client *c;
537
538   if (client == NULL)
539     return;
540 #if DEBUG_CORE
541   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
542               "Client %p has disconnected from core service.\n", client);
543 #endif
544   c = find_client (client);
545   if (c == NULL)
546     return; /* client never sent INIT */
547   GNUNET_CONTAINER_DLL_remove (client_head,
548                                client_tail,
549                                c);
550   if (c->requests != NULL)
551   {
552     GNUNET_CONTAINER_multihashmap_iterate (c->requests,
553                                            &destroy_active_client_request,
554                                            NULL);
555     GNUNET_CONTAINER_multihashmap_destroy (c->requests);
556   }
557   GSC_TYPEMAP_remove (c->types, c->tcnt);
558   GNUNET_free (c);
559 }
560
561
562 /**
563  * Tell a client that we are ready to receive the message.
564  *
565  * @param car request that is now ready; the responsibility
566  *        for the handle remains shared between CLIENTS
567  *        and SESSIONS after this call.
568  */
569 void
570 GSC_CLIENTS_solicit_request (struct GSC_ClientActiveRequest *car)
571 {
572   struct GSC_Client *c;
573   struct SendMessageReady smr;
574
575   c = car->client_handle;
576   smr.header.size = htons (sizeof (struct SendMessageReady));
577   smr.header.type = htons (GNUNET_MESSAGE_TYPE_CORE_SEND_READY);
578   smr.size = htons (car->msize);
579   smr.smr_id = car->smr_id;
580   smr.peer = car->target;
581   send_to_client (c, &smr.header, GNUNET_NO);
582 }
583
584
585 /**
586  * Tell a client that we will never be ready to receive the
587  * given message in time (disconnect or timeout).
588  *
589  * @param car request that now permanently failed; the
590  *        responsibility for the handle is now returned
591  *        to CLIENTS (SESSIONS is done with it).
592  */
593 void
594 GSC_CLIENTS_reject_request (struct GSC_ClientActiveRequest *car)
595 {
596   GNUNET_assert (GNUNET_YES ==
597                  GNUNET_CONTAINER_multihashmap_remove (car->client_handle->requests,
598                                                        &car->target.hashPubKey,
599                                                        car));
600   GNUNET_free (car);
601 }
602
603
604 /**
605  * Notify a particular client about a change to existing connection to
606  * one of our neighbours (check if the client is interested).  Called
607  * from 'GSC_SESSIONS_notify_client_about_sessions'.
608  *
609  * @param client client to notify
610  * @param neighbour identity of the neighbour that changed status
611  * @param atsi performance information about neighbour
612  * @param atsi_count number of entries in 'ats' array
613  * @param tmap_old previous type map for the neighbour, NULL for disconnect
614  * @param tmap_new updated type map for the neighbour, NULL for disconnect
615  * @param is_new GNUNET_YES if this is a completely new neighbour
616  */
617 void
618 GSC_CLIENTS_notify_client_about_neighbour (struct GSC_Client *client,
619                                            const struct GNUNET_PeerIdentity *neighbour,
620                                            const struct GNUNET_ATS_Information *atsi,
621                                            unsigned int atsi_count,
622                                            const struct GSC_TypeMap *tmap_old,
623                                            const struct GSC_TypeMap *tmap_new,
624                                            int is_new)
625 {
626   struct ConnectNotifyMessage *cnm;
627   size_t size;
628   char buf[GNUNET_SERVER_MAX_MESSAGE_SIZE - 1];
629   struct GNUNET_ATS_Information *a;
630   struct DisconnectNotifyMessage dcm;
631   int old_match;
632   int new_match;
633
634   old_match = GSC_TYPEMAP_test_match (tmap_old, client->types, client->tcnt);
635   new_match = GSC_TYPEMAP_test_match (tmap_new, client->types, client->tcnt);
636   if (client->tcnt == 0)
637   {
638     /* empty list matches ALL (if not NULL) */
639     if (tmap_new != NULL)
640       new_match = GNUNET_YES; 
641     if (tmap_old != NULL)
642       old_match = GNUNET_YES;
643   }
644   if (GNUNET_YES == is_new)
645     old_match = GNUNET_NO;
646   if (old_match == new_match)
647     return; /* no change */
648   if (old_match == GNUNET_NO)
649   {
650     /* send connect */  
651     size =
652       sizeof (struct ConnectNotifyMessage) +
653       (atsi_count) * sizeof (struct GNUNET_ATS_Information);
654     if (size >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
655       {
656         GNUNET_break (0);
657         /* recovery strategy: throw away performance data */
658         atsi_count = 0;
659         size = sizeof (struct ConnectNotifyMessage);
660       }
661     cnm = (struct ConnectNotifyMessage *) buf;
662     cnm->header.size = htons (size);
663     cnm->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_NOTIFY_CONNECT);
664     cnm->ats_count = htonl (atsi_count);
665     a = &cnm->ats;
666     memcpy (a, atsi,
667             sizeof (struct GNUNET_ATS_Information) * atsi_count);
668     a[atsi_count].type = htonl (GNUNET_ATS_ARRAY_TERMINATOR);
669     a[atsi_count].value = htonl (0);
670 #if DEBUG_CORE
671     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
672                 "Sending `%s' message to client.\n",
673                 "NOTIFY_CONNECT");
674 #endif
675     cnm->peer = *neighbour;
676     send_to_client (client, &cnm->header, GNUNET_NO);
677   }
678   else
679   {
680     /* send disconnect */
681     dcm.header.size = htons (sizeof (struct DisconnectNotifyMessage));
682     dcm.header.type = htons (GNUNET_MESSAGE_TYPE_CORE_NOTIFY_DISCONNECT);
683     dcm.reserved = htonl (0);
684     dcm.peer = *neighbour;
685     send_to_client (client, &dcm.header, GNUNET_NO);
686   }
687 }
688
689
690 /**
691  * Notify all clients about a change to existing session.
692  * Called from SESSIONS whenever there is a change in sessions
693  * or types processed by the respective peer.
694  *
695  * @param neighbour identity of the neighbour that changed status
696  * @param atsi performance information about neighbour
697  * @param atsi_count number of entries in 'ats' array
698  * @param tmap_old previous type map for the neighbour, NULL for disconnect
699  * @param tmap_new updated type map for the neighbour, NULL for disconnect
700  */
701 void
702 GSC_CLIENTS_notify_clients_about_neighbour (const struct GNUNET_PeerIdentity *neighbour,
703                                             const struct GNUNET_ATS_Information *atsi,
704                                             unsigned int atsi_count,
705                                             const struct GSC_TypeMap *tmap_old,
706                                             const struct GSC_TypeMap *tmap_new)
707 {
708   struct GSC_Client *c;
709
710   for (c = client_head; c != NULL; c = c->next)
711     GSC_CLIENTS_notify_client_about_neighbour (c, neighbour, atsi,
712                                                atsi_count, 
713                                                tmap_old, tmap_new,
714                                                GNUNET_NO);
715 }
716
717
718 /**
719  * Deliver P2P message to interested clients.  Caller must have checked
720  * that the sending peer actually lists the given message type as one 
721  * of its types.
722  *
723  * @param sender peer who sent us the message 
724  * @param atsi performance information about neighbour
725  * @param atsi_count number of entries in 'ats' array
726  * @param msg the message
727  * @param msize number of bytes to transmit
728  * @param options options for checking which clients should
729  *        receive the message
730  */
731 void
732 GSC_CLIENTS_deliver_message (const struct GNUNET_PeerIdentity *sender,
733                              const struct GNUNET_ATS_Information *atsi,
734                              unsigned int atsi_count,
735                              const struct GNUNET_MessageHeader *msg,
736                              uint16_t msize,
737                              int options)
738 {
739   size_t size = msize + sizeof (struct NotifyTrafficMessage) +
740       atsi_count * sizeof (struct GNUNET_ATS_Information);
741   char buf[size];
742   struct NotifyTrafficMessage *ntm;
743   struct GNUNET_ATS_Information *a;
744
745   if (0 == options)
746   {
747     GNUNET_snprintf (buf, sizeof (buf),
748                      gettext_noop ("# bytes of messages of type %u received"),
749                      (unsigned int) ntohs (msg->type));
750     GNUNET_STATISTICS_update (GSC_stats, buf, msize, GNUNET_NO);
751   }
752   if (size >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
753   {
754     GNUNET_break (0);
755     /* recovery strategy: throw performance data away... */
756     atsi_count = 0;
757     size = msize + sizeof (struct NotifyTrafficMessage);
758   }
759 #if DEBUG_CORE
760   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
761               "Core service passes message from `%4s' of type %u to client.\n",
762               GNUNET_i2s (sender),
763               (unsigned int) ntohs (msg->type));
764 #endif
765   GSC_SESSIONS_add_to_typemap (sender, ntohs (msg->type));
766   ntm = (struct NotifyTrafficMessage *) buf;
767   ntm->header.size = htons (size);
768   ntm->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_NOTIFY_INBOUND);
769   ntm->ats_count = htonl (atsi_count);
770   ntm->peer = *sender;
771   a = &ntm->ats;
772   memcpy (a, atsi,
773           sizeof (struct GNUNET_ATS_Information) * atsi_count);
774   a[atsi_count].type = htonl (GNUNET_ATS_ARRAY_TERMINATOR);
775   a[atsi_count].value = htonl (0);
776   memcpy (&a[atsi_count + 1], msg, msize);
777   send_to_all_clients (&ntm->header, GNUNET_YES, 
778                        options, ntohs (msg->type));
779 }
780
781
782 /**
783  * Initialize clients subsystem.
784  *
785  * @param server handle to server clients connect to
786  */
787 void
788 GSC_CLIENTS_init (struct GNUNET_SERVER_Handle *server)
789 {
790   static const struct GNUNET_SERVER_MessageHandler handlers[] = {
791     {&handle_client_init, NULL,
792      GNUNET_MESSAGE_TYPE_CORE_INIT, 0},
793     {&GSC_SESSIONS_handle_client_iterate_peers, NULL,
794      GNUNET_MESSAGE_TYPE_CORE_ITERATE_PEERS,
795      sizeof (struct GNUNET_MessageHeader)},
796     {&GSC_SESSIONS_handle_client_have_peer, NULL,
797      GNUNET_MESSAGE_TYPE_CORE_PEER_CONNECTED,
798      sizeof (struct GNUNET_MessageHeader) +
799      sizeof (struct GNUNET_PeerIdentity)},
800     {&handle_client_send_request, NULL,
801      GNUNET_MESSAGE_TYPE_CORE_SEND_REQUEST,
802      sizeof (struct SendMessageRequest)},
803     {&handle_client_send, NULL,
804      GNUNET_MESSAGE_TYPE_CORE_SEND, 0},
805     {NULL, NULL, 0, 0}
806   };
807
808   /* setup notification */
809   client_mst = GNUNET_SERVER_mst_create (&client_tokenizer_callback, NULL);
810   notifier =
811       GNUNET_SERVER_notification_context_create (server, MAX_NOTIFY_QUEUE);
812   GNUNET_SERVER_disconnect_notify (server, &handle_client_disconnect, NULL);
813   GNUNET_SERVER_add_handlers (server, handlers);
814 }
815
816
817 /**
818  * Shutdown clients subsystem.
819  */
820 void
821 GSC_CLIENTS_done ()
822 {
823   struct GSC_Client *c;
824
825   while (NULL != (c = client_head))  
826     handle_client_disconnect (NULL, c->client_handle);
827   if (NULL != notifier)
828   {
829     GNUNET_SERVER_notification_context_destroy (notifier);
830     notifier = NULL;
831   }
832   GNUNET_SERVER_mst_destroy (client_mst);
833   client_mst = NULL;
834 }
835
836 /* end of gnunet-service-core_clients.c */