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_statistics_service.h"
29 #include "gnunet_transport_service.h"
30 #include "gnunet-service-core.h"
31 #include "gnunet-service-core_clients.h"
32 #include "gnunet-service-core_sessions.h"
33 #include "gnunet-service-core_typemap.h"
38 * How many messages do we queue up at most for optional
39 * notifications to a client? (this can cause notifications
40 * about outgoing messages to be dropped).
42 #define MAX_NOTIFY_QUEUE 1024
46 * Data structure for each client connected to the core service.
51 * Clients are kept in a linked list.
53 struct GSC_Client *next;
56 * Clients are kept in a linked list.
58 struct GSC_Client *prev;
61 * Handle for the client with the server API.
63 struct GNUNET_SERVER_Client *client_handle;
66 * Array of the types of messages this peer cares
67 * about (with "tcnt" entries). Allocated as part
68 * of this client struct, do not free!
70 const uint16_t *types;
73 * Map of peer identities to active transmission requests of this
74 * client to the peer (of type 'struct GSC_ClientActiveRequest').
76 struct GNUNET_CONTAINER_MultiHashMap *requests;
79 * Map containing all peers that this client knows we're connected to.
81 struct GNUNET_CONTAINER_MultiHashMap *connectmap;
84 * Options for messages this client cares about,
85 * see GNUNET_CORE_OPTION_ values.
90 * Number of types of incoming messages this client
91 * specifically cares about. Size of the "types" array.
99 * Big "or" of all client options.
101 static uint32_t all_client_options;
104 * Head of linked list of our clients.
106 static struct GSC_Client *client_head;
109 * Tail of linked list of our clients.
111 static struct GSC_Client *client_tail;
114 * Context for notifications we need to send to our clients.
116 static struct GNUNET_SERVER_NotificationContext *notifier;
119 * Tokenizer for messages received from clients.
121 static struct GNUNET_SERVER_MessageStreamTokenizer *client_mst;
125 * Lookup our client struct given the server's client handle.
127 * @param client server client handle to look up
128 * @return our client handle for the client
130 static struct GSC_Client *
131 find_client (struct GNUNET_SERVER_Client *client)
133 struct GSC_Client *c;
136 while ((c != NULL) && (c->client_handle != client))
143 * Send a message to one of our clients.
145 * @param client target for the message
146 * @param msg message to transmit
147 * @param can_drop could this message be dropped if the
148 * client's queue is getting too large?
151 send_to_client (struct GSC_Client *client,
152 const struct GNUNET_MessageHeader *msg, int can_drop)
154 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
155 "Preparing to send %u bytes of message of type %u to client.\n",
156 (unsigned int) ntohs (msg->size),
157 (unsigned int) ntohs (msg->type));
158 GNUNET_SERVER_notification_context_unicast (notifier, client->client_handle,
164 * Send a message to one of our clients.
166 * @param client target for the message
167 * @param msg message to transmit
168 * @param can_drop could this message be dropped if the
169 * client's queue is getting too large?
172 GSC_CLIENTS_send_to_client (struct GNUNET_SERVER_Client *client,
173 const struct GNUNET_MessageHeader *msg,
176 struct GSC_Client *c;
178 c = find_client (client);
184 send_to_client (c, msg, can_drop);
189 * Test if the client is interested in messages of the given type.
191 * @param type message type
192 * @param c client to test
193 * @return GNUNET_YES if 'c' is interested, GNUNET_NO if not.
196 type_match (uint16_t type, struct GSC_Client *c)
201 return GNUNET_YES; /* peer without handlers matches ALL */
202 for (i = 0; i < c->tcnt; i++)
203 if (type == c->types[i])
210 * Send a message to all of our current clients that have the right
213 * @param partner origin (or destination) of the message (used to check that this peer is
214 * known to be connected to the respective client)
215 * @param msg message to multicast
216 * @param can_drop can this message be discarded if the queue is too long
217 * @param options mask to use
218 * @param type type of the embedded message, 0 for none
221 send_to_all_clients (const struct GNUNET_PeerIdentity *partner,
222 const struct GNUNET_MessageHeader *msg, int can_drop,
223 uint32_t options, uint16_t type)
225 struct GSC_Client *c;
227 for (c = client_head; c != NULL; c = c->next)
229 if (! ( (0 != (c->options & options)) ||
230 ( (0 != (options & GNUNET_CORE_OPTION_SEND_FULL_INBOUND)) &&
231 (GNUNET_YES == type_match (type, c)) ) ) )
232 continue; /* neither options nor type match permit the message */
233 if ( (0 != (options & GNUNET_CORE_OPTION_SEND_HDR_INBOUND)) &&
234 ( (0 != (c->options & GNUNET_CORE_OPTION_SEND_FULL_INBOUND)) ||
235 (GNUNET_YES == type_match (type, c)) ) )
237 if ( (0 != (options & GNUNET_CORE_OPTION_SEND_HDR_OUTBOUND)) &&
238 (0 != (c->options & GNUNET_CORE_OPTION_SEND_FULL_OUTBOUND)) )
240 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
241 "Sending %u message with %u bytes to client interested in messages of type %u.\n",
244 (unsigned int) type);
245 GNUNET_assert (GNUNET_YES ==
246 GNUNET_CONTAINER_multihashmap_contains (c->connectmap,
247 &partner->hashPubKey));
248 send_to_client (c, msg, can_drop);
254 * Handle CORE_INIT request.
257 * @param client new client that sent INIT
258 * @param message the 'struct InitMessage' (presumably)
261 handle_client_init (void *cls, struct GNUNET_SERVER_Client *client,
262 const struct GNUNET_MessageHeader *message)
264 const struct InitMessage *im;
265 struct InitReplyMessage irm;
266 struct GSC_Client *c;
268 const uint16_t *types;
272 /* check that we don't have an entry already */
273 c = find_client (client);
277 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
280 msize = ntohs (message->size);
281 if (msize < sizeof (struct InitMessage))
284 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
287 GNUNET_SERVER_notification_context_add (notifier, client);
288 im = (const struct InitMessage *) message;
289 types = (const uint16_t *) &im[1];
290 msize -= sizeof (struct InitMessage);
291 c = GNUNET_malloc (sizeof (struct GSC_Client) + msize);
292 c->client_handle = client;
293 c->tcnt = msize / sizeof (uint16_t);
294 c->options = ntohl (im->options);
295 all_client_options |= c->options;
296 c->types = (const uint16_t *) &c[1];
297 c->connectmap = GNUNET_CONTAINER_multihashmap_create (16);
298 GNUNET_assert (GNUNET_YES ==
299 GNUNET_CONTAINER_multihashmap_put (c->connectmap,
300 &GSC_my_identity.hashPubKey,
302 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
303 wtypes = (uint16_t *) & c[1];
304 for (i = 0; i < c->tcnt; i++)
305 wtypes[i] = ntohs (types[i]);
306 GSC_TYPEMAP_add (wtypes, c->tcnt);
307 GNUNET_CONTAINER_DLL_insert (client_head, client_tail, c);
308 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
309 "Client connecting to core service is interested in %u message types\n",
310 (unsigned int) c->tcnt);
311 /* send init reply message */
312 irm.header.size = htons (sizeof (struct InitReplyMessage));
313 irm.header.type = htons (GNUNET_MESSAGE_TYPE_CORE_INIT_REPLY);
314 irm.reserved = htonl (0);
315 irm.my_identity = GSC_my_identity;
316 send_to_client (c, &irm.header, GNUNET_NO);
317 GSC_SESSIONS_notify_client_about_sessions (c);
318 GNUNET_SERVER_receive_done (client, GNUNET_OK);
323 * Handle CORE_SEND_REQUEST message.
326 * @param client new client that sent CORE_SEND_REQUEST
327 * @param message the 'struct SendMessageRequest' (presumably)
330 handle_client_send_request (void *cls, struct GNUNET_SERVER_Client *client,
331 const struct GNUNET_MessageHeader *message)
333 const struct SendMessageRequest *req;
334 struct GSC_Client *c;
335 struct GSC_ClientActiveRequest *car;
338 req = (const struct SendMessageRequest *) message;
339 c = find_client (client);
342 /* client did not send INIT first! */
344 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
347 if (c->requests == NULL)
348 c->requests = GNUNET_CONTAINER_multihashmap_create (16);
349 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
350 "Client asked for transmission to `%s'\n",
351 GNUNET_i2s (&req->peer));
354 memcmp (&req->peer, &GSC_my_identity,
355 sizeof (struct GNUNET_PeerIdentity)));
356 if ((!is_loopback) &&
358 GNUNET_CONTAINER_multihashmap_contains (c->connectmap,
359 &req->peer.hashPubKey)))
361 /* neighbour must have disconnected since request was issued,
362 * ignore (client will realize it once it processes the
363 * disconnect notification) */
364 GNUNET_STATISTICS_update (GSC_stats,
366 ("# send requests dropped (disconnected)"), 1,
368 GNUNET_SERVER_receive_done (client, GNUNET_OK);
372 car = GNUNET_CONTAINER_multihashmap_get (c->requests, &req->peer.hashPubKey);
375 /* create new entry */
376 car = GNUNET_malloc (sizeof (struct GSC_ClientActiveRequest));
377 GNUNET_assert (GNUNET_OK ==
378 GNUNET_CONTAINER_multihashmap_put (c->requests,
379 &req->peer.hashPubKey,
381 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST));
382 car->client_handle = c;
386 GSC_SESSIONS_dequeue_request (car);
388 car->target = req->peer;
389 car->deadline = GNUNET_TIME_absolute_ntoh (req->deadline);
390 car->priority = ntohl (req->priority);
391 car->msize = ntohs (req->size);
392 car->smr_id = req->smr_id;
393 car->was_solicited = GNUNET_NO;
396 /* loopback, satisfy immediately */
397 GSC_CLIENTS_solicit_request (car);
398 GNUNET_SERVER_receive_done (client, GNUNET_OK);
401 GSC_SESSIONS_queue_request (car);
402 GNUNET_SERVER_receive_done (client, GNUNET_OK);
407 * Closure for the 'client_tokenizer_callback'.
409 struct TokenizerContext
413 * Active request handle for the message.
415 struct GSC_ClientActiveRequest *car;
418 * Is corking allowed (set only once we have the real message).
426 * Handle CORE_SEND request.
429 * @param client the client issuing the request
430 * @param message the "struct SendMessage"
433 handle_client_send (void *cls, struct GNUNET_SERVER_Client *client,
434 const struct GNUNET_MessageHeader *message)
436 const struct SendMessage *sm;
437 struct GSC_Client *c;
438 struct TokenizerContext tc;
441 msize = ntohs (message->size);
443 sizeof (struct SendMessage) + sizeof (struct GNUNET_MessageHeader))
446 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
449 sm = (const struct SendMessage *) message;
450 msize -= sizeof (struct SendMessage);
451 GNUNET_break (0 == ntohl (sm->reserved));
452 c = find_client (client);
455 /* client did not send INIT first! */
457 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
461 GNUNET_CONTAINER_multihashmap_get (c->requests, &sm->peer.hashPubKey);
464 /* Must have been that we first approved the request, then got disconnected
465 * (which triggered removal of the 'car') and now the client gives us a message
466 * just *before* the client learns about the disconnect. Theoretically, we
467 * might also now be *again* connected. So this can happen (but should be
468 * rare). If it does happen, the message is discarded. */
469 GNUNET_STATISTICS_update (GSC_stats,
471 ("# messages discarded (session disconnected)"),
473 GNUNET_SERVER_receive_done (client, GNUNET_OK);
476 GNUNET_assert (GNUNET_YES ==
477 GNUNET_CONTAINER_multihashmap_remove (c->requests,
478 &sm->peer.hashPubKey,
480 tc.cork = ntohl (sm->cork);
481 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
482 "Client asked for transmission of %u bytes to `%s' %s\n", msize,
483 GNUNET_i2s (&sm->peer), tc.cork ? "now" : "");
484 GNUNET_SERVER_mst_receive (client_mst, &tc, (const char *) &sm[1], msize,
485 GNUNET_YES, GNUNET_NO);
487 memcmp (&tc.car->target, &GSC_my_identity,
488 sizeof (struct GNUNET_PeerIdentity)))
489 GSC_SESSIONS_dequeue_request (tc.car);
490 GNUNET_free (tc.car);
491 GNUNET_SERVER_receive_done (client, GNUNET_OK);
496 * Functions with this signature are called whenever a complete
497 * message is received by the tokenizer. Used by the 'client_mst' for
498 * dispatching messages from clients to either the SESSION subsystem
499 * or other CLIENT (for loopback).
502 * @param client reservation request ('struct GSC_ClientActiveRequest')
503 * @param message the actual message
506 client_tokenizer_callback (void *cls, void *client,
507 const struct GNUNET_MessageHeader *message)
509 struct TokenizerContext *tc = client;
510 struct GSC_ClientActiveRequest *car = tc->car;
513 memcmp (&car->target, &GSC_my_identity,
514 sizeof (struct GNUNET_PeerIdentity)))
516 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
517 "Delivering message of type %u to myself\n",
518 ntohs (message->type));
519 GSC_CLIENTS_deliver_message (&GSC_my_identity, NULL, 0, message,
520 ntohs (message->size),
521 GNUNET_CORE_OPTION_SEND_FULL_OUTBOUND);
522 GSC_CLIENTS_deliver_message (&GSC_my_identity, NULL, 0, message,
523 sizeof (struct GNUNET_MessageHeader),
524 GNUNET_CORE_OPTION_SEND_HDR_OUTBOUND);
525 GSC_CLIENTS_deliver_message (&GSC_my_identity, NULL, 0, message,
526 ntohs (message->size),
527 GNUNET_CORE_OPTION_SEND_FULL_INBOUND);
528 GSC_CLIENTS_deliver_message (&GSC_my_identity, NULL, 0, message,
529 sizeof (struct GNUNET_MessageHeader),
530 GNUNET_CORE_OPTION_SEND_HDR_INBOUND);
535 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
536 "Delivering message of type %u to %s\n", ntohs (message->type),
537 GNUNET_i2s (&car->target));
539 GSC_CLIENTS_deliver_message (&car->target, NULL, 0, message,
540 ntohs (message->size),
541 GNUNET_CORE_OPTION_SEND_FULL_OUTBOUND);
542 GSC_CLIENTS_deliver_message (&car->target, NULL, 0, message,
543 sizeof (struct GNUNET_MessageHeader),
544 GNUNET_CORE_OPTION_SEND_HDR_OUTBOUND);
545 GSC_SESSIONS_transmit (car, message, tc->cork);
551 * Free client request records.
554 * @param key identity of peer for which this is an active request
555 * @param value the 'struct GSC_ClientActiveRequest' to free
556 * @return GNUNET_YES (continue iteration)
559 destroy_active_client_request (void *cls, const GNUNET_HashCode * key,
562 struct GSC_ClientActiveRequest *car = value;
564 GNUNET_assert (GNUNET_YES ==
565 GNUNET_CONTAINER_multihashmap_remove (car->
566 client_handle->requests,
567 &car->target.hashPubKey,
569 GSC_SESSIONS_dequeue_request (car);
576 * A client disconnected, clean up.
579 * @param client identification of the client
582 handle_client_disconnect (void *cls, struct GNUNET_SERVER_Client *client)
584 struct GSC_Client *c;
589 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
590 "Client %p has disconnected from core service.\n", client);
592 c = find_client (client);
594 return; /* client never sent INIT */
595 GNUNET_CONTAINER_DLL_remove (client_head, client_tail, c);
596 if (c->requests != NULL)
598 GNUNET_CONTAINER_multihashmap_iterate (c->requests,
599 &destroy_active_client_request,
601 GNUNET_CONTAINER_multihashmap_destroy (c->requests);
603 GNUNET_CONTAINER_multihashmap_destroy (c->connectmap);
604 c->connectmap = NULL;
605 GSC_TYPEMAP_remove (c->types, c->tcnt);
608 /* recalculate 'all_client_options' */
609 all_client_options = 0;
610 for (c = client_head; NULL != c ; c = c->next)
611 all_client_options |= c->options;
616 * Tell a client that we are ready to receive the message.
618 * @param car request that is now ready; the responsibility
619 * for the handle remains shared between CLIENTS
620 * and SESSIONS after this call.
623 GSC_CLIENTS_solicit_request (struct GSC_ClientActiveRequest *car)
625 struct GSC_Client *c;
626 struct SendMessageReady smr;
628 c = car->client_handle;
630 GNUNET_CONTAINER_multihashmap_contains (c->connectmap,
631 &car->target.hashPubKey))
633 /* connection has gone down since, drop request */
635 memcmp (&car->target, &GSC_my_identity,
636 sizeof (struct GNUNET_PeerIdentity)));
637 GSC_SESSIONS_dequeue_request (car);
638 GSC_CLIENTS_reject_request (car);
641 smr.header.size = htons (sizeof (struct SendMessageReady));
642 smr.header.type = htons (GNUNET_MESSAGE_TYPE_CORE_SEND_READY);
643 smr.size = htons (car->msize);
644 smr.smr_id = car->smr_id;
645 smr.peer = car->target;
646 send_to_client (c, &smr.header, GNUNET_NO);
651 * Tell a client that we will never be ready to receive the
652 * given message in time (disconnect or timeout).
654 * @param car request that now permanently failed; the
655 * responsibility for the handle is now returned
656 * to CLIENTS (SESSIONS is done with it).
659 GSC_CLIENTS_reject_request (struct GSC_ClientActiveRequest *car)
661 GNUNET_assert (GNUNET_YES ==
662 GNUNET_CONTAINER_multihashmap_remove (car->
663 client_handle->requests,
664 &car->target.hashPubKey,
671 * Notify a particular client about a change to existing connection to
672 * one of our neighbours (check if the client is interested). Called
673 * from 'GSC_SESSIONS_notify_client_about_sessions'.
675 * @param client client to notify
676 * @param neighbour identity of the neighbour that changed status
677 * @param atsi performance information about neighbour
678 * @param atsi_count number of entries in 'ats' array
679 * @param tmap_old previous type map for the neighbour, NULL for disconnect
680 * @param tmap_new updated type map for the neighbour, NULL for disconnect
683 GSC_CLIENTS_notify_client_about_neighbour (struct GSC_Client *client,
684 const struct GNUNET_PeerIdentity
686 const struct GNUNET_ATS_Information
687 *atsi, unsigned int atsi_count,
688 const struct GSC_TypeMap *tmap_old,
689 const struct GSC_TypeMap *tmap_new)
691 struct ConnectNotifyMessage *cnm;
693 char buf[GNUNET_SERVER_MAX_MESSAGE_SIZE - 1];
694 struct GNUNET_ATS_Information *a;
695 struct DisconnectNotifyMessage dcm;
699 old_match = GSC_TYPEMAP_test_match (tmap_old, client->types, client->tcnt);
700 new_match = GSC_TYPEMAP_test_match (tmap_new, client->types, client->tcnt);
701 if (old_match == new_match)
703 GNUNET_assert (old_match ==
704 GNUNET_CONTAINER_multihashmap_contains (client->connectmap,
705 &neighbour->hashPubKey));
706 return; /* no change */
708 if (old_match == GNUNET_NO)
711 GNUNET_assert (GNUNET_NO ==
712 GNUNET_CONTAINER_multihashmap_contains (client->connectmap,
713 &neighbour->hashPubKey));
714 GNUNET_assert (GNUNET_YES ==
715 GNUNET_CONTAINER_multihashmap_put (client->connectmap,
716 &neighbour->hashPubKey,
718 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
720 sizeof (struct ConnectNotifyMessage) +
721 (atsi_count) * sizeof (struct GNUNET_ATS_Information);
722 if (size >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
725 /* recovery strategy: throw away performance data */
727 size = sizeof (struct ConnectNotifyMessage);
729 cnm = (struct ConnectNotifyMessage *) buf;
730 cnm->header.size = htons (size);
731 cnm->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_NOTIFY_CONNECT);
732 cnm->ats_count = htonl (atsi_count);
733 a = (struct GNUNET_ATS_Information *) &cnm[1];
734 memcpy (a, atsi, sizeof (struct GNUNET_ATS_Information) * atsi_count);
736 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending `%s' message to client.\n",
739 cnm->peer = *neighbour;
740 send_to_client (client, &cnm->header, GNUNET_NO);
744 /* send disconnect */
745 GNUNET_assert (GNUNET_YES ==
746 GNUNET_CONTAINER_multihashmap_contains (client->connectmap,
747 &neighbour->hashPubKey));
748 GNUNET_assert (GNUNET_YES ==
749 GNUNET_CONTAINER_multihashmap_remove (client->connectmap,
750 &neighbour->hashPubKey,
752 dcm.header.size = htons (sizeof (struct DisconnectNotifyMessage));
753 dcm.header.type = htons (GNUNET_MESSAGE_TYPE_CORE_NOTIFY_DISCONNECT);
754 dcm.reserved = htonl (0);
755 dcm.peer = *neighbour;
756 send_to_client (client, &dcm.header, GNUNET_NO);
762 * Notify all clients about a change to existing session.
763 * Called from SESSIONS whenever there is a change in sessions
764 * or types processed by the respective peer.
766 * @param neighbour identity of the neighbour that changed status
767 * @param atsi performance information about neighbour
768 * @param atsi_count number of entries in 'ats' array
769 * @param tmap_old previous type map for the neighbour, NULL for disconnect
770 * @param tmap_new updated type map for the neighbour, NULL for disconnect
773 GSC_CLIENTS_notify_clients_about_neighbour (const struct GNUNET_PeerIdentity
775 const struct GNUNET_ATS_Information
776 *atsi, unsigned int atsi_count,
777 const struct GSC_TypeMap *tmap_old,
778 const struct GSC_TypeMap *tmap_new)
780 struct GSC_Client *c;
782 for (c = client_head; c != NULL; c = c->next)
783 GSC_CLIENTS_notify_client_about_neighbour (c, neighbour, atsi, atsi_count,
789 * Deliver P2P message to interested clients. Caller must have checked
790 * that the sending peer actually lists the given message type as one
793 * @param sender peer who sent us the message
794 * @param atsi performance information about neighbour
795 * @param atsi_count number of entries in 'ats' array
796 * @param msg the message
797 * @param msize number of bytes to transmit
798 * @param options options for checking which clients should
799 * receive the message
802 GSC_CLIENTS_deliver_message (const struct GNUNET_PeerIdentity *sender,
803 const struct GNUNET_ATS_Information *atsi,
804 unsigned int atsi_count,
805 const struct GNUNET_MessageHeader *msg,
810 msize + sizeof (struct NotifyTrafficMessage) +
811 atsi_count * sizeof (struct GNUNET_ATS_Information);
813 struct NotifyTrafficMessage *ntm;
814 struct GNUNET_ATS_Information *a;
818 GNUNET_snprintf (buf, sizeof (buf),
819 gettext_noop ("# bytes of messages of type %u received"),
820 (unsigned int) ntohs (msg->type));
821 GNUNET_STATISTICS_update (GSC_stats, buf, msize, GNUNET_NO);
823 if (size >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
826 /* recovery strategy: throw performance data away... */
828 size = msize + sizeof (struct NotifyTrafficMessage);
830 if (! ( (0 != (all_client_options & options)) ||
831 (0 != (options & GNUNET_CORE_OPTION_SEND_FULL_INBOUND)) ))
832 return; /* no client cares about this message notification */
833 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
834 "Core service passes message from `%4s' of type %u to client.\n",
835 GNUNET_i2s (sender), (unsigned int) ntohs (msg->type));
836 GSC_SESSIONS_add_to_typemap (sender, ntohs (msg->type));
837 ntm = (struct NotifyTrafficMessage *) buf;
838 ntm->header.size = htons (size);
839 if (0 != (options & (GNUNET_CORE_OPTION_SEND_FULL_INBOUND | GNUNET_CORE_OPTION_SEND_HDR_INBOUND)))
840 ntm->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_NOTIFY_INBOUND);
842 ntm->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_NOTIFY_OUTBOUND);
843 ntm->ats_count = htonl (atsi_count);
846 memcpy (a, atsi, sizeof (struct GNUNET_ATS_Information) * atsi_count);
847 a[atsi_count].type = htonl (GNUNET_ATS_ARRAY_TERMINATOR);
848 a[atsi_count].value = htonl (0);
849 memcpy (&a[atsi_count + 1], msg, msize);
850 send_to_all_clients (sender, &ntm->header, GNUNET_YES, options,
856 * Initialize clients subsystem.
858 * @param server handle to server clients connect to
861 GSC_CLIENTS_init (struct GNUNET_SERVER_Handle *server)
863 static const struct GNUNET_SERVER_MessageHandler handlers[] = {
864 {&handle_client_init, NULL,
865 GNUNET_MESSAGE_TYPE_CORE_INIT, 0},
866 {&GSC_SESSIONS_handle_client_iterate_peers, NULL,
867 GNUNET_MESSAGE_TYPE_CORE_ITERATE_PEERS,
868 sizeof (struct GNUNET_MessageHeader)},
869 {&GSC_SESSIONS_handle_client_have_peer, NULL,
870 GNUNET_MESSAGE_TYPE_CORE_PEER_CONNECTED,
871 sizeof (struct GNUNET_MessageHeader) +
872 sizeof (struct GNUNET_PeerIdentity)},
873 {&handle_client_send_request, NULL,
874 GNUNET_MESSAGE_TYPE_CORE_SEND_REQUEST,
875 sizeof (struct SendMessageRequest)},
876 {&handle_client_send, NULL,
877 GNUNET_MESSAGE_TYPE_CORE_SEND, 0},
881 /* setup notification */
882 client_mst = GNUNET_SERVER_mst_create (&client_tokenizer_callback, NULL);
884 GNUNET_SERVER_notification_context_create (server, MAX_NOTIFY_QUEUE);
885 GNUNET_SERVER_disconnect_notify (server, &handle_client_disconnect, NULL);
886 GNUNET_SERVER_add_handlers (server, handlers);
891 * Shutdown clients subsystem.
896 struct GSC_Client *c;
898 while (NULL != (c = client_head))
899 handle_client_disconnect (NULL, c->client_handle);
900 if (NULL != notifier)
902 GNUNET_SERVER_notification_context_destroy (notifier);
905 GNUNET_SERVER_mst_destroy (client_mst);
909 /* end of gnunet-service-core_clients.c */