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