copy from API
[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
33
34 /**
35  * Data structure for each client connected to the core service.
36  */
37 struct Client
38 {
39   /**
40    * Clients are kept in a linked list.
41    */
42   struct Client *next;
43
44   /**
45    * Clients are kept in a linked list.
46    */
47   struct Client *prev;
48
49   /**
50    * Handle for the client with the server API.
51    */
52   struct GNUNET_SERVER_Client *client_handle;
53
54   /**
55    * Array of the types of messages this peer cares
56    * about (with "tcnt" entries).  Allocated as part
57    * of this client struct, do not free!
58    */
59   const uint16_t *types;
60
61   /**
62    * Map of peer identities to active transmission requests of this
63    * client to the peer (of type 'struct ClientActiveRequest').
64    */
65   struct GNUNET_CONTAINER_MultiHashMap *requests;
66
67   /**
68    * Options for messages this client cares about,
69    * see GNUNET_CORE_OPTION_ values.
70    */
71   uint32_t options;
72
73   /**
74    * Number of types of incoming messages this client
75    * specifically cares about.  Size of the "types" array.
76    */
77   unsigned int tcnt;
78
79 };
80
81
82 /**
83  * Record kept for each request for transmission issued by a
84  * client that is still pending.
85  */
86 struct ClientActiveRequest
87 {
88
89   /**
90    * Active requests are kept in a doubly-linked list of
91    * the respective target peer.
92    */
93   struct ClientActiveRequest *next;
94
95   /**
96    * Active requests are kept in a doubly-linked list of
97    * the respective target peer.
98    */
99   struct ClientActiveRequest *prev;
100
101   /**
102    * Handle to the client.
103    */
104   struct Client *client;
105
106   /**
107    * By what time would the client want to see this message out?
108    */
109   struct GNUNET_TIME_Absolute deadline;
110
111   /**
112    * How important is this request.
113    */
114   uint32_t priority;
115
116   /**
117    * How many more requests does this client have?
118    */
119   uint32_t queue_size;
120
121   /**
122    * How many bytes does the client intend to send?
123    */
124   uint16_t msize;
125
126   /**
127    * Unique request ID (in big endian).
128    */
129   uint16_t smr_id;
130
131 };
132
133
134
135 /**
136  * Linked list of our clients.
137  */
138 static struct Client *clients;
139
140 /**
141  * Context for notifications we need to send to our clients.
142  */
143 static struct GNUNET_SERVER_NotificationContext *notifier;
144
145
146 /**
147  * Our message stream tokenizer (for encrypted payload).
148  */
149 static struct GNUNET_SERVER_MessageStreamTokenizer *mst;
150
151
152
153 /**
154  * Send a message to one of our clients.
155  *
156  * @param client target for the message
157  * @param msg message to transmit
158  * @param can_drop could this message be dropped if the
159  *        client's queue is getting too large?
160  */
161 static void
162 send_to_client (struct Client *client, const struct GNUNET_MessageHeader *msg,
163                 int can_drop)
164 {
165 #if DEBUG_CORE_CLIENT
166   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
167               "Preparing to send %u bytes of message of type %u to client.\n",
168               (unsigned int) ntohs (msg->size),
169               (unsigned int) ntohs (msg->type));
170 #endif
171   GNUNET_SERVER_notification_context_unicast (notifier, client->client_handle,
172                                               msg, can_drop);
173 }
174
175
176
177
178
179 /**
180  * Send a message to all of our current clients that have
181  * the right options set.
182  *
183  * @param msg message to multicast
184  * @param can_drop can this message be discarded if the queue is too long
185  * @param options mask to use
186  */
187 static void
188 send_to_all_clients (const struct GNUNET_MessageHeader *msg, int can_drop,
189                      int options)
190 {
191   struct Client *c;
192
193   c = clients;
194   while (c != NULL)
195   {
196     if (0 != (c->options & options))
197     {
198 #if DEBUG_CORE_CLIENT > 1
199       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
200                   "Sending message of type %u to client.\n",
201                   (unsigned int) ntohs (msg->type));
202 #endif
203       send_to_client (c, msg, can_drop);
204     }
205     c = c->next;
206   }
207 }
208
209
210
211 /**
212  * Handle CORE_SEND_REQUEST message.
213  */
214 static void
215 handle_client_send_request (void *cls, struct GNUNET_SERVER_Client *client,
216                             const struct GNUNET_MessageHeader *message)
217 {
218   const struct SendMessageRequest *req;
219   struct Neighbour *n;
220   struct Client *c;
221   struct ClientActiveRequest *car;
222
223   req = (const struct SendMessageRequest *) message;
224   if (0 ==
225       memcmp (&req->peer, &my_identity, sizeof (struct GNUNET_PeerIdentity)))
226     n = &self;
227   else
228     n = find_neighbour (&req->peer);
229   if ((n == NULL) || (GNUNET_YES != n->is_connected) ||
230       (n->status != PEER_STATE_KEY_CONFIRMED))
231   {
232     /* neighbour must have disconnected since request was issued,
233      * ignore (client will realize it once it processes the
234      * disconnect notification) */
235 #if DEBUG_CORE_CLIENT
236     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
237                 "Dropped client request for transmission (am disconnected)\n");
238 #endif
239     GNUNET_STATISTICS_update (stats,
240                               gettext_noop
241                               ("# send requests dropped (disconnected)"), 1,
242                               GNUNET_NO);
243     GNUNET_SERVER_receive_done (client, GNUNET_OK);
244     return;
245   }
246   c = clients;
247   while ((c != NULL) && (c->client_handle != client))
248     c = c->next;
249   if (c == NULL)
250   {
251     /* client did not send INIT first! */
252     GNUNET_break (0);
253     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
254     return;
255   }
256   if (c->requests == NULL)
257     c->requests = GNUNET_CONTAINER_multihashmap_create (16);
258 #if DEBUG_CORE_CLIENT
259   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
260               "Received client transmission request. queueing\n");
261 #endif
262   car = GNUNET_CONTAINER_multihashmap_get (c->requests, &req->peer.hashPubKey);
263   if (car == NULL)
264   {
265     /* create new entry */
266     car = GNUNET_malloc (sizeof (struct ClientActiveRequest));
267     GNUNET_assert (GNUNET_OK ==
268                    GNUNET_CONTAINER_multihashmap_put (c->requests,
269                                                       &req->peer.hashPubKey,
270                                                       car,
271                                                       GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST));
272     GNUNET_CONTAINER_DLL_insert (n->active_client_request_head,
273                                  n->active_client_request_tail, car);
274     car->client = c;
275   }
276   car->deadline = GNUNET_TIME_absolute_ntoh (req->deadline);
277   car->priority = ntohl (req->priority);
278   car->queue_size = ntohl (req->queue_size);
279   car->msize = ntohs (req->size);
280   car->smr_id = req->smr_id;
281   schedule_peer_messages (n);
282   GNUNET_SERVER_receive_done (client, GNUNET_OK);
283 }
284
285
286 /**
287  * Notify client about an existing connection to one of our neighbours.
288  */
289 static int
290 notify_client_about_neighbour (void *cls, const GNUNET_HashCode * key,
291                                void *value)
292 {
293   struct Client *c = cls;
294   struct Neighbour *n = value;
295   size_t size;
296   char buf[GNUNET_SERVER_MAX_MESSAGE_SIZE - 1];
297   struct GNUNET_TRANSPORT_ATS_Information *ats;
298   struct ConnectNotifyMessage *cnm;
299
300   size =
301       sizeof (struct ConnectNotifyMessage) +
302       (n->ats_count) * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
303   if (size >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
304   {
305     GNUNET_break (0);
306     /* recovery strategy: throw away performance data */
307     GNUNET_array_grow (n->ats, n->ats_count, 0);
308     size =
309         sizeof (struct ConnectNotifyMessage) +
310         (n->ats_count) * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
311   }
312   cnm = (struct ConnectNotifyMessage *) buf;
313   cnm->header.size = htons (size);
314   cnm->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_NOTIFY_CONNECT);
315   cnm->ats_count = htonl (n->ats_count);
316   ats = &cnm->ats;
317   memcpy (ats, n->ats,
318           sizeof (struct GNUNET_TRANSPORT_ATS_Information) * n->ats_count);
319   ats[n->ats_count].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
320   ats[n->ats_count].value = htonl (0);
321   if (n->status == PEER_STATE_KEY_CONFIRMED)
322   {
323 #if DEBUG_CORE_CLIENT
324     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending `%s' message to client.\n",
325                 "NOTIFY_CONNECT");
326 #endif
327     cnm->peer = n->peer;
328     send_to_client (c, &cnm->header, GNUNET_NO);
329   }
330   return GNUNET_OK;
331 }
332
333
334
335 /**
336  * Handle CORE_INIT request.
337  */
338 static void
339 handle_client_init (void *cls, struct GNUNET_SERVER_Client *client,
340                     const struct GNUNET_MessageHeader *message)
341 {
342   const struct InitMessage *im;
343   struct InitReplyMessage irm;
344   struct Client *c;
345   uint16_t msize;
346   const uint16_t *types;
347   uint16_t *wtypes;
348   unsigned int i;
349
350 #if DEBUG_CORE_CLIENT
351   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
352               "Client connecting to core service with `%s' message\n", "INIT");
353 #endif
354   /* check that we don't have an entry already */
355   c = clients;
356   while (c != NULL)
357   {
358     if (client == c->client_handle)
359     {
360       GNUNET_break (0);
361       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
362       return;
363     }
364     c = c->next;
365   }
366   msize = ntohs (message->size);
367   if (msize < sizeof (struct InitMessage))
368   {
369     GNUNET_break (0);
370     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
371     return;
372   }
373   GNUNET_SERVER_notification_context_add (notifier, client);
374   im = (const struct InitMessage *) message;
375   types = (const uint16_t *) &im[1];
376   msize -= sizeof (struct InitMessage);
377   c = GNUNET_malloc (sizeof (struct Client) + msize);
378   c->client_handle = client;
379   c->next = clients;
380   clients = c;
381   c->tcnt = msize / sizeof (uint16_t);
382   c->types = (const uint16_t *) &c[1];
383   wtypes = (uint16_t *) & c[1];
384   for (i = 0; i < c->tcnt; i++)
385   {
386     wtypes[i] = ntohs (types[i]);
387     my_type_map[wtypes[i] / 32] |= (1 << (wtypes[i] % 32));
388   }
389   if (c->tcnt > 0)
390     broadcast_my_type_map ();
391   c->options = ntohl (im->options);
392 #if DEBUG_CORE_CLIENT
393   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
394               "Client %p is interested in %u message types\n", c,
395               (unsigned int) c->tcnt);
396 #endif
397   /* send init reply message */
398   irm.header.size = htons (sizeof (struct InitReplyMessage));
399   irm.header.type = htons (GNUNET_MESSAGE_TYPE_CORE_INIT_REPLY);
400   irm.reserved = htonl (0);
401   memcpy (&irm.publicKey, &my_public_key,
402           sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
403 #if DEBUG_CORE_CLIENT
404   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending `%s' message to client.\n",
405               "INIT_REPLY");
406 #endif
407   send_to_client (c, &irm.header, GNUNET_NO);
408   if (0 != (c->options & GNUNET_CORE_OPTION_SEND_CONNECT))
409   {
410     /* notify new client about existing neighbours */
411     GNUNET_CONTAINER_multihashmap_iterate (neighbours,
412                                            &notify_client_about_neighbour, c);
413   }
414   GNUNET_SERVER_receive_done (client, GNUNET_OK);
415 }
416
417
418 /**
419  * Free client request records.
420  *
421  * @param cls NULL
422  * @param key identity of peer for which this is an active request
423  * @param value the 'struct ClientActiveRequest' to free
424  * @return GNUNET_YES (continue iteration)
425  */
426 static int
427 destroy_active_client_request (void *cls, const GNUNET_HashCode * key,
428                                void *value)
429 {
430   struct ClientActiveRequest *car = value;
431   struct Neighbour *n;
432   struct GNUNET_PeerIdentity peer;
433
434   peer.hashPubKey = *key;
435   n = find_neighbour (&peer);
436   GNUNET_assert (NULL != n);
437   GNUNET_CONTAINER_DLL_remove (n->active_client_request_head,
438                                n->active_client_request_tail, car);
439   GNUNET_free (car);
440   return GNUNET_YES;
441 }
442
443
444 /**
445  * A client disconnected, clean up.
446  *
447  * @param cls closure
448  * @param client identification of the client
449  */
450 static void
451 handle_client_disconnect (void *cls, struct GNUNET_SERVER_Client *client)
452 {
453   struct Client *pos;
454   struct Client *prev;
455   unsigned int i;
456   const uint16_t *wtypes;
457
458   if (client == NULL)
459     return;
460 #if DEBUG_CORE_CLIENT
461   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
462               "Client %p has disconnected from core service.\n", client);
463 #endif
464   prev = NULL;
465   pos = clients;
466   while (pos != NULL)
467   {
468     if (client == pos->client_handle)
469       break;
470     prev = pos;
471     pos = pos->next;
472   }
473   if (pos == NULL)
474   {
475     /* client never sent INIT */
476     return;
477   }
478   if (prev == NULL)
479     clients = pos->next;
480   else
481     prev->next = pos->next;
482   if (pos->requests != NULL)
483   {
484     GNUNET_CONTAINER_multihashmap_iterate (pos->requests,
485                                            &destroy_active_client_request,
486                                            NULL);
487     GNUNET_CONTAINER_multihashmap_destroy (pos->requests);
488   }
489   GNUNET_free (pos);
490
491   /* rebuild my_type_map */
492   memset (my_type_map, 0, sizeof (my_type_map));
493   for (pos = clients; NULL != pos; pos = pos->next)
494   {
495     wtypes = (const uint16_t *) &pos[1];
496     for (i = 0; i < pos->tcnt; i++)
497       my_type_map[wtypes[i] / 32] |= (1 << (wtypes[i] % 32));
498   }
499   broadcast_my_type_map ();
500 }
501
502
503
504
505
506 /**
507  * Handle CORE_SEND request.
508  *
509  * @param cls unused
510  * @param client the client issuing the request
511  * @param message the "struct SendMessage"
512  */
513 static void
514 handle_client_send (void *cls, struct GNUNET_SERVER_Client *client,
515                     const struct GNUNET_MessageHeader *message)
516 {
517   const struct SendMessage *sm;
518   struct Neighbour *n;
519   struct MessageEntry *prev;
520   struct MessageEntry *pos;
521   struct MessageEntry *e;
522   struct MessageEntry *min_prio_entry;
523   struct MessageEntry *min_prio_prev;
524   unsigned int min_prio;
525   unsigned int queue_size;
526   uint16_t msize;
527
528   msize = ntohs (message->size);
529   if (msize <
530       sizeof (struct SendMessage) + sizeof (struct GNUNET_MessageHeader))
531   {
532     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
533                 "msize is %u, should be at least %u (in %s:%d)\n", msize,
534                 sizeof (struct SendMessage) +
535                 sizeof (struct GNUNET_MessageHeader), __FILE__, __LINE__);
536     GNUNET_break (0);
537     if (client != NULL)
538       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
539     return;
540   }
541   sm = (const struct SendMessage *) message;
542   msize -= sizeof (struct SendMessage);
543   if (0 ==
544       memcmp (&sm->peer, &my_identity, sizeof (struct GNUNET_PeerIdentity)))
545   {
546     /* loopback */
547     GNUNET_SERVER_mst_receive (mst, &self, (const char *) &sm[1], msize,
548                                GNUNET_YES, GNUNET_NO);
549     if (client != NULL)
550       GNUNET_SERVER_receive_done (client, GNUNET_OK);
551     return;
552   }
553   n = find_neighbour (&sm->peer);
554   if ((n == NULL) || (GNUNET_YES != n->is_connected) ||
555       (n->status != PEER_STATE_KEY_CONFIRMED))
556   {
557     /* attempt to send message to peer that is not connected anymore
558      * (can happen due to asynchrony) */
559     GNUNET_STATISTICS_update (stats,
560                               gettext_noop
561                               ("# messages discarded (disconnected)"), 1,
562                               GNUNET_NO);
563     if (client != NULL)
564       GNUNET_SERVER_receive_done (client, GNUNET_OK);
565     return;
566   }
567 #if DEBUG_CORE
568   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
569               "Core received `%s' request, queueing %u bytes of plaintext data for transmission to `%4s'.\n",
570               "SEND", (unsigned int) msize, GNUNET_i2s (&sm->peer));
571 #endif
572   discard_expired_messages (n);
573   /* bound queue size */
574   /* NOTE: this entire block to bound the queue size should be
575    * obsolete with the new client-request code and the
576    * 'schedule_peer_messages' mechanism; we still have this code in
577    * here for now as a sanity check for the new mechanmism;
578    * ultimately, we should probably simply reject SEND messages that
579    * are not 'approved' (or provide a new core API for very unreliable
580    * delivery that always sends with priority 0).  Food for thought. */
581   min_prio = UINT32_MAX;
582   min_prio_entry = NULL;
583   min_prio_prev = NULL;
584   queue_size = 0;
585   prev = NULL;
586   pos = n->messages;
587   while (pos != NULL)
588   {
589     if (pos->priority <= min_prio)
590     {
591       min_prio_entry = pos;
592       min_prio_prev = prev;
593       min_prio = pos->priority;
594     }
595     queue_size++;
596     prev = pos;
597     pos = pos->next;
598   }
599   if (queue_size >= MAX_PEER_QUEUE_SIZE)
600   {
601     /* queue full */
602     if (ntohl (sm->priority) <= min_prio)
603     {
604       /* discard new entry; this should no longer happen! */
605       GNUNET_break (0);
606 #if DEBUG_CORE
607       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
608                   "Queue full (%u/%u), discarding new request (%u bytes of type %u)\n",
609                   queue_size, (unsigned int) MAX_PEER_QUEUE_SIZE,
610                   (unsigned int) msize, (unsigned int) ntohs (message->type));
611 #endif
612       GNUNET_STATISTICS_update (stats,
613                                 gettext_noop ("# discarded CORE_SEND requests"),
614                                 1, GNUNET_NO);
615
616       if (client != NULL)
617         GNUNET_SERVER_receive_done (client, GNUNET_OK);
618       return;
619     }
620     GNUNET_assert (min_prio_entry != NULL);
621     /* discard "min_prio_entry" */
622 #if DEBUG_CORE
623     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
624                 "Queue full, discarding existing older request\n");
625 #endif
626     GNUNET_STATISTICS_update (stats,
627                               gettext_noop
628                               ("# discarded lower priority CORE_SEND requests"),
629                               1, GNUNET_NO);
630     if (min_prio_prev == NULL)
631       n->messages = min_prio_entry->next;
632     else
633       min_prio_prev->next = min_prio_entry->next;
634     GNUNET_free (min_prio_entry);
635   }
636
637 #if DEBUG_CORE
638   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
639               "Adding transmission request for `%4s' of size %u to queue\n",
640               GNUNET_i2s (&sm->peer), (unsigned int) msize);
641 #endif
642   GNUNET_break (0 == ntohl (sm->reserved));
643   e = GNUNET_malloc (sizeof (struct MessageEntry) + msize);
644   e->deadline = GNUNET_TIME_absolute_ntoh (sm->deadline);
645   e->priority = ntohl (sm->priority);
646   e->size = msize;
647   if (GNUNET_YES != (int) ntohl (sm->cork))
648     e->got_slack = GNUNET_YES;
649   memcpy (&e[1], &sm[1], msize);
650
651   /* insert, keep list sorted by deadline */
652   prev = NULL;
653   pos = n->messages;
654   while ((pos != NULL) && (pos->deadline.abs_value < e->deadline.abs_value))
655   {
656     prev = pos;
657     pos = pos->next;
658   }
659   if (prev == NULL)
660     n->messages = e;
661   else
662     prev->next = e;
663   e->next = pos;
664
665   /* consider scheduling now */
666   process_plaintext_neighbour_queue (n);
667   if (client != NULL)
668     GNUNET_SERVER_receive_done (client, GNUNET_OK);
669 }
670
671
672 /**
673  * Helper function for handle_client_iterate_peers.
674  *
675  * @param cls the 'struct GNUNET_SERVER_TransmitContext' to queue replies
676  * @param key identity of the connected peer
677  * @param value the 'struct Neighbour' for the peer
678  * @return GNUNET_OK (continue to iterate)
679  */
680 static int
681 queue_connect_message (void *cls, const GNUNET_HashCode * key, void *value)
682 {
683   struct GNUNET_SERVER_TransmitContext *tc = cls;
684   struct Neighbour *n = value;
685   char buf[GNUNET_SERVER_MAX_MESSAGE_SIZE - 1];
686   struct GNUNET_TRANSPORT_ATS_Information *ats;
687   size_t size;
688   struct ConnectNotifyMessage *cnm;
689
690   cnm = (struct ConnectNotifyMessage *) buf;
691   if (n->status != PEER_STATE_KEY_CONFIRMED)
692     return GNUNET_OK;
693   size =
694       sizeof (struct ConnectNotifyMessage) +
695       (n->ats_count) * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
696   if (size >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
697   {
698     GNUNET_break (0);
699     /* recovery strategy: throw away performance data */
700     GNUNET_array_grow (n->ats, n->ats_count, 0);
701     size =
702         sizeof (struct PeerStatusNotifyMessage) +
703         n->ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
704   }
705   cnm = (struct ConnectNotifyMessage *) buf;
706   cnm->header.size = htons (size);
707   cnm->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_NOTIFY_CONNECT);
708   cnm->ats_count = htonl (n->ats_count);
709   ats = &cnm->ats;
710   memcpy (ats, n->ats,
711           n->ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information));
712   ats[n->ats_count].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
713   ats[n->ats_count].value = htonl (0);
714 #if DEBUG_CORE_CLIENT
715   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending `%s' message to client.\n",
716               "NOTIFY_CONNECT");
717 #endif
718   cnm->peer = n->peer;
719   GNUNET_SERVER_transmit_context_append_message (tc, &cnm->header);
720   return GNUNET_OK;
721 }
722
723
724 /**
725  * Handle CORE_ITERATE_PEERS request.
726  *
727  * @param cls unused
728  * @param client client sending the iteration request
729  * @param message iteration request message
730  */
731 static void
732 handle_client_iterate_peers (void *cls, struct GNUNET_SERVER_Client *client,
733                              const struct GNUNET_MessageHeader *message)
734 {
735   struct GNUNET_MessageHeader done_msg;
736   struct GNUNET_SERVER_TransmitContext *tc;
737   int msize;
738
739   /* notify new client about existing neighbours */
740
741   msize = ntohs (message->size);
742   tc = GNUNET_SERVER_transmit_context_create (client);
743   if (msize == sizeof (struct GNUNET_MessageHeader))
744     GNUNET_CONTAINER_multihashmap_iterate (neighbours, &queue_connect_message,
745                                            tc);
746   else
747     GNUNET_break (0);
748
749   done_msg.size = htons (sizeof (struct GNUNET_MessageHeader));
750   done_msg.type = htons (GNUNET_MESSAGE_TYPE_CORE_ITERATE_PEERS_END);
751   GNUNET_SERVER_transmit_context_append_message (tc, &done_msg);
752   GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
753 }
754
755
756 /**
757  * Handle CORE_PEER_CONNECTED request.  Notify client about existing neighbours.
758  *
759  * @param cls unused
760  * @param client client sending the iteration request
761  * @param message iteration request message
762  */
763 static void
764 handle_client_have_peer (void *cls, struct GNUNET_SERVER_Client *client,
765                          const struct GNUNET_MessageHeader *message)
766 {
767   struct GNUNET_MessageHeader done_msg;
768   struct GNUNET_SERVER_TransmitContext *tc;
769   struct GNUNET_PeerIdentity *peer;
770
771   tc = GNUNET_SERVER_transmit_context_create (client);
772   peer = (struct GNUNET_PeerIdentity *) &message[1];
773   GNUNET_CONTAINER_multihashmap_get_multiple (neighbours, &peer->hashPubKey,
774                                               &queue_connect_message, tc);
775   done_msg.size = htons (sizeof (struct GNUNET_MessageHeader));
776   done_msg.type = htons (GNUNET_MESSAGE_TYPE_CORE_ITERATE_PEERS_END);
777   GNUNET_SERVER_transmit_context_append_message (tc, &done_msg);
778   GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
779 }
780
781
782 /**
783  * Handle REQUEST_INFO request.
784  *
785  * @param cls unused
786  * @param client client sending the request
787  * @param message iteration request message
788  */
789 static void
790 handle_client_request_info (void *cls, struct GNUNET_SERVER_Client *client,
791                             const struct GNUNET_MessageHeader *message)
792 {
793   const struct RequestInfoMessage *rcm;
794   struct Client *pos;
795   struct Neighbour *n;
796   struct ConfigurationInfoMessage cim;
797   int32_t want_reserv;
798   int32_t got_reserv;
799   unsigned long long old_preference;
800   struct GNUNET_TIME_Relative rdelay;
801
802   rdelay = GNUNET_TIME_relative_get_zero ();
803 #if DEBUG_CORE_CLIENT
804   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Core service receives `%s' request.\n",
805               "REQUEST_INFO");
806 #endif
807   pos = clients;
808   while (pos != NULL)
809   {
810     if (client == pos->client_handle)
811       break;
812     pos = pos->next;
813   }
814   if (pos == NULL)
815   {
816     GNUNET_break (0);
817     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
818     return;
819   }
820
821   rcm = (const struct RequestInfoMessage *) message;
822   n = find_neighbour (&rcm->peer);
823   memset (&cim, 0, sizeof (cim));
824   if ((n != NULL) && (GNUNET_YES == n->is_connected))
825   {
826     want_reserv = ntohl (rcm->reserve_inbound);
827     if (n->bw_out_internal_limit.value__ != rcm->limit_outbound.value__)
828     {
829       n->bw_out_internal_limit = rcm->limit_outbound;
830       if (n->bw_out.value__ !=
831           GNUNET_BANDWIDTH_value_min (n->bw_out_internal_limit,
832                                       n->bw_out_external_limit).value__)
833       {
834         n->bw_out =
835             GNUNET_BANDWIDTH_value_min (n->bw_out_internal_limit,
836                                         n->bw_out_external_limit);
837         GNUNET_BANDWIDTH_tracker_update_quota (&n->available_recv_window,
838                                                n->bw_out);
839         GNUNET_TRANSPORT_set_quota (transport, &n->peer, n->bw_in, n->bw_out);
840         handle_peer_status_change (n);
841       }
842     }
843     if (want_reserv < 0)
844     {
845       got_reserv = want_reserv;
846     }
847     else if (want_reserv > 0)
848     {
849       rdelay =
850           GNUNET_BANDWIDTH_tracker_get_delay (&n->available_recv_window,
851                                               want_reserv);
852       if (rdelay.rel_value == 0)
853         got_reserv = want_reserv;
854       else
855         got_reserv = 0;         /* all or nothing */
856     }
857     else
858       got_reserv = 0;
859     GNUNET_BANDWIDTH_tracker_consume (&n->available_recv_window, got_reserv);
860     old_preference = n->current_preference;
861     n->current_preference += GNUNET_ntohll (rcm->preference_change);
862     if (old_preference > n->current_preference)
863     {
864       /* overflow; cap at maximum value */
865       n->current_preference = ULLONG_MAX;
866     }
867     update_preference_sum (n->current_preference - old_preference);
868 #if DEBUG_CORE_QUOTA
869     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
870                 "Received reservation request for %d bytes for peer `%4s', reserved %d bytes, suggesting delay of %llu ms\n",
871                 (int) want_reserv, GNUNET_i2s (&rcm->peer), (int) got_reserv,
872                 (unsigned long long) rdelay.rel_value);
873 #endif
874     cim.reserved_amount = htonl (got_reserv);
875     cim.reserve_delay = GNUNET_TIME_relative_hton (rdelay);
876     cim.bw_out = n->bw_out;
877     cim.preference = n->current_preference;
878   }
879   else
880   {
881     /* Technically, this COULD happen (due to asynchronous behavior),
882      * but it should be rare, so we should generate an info event
883      * to help diagnosis of serious errors that might be masked by this */
884     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
885                 _
886                 ("Client asked for preference change with peer `%s', which is not connected!\n"),
887                 GNUNET_i2s (&rcm->peer));
888     GNUNET_SERVER_receive_done (client, GNUNET_OK);
889     return;
890   }
891   cim.header.size = htons (sizeof (struct ConfigurationInfoMessage));
892   cim.header.type = htons (GNUNET_MESSAGE_TYPE_CORE_CONFIGURATION_INFO);
893   cim.peer = rcm->peer;
894   cim.rim_id = rcm->rim_id;
895 #if DEBUG_CORE_CLIENT
896   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending `%s' message to client.\n",
897               "CONFIGURATION_INFO");
898 #endif
899   send_to_client (pos, &cim.header, GNUNET_NO);
900   GNUNET_SERVER_receive_done (client, GNUNET_OK);
901 }
902
903
904
905
906 /**
907  * Send a P2P message to a client.
908  *
909  * @param sender who sent us the message?
910  * @param client who should we give the message to?
911  * @param m contains the message to transmit
912  * @param msize number of bytes in buf to transmit
913  */
914 static void
915 send_p2p_message_to_client (struct Neighbour *sender, struct Client *client,
916                             const void *m, size_t msize)
917 {
918   size_t size =
919       msize + sizeof (struct NotifyTrafficMessage) +
920       (sender->ats_count) * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
921   char buf[size];
922   struct NotifyTrafficMessage *ntm;
923   struct GNUNET_TRANSPORT_ATS_Information *ats;
924
925   GNUNET_assert (GNUNET_YES == sender->is_connected);
926   GNUNET_break (sender->status == PEER_STATE_KEY_CONFIRMED);
927   if (size >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
928   {
929     GNUNET_break (0);
930     /* recovery strategy: throw performance data away... */
931     GNUNET_array_grow (sender->ats, sender->ats_count, 0);
932     size =
933         msize + sizeof (struct NotifyTrafficMessage) +
934         (sender->ats_count) * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
935   }
936 #if DEBUG_CORE
937   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
938               "Core service passes message from `%4s' of type %u to client.\n",
939               GNUNET_i2s (&sender->peer),
940               (unsigned int)
941               ntohs (((const struct GNUNET_MessageHeader *) m)->type));
942 #endif
943   ntm = (struct NotifyTrafficMessage *) buf;
944   ntm->header.size = htons (size);
945   ntm->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_NOTIFY_INBOUND);
946   ntm->ats_count = htonl (sender->ats_count);
947   ntm->peer = sender->peer;
948   ats = &ntm->ats;
949   memcpy (ats, sender->ats,
950           sizeof (struct GNUNET_TRANSPORT_ATS_Information) * sender->ats_count);
951   ats[sender->ats_count].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
952   ats[sender->ats_count].value = htonl (0);
953   memcpy (&ats[sender->ats_count + 1], m, msize);
954   send_to_client (client, &ntm->header, GNUNET_YES);
955 }
956
957
958
959
960 /**
961  * Notify client about a change to existing connection to one of our neighbours.
962  *
963  * @param neighbour identity of the neighbour that changed status
964  * @param tmap updated type map for the neighbour, NULL for disconnect
965  */
966 void
967 GDS_CLIENTS_notify_clients_about_neighbour (const struct GNUNET_PeerIdentity *neighbour,
968                                             const struct GSC_TypeMap *tmap)
969 {
970 }
971
972
973 /**
974  * Deliver P2P message to interested clients.
975  *
976  * @param sender peer who sent us the message 
977  * @param m the message
978  */
979 void
980 GSC_CLIENTS_deliver_message (const struct GNUNET_PeerIdentity *sender,
981                              const struct GNUNET_MessageHeader *m)
982 {
983   struct Neighbour *sender = client;
984   size_t msize = ntohs (m->size);
985   char buf[256];
986   struct Client *cpos;
987   uint16_t type;
988   unsigned int tpos;
989   int deliver_full;
990   int dropped;
991
992   GNUNET_break (sender->status == PEER_STATE_KEY_CONFIRMED);
993   type = ntohs (m->type);
994 #if DEBUG_CORE > 1
995   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
996               "Received encapsulated message of type %u and size %u from `%4s'\n",
997               (unsigned int) type, ntohs (m->size), GNUNET_i2s (&sender->peer));
998 #endif
999   GNUNET_snprintf (buf, sizeof (buf),
1000                    gettext_noop ("# bytes of messages of type %u received"),
1001                    (unsigned int) type);
1002   GNUNET_STATISTICS_update (stats, buf, msize, GNUNET_NO);
1003   if ((GNUNET_MESSAGE_TYPE_CORE_BINARY_TYPE_MAP == type) ||
1004       (GNUNET_MESSAGE_TYPE_CORE_COMPRESSED_TYPE_MAP == type))
1005   {
1006     /* FIXME: update message type map for 'Neighbour' */
1007     return;
1008   }
1009   dropped = GNUNET_YES;
1010   cpos = clients;
1011   while (cpos != NULL)
1012   {
1013     deliver_full = GNUNET_NO;
1014     if (0 != (cpos->options & GNUNET_CORE_OPTION_SEND_FULL_INBOUND))
1015       deliver_full = GNUNET_YES;
1016     else
1017     {
1018       for (tpos = 0; tpos < cpos->tcnt; tpos++)
1019       {
1020         if (type != cpos->types[tpos])
1021           continue;
1022         deliver_full = GNUNET_YES;
1023         break;
1024       }
1025     }
1026     if (GNUNET_YES == deliver_full)
1027     {
1028       send_p2p_message_to_client (sender, cpos, m, msize);
1029       dropped = GNUNET_NO;
1030     }
1031     else if (cpos->options & GNUNET_CORE_OPTION_SEND_HDR_INBOUND)
1032     {
1033       send_p2p_message_to_client (sender, cpos, m,
1034                                   sizeof (struct GNUNET_MessageHeader));
1035     }
1036     cpos = cpos->next;
1037   }
1038   if (dropped == GNUNET_YES)
1039   {
1040 #if DEBUG_CORE
1041     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1042                 "Message of type %u from `%4s' not delivered to any client.\n",
1043                 (unsigned int) type, GNUNET_i2s (&sender->peer));
1044 #endif
1045     GNUNET_STATISTICS_update (stats,
1046                               gettext_noop
1047                               ("# messages not delivered to any client"), 1,
1048                               GNUNET_NO);
1049   }
1050 }
1051
1052
1053
1054 void
1055 GSC_CLIENTS_init (struct GNUNET_SERVER_Handle *server)
1056 {
1057   static const struct GNUNET_SERVER_MessageHandler handlers[] = {
1058     {&handle_client_init, NULL,
1059      GNUNET_MESSAGE_TYPE_CORE_INIT, 0},
1060     {&handle_client_iterate_peers, NULL,
1061      GNUNET_MESSAGE_TYPE_CORE_ITERATE_PEERS,
1062      sizeof (struct GNUNET_MessageHeader)},
1063     {&handle_client_have_peer, NULL,
1064      GNUNET_MESSAGE_TYPE_CORE_PEER_CONNECTED,
1065      sizeof (struct GNUNET_MessageHeader) +
1066      sizeof (struct GNUNET_PeerIdentity)},
1067     {&handle_client_request_info, NULL,
1068      GNUNET_MESSAGE_TYPE_CORE_REQUEST_INFO,
1069      sizeof (struct RequestInfoMessage)},
1070     {&handle_client_send_request, NULL,
1071      GNUNET_MESSAGE_TYPE_CORE_SEND_REQUEST,
1072      sizeof (struct SendMessageRequest)},
1073     {&handle_client_send, NULL,
1074      GNUNET_MESSAGE_TYPE_CORE_SEND, 0},
1075     {NULL, NULL, 0, 0}
1076   };
1077
1078   /* setup notification */
1079   notifier =
1080       GNUNET_SERVER_notification_context_create (server, MAX_NOTIFY_QUEUE);
1081   GNUNET_SERVER_disconnect_notify (server, &handle_client_disconnect, NULL);
1082   GNUNET_SERVER_add_handlers (server, handlers);
1083   mst = GNUNET_SERVER_mst_create (&deliver_message, NULL);
1084 }
1085
1086
1087 void
1088 GSC_CLIENTS_done ()
1089 {
1090   struct Client *c;
1091
1092   while (NULL != (c = clients))
1093     handle_client_disconnect (NULL, c->client_handle);
1094   GNUNET_SERVER_notification_context_destroy (notifier);
1095   notifier = NULL;
1096   if (mst != NULL)
1097     {
1098       GNUNET_SERVER_mst_destroy (mst);
1099       mst = NULL;
1100     }
1101
1102 }