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