cleaner
[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_CLIENT
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   for (i=0;i<c->tcnt;i++)
194     if (type == c->types[i])
195       return GNUNET_YES;
196   return GNUNET_NO;
197 }
198
199
200 /**
201  * Send a message to all of our current clients that have the right
202  * options set.
203  *
204  * @param msg message to multicast
205  * @param can_drop can this message be discarded if the queue is too long
206  * @param options mask to use
207  * @param type type of the embedded message, 0 for none
208  */
209 static void
210 send_to_all_clients (const struct GNUNET_MessageHeader *msg, 
211                      int can_drop,
212                      int options,
213                      uint16_t type)
214 {
215   struct GSC_Client *c;
216
217   for (c = client_head; c != NULL; c = c->next)
218   {
219     if (! ( (0 != (c->options & options)) ||
220             ( (0 != (options & GNUNET_CORE_OPTION_SEND_FULL_INBOUND)) &&
221               (GNUNET_YES == type_match (type, c)) ) ) )
222       continue; /* skip */
223 #if DEBUG_CORE_CLIENT > 1
224     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
225                 "Sending message of type %u to client.\n",
226                 (unsigned int) ntohs (msg->type));
227 #endif
228     send_to_client (c, msg, can_drop);
229   }
230 }
231
232
233 /**
234  * Handle CORE_INIT request.
235  *
236  * @param cls unused
237  * @param client new client that sent INIT
238  * @param message the 'struct InitMessage' (presumably)
239  */
240 static void
241 handle_client_init (void *cls, struct GNUNET_SERVER_Client *client,
242                     const struct GNUNET_MessageHeader *message)
243 {
244   const struct InitMessage *im;
245   struct InitReplyMessage irm;
246   struct GSC_Client *c;
247   uint16_t msize;
248   const uint16_t *types;
249   uint16_t *wtypes;
250   unsigned int i;
251
252   /* check that we don't have an entry already */
253   c = find_client (client);
254   if (NULL != c)
255   {
256     GNUNET_break (0);
257     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
258     return;
259   }
260   msize = ntohs (message->size);
261   if (msize < sizeof (struct InitMessage))
262   {
263     GNUNET_break (0);
264     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
265     return;
266   }
267   GNUNET_SERVER_notification_context_add (notifier, client);
268   im = (const struct InitMessage *) message;
269   types = (const uint16_t *) &im[1];
270   msize -= sizeof (struct InitMessage);
271   c = GNUNET_malloc (sizeof (struct GSC_Client) + msize);
272   c->client_handle = client;
273   c->tcnt = msize / sizeof (uint16_t);
274   c->options = ntohl (im->options);
275   c->types = (const uint16_t *) &c[1];
276   wtypes = (uint16_t *) & c[1];
277   for (i = 0; i < c->tcnt; i++)
278     wtypes[i] = ntohs (types[i]);
279   GSC_TYPEMAP_add (wtypes, c->tcnt);
280   GNUNET_CONTAINER_DLL_insert (client_head,
281                                client_tail,
282                                c);
283 #if DEBUG_CORE_CLIENT
284   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
285               "Client connecting to core service is interested in %u message types\n", 
286               (unsigned int) c->tcnt);
287 #endif
288   /* send init reply message */
289   irm.header.size = htons (sizeof (struct InitReplyMessage));
290   irm.header.type = htons (GNUNET_MESSAGE_TYPE_CORE_INIT_REPLY);
291   irm.reserved = htonl (0);
292   irm.my_identity = GSC_my_identity;
293   send_to_client (c, &irm.header, GNUNET_NO);
294   if (0 != (c->options & GNUNET_CORE_OPTION_SEND_CONNECT))
295     GSC_SESSIONS_notify_client_about_sessions (c);
296   GNUNET_SERVER_receive_done (client, GNUNET_OK);
297 }
298
299
300 /**
301  * Handle CORE_SEND_REQUEST message.
302  *
303  * @param cls unused
304  * @param client new client that sent CORE_SEND_REQUEST
305  * @param message the 'struct InitMessage' (presumably)
306  */
307 static void
308 handle_client_send_request (void *cls, struct GNUNET_SERVER_Client *client,
309                             const struct GNUNET_MessageHeader *message)
310 {
311   const struct SendMessageRequest *req;
312   struct GSC_Client *c;
313   struct GSC_ClientActiveRequest *car;
314
315   req = (const struct SendMessageRequest *) message;
316   c = find_client (client);
317   if (c == NULL)
318   {
319     /* client did not send INIT first! */
320     GNUNET_break (0);
321     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
322     return;
323   }
324   if (c->requests == NULL)
325     c->requests = GNUNET_CONTAINER_multihashmap_create (16);
326   car = GNUNET_CONTAINER_multihashmap_get (c->requests, &req->peer.hashPubKey);
327   if (car == NULL)
328   {
329     /* create new entry */
330     car = GNUNET_malloc (sizeof (struct GSC_ClientActiveRequest));
331     GNUNET_assert (GNUNET_OK ==
332                    GNUNET_CONTAINER_multihashmap_put (c->requests,
333                                                       &req->peer.hashPubKey,
334                                                       car,
335                                                       GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST));
336     car->client_handle = c;
337   }
338   car->target = req->peer;
339   car->deadline = GNUNET_TIME_absolute_ntoh (req->deadline);
340   car->priority = ntohl (req->priority);
341   car->msize = ntohs (req->size);
342   car->smr_id = req->smr_id;
343   car->was_solicited = GNUNET_NO;
344   if (0 ==
345       memcmp (&req->peer, &GSC_my_identity, sizeof (struct GNUNET_PeerIdentity)))
346     GSC_CLIENTS_solicit_request (car);
347   else
348     GSC_SESSIONS_queue_request (car);
349   GNUNET_SERVER_receive_done (client, GNUNET_OK);
350 }
351
352
353 /**
354  * Closure for the 'client_tokenizer_callback'.
355  */
356 struct TokenizerContext
357 {
358
359   /**
360    * Active request handle for the message.
361    */ 
362   struct GSC_ClientActiveRequest *car;
363
364   /**
365    * Is corking allowed (set only once we have the real message).
366    */
367   int cork;
368
369 };
370
371
372 /**
373  * Handle CORE_SEND request.
374  *
375  * @param cls unused
376  * @param client the client issuing the request
377  * @param message the "struct SendMessage"
378  */
379 static void
380 handle_client_send (void *cls, struct GNUNET_SERVER_Client *client,
381                     const struct GNUNET_MessageHeader *message)
382 {
383   const struct SendMessage *sm;
384   struct GSC_Client *c;
385   struct TokenizerContext tc;
386   uint16_t msize;
387
388   msize = ntohs (message->size);
389   if (msize <
390       sizeof (struct SendMessage) + sizeof (struct GNUNET_MessageHeader))
391   {
392     GNUNET_break (0);
393     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
394     return;
395   }
396   sm = (const struct SendMessage *) message;
397   msize -= sizeof (struct SendMessage);
398   GNUNET_break (0 == ntohl (sm->reserved));
399   c = find_client (client);
400   if (c == NULL)
401   {
402     /* client did not send INIT first! */
403     GNUNET_break (0);
404     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
405     return;
406   }
407   tc.car = GNUNET_CONTAINER_multihashmap_get (c->requests, &sm->peer.hashPubKey);
408   if (NULL == tc.car)
409   {
410     /* client did not request transmission first! */
411     GNUNET_break (0);
412     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
413     return;
414   }
415   GNUNET_assert (GNUNET_YES ==
416                  GNUNET_CONTAINER_multihashmap_remove (c->requests, 
417                                                        &sm->peer.hashPubKey,
418                                                        tc.car));
419   tc.cork = ntohl (sm->cork);
420   GNUNET_SERVER_mst_receive (client_mst,
421                              &tc, 
422                              (const char*) &sm[1], msize,
423                              GNUNET_YES,
424                              GNUNET_NO);
425   if (0 !=
426       memcmp (&tc.car->target, &GSC_my_identity, sizeof (struct GNUNET_PeerIdentity)))  
427     GSC_SESSIONS_dequeue_request (tc.car);
428   GNUNET_free (tc.car);  
429   GNUNET_SERVER_receive_done (client, GNUNET_OK);
430 }
431
432
433 /**
434  * Functions with this signature are called whenever a complete
435  * message is received by the tokenizer.  Used by the 'client_mst' for
436  * dispatching messages from clients to either the SESSION subsystem
437  * or other CLIENT (for loopback).
438  *
439  * @param cls closure
440  * @param client reservation request ('struct GSC_ClientActiveRequest')
441  * @param message the actual message
442  */
443 static void
444 client_tokenizer_callback (void *cls, void *client,
445                            const struct GNUNET_MessageHeader *message)
446 {
447   struct TokenizerContext *tc = cls;
448   struct GSC_ClientActiveRequest *car = tc->car;
449
450   if (0 ==
451       memcmp (&car->target, &GSC_my_identity, sizeof (struct GNUNET_PeerIdentity)))  
452   {
453     GSC_CLIENTS_deliver_message (&GSC_my_identity, 
454                                  NULL, 0,
455                                  message,
456                                  ntohs (message->size),
457                                  GNUNET_CORE_OPTION_SEND_FULL_INBOUND | GNUNET_CORE_OPTION_SEND_FULL_OUTBOUND);  
458     GSC_CLIENTS_deliver_message (&GSC_my_identity, 
459                                  NULL, 0,
460                                  message,
461                                  sizeof (struct GNUNET_MessageHeader),
462                                  GNUNET_CORE_OPTION_SEND_HDR_INBOUND | GNUNET_CORE_OPTION_SEND_HDR_OUTBOUND);  
463   }
464   else
465     GSC_SESSIONS_transmit (car, message, tc->cork);
466 }
467
468
469 /**
470  * Free client request records.
471  *
472  * @param cls NULL
473  * @param key identity of peer for which this is an active request
474  * @param value the 'struct GSC_ClientActiveRequest' to free
475  * @return GNUNET_YES (continue iteration)
476  */
477 static int
478 destroy_active_client_request (void *cls, const GNUNET_HashCode * key,
479                                void *value)
480 {
481   struct GSC_ClientActiveRequest *car = value;
482
483   GNUNET_assert (GNUNET_YES ==
484                  GNUNET_CONTAINER_multihashmap_remove (car->client_handle->requests,
485                                                        &car->target.hashPubKey,
486                                                        car));
487   GSC_SESSIONS_dequeue_request (car);
488   GNUNET_free (car);
489   return GNUNET_YES;
490 }
491
492
493 /**
494  * A client disconnected, clean up.
495  *
496  * @param cls closure
497  * @param client identification of the client
498  */
499 static void
500 handle_client_disconnect (void *cls,
501                           struct GNUNET_SERVER_Client *client)
502 {
503   struct GSC_Client *c;
504
505   if (client == NULL)
506     return;
507 #if DEBUG_CORE_CLIENT
508   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
509               "Client %p has disconnected from core service.\n", client);
510 #endif
511   c = find_client (client);
512   if (c == NULL)
513     return; /* client never sent INIT */
514   GNUNET_CONTAINER_DLL_remove (client_head,
515                                client_tail,
516                                c);
517   if (c->requests != NULL)
518   {
519     GNUNET_CONTAINER_multihashmap_iterate (c->requests,
520                                            &destroy_active_client_request,
521                                            NULL);
522     GNUNET_CONTAINER_multihashmap_destroy (c->requests);
523   }
524   GSC_TYPEMAP_remove (c->types, c->tcnt);
525   GNUNET_free (c);
526 }
527
528
529 /**
530  * Tell a client that we are ready to receive the message.
531  *
532  * @param car request that is now ready; the responsibility
533  *        for the handle remains shared between CLIENTS
534  *        and SESSIONS after this call.
535  */
536 void
537 GSC_CLIENTS_solicit_request (struct GSC_ClientActiveRequest *car)
538 {
539   struct GSC_Client *c;
540   struct SendMessageReady smr;
541
542   c = car->client_handle;
543   smr.header.size = htons (sizeof (struct SendMessageReady));
544   smr.header.type = htons (GNUNET_MESSAGE_TYPE_CORE_SEND_READY);
545   smr.size = htons (car->msize);
546   smr.smr_id = car->smr_id;
547   smr.peer = car->target;
548   send_to_client (c, &smr.header, GNUNET_NO);
549 }
550
551
552 /**
553  * Tell a client that we will never be ready to receive the
554  * given message in time (disconnect or timeout).
555  *
556  * @param car request that now permanently failed; the
557  *        responsibility for the handle is now returned
558  *        to CLIENTS (SESSIONS is done with it).
559  */
560 void
561 GSC_CLIENTS_reject_request (struct GSC_ClientActiveRequest *car)
562 {
563   GNUNET_assert (GNUNET_YES ==
564                  destroy_active_client_request (NULL, &car->target.hashPubKey, car));  
565 }
566
567
568 /**
569  * Notify a particular client about a change to existing connection to
570  * one of our neighbours (check if the client is interested).  Called
571  * from 'GSC_SESSIONS_notify_client_about_sessions'.
572  *
573  * @param client client to notify
574  * @param neighbour identity of the neighbour that changed status
575  * @param atsi performance information about neighbour
576  * @param atsi_count number of entries in 'ats' array
577  * @param tmap_old previous type map for the neighbour, NULL for disconnect
578  * @param tmap_new updated type map for the neighbour, NULL for disconnect
579  */
580 void
581 GDS_CLIENTS_notify_client_about_neighbour (struct GSC_Client *client,
582                                            const struct GNUNET_PeerIdentity *neighbour,
583                                            const struct GNUNET_TRANSPORT_ATS_Information *atsi,
584                                            unsigned int atsi_count,
585                                            const struct GSC_TypeMap *tmap_old,
586                                            const struct GSC_TypeMap *tmap_new)
587 {
588   struct ConnectNotifyMessage *cnm;
589   size_t size;
590   char buf[GNUNET_SERVER_MAX_MESSAGE_SIZE - 1];
591   struct GNUNET_TRANSPORT_ATS_Information *a;
592   struct DisconnectNotifyMessage dcm;
593   int old_match;
594   int new_match;
595
596   old_match = GSC_TYPEMAP_test_match (tmap_old, client->types, client->tcnt);
597   new_match = GSC_TYPEMAP_test_match (tmap_new, client->types, client->tcnt);
598   if (old_match == new_match)
599     return; /* no change */
600   if (old_match == GNUNET_NO)
601   {
602     /* send connect */  
603     size =
604       sizeof (struct ConnectNotifyMessage) +
605       (atsi_count) * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
606     if (size >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
607       {
608         GNUNET_break (0);
609         /* recovery strategy: throw away performance data */
610         atsi_count = 0;
611         size = sizeof (struct ConnectNotifyMessage);
612       }
613     cnm = (struct ConnectNotifyMessage *) buf;
614     cnm->header.size = htons (size);
615     cnm->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_NOTIFY_CONNECT);
616     cnm->ats_count = htonl (atsi_count);
617     a = &cnm->ats;
618     memcpy (a, atsi,
619             sizeof (struct GNUNET_TRANSPORT_ATS_Information) * atsi_count);
620     a[atsi_count].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
621     a[atsi_count].value = htonl (0);
622 #if DEBUG_CORE_CLIENT
623     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
624                 "Sending `%s' message to client.\n",
625                 "NOTIFY_CONNECT");
626 #endif
627     cnm->peer = *neighbour;
628     send_to_client (client, &cnm->header, GNUNET_NO);
629   }
630   else
631   {
632     /* send disconnect */
633     dcm.header.size = htons (sizeof (struct DisconnectNotifyMessage));
634     dcm.header.type = htons (GNUNET_MESSAGE_TYPE_CORE_NOTIFY_DISCONNECT);
635     dcm.reserved = htonl (0);
636     dcm.peer = *neighbour;
637     send_to_client (client, &dcm.header, GNUNET_NO);
638   }
639 }
640
641
642 /**
643  * Notify all clients about a change to existing session.
644  * Called from SESSIONS whenever there is a change in sessions
645  * or types processed by the respective peer.
646  *
647  * @param neighbour identity of the neighbour that changed status
648  * @param atsi performance information about neighbour
649  * @param atsi_count number of entries in 'ats' array
650  * @param tmap_old previous type map for the neighbour, NULL for disconnect
651  * @param tmap_new updated type map for the neighbour, NULL for disconnect
652  */
653 void
654 GDS_CLIENTS_notify_clients_about_neighbour (const struct GNUNET_PeerIdentity *neighbour,
655                                             const struct GNUNET_TRANSPORT_ATS_Information *atsi,
656                                             unsigned int atsi_count,
657                                             const struct GSC_TypeMap *tmap_old,
658                                             const struct GSC_TypeMap *tmap_new)
659 {
660   struct GSC_Client *c;
661
662   for (c = client_head; c != NULL; c = c->next)
663     GDS_CLIENTS_notify_client_about_neighbour (c, neighbour, atsi,
664                                                atsi_count, 
665                                                tmap_old, tmap_new);
666 }
667
668
669 /**
670  * Deliver P2P message to interested clients.  Caller must have checked
671  * that the sending peer actually lists the given message type as one 
672  * of its types.
673  *
674  * @param sender peer who sent us the message 
675  * @param atsi performance information about neighbour
676  * @param atsi_count number of entries in 'ats' array
677  * @param msg the message
678  * @param msize number of bytes to transmit
679  * @param options options for checking which clients should
680  *        receive the message
681  */
682 void
683 GSC_CLIENTS_deliver_message (const struct GNUNET_PeerIdentity *sender,
684                              const struct GNUNET_TRANSPORT_ATS_Information *atsi,
685                              unsigned int atsi_count,
686                              const struct GNUNET_MessageHeader *msg,
687                              uint16_t msize,
688                              int options)
689 {
690   size_t size = msize + sizeof (struct NotifyTrafficMessage) +
691       atsi_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
692   char buf[size];
693   struct NotifyTrafficMessage *ntm;
694   struct GNUNET_TRANSPORT_ATS_Information *a;
695
696   if (0 == options)
697   {
698     GNUNET_snprintf (buf, sizeof (buf),
699                      gettext_noop ("# bytes of messages of type %u received"),
700                      (unsigned int) ntohs (msg->type));
701     GNUNET_STATISTICS_update (GSC_stats, buf, msize, GNUNET_NO);
702   }
703   if (size >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
704   {
705     GNUNET_break (0);
706     /* recovery strategy: throw performance data away... */
707     atsi_count = 0;
708     size = msize + sizeof (struct NotifyTrafficMessage);
709   }
710 #if DEBUG_CORE
711   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
712               "Core service passes message from `%4s' of type %u to client.\n",
713               GNUNET_i2s (sender),
714               (unsigned int) ntohs (msg->type));
715 #endif
716   ntm = (struct NotifyTrafficMessage *) buf;
717   ntm->header.size = htons (size);
718   ntm->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_NOTIFY_INBOUND);
719   ntm->ats_count = htonl (atsi_count);
720   ntm->peer = *sender;
721   a = &ntm->ats;
722   memcpy (a, atsi,
723           sizeof (struct GNUNET_TRANSPORT_ATS_Information) * atsi_count);
724   a[atsi_count].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
725   a[atsi_count].value = htonl (0);
726   memcpy (&a[atsi_count + 1], msg, msize);
727   send_to_all_clients (&ntm->header, GNUNET_YES, 
728                        options, ntohs (msg->type));
729 }
730
731
732 /**
733  * Initialize clients subsystem.
734  *
735  * @param server handle to server clients connect to
736  */
737 void
738 GSC_CLIENTS_init (struct GNUNET_SERVER_Handle *server)
739 {
740   static const struct GNUNET_SERVER_MessageHandler handlers[] = {
741     {&handle_client_init, NULL,
742      GNUNET_MESSAGE_TYPE_CORE_INIT, 0},
743     {&GSC_SESSIONS_handle_client_iterate_peers, NULL,
744      GNUNET_MESSAGE_TYPE_CORE_ITERATE_PEERS,
745      sizeof (struct GNUNET_MessageHeader)},
746     {&GSC_SESSIONS_handle_client_have_peer, NULL,
747      GNUNET_MESSAGE_TYPE_CORE_PEER_CONNECTED,
748      sizeof (struct GNUNET_MessageHeader) +
749      sizeof (struct GNUNET_PeerIdentity)},
750     {&handle_client_send_request, NULL,
751      GNUNET_MESSAGE_TYPE_CORE_SEND_REQUEST,
752      sizeof (struct SendMessageRequest)},
753     {&handle_client_send, NULL,
754      GNUNET_MESSAGE_TYPE_CORE_SEND, 0},
755     {NULL, NULL, 0, 0}
756   };
757
758   /* setup notification */
759   client_mst = GNUNET_SERVER_mst_create (&client_tokenizer_callback, NULL);
760   notifier =
761       GNUNET_SERVER_notification_context_create (server, MAX_NOTIFY_QUEUE);
762   GNUNET_SERVER_disconnect_notify (server, &handle_client_disconnect, NULL);
763   GNUNET_SERVER_add_handlers (server, handlers);
764 }
765
766
767 /**
768  * Shutdown clients subsystem.
769  */
770 void
771 GSC_CLIENTS_done ()
772 {
773   struct GSC_Client *c;
774
775   while (NULL != (c = client_head))  
776     handle_client_disconnect (NULL, c->client_handle);
777   GNUNET_SERVER_notification_context_destroy (notifier);
778   notifier = NULL;
779   GNUNET_SERVER_mst_destroy (client_mst);
780   client_mst = NULL;
781 }
782
783 /* end of gnunet-service-core_clients.c */