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"
32 #include "gnunet_service_core_typemap.h"
37 * Data structure for each client connected to the core service.
42 * Clients are kept in a linked list.
44 struct GSC_Client *next;
47 * Clients are kept in a linked list.
49 struct GSC_Client *prev;
52 * Handle for the client with the server API.
54 struct GNUNET_SERVER_Client *client_handle;
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!
61 const uint16_t *types;
64 * Map of peer identities to active transmission requests of this
65 * client to the peer (of type 'struct GSC_ClientActiveRequest').
67 struct GNUNET_CONTAINER_MultiHashMap *requests;
70 * Options for messages this client cares about,
71 * see GNUNET_CORE_OPTION_ values.
76 * Number of types of incoming messages this client
77 * specifically cares about. Size of the "types" array.
85 * Head of linked list of our clients.
87 static struct GSC_Client *client_head;
90 * Tail of linked list of our clients.
92 static struct GSC_Client *client_tail;
95 * Context for notifications we need to send to our clients.
97 static struct GNUNET_SERVER_NotificationContext *notifier;
100 * Tokenizer for messages received from clients.
102 static struct GNUNET_SERVER_MessageStreamTokenizer *client_mst;
106 * Lookup our client struct given the server's client handle.
108 * @param client server client handle to look up
109 * @return our client handle for the client
111 static struct GSC_Client *
112 find_client (struct GNUNET_SERVER_Client *client)
114 struct GSC_Client *c;
117 while ((c != NULL) && (c->client_handle != client))
124 * Send a message to one of our clients.
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?
132 send_to_client (struct GSC_Client *client,
133 const struct GNUNET_MessageHeader *msg,
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));
142 GNUNET_SERVER_notification_context_unicast (notifier, client->client_handle,
148 * Test if the client is interested in messages of the given type.
150 * @param type message type
151 * @param c client to test
152 * @return GNUNET_YES if 'c' is interested, GNUNET_NO if not.
155 type_match (uint16_t type,
156 struct GSC_Client *c)
160 for (i=0;i<c->tcnt;i++)
161 if (type == c->types[i])
168 * Send a message to all of our current clients that have the right
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
177 send_to_all_clients (const struct GNUNET_MessageHeader *msg,
182 struct GSC_Client *c;
184 for (c = client_head; c != NULL; c = c->next)
186 if ( (0 == (c->options & options)) &&
187 (GNUNET_YES != type_match (type, c)) )
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));
194 send_to_client (c, msg, can_drop);
200 * Handle CORE_INIT request.
203 * @param client new client that sent INIT
204 * @param message the 'struct InitMessage' (presumably)
207 handle_client_init (void *cls, struct GNUNET_SERVER_Client *client,
208 const struct GNUNET_MessageHeader *message)
210 const struct InitMessage *im;
211 struct InitReplyMessage irm;
212 struct GSC_Client *c;
214 const uint16_t *types;
218 /* check that we don't have an entry already */
219 c = find_client (client);
223 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
226 msize = ntohs (message->size);
227 if (msize < sizeof (struct InitMessage))
230 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
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 GSC_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,
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);
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);
267 * Handle CORE_SEND_REQUEST message.
270 * @param client new client that sent CORE_SEND_REQUEST
271 * @param message the 'struct InitMessage' (presumably)
274 handle_client_send_request (void *cls, struct GNUNET_SERVER_Client *client,
275 const struct GNUNET_MessageHeader *message)
277 const struct SendMessageRequest *req;
278 struct GSC_Client *c;
279 struct GSC_ClientActiveRequest *car;
281 req = (const struct SendMessageRequest *) message;
282 c = find_client (client);
285 /* client did not send INIT first! */
287 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
290 if (c->requests == NULL)
291 c->requests = GNUNET_CONTAINER_multihashmap_create (16);
292 car = GNUNET_CONTAINER_multihashmap_get (c->requests, &req->peer.hashPubKey);
295 /* create new entry */
296 car = GNUNET_malloc (sizeof (struct GSC_ClientActiveRequest));
297 GNUNET_assert (GNUNET_OK ==
298 GNUNET_CONTAINER_multihashmap_put (c->requests,
299 &req->peer.hashPubKey,
301 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST));
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;
312 memcmp (&req->peer, &GSC_my_identity, sizeof (struct GNUNET_PeerIdentity)))
313 GSC_CLIENTS_solicit_request (car);
315 GSC_SESSIONS_queue_request (car);
316 GNUNET_SERVER_receive_done (client, GNUNET_OK);
321 * Handle CORE_SEND request.
324 * @param client the client issuing the request
325 * @param message the "struct SendMessage"
328 handle_client_send (void *cls, struct GNUNET_SERVER_Client *client,
329 const struct GNUNET_MessageHeader *message)
331 const struct SendMessage *sm;
332 struct GSC_Client *c;
333 struct GSC_ClientActiveRequest *car;
336 msize = ntohs (message->size);
338 sizeof (struct SendMessage) + sizeof (struct GNUNET_MessageHeader))
341 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
344 sm = (const struct SendMessage *) message;
345 msize -= sizeof (struct SendMessage);
346 GNUNET_break (0 == ntohl (sm->reserved));
347 c = find_client (client);
350 /* client did not send INIT first! */
352 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
355 car = GNUNET_CONTAINER_multihashmap_get (c->requests, &sm->peer.hashPubKey);
358 /* client did not request transmission first! */
360 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
363 GNUNET_assert (GNUNET_YES ==
364 GNUNET_CONTAINER_multihashmap_remove (c->requests,
365 &sm->peer.hashPubKey,
367 GNUNET_SERVER_mst_receive (client_mst,
373 memcmp (&car->peer, &GSC_my_identity, sizeof (struct GNUNET_PeerIdentity)))
374 GSC_SESSIONS_dequeue_request (car);
376 GNUNET_SERVER_receive_done (client, GNUNET_OK);
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).
387 * @param client reservation request ('struct GSC_ClientActiveRequest')
388 * @param message the actual message
391 client_tokenizer_callback (void *cls, void *client,
392 const struct GNUNET_MessageHeader *message)
394 struct GSC_ClientActiveRequest *car = client;
397 memcmp (&car->peer, &GSC_my_identity, sizeof (struct GNUNET_PeerIdentity)))
398 GDS_CLIENTS_deliver_message (&GSC_my_identity, &payload->header);
400 GSC_SESSIONS_transmit (car, &payload->header);
405 * Free client request records.
408 * @param key identity of peer for which this is an active request
409 * @param value the 'struct GSC_ClientActiveRequest' to free
410 * @return GNUNET_YES (continue iteration)
413 destroy_active_client_request (void *cls, const GNUNET_HashCode * key,
416 struct GSC_ClientActiveRequest *car = value;
418 GNUNET_assert (GNUNET_YES ==
419 GNUNET_CONTAINER_multihashmap_remove (car->client->requests,
422 GSC_SESSIONS_dequeue_request (car);
429 * A client disconnected, clean up.
432 * @param client identification of the client
435 handle_client_disconnect (void *cls,
436 struct GNUNET_SERVER_Client *client)
438 struct GSC_Client *c;
442 #if DEBUG_CORE_CLIENT
443 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
444 "Client %p has disconnected from core service.\n", client);
446 c = find_client (client);
448 return; /* client never sent INIT */
449 GNUNET_CONTAINER_DLL_remove (client_head,
452 if (c->requests != NULL)
454 GNUNET_CONTAINER_multihashmap_iterate (c->requests,
455 &destroy_active_client_request,
457 GNUNET_CONTAINER_multihashmap_destroy (c->requests);
459 GSC_TYPEMAP_remove (c->types, c->tcnt);
465 * Tell a client that we are ready to receive the message.
467 * @param car request that is now ready; the responsibility
468 * for the handle remains shared between CLIENTS
469 * and SESSIONS after this call.
472 GSC_CLIENTS_solicit_request (struct GSC_ClientActiveRequest *car)
474 struct GSC_Client *c;
475 struct SendMessageReady smr;
478 smr.header.size = htons (sizeof (struct SendMessageReady));
479 smr.header.type = htons (GNUNET_MESSAGE_TYPE_CORE_SEND_READY);
480 smr.size = htons (car->msize);
481 smr.smr_id = car->smr_id;
483 send_to_client (c, &smr.header, GNUNET_NO);
488 * Tell a client that we will never be ready to receive the
489 * given message in time (disconnect or timeout).
491 * @param car request that now permanently failed; the
492 * responsibility for the handle is now returned
493 * to CLIENTS (SESSIONS is done with it).
496 GSC_CLIENTS_reject_request (struct GSC_ClientActiveRequest *car)
498 GNUNET_assert (GNUNET_YES ==
499 destroy_active_client_request (NULL, &car->peer.hashPubKey, car));
504 // FIXME from here.......................................
512 * Notify client about an existing connection to one of our neighbours.
515 notify_client_about_neighbour (void *cls, const GNUNET_HashCode * key,
518 struct GSC_Client *c = cls;
519 struct Neighbour *n = value;
521 char buf[GNUNET_SERVER_MAX_MESSAGE_SIZE - 1];
522 struct GNUNET_TRANSPORT_ATS_Information *ats;
523 struct ConnectNotifyMessage *cnm;
526 sizeof (struct ConnectNotifyMessage) +
527 (n->ats_count) * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
528 if (size >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
531 /* recovery strategy: throw away performance data */
532 GNUNET_array_grow (n->ats, n->ats_count, 0);
534 sizeof (struct ConnectNotifyMessage) +
535 (n->ats_count) * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
537 cnm = (struct ConnectNotifyMessage *) buf;
538 cnm->header.size = htons (size);
539 cnm->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_NOTIFY_CONNECT);
540 cnm->ats_count = htonl (n->ats_count);
543 sizeof (struct GNUNET_TRANSPORT_ATS_Information) * n->ats_count);
544 ats[n->ats_count].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
545 ats[n->ats_count].value = htonl (0);
546 if (n->status == PEER_STATE_KEY_CONFIRMED)
548 #if DEBUG_CORE_CLIENT
549 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending `%s' message to client.\n",
553 send_to_client (c, &cnm->header, GNUNET_NO);
561 * Helper function for handle_client_iterate_peers.
563 * @param cls the 'struct GNUNET_SERVER_TransmitContext' to queue replies
564 * @param key identity of the connected peer
565 * @param value the 'struct Neighbour' for the peer
566 * @return GNUNET_OK (continue to iterate)
569 queue_connect_message (void *cls, const GNUNET_HashCode * key, void *value)
571 struct GNUNET_SERVER_TransmitContext *tc = cls;
572 struct Neighbour *n = value;
573 char buf[GNUNET_SERVER_MAX_MESSAGE_SIZE - 1];
574 struct GNUNET_TRANSPORT_ATS_Information *ats;
576 struct ConnectNotifyMessage *cnm;
578 cnm = (struct ConnectNotifyMessage *) buf;
579 if (n->status != PEER_STATE_KEY_CONFIRMED)
582 sizeof (struct ConnectNotifyMessage) +
583 (n->ats_count) * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
584 if (size >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
587 /* recovery strategy: throw away performance data */
588 GNUNET_array_grow (n->ats, n->ats_count, 0);
590 sizeof (struct PeerStatusNotifyMessage) +
591 n->ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
593 cnm = (struct ConnectNotifyMessage *) buf;
594 cnm->header.size = htons (size);
595 cnm->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_NOTIFY_CONNECT);
596 cnm->ats_count = htonl (n->ats_count);
599 n->ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information));
600 ats[n->ats_count].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
601 ats[n->ats_count].value = htonl (0);
602 #if DEBUG_CORE_CLIENT
603 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending `%s' message to client.\n",
607 GNUNET_SERVER_transmit_context_append_message (tc, &cnm->header);
615 * Send a P2P message to a client.
617 * @param sender who sent us the message?
618 * @param client who should we give the message to?
619 * @param m contains the message to transmit
620 * @param msize number of bytes in buf to transmit
623 send_p2p_message_to_client (struct Neighbour *sender, struct GSC_Client *client,
624 const void *m, size_t msize)
627 msize + sizeof (struct NotifyTrafficMessage) +
628 (sender->ats_count) * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
630 struct NotifyTrafficMessage *ntm;
631 struct GNUNET_TRANSPORT_ATS_Information *ats;
633 GNUNET_assert (GNUNET_YES == sender->is_connected);
634 GNUNET_break (sender->status == PEER_STATE_KEY_CONFIRMED);
635 if (size >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
638 /* recovery strategy: throw performance data away... */
639 GNUNET_array_grow (sender->ats, sender->ats_count, 0);
641 msize + sizeof (struct NotifyTrafficMessage) +
642 (sender->ats_count) * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
645 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
646 "Core service passes message from `%4s' of type %u to client.\n",
647 GNUNET_i2s (&sender->peer),
649 ntohs (((const struct GNUNET_MessageHeader *) m)->type));
651 ntm = (struct NotifyTrafficMessage *) buf;
652 ntm->header.size = htons (size);
653 ntm->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_NOTIFY_INBOUND);
654 ntm->ats_count = htonl (sender->ats_count);
655 ntm->peer = sender->peer;
657 memcpy (ats, sender->ats,
658 sizeof (struct GNUNET_TRANSPORT_ATS_Information) * sender->ats_count);
659 ats[sender->ats_count].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
660 ats[sender->ats_count].value = htonl (0);
661 memcpy (&ats[sender->ats_count + 1], m, msize);
662 send_to_client (client, &ntm->header, GNUNET_YES);
668 * Notify a particular client about a change to existing connection to
669 * one of our neighbours (check if the client is interested). Called
670 * from 'GSC_SESSIONS_notify_client_about_sessions'.
672 * @param client client to notify
673 * @param neighbour identity of the neighbour that changed status
674 * @param tmap_old previous type map for the neighbour, NULL for disconnect
675 * @param tmap_new updated type map for the neighbour, NULL for disconnect
678 GDS_CLIENTS_notify_client_about_neighbour (struct GSC_Client *client,
679 const struct GNUNET_PeerIdentity *neighbour,
680 const struct GSC_TypeMap *tmap_old,
681 const struct GSC_TypeMap *tmap_new)
687 * Notify client about a change to existing connection to one of our neighbours.
689 * @param neighbour identity of the neighbour that changed status
690 * @param tmap_old previous type map for the neighbour, NULL for disconnect
691 * @param tmap_new updated type map for the neighbour, NULL for disconnect
694 GDS_CLIENTS_notify_clients_about_neighbour (const struct GNUNET_PeerIdentity *neighbour,
695 const struct GSC_TypeMap *tmap_old,
696 const struct GSC_TypeMap *tmap_new)
702 * Deliver P2P message to interested clients.
704 * @param sender peer who sent us the message
705 * @param m the message
708 GSC_CLIENTS_deliver_message (const struct GNUNET_PeerIdentity *sender,
709 const struct GNUNET_MessageHeader *m)
711 struct Neighbour *sender = client;
712 size_t msize = ntohs (m->size);
714 struct GSC_Client *cpos;
720 GNUNET_break (sender->status == PEER_STATE_KEY_CONFIRMED);
721 type = ntohs (m->type);
723 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
724 "Received encapsulated message of type %u and size %u from `%4s'\n",
725 (unsigned int) type, ntohs (m->size), GNUNET_i2s (&sender->peer));
727 GNUNET_snprintf (buf, sizeof (buf),
728 gettext_noop ("# bytes of messages of type %u received"),
729 (unsigned int) type);
730 GNUNET_STATISTICS_update (stats, buf, msize, GNUNET_NO);
731 if ((GNUNET_MESSAGE_TYPE_CORE_BINARY_TYPE_MAP == type) ||
732 (GNUNET_MESSAGE_TYPE_CORE_COMPRESSED_TYPE_MAP == type))
734 /* FIXME: update message type map for 'Neighbour' */
737 dropped = GNUNET_YES;
741 deliver_full = GNUNET_NO;
742 if (0 != (cpos->options & GNUNET_CORE_OPTION_SEND_FULL_INBOUND))
743 deliver_full = GNUNET_YES;
746 for (tpos = 0; tpos < cpos->tcnt; tpos++)
748 if (type != cpos->types[tpos])
750 deliver_full = GNUNET_YES;
754 if (GNUNET_YES == deliver_full)
756 send_p2p_message_to_client (sender, cpos, m, msize);
759 else if (cpos->options & GNUNET_CORE_OPTION_SEND_HDR_INBOUND)
761 send_p2p_message_to_client (sender, cpos, m,
762 sizeof (struct GNUNET_MessageHeader));
766 if (dropped == GNUNET_YES)
769 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
770 "Message of type %u from `%4s' not delivered to any client.\n",
771 (unsigned int) type, GNUNET_i2s (&sender->peer));
773 GNUNET_STATISTICS_update (stats,
775 ("# messages not delivered to any client"), 1,
784 * Handle CORE_ITERATE_PEERS request.
787 * @param client client sending the iteration request
788 * @param message iteration request message
791 handle_client_iterate_peers (void *cls, struct GNUNET_SERVER_Client *client,
792 const struct GNUNET_MessageHeader *message)
794 struct GNUNET_MessageHeader done_msg;
795 struct GNUNET_SERVER_TransmitContext *tc;
798 /* notify new client about existing neighbours */
800 msize = ntohs (message->size);
801 tc = GNUNET_SERVER_transmit_context_create (client);
802 if (msize == sizeof (struct GNUNET_MessageHeader))
803 GNUNET_CONTAINER_multihashmap_iterate (neighbours, &queue_connect_message,
808 done_msg.size = htons (sizeof (struct GNUNET_MessageHeader));
809 done_msg.type = htons (GNUNET_MESSAGE_TYPE_CORE_ITERATE_PEERS_END);
810 GNUNET_SERVER_transmit_context_append_message (tc, &done_msg);
811 GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
816 * Handle CORE_PEER_CONNECTED request. Notify client about existing neighbours.
819 * @param client client sending the iteration request
820 * @param message iteration request message
823 handle_client_have_peer (void *cls, struct GNUNET_SERVER_Client *client,
824 const struct GNUNET_MessageHeader *message)
826 struct GNUNET_MessageHeader done_msg;
827 struct GNUNET_SERVER_TransmitContext *tc;
828 struct GNUNET_PeerIdentity *peer;
830 tc = GNUNET_SERVER_transmit_context_create (client);
831 peer = (struct GNUNET_PeerIdentity *) &message[1];
832 GNUNET_CONTAINER_multihashmap_get_multiple (neighbours, &peer->hashPubKey,
833 &queue_connect_message, tc);
834 done_msg.size = htons (sizeof (struct GNUNET_MessageHeader));
835 done_msg.type = htons (GNUNET_MESSAGE_TYPE_CORE_ITERATE_PEERS_END);
836 GNUNET_SERVER_transmit_context_append_message (tc, &done_msg);
837 GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
842 * Handle REQUEST_INFO request.
845 * @param client client sending the request
846 * @param message iteration request message
849 handle_client_request_info (void *cls, struct GNUNET_SERVER_Client *client,
850 const struct GNUNET_MessageHeader *message)
852 const struct RequestInfoMessage *rcm;
853 struct GSC_Client *pos;
855 struct ConfigurationInfoMessage cim;
858 unsigned long long old_preference;
859 struct GNUNET_TIME_Relative rdelay;
861 rdelay = GNUNET_TIME_relative_get_zero ();
862 #if DEBUG_CORE_CLIENT
863 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Core service receives `%s' request.\n",
869 if (client == pos->client_handle)
876 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
880 rcm = (const struct RequestInfoMessage *) message;
881 n = find_neighbour (&rcm->peer);
882 memset (&cim, 0, sizeof (cim));
883 if ((n != NULL) && (GNUNET_YES == n->is_connected))
885 want_reserv = ntohl (rcm->reserve_inbound);
886 if (n->bw_out_internal_limit.value__ != rcm->limit_outbound.value__)
888 n->bw_out_internal_limit = rcm->limit_outbound;
889 if (n->bw_out.value__ !=
890 GNUNET_BANDWIDTH_value_min (n->bw_out_internal_limit,
891 n->bw_out_external_limit).value__)
894 GNUNET_BANDWIDTH_value_min (n->bw_out_internal_limit,
895 n->bw_out_external_limit);
896 GNUNET_BANDWIDTH_tracker_update_quota (&n->available_recv_window,
898 GNUNET_TRANSPORT_set_quota (transport, &n->peer, n->bw_in, n->bw_out);
899 handle_peer_status_change (n);
904 got_reserv = want_reserv;
906 else if (want_reserv > 0)
909 GNUNET_BANDWIDTH_tracker_get_delay (&n->available_recv_window,
911 if (rdelay.rel_value == 0)
912 got_reserv = want_reserv;
914 got_reserv = 0; /* all or nothing */
918 GNUNET_BANDWIDTH_tracker_consume (&n->available_recv_window, got_reserv);
919 old_preference = n->current_preference;
920 n->current_preference += GNUNET_ntohll (rcm->preference_change);
921 if (old_preference > n->current_preference)
923 /* overflow; cap at maximum value */
924 n->current_preference = ULLONG_MAX;
926 update_preference_sum (n->current_preference - old_preference);
928 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
929 "Received reservation request for %d bytes for peer `%4s', reserved %d bytes, suggesting delay of %llu ms\n",
930 (int) want_reserv, GNUNET_i2s (&rcm->peer), (int) got_reserv,
931 (unsigned long long) rdelay.rel_value);
933 cim.reserved_amount = htonl (got_reserv);
934 cim.reserve_delay = GNUNET_TIME_relative_hton (rdelay);
935 cim.bw_out = n->bw_out;
936 cim.preference = n->current_preference;
940 /* Technically, this COULD happen (due to asynchronous behavior),
941 * but it should be rare, so we should generate an info event
942 * to help diagnosis of serious errors that might be masked by this */
943 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
945 ("Client asked for preference change with peer `%s', which is not connected!\n"),
946 GNUNET_i2s (&rcm->peer));
947 GNUNET_SERVER_receive_done (client, GNUNET_OK);
950 cim.header.size = htons (sizeof (struct ConfigurationInfoMessage));
951 cim.header.type = htons (GNUNET_MESSAGE_TYPE_CORE_CONFIGURATION_INFO);
952 cim.peer = rcm->peer;
953 cim.rim_id = rcm->rim_id;
954 #if DEBUG_CORE_CLIENT
955 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending `%s' message to client.\n",
956 "CONFIGURATION_INFO");
958 send_to_client (pos, &cim.header, GNUNET_NO);
959 GNUNET_SERVER_receive_done (client, GNUNET_OK);
966 * Initialize clients subsystem.
968 * @param server handle to server clients connect to
971 GSC_CLIENTS_init (struct GNUNET_SERVER_Handle *server)
973 static const struct GNUNET_SERVER_MessageHandler handlers[] = {
974 {&handle_client_init, NULL,
975 GNUNET_MESSAGE_TYPE_CORE_INIT, 0},
976 {&handle_client_iterate_peers, NULL,
977 GNUNET_MESSAGE_TYPE_CORE_ITERATE_PEERS,
978 sizeof (struct GNUNET_MessageHeader)},
979 {&handle_client_have_peer, NULL,
980 GNUNET_MESSAGE_TYPE_CORE_PEER_CONNECTED,
981 sizeof (struct GNUNET_MessageHeader) +
982 sizeof (struct GNUNET_PeerIdentity)},
983 {&handle_client_request_info, NULL,
984 GNUNET_MESSAGE_TYPE_CORE_REQUEST_INFO,
985 sizeof (struct RequestInfoMessage)},
986 {&handle_client_send_request, NULL,
987 GNUNET_MESSAGE_TYPE_CORE_SEND_REQUEST,
988 sizeof (struct SendMessageRequest)},
989 {&handle_client_send, NULL,
990 GNUNET_MESSAGE_TYPE_CORE_SEND, 0},
994 /* setup notification */
995 client_mst = GNUNET_SERVER_mst_create (&client_tokenizer_callback, NULL);
997 GNUNET_SERVER_notification_context_create (server, MAX_NOTIFY_QUEUE);
998 GNUNET_SERVER_disconnect_notify (server, &handle_client_disconnect, NULL);
999 GNUNET_SERVER_add_handlers (server, handlers);
1004 * Shutdown clients subsystem.
1009 struct GSC_Client *c;
1011 while (NULL != (c = client_head))
1012 handle_client_disconnect (NULL, c->client_handle);
1013 GNUNET_SERVER_notification_context_destroy (notifier);
1015 GNUNET_SERVER_MST_destroy (client_mst);
1019 /* end of gnunet-service-core_clients.c */