2 This file is part of GNUnet.
3 Copyright (C) 2010-2015 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 transport/gnunet-service-transport_clients.c
23 * @brief communication with clients (core service and monitors)
24 * @author Christian Grothoff
27 #include "gnunet-service-transport_blacklist.h"
28 #include "gnunet-service-transport_clients.h"
29 #include "gnunet-service-transport_hello.h"
30 #include "gnunet-service-transport_neighbours.h"
31 #include "gnunet-service-transport_plugins.h"
32 #include "gnunet-service-transport_validation.h"
33 #include "gnunet-service-transport_manipulation.h"
34 #include "gnunet-service-transport.h"
35 #include "transport.h"
39 * How many messages can we have pending for a given client process
40 * before we start to drop incoming messages? We typically should
41 * have only one client and so this would be the primary buffer for
42 * messages, so the number should be chosen rather generously.
44 * The expectation here is that most of the time the queue is large
45 * enough so that a drop is virtually never required. Note that
46 * this value must be about as large as 'TOTAL_MSGS' in the
47 * 'test_transport_api_reliability.c', otherwise that testcase may
50 #define MAX_PENDING (128 * 1024)
54 * Linked list of messages to be transmitted to the client. Each
55 * entry is followed by the actual message.
57 struct ClientMessageQueueEntry
60 * This is a doubly-linked list.
62 struct ClientMessageQueueEntry *next;
65 * This is a doubly-linked list.
67 struct ClientMessageQueueEntry *prev;
72 * Client connected to the transport service.
74 struct TransportClient
78 * This is a doubly-linked list.
80 struct TransportClient *next;
83 * This is a doubly-linked list.
85 struct TransportClient *prev;
88 * Handle to the client.
90 struct GNUNET_SERVER_Client *client;
93 * Linked list of messages yet to be transmitted to
96 struct ClientMessageQueueEntry *message_queue_head;
99 * Tail of linked list of messages yet to be transmitted to the
102 struct ClientMessageQueueEntry *message_queue_tail;
105 * Current transmit request handle.
107 struct GNUNET_SERVER_TransmitHandle *th;
110 * Length of the list of messages pending for this client.
112 unsigned int message_count;
115 * Is this client interested in payload messages?
122 * Context for address to string operations
124 struct AddressToStringContext
127 * This is a doubly-linked list.
129 struct AddressToStringContext *next;
132 * This is a doubly-linked list.
134 struct AddressToStringContext *prev;
137 * Transmission context
139 struct GNUNET_SERVER_TransmitContext* tc;
144 * Client monitoring changes of active addresses or validations
145 * of our neighbours. Which type is being monitored depends on the
146 * DLL this struct is in.
148 struct MonitoringClient
151 * This is a doubly-linked list.
153 struct MonitoringClient *next;
156 * This is a doubly-linked list.
158 struct MonitoringClient *prev;
161 * Handle to the client.
163 struct GNUNET_SERVER_Client *client;
166 * Peer identity to monitor the addresses of.
167 * Zero to monitor all neighrours.
169 struct GNUNET_PeerIdentity peer;
175 * Head of linked list of all clients to this service.
177 static struct TransportClient *clients_head;
180 * Tail of linked list of all clients to this service.
182 static struct TransportClient *clients_tail;
185 * Head of linked list of all pending address iterations
187 static struct AddressToStringContext *a2s_head;
190 * Tail of linked list of all pending address iterations
192 static struct AddressToStringContext *a2s_tail;
195 * Head of linked list of monitoring clients.
197 static struct MonitoringClient *peer_monitoring_clients_head;
200 * Tail of linked list of monitoring clients.
202 static struct MonitoringClient *peer_monitoring_clients_tail;
205 * Head of linked list of validation monitoring clients.
207 static struct MonitoringClient *val_monitoring_clients_head;
210 * Tail of linked list of validation monitoring clients.
212 static struct MonitoringClient *val_monitoring_clients_tail;
215 * Notification context, to send updates on changes to active addresses
218 static struct GNUNET_SERVER_NotificationContext *peer_nc;
221 * Notification context, to send updates on changes to active addresses
224 static struct GNUNET_SERVER_NotificationContext *val_nc;
227 * Notification context, to send updates on changes to active plugin
230 static struct GNUNET_SERVER_NotificationContext *plugin_nc;
233 * Plugin monitoring client we are currently syncing, NULL if all
234 * monitoring clients are in sync.
236 static struct GNUNET_SERVER_Client *sync_client;
239 * Peer identity that is all zeros, used as a way to indicate
240 * "all peers". Used for comparissons.
242 static struct GNUNET_PeerIdentity all_zeros;
246 * Find the internal handle associated with the given client handle.
248 * @param client server's client handle to look up
249 * @return internal client handle
251 static struct TransportClient *
252 lookup_client (struct GNUNET_SERVER_Client *client)
254 return GNUNET_SERVER_client_get_user_context (client,
255 struct TransportClient);
260 * Create the internal handle for the given server client handle.
262 * @param client server's client handle to create our internal handle for
263 * @return fresh internal client handle
265 static struct TransportClient *
266 setup_client (struct GNUNET_SERVER_Client *client)
268 struct TransportClient *tc;
270 GNUNET_assert (NULL == lookup_client (client));
271 tc = GNUNET_new (struct TransportClient);
273 GNUNET_SERVER_client_set_user_context (client, tc);
274 GNUNET_CONTAINER_DLL_insert (clients_head,
277 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
278 "Client %p connected\n",
285 * Find the handle to the monitoring client associated with the given
288 * @param head the head of the client queue to look in
289 * @param client server's client handle to look up
290 * @return handle to the monitoring client
292 static struct MonitoringClient *
293 lookup_monitoring_client (struct MonitoringClient *head,
294 struct GNUNET_SERVER_Client *client)
296 struct MonitoringClient *mc;
298 for (mc = head; NULL != mc; mc = mc->next)
299 if (mc->client == client)
306 * Setup a new monitoring client using the given server client handle and
309 * @param client server's client handle to create our internal handle for
310 * @param peer identity of the peer to monitor the addresses of,
311 * zero to monitor all neighrours.
312 * @return handle to the new monitoring client
314 static struct MonitoringClient *
315 setup_peer_monitoring_client (struct GNUNET_SERVER_Client *client,
316 const struct GNUNET_PeerIdentity *peer)
318 struct MonitoringClient *mc;
320 GNUNET_assert (NULL ==
321 lookup_monitoring_client (peer_monitoring_clients_head,
323 mc = GNUNET_new (struct MonitoringClient);
326 GNUNET_CONTAINER_DLL_insert (peer_monitoring_clients_head,
327 peer_monitoring_clients_tail,
329 GNUNET_SERVER_client_mark_monitor (client);
330 GNUNET_SERVER_notification_context_add (peer_nc,
332 if (0 != memcmp (peer,
334 sizeof (struct GNUNET_PeerIdentity)))
335 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
336 "Client %p started monitoring of the peer `%s'\n",
340 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
341 "Client %p started monitoring all peers\n",
348 * Setup a new monitoring client using the given server client handle and
351 * @param client server's client handle to create our internal handle for
352 * @param peer identity of the peer to monitor the addresses of,
353 * zero to monitor all neighrours.
354 * @return handle to the new monitoring client
356 static struct MonitoringClient *
357 setup_val_monitoring_client (struct GNUNET_SERVER_Client *client,
358 struct GNUNET_PeerIdentity *peer)
360 struct MonitoringClient *mc;
362 GNUNET_assert (NULL ==
363 lookup_monitoring_client (val_monitoring_clients_head,
365 mc = GNUNET_new (struct MonitoringClient);
368 GNUNET_CONTAINER_DLL_insert (val_monitoring_clients_head,
369 val_monitoring_clients_tail,
371 GNUNET_SERVER_notification_context_add (val_nc, client);
373 if (0 != memcmp (peer,
375 sizeof (struct GNUNET_PeerIdentity)))
376 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
377 "Client %p started monitoring of the peer `%s'\n",
381 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
382 "Client %p started monitoring all peers\n",
389 * Function called to notify a client about the socket being ready to
390 * queue more data. @a buf will be NULL and @a size zero if the socket
391 * was closed for writing in the meantime.
394 * @param size number of bytes available in @a buf
395 * @param buf where the callee should write the message
396 * @return number of bytes written to @a buf
399 transmit_to_client_callback (void *cls,
403 struct TransportClient *tc = cls;
404 struct ClientMessageQueueEntry *q;
405 const struct GNUNET_MessageHeader *msg;
413 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
414 "Transmission to client failed, closing connection.\n");
419 while (NULL != (q = tc->message_queue_head))
421 msg = (const struct GNUNET_MessageHeader *) &q[1];
422 msize = ntohs (msg->size);
423 if (msize + tsize > size)
425 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
426 "Transmitting message of type %u to client %p.\n",
429 GNUNET_CONTAINER_DLL_remove (tc->message_queue_head,
430 tc->message_queue_tail,
433 memcpy (&cbuf[tsize], msg, msize);
439 GNUNET_assert (msize >= sizeof (struct GNUNET_MessageHeader));
441 GNUNET_SERVER_notify_transmit_ready (tc->client, msize,
442 GNUNET_TIME_UNIT_FOREVER_REL,
443 &transmit_to_client_callback, tc);
444 GNUNET_assert (NULL != tc->th);
451 * Queue the given message for transmission to the given client
453 * @param tc target of the message
454 * @param msg message to transmit
455 * @param may_drop #GNUNET_YES if the message can be dropped
458 unicast (struct TransportClient *tc,
459 const struct GNUNET_MessageHeader *msg,
462 struct ClientMessageQueueEntry *q;
470 if ( (tc->message_count >= MAX_PENDING) &&
471 (GNUNET_YES == may_drop) )
473 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
474 "Dropping message of type %u and size %u, have %u/%u messages pending\n",
479 GNUNET_STATISTICS_update (GST_stats,
481 ("# messages dropped due to slow client"), 1,
485 msize = ntohs (msg->size);
486 GNUNET_assert (msize >= sizeof (struct GNUNET_MessageHeader));
487 q = GNUNET_malloc (sizeof (struct ClientMessageQueueEntry) + msize);
488 memcpy (&q[1], msg, msize);
489 GNUNET_CONTAINER_DLL_insert_tail (tc->message_queue_head,
490 tc->message_queue_tail,
496 GNUNET_SERVER_notify_transmit_ready (tc->client, msize,
497 GNUNET_TIME_UNIT_FOREVER_REL,
498 &transmit_to_client_callback, tc);
499 GNUNET_assert (NULL != tc->th);
504 * Called whenever a client is disconnected. Frees our
505 * resources associated with that client.
507 * @param cls closure, NULL
508 * @param client identification of the client
511 client_disconnect_notification (void *cls,
512 struct GNUNET_SERVER_Client *client)
514 struct TransportClient *tc;
515 struct MonitoringClient *mc;
516 struct ClientMessageQueueEntry *mqe;
520 mc = lookup_monitoring_client (peer_monitoring_clients_head,
524 GNUNET_CONTAINER_DLL_remove (peer_monitoring_clients_head,
525 peer_monitoring_clients_tail,
529 mc = lookup_monitoring_client (val_monitoring_clients_head,
533 GNUNET_CONTAINER_DLL_remove (val_monitoring_clients_head,
534 val_monitoring_clients_tail,
538 tc = lookup_client (client);
541 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
542 "Client %p disconnected, cleaning up.\n",
544 while (NULL != (mqe = tc->message_queue_head))
546 GNUNET_CONTAINER_DLL_remove (tc->message_queue_head,
547 tc->message_queue_tail,
552 GNUNET_CONTAINER_DLL_remove (clients_head,
555 GNUNET_SERVER_client_set_user_context (client, NULL);
558 GNUNET_SERVER_notify_transmit_ready_cancel (tc->th);
561 GNUNET_break (0 == tc->message_count);
567 * Function called for each of our connected neighbours. Notify the
568 * client about the existing neighbour.
570 * @param cls the `struct TransportClient *` to notify
571 * @param peer identity of the neighbour
572 * @param address the address
573 * @param state the current state of the peer
574 * @param state_timeout the time out for the state
575 * @param bandwidth_in inbound bandwidth in NBO
576 * @param bandwidth_out outbound bandwidth in NBO
579 notify_client_about_neighbour (void *cls,
580 const struct GNUNET_PeerIdentity *peer,
581 const struct GNUNET_HELLO_Address *address,
582 enum GNUNET_TRANSPORT_PeerState state,
583 struct GNUNET_TIME_Absolute state_timeout,
584 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in,
585 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out)
587 struct TransportClient *tc = cls;
588 struct ConnectInfoMessage cim;
590 if (GNUNET_NO == GST_neighbours_test_connected (peer))
592 cim.header.size = htons (sizeof (struct ConnectInfoMessage));
593 cim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
595 cim.quota_in = bandwidth_in;
596 cim.quota_out = bandwidth_out;
597 unicast (tc, &cim.header, GNUNET_NO);
602 * Initialize a normal client. We got a start message from this
603 * client, add him to the list of clients for broadcasting of inbound
607 * @param client the client
608 * @param message the start message that was sent
611 clients_handle_start (void *cls,
612 struct GNUNET_SERVER_Client *client,
613 const struct GNUNET_MessageHeader *message)
615 const struct StartMessage *start;
616 const struct GNUNET_MessageHeader *hello;
617 struct TransportClient *tc;
620 tc = lookup_client (client);
623 /* got 'start' twice from the same client, not allowed */
625 GNUNET_SERVER_receive_done (client,
629 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
630 "Client %p sent START\n",
632 start = (const struct StartMessage *) message;
633 options = ntohl (start->options);
634 if ((0 != (1 & options)) &&
636 memcmp (&start->self,
638 sizeof (struct GNUNET_PeerIdentity))))
640 /* client thinks this is a different peer, reject */
642 GNUNET_SERVER_receive_done (client,
646 tc = setup_client (client);
647 tc->send_payload = (0 != (2 & options));
648 hello = GST_hello_get ();
651 /* We are during startup and should have no neighbours, hence
652 iteration with NULL must work. The HELLO will be sent to
653 all clients once it has been created, so this should happen
654 next anyway, and certainly before we get neighbours. */
655 GST_neighbours_iterate (NULL, NULL);
662 GST_neighbours_iterate (¬ify_client_about_neighbour,
665 GNUNET_SERVER_receive_done (client,
671 * Client sent us a HELLO. Process the request.
674 * @param client the client
675 * @param message the HELLO message
678 clients_handle_hello (void *cls,
679 struct GNUNET_SERVER_Client *client,
680 const struct GNUNET_MessageHeader *message)
682 GST_validation_handle_hello (message);
683 GNUNET_SERVER_receive_done (client, GNUNET_OK);
688 * Closure for #handle_send_transmit_continuation()
690 struct SendTransmitContinuationContext
693 * Client that made the request.
695 struct GNUNET_SERVER_Client *client;
698 * Peer that was the target.
700 struct GNUNET_PeerIdentity target;
705 * Function called after the transmission is done. Notify the client that it is
706 * OK to send the next message.
709 * @param success #GNUNET_OK on success, #GNUNET_NO on failure, #GNUNET_SYSERR if we're not connected
710 * @param bytes_payload bytes payload sent
711 * @param bytes_on_wire bytes sent on wire
714 handle_send_transmit_continuation (void *cls,
716 size_t bytes_payload,
717 size_t bytes_on_wire)
719 struct SendTransmitContinuationContext *stcc = cls;
720 struct SendOkMessage send_ok_msg;
722 send_ok_msg.header.size = htons (sizeof (send_ok_msg));
723 send_ok_msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK);
724 send_ok_msg.bytes_msg = htonl (bytes_payload);
725 send_ok_msg.bytes_physical = htonl (bytes_on_wire);
726 send_ok_msg.success = htonl (success);
727 send_ok_msg.peer = stcc->target;
728 GST_clients_unicast (stcc->client,
731 GNUNET_SERVER_client_drop (stcc->client);
737 * Client asked for transmission to a peer. Process the request.
740 * @param client the client
741 * @param message the send message that was sent
744 clients_handle_send (void *cls,
745 struct GNUNET_SERVER_Client *client,
746 const struct GNUNET_MessageHeader *message)
748 const struct OutboundMessage *obm;
749 const struct GNUNET_MessageHeader *obmm;
750 struct SendTransmitContinuationContext *stcc;
753 struct TransportClient *tc;
755 tc = lookup_client (client);
758 /* client asked for transmission before 'START' */
760 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
764 size = ntohs (message->size);
766 sizeof (struct OutboundMessage) + sizeof (struct GNUNET_MessageHeader))
769 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
772 obm = (const struct OutboundMessage *) message;
773 obmm = (const struct GNUNET_MessageHeader *) &obm[1];
774 msize = size - sizeof (struct OutboundMessage);
775 if (msize < sizeof (struct GNUNET_MessageHeader))
778 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
782 if (GNUNET_NO == GST_neighbours_test_connected (&obm->peer))
784 /* not connected, not allowed to send; can happen due to asynchronous operations */
785 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
786 "Could not send message to peer `%s': not connected\n",
787 GNUNET_i2s (&obm->peer));
788 GNUNET_STATISTICS_update (GST_stats,
790 ("# bytes payload dropped (other peer was not connected)"),
792 GNUNET_SERVER_receive_done (client, GNUNET_OK);
795 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
796 "Received `%s' request from client with target `%4s' and first message of type %u and total size %u\n",
798 GNUNET_i2s (&obm->peer),
801 GNUNET_SERVER_receive_done (client, GNUNET_OK);
802 stcc = GNUNET_new (struct SendTransmitContinuationContext);
803 stcc->target = obm->peer;
804 stcc->client = client;
805 GNUNET_SERVER_client_keep (client);
806 GST_manipulation_send (&obm->peer, obmm, msize,
807 GNUNET_TIME_relative_ntoh (obm->timeout),
808 &handle_send_transmit_continuation, stcc);
813 * Handle request connect message
815 * @param cls closure (always NULL)
816 * @param client identification of the client
817 * @param message the actual message
820 clients_handle_request_connect (void *cls,
821 struct GNUNET_SERVER_Client *client,
822 const struct GNUNET_MessageHeader *message)
824 const struct TransportRequestConnectMessage *trcm;
826 trcm = (const struct TransportRequestConnectMessage *) message;
827 GNUNET_break (0 == ntohl (trcm->reserved));
828 GNUNET_STATISTICS_update (GST_stats,
830 ("# REQUEST CONNECT messages received"), 1,
832 if (0 == memcmp (&trcm->peer,
834 sizeof (struct GNUNET_PeerIdentity)))
837 GNUNET_SERVER_receive_done (client, GNUNET_OK);
840 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
841 "Received a request connect message for peer `%s'\n",
842 GNUNET_i2s (&trcm->peer));
843 GST_neighbours_try_connect (&trcm->peer);
844 GNUNET_SERVER_receive_done (client, GNUNET_OK);
849 * Handle request disconnect message
851 * @param cls closure (always NULL)
852 * @param client identification of the client
853 * @param message the actual message
856 clients_handle_request_disconnect (void *cls,
857 struct GNUNET_SERVER_Client *client,
858 const struct GNUNET_MessageHeader *message)
860 const struct TransportRequestDisconnectMessage *trdm;
862 trdm = (const struct TransportRequestDisconnectMessage *) message;
863 GNUNET_break (0 == ntohl (trdm->reserved));
864 GNUNET_STATISTICS_update (GST_stats,
866 ("# REQUEST DISCONNECT messages received"), 1,
868 if (0 == memcmp (&trdm->peer,
870 sizeof (struct GNUNET_PeerIdentity)))
873 GNUNET_SERVER_receive_done (client, GNUNET_OK);
876 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
877 "Received a request disconnect message for peer `%s'\n",
878 GNUNET_i2s (&trdm->peer));
879 (void) GST_neighbours_force_disconnect (&trdm->peer);
880 GNUNET_SERVER_receive_done (client, GNUNET_OK);
885 * Take the given address and append it to the set of results sent back to
886 * the client. This function may be called serveral times for a single
887 * conversion. The last invocation will be with a @a address of
888 * NULL and a @a res of #GNUNET_OK. Thus, to indicate conversion
889 * errors, the callback might be called first with @a address NULL and
890 * @a res being #GNUNET_SYSERR. In that case, there will still be a
891 * subsequent call later with @a address NULL and @a res #GNUNET_OK.
893 * @param cls the transmission context used (`struct GNUNET_SERVER_TransmitContext *`)
894 * @param buf text to transmit (contains the human-readable address, or NULL)
895 * @param res #GNUNET_OK if conversion was successful, #GNUNET_SYSERR on error,
899 transmit_address_to_client (void *cls,
903 struct AddressToStringContext *actx = cls;
904 struct AddressToStringResultMessage *atsm;
908 GNUNET_assert ( (GNUNET_OK == res) ||
909 (GNUNET_SYSERR == res) );
912 len = sizeof (struct AddressToStringResultMessage);
913 atsm = GNUNET_malloc (len);
914 atsm->header.size = ntohs (len);
915 atsm->header.type = ntohs (GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_TO_STRING_REPLY);
916 if (GNUNET_OK == res)
918 /* this was the last call, transmit */
919 atsm->res = htonl (GNUNET_OK);
920 atsm->addr_len = htonl (0);
921 GNUNET_SERVER_transmit_context_append_message (actx->tc,
922 (const struct GNUNET_MessageHeader *) atsm);
923 GNUNET_SERVER_transmit_context_run (actx->tc,
924 GNUNET_TIME_UNIT_FOREVER_REL);
925 GNUNET_CONTAINER_DLL_remove (a2s_head,
932 if (GNUNET_SYSERR == res)
934 /* address conversion failed, but there will be more callbacks */
935 atsm->res = htonl (GNUNET_SYSERR);
936 atsm->addr_len = htonl (0);
937 GNUNET_SERVER_transmit_context_append_message (actx->tc,
938 (const struct GNUNET_MessageHeader *) atsm);
943 GNUNET_assert (GNUNET_OK == res);
944 /* succesful conversion, append*/
945 slen = strlen (buf) + 1;
946 len = sizeof (struct AddressToStringResultMessage) + slen;
947 atsm = GNUNET_malloc (len);
948 atsm->header.size = ntohs (len);
949 atsm->header.type = ntohs (GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_TO_STRING_REPLY);
950 atsm->res = htonl (GNUNET_YES);
951 atsm->addr_len = htonl (slen);
955 GNUNET_SERVER_transmit_context_append_message (actx->tc,
956 (const struct GNUNET_MessageHeader *) atsm);
962 * Client asked to resolve an address. Process the request.
965 * @param client the client
966 * @param message the resolution request
969 clients_handle_address_to_string (void *cls,
970 struct GNUNET_SERVER_Client *client,
971 const struct GNUNET_MessageHeader *message)
973 const struct AddressLookupMessage *alum;
974 struct GNUNET_TRANSPORT_PluginFunctions *papi;
975 const char *plugin_name;
977 uint32_t address_len;
979 struct GNUNET_SERVER_TransmitContext *tc;
980 struct AddressToStringContext *actx;
981 struct AddressToStringResultMessage atsm;
982 struct GNUNET_TIME_Relative rtimeout;
985 size = ntohs (message->size);
986 if (size < sizeof (struct AddressLookupMessage))
989 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
992 alum = (const struct AddressLookupMessage *) message;
993 address_len = ntohs (alum->addrlen);
994 if (size <= sizeof (struct AddressLookupMessage) + address_len)
997 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1000 address = (const char *) &alum[1];
1001 plugin_name = (const char *) &address[address_len];
1002 if ('\0' != plugin_name[size - sizeof (struct AddressLookupMessage) - address_len - 1])
1005 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1008 rtimeout = GNUNET_TIME_relative_ntoh (alum->timeout);
1009 numeric = ntohs (alum->numeric_only);
1010 tc = GNUNET_SERVER_transmit_context_create (client);
1011 papi = GST_plugins_printer_find (plugin_name);
1014 atsm.header.size = ntohs (sizeof (struct AddressToStringResultMessage));
1015 atsm.header.type = ntohs (GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_TO_STRING_REPLY);
1016 atsm.res = htonl (GNUNET_SYSERR);
1017 atsm.addr_len = htonl (0);
1018 GNUNET_SERVER_transmit_context_append_message (tc,
1020 atsm.header.size = ntohs (sizeof (struct AddressToStringResultMessage));
1021 atsm.header.type = ntohs (GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_TO_STRING_REPLY);
1022 atsm.res = htonl (GNUNET_OK);
1023 atsm.addr_len = htonl (0);
1024 GNUNET_SERVER_transmit_context_append_message (tc,
1026 GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
1029 actx = GNUNET_new (struct AddressToStringContext);
1031 GNUNET_CONTAINER_DLL_insert (a2s_head, a2s_tail, actx);
1032 GNUNET_SERVER_disable_receive_done_warning (client);
1033 papi->address_pretty_printer (papi->cls,
1035 address, address_len,
1038 &transmit_address_to_client,
1044 * Compose #PeerIterateResponseMessage using the given peer and address.
1046 * @param peer identity of the peer
1047 * @param address the address, NULL on disconnect
1048 * @return composed message
1050 static struct PeerIterateResponseMessage *
1051 compose_address_iterate_response_message (const struct GNUNET_PeerIdentity *peer,
1052 const struct GNUNET_HELLO_Address *address)
1054 struct PeerIterateResponseMessage *msg;
1060 GNUNET_assert (NULL != peer);
1061 if (NULL != address)
1063 tlen = strlen (address->transport_name) + 1;
1064 alen = address->address_length;
1071 size = (sizeof (struct PeerIterateResponseMessage) + alen + tlen);
1072 msg = GNUNET_malloc (size);
1073 msg->header.size = htons (size);
1075 htons (GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_PEER_RESPONSE);
1076 msg->reserved = htonl (0);
1078 msg->addrlen = htonl (alen);
1079 msg->pluginlen = htonl (tlen);
1081 if (NULL != address)
1083 msg->local_address_info = htonl((uint32_t) address->local_info);
1084 addr = (char *) &msg[1];
1085 memcpy (addr, address->address, alen);
1086 memcpy (&addr[alen], address->transport_name, tlen);
1093 * Compose #PeerIterateResponseMessage using the given peer and address.
1095 * @param peer identity of the peer
1096 * @param address the address, NULL on disconnect
1097 * @return composed message
1099 static struct ValidationIterateResponseMessage *
1100 compose_validation_iterate_response_message (const struct GNUNET_PeerIdentity *peer,
1101 const struct GNUNET_HELLO_Address *address)
1103 struct ValidationIterateResponseMessage *msg;
1109 GNUNET_assert (NULL != peer);
1110 if (NULL != address)
1112 tlen = strlen (address->transport_name) + 1;
1113 alen = address->address_length;
1120 size = (sizeof (struct ValidationIterateResponseMessage) + alen + tlen);
1121 msg = GNUNET_malloc (size);
1122 msg->header.size = htons (size);
1124 htons (GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_VALIDATION_RESPONSE);
1125 msg->reserved = htonl (0);
1127 msg->addrlen = htonl (alen);
1128 msg->pluginlen = htonl (tlen);
1130 if (NULL != address)
1132 msg->local_address_info = htonl((uint32_t) address->local_info);
1133 addr = (char *) &msg[1];
1134 memcpy (addr, address->address, alen);
1135 memcpy (&addr[alen], address->transport_name, tlen);
1142 * Context for #send_validation_information() and
1143 * #send_peer_information().
1145 struct IterationContext
1148 * Context to use for the transmission.
1150 struct GNUNET_SERVER_TransmitContext *tc;
1153 * Which peers do we care about?
1155 struct GNUNET_PeerIdentity id;
1158 * #GNUNET_YES if @e id should be ignored because we want all peers.
1165 * Output information of validation entries to the given client.
1167 * @param cls the `struct IterationContext *`
1168 * @param address the address
1169 * @param last_validation point in time when last validation was performed
1170 * @param valid_until point in time how long address is valid
1171 * @param next_validation point in time when next validation will be performed
1172 * @param state state of validation notification
1175 send_validation_information (void *cls,
1176 const struct GNUNET_HELLO_Address *address,
1177 struct GNUNET_TIME_Absolute last_validation,
1178 struct GNUNET_TIME_Absolute valid_until,
1179 struct GNUNET_TIME_Absolute next_validation,
1180 enum GNUNET_TRANSPORT_ValidationState state)
1182 struct IterationContext *pc = cls;
1183 struct ValidationIterateResponseMessage *msg;
1185 if ( (GNUNET_YES != pc->all) &&
1186 (0 != memcmp (&address->peer, &pc->id, sizeof (pc->id))) )
1188 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1189 "Sending information about for validation entry for peer `%s' using address `%s'\n",
1190 GNUNET_i2s (&address->peer),
1191 (NULL != address) ? GST_plugins_a2s (address) : "<none>");
1192 msg = compose_validation_iterate_response_message (&address->peer, address);
1193 msg->last_validation = GNUNET_TIME_absolute_hton(last_validation);
1194 msg->valid_until = GNUNET_TIME_absolute_hton(valid_until);
1195 msg->next_validation = GNUNET_TIME_absolute_hton(next_validation);
1196 msg->state = htonl ((uint32_t) state);
1197 GNUNET_SERVER_transmit_context_append_message (pc->tc, &msg->header);
1203 * Output information of neighbours to the given client.
1205 * @param cls the `struct PeerIterationContext *`
1206 * @param peer identity of the neighbour
1207 * @param address the address
1208 * @param state current state this peer is in
1209 * @param state_timeout timeout for the current state of the peer
1210 * @param bandwidth_in inbound quota in NBO
1211 * @param bandwidth_out outbound quota in NBO
1214 send_peer_information (void *cls,
1215 const struct GNUNET_PeerIdentity *peer,
1216 const struct GNUNET_HELLO_Address *address,
1217 enum GNUNET_TRANSPORT_PeerState state,
1218 struct GNUNET_TIME_Absolute state_timeout,
1219 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in,
1220 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out)
1222 struct IterationContext *pc = cls;
1223 struct PeerIterateResponseMessage *msg;
1225 if ( (GNUNET_YES != pc->all) &&
1226 (0 != memcmp (peer, &pc->id, sizeof (pc->id))) )
1228 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1229 "Sending information about `%s' using address `%s' in state `%s'\n",
1231 (NULL != address) ? GST_plugins_a2s (address) : "<none>",
1232 GNUNET_TRANSPORT_ps2s (state));
1233 msg = compose_address_iterate_response_message (peer, address);
1234 msg->state = htonl (state);
1235 msg->state_timeout = GNUNET_TIME_absolute_hton(state_timeout);
1236 GNUNET_SERVER_transmit_context_append_message (pc->tc, &msg->header);
1242 * Client asked to obtain information about a specific or all peers
1243 * Process the request.
1246 * @param client the client
1247 * @param message the peer address information request
1250 clients_handle_monitor_peers (void *cls,
1251 struct GNUNET_SERVER_Client *client,
1252 const struct GNUNET_MessageHeader *message)
1254 struct GNUNET_SERVER_TransmitContext *tc;
1255 const struct PeerMonitorMessage *msg;
1256 struct IterationContext pc;
1258 msg = (const struct PeerMonitorMessage *) message;
1259 if ( (GNUNET_YES != ntohl (msg->one_shot)) &&
1260 (NULL != lookup_monitoring_client (peer_monitoring_clients_head,
1264 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1267 GNUNET_SERVER_disable_receive_done_warning (client);
1268 GNUNET_SERVER_client_mark_monitor (client);
1269 pc.tc = tc = GNUNET_SERVER_transmit_context_create (client);
1271 /* Send initial list */
1272 if (0 == memcmp (&msg->peer,
1274 sizeof (struct GNUNET_PeerIdentity)))
1276 /* iterate over all neighbours */
1277 pc.all = GNUNET_YES;
1282 /* just return one neighbour */
1286 GST_neighbours_iterate (&send_peer_information, &pc);
1288 if (GNUNET_YES != ntohl (msg->one_shot))
1290 setup_peer_monitoring_client (client, &msg->peer);
1294 GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
1295 GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_PEER_RESPONSE);
1298 GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
1303 * Client asked to obtain information about a specific or all validation
1307 * @param client the client
1308 * @param message the peer address information request
1311 clients_handle_monitor_validation (void *cls,
1312 struct GNUNET_SERVER_Client *client,
1313 const struct GNUNET_MessageHeader *message)
1315 struct GNUNET_SERVER_TransmitContext *tc;
1316 struct PeerMonitorMessage *msg;
1317 struct IterationContext pc;
1319 if (ntohs (message->type) != GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_VALIDATION_REQUEST)
1322 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1325 if (ntohs (message->size) != sizeof (struct ValidationMonitorMessage))
1328 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1331 msg = (struct PeerMonitorMessage *) message;
1332 if ( (GNUNET_YES != ntohl (msg->one_shot)) &&
1333 (NULL != lookup_monitoring_client (val_monitoring_clients_head, client)) )
1336 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1339 GNUNET_SERVER_disable_receive_done_warning (client);
1340 GNUNET_SERVER_client_mark_monitor (client);
1341 pc.tc = tc = GNUNET_SERVER_transmit_context_create (client);
1343 /* Send initial list */
1344 if (0 == memcmp (&msg->peer,
1346 sizeof (struct GNUNET_PeerIdentity)))
1348 /* iterate over all neighbours */
1349 pc.all = GNUNET_YES;
1354 /* just return one neighbour */
1358 GST_validation_iterate (&send_validation_information,
1361 if (GNUNET_YES != ntohl (msg->one_shot))
1363 setup_val_monitoring_client (client, &msg->peer);
1367 GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
1368 GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_VALIDATION_RESPONSE);
1370 GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
1375 * Function called by the plugin with information about the
1376 * current sessions managed by the plugin (for monitoring).
1378 * @param cls closure
1379 * @param session session handle this information is about,
1380 * NULL to indicate that we are "in sync" (initial
1381 * iteration complete)
1382 * @param info information about the state of the session,
1383 * NULL if @a session is also NULL and we are
1384 * merely signalling that the initial iteration is over
1387 plugin_session_info_cb (void *cls,
1388 struct Session *session,
1389 const struct GNUNET_TRANSPORT_SessionInfo *info)
1391 struct TransportPluginMonitorMessage *msg;
1392 struct GNUNET_MessageHeader sync;
1399 if (0 == GNUNET_SERVER_notification_context_get_size (plugin_nc))
1401 fprintf (stderr, "UNSUB!\n");
1402 GST_plugins_monitor_subscribe (NULL, NULL);
1405 if ( (NULL == info) &&
1408 /* end of initial iteration */
1409 if (NULL != sync_client)
1411 sync.size = htons (sizeof (struct GNUNET_MessageHeader));
1412 sync.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_PLUGIN_SYNC);
1413 GNUNET_SERVER_notification_context_unicast (plugin_nc,
1421 GNUNET_assert (NULL != info);
1422 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1423 "Plugin event for peer %s on transport %s\n",
1424 GNUNET_i2s (&info->address->peer),
1425 info->address->transport_name);
1426 slen = strlen (info->address->transport_name) + 1;
1427 alen = info->address->address_length;
1428 size = sizeof (struct TransportPluginMonitorMessage) + slen + alen;
1429 if (size > UINT16_MAX)
1434 msg = GNUNET_malloc (size);
1435 msg->header.size = htons (size);
1436 msg->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_PLUGIN_EVENT);
1437 msg->session_state = htons ((uint16_t) info->state);
1438 msg->is_inbound = htons ((int16_t) info->is_inbound);
1439 msg->msgs_pending = htonl (info->num_msg_pending);
1440 msg->bytes_pending = htonl (info->num_bytes_pending);
1441 msg->timeout = GNUNET_TIME_absolute_hton (info->session_timeout);
1442 msg->delay = GNUNET_TIME_absolute_hton (info->receive_delay);
1443 msg->peer = info->address->peer;
1444 msg->session_id = (uint64_t) (intptr_t) session;
1445 msg->plugin_name_len = htons (slen);
1446 msg->plugin_address_len = htons (alen);
1447 name = (char *) &msg[1];
1448 memcpy (name, info->address->transport_name, slen);
1450 memcpy (addr, info->address->address, alen);
1451 if (NULL != sync_client)
1452 GNUNET_SERVER_notification_context_unicast (plugin_nc,
1457 GNUNET_SERVER_notification_context_broadcast (plugin_nc,
1465 * Client asked to obtain information about all plugin connections.
1468 * @param client the client
1469 * @param message the peer address information request
1472 clients_handle_monitor_plugins (void *cls,
1473 struct GNUNET_SERVER_Client *client,
1474 const struct GNUNET_MessageHeader *message)
1476 GNUNET_SERVER_client_mark_monitor (client);
1477 GNUNET_SERVER_disable_receive_done_warning (client);
1478 GNUNET_SERVER_notification_context_add (plugin_nc, client);
1479 sync_client = client;
1480 GST_plugins_monitor_subscribe (&plugin_session_info_cb, NULL);
1485 * Start handling requests from clients.
1487 * @param server server used to accept clients from.
1490 GST_clients_start (struct GNUNET_SERVER_Handle *server)
1492 static const struct GNUNET_SERVER_MessageHandler handlers[] = {
1493 {&clients_handle_start, NULL,
1494 GNUNET_MESSAGE_TYPE_TRANSPORT_START, sizeof (struct StartMessage)},
1495 {&clients_handle_hello, NULL,
1496 GNUNET_MESSAGE_TYPE_HELLO, 0},
1497 {&clients_handle_send, NULL,
1498 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND, 0},
1499 {&clients_handle_request_connect, NULL,
1500 GNUNET_MESSAGE_TYPE_TRANSPORT_REQUEST_CONNECT,
1501 sizeof (struct TransportRequestConnectMessage)},
1502 {&clients_handle_request_disconnect, NULL,
1503 GNUNET_MESSAGE_TYPE_TRANSPORT_REQUEST_DISCONNECT,
1504 sizeof (struct TransportRequestDisconnectMessage)},
1505 {&clients_handle_address_to_string, NULL,
1506 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_TO_STRING, 0},
1507 {&clients_handle_monitor_peers, NULL,
1508 GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_PEER_REQUEST,
1509 sizeof (struct PeerMonitorMessage)},
1510 {&clients_handle_monitor_validation, NULL,
1511 GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_VALIDATION_REQUEST,
1512 sizeof (struct ValidationMonitorMessage)},
1513 {&GST_blacklist_handle_init, NULL,
1514 GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_INIT,
1515 sizeof (struct GNUNET_MessageHeader)},
1516 {&GST_blacklist_handle_reply, NULL,
1517 GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_REPLY,
1518 sizeof (struct BlacklistMessage)},
1519 {&GST_manipulation_set_metric, NULL,
1520 GNUNET_MESSAGE_TYPE_TRANSPORT_TRAFFIC_METRIC, 0},
1521 {&clients_handle_monitor_plugins, NULL,
1522 GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_PLUGIN_START,
1523 sizeof (struct GNUNET_MessageHeader) },
1526 peer_nc = GNUNET_SERVER_notification_context_create (server, 0);
1527 val_nc = GNUNET_SERVER_notification_context_create (server, 0);
1528 plugin_nc = GNUNET_SERVER_notification_context_create (server, 0);
1529 GNUNET_SERVER_add_handlers (server, handlers);
1530 GNUNET_SERVER_disconnect_notify (server,
1531 &client_disconnect_notification,
1537 * Stop processing clients.
1542 struct AddressToStringContext *cur;
1544 while (NULL != (cur = a2s_head))
1546 GNUNET_SERVER_transmit_context_destroy (cur->tc, GNUNET_NO);
1547 GNUNET_CONTAINER_DLL_remove (a2s_head, a2s_tail, cur);
1550 if (NULL != peer_nc)
1552 GNUNET_SERVER_notification_context_destroy (peer_nc);
1557 GNUNET_SERVER_notification_context_destroy (val_nc);
1560 if (NULL != plugin_nc)
1562 GNUNET_SERVER_notification_context_destroy (plugin_nc);
1569 * Broadcast the given message to all of our clients.
1571 * @param msg message to broadcast
1572 * @param may_drop #GNUNET_YES if the message can be dropped / is payload
1575 GST_clients_broadcast (const struct GNUNET_MessageHeader *msg,
1578 struct TransportClient *tc;
1580 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1581 "Asked to broadcast message of type %u with %u bytes\n",
1582 (unsigned int) ntohs (msg->type),
1583 (unsigned int) ntohs (msg->size));
1584 for (tc = clients_head; NULL != tc; tc = tc->next)
1586 if ( (GNUNET_YES == may_drop) &&
1587 (GNUNET_YES != tc->send_payload) )
1588 continue; /* skip, this client does not care about payload */
1589 unicast (tc, msg, may_drop);
1595 * Send the given message to a particular client
1597 * @param client target of the message
1598 * @param msg message to transmit
1599 * @param may_drop #GNUNET_YES if the message can be dropped
1602 GST_clients_unicast (struct GNUNET_SERVER_Client *client,
1603 const struct GNUNET_MessageHeader *msg,
1606 struct TransportClient *tc;
1608 tc = lookup_client (client);
1610 return; /* client got disconnected in the meantime, drop message */
1611 unicast (tc, msg, may_drop);
1616 * Broadcast the new active address to all clients monitoring the peer.
1618 * @param peer peer this update is about (never NULL)
1619 * @param address address, NULL on disconnect
1620 * @param state the current state of the peer
1621 * @param state_timeout the time out for the state
1624 GST_clients_broadcast_peer_notification (const struct GNUNET_PeerIdentity *peer,
1625 const struct GNUNET_HELLO_Address *address,
1626 enum GNUNET_TRANSPORT_PeerState state,
1627 struct GNUNET_TIME_Absolute state_timeout)
1629 struct PeerIterateResponseMessage *msg;
1630 struct MonitoringClient *mc;
1632 msg = compose_address_iterate_response_message (peer, address);
1633 msg->state = htonl (state);
1634 msg->state_timeout = GNUNET_TIME_absolute_hton (state_timeout);
1635 for (mc = peer_monitoring_clients_head; NULL != mc; mc = mc->next)
1636 if ((0 == memcmp (&mc->peer, &all_zeros,
1637 sizeof (struct GNUNET_PeerIdentity))) ||
1638 (0 == memcmp (&mc->peer, peer,
1639 sizeof (struct GNUNET_PeerIdentity))))
1640 GNUNET_SERVER_notification_context_unicast (peer_nc,
1649 * Broadcast the new validation changes to all clients monitoring the peer.
1651 * @param peer peer this update is about (never NULL)
1652 * @param address address, NULL on disconnect
1653 * @param last_validation point in time when last validation was performed
1654 * @param valid_until point in time how long address is valid
1655 * @param next_validation point in time when next validation will be performed
1656 * @param state state of validation notification
1659 GST_clients_broadcast_validation_notification (const struct GNUNET_PeerIdentity *peer,
1660 const struct GNUNET_HELLO_Address *address,
1661 struct GNUNET_TIME_Absolute last_validation,
1662 struct GNUNET_TIME_Absolute valid_until,
1663 struct GNUNET_TIME_Absolute next_validation,
1664 enum GNUNET_TRANSPORT_ValidationState state)
1666 struct ValidationIterateResponseMessage *msg;
1667 struct MonitoringClient *mc;
1669 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1670 "Sending information about for validation entry for peer `%s' using address `%s'\n",
1672 (address != NULL) ? GST_plugins_a2s (address) : "<none>");
1673 msg = compose_validation_iterate_response_message (peer, address);
1674 msg->last_validation = GNUNET_TIME_absolute_hton(last_validation);
1675 msg->valid_until = GNUNET_TIME_absolute_hton(valid_until);
1676 msg->next_validation = GNUNET_TIME_absolute_hton(next_validation);
1677 msg->state = htonl ((uint32_t) state);
1678 for (mc = val_monitoring_clients_head; NULL != mc; mc = mc->next)
1679 if ((0 == memcmp (&mc->peer, &all_zeros,
1680 sizeof (struct GNUNET_PeerIdentity))) ||
1681 (0 == memcmp (&mc->peer, peer,
1682 sizeof (struct GNUNET_PeerIdentity))))
1683 GNUNET_SERVER_notification_context_unicast (val_nc,
1691 /* end of file gnunet-service-transport_clients.c */