2 This file is part of GNUnet.
3 (C) 2009, 2010, 2011 Christian Grothoff (and other contributing authors)
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.
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.
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.
22 * @file core/gnunet-service-core_clients.c
23 * @brief code for managing interactions with clients of core service
24 * @author Christian Grothoff
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"
35 * Data structure for each client connected to the core service.
40 * Clients are kept in a linked list.
45 * Clients are kept in a linked list.
50 * Handle for the client with the server API.
52 struct GNUNET_SERVER_Client *client_handle;
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!
59 const uint16_t *types;
62 * Map of peer identities to active transmission requests of this
63 * client to the peer (of type 'struct ClientActiveRequest').
65 struct GNUNET_CONTAINER_MultiHashMap *requests;
68 * Options for messages this client cares about,
69 * see GNUNET_CORE_OPTION_ values.
74 * Number of types of incoming messages this client
75 * specifically cares about. Size of the "types" array.
83 * Record kept for each request for transmission issued by a
84 * client that is still pending.
86 struct ClientActiveRequest
90 * Active requests are kept in a doubly-linked list of
91 * the respective target peer.
93 struct ClientActiveRequest *next;
96 * Active requests are kept in a doubly-linked list of
97 * the respective target peer.
99 struct ClientActiveRequest *prev;
102 * Handle to the client.
104 struct Client *client;
107 * By what time would the client want to see this message out?
109 struct GNUNET_TIME_Absolute deadline;
112 * How important is this request.
117 * How many more requests does this client have?
122 * How many bytes does the client intend to send?
127 * Unique request ID (in big endian).
136 * Linked list of our clients.
138 static struct Client *clients;
141 * Context for notifications we need to send to our clients.
143 static struct GNUNET_SERVER_NotificationContext *notifier;
147 * Our message stream tokenizer (for encrypted payload).
149 static struct GNUNET_SERVER_MessageStreamTokenizer *mst;
154 * Send a message to one of our clients.
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?
162 send_to_client (struct Client *client, const struct GNUNET_MessageHeader *msg,
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));
171 GNUNET_SERVER_notification_context_unicast (notifier, client->client_handle,
180 * Send a message to all of our current clients that have
181 * the right options set.
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
188 send_to_all_clients (const struct GNUNET_MessageHeader *msg, int can_drop,
196 if (0 != (c->options & options))
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));
203 send_to_client (c, msg, can_drop);
212 * Handle CORE_SEND_REQUEST message.
215 handle_client_send_request (void *cls, struct GNUNET_SERVER_Client *client,
216 const struct GNUNET_MessageHeader *message)
218 const struct SendMessageRequest *req;
221 struct ClientActiveRequest *car;
223 req = (const struct SendMessageRequest *) message;
225 memcmp (&req->peer, &my_identity, sizeof (struct GNUNET_PeerIdentity)))
228 n = find_neighbour (&req->peer);
229 if ((n == NULL) || (GNUNET_YES != n->is_connected) ||
230 (n->status != PEER_STATE_KEY_CONFIRMED))
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");
239 GNUNET_STATISTICS_update (stats,
241 ("# send requests dropped (disconnected)"), 1,
243 GNUNET_SERVER_receive_done (client, GNUNET_OK);
247 while ((c != NULL) && (c->client_handle != client))
251 /* client did not send INIT first! */
253 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
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");
262 car = GNUNET_CONTAINER_multihashmap_get (c->requests, &req->peer.hashPubKey);
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,
271 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST));
272 GNUNET_CONTAINER_DLL_insert (n->active_client_request_head,
273 n->active_client_request_tail, car);
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);
287 * Notify client about an existing connection to one of our neighbours.
290 notify_client_about_neighbour (void *cls, const GNUNET_HashCode * key,
293 struct Client *c = cls;
294 struct Neighbour *n = value;
296 char buf[GNUNET_SERVER_MAX_MESSAGE_SIZE - 1];
297 struct GNUNET_TRANSPORT_ATS_Information *ats;
298 struct ConnectNotifyMessage *cnm;
301 sizeof (struct ConnectNotifyMessage) +
302 (n->ats_count) * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
303 if (size >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
306 /* recovery strategy: throw away performance data */
307 GNUNET_array_grow (n->ats, n->ats_count, 0);
309 sizeof (struct ConnectNotifyMessage) +
310 (n->ats_count) * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
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);
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)
323 #if DEBUG_CORE_CLIENT
324 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending `%s' message to client.\n",
328 send_to_client (c, &cnm->header, GNUNET_NO);
336 * Handle CORE_INIT request.
339 handle_client_init (void *cls, struct GNUNET_SERVER_Client *client,
340 const struct GNUNET_MessageHeader *message)
342 const struct InitMessage *im;
343 struct InitReplyMessage irm;
346 const uint16_t *types;
350 #if DEBUG_CORE_CLIENT
351 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
352 "Client connecting to core service with `%s' message\n", "INIT");
354 /* check that we don't have an entry already */
358 if (client == c->client_handle)
361 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
366 msize = ntohs (message->size);
367 if (msize < sizeof (struct InitMessage))
370 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
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;
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++)
386 wtypes[i] = ntohs (types[i]);
387 my_type_map[wtypes[i] / 32] |= (1 << (wtypes[i] % 32));
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);
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",
407 send_to_client (c, &irm.header, GNUNET_NO);
408 if (0 != (c->options & GNUNET_CORE_OPTION_SEND_CONNECT))
410 /* notify new client about existing neighbours */
411 GNUNET_CONTAINER_multihashmap_iterate (neighbours,
412 ¬ify_client_about_neighbour, c);
414 GNUNET_SERVER_receive_done (client, GNUNET_OK);
419 * Free client request records.
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)
427 destroy_active_client_request (void *cls, const GNUNET_HashCode * key,
430 struct ClientActiveRequest *car = value;
432 struct GNUNET_PeerIdentity peer;
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);
445 * A client disconnected, clean up.
448 * @param client identification of the client
451 handle_client_disconnect (void *cls, struct GNUNET_SERVER_Client *client)
456 const uint16_t *wtypes;
460 #if DEBUG_CORE_CLIENT
461 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
462 "Client %p has disconnected from core service.\n", client);
468 if (client == pos->client_handle)
475 /* client never sent INIT */
481 prev->next = pos->next;
482 if (pos->requests != NULL)
484 GNUNET_CONTAINER_multihashmap_iterate (pos->requests,
485 &destroy_active_client_request,
487 GNUNET_CONTAINER_multihashmap_destroy (pos->requests);
491 /* rebuild my_type_map */
492 memset (my_type_map, 0, sizeof (my_type_map));
493 for (pos = clients; NULL != pos; pos = pos->next)
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));
499 broadcast_my_type_map ();
507 * Handle CORE_SEND request.
510 * @param client the client issuing the request
511 * @param message the "struct SendMessage"
514 handle_client_send (void *cls, struct GNUNET_SERVER_Client *client,
515 const struct GNUNET_MessageHeader *message)
517 const struct SendMessage *sm;
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;
528 msize = ntohs (message->size);
530 sizeof (struct SendMessage) + sizeof (struct GNUNET_MessageHeader))
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__);
538 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
541 sm = (const struct SendMessage *) message;
542 msize -= sizeof (struct SendMessage);
544 memcmp (&sm->peer, &my_identity, sizeof (struct GNUNET_PeerIdentity)))
547 GNUNET_SERVER_mst_receive (mst, &self, (const char *) &sm[1], msize,
548 GNUNET_YES, GNUNET_NO);
550 GNUNET_SERVER_receive_done (client, GNUNET_OK);
553 n = find_neighbour (&sm->peer);
554 if ((n == NULL) || (GNUNET_YES != n->is_connected) ||
555 (n->status != PEER_STATE_KEY_CONFIRMED))
557 /* attempt to send message to peer that is not connected anymore
558 * (can happen due to asynchrony) */
559 GNUNET_STATISTICS_update (stats,
561 ("# messages discarded (disconnected)"), 1,
564 GNUNET_SERVER_receive_done (client, GNUNET_OK);
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));
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;
589 if (pos->priority <= min_prio)
591 min_prio_entry = pos;
592 min_prio_prev = prev;
593 min_prio = pos->priority;
599 if (queue_size >= MAX_PEER_QUEUE_SIZE)
602 if (ntohl (sm->priority) <= min_prio)
604 /* discard new entry; this should no longer happen! */
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));
612 GNUNET_STATISTICS_update (stats,
613 gettext_noop ("# discarded CORE_SEND requests"),
617 GNUNET_SERVER_receive_done (client, GNUNET_OK);
620 GNUNET_assert (min_prio_entry != NULL);
621 /* discard "min_prio_entry" */
623 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
624 "Queue full, discarding existing older request\n");
626 GNUNET_STATISTICS_update (stats,
628 ("# discarded lower priority CORE_SEND requests"),
630 if (min_prio_prev == NULL)
631 n->messages = min_prio_entry->next;
633 min_prio_prev->next = min_prio_entry->next;
634 GNUNET_free (min_prio_entry);
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);
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);
647 if (GNUNET_YES != (int) ntohl (sm->cork))
648 e->got_slack = GNUNET_YES;
649 memcpy (&e[1], &sm[1], msize);
651 /* insert, keep list sorted by deadline */
654 while ((pos != NULL) && (pos->deadline.abs_value < e->deadline.abs_value))
665 /* consider scheduling now */
666 process_plaintext_neighbour_queue (n);
668 GNUNET_SERVER_receive_done (client, GNUNET_OK);
673 * Helper function for handle_client_iterate_peers.
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)
681 queue_connect_message (void *cls, const GNUNET_HashCode * key, void *value)
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;
688 struct ConnectNotifyMessage *cnm;
690 cnm = (struct ConnectNotifyMessage *) buf;
691 if (n->status != PEER_STATE_KEY_CONFIRMED)
694 sizeof (struct ConnectNotifyMessage) +
695 (n->ats_count) * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
696 if (size >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
699 /* recovery strategy: throw away performance data */
700 GNUNET_array_grow (n->ats, n->ats_count, 0);
702 sizeof (struct PeerStatusNotifyMessage) +
703 n->ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
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);
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",
719 GNUNET_SERVER_transmit_context_append_message (tc, &cnm->header);
725 * Handle CORE_ITERATE_PEERS request.
728 * @param client client sending the iteration request
729 * @param message iteration request message
732 handle_client_iterate_peers (void *cls, struct GNUNET_SERVER_Client *client,
733 const struct GNUNET_MessageHeader *message)
735 struct GNUNET_MessageHeader done_msg;
736 struct GNUNET_SERVER_TransmitContext *tc;
739 /* notify new client about existing neighbours */
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,
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);
757 * Handle CORE_PEER_CONNECTED request. Notify client about existing neighbours.
760 * @param client client sending the iteration request
761 * @param message iteration request message
764 handle_client_have_peer (void *cls, struct GNUNET_SERVER_Client *client,
765 const struct GNUNET_MessageHeader *message)
767 struct GNUNET_MessageHeader done_msg;
768 struct GNUNET_SERVER_TransmitContext *tc;
769 struct GNUNET_PeerIdentity *peer;
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);
783 * Handle REQUEST_INFO request.
786 * @param client client sending the request
787 * @param message iteration request message
790 handle_client_request_info (void *cls, struct GNUNET_SERVER_Client *client,
791 const struct GNUNET_MessageHeader *message)
793 const struct RequestInfoMessage *rcm;
796 struct ConfigurationInfoMessage cim;
799 unsigned long long old_preference;
800 struct GNUNET_TIME_Relative rdelay;
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",
810 if (client == pos->client_handle)
817 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
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))
826 want_reserv = ntohl (rcm->reserve_inbound);
827 if (n->bw_out_internal_limit.value__ != rcm->limit_outbound.value__)
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__)
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,
839 GNUNET_TRANSPORT_set_quota (transport, &n->peer, n->bw_in, n->bw_out);
840 handle_peer_status_change (n);
845 got_reserv = want_reserv;
847 else if (want_reserv > 0)
850 GNUNET_BANDWIDTH_tracker_get_delay (&n->available_recv_window,
852 if (rdelay.rel_value == 0)
853 got_reserv = want_reserv;
855 got_reserv = 0; /* all or nothing */
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)
864 /* overflow; cap at maximum value */
865 n->current_preference = ULLONG_MAX;
867 update_preference_sum (n->current_preference - old_preference);
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);
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;
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,
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);
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");
899 send_to_client (pos, &cim.header, GNUNET_NO);
900 GNUNET_SERVER_receive_done (client, GNUNET_OK);
907 * Send a P2P message to a client.
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
915 send_p2p_message_to_client (struct Neighbour *sender, struct Client *client,
916 const void *m, size_t msize)
919 msize + sizeof (struct NotifyTrafficMessage) +
920 (sender->ats_count) * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
922 struct NotifyTrafficMessage *ntm;
923 struct GNUNET_TRANSPORT_ATS_Information *ats;
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)
930 /* recovery strategy: throw performance data away... */
931 GNUNET_array_grow (sender->ats, sender->ats_count, 0);
933 msize + sizeof (struct NotifyTrafficMessage) +
934 (sender->ats_count) * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
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),
941 ntohs (((const struct GNUNET_MessageHeader *) m)->type));
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;
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);
961 * Notify client about a change to existing connection to one of our neighbours.
963 * @param neighbour identity of the neighbour that changed status
964 * @param tmap updated type map for the neighbour, NULL for disconnect
967 GDS_CLIENTS_notify_clients_about_neighbour (const struct GNUNET_PeerIdentity *neighbour,
968 const struct GSC_TypeMap *tmap)
974 * Deliver P2P message to interested clients.
976 * @param sender peer who sent us the message
977 * @param m the message
980 GSC_CLIENTS_deliver_message (const struct GNUNET_PeerIdentity *sender,
981 const struct GNUNET_MessageHeader *m)
983 struct Neighbour *sender = client;
984 size_t msize = ntohs (m->size);
992 GNUNET_break (sender->status == PEER_STATE_KEY_CONFIRMED);
993 type = ntohs (m->type);
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));
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))
1006 /* FIXME: update message type map for 'Neighbour' */
1009 dropped = GNUNET_YES;
1011 while (cpos != NULL)
1013 deliver_full = GNUNET_NO;
1014 if (0 != (cpos->options & GNUNET_CORE_OPTION_SEND_FULL_INBOUND))
1015 deliver_full = GNUNET_YES;
1018 for (tpos = 0; tpos < cpos->tcnt; tpos++)
1020 if (type != cpos->types[tpos])
1022 deliver_full = GNUNET_YES;
1026 if (GNUNET_YES == deliver_full)
1028 send_p2p_message_to_client (sender, cpos, m, msize);
1029 dropped = GNUNET_NO;
1031 else if (cpos->options & GNUNET_CORE_OPTION_SEND_HDR_INBOUND)
1033 send_p2p_message_to_client (sender, cpos, m,
1034 sizeof (struct GNUNET_MessageHeader));
1038 if (dropped == GNUNET_YES)
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));
1045 GNUNET_STATISTICS_update (stats,
1047 ("# messages not delivered to any client"), 1,
1055 GSC_CLIENTS_init (struct GNUNET_SERVER_Handle *server)
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},
1078 /* setup notification */
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);
1092 while (NULL != (c = clients))
1093 handle_client_disconnect (NULL, c->client_handle);
1094 GNUNET_SERVER_notification_context_destroy (notifier);
1098 GNUNET_SERVER_mst_destroy (mst);