aboutsummaryrefslogtreecommitdiff
path: root/src/transport
diff options
context:
space:
mode:
Diffstat (limited to 'src/transport')
-rw-r--r--src/transport/Makefile.am2
-rw-r--r--src/transport/gnunet-service-transport.c2103
-rw-r--r--src/transport/gnunet-service-transport.h112
-rw-r--r--src/transport/gnunet-service-transport_blacklist.c933
-rw-r--r--src/transport/gnunet-service-transport_blacklist.h159
-rw-r--r--src/transport/gnunet-service-transport_clients.c1491
-rw-r--r--src/transport/gnunet-service-transport_clients.h101
-rw-r--r--src/transport/gnunet-service-transport_manipulation.c20
-rw-r--r--src/transport/gnunet-service-transport_manipulation.h8
-rw-r--r--src/transport/gnunet-service-transport_neighbours.c2
-rw-r--r--src/transport/gnunet-service-transport_validation.c2
-rw-r--r--src/transport/test_transport_api_manipulation_recv_tcp.c16
-rw-r--r--src/transport/test_transport_api_manipulation_send_tcp.c22
13 files changed, 2195 insertions, 2776 deletions
diff --git a/src/transport/Makefile.am b/src/transport/Makefile.am
index 2d79ae534..9fb451383 100644
--- a/src/transport/Makefile.am
+++ b/src/transport/Makefile.am
@@ -253,8 +253,6 @@ gnunet_transport_LDADD = \
253gnunet_service_transport_SOURCES = \ 253gnunet_service_transport_SOURCES = \
254 gnunet-service-transport.c gnunet-service-transport.h \ 254 gnunet-service-transport.c gnunet-service-transport.h \
255 gnunet-service-transport_ats.h gnunet-service-transport_ats.c \ 255 gnunet-service-transport_ats.h gnunet-service-transport_ats.c \
256 gnunet-service-transport_blacklist.h gnunet-service-transport_blacklist.c \
257 gnunet-service-transport_clients.h gnunet-service-transport_clients.c \
258 gnunet-service-transport_hello.h gnunet-service-transport_hello.c \ 256 gnunet-service-transport_hello.h gnunet-service-transport_hello.c \
259 gnunet-service-transport_neighbours.h gnunet-service-transport_neighbours.c \ 257 gnunet-service-transport_neighbours.h gnunet-service-transport_neighbours.c \
260 gnunet-service-transport_plugins.h gnunet-service-transport_plugins.c \ 258 gnunet-service-transport_plugins.h gnunet-service-transport_plugins.c \
diff --git a/src/transport/gnunet-service-transport.c b/src/transport/gnunet-service-transport.c
index a21ddabd6..e7b221344 100644
--- a/src/transport/gnunet-service-transport.c
+++ b/src/transport/gnunet-service-transport.c
@@ -1,6 +1,6 @@
1/* 1/*
2 This file is part of GNUnet. 2 This file is part of GNUnet.
3 Copyright (C) 2010-2015 GNUnet e.V. 3 Copyright (C) 2010-2016 GNUnet e.V.
4 4
5 GNUnet is free software; you can redistribute it and/or modify 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 6 it under the terms of the GNU General Public License as published
@@ -31,8 +31,6 @@
31#include "gnunet_ats_service.h" 31#include "gnunet_ats_service.h"
32#include "gnunet-service-transport.h" 32#include "gnunet-service-transport.h"
33#include "gnunet-service-transport_ats.h" 33#include "gnunet-service-transport_ats.h"
34#include "gnunet-service-transport_blacklist.h"
35#include "gnunet-service-transport_clients.h"
36#include "gnunet-service-transport_hello.h" 34#include "gnunet-service-transport_hello.h"
37#include "gnunet-service-transport_neighbours.h" 35#include "gnunet-service-transport_neighbours.h"
38#include "gnunet-service-transport_plugins.h" 36#include "gnunet-service-transport_plugins.h"
@@ -40,6 +38,25 @@
40#include "gnunet-service-transport_manipulation.h" 38#include "gnunet-service-transport_manipulation.h"
41#include "transport.h" 39#include "transport.h"
42 40
41/**
42 * Size of the blacklist hash map.
43 */
44#define TRANSPORT_BLACKLIST_HT_SIZE 64
45
46/**
47 * How many messages can we have pending for a given client process
48 * before we start to drop incoming messages? We typically should
49 * have only one client and so this would be the primary buffer for
50 * messages, so the number should be chosen rather generously.
51 *
52 * The expectation here is that most of the time the queue is large
53 * enough so that a drop is virtually never required. Note that
54 * this value must be about as large as 'TOTAL_MSGS' in the
55 * 'test_transport_api_reliability.c', otherwise that testcase may
56 * fail.
57 */
58#define MAX_PENDING (128 * 1024)
59
43 60
44/** 61/**
45 * Information we need for an asynchronous session kill. 62 * Information we need for an asynchronous session kill.
@@ -73,7 +90,279 @@ struct GNUNET_ATS_SessionKiller
73}; 90};
74 91
75 92
76/* globals */ 93/**
94 * What type of client is the `struct TransportClient` about?
95 */
96enum ClientType
97{
98 /**
99 * We do not know yet (client is fresh).
100 */
101 CT_NONE = 0,
102
103 /**
104 * Is the CORE service, we need to forward traffic to it.
105 */
106 CT_CORE = 1,
107
108 /**
109 * It is a monitor, forward monitor data.
110 */
111 CT_MONITOR = 2,
112
113 /**
114 * It is a blacklist, query about allowed connections.
115 */
116 CT_BLACKLIST = 3
117};
118
119
120/**
121 * Context we use when performing a blacklist check.
122 */
123struct GST_BlacklistCheck;
124
125/**
126 * Client connected to the transport service.
127 */
128struct TransportClient
129{
130
131 /**
132 * This is a doubly-linked list.
133 */
134 struct TransportClient *next;
135
136 /**
137 * This is a doubly-linked list.
138 */
139 struct TransportClient *prev;
140
141 /**
142 * Handle to the client.
143 */
144 struct GNUNET_SERVICE_Client *client;
145
146 /**
147 * Message queue to the client.
148 */
149 struct GNUNET_MQ_Handle *mq;
150
151 /**
152 * What type of client is this?
153 */
154 enum ClientType type;
155
156 union {
157
158 /**
159 * Peer identity to monitor the addresses of.
160 * Zero to monitor all neighbours. Valid if
161 * @e type is CT_MONITOR.
162 */
163 struct GNUNET_PeerIdentity monitor_peer;
164
165 /**
166 * Additional details if @e type is CT_BLACKLIST.
167 */
168 struct {
169
170 /**
171 * Blacklist check that we're currently performing (or NULL
172 * if we're performing one that has been cancelled).
173 */
174 struct GST_BlacklistCheck *bc;
175
176 /**
177 * Set to #GNUNET_YES if we're currently waiting for a reply.
178 */
179 int waiting_for_reply;
180
181 /**
182 * #GNUNET_YES if we have to call receive_done for this client
183 */
184 int call_receive_done;
185
186 } blacklist;
187
188 } details;
189
190};
191
192
193
194/**
195 * Context we use when performing a blacklist check.
196 */
197struct GST_BlacklistCheck
198{
199
200 /**
201 * This is a linked list.
202 */
203 struct GST_BlacklistCheck *next;
204
205 /**
206 * This is a linked list.
207 */
208 struct GST_BlacklistCheck *prev;
209
210 /**
211 * Peer being checked.
212 */
213 struct GNUNET_PeerIdentity peer;
214
215 /**
216 * Continuation to call with the result.
217 */
218 GST_BlacklistTestContinuation cont;
219
220 /**
221 * Closure for @e cont.
222 */
223 void *cont_cls;
224
225 /**
226 * Address for #GST_blacklist_abort_matching(), can be NULL.
227 */
228 struct GNUNET_HELLO_Address *address;
229
230 /**
231 * Session for #GST_blacklist_abort_matching(), can be NULL.
232 */
233 struct GNUNET_ATS_Session *session;
234
235 /**
236 * Our current position in the blacklisters list.
237 */
238 struct TransportClient *bl_pos;
239
240 /**
241 * Current task performing the check.
242 */
243 struct GNUNET_SCHEDULER_Task *task;
244
245};
246
247
248/**
249 * Context for address to string operations
250 */
251struct AddressToStringContext
252{
253 /**
254 * This is a doubly-linked list.
255 */
256 struct AddressToStringContext *next;
257
258 /**
259 * This is a doubly-linked list.
260 */
261 struct AddressToStringContext *prev;
262
263 /**
264 * Client that made the request.
265 */
266 struct TransportClient* tc;
267};
268
269
270/**
271 * Closure for #handle_send_transmit_continuation()
272 */
273struct SendTransmitContinuationContext
274{
275
276 /**
277 * Client that made the request.
278 */
279 struct TransportClient *tc;
280
281 /**
282 * Peer that was the target.
283 */
284 struct GNUNET_PeerIdentity target;
285
286 /**
287 * At what time did we receive the message?
288 */
289 struct GNUNET_TIME_Absolute send_time;
290
291 /**
292 * Unique ID, for logging.
293 */
294 unsigned long long uuid;
295
296 /**
297 * Set to #GNUNET_YES if the connection for @e target goes
298 * down and we thus must no longer send the
299 * #GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK message.
300 */
301 int down;
302};
303
304
305/**
306 * Head of linked list of all clients to this service.
307 */
308static struct TransportClient *clients_head;
309
310/**
311 * Tail of linked list of all clients to this service.
312 */
313static struct TransportClient *clients_tail;
314
315/**
316 * Map of peer identities to active send transmit continuation
317 * contexts. Used to flag contexts as 'dead' when a connection goes
318 * down. Values are of type `struct SendTransmitContinuationContext
319 * *`.
320 */
321static struct GNUNET_CONTAINER_MultiPeerMap *active_stccs;
322
323/**
324 * Head of linked list of all pending address iterations
325 */
326static struct AddressToStringContext *a2s_head;
327
328/**
329 * Tail of linked list of all pending address iterations
330 */
331static struct AddressToStringContext *a2s_tail;
332
333/**
334 * Head of DLL of active blacklisting queries.
335 */
336static struct GST_BlacklistCheck *bc_head;
337
338/**
339 * Tail of DLL of active blacklisting queries.
340 */
341static struct GST_BlacklistCheck *bc_tail;
342
343/**
344 * Hashmap of blacklisted peers. Values are of type 'char *' (transport names),
345 * can be NULL if we have no static blacklist.
346 */
347static struct GNUNET_CONTAINER_MultiPeerMap *blacklist;
348
349/**
350 * Notification context, to send updates on changes to active plugin
351 * connections.
352 */
353static struct GNUNET_NotificationContext *plugin_nc;
354
355/**
356 * Plugin monitoring client we are currently syncing, NULL if all
357 * monitoring clients are in sync.
358 */
359static struct TransportClient *sync_client;
360
361/**
362 * Peer identity that is all zeros, used as a way to indicate
363 * "all peers". Used for comparissons.
364 */
365static struct GNUNET_PeerIdentity all_zeros;
77 366
78/** 367/**
79 * Statistics handle. 368 * Statistics handle.
@@ -96,11 +385,6 @@ struct GNUNET_PeerIdentity GST_my_identity;
96struct GNUNET_PEERINFO_Handle *GST_peerinfo; 385struct GNUNET_PEERINFO_Handle *GST_peerinfo;
97 386
98/** 387/**
99 * Handle to our service's server.
100 */
101static struct GNUNET_SERVER_Handle *GST_server;
102
103/**
104 * Our private key. 388 * Our private key.
105 */ 389 */
106struct GNUNET_CRYPTO_EddsaPrivateKey *GST_my_private_key; 390struct GNUNET_CRYPTO_EddsaPrivateKey *GST_my_private_key;
@@ -137,6 +421,1029 @@ struct GNUNET_ATS_InterfaceScanner *GST_is;
137 421
138 422
139/** 423/**
424 * Queue the given message for transmission to the given client
425 *
426 * @param tc target of the message
427 * @param msg message to transmit
428 * @param may_drop #GNUNET_YES if the message can be dropped
429 */
430static void
431unicast (struct TransportClient *tc,
432 const struct GNUNET_MessageHeader *msg,
433 int may_drop)
434{
435 struct GNUNET_MQ_Envelope *env;
436
437 if ( (GNUNET_MQ_get_length (tc->mq) >= MAX_PENDING) &&
438 (GNUNET_YES == may_drop) )
439 {
440 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
441 "Dropping message of type %u and size %u, have %u/%u messages pending\n",
442 ntohs (msg->type),
443 ntohs (msg->size),
444 GNUNET_MQ_get_length (tc->mq),
445 MAX_PENDING);
446 GNUNET_STATISTICS_update (GST_stats,
447 gettext_noop
448 ("# messages dropped due to slow client"), 1,
449 GNUNET_NO);
450 return;
451 }
452 env = GNUNET_MQ_msg_copy (msg);
453 GNUNET_MQ_send (tc->mq,
454 env);
455}
456
457
458/**
459 * Called whenever a client connects. Allocates our
460 * data structures associated with that client.
461 *
462 * @param cls closure, NULL
463 * @param client identification of the client
464 * @param mq message queue for the client
465 * @return our `struct TransportClient`
466 */
467static void *
468client_connect_cb (void *cls,
469 struct GNUNET_SERVICE_Client *client,
470 struct GNUNET_MQ_Handle *mq)
471{
472 struct TransportClient *tc;
473
474 tc = GNUNET_new (struct TransportClient);
475 tc->client = client;
476 tc->mq = mq;
477 GNUNET_CONTAINER_DLL_insert (clients_head,
478 clients_tail,
479 tc);
480 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
481 "Client %p connected\n",
482 tc);
483 return tc;
484}
485
486
487/**
488 * Perform next action in the blacklist check.
489 *
490 * @param cls the `struct BlacklistCheck*`
491 */
492static void
493do_blacklist_check (void *cls);
494
495
496/**
497 * Mark the peer as down so we don't call the continuation
498 * context in the future.
499 *
500 * @param cls a `struct TransportClient`
501 * @param peer a peer we are sending to
502 * @param value a `struct SendTransmitContinuationContext` to mark
503 * @return #GNUNET_OK (continue to iterate)
504 */
505static int
506mark_match_down (void *cls,
507 const struct GNUNET_PeerIdentity *peer,
508 void *value)
509{
510 struct TransportClient *tc = cls;
511 struct SendTransmitContinuationContext *stcc = value;
512
513 if (tc == stcc->tc)
514 {
515 stcc->down = GNUNET_YES;
516 stcc->tc = NULL;
517 }
518 return GNUNET_OK;
519}
520
521
522/**
523 * Called whenever a client is disconnected. Frees our
524 * resources associated with that client.
525 *
526 * @param cls closure, NULL
527 * @param client identification of the client
528 * @param app_ctx our `struct TransportClient`
529 */
530static void
531client_disconnect_cb (void *cls,
532 struct GNUNET_SERVICE_Client *client,
533 void *app_ctx)
534{
535 struct TransportClient *tc = app_ctx;
536 struct GST_BlacklistCheck *bc;
537
538 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
539 "Client %p disconnected, cleaning up.\n",
540 tc);
541 GNUNET_CONTAINER_multipeermap_iterate (active_stccs,
542 &mark_match_down,
543 tc);
544 GNUNET_CONTAINER_DLL_remove (clients_head,
545 clients_tail,
546 tc);
547 switch (tc->type)
548 {
549 case CT_NONE:
550 break;
551 case CT_CORE:
552 break;
553 case CT_MONITOR:
554 break;
555 case CT_BLACKLIST:
556 for (bc = bc_head; NULL != bc; bc = bc->next)
557 {
558 if (bc->bl_pos != tc)
559 continue;
560 bc->bl_pos = tc->next;
561 if (NULL == bc->task)
562 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
563 bc);
564 }
565 break;
566 }
567 GNUNET_free (tc);
568}
569
570
571/**
572 * Function called for each of our connected neighbours. Notify the
573 * client about the existing neighbour.
574 *
575 * @param cls the `struct TransportClient *` to notify
576 * @param peer identity of the neighbour
577 * @param address the address
578 * @param state the current state of the peer
579 * @param state_timeout the time out for the state
580 * @param bandwidth_in inbound bandwidth in NBO
581 * @param bandwidth_out outbound bandwidth in NBO
582 */
583static void
584notify_client_about_neighbour (void *cls,
585 const struct GNUNET_PeerIdentity *peer,
586 const struct GNUNET_HELLO_Address *address,
587 enum GNUNET_TRANSPORT_PeerState state,
588 struct GNUNET_TIME_Absolute state_timeout,
589 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in,
590 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out)
591{
592 struct TransportClient *tc = cls;
593 struct ConnectInfoMessage cim;
594
595 if (GNUNET_NO == GST_neighbours_test_connected (peer))
596 return;
597 cim.header.size = htons (sizeof (struct ConnectInfoMessage));
598 cim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
599 cim.id = *peer;
600 cim.quota_in = bandwidth_in;
601 cim.quota_out = bandwidth_out;
602 unicast (tc,
603 &cim.header,
604 GNUNET_NO);
605}
606
607
608/**
609 * Initialize a normal client. We got a start message from this
610 * client, add him to the list of clients for broadcasting of inbound
611 * messages.
612 *
613 * @param cls the client
614 * @param start the start message that was sent
615 */
616static void
617handle_client_start (void *cls,
618 const struct StartMessage *start)
619{
620 struct TransportClient *tc = cls;
621 const struct GNUNET_MessageHeader *hello;
622 uint32_t options;
623
624 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
625 "Client %p sent START\n",
626 tc);
627 options = ntohl (start->options);
628 if ((0 != (1 & options)) &&
629 (0 !=
630 memcmp (&start->self,
631 &GST_my_identity,
632 sizeof (struct GNUNET_PeerIdentity))))
633 {
634 /* client thinks this is a different peer, reject */
635 GNUNET_break (0);
636 GNUNET_SERVICE_client_drop (tc->client);
637 return;
638 }
639 if (CT_NONE != tc->type)
640 {
641 GNUNET_break (0);
642 GNUNET_SERVICE_client_drop (tc->client);
643 return;
644 }
645 if (0 != (2 & options))
646 tc->type = CT_CORE;
647 hello = GST_hello_get ();
648 if (NULL != hello)
649 unicast (tc,
650 hello,
651 GNUNET_NO);
652 GST_neighbours_iterate (&notify_client_about_neighbour,
653 tc);
654 GNUNET_SERVICE_client_continue (tc->client);
655}
656
657
658/**
659 * Client sent us a HELLO. Check the request.
660 *
661 * @param cls the client
662 * @param message the HELLO message
663 */
664static int
665check_client_hello (void *cls,
666 const struct GNUNET_MessageHeader *message)
667{
668 return GNUNET_OK; /* FIXME: check here? */
669}
670
671
672/**
673 * Client sent us a HELLO. Process the request.
674 *
675 * @param cls the client
676 * @param message the HELLO message
677 */
678static void
679handle_client_hello (void *cls,
680 const struct GNUNET_MessageHeader *message)
681{
682 struct TransportClient *tc = cls;
683
684 GST_validation_handle_hello (message);
685 GNUNET_SERVICE_client_continue (tc->client);
686}
687
688
689/**
690 * Function called after the transmission is done. Notify the client that it is
691 * OK to send the next message.
692 *
693 * @param cls closure
694 * @param success #GNUNET_OK on success, #GNUNET_NO on failure, #GNUNET_SYSERR if we're not connected
695 * @param bytes_payload bytes payload sent
696 * @param bytes_on_wire bytes sent on wire
697 */
698static void
699handle_send_transmit_continuation (void *cls,
700 int success,
701 size_t bytes_payload,
702 size_t bytes_on_wire)
703{
704 struct SendTransmitContinuationContext *stcc = cls;
705 struct SendOkMessage send_ok_msg;
706 struct GNUNET_TIME_Relative delay;
707 const struct GNUNET_HELLO_Address *addr;
708
709 delay = GNUNET_TIME_absolute_get_duration (stcc->send_time);
710 addr = GST_neighbour_get_current_address (&stcc->target);
711 if (delay.rel_value_us > GNUNET_CONSTANTS_LATENCY_WARN.rel_value_us)
712 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
713 "It took us %s to send %u/%u bytes to %s (%d, %s)\n",
714 GNUNET_STRINGS_relative_time_to_string (delay,
715 GNUNET_YES),
716 (unsigned int) bytes_payload,
717 (unsigned int) bytes_on_wire,
718 GNUNET_i2s (&stcc->target),
719 success,
720 (NULL != addr) ? addr->transport_name : "%");
721 else
722 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
723 "It took us %s to send %u/%u bytes to %s (%d, %s)\n",
724 GNUNET_STRINGS_relative_time_to_string (delay,
725 GNUNET_YES),
726 (unsigned int) bytes_payload,
727 (unsigned int) bytes_on_wire,
728 GNUNET_i2s (&stcc->target),
729 success,
730 (NULL != addr) ? addr->transport_name : "%");
731
732 if (GNUNET_NO == stcc->down)
733 {
734 /* Only send confirmation if we are still connected */
735 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
736 "Sending SEND_OK for transmission request %llu\n",
737 stcc->uuid);
738 send_ok_msg.header.size = htons (sizeof (send_ok_msg));
739 send_ok_msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK);
740 send_ok_msg.bytes_msg = htonl (bytes_payload);
741 send_ok_msg.bytes_physical = htonl (bytes_on_wire);
742 send_ok_msg.success = htonl (success);
743 send_ok_msg.peer = stcc->target;
744 unicast (stcc->tc,
745 &send_ok_msg.header,
746 GNUNET_NO);
747 }
748 GNUNET_assert (GNUNET_OK ==
749 GNUNET_CONTAINER_multipeermap_remove (active_stccs,
750 &stcc->target,
751 stcc));
752 GNUNET_free (stcc);
753}
754
755
756/**
757 * Client asked for transmission to a peer. Process the request.
758 *
759 * @param cls the client
760 * @param obm the send message that was sent
761 */
762static int
763check_client_send (void *cls,
764 const struct OutboundMessage *obm)
765{
766 uint16_t size;
767 const struct GNUNET_MessageHeader *obmm;
768
769 size = ntohs (obm->header.size) - sizeof (struct OutboundMessage);
770 if (size < sizeof (struct GNUNET_MessageHeader))
771 {
772 GNUNET_break (0);
773 return GNUNET_SYSERR;
774 }
775 obmm = (const struct GNUNET_MessageHeader *) &obm[1];
776 if (size != ntohs (obmm->size))
777 {
778 GNUNET_break (0);
779 return GNUNET_SYSERR;
780 }
781 return GNUNET_OK;
782}
783
784
785/**
786 * Client asked for transmission to a peer. Process the request.
787 *
788 * @param cls the client
789 * @param obm the send message that was sent
790 */
791static void
792handle_client_send (void *cls,
793 const struct OutboundMessage *obm)
794{
795 static unsigned long long uuid_gen;
796 struct TransportClient *tc = cls;
797 const struct GNUNET_MessageHeader *obmm;
798 struct SendTransmitContinuationContext *stcc;
799
800 obmm = (const struct GNUNET_MessageHeader *) &obm[1];
801 if (GNUNET_NO == GST_neighbours_test_connected (&obm->peer))
802 {
803 /* not connected, not allowed to send; can happen due to asynchronous operations */
804 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
805 "Could not send message to peer `%s': not connected\n",
806 GNUNET_i2s (&obm->peer));
807 GNUNET_STATISTICS_update (GST_stats,
808 gettext_noop
809 ("# bytes payload dropped (other peer was not connected)"),
810 ntohs (obmm->size),
811 GNUNET_NO);
812 GNUNET_SERVICE_client_continue (tc->client);
813 return;
814 }
815 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
816 "Received SEND request %llu for `%s' and first message of type %u and total size %u\n",
817 uuid_gen,
818 GNUNET_i2s (&obm->peer),
819 ntohs (obmm->type),
820 ntohs (obmm->size));
821 GNUNET_SERVICE_client_continue (tc->client);
822
823 stcc = GNUNET_new (struct SendTransmitContinuationContext);
824 stcc->target = obm->peer;
825 stcc->tc = tc;
826 stcc->send_time = GNUNET_TIME_absolute_get ();
827 stcc->uuid = uuid_gen++;
828 (void) GNUNET_CONTAINER_multipeermap_put (active_stccs,
829 &stcc->target,
830 stcc,
831 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
832 GST_manipulation_send (&obm->peer,
833 obmm,
834 ntohs (obmm->size),
835 GNUNET_TIME_relative_ntoh (obm->timeout),
836 &handle_send_transmit_continuation,
837 stcc);
838}
839
840
841/**
842 * Take the given address and append it to the set of results sent back to
843 * the client. This function may be called serveral times for a single
844 * conversion. The last invocation will be with a @a address of
845 * NULL and a @a res of #GNUNET_OK. Thus, to indicate conversion
846 * errors, the callback might be called first with @a address NULL and
847 * @a res being #GNUNET_SYSERR. In that case, there will still be a
848 * subsequent call later with @a address NULL and @a res #GNUNET_OK.
849 *
850 * @param cls the `struct AddressToStringContext`
851 * @param buf text to transmit (contains the human-readable address, or NULL)
852 * @param res #GNUNET_OK if conversion was successful, #GNUNET_SYSERR on error,
853 * never #GNUNET_NO
854 */
855static void
856transmit_address_to_client (void *cls,
857 const char *buf,
858 int res)
859{
860 struct AddressToStringContext *actx = cls;
861 struct GNUNET_MQ_Envelope *env;
862 struct AddressToStringResultMessage *atsm;
863 size_t slen;
864
865 GNUNET_assert ( (GNUNET_OK == res) ||
866 (GNUNET_SYSERR == res) );
867 if (NULL == buf)
868 {
869 env = GNUNET_MQ_msg (atsm,
870 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_TO_STRING_REPLY);
871 if (GNUNET_OK == res)
872 {
873 /* this was the last call, transmit */
874 atsm->res = htonl (GNUNET_OK);
875 atsm->addr_len = htonl (0);
876 GNUNET_MQ_send (actx->tc->mq,
877 env);
878 GNUNET_CONTAINER_DLL_remove (a2s_head,
879 a2s_tail,
880 actx);
881 return;
882 }
883 if (GNUNET_SYSERR == res)
884 {
885 /* address conversion failed, but there will be more callbacks */
886 atsm->res = htonl (GNUNET_SYSERR);
887 atsm->addr_len = htonl (0);
888 GNUNET_MQ_send (actx->tc->mq,
889 env);
890 return;
891 }
892 }
893 GNUNET_assert (GNUNET_OK == res);
894 /* succesful conversion, append*/
895 slen = strlen (buf) + 1;
896 env = GNUNET_MQ_msg_extra (atsm,
897 slen,
898 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_TO_STRING_REPLY);
899 atsm->res = htonl (GNUNET_YES);
900 atsm->addr_len = htonl (slen);
901 GNUNET_memcpy (&atsm[1],
902 buf,
903 slen);
904 GNUNET_MQ_send (actx->tc->mq,
905 env);
906}
907
908
909/**
910 * Client asked to resolve an address. Check the request.
911 *
912 * @param cls the client
913 * @param alum the resolution request
914 * @return #GNUNET_OK if @a alum is well-formed
915 */
916static int
917check_client_address_to_string (void *cls,
918 const struct AddressLookupMessage *alum)
919{
920 const char *plugin_name;
921 const char *address;
922 uint32_t address_len;
923 uint16_t size;
924
925 size = ntohs (alum->header.size);
926 address_len = ntohs (alum->addrlen);
927 if (size <= sizeof (struct AddressLookupMessage) + address_len)
928 {
929 GNUNET_break (0);
930 return GNUNET_SYSERR;
931 }
932 address = (const char *) &alum[1];
933 plugin_name = (const char *) &address[address_len];
934 if ('\0' != plugin_name[size - sizeof (struct AddressLookupMessage) - address_len - 1])
935 {
936 GNUNET_break (0);
937 return GNUNET_SYSERR;
938 }
939 return GNUNET_OK;
940}
941
942
943/**
944 * Client asked to resolve an address. Process the request.
945 *
946 * @param cls the client
947 * @param alum the resolution request
948 */
949static void
950handle_client_address_to_string (void *cls,
951 const struct AddressLookupMessage *alum)
952{
953 struct TransportClient *tc = cls;
954 struct GNUNET_TRANSPORT_PluginFunctions *papi;
955 const char *plugin_name;
956 const char *address;
957 uint32_t address_len;
958 struct AddressToStringContext *actx;
959 struct GNUNET_MQ_Envelope *env;
960 struct AddressToStringResultMessage *atsm;
961 struct GNUNET_TIME_Relative rtimeout;
962 int32_t numeric;
963
964 address_len = ntohs (alum->addrlen);
965 address = (const char *) &alum[1];
966 plugin_name = (const char *) &address[address_len];
967 rtimeout = GNUNET_TIME_relative_ntoh (alum->timeout);
968 numeric = ntohs (alum->numeric_only);
969 papi = GST_plugins_printer_find (plugin_name);
970 if (NULL == papi)
971 {
972 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
973 "Failed to find plugin `%s'\n",
974 plugin_name);
975 env = GNUNET_MQ_msg (atsm,
976 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_TO_STRING_REPLY);
977 atsm->res = htonl (GNUNET_SYSERR);
978 atsm->addr_len = htonl (0);
979 GNUNET_MQ_send (tc->mq,
980 env);
981 env = GNUNET_MQ_msg (atsm,
982 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_TO_STRING_REPLY);
983 atsm->res = htonl (GNUNET_OK);
984 atsm->addr_len = htonl (0);
985 GNUNET_MQ_send (tc->mq,
986 env);
987 return;
988 }
989 actx = GNUNET_new (struct AddressToStringContext);
990 actx->tc = tc;
991 GNUNET_CONTAINER_DLL_insert (a2s_head,
992 a2s_tail,
993 actx);
994 GNUNET_SERVICE_client_disable_continue_warning (tc->client);
995 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
996 "Pretty-printing address of %u bytes using plugin `%s'\n",
997 address_len,
998 plugin_name);
999 papi->address_pretty_printer (papi->cls,
1000 plugin_name,
1001 address,
1002 address_len,
1003 numeric,
1004 rtimeout,
1005 &transmit_address_to_client,
1006 actx);
1007}
1008
1009
1010/**
1011 * Compose #PeerIterateResponseMessage using the given peer and address.
1012 *
1013 * @param peer identity of the peer
1014 * @param address the address, NULL on disconnect
1015 * @return composed message
1016 */
1017static struct PeerIterateResponseMessage *
1018compose_address_iterate_response_message (const struct GNUNET_PeerIdentity *peer,
1019 const struct GNUNET_HELLO_Address *address)
1020{
1021 struct PeerIterateResponseMessage *msg;
1022 size_t size;
1023 size_t tlen;
1024 size_t alen;
1025 char *addr;
1026
1027 GNUNET_assert (NULL != peer);
1028 if (NULL != address)
1029 {
1030 tlen = strlen (address->transport_name) + 1;
1031 alen = address->address_length;
1032 }
1033 else
1034 {
1035 tlen = 0;
1036 alen = 0;
1037 }
1038 size = (sizeof (struct PeerIterateResponseMessage) + alen + tlen);
1039 msg = GNUNET_malloc (size);
1040 msg->header.size = htons (size);
1041 msg->header.type
1042 = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_PEER_RESPONSE);
1043 msg->reserved = htonl (0);
1044 msg->peer = *peer;
1045 msg->addrlen = htonl (alen);
1046 msg->pluginlen = htonl (tlen);
1047
1048 if (NULL != address)
1049 {
1050 msg->local_address_info = htonl((uint32_t) address->local_info);
1051 addr = (char *) &msg[1];
1052 GNUNET_memcpy (addr,
1053 address->address,
1054 alen);
1055 GNUNET_memcpy (&addr[alen],
1056 address->transport_name,
1057 tlen);
1058 }
1059 return msg;
1060}
1061
1062
1063/**
1064 * Context for #send_validation_information() and
1065 * #send_peer_information().
1066 */
1067struct IterationContext
1068{
1069 /**
1070 * Context to use for the transmission.
1071 */
1072 struct TransportClient *tc;
1073
1074 /**
1075 * Which peers do we care about?
1076 */
1077 struct GNUNET_PeerIdentity id;
1078
1079 /**
1080 * #GNUNET_YES if @e id should be ignored because we want all peers.
1081 */
1082 int all;
1083};
1084
1085
1086/**
1087 * Output information of neighbours to the given client.
1088 *
1089 * @param cls the `struct PeerIterationContext *`
1090 * @param peer identity of the neighbour
1091 * @param address the address
1092 * @param state current state this peer is in
1093 * @param state_timeout timeout for the current state of the peer
1094 * @param bandwidth_in inbound quota in NBO
1095 * @param bandwidth_out outbound quota in NBO
1096 */
1097static void
1098send_peer_information (void *cls,
1099 const struct GNUNET_PeerIdentity *peer,
1100 const struct GNUNET_HELLO_Address *address,
1101 enum GNUNET_TRANSPORT_PeerState state,
1102 struct GNUNET_TIME_Absolute state_timeout,
1103 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in,
1104 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out)
1105{
1106 struct IterationContext *pc = cls;
1107 struct GNUNET_MQ_Envelope *env;
1108 struct PeerIterateResponseMessage *msg;
1109
1110 if ( (GNUNET_YES != pc->all) &&
1111 (0 != memcmp (peer,
1112 &pc->id,
1113 sizeof (pc->id))) )
1114 return;
1115 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1116 "Sending information about `%s' using address `%s' in state `%s'\n",
1117 GNUNET_i2s(peer),
1118 (NULL != address) ? GST_plugins_a2s (address) : "<none>",
1119 GNUNET_TRANSPORT_ps2s (state));
1120 msg = compose_address_iterate_response_message (peer,
1121 address);
1122 msg->state = htonl (state);
1123 msg->state_timeout = GNUNET_TIME_absolute_hton(state_timeout);
1124 env = GNUNET_MQ_msg_copy (&msg->header);
1125 GNUNET_free (msg);
1126 GNUNET_MQ_send (pc->tc->mq,
1127 env);
1128}
1129
1130
1131/**
1132 * Client asked to obtain information about a specific or all peers
1133 * Process the request.
1134 *
1135 * @param cls the client
1136 * @param msg the peer address information request
1137 */
1138static void
1139handle_client_monitor_peers (void *cls,
1140 const struct PeerMonitorMessage *msg)
1141{
1142 struct TransportClient *tc = cls;
1143 struct IterationContext pc;
1144
1145 if (CT_NONE != tc->type)
1146 {
1147 GNUNET_break (0);
1148 GNUNET_SERVICE_client_drop (tc->client);
1149 return;
1150 }
1151 GNUNET_SERVICE_client_disable_continue_warning (tc->client);
1152 GNUNET_SERVICE_client_mark_monitor (tc->client);
1153
1154 /* Send initial list */
1155 pc.tc = tc;
1156 if (0 == memcmp (&msg->peer,
1157 &all_zeros,
1158 sizeof (struct GNUNET_PeerIdentity)))
1159 {
1160 /* iterate over all neighbours */
1161 pc.all = GNUNET_YES;
1162 pc.id = msg->peer;
1163 }
1164 else
1165 {
1166 /* just return one neighbour */
1167 pc.all = GNUNET_NO;
1168 pc.id = msg->peer;
1169 }
1170 GST_neighbours_iterate (&send_peer_information,
1171 &pc);
1172
1173 if (GNUNET_YES != ntohl (msg->one_shot))
1174 {
1175 tc->details.monitor_peer = msg->peer;
1176 tc->type = CT_MONITOR;
1177 if (0 != memcmp (&msg->peer,
1178 &all_zeros,
1179 sizeof (struct GNUNET_PeerIdentity)))
1180 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1181 "Client %p started monitoring of the peer `%s'\n",
1182 tc,
1183 GNUNET_i2s (&msg->peer));
1184 else
1185 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1186 "Client %p started monitoring all peers\n",
1187 tc);
1188 }
1189 else
1190 {
1191 struct GNUNET_MessageHeader *msg;
1192 struct GNUNET_MQ_Envelope *env;
1193
1194 env = GNUNET_MQ_msg (msg,
1195 GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_PEER_RESPONSE_END);
1196 GNUNET_MQ_send (tc->mq,
1197 env);
1198 }
1199}
1200
1201
1202/**
1203 * Function called by the plugin with information about the
1204 * current sessions managed by the plugin (for monitoring).
1205 *
1206 * @param cls closure
1207 * @param session session handle this information is about,
1208 * NULL to indicate that we are "in sync" (initial
1209 * iteration complete)
1210 * @param info information about the state of the session,
1211 * NULL if @a session is also NULL and we are
1212 * merely signalling that the initial iteration is over
1213 */
1214static void
1215plugin_session_info_cb (void *cls,
1216 struct GNUNET_ATS_Session *session,
1217 const struct GNUNET_TRANSPORT_SessionInfo *info)
1218{
1219 struct GNUNET_MQ_Envelope *env;
1220 struct TransportPluginMonitorMessage *msg;
1221 struct GNUNET_MessageHeader *sync;
1222 size_t size;
1223 size_t slen;
1224 uint16_t alen;
1225 char *name;
1226 char *addr;
1227
1228 if (0 == GNUNET_notification_context_get_size (plugin_nc))
1229 {
1230 GST_plugins_monitor_subscribe (NULL,
1231 NULL);
1232 return;
1233 }
1234 if ( (NULL == info) &&
1235 (NULL == session) )
1236 {
1237 /* end of initial iteration */
1238 if (NULL != sync_client)
1239 {
1240 env = GNUNET_MQ_msg (sync,
1241 GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_PLUGIN_SYNC);
1242 GNUNET_MQ_send (sync_client->mq,
1243 env);
1244 sync_client = NULL;
1245 }
1246 return;
1247 }
1248 GNUNET_assert (NULL != info);
1249 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1250 "Plugin event for peer %s on transport %s\n",
1251 GNUNET_i2s (&info->address->peer),
1252 info->address->transport_name);
1253 slen = strlen (info->address->transport_name) + 1;
1254 alen = info->address->address_length;
1255 size = sizeof (struct TransportPluginMonitorMessage) + slen + alen;
1256 if (size > UINT16_MAX)
1257 {
1258 GNUNET_break (0);
1259 return;
1260 }
1261 msg = GNUNET_malloc (size);
1262 msg->header.size = htons (size);
1263 msg->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_PLUGIN_EVENT);
1264 msg->session_state = htons ((uint16_t) info->state);
1265 msg->is_inbound = htons ((int16_t) info->is_inbound);
1266 msg->msgs_pending = htonl (info->num_msg_pending);
1267 msg->bytes_pending = htonl (info->num_bytes_pending);
1268 msg->timeout = GNUNET_TIME_absolute_hton (info->session_timeout);
1269 msg->delay = GNUNET_TIME_absolute_hton (info->receive_delay);
1270 msg->peer = info->address->peer;
1271 msg->session_id = (uint64_t) (intptr_t) session;
1272 msg->plugin_name_len = htons (slen);
1273 msg->plugin_address_len = htons (alen);
1274 name = (char *) &msg[1];
1275 GNUNET_memcpy (name,
1276 info->address->transport_name,
1277 slen);
1278 addr = &name[slen];
1279 GNUNET_memcpy (addr,
1280 info->address->address,
1281 alen);
1282 if (NULL != sync_client)
1283 {
1284 struct GNUNET_MQ_Envelope *env;
1285
1286 env = GNUNET_MQ_msg_copy (&msg->header);
1287 GNUNET_MQ_send (sync_client->mq,
1288 env);
1289 }
1290 else
1291 {
1292 GNUNET_notification_context_broadcast (plugin_nc,
1293 &msg->header,
1294 GNUNET_NO);
1295 }
1296 GNUNET_free (msg);
1297}
1298
1299
1300/**
1301 * Client asked to obtain information about all plugin connections.
1302 *
1303 * @param cls the client
1304 * @param message the peer address information request
1305 */
1306static void
1307handle_client_monitor_plugins (void *cls,
1308 const struct GNUNET_MessageHeader *message)
1309{
1310 struct TransportClient *tc = cls;
1311
1312 GNUNET_SERVICE_client_mark_monitor (tc->client);
1313 GNUNET_SERVICE_client_disable_continue_warning (tc->client);
1314 GNUNET_notification_context_add (plugin_nc,
1315 tc->mq);
1316 GNUNET_assert (NULL == sync_client);
1317 sync_client = tc;
1318 GST_plugins_monitor_subscribe (&plugin_session_info_cb,
1319 NULL);
1320}
1321
1322
1323/**
1324 * Broadcast the given message to all of our clients.
1325 *
1326 * @param msg message to broadcast
1327 * @param may_drop #GNUNET_YES if the message can be dropped / is payload
1328 */
1329void
1330GST_clients_broadcast (const struct GNUNET_MessageHeader *msg,
1331 int may_drop)
1332{
1333 struct TransportClient *tc;
1334 int done;
1335
1336 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1337 "Asked to broadcast message of type %u with %u bytes\n",
1338 (unsigned int) ntohs (msg->type),
1339 (unsigned int) ntohs (msg->size));
1340 done = GNUNET_NO;
1341 for (tc = clients_head; NULL != tc; tc = tc->next)
1342 {
1343 if ( (GNUNET_YES == may_drop) &&
1344 (CT_CORE != tc->type) )
1345 continue; /* skip, this client does not care about payload */
1346 unicast (tc,
1347 msg,
1348 may_drop);
1349 done = GNUNET_YES;
1350 }
1351 if (GNUNET_NO == done)
1352 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1353 "Message of type %u not delivered, is CORE service up?\n",
1354 ntohs (msg->type));
1355}
1356
1357
1358/**
1359 * Broadcast the new active address to all clients monitoring the peer.
1360 *
1361 * @param peer peer this update is about (never NULL)
1362 * @param address address, NULL on disconnect
1363 * @param state the current state of the peer
1364 * @param state_timeout the time out for the state
1365 */
1366void
1367GST_clients_broadcast_peer_notification (const struct GNUNET_PeerIdentity *peer,
1368 const struct GNUNET_HELLO_Address *address,
1369 enum GNUNET_TRANSPORT_PeerState state,
1370 struct GNUNET_TIME_Absolute state_timeout)
1371{
1372 struct GNUNET_MQ_Envelope *env;
1373 struct PeerIterateResponseMessage *msg;
1374 struct TransportClient *tc;
1375
1376 msg = compose_address_iterate_response_message (peer,
1377 address);
1378 msg->state = htonl (state);
1379 msg->state_timeout = GNUNET_TIME_absolute_hton (state_timeout);
1380 for (tc = clients_head; NULL != tc; tc = tc->next)
1381 {
1382 if (CT_MONITOR != tc->type)
1383 continue;
1384 if ((0 == memcmp (&tc->details.monitor_peer,
1385 &all_zeros,
1386 sizeof (struct GNUNET_PeerIdentity))) ||
1387 (0 == memcmp (&tc->details.monitor_peer,
1388 peer,
1389 sizeof (struct GNUNET_PeerIdentity))))
1390 {
1391 env = GNUNET_MQ_msg_copy (&msg->header);
1392 GNUNET_MQ_send (tc->mq,
1393 env);
1394 }
1395 }
1396 GNUNET_free (msg);
1397}
1398
1399
1400/**
1401 * Mark the peer as down so we don't call the continuation
1402 * context in the future.
1403 *
1404 * @param cls NULL
1405 * @param peer peer that got disconnected
1406 * @param value a `struct SendTransmitContinuationContext` to mark
1407 * @return #GNUNET_OK (continue to iterate)
1408 */
1409static int
1410mark_peer_down (void *cls,
1411 const struct GNUNET_PeerIdentity *peer,
1412 void *value)
1413{
1414 struct SendTransmitContinuationContext *stcc = value;
1415
1416 stcc->down = GNUNET_YES;
1417 return GNUNET_OK;
1418}
1419
1420
1421/**
1422 * Notify all clients about a disconnect, and cancel
1423 * pending SEND_OK messages for this peer.
1424 *
1425 * @param peer peer that disconnected
1426 */
1427void
1428GST_clients_broadcast_disconnect (const struct GNUNET_PeerIdentity *peer)
1429{
1430 struct DisconnectInfoMessage disconnect_msg;
1431
1432 GNUNET_CONTAINER_multipeermap_get_multiple (active_stccs,
1433 peer,
1434 &mark_peer_down,
1435 NULL);
1436 disconnect_msg.header.size = htons (sizeof(struct DisconnectInfoMessage));
1437 disconnect_msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT);
1438 disconnect_msg.reserved = htonl (0);
1439 disconnect_msg.peer = *peer;
1440 GST_clients_broadcast (&disconnect_msg.header,
1441 GNUNET_NO);
1442
1443}
1444
1445
1446/**
140 * Transmit our HELLO message to the given (connected) neighbour. 1447 * Transmit our HELLO message to the given (connected) neighbour.
141 * 1448 *
142 * @param cls the 'HELLO' message 1449 * @param cls the 'HELLO' message
@@ -170,7 +1477,8 @@ transmit_our_hello (void *cls,
170 hello, 1477 hello,
171 ntohs (hello->size), 1478 ntohs (hello->size),
172 hello_expiration, 1479 hello_expiration,
173 NULL, NULL); 1480 NULL,
1481 NULL);
174} 1482}
175 1483
176 1484
@@ -240,8 +1548,11 @@ process_payload (const struct GNUNET_HELLO_Address *address,
240 im->header.size = htons (size); 1548 im->header.size = htons (size);
241 im->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RECV); 1549 im->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RECV);
242 im->peer = address->peer; 1550 im->peer = address->peer;
243 GNUNET_memcpy (&im[1], message, ntohs (message->size)); 1551 GNUNET_memcpy (&im[1],
244 GST_clients_broadcast (&im->header, GNUNET_YES); 1552 message,
1553 ntohs (message->size));
1554 GST_clients_broadcast (&im->header,
1555 GNUNET_YES);
245 return ret; 1556 return ret;
246} 1557}
247 1558
@@ -257,8 +1568,11 @@ kill_session_task (void *cls)
257 struct GNUNET_ATS_SessionKiller *sk = cls; 1568 struct GNUNET_ATS_SessionKiller *sk = cls;
258 1569
259 sk->task = NULL; 1570 sk->task = NULL;
260 GNUNET_CONTAINER_DLL_remove (sk_head, sk_tail, sk); 1571 GNUNET_CONTAINER_DLL_remove (sk_head,
261 sk->plugin->disconnect_session (sk->plugin->cls, sk->session); 1572 sk_tail,
1573 sk);
1574 sk->plugin->disconnect_session (sk->plugin->cls,
1575 sk->session);
262 GNUNET_free(sk); 1576 GNUNET_free(sk);
263} 1577}
264 1578
@@ -290,7 +1604,8 @@ kill_session (const char *plugin_name,
290 sk = GNUNET_new (struct GNUNET_ATS_SessionKiller); 1604 sk = GNUNET_new (struct GNUNET_ATS_SessionKiller);
291 sk->session = session; 1605 sk->session = session;
292 sk->plugin = plugin; 1606 sk->plugin = plugin;
293 sk->task = GNUNET_SCHEDULER_add_now (&kill_session_task, sk); 1607 sk->task = GNUNET_SCHEDULER_add_now (&kill_session_task,
1608 sk);
294 GNUNET_CONTAINER_DLL_insert (sk_head, 1609 GNUNET_CONTAINER_DLL_insert (sk_head,
295 sk_tail, 1610 sk_tail,
296 sk); 1611 sk);
@@ -418,7 +1733,9 @@ GST_receive_callback (void *cls,
418 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, 1733 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
419 "Processing PONG from `%s'\n", 1734 "Processing PONG from `%s'\n",
420 GST_plugins_a2s (address)); 1735 GST_plugins_a2s (address));
421 if (GNUNET_OK != GST_validation_handle_pong (&address->peer, message)) 1736 if (GNUNET_OK !=
1737 GST_validation_handle_pong (&address->peer,
1738 message))
422 { 1739 {
423 GNUNET_break_op (0); 1740 GNUNET_break_op (0);
424 GST_blacklist_abort_matching (address, 1741 GST_blacklist_abort_matching (address,
@@ -508,12 +1825,11 @@ plugin_env_address_change_notification (void *cls,
508 const struct GNUNET_HELLO_Address *address) 1825 const struct GNUNET_HELLO_Address *address)
509{ 1826{
510 static int addresses = 0; 1827 static int addresses = 0;
511 struct GNUNET_STATISTICS_Handle *cfg = GST_stats;
512 1828
513 if (GNUNET_YES == add_remove) 1829 if (GNUNET_YES == add_remove)
514 { 1830 {
515 addresses ++; 1831 addresses ++;
516 GNUNET_STATISTICS_update (cfg, 1832 GNUNET_STATISTICS_update (GST_stats,
517 "# transport addresses", 1833 "# transport addresses",
518 1, 1834 1,
519 GNUNET_NO); 1835 GNUNET_NO);
@@ -527,7 +1843,7 @@ plugin_env_address_change_notification (void *cls,
527 else 1843 else
528 { 1844 {
529 addresses --; 1845 addresses --;
530 GNUNET_STATISTICS_update (cfg, 1846 GNUNET_STATISTICS_update (GST_stats,
531 "# transport addresses", 1847 "# transport addresses",
532 -1, 1848 -1,
533 GNUNET_NO); 1849 GNUNET_NO);
@@ -579,16 +1895,20 @@ plugin_env_session_end (void *cls,
579 GNUNET_i2s (&address->peer), 1895 GNUNET_i2s (&address->peer),
580 GST_plugins_a2s (address)); 1896 GST_plugins_a2s (address));
581 1897
582 GST_neighbours_session_terminated (&address->peer, session); 1898 GST_neighbours_session_terminated (&address->peer,
1899 session);
583 GST_ats_del_session (address, 1900 GST_ats_del_session (address,
584 session); 1901 session);
585 GST_blacklist_abort_matching (address, session); 1902 GST_blacklist_abort_matching (address,
1903 session);
586 1904
587 for (sk = sk_head; NULL != sk; sk = sk->next) 1905 for (sk = sk_head; NULL != sk; sk = sk->next)
588 { 1906 {
589 if (sk->session == session) 1907 if (sk->session == session)
590 { 1908 {
591 GNUNET_CONTAINER_DLL_remove (sk_head, sk_tail, sk); 1909 GNUNET_CONTAINER_DLL_remove (sk_head,
1910 sk_tail,
1911 sk);
592 GNUNET_SCHEDULER_cancel (sk->task); 1912 GNUNET_SCHEDULER_cancel (sk->task);
593 GNUNET_free(sk); 1913 GNUNET_free(sk);
594 break; 1914 break;
@@ -672,7 +1992,9 @@ plugin_env_session_start (void *cls,
672 for example for UNIX, we have symmetric connections and thus we 1992 for example for UNIX, we have symmetric connections and thus we
673 may not know the address yet; add if necessary! */ 1993 may not know the address yet; add if necessary! */
674 /* FIXME: maybe change API here so we just pass scope? */ 1994 /* FIXME: maybe change API here so we just pass scope? */
675 memset (&prop, 0, sizeof (prop)); 1995 memset (&prop,
1996 0,
1997 sizeof (prop));
676 GNUNET_break (GNUNET_ATS_NET_UNSPECIFIED != scope); 1998 GNUNET_break (GNUNET_ATS_NET_UNSPECIFIED != scope);
677 prop.scope = scope; 1999 prop.scope = scope;
678 GST_ats_add_inbound_address (address, 2000 GST_ats_add_inbound_address (address,
@@ -750,6 +2072,167 @@ ats_request_address_change (void *cls,
750 2072
751 2073
752/** 2074/**
2075 * Closure for #test_connection_ok().
2076 */
2077struct TestConnectionContext
2078{
2079 /**
2080 * Is this the first neighbour we're checking?
2081 */
2082 int first;
2083
2084 /**
2085 * Handle to the blacklisting client we need to ask.
2086 */
2087 struct TransportClient *tc;
2088};
2089
2090
2091/**
2092 * Got the result about an existing connection from a new blacklister.
2093 * Shutdown the neighbour if necessary.
2094 *
2095 * @param cls unused
2096 * @param peer the neighbour that was investigated
2097 * @param address address associated with the request
2098 * @param session session associated with the request
2099 * @param allowed #GNUNET_OK if we can keep it,
2100 * #GNUNET_NO if we must shutdown the connection
2101 */
2102static void
2103confirm_or_drop_neighbour (void *cls,
2104 const struct GNUNET_PeerIdentity *peer,
2105 const struct GNUNET_HELLO_Address *address,
2106 struct GNUNET_ATS_Session *session,
2107 int allowed)
2108{
2109 if (GNUNET_OK == allowed)
2110 return; /* we're done */
2111 GNUNET_STATISTICS_update (GST_stats,
2112 gettext_noop ("# disconnects due to blacklist"),
2113 1,
2114 GNUNET_NO);
2115 GST_neighbours_force_disconnect (peer);
2116}
2117
2118
2119/**
2120 * Test if an existing connection is still acceptable given a new
2121 * blacklisting client.
2122 *
2123 * @param cls the `struct TestConnectionContext *`
2124 * @param peer identity of the peer
2125 * @param address the address
2126 * @param state current state this peer is in
2127 * @param state_timeout timeout for the current state of the peer
2128 * @param bandwidth_in bandwidth assigned inbound
2129 * @param bandwidth_out bandwidth assigned outbound
2130 */
2131static void
2132test_connection_ok (void *cls,
2133 const struct GNUNET_PeerIdentity *peer,
2134 const struct GNUNET_HELLO_Address *address,
2135 enum GNUNET_TRANSPORT_PeerState state,
2136 struct GNUNET_TIME_Absolute state_timeout,
2137 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in,
2138 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out)
2139{
2140 struct TestConnectionContext *tcc = cls;
2141 struct GST_BlacklistCheck *bc;
2142
2143 bc = GNUNET_new (struct GST_BlacklistCheck);
2144 GNUNET_CONTAINER_DLL_insert (bc_head,
2145 bc_tail,
2146 bc);
2147 bc->peer = *peer;
2148 bc->address = GNUNET_HELLO_address_copy (address);
2149 bc->cont = &confirm_or_drop_neighbour;
2150 bc->cont_cls = NULL;
2151 bc->bl_pos = tcc->tc;
2152 if (GNUNET_YES == tcc->first)
2153 {
2154 /* all would wait for the same client, no need to
2155 * create more than just the first task right now */
2156 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
2157 bc);
2158 tcc->first = GNUNET_NO;
2159 }
2160}
2161
2162
2163/**
2164 * Initialize a blacklisting client. We got a blacklist-init
2165 * message from this client, add him to the list of clients
2166 * to query for blacklisting.
2167 *
2168 * @param cls the client
2169 * @param message the blacklist-init message that was sent
2170 */
2171static void
2172handle_client_blacklist_init (void *cls,
2173 const struct GNUNET_MessageHeader *message)
2174{
2175 struct TransportClient *tc = cls;
2176 struct TestConnectionContext tcc;
2177
2178 if (CT_NONE != tc->type)
2179 {
2180 GNUNET_break (0);
2181 GNUNET_SERVICE_client_drop (tc->client);
2182 return;
2183 }
2184 GNUNET_SERVICE_client_mark_monitor (tc->client);
2185 tc->type = CT_BLACKLIST;
2186 tc->details.blacklist.call_receive_done = GNUNET_YES;
2187 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2188 "New blacklist client %p\n",
2189 tc);
2190 /* confirm that all existing connections are OK! */
2191 tcc.tc = tc;
2192 tcc.first = GNUNET_YES;
2193 GST_neighbours_iterate (&test_connection_ok,
2194 &tcc);
2195}
2196
2197
2198/**
2199 * Free the given entry in the blacklist.
2200 *
2201 * @param cls unused
2202 * @param key host identity (unused)
2203 * @param value the blacklist entry
2204 * @return #GNUNET_OK (continue to iterate)
2205 */
2206static int
2207free_blacklist_entry (void *cls,
2208 const struct GNUNET_PeerIdentity *key,
2209 void *value)
2210{
2211 char *be = value;
2212
2213 GNUNET_free_non_null (be);
2214 return GNUNET_OK;
2215}
2216
2217
2218/**
2219 * Set traffic metric to manipulate
2220 *
2221 * @param cls closure
2222 * @param message containing information
2223 */
2224static void
2225handle_client_set_metric (void *cls,
2226 const struct TrafficMetricMessage *tm)
2227{
2228 struct TransportClient *tc = cls;
2229
2230 GST_manipulation_set_metric (tm);
2231 GNUNET_SERVICE_client_continue (tc->client);
2232}
2233
2234
2235/**
753 * Function called when the service shuts down. Unloads our plugins 2236 * Function called when the service shuts down. Unloads our plugins
754 * and cancels pending validations. 2237 * and cancels pending validations.
755 * 2238 *
@@ -758,6 +2241,8 @@ ats_request_address_change (void *cls,
758static void 2241static void
759shutdown_task (void *cls) 2242shutdown_task (void *cls)
760{ 2243{
2244 struct AddressToStringContext *cur;
2245
761 GST_neighbours_stop (); 2246 GST_neighbours_stop ();
762 GST_plugins_unload (); 2247 GST_plugins_unload ();
763 GST_validation_stop (); 2248 GST_validation_stop ();
@@ -768,8 +2253,28 @@ shutdown_task (void *cls)
768 GST_ats_connect = NULL; 2253 GST_ats_connect = NULL;
769 GNUNET_ATS_scanner_done (GST_is); 2254 GNUNET_ATS_scanner_done (GST_is);
770 GST_is = NULL; 2255 GST_is = NULL;
771 GST_clients_stop (); 2256 while (NULL != (cur = a2s_head))
772 GST_blacklist_stop (); 2257 {
2258 GNUNET_CONTAINER_DLL_remove (a2s_head,
2259 a2s_tail,
2260 cur);
2261 GNUNET_free (cur);
2262 }
2263 if (NULL != plugin_nc)
2264 {
2265 GNUNET_notification_context_destroy (plugin_nc);
2266 plugin_nc = NULL;
2267 }
2268 GNUNET_CONTAINER_multipeermap_destroy (active_stccs);
2269 active_stccs = NULL;
2270 if (NULL != blacklist)
2271 {
2272 GNUNET_CONTAINER_multipeermap_iterate (blacklist,
2273 &free_blacklist_entry,
2274 NULL);
2275 GNUNET_CONTAINER_multipeermap_destroy (blacklist);
2276 blacklist = NULL;
2277 }
773 GST_hello_stop (); 2278 GST_hello_stop ();
774 GST_manipulation_stop (); 2279 GST_manipulation_stop ();
775 2280
@@ -785,10 +2290,452 @@ shutdown_task (void *cls)
785 } 2290 }
786 if (NULL != GST_my_private_key) 2291 if (NULL != GST_my_private_key)
787 { 2292 {
788 GNUNET_free(GST_my_private_key); 2293 GNUNET_free (GST_my_private_key);
789 GST_my_private_key = NULL; 2294 GST_my_private_key = NULL;
790 } 2295 }
791 GST_server = NULL; 2296}
2297
2298
2299/**
2300 * Perform next action in the blacklist check.
2301 *
2302 * @param cls the `struct GST_BlacklistCheck *`
2303 */
2304static void
2305do_blacklist_check (void *cls)
2306{
2307 struct GST_BlacklistCheck *bc = cls;
2308 struct TransportClient *tc;
2309 struct GNUNET_MQ_Envelope *env;
2310 struct BlacklistMessage *bm;
2311
2312 bc->task = NULL;
2313 while (NULL != (tc = bc->bl_pos))
2314 {
2315 if (CT_BLACKLIST == tc->type)
2316 break;
2317 bc->bl_pos = tc->next;
2318 }
2319 if (NULL == tc)
2320 {
2321 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2322 "No other blacklist clients active, will allow neighbour `%s'\n",
2323 GNUNET_i2s (&bc->peer));
2324
2325 bc->cont (bc->cont_cls,
2326 &bc->peer,
2327 bc->address,
2328 bc->session,
2329 GNUNET_OK);
2330 GST_blacklist_test_cancel (bc);
2331 return;
2332 }
2333 if ( (NULL != tc->details.blacklist.bc) ||
2334 (GNUNET_NO != tc->details.blacklist.waiting_for_reply) )
2335 return; /* someone else busy with this client */
2336 tc->details.blacklist.bc = bc;
2337 env = GNUNET_MQ_msg (bm,
2338 GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_QUERY);
2339 bm->is_allowed = htonl (0);
2340 bm->peer = bc->peer;
2341 GNUNET_MQ_send (tc->mq,
2342 env);
2343 if (GNUNET_YES == tc->details.blacklist.call_receive_done)
2344 {
2345 tc->details.blacklist.call_receive_done = GNUNET_NO;
2346 GNUNET_SERVICE_client_continue (tc->client);
2347 }
2348 tc->details.blacklist.waiting_for_reply = GNUNET_YES;
2349}
2350
2351
2352/**
2353 * A blacklisting client has sent us reply. Process it.
2354 *
2355 * @param cls the client
2356 * @param msg the blacklist-reply message that was sent
2357 */
2358static void
2359handle_client_blacklist_reply (void *cls,
2360 const struct BlacklistMessage *msg)
2361{
2362 struct TransportClient *tc = cls;
2363 struct GST_BlacklistCheck *bc;
2364
2365 if (CT_BLACKLIST != tc->type)
2366 {
2367 GNUNET_break (0);
2368 GNUNET_SERVICE_client_drop (tc->client);
2369 return;
2370 }
2371 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2372 "Blacklist client %p sent reply for `%s'\n",
2373 tc,
2374 GNUNET_i2s (&msg->peer));
2375 bc = tc->details.blacklist.bc;
2376 tc->details.blacklist.bc = NULL;
2377 tc->details.blacklist.waiting_for_reply = GNUNET_NO;
2378 tc->details.blacklist.call_receive_done = GNUNET_YES;
2379 if (NULL != bc)
2380 {
2381 /* only run this if the blacklist check has not been
2382 * cancelled in the meantime... */
2383 GNUNET_assert (bc->bl_pos == tc);
2384 if (ntohl (msg->is_allowed) == GNUNET_SYSERR)
2385 {
2386 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2387 "Blacklist check failed, peer not allowed\n");
2388 /* For the duration of the continuation, make the ongoing
2389 check invisible (to avoid double-cancellation); then
2390 add it back again so we can re-use GST_blacklist_test_cancel() */
2391 GNUNET_CONTAINER_DLL_remove (bc_head,
2392 bc_tail,
2393 bc);
2394 bc->cont (bc->cont_cls,
2395 &bc->peer,
2396 bc->address,
2397 bc->session,
2398 GNUNET_NO);
2399 GNUNET_CONTAINER_DLL_insert (bc_head,
2400 bc_tail,
2401 bc);
2402 GST_blacklist_test_cancel (bc);
2403 tc->details.blacklist.call_receive_done = GNUNET_NO;
2404 GNUNET_SERVICE_client_continue (tc->client);
2405 return;
2406 }
2407 else
2408 {
2409 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2410 "Blacklist check succeeded, continuing with checks\n");
2411 tc->details.blacklist.call_receive_done = GNUNET_NO;
2412 GNUNET_SERVICE_client_continue (tc->client);
2413 bc->bl_pos = tc->next;
2414 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
2415 bc);
2416 }
2417 }
2418 /* check if any other blacklist checks are waiting for this blacklister */
2419 for (bc = bc_head; bc != NULL; bc = bc->next)
2420 if ( (bc->bl_pos == tc) &&
2421 (NULL == bc->task) )
2422 {
2423 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
2424 bc);
2425 break;
2426 }
2427}
2428
2429
2430/**
2431 * Add the given peer to the blacklist (for the given transport).
2432 *
2433 * @param peer peer to blacklist
2434 * @param transport_name transport to blacklist for this peer, NULL for all
2435 */
2436void
2437GST_blacklist_add_peer (const struct GNUNET_PeerIdentity *peer,
2438 const char *transport_name)
2439{
2440 char *transport = NULL;
2441
2442 if (NULL != transport_name)
2443 {
2444 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2445 "Adding peer `%s' with plugin `%s' to blacklist\n",
2446 GNUNET_i2s (peer),
2447 transport_name);
2448 transport = GNUNET_strdup (transport_name);
2449 }
2450 else
2451 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2452 "Adding peer `%s' with all plugins to blacklist\n",
2453 GNUNET_i2s (peer));
2454 if (NULL == blacklist)
2455 blacklist =
2456 GNUNET_CONTAINER_multipeermap_create (TRANSPORT_BLACKLIST_HT_SIZE,
2457 GNUNET_NO);
2458
2459 GNUNET_CONTAINER_multipeermap_put (blacklist,
2460 peer,
2461 transport,
2462 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
2463}
2464
2465
2466/**
2467 * Abort blacklist if @a address and @a session match.
2468 *
2469 * @param address address used to abort matching checks
2470 * @param session session used to abort matching checks
2471 */
2472void
2473GST_blacklist_abort_matching (const struct GNUNET_HELLO_Address *address,
2474 struct GNUNET_ATS_Session *session)
2475{
2476 struct GST_BlacklistCheck *bc;
2477 struct GST_BlacklistCheck *n;
2478
2479 n = bc_head;
2480 while (NULL != (bc = n))
2481 {
2482 n = bc->next;
2483 if ( (bc->session == session) &&
2484 (0 == GNUNET_HELLO_address_cmp (bc->address,
2485 address)) )
2486 {
2487 bc->cont (bc->cont_cls,
2488 &bc->peer,
2489 bc->address,
2490 bc->session,
2491 GNUNET_SYSERR);
2492 GST_blacklist_test_cancel (bc);
2493 }
2494 }
2495}
2496
2497
2498/**
2499 * Test if the given blacklist entry matches. If so,
2500 * abort the iteration.
2501 *
2502 * @param cls the transport name to match (const char*)
2503 * @param key the key (unused)
2504 * @param value the 'char *' (name of a blacklisted transport)
2505 * @return #GNUNET_OK if the entry does not match, #GNUNET_NO if it matches
2506 */
2507static int
2508test_blacklisted (void *cls,
2509 const struct GNUNET_PeerIdentity *key,
2510 void *value)
2511{
2512 const char *transport_name = cls;
2513 char *be = value;
2514
2515 /* Blacklist entry be:
2516 * (NULL == be): peer is blacklisted with all plugins
2517 * (NULL != be): peer is blacklisted for a specific plugin
2518 *
2519 * If (NULL != transport_name) we look for a transport specific entry:
2520 * if (transport_name == be) forbidden
2521 *
2522 */
2523
2524 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2525 "Comparing BL request for peer `%4s':`%s' with BL entry: `%s'\n",
2526 GNUNET_i2s (key),
2527 (NULL == transport_name) ? "unspecified" : transport_name,
2528 (NULL == be) ? "all plugins" : be);
2529 /* all plugins for this peer were blacklisted: disallow */
2530 if (NULL == value)
2531 return GNUNET_NO;
2532
2533 /* blacklist check for specific transport */
2534 if ( (NULL != transport_name) &&
2535 (NULL != value) )
2536 {
2537 if (0 == strcmp (transport_name,
2538 be))
2539 return GNUNET_NO; /* plugin is blacklisted! */
2540 }
2541 return GNUNET_OK;
2542}
2543
2544
2545/**
2546 * Test if a peer/transport combination is blacklisted.
2547 *
2548 * @param peer the identity of the peer to test
2549 * @param transport_name name of the transport to test, never NULL
2550 * @param cont function to call with result
2551 * @param cont_cls closure for @a cont
2552 * @param address address to pass back to @a cont, can be NULL
2553 * @param session session to pass back to @a cont, can be NULL
2554 * @return handle to the blacklist check, NULL if the decision
2555 * was made instantly and @a cont was already called
2556 */
2557struct GST_BlacklistCheck *
2558GST_blacklist_test_allowed (const struct GNUNET_PeerIdentity *peer,
2559 const char *transport_name,
2560 GST_BlacklistTestContinuation cont,
2561 void *cont_cls,
2562 const struct GNUNET_HELLO_Address *address,
2563 struct GNUNET_ATS_Session *session)
2564{
2565 struct GST_BlacklistCheck *bc;
2566 struct TransportClient *tc;
2567
2568 GNUNET_assert (NULL != peer);
2569 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2570 "Blacklist check for peer `%s':%s\n",
2571 GNUNET_i2s (peer),
2572 (NULL != transport_name) ? transport_name : "unspecified");
2573
2574 /* Check local blacklist by iterating over hashmap
2575 * If iteration is aborted, we found a matching blacklist entry */
2576 if ((NULL != blacklist) &&
2577 (GNUNET_SYSERR ==
2578 GNUNET_CONTAINER_multipeermap_get_multiple (blacklist, peer,
2579 &test_blacklisted,
2580 (void *) transport_name)))
2581 {
2582 /* Disallowed by config, disapprove instantly */
2583 GNUNET_STATISTICS_update (GST_stats,
2584 gettext_noop ("# disconnects due to blacklist"),
2585 1,
2586 GNUNET_NO);
2587 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2588 _("Disallowing connection to peer `%s' on transport %s\n"),
2589 GNUNET_i2s (peer),
2590 (NULL != transport_name) ? transport_name : "unspecified");
2591 if (NULL != cont)
2592 cont (cont_cls,
2593 peer,
2594 address,
2595 session,
2596 GNUNET_NO);
2597 return NULL;
2598 }
2599
2600 for (tc = clients_head; NULL != tc; tc = tc->next)
2601 if (CT_BLACKLIST == tc->type)
2602 break;
2603 if (NULL == tc)
2604 {
2605 /* no blacklist clients, approve instantly */
2606 if (NULL != cont)
2607 cont (cont_cls,
2608 peer,
2609 address,
2610 session,
2611 GNUNET_OK);
2612 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2613 "Allowing connection to peer `%s' %s\n",
2614 GNUNET_i2s (peer),
2615 (NULL != transport_name) ? transport_name : "");
2616 return NULL;
2617 }
2618
2619 /* need to query blacklist clients */
2620 bc = GNUNET_new (struct GST_BlacklistCheck);
2621 GNUNET_CONTAINER_DLL_insert (bc_head,
2622 bc_tail,
2623 bc);
2624 bc->peer = *peer;
2625 bc->address = GNUNET_HELLO_address_copy (address);
2626 bc->session = session;
2627 bc->cont = cont;
2628 bc->cont_cls = cont_cls;
2629 bc->bl_pos = tc;
2630 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
2631 bc);
2632 return bc;
2633}
2634
2635
2636/**
2637 * Cancel a blacklist check.
2638 *
2639 * @param bc check to cancel
2640 */
2641void
2642GST_blacklist_test_cancel (struct GST_BlacklistCheck *bc)
2643{
2644 GNUNET_CONTAINER_DLL_remove (bc_head,
2645 bc_tail,
2646 bc);
2647 if (NULL != bc->bl_pos)
2648 {
2649 if ( (CT_BLACKLIST == bc->bl_pos->type) &&
2650 (bc->bl_pos->details.blacklist.bc == bc) )
2651 {
2652 /* we're at the head of the queue, remove us! */
2653 bc->bl_pos->details.blacklist.bc = NULL;
2654 }
2655 }
2656 if (NULL != bc->task)
2657 {
2658 GNUNET_SCHEDULER_cancel (bc->task);
2659 bc->task = NULL;
2660 }
2661 GNUNET_free_non_null (bc->address);
2662 GNUNET_free (bc);
2663}
2664
2665
2666/**
2667 * Function to iterate over options in the blacklisting section for a peer.
2668 *
2669 * @param cls closure
2670 * @param section name of the section
2671 * @param option name of the option
2672 * @param value value of the option
2673 */
2674static void
2675blacklist_cfg_iter (void *cls,
2676 const char *section,
2677 const char *option,
2678 const char *value)
2679{
2680 unsigned int *res = cls;
2681 struct GNUNET_PeerIdentity peer;
2682 char *plugs;
2683 char *pos;
2684
2685 if (GNUNET_OK !=
2686 GNUNET_CRYPTO_eddsa_public_key_from_string (option,
2687 strlen (option),
2688 &peer.public_key))
2689 return;
2690
2691 if ((NULL == value) || (0 == strcmp(value, "")))
2692 {
2693 /* Blacklist whole peer */
2694 GST_blacklist_add_peer (&peer, NULL);
2695 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2696 _("Adding blacklisting entry for peer `%s'\n"),
2697 GNUNET_i2s (&peer));
2698 }
2699 else
2700 {
2701 plugs = GNUNET_strdup (value);
2702 for (pos = strtok (plugs, " "); pos != NULL; pos = strtok (NULL, " "))
2703 {
2704 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2705 _("Adding blacklisting entry for peer `%s':`%s'\n"),
2706 GNUNET_i2s (&peer), pos);
2707 GST_blacklist_add_peer (&peer, pos);
2708 }
2709 GNUNET_free (plugs);
2710 }
2711 (*res)++;
2712}
2713
2714
2715/**
2716 * Read blacklist configuration
2717 *
2718 * @param cfg the configuration handle
2719 * @param my_id my peer identity
2720 */
2721static void
2722read_blacklist_configuration (const struct GNUNET_CONFIGURATION_Handle *cfg,
2723 const struct GNUNET_PeerIdentity *my_id)
2724{
2725 char cfg_sect[512];
2726 unsigned int res = 0;
2727
2728 GNUNET_snprintf (cfg_sect,
2729 sizeof (cfg_sect),
2730 "transport-blacklist-%s",
2731 GNUNET_i2s_full (my_id));
2732 GNUNET_CONFIGURATION_iterate_section_values (cfg,
2733 cfg_sect,
2734 &blacklist_cfg_iter,
2735 &res);
2736 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2737 "Loaded %u blacklisting entries from configuration\n",
2738 res);
792} 2739}
793 2740
794 2741
@@ -796,13 +2743,13 @@ shutdown_task (void *cls)
796 * Initiate transport service. 2743 * Initiate transport service.
797 * 2744 *
798 * @param cls closure 2745 * @param cls closure
799 * @param server the initialized server
800 * @param c configuration to use 2746 * @param c configuration to use
2747 * @param service the initialized service
801 */ 2748 */
802static void 2749static void
803run (void *cls, 2750run (void *cls,
804 struct GNUNET_SERVER_Handle *server, 2751 const struct GNUNET_CONFIGURATION_Handle *c,
805 const struct GNUNET_CONFIGURATION_Handle *c) 2752 struct GNUNET_SERVICE_Handle *service)
806{ 2753{
807 char *keyfile; 2754 char *keyfile;
808 struct GNUNET_CRYPTO_EddsaPrivateKey *pk; 2755 struct GNUNET_CRYPTO_EddsaPrivateKey *pk;
@@ -832,7 +2779,6 @@ run (void *cls,
832 { 2779 {
833 hello_expiration = GNUNET_CONSTANTS_HELLO_ADDRESS_EXPIRATION; 2780 hello_expiration = GNUNET_CONSTANTS_HELLO_ADDRESS_EXPIRATION;
834 } 2781 }
835 GST_server = server;
836 pk = GNUNET_CRYPTO_eddsa_key_create_from_file (keyfile); 2782 pk = GNUNET_CRYPTO_eddsa_key_create_from_file (keyfile);
837 GNUNET_free (keyfile); 2783 GNUNET_free (keyfile);
838 GNUNET_assert (NULL != pk); 2784 GNUNET_assert (NULL != pk);
@@ -842,7 +2788,7 @@ run (void *cls,
842 GST_peerinfo = GNUNET_PEERINFO_connect (GST_cfg); 2788 GST_peerinfo = GNUNET_PEERINFO_connect (GST_cfg);
843 GNUNET_CRYPTO_eddsa_key_get_public (GST_my_private_key, 2789 GNUNET_CRYPTO_eddsa_key_get_public (GST_my_private_key,
844 &GST_my_identity.public_key); 2790 &GST_my_identity.public_key);
845 GNUNET_assert(NULL != GST_my_private_key); 2791 GNUNET_assert (NULL != GST_my_private_key);
846 2792
847 GNUNET_log(GNUNET_ERROR_TYPE_INFO, 2793 GNUNET_log(GNUNET_ERROR_TYPE_INFO,
848 "My identity is `%4s'\n", 2794 "My identity is `%4s'\n",
@@ -852,24 +2798,28 @@ run (void *cls,
852 NULL); 2798 NULL);
853 if (NULL == GST_peerinfo) 2799 if (NULL == GST_peerinfo)
854 { 2800 {
855 GNUNET_log(GNUNET_ERROR_TYPE_ERROR, 2801 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
856 _("Could not access PEERINFO service. Exiting.\n")); 2802 _("Could not access PEERINFO service. Exiting.\n"));
857 GNUNET_SCHEDULER_shutdown (); 2803 GNUNET_SCHEDULER_shutdown ();
858 return; 2804 return;
859 } 2805 }
860 2806
861 max_fd_rlimit = 0; 2807 max_fd_rlimit = 0;
862#if HAVE_GETRLIMIT 2808#if HAVE_GETRLIMIT
863 struct rlimit r_file;
864 if (0 == getrlimit (RLIMIT_NOFILE, &r_file))
865 { 2809 {
866 max_fd_rlimit = r_file.rlim_cur; 2810 struct rlimit r_file;
867 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 2811
868 "Maximum number of open files was: %u/%u\n", 2812 if (0 == getrlimit (RLIMIT_NOFILE,
869 (unsigned int) r_file.rlim_cur, 2813 &r_file))
870 (unsigned int) r_file.rlim_max); 2814 {
2815 max_fd_rlimit = r_file.rlim_cur;
2816 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2817 "Maximum number of open files was: %u/%u\n",
2818 (unsigned int) r_file.rlim_cur,
2819 (unsigned int) r_file.rlim_max);
2820 }
2821 max_fd_rlimit = (9 * max_fd_rlimit) / 10; /* Keep 10% for rest of transport */
871 } 2822 }
872 max_fd_rlimit = (9 * max_fd_rlimit) / 10; /* Keep 10% for rest of transport */
873#endif 2823#endif
874 if (GNUNET_OK != 2824 if (GNUNET_OK !=
875 GNUNET_CONFIGURATION_get_value_number (GST_cfg, 2825 GNUNET_CONFIGURATION_get_value_number (GST_cfg,
@@ -897,9 +2847,8 @@ run (void *cls,
897 if (GNUNET_SYSERR == friend_only) 2847 if (GNUNET_SYSERR == friend_only)
898 friend_only = GNUNET_NO; /* According to topology defaults */ 2848 friend_only = GNUNET_NO; /* According to topology defaults */
899 /* start subsystems */ 2849 /* start subsystems */
900 GST_blacklist_start (GST_server, 2850 read_blacklist_configuration (GST_cfg,
901 GST_cfg, 2851 &GST_my_identity);
902 &GST_my_identity);
903 GST_is = GNUNET_ATS_scanner_init (); 2852 GST_is = GNUNET_ATS_scanner_init ();
904 GST_ats_connect = GNUNET_ATS_connectivity_init (GST_cfg); 2853 GST_ats_connect = GNUNET_ATS_connectivity_init (GST_cfg);
905 GST_ats = GNUNET_ATS_scheduling_init (GST_cfg, 2854 GST_ats = GNUNET_ATS_scheduling_init (GST_cfg,
@@ -915,26 +2864,60 @@ run (void *cls,
915 &process_hello_update, 2864 &process_hello_update,
916 NULL); 2865 NULL);
917 GST_neighbours_start ((max_fd / 3) * 2); 2866 GST_neighbours_start ((max_fd / 3) * 2);
918 GST_clients_start (GST_server); 2867 active_stccs = GNUNET_CONTAINER_multipeermap_create (128,
2868 GNUNET_YES);
2869 plugin_nc = GNUNET_notification_context_create (0);
919 GST_validation_start ((max_fd / 3)); 2870 GST_validation_start ((max_fd / 3));
920} 2871}
921 2872
922 2873
923/** 2874/**
924 * The main function for the transport service. 2875 * Define "main" method using service macro.
925 *
926 * @param argc number of arguments from the command line
927 * @param argv command line arguments
928 * @return 0 ok, 1 on error
929 */ 2876 */
930int 2877GNUNET_SERVICE_MAIN
931main (int argc, 2878("transport",
932 char * const *argv) 2879 GNUNET_SERVICE_OPTION_NONE,
933{ 2880 &run,
934 return 2881 &client_connect_cb,
935 (GNUNET_OK 2882 &client_disconnect_cb,
936 == GNUNET_SERVICE_run (argc, argv, "transport", 2883 NULL,
937 GNUNET_SERVICE_OPTION_NONE, &run, NULL )) ? 0 : 1; 2884 GNUNET_MQ_hd_fixed_size (client_start,
938} 2885 GNUNET_MESSAGE_TYPE_TRANSPORT_START,
2886 struct StartMessage,
2887 NULL),
2888 GNUNET_MQ_hd_var_size (client_hello,
2889 GNUNET_MESSAGE_TYPE_HELLO,
2890 struct GNUNET_MessageHeader,
2891 NULL),
2892 GNUNET_MQ_hd_var_size (client_send,
2893 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND,
2894 struct OutboundMessage,
2895 NULL),
2896 GNUNET_MQ_hd_var_size (client_address_to_string,
2897 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_TO_STRING,
2898 struct AddressLookupMessage,
2899 NULL),
2900 GNUNET_MQ_hd_fixed_size (client_monitor_peers,
2901 GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_PEER_REQUEST,
2902 struct PeerMonitorMessage,
2903 NULL),
2904 GNUNET_MQ_hd_fixed_size (client_blacklist_init,
2905 GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_INIT,
2906 struct GNUNET_MessageHeader,
2907 NULL),
2908 GNUNET_MQ_hd_fixed_size (client_blacklist_reply,
2909 GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_REPLY,
2910 struct BlacklistMessage,
2911 NULL),
2912 GNUNET_MQ_hd_fixed_size (client_set_metric,
2913 GNUNET_MESSAGE_TYPE_TRANSPORT_TRAFFIC_METRIC,
2914 struct TrafficMetricMessage,
2915 NULL),
2916 GNUNET_MQ_hd_fixed_size (client_monitor_plugins,
2917 GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_PLUGIN_START,
2918 struct GNUNET_MessageHeader,
2919 NULL),
2920 GNUNET_MQ_handler_end ());
2921
939 2922
940/* end of file gnunet-service-transport.c */ 2923/* end of file gnunet-service-transport.c */
diff --git a/src/transport/gnunet-service-transport.h b/src/transport/gnunet-service-transport.h
index 981996a00..2807afd79 100644
--- a/src/transport/gnunet-service-transport.h
+++ b/src/transport/gnunet-service-transport.h
@@ -92,6 +92,83 @@ typedef void
92 92
93 93
94/** 94/**
95 * Continuation called from a blacklist test.
96 *
97 * @param cls closure
98 * @param peer identity of peer that was tested
99 * @param address address associated with the request
100 * @param session session associated with the request
101 * @param result #GNUNET_OK if the connection is allowed,
102 * #GNUNET_NO if not,
103 * #GNUNET_SYSERR if operation was aborted
104 */
105typedef void
106(*GST_BlacklistTestContinuation) (void *cls,
107 const struct GNUNET_PeerIdentity *peer,
108 const struct GNUNET_HELLO_Address *address,
109 struct GNUNET_ATS_Session *session,
110 int result);
111
112
113/**
114 * Add the given peer to the blacklist (for the given transport).
115 *
116 * @param peer peer to blacklist
117 * @param transport_name transport to blacklist for this peer, NULL for all
118 */
119void
120GST_blacklist_add_peer (const struct GNUNET_PeerIdentity *peer,
121 const char *transport_name);
122
123
124/**
125 * Handle to an active blacklist check.
126 */
127struct GST_BlacklistCheck;
128
129
130
131/**
132 * Test if a peer/transport combination is blacklisted.
133 *
134 * @param peer the identity of the peer to test
135 * @param transport_name name of the transport to test, never NULL
136 * @param cont function to call with result
137 * @param cont_cls closure for @a cont
138 * @param address address to pass back to @a cont, can be NULL
139 * @param session session to pass back to @a cont, can be NULL
140 * @return handle to the blacklist check, NULL if the decision
141 * was made instantly and @a cont was already called
142 */
143struct GST_BlacklistCheck *
144GST_blacklist_test_allowed (const struct GNUNET_PeerIdentity *peer,
145 const char *transport_name,
146 GST_BlacklistTestContinuation cont,
147 void *cont_cls,
148 const struct GNUNET_HELLO_Address *address,
149 struct GNUNET_ATS_Session *session);
150
151
152/**
153 * Abort blacklist if @a address and @a session match.
154 *
155 * @param address address used to abort matching checks
156 * @param session session used to abort matching checks
157 */
158void
159GST_blacklist_abort_matching (const struct GNUNET_HELLO_Address *address,
160 struct GNUNET_ATS_Session *session);
161
162/**
163 * Cancel a blacklist check.
164 *
165 * @param bc check to cancel
166 */
167void
168GST_blacklist_test_cancel (struct GST_BlacklistCheck *bc);
169
170
171/**
95 * Function called by the transport for each received message. 172 * Function called by the transport for each received message.
96 * 173 *
97 * @param cls closure, const char* with the name of the plugin we received the message from 174 * @param cls closure, const char* with the name of the plugin we received the message from
@@ -110,6 +187,41 @@ GST_receive_callback (void *cls,
110 struct GNUNET_ATS_Session *session, 187 struct GNUNET_ATS_Session *session,
111 const struct GNUNET_MessageHeader *message); 188 const struct GNUNET_MessageHeader *message);
112 189
190/**
191 * Broadcast the given message to all of our clients.
192 *
193 * @param msg message to broadcast
194 * @param may_drop #GNUNET_YES if the message can be dropped / is payload
195 */
196void
197GST_clients_broadcast (const struct GNUNET_MessageHeader *msg,
198 int may_drop);
199
200
201/**
202 * Broadcast the new active address to all clients monitoring the peer.
203 *
204 * @param peer peer this update is about (never NULL)
205 * @param address address, NULL on disconnect
206 * @param state the current state of the peer
207 * @param state_timeout the time out for the state
208 */
209void
210GST_clients_broadcast_peer_notification (const struct GNUNET_PeerIdentity *peer,
211 const struct GNUNET_HELLO_Address *address,
212 enum GNUNET_TRANSPORT_PeerState state,
213 struct GNUNET_TIME_Absolute state_timeout);
214
215
216/**
217 * Notify all clients about a disconnect, and cancel
218 * pending SEND_OK messages for this peer.
219 *
220 * @param peer peer that disconnected
221 */
222void
223GST_clients_broadcast_disconnect (const struct GNUNET_PeerIdentity *peer);
224
113 225
114 226
115 227
diff --git a/src/transport/gnunet-service-transport_blacklist.c b/src/transport/gnunet-service-transport_blacklist.c
deleted file mode 100644
index b6c36a6cd..000000000
--- a/src/transport/gnunet-service-transport_blacklist.c
+++ /dev/null
@@ -1,933 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2010,2011 GNUnet e.V.
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
19*/
20
21/**
22 * @file transport/gnunet-service-transport_blacklist.c
23 * @brief blacklisting implementation
24 * @author Christian Grothoff
25 * @author Matthias Wachs
26 * @details This is the blacklisting component of transport service. With
27 * blacklisting it is possible to deny connections to specific peers of
28 * to use a specific plugin to a specific peer. Peers can be blacklisted using
29 * the configuration or a blacklist client can be asked.
30 *
31 * To blacklist peers using the configuration you have to add a section to your
32 * configuration containing the peer id of the peer to blacklist and the plugin
33 * if required.
34 *
35 * Example:
36 * To blacklist connections to P565... on peer AG2P... using tcp add:
37 * [transport-blacklist-AG2PHES1BARB9IJCPAMJTFPVJ5V3A72S3F2A8SBUB8DAQ2V0O3V8G6G2JU56FHGFOHMQVKBSQFV98TCGTC3RJ1NINP82G0RC00N1520]
38 * P565723JO1C2HSN6J29TAQ22MN6CI8HTMUU55T0FUQG4CMDGGEQ8UCNBKUMB94GC8R9G4FB2SF9LDOBAJ6AMINBP4JHHDD6L7VD801G = tcp
39 *
40 * To blacklist connections to P565... on peer AG2P... using all plugins add:
41 * [transport-blacklist-AG2PHES1BARB9IJCPAMJTFPVJ5V3A72S3F2A8SBUB8DAQ2V0O3V8G6G2JU56FHGFOHMQVKBSQFV98TCGTC3RJ1NINP82G0RC00N1520]
42 * P565723JO1C2HSN6J29TAQ22MN6CI8HTMUU55T0FUQG4CMDGGEQ8UCNBKUMB94GC8R9G4FB2SF9LDOBAJ6AMINBP4JHHDD6L7VD801G =
43 *
44 * You can also add a blacklist client usign the blacklist api. On a blacklist
45 * check, blacklisting first checks internally if the peer is blacklisted and
46 * if not, it asks the blacklisting clients. Clients are asked if it is OK to
47 * connect to a peer ID, the plugin is omitted.
48 *
49 * On blacklist check for (peer, plugin)
50 * - Do we have a local blacklist entry for this peer and this plugin?
51 * - YES: disallow connection
52 * - Do we have a local blacklist entry for this peer and all plugins?
53 * - YES: disallow connection
54 * - Does one of the clients disallow?
55 * - YES: disallow connection
56 *
57 */
58#include "platform.h"
59#include "gnunet-service-transport.h"
60#include "gnunet-service-transport_blacklist.h"
61#include "gnunet-service-transport_neighbours.h"
62#include "transport.h"
63
64/**
65 * Size of the blacklist hash map.
66 */
67#define TRANSPORT_BLACKLIST_HT_SIZE 64
68
69
70/**
71 * Context we use when performing a blacklist check.
72 */
73struct GST_BlacklistCheck;
74
75
76/**
77 * Information kept for each client registered to perform
78 * blacklisting.
79 */
80struct Blacklisters
81{
82 /**
83 * This is a linked list.
84 */
85 struct Blacklisters *next;
86
87 /**
88 * This is a linked list.
89 */
90 struct Blacklisters *prev;
91
92 /**
93 * Client responsible for this entry.
94 */
95 struct GNUNET_SERVER_Client *client;
96
97 /**
98 * Blacklist check that we're currently performing (or NULL
99 * if we're performing one that has been cancelled).
100 */
101 struct GST_BlacklistCheck *bc;
102
103 /**
104 * Set to #GNUNET_YES if we're currently waiting for a reply.
105 */
106 int waiting_for_reply;
107
108 /**
109 * #GNUNET_YES if we have to call receive_done for this client
110 */
111 int call_receive_done;
112
113};
114
115
116
117/**
118 * Context we use when performing a blacklist check.
119 */
120struct GST_BlacklistCheck
121{
122
123 /**
124 * This is a linked list.
125 */
126 struct GST_BlacklistCheck *next;
127
128 /**
129 * This is a linked list.
130 */
131 struct GST_BlacklistCheck *prev;
132
133 /**
134 * Peer being checked.
135 */
136 struct GNUNET_PeerIdentity peer;
137
138 /**
139 * Continuation to call with the result.
140 */
141 GST_BlacklistTestContinuation cont;
142
143 /**
144 * Closure for @e cont.
145 */
146 void *cont_cls;
147
148 /**
149 * Address for #GST_blacklist_abort_matching(), can be NULL.
150 */
151 struct GNUNET_HELLO_Address *address;
152
153 /**
154 * Session for #GST_blacklist_abort_matching(), can be NULL.
155 */
156 struct GNUNET_ATS_Session *session;
157
158 /**
159 * Current transmission request handle for this client, or NULL if no
160 * request is pending.
161 */
162 struct GNUNET_SERVER_TransmitHandle *th;
163
164 /**
165 * Our current position in the blacklisters list.
166 */
167 struct Blacklisters *bl_pos;
168
169 /**
170 * Current task performing the check.
171 */
172 struct GNUNET_SCHEDULER_Task *task;
173
174};
175
176
177/**
178 * Head of DLL of active blacklisting queries.
179 */
180static struct GST_BlacklistCheck *bc_head;
181
182/**
183 * Tail of DLL of active blacklisting queries.
184 */
185static struct GST_BlacklistCheck *bc_tail;
186
187/**
188 * Head of DLL of blacklisting clients.
189 */
190static struct Blacklisters *bl_head;
191
192/**
193 * Tail of DLL of blacklisting clients.
194 */
195static struct Blacklisters *bl_tail;
196
197/**
198 * Hashmap of blacklisted peers. Values are of type 'char *' (transport names),
199 * can be NULL if we have no static blacklist.
200 */
201static struct GNUNET_CONTAINER_MultiPeerMap *blacklist;
202
203
204/**
205 * Perform next action in the blacklist check.
206 *
207 * @param cls the `struct BlacklistCheck*`
208 */
209static void
210do_blacklist_check (void *cls);
211
212
213/**
214 * Called whenever a client is disconnected. Frees our
215 * resources associated with that client.
216 *
217 * @param cls closure (unused)
218 * @param client identification of the client
219 */
220static void
221client_disconnect_notification (void *cls,
222 struct GNUNET_SERVER_Client *client)
223{
224 struct Blacklisters *bl;
225 struct GST_BlacklistCheck *bc;
226
227 if (NULL == client)
228 return;
229 for (bl = bl_head; bl != NULL; bl = bl->next)
230 {
231 if (bl->client != client)
232 continue;
233 for (bc = bc_head; NULL != bc; bc = bc->next)
234 {
235 if (bc->bl_pos != bl)
236 continue;
237 bc->bl_pos = bl->next;
238 if (NULL != bc->th)
239 {
240 GNUNET_SERVER_notify_transmit_ready_cancel (bc->th);
241 bc->th = NULL;
242 }
243 if (NULL == bc->task)
244 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check, bc);
245 }
246 GNUNET_CONTAINER_DLL_remove (bl_head, bl_tail, bl);
247 GNUNET_SERVER_client_drop (bl->client);
248 GNUNET_free (bl);
249 break;
250 }
251}
252
253
254/**
255 * Function to iterate over options in the blacklisting section for a peer.
256 *
257 * @param cls closure
258 * @param section name of the section
259 * @param option name of the option
260 * @param value value of the option
261 */
262static void
263blacklist_cfg_iter (void *cls,
264 const char *section,
265 const char *option,
266 const char *value)
267{
268 unsigned int *res = cls;
269 struct GNUNET_PeerIdentity peer;
270 char *plugs;
271 char *pos;
272
273 if (GNUNET_OK !=
274 GNUNET_CRYPTO_eddsa_public_key_from_string (option,
275 strlen (option),
276 &peer.public_key))
277 return;
278
279 if ((NULL == value) || (0 == strcmp(value, "")))
280 {
281 /* Blacklist whole peer */
282 GST_blacklist_add_peer (&peer, NULL);
283 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
284 _("Adding blacklisting entry for peer `%s'\n"),
285 GNUNET_i2s (&peer));
286 }
287 else
288 {
289 plugs = GNUNET_strdup (value);
290 for (pos = strtok (plugs, " "); pos != NULL; pos = strtok (NULL, " "))
291 {
292 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
293 _("Adding blacklisting entry for peer `%s':`%s'\n"),
294 GNUNET_i2s (&peer), pos);
295 GST_blacklist_add_peer (&peer, pos);
296 }
297 GNUNET_free (plugs);
298 }
299 (*res)++;
300}
301
302
303/**
304 * Read blacklist configuration
305 *
306 * @param cfg the configuration handle
307 * @param my_id my peer identity
308 */
309static void
310read_blacklist_configuration (const struct GNUNET_CONFIGURATION_Handle *cfg,
311 const struct GNUNET_PeerIdentity *my_id)
312{
313 char cfg_sect[512];
314 unsigned int res = 0;
315
316 GNUNET_snprintf (cfg_sect,
317 sizeof (cfg_sect),
318 "transport-blacklist-%s",
319 GNUNET_i2s_full (my_id));
320 GNUNET_CONFIGURATION_iterate_section_values (cfg,
321 cfg_sect,
322 &blacklist_cfg_iter,
323 &res);
324 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
325 "Loaded %u blacklisting entries from configuration\n",
326 res);
327}
328
329
330/**
331 * Start blacklist subsystem.
332 *
333 * @param server server used to accept clients from
334 * @param cfg configuration handle
335 * @param my_id my peer id
336 */
337void
338GST_blacklist_start (struct GNUNET_SERVER_Handle *server,
339 const struct GNUNET_CONFIGURATION_Handle *cfg,
340 const struct GNUNET_PeerIdentity *my_id)
341{
342 GNUNET_assert (NULL != cfg);
343 GNUNET_assert (NULL != my_id);
344 read_blacklist_configuration (cfg, my_id);
345 GNUNET_SERVER_disconnect_notify (server,
346 &client_disconnect_notification,
347 NULL);
348}
349
350
351/**
352 * Free the given entry in the blacklist.
353 *
354 * @param cls unused
355 * @param key host identity (unused)
356 * @param value the blacklist entry
357 * @return #GNUNET_OK (continue to iterate)
358 */
359static int
360free_blacklist_entry (void *cls,
361 const struct GNUNET_PeerIdentity *key,
362 void *value)
363{
364 char *be = value;
365
366 GNUNET_free_non_null (be);
367 return GNUNET_OK;
368}
369
370
371/**
372 * Stop blacklist subsystem.
373 */
374void
375GST_blacklist_stop ()
376{
377 if (NULL == blacklist)
378 return;
379 GNUNET_CONTAINER_multipeermap_iterate (blacklist,
380 &free_blacklist_entry,
381 NULL);
382 GNUNET_CONTAINER_multipeermap_destroy (blacklist);
383 blacklist = NULL;
384}
385
386
387/**
388 * Transmit blacklist query to the client.
389 *
390 * @param cls the `struct GST_BlacklistCheck`
391 * @param size number of bytes allowed
392 * @param buf where to copy the message
393 * @return number of bytes copied to @a buf
394 */
395static size_t
396transmit_blacklist_message (void *cls,
397 size_t size,
398 void *buf)
399{
400 struct GST_BlacklistCheck *bc = cls;
401 struct Blacklisters *bl;
402 struct BlacklistMessage bm;
403
404 bc->th = NULL;
405 if (0 == size)
406 {
407 GNUNET_assert (NULL == bc->task);
408 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
409 bc);
410 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
411 "Failed to send blacklist test for peer `%s' to client\n",
412 GNUNET_i2s (&bc->peer));
413 return 0;
414 }
415 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
416 "Sending blacklist test for peer `%s' to client %p\n",
417 GNUNET_i2s (&bc->peer),
418 bc->bl_pos->client);
419 bl = bc->bl_pos;
420 bm.header.size = htons (sizeof (struct BlacklistMessage));
421 bm.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_QUERY);
422 bm.is_allowed = htonl (0);
423 bm.peer = bc->peer;
424 GNUNET_memcpy (buf,
425 &bm,
426 sizeof (bm));
427 if (GNUNET_YES == bl->call_receive_done)
428 {
429 GNUNET_SERVER_receive_done (bl->client,
430 GNUNET_OK);
431 bl->call_receive_done = GNUNET_NO;
432 }
433
434 bl->waiting_for_reply = GNUNET_YES;
435 return sizeof (bm);
436}
437
438
439/**
440 * Perform next action in the blacklist check.
441 *
442 * @param cls the `struct GST_BlacklistCheck *`
443 */
444static void
445do_blacklist_check (void *cls)
446{
447 struct GST_BlacklistCheck *bc = cls;
448 struct Blacklisters *bl;
449
450 bc->task = NULL;
451 bl = bc->bl_pos;
452 if (NULL == bl)
453 {
454 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
455 "No other blacklist clients active, will allow neighbour `%s'\n",
456 GNUNET_i2s (&bc->peer));
457
458 bc->cont (bc->cont_cls,
459 &bc->peer,
460 bc->address,
461 bc->session,
462 GNUNET_OK);
463 GST_blacklist_test_cancel (bc);
464 return;
465 }
466 if ( (NULL != bl->bc) ||
467 (GNUNET_NO != bl->waiting_for_reply) )
468 return; /* someone else busy with this client */
469 bl->bc = bc;
470 bc->th =
471 GNUNET_SERVER_notify_transmit_ready (bl->client,
472 sizeof (struct BlacklistMessage),
473 GNUNET_TIME_UNIT_FOREVER_REL,
474 &transmit_blacklist_message,
475 bc);
476}
477
478
479/**
480 * Got the result about an existing connection from a new blacklister.
481 * Shutdown the neighbour if necessary.
482 *
483 * @param cls unused
484 * @param peer the neighbour that was investigated
485 * @param address address associated with the request
486 * @param session session associated with the request
487 * @param allowed #GNUNET_OK if we can keep it,
488 * #GNUNET_NO if we must shutdown the connection
489 */
490static void
491confirm_or_drop_neighbour (void *cls,
492 const struct GNUNET_PeerIdentity *peer,
493 const struct GNUNET_HELLO_Address *address,
494 struct GNUNET_ATS_Session *session,
495 int allowed)
496{
497 if (GNUNET_OK == allowed)
498 return; /* we're done */
499 GNUNET_STATISTICS_update (GST_stats,
500 gettext_noop ("# disconnects due to blacklist"),
501 1,
502 GNUNET_NO);
503 GST_neighbours_force_disconnect (peer);
504}
505
506
507/**
508 * Closure for #test_connection_ok().
509 */
510struct TestConnectionContext
511{
512 /**
513 * Is this the first neighbour we're checking?
514 */
515 int first;
516
517 /**
518 * Handle to the blacklisting client we need to ask.
519 */
520 struct Blacklisters *bl;
521};
522
523
524/**
525 * Test if an existing connection is still acceptable given a new
526 * blacklisting client.
527 *
528 * @param cls the `struct TestConnectionContext *`
529 * @param peer identity of the peer
530 * @param address the address
531 * @param state current state this peer is in
532 * @param state_timeout timeout for the current state of the peer
533 * @param bandwidth_in bandwidth assigned inbound
534 * @param bandwidth_out bandwidth assigned outbound
535 */
536static void
537test_connection_ok (void *cls,
538 const struct GNUNET_PeerIdentity *peer,
539 const struct GNUNET_HELLO_Address *address,
540 enum GNUNET_TRANSPORT_PeerState state,
541 struct GNUNET_TIME_Absolute state_timeout,
542 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in,
543 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out)
544{
545 struct TestConnectionContext *tcc = cls;
546 struct GST_BlacklistCheck *bc;
547
548 bc = GNUNET_new (struct GST_BlacklistCheck);
549 GNUNET_CONTAINER_DLL_insert (bc_head,
550 bc_tail,
551 bc);
552 bc->peer = *peer;
553 bc->address = GNUNET_HELLO_address_copy (address);
554 bc->cont = &confirm_or_drop_neighbour;
555 bc->cont_cls = NULL;
556 bc->bl_pos = tcc->bl;
557 if (GNUNET_YES == tcc->first)
558 {
559 /* all would wait for the same client, no need to
560 * create more than just the first task right now */
561 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check, bc);
562 tcc->first = GNUNET_NO;
563 }
564}
565
566
567/**
568 * Initialize a blacklisting client. We got a blacklist-init
569 * message from this client, add him to the list of clients
570 * to query for blacklisting.
571 *
572 * @param cls unused
573 * @param client the client
574 * @param message the blacklist-init message that was sent
575 */
576void
577GST_blacklist_handle_init (void *cls,
578 struct GNUNET_SERVER_Client *client,
579 const struct GNUNET_MessageHeader *message)
580{
581 struct Blacklisters *bl;
582 struct TestConnectionContext tcc;
583
584 for (bl = bl_head; NULL != bl; bl = bl->next)
585 if (bl->client == client)
586 {
587 GNUNET_break (0);
588 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
589 return;
590 }
591
592 GNUNET_SERVER_client_mark_monitor (client);
593 bl = GNUNET_new (struct Blacklisters);
594 bl->client = client;
595 bl->call_receive_done = GNUNET_YES;
596 GNUNET_SERVER_client_keep (client);
597 GNUNET_CONTAINER_DLL_insert_after (bl_head,
598 bl_tail,
599 bl_tail,
600 bl);
601 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
602 "New blacklist client %p\n",
603 client);
604
605 /* confirm that all existing connections are OK! */
606 tcc.bl = bl;
607 tcc.first = GNUNET_YES;
608 GST_neighbours_iterate (&test_connection_ok, &tcc);
609}
610
611
612/**
613 * A blacklisting client has sent us reply. Process it.
614 *
615 * @param cls unused
616 * @param client the client
617 * @param message the blacklist-init message that was sent
618 */
619void
620GST_blacklist_handle_reply (void *cls,
621 struct GNUNET_SERVER_Client *client,
622 const struct GNUNET_MessageHeader *message)
623{
624 const struct BlacklistMessage *msg =
625 (const struct BlacklistMessage *) message;
626 struct Blacklisters *bl;
627 struct GST_BlacklistCheck *bc;
628
629 bl = bl_head;
630 while ((bl != NULL) && (bl->client != client))
631 bl = bl->next;
632 if (NULL == bl)
633 {
634 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
635 "Blacklist client disconnected\n");
636 GNUNET_SERVER_receive_done (client,
637 GNUNET_SYSERR);
638 return;
639 }
640
641 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
642 "Blacklist client %p sent reply for `%s'\n",
643 client,
644 GNUNET_i2s (&msg->peer));
645
646 bc = bl->bc;
647 bl->bc = NULL;
648 bl->waiting_for_reply = GNUNET_NO;
649 bl->call_receive_done = GNUNET_YES; /* Remember to call receive_done */
650 if (NULL != bc)
651 {
652 /* only run this if the blacklist check has not been
653 * cancelled in the meantime... */
654 GNUNET_assert (bc->bl_pos == bl);
655 if (ntohl (msg->is_allowed) == GNUNET_SYSERR)
656 {
657 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
658 "Blacklist check failed, peer not allowed\n");
659 /* For the duration of the continuation, make the ongoing
660 check invisible (to avoid double-cancellation); then
661 add it back again so we can re-use GST_blacklist_test_cancel() */
662 GNUNET_CONTAINER_DLL_remove (bc_head,
663 bc_tail,
664 bc);
665 bc->cont (bc->cont_cls,
666 &bc->peer,
667 bc->address,
668 bc->session,
669 GNUNET_NO);
670 GNUNET_CONTAINER_DLL_insert (bc_head,
671 bc_tail,
672 bc);
673 GST_blacklist_test_cancel (bc);
674 GNUNET_SERVER_receive_done (bl->client, GNUNET_OK);
675 bl->call_receive_done = GNUNET_NO;
676 return;
677 }
678 else
679 {
680 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
681 "Blacklist check succeeded, continuing with checks\n");
682 GNUNET_SERVER_receive_done (bl->client,
683 GNUNET_OK);
684 bl->call_receive_done = GNUNET_NO;
685 bc->bl_pos = bl->next;
686 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
687 bc);
688 }
689 }
690 /* check if any other blacklist checks are waiting for this blacklister */
691 for (bc = bc_head; bc != NULL; bc = bc->next)
692 if ((bc->bl_pos == bl) && (NULL == bc->task))
693 {
694 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
695 bc);
696 break;
697 }
698}
699
700
701/**
702 * Add the given peer to the blacklist (for the given transport).
703 *
704 * @param peer peer to blacklist
705 * @param transport_name transport to blacklist for this peer, NULL for all
706 */
707void
708GST_blacklist_add_peer (const struct GNUNET_PeerIdentity *peer,
709 const char *transport_name)
710{
711 char *transport = NULL;
712
713 if (NULL != transport_name)
714 {
715 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
716 "Adding peer `%s' with plugin `%s' to blacklist\n",
717 GNUNET_i2s (peer), transport_name);
718 transport = GNUNET_strdup (transport_name);
719 }
720 else
721 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
722 "Adding peer `%s' with all plugins to blacklist\n",
723 GNUNET_i2s (peer));
724 if (NULL == blacklist)
725 blacklist =
726 GNUNET_CONTAINER_multipeermap_create (TRANSPORT_BLACKLIST_HT_SIZE,
727 GNUNET_NO);
728
729 GNUNET_CONTAINER_multipeermap_put (blacklist, peer,
730 transport,
731 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
732}
733
734
735/**
736 * Abort blacklist if @a address and @a session match.
737 *
738 * @param address address used to abort matching checks
739 * @param session session used to abort matching checks
740 */
741void
742GST_blacklist_abort_matching (const struct GNUNET_HELLO_Address *address,
743 struct GNUNET_ATS_Session *session)
744{
745 struct GST_BlacklistCheck *bc;
746 struct GST_BlacklistCheck *n;
747
748 n = bc_head;
749 while (NULL != (bc = n))
750 {
751 n = bc->next;
752 if ( (bc->session == session) &&
753 (0 == GNUNET_HELLO_address_cmp (bc->address,
754 address)) )
755 {
756 bc->cont (bc->cont_cls,
757 &bc->peer,
758 bc->address,
759 bc->session,
760 GNUNET_SYSERR);
761 GST_blacklist_test_cancel (bc);
762 }
763 }
764}
765
766
767/**
768 * Test if the given blacklist entry matches. If so,
769 * abort the iteration.
770 *
771 * @param cls the transport name to match (const char*)
772 * @param key the key (unused)
773 * @param value the 'char *' (name of a blacklisted transport)
774 * @return #GNUNET_OK if the entry does not match, #GNUNET_NO if it matches
775 */
776static int
777test_blacklisted (void *cls,
778 const struct GNUNET_PeerIdentity *key,
779 void *value)
780{
781 const char *transport_name = cls;
782 char *be = value;
783
784 /* Blacklist entry be:
785 * (NULL == be): peer is blacklisted with all plugins
786 * (NULL != be): peer is blacklisted for a specific plugin
787 *
788 * If (NULL != transport_name) we look for a transport specific entry:
789 * if (transport_name == be) forbidden
790 *
791 */
792
793 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
794 "Comparing BL request for peer `%4s':`%s' with BL entry: `%s'\n",
795 GNUNET_i2s (key),
796 (NULL == transport_name) ? "unspecified" : transport_name,
797 (NULL == be) ? "all plugins" : be);
798 /* all plugins for this peer were blacklisted: disallow */
799 if (NULL == value)
800 return GNUNET_NO;
801
802 /* blacklist check for specific transport */
803 if ((NULL != transport_name) && (NULL != value))
804 {
805 if (0 == strcmp (transport_name,
806 be))
807 return GNUNET_NO; /* plugin is blacklisted! */
808 }
809 return GNUNET_OK;
810}
811
812
813/**
814 * Test if a peer/transport combination is blacklisted.
815 *
816 * @param peer the identity of the peer to test
817 * @param transport_name name of the transport to test, never NULL
818 * @param cont function to call with result
819 * @param cont_cls closure for @a cont
820 * @param address address to pass back to @a cont, can be NULL
821 * @param session session to pass back to @a cont, can be NULL
822 * @return handle to the blacklist check, NULL if the decision
823 * was made instantly and @a cont was already called
824 */
825struct GST_BlacklistCheck *
826GST_blacklist_test_allowed (const struct GNUNET_PeerIdentity *peer,
827 const char *transport_name,
828 GST_BlacklistTestContinuation cont,
829 void *cont_cls,
830 const struct GNUNET_HELLO_Address *address,
831 struct GNUNET_ATS_Session *session)
832{
833 struct GST_BlacklistCheck *bc;
834
835 GNUNET_assert (NULL != peer);
836 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
837 "Blacklist check for peer `%s':%s\n",
838 GNUNET_i2s (peer),
839 (NULL != transport_name) ? transport_name : "unspecified");
840
841 /* Check local blacklist by iterating over hashmap
842 * If iteration is aborted, we found a matching blacklist entry */
843 if ((NULL != blacklist) &&
844 (GNUNET_SYSERR ==
845 GNUNET_CONTAINER_multipeermap_get_multiple (blacklist, peer,
846 &test_blacklisted,
847 (void *) transport_name)))
848 {
849 /* Disallowed by config, disapprove instantly */
850 GNUNET_STATISTICS_update (GST_stats,
851 gettext_noop ("# disconnects due to blacklist"),
852 1,
853 GNUNET_NO);
854 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
855 _("Disallowing connection to peer `%s' on transport %s\n"),
856 GNUNET_i2s (peer),
857 (NULL != transport_name) ? transport_name : "unspecified");
858 if (NULL != cont)
859 cont (cont_cls,
860 peer,
861 address,
862 session,
863 GNUNET_NO);
864 return NULL;
865 }
866
867 if (NULL == bl_head)
868 {
869 /* no blacklist clients, approve instantly */
870 if (NULL != cont)
871 cont (cont_cls,
872 peer,
873 address,
874 session,
875 GNUNET_OK);
876 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
877 "Allowing connection to peer `%s' %s\n",
878 GNUNET_i2s (peer),
879 (NULL != transport_name) ? transport_name : "");
880 return NULL;
881 }
882
883 /* need to query blacklist clients */
884 bc = GNUNET_new (struct GST_BlacklistCheck);
885 GNUNET_CONTAINER_DLL_insert (bc_head,
886 bc_tail,
887 bc);
888 bc->peer = *peer;
889 bc->address = GNUNET_HELLO_address_copy (address);
890 bc->session = session;
891 bc->cont = cont;
892 bc->cont_cls = cont_cls;
893 bc->bl_pos = bl_head;
894 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check, bc);
895 return bc;
896}
897
898
899/**
900 * Cancel a blacklist check.
901 *
902 * @param bc check to cancel
903 */
904void
905GST_blacklist_test_cancel (struct GST_BlacklistCheck *bc)
906{
907 GNUNET_CONTAINER_DLL_remove (bc_head,
908 bc_tail,
909 bc);
910 if (NULL != bc->bl_pos)
911 {
912 if (bc->bl_pos->bc == bc)
913 {
914 /* we're at the head of the queue, remove us! */
915 bc->bl_pos->bc = NULL;
916 }
917 }
918 if (NULL != bc->task)
919 {
920 GNUNET_SCHEDULER_cancel (bc->task);
921 bc->task = NULL;
922 }
923 if (NULL != bc->th)
924 {
925 GNUNET_SERVER_notify_transmit_ready_cancel (bc->th);
926 bc->th = NULL;
927 }
928 GNUNET_free_non_null (bc->address);
929 GNUNET_free (bc);
930}
931
932
933/* end of file gnunet-service-transport_blacklist.c */
diff --git a/src/transport/gnunet-service-transport_blacklist.h b/src/transport/gnunet-service-transport_blacklist.h
deleted file mode 100644
index 3888d33d3..000000000
--- a/src/transport/gnunet-service-transport_blacklist.h
+++ /dev/null
@@ -1,159 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2010,2011 GNUnet e.V.
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
19*/
20
21/**
22 * @file transport/gnunet-service-transport_blacklist.h
23 * @brief blacklisting API
24 * @author Christian Grothoff
25 */
26#ifndef GNUNET_SERVICE_TRANSPORT_BLACKLIST_H
27#define GNUNET_SERVICE_TRANSPORT_BLACKLIST_H
28
29#include "gnunet_statistics_service.h"
30#include "gnunet_ats_service.h"
31#include "gnunet_util_lib.h"
32
33/**
34 * Start blacklist subsystem.
35 *
36 * @param server server used to accept clients from
37 * @param cfg configuration handle
38 * @param my_id my peer id
39 */
40void
41GST_blacklist_start (struct GNUNET_SERVER_Handle *server,
42 const struct GNUNET_CONFIGURATION_Handle *cfg,
43 const struct GNUNET_PeerIdentity *my_id);
44
45
46/**
47 * Stop blacklist subsystem.
48 */
49void
50GST_blacklist_stop (void);
51
52
53/**
54 * Initialize a blacklisting client. We got a blacklist-init
55 * message from this client, add him to the list of clients
56 * to query for blacklisting.
57 *
58 * @param cls unused
59 * @param client the client
60 * @param message the blacklist-init message that was sent
61 */
62void
63GST_blacklist_handle_init (void *cls,
64 struct GNUNET_SERVER_Client *client,
65 const struct GNUNET_MessageHeader *message);
66
67
68/**
69 * A blacklisting client has sent us reply. Process it.
70 *
71 * @param cls unused
72 * @param client the client
73 * @param message the blacklist-init message that was sent
74 */
75void
76GST_blacklist_handle_reply (void *cls,
77 struct GNUNET_SERVER_Client *client,
78 const struct GNUNET_MessageHeader *message);
79
80
81/**
82 * Add the given peer to the blacklist (for the given transport).
83 *
84 * @param peer peer to blacklist
85 * @param transport_name transport to blacklist for this peer, NULL for all
86 */
87void
88GST_blacklist_add_peer (const struct GNUNET_PeerIdentity *peer,
89 const char *transport_name);
90
91
92/**
93 * Handle to an active blacklist check.
94 */
95struct GST_BlacklistCheck;
96
97
98/**
99 * Continuation called from a blacklist test.
100 *
101 * @param cls closure
102 * @param peer identity of peer that was tested
103 * @param address address associated with the request
104 * @param session session associated with the request
105 * @param result #GNUNET_OK if the connection is allowed,
106 * #GNUNET_NO if not,
107 * #GNUNET_SYSERR if operation was aborted
108 */
109typedef void
110(*GST_BlacklistTestContinuation) (void *cls,
111 const struct GNUNET_PeerIdentity *peer,
112 const struct GNUNET_HELLO_Address *address,
113 struct GNUNET_ATS_Session *session,
114 int result);
115
116
117/**
118 * Test if a peer/transport combination is blacklisted.
119 *
120 * @param peer the identity of the peer to test
121 * @param transport_name name of the transport to test, never NULL
122 * @param cont function to call with result
123 * @param cont_cls closure for @a cont
124 * @param address address to pass back to @a cont, can be NULL
125 * @param session session to pass back to @a cont, can be NULL
126 * @return handle to the blacklist check, NULL if the decision
127 * was made instantly and @a cont was already called
128 */
129struct GST_BlacklistCheck *
130GST_blacklist_test_allowed (const struct GNUNET_PeerIdentity *peer,
131 const char *transport_name,
132 GST_BlacklistTestContinuation cont,
133 void *cont_cls,
134 const struct GNUNET_HELLO_Address *address,
135 struct GNUNET_ATS_Session *session);
136
137
138/**
139 * Abort blacklist if @a address and @a session match.
140 *
141 * @param address address used to abort matching checks
142 * @param session session used to abort matching checks
143 */
144void
145GST_blacklist_abort_matching (const struct GNUNET_HELLO_Address *address,
146 struct GNUNET_ATS_Session *session);
147
148
149
150/**
151 * Cancel a blacklist check.
152 *
153 * @param bc check to cancel
154 */
155void
156GST_blacklist_test_cancel (struct GST_BlacklistCheck *bc);
157
158#endif
159/* end of file gnunet-service-transport_blacklist.h */
diff --git a/src/transport/gnunet-service-transport_clients.c b/src/transport/gnunet-service-transport_clients.c
deleted file mode 100644
index 036fc5637..000000000
--- a/src/transport/gnunet-service-transport_clients.c
+++ /dev/null
@@ -1,1491 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2010-2015 GNUnet e.V.
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
19*/
20
21/**
22 * @file transport/gnunet-service-transport_clients.c
23 * @brief communication with clients (core service and monitors)
24 * @author Christian Grothoff
25 */
26#include "platform.h"
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"
36
37
38/**
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.
43 *
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
48 * fail.
49 */
50#define MAX_PENDING (128 * 1024)
51
52
53/**
54 * Linked list of messages to be transmitted to the client. Each
55 * entry is followed by the actual message.
56 */
57struct ClientMessageQueueEntry
58{
59 /**
60 * This is a doubly-linked list.
61 */
62 struct ClientMessageQueueEntry *next;
63
64 /**
65 * This is a doubly-linked list.
66 */
67 struct ClientMessageQueueEntry *prev;
68};
69
70
71/**
72 * Client connected to the transport service.
73 */
74struct TransportClient
75{
76
77 /**
78 * This is a doubly-linked list.
79 */
80 struct TransportClient *next;
81
82 /**
83 * This is a doubly-linked list.
84 */
85 struct TransportClient *prev;
86
87 /**
88 * Handle to the client.
89 */
90 struct GNUNET_SERVER_Client *client;
91
92 /**
93 * Linked list of messages yet to be transmitted to
94 * the client.
95 */
96 struct ClientMessageQueueEntry *message_queue_head;
97
98 /**
99 * Tail of linked list of messages yet to be transmitted to the
100 * client.
101 */
102 struct ClientMessageQueueEntry *message_queue_tail;
103
104 /**
105 * Current transmit request handle.
106 */
107 struct GNUNET_SERVER_TransmitHandle *th;
108
109 /**
110 * Length of the list of messages pending for this client.
111 */
112 unsigned int message_count;
113
114 /**
115 * Is this client interested in payload messages?
116 */
117 int send_payload;
118};
119
120
121/**
122 * Context for address to string operations
123 */
124struct AddressToStringContext
125{
126 /**
127 * This is a doubly-linked list.
128 */
129 struct AddressToStringContext *next;
130
131 /**
132 * This is a doubly-linked list.
133 */
134 struct AddressToStringContext *prev;
135
136 /**
137 * Transmission context
138 */
139 struct GNUNET_SERVER_TransmitContext* tc;
140};
141
142
143/**
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.
147 */
148struct MonitoringClient
149{
150 /**
151 * This is a doubly-linked list.
152 */
153 struct MonitoringClient *next;
154
155 /**
156 * This is a doubly-linked list.
157 */
158 struct MonitoringClient *prev;
159
160 /**
161 * Handle to the client.
162 */
163 struct GNUNET_SERVER_Client *client;
164
165 /**
166 * Peer identity to monitor the addresses of.
167 * Zero to monitor all neighrours.
168 */
169 struct GNUNET_PeerIdentity peer;
170
171};
172
173
174/**
175 * Closure for #handle_send_transmit_continuation()
176 */
177struct SendTransmitContinuationContext
178{
179 /**
180 * Client that made the request.
181 */
182 struct GNUNET_SERVER_Client *client;
183
184 /**
185 * Peer that was the target.
186 */
187 struct GNUNET_PeerIdentity target;
188
189 /**
190 * At what time did we receive the message?
191 */
192 struct GNUNET_TIME_Absolute send_time;
193
194 /**
195 * Unique ID, for logging.
196 */
197 unsigned long long uuid;
198
199 /**
200 * Set to #GNUNET_YES if the connection for @e target goes
201 * down and we thus must no longer send the
202 * #GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK message.
203 */
204 int down;
205};
206
207
208/**
209 * Head of linked list of all clients to this service.
210 */
211static struct TransportClient *clients_head;
212
213/**
214 * Tail of linked list of all clients to this service.
215 */
216static struct TransportClient *clients_tail;
217
218/**
219 * Map of peer identities to active send transmit continuation
220 * contexts. Used to flag contexts as 'dead' when a connection goes
221 * down. Values are of type `struct SendTransmitContinuationContext
222 * *`.
223 */
224static struct GNUNET_CONTAINER_MultiPeerMap *active_stccs;
225
226/**
227 * Head of linked list of all pending address iterations
228 */
229static struct AddressToStringContext *a2s_head;
230
231/**
232 * Tail of linked list of all pending address iterations
233 */
234static struct AddressToStringContext *a2s_tail;
235
236/**
237 * Head of linked list of monitoring clients.
238 */
239static struct MonitoringClient *peer_monitoring_clients_head;
240
241/**
242 * Tail of linked list of monitoring clients.
243 */
244static struct MonitoringClient *peer_monitoring_clients_tail;
245
246/**
247 * Notification context, to send updates on changes to active addresses
248 * of our neighbours.
249 */
250static struct GNUNET_SERVER_NotificationContext *peer_nc;
251
252/**
253 * Notification context, to send updates on changes to active addresses
254 * of our neighbours.
255 */
256static struct GNUNET_SERVER_NotificationContext *val_nc;
257
258/**
259 * Notification context, to send updates on changes to active plugin
260 * connections.
261 */
262static struct GNUNET_SERVER_NotificationContext *plugin_nc;
263
264/**
265 * Plugin monitoring client we are currently syncing, NULL if all
266 * monitoring clients are in sync.
267 */
268static struct GNUNET_SERVER_Client *sync_client;
269
270/**
271 * Peer identity that is all zeros, used as a way to indicate
272 * "all peers". Used for comparissons.
273 */
274static struct GNUNET_PeerIdentity all_zeros;
275
276
277/**
278 * Find the internal handle associated with the given client handle.
279 *
280 * @param client server's client handle to look up
281 * @return internal client handle
282 */
283static struct TransportClient *
284lookup_client (struct GNUNET_SERVER_Client *client)
285{
286 return GNUNET_SERVER_client_get_user_context (client,
287 struct TransportClient);
288}
289
290
291/**
292 * Create the internal handle for the given server client handle.
293 *
294 * @param client server's client handle to create our internal handle for
295 * @return fresh internal client handle
296 */
297static struct TransportClient *
298setup_client (struct GNUNET_SERVER_Client *client)
299{
300 struct TransportClient *tc;
301
302 GNUNET_assert (NULL == lookup_client (client));
303 tc = GNUNET_new (struct TransportClient);
304 tc->client = client;
305 GNUNET_SERVER_client_set_user_context (client, tc);
306 GNUNET_CONTAINER_DLL_insert (clients_head,
307 clients_tail,
308 tc);
309 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
310 "Client %p connected\n",
311 tc);
312 return tc;
313}
314
315
316/**
317 * Find the handle to the monitoring client associated with the given
318 * client handle.
319 *
320 * @param head the head of the client queue to look in
321 * @param client server's client handle to look up
322 * @return handle to the monitoring client
323 */
324static struct MonitoringClient *
325lookup_monitoring_client (struct MonitoringClient *head,
326 struct GNUNET_SERVER_Client *client)
327{
328 struct MonitoringClient *mc;
329
330 for (mc = head; NULL != mc; mc = mc->next)
331 if (mc->client == client)
332 return mc;
333 return NULL;
334}
335
336
337/**
338 * Setup a new monitoring client using the given server client handle and
339 * the peer identity.
340 *
341 * @param client server's client handle to create our internal handle for
342 * @param peer identity of the peer to monitor the addresses of,
343 * zero to monitor all neighrours.
344 * @return handle to the new monitoring client
345 */
346static struct MonitoringClient *
347setup_peer_monitoring_client (struct GNUNET_SERVER_Client *client,
348 const struct GNUNET_PeerIdentity *peer)
349{
350 struct MonitoringClient *mc;
351
352 GNUNET_assert (NULL ==
353 lookup_monitoring_client (peer_monitoring_clients_head,
354 client));
355 mc = GNUNET_new (struct MonitoringClient);
356 mc->client = client;
357 mc->peer = *peer;
358 GNUNET_CONTAINER_DLL_insert (peer_monitoring_clients_head,
359 peer_monitoring_clients_tail,
360 mc);
361 GNUNET_SERVER_client_mark_monitor (client);
362 GNUNET_SERVER_notification_context_add (peer_nc,
363 client);
364 if (0 != memcmp (peer,
365 &all_zeros,
366 sizeof (struct GNUNET_PeerIdentity)))
367 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
368 "Client %p started monitoring of the peer `%s'\n",
369 mc,
370 GNUNET_i2s (peer));
371 else
372 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
373 "Client %p started monitoring all peers\n",
374 mc);
375 return mc;
376}
377
378
379/**
380 * Function called to notify a client about the socket being ready to
381 * queue more data. @a buf will be NULL and @a size zero if the socket
382 * was closed for writing in the meantime.
383 *
384 * @param cls closure
385 * @param size number of bytes available in @a buf
386 * @param buf where the callee should write the message
387 * @return number of bytes written to @a buf
388 */
389static size_t
390transmit_to_client_callback (void *cls,
391 size_t size,
392 void *buf)
393{
394 struct TransportClient *tc = cls;
395 struct ClientMessageQueueEntry *q;
396 const struct GNUNET_MessageHeader *msg;
397 char *cbuf;
398 uint16_t msize;
399 size_t tsize;
400
401 tc->th = NULL;
402 if (NULL == buf)
403 {
404 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
405 "Transmission to client failed, closing connection.\n");
406 return 0;
407 }
408 cbuf = buf;
409 tsize = 0;
410 while (NULL != (q = tc->message_queue_head))
411 {
412 msg = (const struct GNUNET_MessageHeader *) &q[1];
413 msize = ntohs (msg->size);
414 if (msize + tsize > size)
415 break;
416 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
417 "Transmitting message of type %u to client %p.\n",
418 ntohs (msg->type),
419 tc);
420 GNUNET_CONTAINER_DLL_remove (tc->message_queue_head,
421 tc->message_queue_tail,
422 q);
423 tc->message_count--;
424 GNUNET_memcpy (&cbuf[tsize], msg, msize);
425 GNUNET_free (q);
426 tsize += msize;
427 }
428 if (NULL != q)
429 {
430 GNUNET_assert (msize >= sizeof (struct GNUNET_MessageHeader));
431 tc->th =
432 GNUNET_SERVER_notify_transmit_ready (tc->client, msize,
433 GNUNET_TIME_UNIT_FOREVER_REL,
434 &transmit_to_client_callback, tc);
435 GNUNET_assert (NULL != tc->th);
436 }
437 return tsize;
438}
439
440
441/**
442 * Queue the given message for transmission to the given client
443 *
444 * @param tc target of the message
445 * @param msg message to transmit
446 * @param may_drop #GNUNET_YES if the message can be dropped
447 */
448static void
449unicast (struct TransportClient *tc,
450 const struct GNUNET_MessageHeader *msg,
451 int may_drop)
452{
453 struct ClientMessageQueueEntry *q;
454 uint16_t msize;
455
456 if (NULL == msg)
457 {
458 GNUNET_break (0);
459 return;
460 }
461 if ( (tc->message_count >= MAX_PENDING) &&
462 (GNUNET_YES == may_drop) )
463 {
464 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
465 "Dropping message of type %u and size %u, have %u/%u messages pending\n",
466 ntohs (msg->type),
467 ntohs (msg->size),
468 tc->message_count,
469 MAX_PENDING);
470 GNUNET_STATISTICS_update (GST_stats,
471 gettext_noop
472 ("# messages dropped due to slow client"), 1,
473 GNUNET_NO);
474 return;
475 }
476 msize = ntohs (msg->size);
477 GNUNET_assert (msize >= sizeof (struct GNUNET_MessageHeader));
478 q = GNUNET_malloc (sizeof (struct ClientMessageQueueEntry) + msize);
479 GNUNET_memcpy (&q[1], msg, msize);
480 GNUNET_CONTAINER_DLL_insert_tail (tc->message_queue_head,
481 tc->message_queue_tail,
482 q);
483 tc->message_count++;
484 if (NULL != tc->th)
485 return;
486 tc->th =
487 GNUNET_SERVER_notify_transmit_ready (tc->client, msize,
488 GNUNET_TIME_UNIT_FOREVER_REL,
489 &transmit_to_client_callback, tc);
490 GNUNET_assert (NULL != tc->th);
491}
492
493
494/**
495 * Called whenever a client is disconnected. Frees our
496 * resources associated with that client.
497 *
498 * @param cls closure, NULL
499 * @param client identification of the client
500 */
501static void
502client_disconnect_notification (void *cls,
503 struct GNUNET_SERVER_Client *client)
504{
505 struct TransportClient *tc;
506 struct MonitoringClient *mc;
507 struct ClientMessageQueueEntry *mqe;
508
509 if (NULL == client)
510 return;
511 mc = lookup_monitoring_client (peer_monitoring_clients_head,
512 client);
513 if (NULL != mc)
514 {
515 GNUNET_CONTAINER_DLL_remove (peer_monitoring_clients_head,
516 peer_monitoring_clients_tail,
517 mc);
518 GNUNET_free (mc);
519 }
520 tc = lookup_client (client);
521 if (NULL == tc)
522 return;
523 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
524 "Client %p disconnected, cleaning up.\n",
525 tc);
526 while (NULL != (mqe = tc->message_queue_head))
527 {
528 GNUNET_CONTAINER_DLL_remove (tc->message_queue_head,
529 tc->message_queue_tail,
530 mqe);
531 tc->message_count--;
532 GNUNET_free (mqe);
533 }
534 GNUNET_CONTAINER_DLL_remove (clients_head,
535 clients_tail,
536 tc);
537 GNUNET_SERVER_client_set_user_context (client, NULL);
538 if (NULL != tc->th)
539 {
540 GNUNET_SERVER_notify_transmit_ready_cancel (tc->th);
541 tc->th = NULL;
542 }
543 GNUNET_break (0 == tc->message_count);
544 GNUNET_free (tc);
545}
546
547
548/**
549 * Function called for each of our connected neighbours. Notify the
550 * client about the existing neighbour.
551 *
552 * @param cls the `struct TransportClient *` to notify
553 * @param peer identity of the neighbour
554 * @param address the address
555 * @param state the current state of the peer
556 * @param state_timeout the time out for the state
557 * @param bandwidth_in inbound bandwidth in NBO
558 * @param bandwidth_out outbound bandwidth in NBO
559 */
560static void
561notify_client_about_neighbour (void *cls,
562 const struct GNUNET_PeerIdentity *peer,
563 const struct GNUNET_HELLO_Address *address,
564 enum GNUNET_TRANSPORT_PeerState state,
565 struct GNUNET_TIME_Absolute state_timeout,
566 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in,
567 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out)
568{
569 struct TransportClient *tc = cls;
570 struct ConnectInfoMessage cim;
571
572 if (GNUNET_NO == GST_neighbours_test_connected (peer))
573 return;
574 cim.header.size = htons (sizeof (struct ConnectInfoMessage));
575 cim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
576 cim.id = *peer;
577 cim.quota_in = bandwidth_in;
578 cim.quota_out = bandwidth_out;
579 unicast (tc, &cim.header, GNUNET_NO);
580}
581
582
583/**
584 * Initialize a normal client. We got a start message from this
585 * client, add him to the list of clients for broadcasting of inbound
586 * messages.
587 *
588 * @param cls unused
589 * @param client the client
590 * @param message the start message that was sent
591 */
592static void
593clients_handle_start (void *cls,
594 struct GNUNET_SERVER_Client *client,
595 const struct GNUNET_MessageHeader *message)
596{
597 const struct StartMessage *start;
598 const struct GNUNET_MessageHeader *hello;
599 struct TransportClient *tc;
600 uint32_t options;
601
602 tc = lookup_client (client);
603 if (NULL != tc)
604 {
605 /* got 'start' twice from the same client, not allowed */
606 GNUNET_break (0);
607 GNUNET_SERVER_receive_done (client,
608 GNUNET_SYSERR);
609 return;
610 }
611 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
612 "Client %p sent START\n",
613 client);
614 start = (const struct StartMessage *) message;
615 options = ntohl (start->options);
616 if ((0 != (1 & options)) &&
617 (0 !=
618 memcmp (&start->self,
619 &GST_my_identity,
620 sizeof (struct GNUNET_PeerIdentity))))
621 {
622 /* client thinks this is a different peer, reject */
623 GNUNET_break (0);
624 GNUNET_SERVER_receive_done (client,
625 GNUNET_SYSERR);
626 return;
627 }
628 tc = setup_client (client);
629 tc->send_payload = (0 != (2 & options));
630 hello = GST_hello_get ();
631 if (NULL != hello)
632 unicast (tc,
633 hello,
634 GNUNET_NO);
635 GST_neighbours_iterate (&notify_client_about_neighbour,
636 tc);
637 GNUNET_SERVER_receive_done (client,
638 GNUNET_OK);
639}
640
641
642/**
643 * Client sent us a HELLO. Process the request.
644 *
645 * @param cls unused
646 * @param client the client
647 * @param message the HELLO message
648 */
649static void
650clients_handle_hello (void *cls,
651 struct GNUNET_SERVER_Client *client,
652 const struct GNUNET_MessageHeader *message)
653{
654 GST_validation_handle_hello (message);
655 GNUNET_SERVER_receive_done (client, GNUNET_OK);
656}
657
658
659/**
660 * Function called after the transmission is done. Notify the client that it is
661 * OK to send the next message.
662 *
663 * @param cls closure
664 * @param success #GNUNET_OK on success, #GNUNET_NO on failure, #GNUNET_SYSERR if we're not connected
665 * @param bytes_payload bytes payload sent
666 * @param bytes_on_wire bytes sent on wire
667 */
668static void
669handle_send_transmit_continuation (void *cls,
670 int success,
671 size_t bytes_payload,
672 size_t bytes_on_wire)
673{
674 struct SendTransmitContinuationContext *stcc = cls;
675 struct SendOkMessage send_ok_msg;
676 struct GNUNET_TIME_Relative delay;
677 const struct GNUNET_HELLO_Address *addr;
678
679 delay = GNUNET_TIME_absolute_get_duration (stcc->send_time);
680 addr = GST_neighbour_get_current_address (&stcc->target);
681 if (delay.rel_value_us > GNUNET_CONSTANTS_LATENCY_WARN.rel_value_us)
682 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
683 "It took us %s to send %u/%u bytes to %s (%d, %s)\n",
684 GNUNET_STRINGS_relative_time_to_string (delay,
685 GNUNET_YES),
686 (unsigned int) bytes_payload,
687 (unsigned int) bytes_on_wire,
688 GNUNET_i2s (&stcc->target),
689 success,
690 (NULL != addr) ? addr->transport_name : "%");
691 else
692 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
693 "It took us %s to send %u/%u bytes to %s (%d, %s)\n",
694 GNUNET_STRINGS_relative_time_to_string (delay,
695 GNUNET_YES),
696 (unsigned int) bytes_payload,
697 (unsigned int) bytes_on_wire,
698 GNUNET_i2s (&stcc->target),
699 success,
700 (NULL != addr) ? addr->transport_name : "%");
701
702 if (GNUNET_NO == stcc->down)
703 {
704 /* Only send confirmation if we are still connected */
705 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
706 "Sending SEND_OK for transmission request %llu\n",
707 stcc->uuid);
708 send_ok_msg.header.size = htons (sizeof (send_ok_msg));
709 send_ok_msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK);
710 send_ok_msg.bytes_msg = htonl (bytes_payload);
711 send_ok_msg.bytes_physical = htonl (bytes_on_wire);
712 send_ok_msg.success = htonl (success);
713 send_ok_msg.peer = stcc->target;
714 GST_clients_unicast (stcc->client,
715 &send_ok_msg.header,
716 GNUNET_NO);
717 }
718 GNUNET_SERVER_client_drop (stcc->client);
719 GNUNET_assert (GNUNET_OK ==
720 GNUNET_CONTAINER_multipeermap_remove (active_stccs,
721 &stcc->target,
722 stcc));
723 GNUNET_free (stcc);
724}
725
726
727/**
728 * Client asked for transmission to a peer. Process the request.
729 *
730 * @param cls unused
731 * @param client the client
732 * @param message the send message that was sent
733 */
734static void
735clients_handle_send (void *cls,
736 struct GNUNET_SERVER_Client *client,
737 const struct GNUNET_MessageHeader *message)
738{
739 static unsigned long long uuid_gen;
740 const struct OutboundMessage *obm;
741 const struct GNUNET_MessageHeader *obmm;
742 struct SendTransmitContinuationContext *stcc;
743 uint16_t size;
744 uint16_t msize;
745 struct TransportClient *tc;
746
747 tc = lookup_client (client);
748 if (NULL == tc)
749 {
750 /* client asked for transmission before 'START' */
751 GNUNET_break (0);
752 GNUNET_SERVER_receive_done (client,
753 GNUNET_SYSERR);
754 return;
755 }
756
757 size = ntohs (message->size);
758 if (size <
759 sizeof (struct OutboundMessage) + sizeof (struct GNUNET_MessageHeader))
760 {
761 GNUNET_break (0);
762 GNUNET_SERVER_receive_done (client,
763 GNUNET_SYSERR);
764 return;
765 }
766 obm = (const struct OutboundMessage *) message;
767 obmm = (const struct GNUNET_MessageHeader *) &obm[1];
768 msize = size - sizeof (struct OutboundMessage);
769 if (msize < sizeof (struct GNUNET_MessageHeader))
770 {
771 GNUNET_break (0);
772 GNUNET_SERVER_receive_done (client,
773 GNUNET_SYSERR);
774 return;
775 }
776
777 if (GNUNET_NO == GST_neighbours_test_connected (&obm->peer))
778 {
779 /* not connected, not allowed to send; can happen due to asynchronous operations */
780 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
781 "Could not send message to peer `%s': not connected\n",
782 GNUNET_i2s (&obm->peer));
783 GNUNET_STATISTICS_update (GST_stats,
784 gettext_noop
785 ("# bytes payload dropped (other peer was not connected)"),
786 msize, GNUNET_NO);
787 GNUNET_SERVER_receive_done (client,
788 GNUNET_OK);
789 return;
790 }
791 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
792 "Received SEND request %llu for `%s' and first message of type %u and total size %u\n",
793 uuid_gen,
794 GNUNET_i2s (&obm->peer),
795 ntohs (obmm->type),
796 msize);
797 GNUNET_SERVER_receive_done (client,
798 GNUNET_OK);
799 stcc = GNUNET_new (struct SendTransmitContinuationContext);
800 stcc->target = obm->peer;
801 stcc->client = client;
802 stcc->send_time = GNUNET_TIME_absolute_get ();
803 stcc->uuid = uuid_gen++;
804 (void) GNUNET_CONTAINER_multipeermap_put (active_stccs,
805 &stcc->target,
806 stcc,
807 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
808 GNUNET_SERVER_client_keep (client);
809 GST_manipulation_send (&obm->peer,
810 obmm,
811 msize,
812 GNUNET_TIME_relative_ntoh (obm->timeout),
813 &handle_send_transmit_continuation,
814 stcc);
815}
816
817
818/**
819 * Take the given address and append it to the set of results sent back to
820 * the client. This function may be called serveral times for a single
821 * conversion. The last invocation will be with a @a address of
822 * NULL and a @a res of #GNUNET_OK. Thus, to indicate conversion
823 * errors, the callback might be called first with @a address NULL and
824 * @a res being #GNUNET_SYSERR. In that case, there will still be a
825 * subsequent call later with @a address NULL and @a res #GNUNET_OK.
826 *
827 * @param cls the transmission context used (`struct GNUNET_SERVER_TransmitContext *`)
828 * @param buf text to transmit (contains the human-readable address, or NULL)
829 * @param res #GNUNET_OK if conversion was successful, #GNUNET_SYSERR on error,
830 * never #GNUNET_NO
831 */
832static void
833transmit_address_to_client (void *cls,
834 const char *buf,
835 int res)
836{
837 struct AddressToStringContext *actx = cls;
838 struct AddressToStringResultMessage *atsm;
839 size_t len;
840 size_t slen;
841
842 GNUNET_assert ( (GNUNET_OK == res) ||
843 (GNUNET_SYSERR == res) );
844 if (NULL == buf)
845 {
846 len = sizeof (struct AddressToStringResultMessage);
847 atsm = GNUNET_malloc (len);
848 atsm->header.size = ntohs (len);
849 atsm->header.type = ntohs (GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_TO_STRING_REPLY);
850 if (GNUNET_OK == res)
851 {
852 /* this was the last call, transmit */
853 atsm->res = htonl (GNUNET_OK);
854 atsm->addr_len = htonl (0);
855 GNUNET_SERVER_transmit_context_append_message (actx->tc,
856 (const struct GNUNET_MessageHeader *) atsm);
857 GNUNET_SERVER_transmit_context_run (actx->tc,
858 GNUNET_TIME_UNIT_FOREVER_REL);
859 GNUNET_CONTAINER_DLL_remove (a2s_head,
860 a2s_tail,
861 actx);
862 GNUNET_free (atsm);
863 GNUNET_free (actx);
864 return;
865 }
866 if (GNUNET_SYSERR == res)
867 {
868 /* address conversion failed, but there will be more callbacks */
869 atsm->res = htonl (GNUNET_SYSERR);
870 atsm->addr_len = htonl (0);
871 GNUNET_SERVER_transmit_context_append_message (actx->tc,
872 (const struct GNUNET_MessageHeader *) atsm);
873 GNUNET_free (atsm);
874 return;
875 }
876 }
877 GNUNET_assert (GNUNET_OK == res);
878 /* succesful conversion, append*/
879 slen = strlen (buf) + 1;
880 len = sizeof (struct AddressToStringResultMessage) + slen;
881 atsm = GNUNET_malloc (len);
882 atsm->header.size = ntohs (len);
883 atsm->header.type = ntohs (GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_TO_STRING_REPLY);
884 atsm->res = htonl (GNUNET_YES);
885 atsm->addr_len = htonl (slen);
886 GNUNET_memcpy (&atsm[1],
887 buf,
888 slen);
889 GNUNET_SERVER_transmit_context_append_message (actx->tc,
890 (const struct GNUNET_MessageHeader *) atsm);
891 GNUNET_free (atsm);
892}
893
894
895/**
896 * Client asked to resolve an address. Process the request.
897 *
898 * @param cls unused
899 * @param client the client
900 * @param message the resolution request
901 */
902static void
903clients_handle_address_to_string (void *cls,
904 struct GNUNET_SERVER_Client *client,
905 const struct GNUNET_MessageHeader *message)
906{
907 const struct AddressLookupMessage *alum;
908 struct GNUNET_TRANSPORT_PluginFunctions *papi;
909 const char *plugin_name;
910 const char *address;
911 uint32_t address_len;
912 uint16_t size;
913 struct GNUNET_SERVER_TransmitContext *tc;
914 struct AddressToStringContext *actx;
915 struct AddressToStringResultMessage atsm;
916 struct GNUNET_TIME_Relative rtimeout;
917 int32_t numeric;
918
919 size = ntohs (message->size);
920 if (size < sizeof (struct AddressLookupMessage))
921 {
922 GNUNET_break (0);
923 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
924 return;
925 }
926 alum = (const struct AddressLookupMessage *) message;
927 address_len = ntohs (alum->addrlen);
928 if (size <= sizeof (struct AddressLookupMessage) + address_len)
929 {
930 GNUNET_break (0);
931 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
932 return;
933 }
934 address = (const char *) &alum[1];
935 plugin_name = (const char *) &address[address_len];
936 if ('\0' != plugin_name[size - sizeof (struct AddressLookupMessage) - address_len - 1])
937 {
938 GNUNET_break (0);
939 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
940 return;
941 }
942 rtimeout = GNUNET_TIME_relative_ntoh (alum->timeout);
943 numeric = ntohs (alum->numeric_only);
944 tc = GNUNET_SERVER_transmit_context_create (client);
945 papi = GST_plugins_printer_find (plugin_name);
946 if (NULL == papi)
947 {
948 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
949 "Failed to find plugin `%s'\n",
950 plugin_name);
951 atsm.header.size = ntohs (sizeof (struct AddressToStringResultMessage));
952 atsm.header.type = ntohs (GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_TO_STRING_REPLY);
953 atsm.res = htonl (GNUNET_SYSERR);
954 atsm.addr_len = htonl (0);
955 GNUNET_SERVER_transmit_context_append_message (tc,
956 &atsm.header);
957 atsm.header.size = ntohs (sizeof (struct AddressToStringResultMessage));
958 atsm.header.type = ntohs (GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_TO_STRING_REPLY);
959 atsm.res = htonl (GNUNET_OK);
960 atsm.addr_len = htonl (0);
961 GNUNET_SERVER_transmit_context_append_message (tc,
962 &atsm.header);
963 GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
964 return;
965 }
966 actx = GNUNET_new (struct AddressToStringContext);
967 actx->tc = tc;
968 GNUNET_CONTAINER_DLL_insert (a2s_head, a2s_tail, actx);
969 GNUNET_SERVER_disable_receive_done_warning (client);
970 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
971 "Pretty-printing address of %u bytes using plugin `%s'\n",
972 address_len,
973 plugin_name);
974 papi->address_pretty_printer (papi->cls,
975 plugin_name,
976 address, address_len,
977 numeric,
978 rtimeout,
979 &transmit_address_to_client,
980 actx);
981}
982
983
984/**
985 * Compose #PeerIterateResponseMessage using the given peer and address.
986 *
987 * @param peer identity of the peer
988 * @param address the address, NULL on disconnect
989 * @return composed message
990 */
991static struct PeerIterateResponseMessage *
992compose_address_iterate_response_message (const struct GNUNET_PeerIdentity *peer,
993 const struct GNUNET_HELLO_Address *address)
994{
995 struct PeerIterateResponseMessage *msg;
996 size_t size;
997 size_t tlen;
998 size_t alen;
999 char *addr;
1000
1001 GNUNET_assert (NULL != peer);
1002 if (NULL != address)
1003 {
1004 tlen = strlen (address->transport_name) + 1;
1005 alen = address->address_length;
1006 }
1007 else
1008 {
1009 tlen = 0;
1010 alen = 0;
1011 }
1012 size = (sizeof (struct PeerIterateResponseMessage) + alen + tlen);
1013 msg = GNUNET_malloc (size);
1014 msg->header.size = htons (size);
1015 msg->header.type =
1016 htons (GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_PEER_RESPONSE);
1017 msg->reserved = htonl (0);
1018 msg->peer = *peer;
1019 msg->addrlen = htonl (alen);
1020 msg->pluginlen = htonl (tlen);
1021
1022 if (NULL != address)
1023 {
1024 msg->local_address_info = htonl((uint32_t) address->local_info);
1025 addr = (char *) &msg[1];
1026 GNUNET_memcpy (addr, address->address, alen);
1027 GNUNET_memcpy (&addr[alen], address->transport_name, tlen);
1028 }
1029 return msg;
1030}
1031
1032
1033/**
1034 * Context for #send_validation_information() and
1035 * #send_peer_information().
1036 */
1037struct IterationContext
1038{
1039 /**
1040 * Context to use for the transmission.
1041 */
1042 struct GNUNET_SERVER_TransmitContext *tc;
1043
1044 /**
1045 * Which peers do we care about?
1046 */
1047 struct GNUNET_PeerIdentity id;
1048
1049 /**
1050 * #GNUNET_YES if @e id should be ignored because we want all peers.
1051 */
1052 int all;
1053};
1054
1055
1056/**
1057 * Output information of neighbours to the given client.
1058 *
1059 * @param cls the `struct PeerIterationContext *`
1060 * @param peer identity of the neighbour
1061 * @param address the address
1062 * @param state current state this peer is in
1063 * @param state_timeout timeout for the current state of the peer
1064 * @param bandwidth_in inbound quota in NBO
1065 * @param bandwidth_out outbound quota in NBO
1066 */
1067static void
1068send_peer_information (void *cls,
1069 const struct GNUNET_PeerIdentity *peer,
1070 const struct GNUNET_HELLO_Address *address,
1071 enum GNUNET_TRANSPORT_PeerState state,
1072 struct GNUNET_TIME_Absolute state_timeout,
1073 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in,
1074 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out)
1075{
1076 struct IterationContext *pc = cls;
1077 struct PeerIterateResponseMessage *msg;
1078
1079 if ( (GNUNET_YES != pc->all) &&
1080 (0 != memcmp (peer, &pc->id, sizeof (pc->id))) )
1081 return;
1082 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1083 "Sending information about `%s' using address `%s' in state `%s'\n",
1084 GNUNET_i2s(peer),
1085 (NULL != address) ? GST_plugins_a2s (address) : "<none>",
1086 GNUNET_TRANSPORT_ps2s (state));
1087 msg = compose_address_iterate_response_message (peer, address);
1088 msg->state = htonl (state);
1089 msg->state_timeout = GNUNET_TIME_absolute_hton(state_timeout);
1090 GNUNET_SERVER_transmit_context_append_message (pc->tc, &msg->header);
1091 GNUNET_free (msg);
1092}
1093
1094
1095/**
1096 * Client asked to obtain information about a specific or all peers
1097 * Process the request.
1098 *
1099 * @param cls unused
1100 * @param client the client
1101 * @param message the peer address information request
1102 */
1103static void
1104clients_handle_monitor_peers (void *cls,
1105 struct GNUNET_SERVER_Client *client,
1106 const struct GNUNET_MessageHeader *message)
1107{
1108 struct GNUNET_SERVER_TransmitContext *tc;
1109 const struct PeerMonitorMessage *msg;
1110 struct IterationContext pc;
1111
1112 msg = (const struct PeerMonitorMessage *) message;
1113 if ( (GNUNET_YES != ntohl (msg->one_shot)) &&
1114 (NULL != lookup_monitoring_client (peer_monitoring_clients_head,
1115 client)) )
1116 {
1117 GNUNET_break (0);
1118 GNUNET_SERVER_receive_done (client,
1119 GNUNET_SYSERR);
1120 return;
1121 }
1122 GNUNET_SERVER_disable_receive_done_warning (client);
1123 GNUNET_SERVER_client_mark_monitor (client);
1124 pc.tc = tc = GNUNET_SERVER_transmit_context_create (client);
1125
1126 /* Send initial list */
1127 if (0 == memcmp (&msg->peer,
1128 &all_zeros,
1129 sizeof (struct GNUNET_PeerIdentity)))
1130 {
1131 /* iterate over all neighbours */
1132 pc.all = GNUNET_YES;
1133 pc.id = msg->peer;
1134 }
1135 else
1136 {
1137 /* just return one neighbour */
1138 pc.all = GNUNET_NO;
1139 pc.id = msg->peer;
1140 }
1141 GST_neighbours_iterate (&send_peer_information,
1142 &pc);
1143
1144 if (GNUNET_YES != ntohl (msg->one_shot))
1145 {
1146 setup_peer_monitoring_client (client,
1147 &msg->peer);
1148 }
1149 else
1150 {
1151 GNUNET_SERVER_transmit_context_append_data (tc,
1152 NULL,
1153 0,
1154 GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_PEER_RESPONSE_END);
1155 }
1156 GNUNET_SERVER_transmit_context_run (tc,
1157 GNUNET_TIME_UNIT_FOREVER_REL);
1158}
1159
1160
1161/**
1162 * Function called by the plugin with information about the
1163 * current sessions managed by the plugin (for monitoring).
1164 *
1165 * @param cls closure
1166 * @param session session handle this information is about,
1167 * NULL to indicate that we are "in sync" (initial
1168 * iteration complete)
1169 * @param info information about the state of the session,
1170 * NULL if @a session is also NULL and we are
1171 * merely signalling that the initial iteration is over
1172 */
1173static void
1174plugin_session_info_cb (void *cls,
1175 struct GNUNET_ATS_Session *session,
1176 const struct GNUNET_TRANSPORT_SessionInfo *info)
1177{
1178 struct TransportPluginMonitorMessage *msg;
1179 struct GNUNET_MessageHeader sync;
1180 size_t size;
1181 size_t slen;
1182 uint16_t alen;
1183 char *name;
1184 char *addr;
1185
1186 if (0 == GNUNET_SERVER_notification_context_get_size (plugin_nc))
1187 {
1188 GST_plugins_monitor_subscribe (NULL,
1189 NULL);
1190 return;
1191 }
1192 if ( (NULL == info) &&
1193 (NULL == session) )
1194 {
1195 /* end of initial iteration */
1196 if (NULL != sync_client)
1197 {
1198 sync.size = htons (sizeof (struct GNUNET_MessageHeader));
1199 sync.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_PLUGIN_SYNC);
1200 GNUNET_SERVER_notification_context_unicast (plugin_nc,
1201 sync_client,
1202 &sync,
1203 GNUNET_NO);
1204 sync_client = NULL;
1205 }
1206 return;
1207 }
1208 GNUNET_assert (NULL != info);
1209 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1210 "Plugin event for peer %s on transport %s\n",
1211 GNUNET_i2s (&info->address->peer),
1212 info->address->transport_name);
1213 slen = strlen (info->address->transport_name) + 1;
1214 alen = info->address->address_length;
1215 size = sizeof (struct TransportPluginMonitorMessage) + slen + alen;
1216 if (size > UINT16_MAX)
1217 {
1218 GNUNET_break (0);
1219 return;
1220 }
1221 msg = GNUNET_malloc (size);
1222 msg->header.size = htons (size);
1223 msg->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_PLUGIN_EVENT);
1224 msg->session_state = htons ((uint16_t) info->state);
1225 msg->is_inbound = htons ((int16_t) info->is_inbound);
1226 msg->msgs_pending = htonl (info->num_msg_pending);
1227 msg->bytes_pending = htonl (info->num_bytes_pending);
1228 msg->timeout = GNUNET_TIME_absolute_hton (info->session_timeout);
1229 msg->delay = GNUNET_TIME_absolute_hton (info->receive_delay);
1230 msg->peer = info->address->peer;
1231 msg->session_id = (uint64_t) (intptr_t) session;
1232 msg->plugin_name_len = htons (slen);
1233 msg->plugin_address_len = htons (alen);
1234 name = (char *) &msg[1];
1235 GNUNET_memcpy (name,
1236 info->address->transport_name,
1237 slen);
1238 addr = &name[slen];
1239 GNUNET_memcpy (addr,
1240 info->address->address,
1241 alen);
1242 if (NULL != sync_client)
1243 GNUNET_SERVER_notification_context_unicast (plugin_nc,
1244 sync_client,
1245 &msg->header,
1246 GNUNET_NO);
1247 else
1248 GNUNET_SERVER_notification_context_broadcast (plugin_nc,
1249 &msg->header,
1250 GNUNET_NO);
1251 GNUNET_free (msg);
1252}
1253
1254
1255/**
1256 * Client asked to obtain information about all plugin connections.
1257 *
1258 * @param cls unused
1259 * @param client the client
1260 * @param message the peer address information request
1261 */
1262static void
1263clients_handle_monitor_plugins (void *cls,
1264 struct GNUNET_SERVER_Client *client,
1265 const struct GNUNET_MessageHeader *message)
1266{
1267 GNUNET_SERVER_client_mark_monitor (client);
1268 GNUNET_SERVER_disable_receive_done_warning (client);
1269 GNUNET_SERVER_notification_context_add (plugin_nc,
1270 client);
1271 GNUNET_assert (NULL == sync_client);
1272 sync_client = client;
1273 GST_plugins_monitor_subscribe (&plugin_session_info_cb,
1274 NULL);
1275}
1276
1277
1278/**
1279 * Start handling requests from clients.
1280 *
1281 * @param server server used to accept clients from.
1282 */
1283void
1284GST_clients_start (struct GNUNET_SERVER_Handle *server)
1285{
1286 static const struct GNUNET_SERVER_MessageHandler handlers[] = {
1287 {&clients_handle_start, NULL,
1288 GNUNET_MESSAGE_TYPE_TRANSPORT_START, sizeof (struct StartMessage)},
1289 {&clients_handle_hello, NULL,
1290 GNUNET_MESSAGE_TYPE_HELLO, 0},
1291 {&clients_handle_send, NULL,
1292 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND, 0},
1293 {&clients_handle_address_to_string, NULL,
1294 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_TO_STRING, 0},
1295 {&clients_handle_monitor_peers, NULL,
1296 GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_PEER_REQUEST,
1297 sizeof (struct PeerMonitorMessage)},
1298 {&GST_blacklist_handle_init, NULL,
1299 GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_INIT,
1300 sizeof (struct GNUNET_MessageHeader)},
1301 {&GST_blacklist_handle_reply, NULL,
1302 GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_REPLY,
1303 sizeof (struct BlacklistMessage)},
1304 {&GST_manipulation_set_metric, NULL,
1305 GNUNET_MESSAGE_TYPE_TRANSPORT_TRAFFIC_METRIC,
1306 sizeof (struct TrafficMetricMessage) },
1307 {&clients_handle_monitor_plugins, NULL,
1308 GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_PLUGIN_START,
1309 sizeof (struct GNUNET_MessageHeader) },
1310 {NULL, NULL, 0, 0}
1311 };
1312 active_stccs = GNUNET_CONTAINER_multipeermap_create (128,
1313 GNUNET_YES);
1314 peer_nc = GNUNET_SERVER_notification_context_create (server, 0);
1315 val_nc = GNUNET_SERVER_notification_context_create (server, 0);
1316 plugin_nc = GNUNET_SERVER_notification_context_create (server, 0);
1317 GNUNET_SERVER_add_handlers (server, handlers);
1318 GNUNET_SERVER_disconnect_notify (server,
1319 &client_disconnect_notification,
1320 NULL);
1321}
1322
1323
1324/**
1325 * Stop processing clients.
1326 */
1327void
1328GST_clients_stop ()
1329{
1330 struct AddressToStringContext *cur;
1331
1332 while (NULL != (cur = a2s_head))
1333 {
1334 GNUNET_SERVER_transmit_context_destroy (cur->tc, GNUNET_NO);
1335 GNUNET_CONTAINER_DLL_remove (a2s_head, a2s_tail, cur);
1336 GNUNET_free (cur);
1337 }
1338 if (NULL != peer_nc)
1339 {
1340 GNUNET_SERVER_notification_context_destroy (peer_nc);
1341 peer_nc = NULL;
1342 }
1343 if (NULL != val_nc)
1344 {
1345 GNUNET_SERVER_notification_context_destroy (val_nc);
1346 val_nc = NULL;
1347 }
1348 if (NULL != plugin_nc)
1349 {
1350 GNUNET_SERVER_notification_context_destroy (plugin_nc);
1351 plugin_nc = NULL;
1352 }
1353 GNUNET_CONTAINER_multipeermap_destroy (active_stccs);
1354 active_stccs = NULL;
1355}
1356
1357
1358/**
1359 * Broadcast the given message to all of our clients.
1360 *
1361 * @param msg message to broadcast
1362 * @param may_drop #GNUNET_YES if the message can be dropped / is payload
1363 */
1364void
1365GST_clients_broadcast (const struct GNUNET_MessageHeader *msg,
1366 int may_drop)
1367{
1368 struct TransportClient *tc;
1369 int done;
1370
1371 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1372 "Asked to broadcast message of type %u with %u bytes\n",
1373 (unsigned int) ntohs (msg->type),
1374 (unsigned int) ntohs (msg->size));
1375 done = GNUNET_NO;
1376 for (tc = clients_head; NULL != tc; tc = tc->next)
1377 {
1378 if ( (GNUNET_YES == may_drop) &&
1379 (GNUNET_YES != tc->send_payload) )
1380 continue; /* skip, this client does not care about payload */
1381 unicast (tc, msg, may_drop);
1382 done = GNUNET_YES;
1383 }
1384 if (GNUNET_NO == done)
1385 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1386 "Message of type %u not delivered, is CORE service up?\n",
1387 ntohs (msg->type));
1388}
1389
1390
1391/**
1392 * Send the given message to a particular client
1393 *
1394 * @param client target of the message
1395 * @param msg message to transmit
1396 * @param may_drop #GNUNET_YES if the message can be dropped
1397 */
1398void
1399GST_clients_unicast (struct GNUNET_SERVER_Client *client,
1400 const struct GNUNET_MessageHeader *msg,
1401 int may_drop)
1402{
1403 struct TransportClient *tc;
1404
1405 tc = lookup_client (client);
1406 if (NULL == tc)
1407 return; /* client got disconnected in the meantime, drop message */
1408 unicast (tc, msg, may_drop);
1409}
1410
1411
1412/**
1413 * Broadcast the new active address to all clients monitoring the peer.
1414 *
1415 * @param peer peer this update is about (never NULL)
1416 * @param address address, NULL on disconnect
1417 * @param state the current state of the peer
1418 * @param state_timeout the time out for the state
1419 */
1420void
1421GST_clients_broadcast_peer_notification (const struct GNUNET_PeerIdentity *peer,
1422 const struct GNUNET_HELLO_Address *address,
1423 enum GNUNET_TRANSPORT_PeerState state,
1424 struct GNUNET_TIME_Absolute state_timeout)
1425{
1426 struct PeerIterateResponseMessage *msg;
1427 struct MonitoringClient *mc;
1428
1429 msg = compose_address_iterate_response_message (peer, address);
1430 msg->state = htonl (state);
1431 msg->state_timeout = GNUNET_TIME_absolute_hton (state_timeout);
1432 for (mc = peer_monitoring_clients_head; NULL != mc; mc = mc->next)
1433 if ((0 == memcmp (&mc->peer, &all_zeros,
1434 sizeof (struct GNUNET_PeerIdentity))) ||
1435 (0 == memcmp (&mc->peer, peer,
1436 sizeof (struct GNUNET_PeerIdentity))))
1437 GNUNET_SERVER_notification_context_unicast (peer_nc,
1438 mc->client,
1439 &msg->header,
1440 GNUNET_NO);
1441 GNUNET_free (msg);
1442}
1443
1444
1445/**
1446 * Mark the peer as down so we don't call the continuation
1447 * context in the future.
1448 *
1449 * @param cls NULL
1450 * @param peer peer that got disconnected
1451 * @param value a `struct SendTransmitContinuationContext` to mark
1452 * @return #GNUNET_OK (continue to iterate)
1453 */
1454static int
1455mark_peer_down (void *cls,
1456 const struct GNUNET_PeerIdentity *peer,
1457 void *value)
1458{
1459 struct SendTransmitContinuationContext *stcc = value;
1460
1461 stcc->down = GNUNET_YES;
1462 return GNUNET_OK;
1463}
1464
1465
1466/**
1467 * Notify all clients about a disconnect, and cancel
1468 * pending SEND_OK messages for this peer.
1469 *
1470 * @param peer peer that disconnected
1471 */
1472void
1473GST_clients_broadcast_disconnect (const struct GNUNET_PeerIdentity *peer)
1474{
1475 struct DisconnectInfoMessage disconnect_msg;
1476
1477 GNUNET_CONTAINER_multipeermap_get_multiple (active_stccs,
1478 peer,
1479 &mark_peer_down,
1480 NULL);
1481 disconnect_msg.header.size = htons (sizeof(struct DisconnectInfoMessage));
1482 disconnect_msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT);
1483 disconnect_msg.reserved = htonl (0);
1484 disconnect_msg.peer = *peer;
1485 GST_clients_broadcast (&disconnect_msg.header,
1486 GNUNET_NO);
1487
1488}
1489
1490
1491/* end of file gnunet-service-transport_clients.c */
diff --git a/src/transport/gnunet-service-transport_clients.h b/src/transport/gnunet-service-transport_clients.h
deleted file mode 100644
index d85e1e340..000000000
--- a/src/transport/gnunet-service-transport_clients.h
+++ /dev/null
@@ -1,101 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2010,2011 GNUnet e.V.
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
19*/
20
21/**
22 * @file transport/gnunet-service-transport_clients.h
23 * @brief client management API
24 * @author Christian Grothoff
25 */
26#ifndef GNUNET_SERVICE_TRANSPORT_CLIENTS_H
27#define GNUNET_SERVICE_TRANSPORT_CLIENTS_H
28
29#include "gnunet_transport_service.h"
30#include "gnunet_statistics_service.h"
31#include "gnunet_util_lib.h"
32#include "gnunet_hello_lib.h"
33
34
35/**
36 * Start handling requests from clients.
37 *
38 * @param server server used to accept clients from.
39 */
40void
41GST_clients_start (struct GNUNET_SERVER_Handle *server);
42
43
44/**
45 * Stop processing clients.
46 */
47void
48GST_clients_stop (void);
49
50
51/**
52 * Broadcast the given message to all of our clients.
53 *
54 * @param msg message to broadcast
55 * @param may_drop #GNUNET_YES if the message can be dropped / is payload
56 */
57void
58GST_clients_broadcast (const struct GNUNET_MessageHeader *msg,
59 int may_drop);
60
61
62/**
63 * Send the given message to a particular client
64 *
65 * @param client target of the message
66 * @param msg message to transmit
67 * @param may_drop #GNUNET_YES if the message can be dropped
68 */
69void
70GST_clients_unicast (struct GNUNET_SERVER_Client *client,
71 const struct GNUNET_MessageHeader *msg,
72 int may_drop);
73
74
75/**
76 * Broadcast the new active address to all clients monitoring the peer.
77 *
78 * @param peer peer this update is about (never NULL)
79 * @param address address, NULL on disconnect
80 * @param state the current state of the peer
81 * @param state_timeout the time out for the state
82 */
83void
84GST_clients_broadcast_peer_notification (const struct GNUNET_PeerIdentity *peer,
85 const struct GNUNET_HELLO_Address *address,
86 enum GNUNET_TRANSPORT_PeerState state,
87 struct GNUNET_TIME_Absolute state_timeout);
88
89
90/**
91 * Notify all clients about a disconnect, and cancel
92 * pending SEND_OK messages for this peer.
93 *
94 * @param peer peer that disconnected
95 */
96void
97GST_clients_broadcast_disconnect (const struct GNUNET_PeerIdentity *peer);
98
99
100#endif
101/* end of file gnunet-service-transport_clients.h */
diff --git a/src/transport/gnunet-service-transport_manipulation.c b/src/transport/gnunet-service-transport_manipulation.c
index 1af023d4d..f198d6e49 100644
--- a/src/transport/gnunet-service-transport_manipulation.c
+++ b/src/transport/gnunet-service-transport_manipulation.c
@@ -25,8 +25,6 @@
25 * @author Matthias Wachs 25 * @author Matthias Wachs
26 */ 26 */
27#include "platform.h" 27#include "platform.h"
28#include "gnunet-service-transport_blacklist.h"
29#include "gnunet-service-transport_clients.h"
30#include "gnunet-service-transport_hello.h" 28#include "gnunet-service-transport_hello.h"
31#include "gnunet-service-transport_neighbours.h" 29#include "gnunet-service-transport_neighbours.h"
32#include "gnunet-service-transport_plugins.h" 30#include "gnunet-service-transport_plugins.h"
@@ -170,20 +168,14 @@ static struct GNUNET_SCHEDULER_Task *generic_send_delay_task;
170/** 168/**
171 * Set traffic metric to manipulate 169 * Set traffic metric to manipulate
172 * 170 *
173 * @param cls closure
174 * @param client client sending message
175 * @param message containing information 171 * @param message containing information
176 */ 172 */
177void 173void
178GST_manipulation_set_metric (void *cls, 174GST_manipulation_set_metric (const struct TrafficMetricMessage *tm)
179 struct GNUNET_SERVER_Client *client,
180 const struct GNUNET_MessageHeader *message)
181{ 175{
182 const struct TrafficMetricMessage *tm;
183 static struct GNUNET_PeerIdentity zero; 176 static struct GNUNET_PeerIdentity zero;
184 struct TM_Peer *tmp; 177 struct TM_Peer *tmp;
185 178
186 tm = (const struct TrafficMetricMessage *) message;
187 if (0 == memcmp (&tm->peer, 179 if (0 == memcmp (&tm->peer,
188 &zero, 180 &zero,
189 sizeof(struct GNUNET_PeerIdentity))) 181 sizeof(struct GNUNET_PeerIdentity)))
@@ -192,13 +184,11 @@ GST_manipulation_set_metric (void *cls,
192 "Received traffic metrics for all peers\n"); 184 "Received traffic metrics for all peers\n");
193 delay_in = GNUNET_TIME_relative_ntoh (tm->delay_in); 185 delay_in = GNUNET_TIME_relative_ntoh (tm->delay_in);
194 delay_out = GNUNET_TIME_relative_ntoh (tm->delay_out); 186 delay_out = GNUNET_TIME_relative_ntoh (tm->delay_out);
195 GNUNET_SERVER_receive_done (client,
196 GNUNET_OK);
197 return; 187 return;
198 } 188 }
199 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 189 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
200 "Received traffic metrics for peer `%s'\n", 190 "Received traffic metrics for peer `%s'\n",
201 GNUNET_i2s(&tm->peer)); 191 GNUNET_i2s (&tm->peer));
202 if (NULL == 192 if (NULL ==
203 (tmp = GNUNET_CONTAINER_multipeermap_get (peers, 193 (tmp = GNUNET_CONTAINER_multipeermap_get (peers,
204 &tm->peer))) 194 &tm->peer)))
@@ -214,8 +204,6 @@ GST_manipulation_set_metric (void *cls,
214 &tm->properties); 204 &tm->properties);
215 tmp->delay_in = GNUNET_TIME_relative_ntoh (tm->delay_in); 205 tmp->delay_in = GNUNET_TIME_relative_ntoh (tm->delay_in);
216 tmp->delay_out = GNUNET_TIME_relative_ntoh (tm->delay_out); 206 tmp->delay_out = GNUNET_TIME_relative_ntoh (tm->delay_out);
217 GNUNET_SERVER_receive_done (client,
218 GNUNET_OK);
219} 207}
220 208
221 209
@@ -494,7 +482,9 @@ GST_manipulation_peer_disconnect (const struct GNUNET_PeerIdentity *peer)
494 while (NULL != (dqe = next)) 482 while (NULL != (dqe = next))
495 { 483 {
496 next = dqe->next; 484 next = dqe->next;
497 if (0 == memcmp(peer, &dqe->id, sizeof(dqe->id))) 485 if (0 == memcmp (peer,
486 &dqe->id,
487 sizeof (dqe->id)))
498 { 488 {
499 GNUNET_CONTAINER_DLL_remove (generic_dqe_head, 489 GNUNET_CONTAINER_DLL_remove (generic_dqe_head,
500 generic_dqe_tail, 490 generic_dqe_tail,
diff --git a/src/transport/gnunet-service-transport_manipulation.h b/src/transport/gnunet-service-transport_manipulation.h
index 6c7cede41..312dd1168 100644
--- a/src/transport/gnunet-service-transport_manipulation.h
+++ b/src/transport/gnunet-service-transport_manipulation.h
@@ -28,8 +28,6 @@
28#define GNUNET_SERVICE_TRANSPORT_MANIPULATION_H 28#define GNUNET_SERVICE_TRANSPORT_MANIPULATION_H
29 29
30#include "platform.h" 30#include "platform.h"
31#include "gnunet-service-transport_blacklist.h"
32#include "gnunet-service-transport_clients.h"
33#include "gnunet-service-transport_hello.h" 31#include "gnunet-service-transport_hello.h"
34#include "gnunet-service-transport_neighbours.h" 32#include "gnunet-service-transport_neighbours.h"
35#include "gnunet-service-transport_plugins.h" 33#include "gnunet-service-transport_plugins.h"
@@ -41,14 +39,10 @@
41/** 39/**
42 * Set traffic metric to manipulate 40 * Set traffic metric to manipulate
43 * 41 *
44 * @param cls closure
45 * @param client client sending message
46 * @param message containing information 42 * @param message containing information
47 */ 43 */
48void 44void
49GST_manipulation_set_metric (void *cls, 45GST_manipulation_set_metric (const struct TrafficMetricMessage *tm);
50 struct GNUNET_SERVER_Client *client,
51 const struct GNUNET_MessageHeader *message);
52 46
53 47
54/** 48/**
diff --git a/src/transport/gnunet-service-transport_neighbours.c b/src/transport/gnunet-service-transport_neighbours.c
index 2614c8551..d82112e03 100644
--- a/src/transport/gnunet-service-transport_neighbours.c
+++ b/src/transport/gnunet-service-transport_neighbours.c
@@ -26,8 +26,6 @@
26#include "platform.h" 26#include "platform.h"
27#include "gnunet_ats_service.h" 27#include "gnunet_ats_service.h"
28#include "gnunet-service-transport_ats.h" 28#include "gnunet-service-transport_ats.h"
29#include "gnunet-service-transport_blacklist.h"
30#include "gnunet-service-transport_clients.h"
31#include "gnunet-service-transport_neighbours.h" 29#include "gnunet-service-transport_neighbours.h"
32#include "gnunet-service-transport_manipulation.h" 30#include "gnunet-service-transport_manipulation.h"
33#include "gnunet-service-transport_plugins.h" 31#include "gnunet-service-transport_plugins.h"
diff --git a/src/transport/gnunet-service-transport_validation.c b/src/transport/gnunet-service-transport_validation.c
index 494f88f11..505626b59 100644
--- a/src/transport/gnunet-service-transport_validation.c
+++ b/src/transport/gnunet-service-transport_validation.c
@@ -25,8 +25,6 @@
25 */ 25 */
26#include "platform.h" 26#include "platform.h"
27#include "gnunet-service-transport_ats.h" 27#include "gnunet-service-transport_ats.h"
28#include "gnunet-service-transport_blacklist.h"
29#include "gnunet-service-transport_clients.h"
30#include "gnunet-service-transport_hello.h" 28#include "gnunet-service-transport_hello.h"
31#include "gnunet-service-transport_neighbours.h" 29#include "gnunet-service-transport_neighbours.h"
32#include "gnunet-service-transport_plugins.h" 30#include "gnunet-service-transport_plugins.h"
diff --git a/src/transport/test_transport_api_manipulation_recv_tcp.c b/src/transport/test_transport_api_manipulation_recv_tcp.c
index 3014715b1..69ccf5763 100644
--- a/src/transport/test_transport_api_manipulation_recv_tcp.c
+++ b/src/transport/test_transport_api_manipulation_recv_tcp.c
@@ -60,6 +60,16 @@ do_free (void *cls)
60 60
61 61
62static void 62static void
63delayed_transmit (void *cls)
64{
65 struct GNUNET_TRANSPORT_TESTING_SendClosure *sc = cls;
66
67 start_delayed = GNUNET_TIME_absolute_get ();
68 GNUNET_TRANSPORT_TESTING_large_send (sc);
69}
70
71
72static void
63sendtask (void *cls) 73sendtask (void *cls)
64{ 74{
65 struct GNUNET_TRANSPORT_TESTING_SendClosure *sc; 75 struct GNUNET_TRANSPORT_TESTING_SendClosure *sc;
@@ -84,7 +94,11 @@ sendtask (void *cls)
84 &prop, 94 &prop,
85 delay, 95 delay,
86 GNUNET_TIME_UNIT_ZERO); 96 GNUNET_TIME_UNIT_ZERO);
87 start_delayed = GNUNET_TIME_absolute_get(); 97 /* wait 1s to allow manipulation to go into effect */
98 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
99 &delayed_transmit,
100 sc);
101 return;
88 } 102 }
89 GNUNET_TRANSPORT_TESTING_large_send (sc); 103 GNUNET_TRANSPORT_TESTING_large_send (sc);
90} 104}
diff --git a/src/transport/test_transport_api_manipulation_send_tcp.c b/src/transport/test_transport_api_manipulation_send_tcp.c
index fbb7ccbdb..602d4d277 100644
--- a/src/transport/test_transport_api_manipulation_send_tcp.c
+++ b/src/transport/test_transport_api_manipulation_send_tcp.c
@@ -59,6 +59,16 @@ do_free (void *cls)
59 59
60 60
61static void 61static void
62delayed_transmit (void *cls)
63{
64 struct GNUNET_TRANSPORT_TESTING_SendClosure *sc = cls;
65
66 start_delayed = GNUNET_TIME_absolute_get ();
67 GNUNET_TRANSPORT_TESTING_large_send (sc);
68}
69
70
71static void
62sendtask (void *cls) 72sendtask (void *cls)
63{ 73{
64 struct GNUNET_TRANSPORT_TESTING_SendClosure *sc; 74 struct GNUNET_TRANSPORT_TESTING_SendClosure *sc;
@@ -76,14 +86,20 @@ sendtask (void *cls)
76 } 86 }
77 if (1 == messages_recv) 87 if (1 == messages_recv)
78 { 88 {
79 memset (&prop, 0, sizeof (prop)); 89 memset (&prop,
90 0,
91 sizeof (prop));
80 delay = GNUNET_TIME_UNIT_SECONDS; 92 delay = GNUNET_TIME_UNIT_SECONDS;
81 GNUNET_TRANSPORT_manipulation_set (ccc->p[0]->tmh, 93 GNUNET_TRANSPORT_manipulation_set (ccc->p[0]->tmh,
82 &ccc->p[1]->id, 94 &ccc->p[1]->id,
83 &prop, 95 &prop,
84 GNUNET_TIME_UNIT_ZERO, 96 GNUNET_TIME_UNIT_ZERO,
85 delay); 97 delay);
86 start_delayed = GNUNET_TIME_absolute_get(); 98 /* wait 1s to allow manipulation to go into effect */
99 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
100 &delayed_transmit,
101 sc);
102 return;
87 } 103 }
88 GNUNET_TRANSPORT_TESTING_large_send (sc); 104 GNUNET_TRANSPORT_TESTING_large_send (sc);
89} 105}
@@ -120,7 +136,7 @@ notify_receive (void *cls,
120 if (0 == messages_recv) 136 if (0 == messages_recv)
121 { 137 {
122 /* Received non-delayed message */ 138 /* Received non-delayed message */
123 dur_normal = GNUNET_TIME_absolute_get_duration(start_normal); 139 dur_normal = GNUNET_TIME_absolute_get_duration (start_normal);
124 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 140 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
125 "Received non-delayed message %u after %s\n", 141 "Received non-delayed message %u after %s\n",
126 messages_recv, 142 messages_recv,