uncrustify as demanded.
[oweals/gnunet.git] / src / transport / gnunet-service-transport.c
1 /*
2    This file is part of GNUnet.
3    Copyright (C) 2010-2016 GNUnet e.V.
4
5    GNUnet is free software: you can redistribute it and/or modify it
6    under the terms of the GNU Affero General Public License as published
7    by the Free Software Foundation, either version 3 of the License,
8    or (at your 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    Affero General Public License for more details.
14
15    You should have received a copy of the GNU Affero General Public License
16    along with this program.  If not, see <http://www.gnu.org/licenses/>.
17
18      SPDX-License-Identifier: AGPL3.0-or-later
19  */
20 /**
21  * @file transport/gnunet-service-transport.c
22  * @brief main for gnunet-service-transport
23  * @author Christian Grothoff
24  */
25 #include "platform.h"
26 #include "gnunet_util_lib.h"
27 #include "gnunet_hello_lib.h"
28 #include "gnunet_statistics_service.h"
29 #include "gnunet_transport_service.h"
30 #include "gnunet_peerinfo_service.h"
31 #include "gnunet_ats_service.h"
32 #include "gnunet-service-transport.h"
33 #include "gnunet-service-transport_ats.h"
34 #include "gnunet-service-transport_hello.h"
35 #include "gnunet-service-transport_neighbours.h"
36 #include "gnunet-service-transport_plugins.h"
37 #include "gnunet-service-transport_validation.h"
38 #include "gnunet-service-transport_manipulation.h"
39 #include "transport.h"
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
60
61 /**
62  * Information we need for an asynchronous session kill.
63  */
64 struct GNUNET_ATS_SessionKiller {
65   /**
66    * Kept in a DLL.
67    */
68   struct GNUNET_ATS_SessionKiller *next;
69
70   /**
71    * Kept in a DLL.
72    */
73   struct GNUNET_ATS_SessionKiller *prev;
74
75   /**
76    * Session to kill.
77    */
78   struct GNUNET_ATS_Session *session;
79
80   /**
81    * Plugin for the session.
82    */
83   struct GNUNET_TRANSPORT_PluginFunctions *plugin;
84
85   /**
86    * The kill task.
87    */
88   struct GNUNET_SCHEDULER_Task *task;
89 };
90
91
92 /**
93  * What type of client is the `struct TransportClient` about?
94  */
95 enum ClientType {
96   /**
97    * We do not know yet (client is fresh).
98    */
99   CT_NONE = 0,
100
101   /**
102    * Is the CORE service, we need to forward traffic to it.
103    */
104   CT_CORE = 1,
105
106   /**
107    * It is a monitor, forward monitor data.
108    */
109   CT_MONITOR = 2,
110
111   /**
112    * It is a blacklist, query about allowed connections.
113    */
114   CT_BLACKLIST = 3,
115
116   /**
117    * CORE client without any handlers.
118    */
119   CT_CORE_NO_HANDLERS = 4
120 };
121
122
123 /**
124  * Context we use when performing a blacklist check.
125  */
126 struct GST_BlacklistCheck;
127
128 /**
129  * Client connected to the transport service.
130  */
131 struct TransportClient {
132   /**
133    * This is a doubly-linked list.
134    */
135   struct TransportClient *next;
136
137   /**
138    * This is a doubly-linked list.
139    */
140   struct TransportClient *prev;
141
142   /**
143    * Handle to the client.
144    */
145   struct GNUNET_SERVICE_Client *client;
146
147   /**
148    * Message queue to the client.
149    */
150   struct GNUNET_MQ_Handle *mq;
151
152   /**
153    * What type of client is this?
154    */
155   enum ClientType type;
156
157   union {
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        * Blacklist check that we're currently performing (or NULL
171        * if we're performing one that has been cancelled).
172        */
173       struct GST_BlacklistCheck *bc;
174
175       /**
176        * Set to #GNUNET_YES if we're currently waiting for a reply.
177        */
178       int waiting_for_reply;
179
180       /**
181        * #GNUNET_YES if we have to call receive_done for this client
182        */
183       int call_receive_done;
184     } blacklist;
185   } details;
186 };
187
188
189 /**
190  * Context we use when performing a blacklist check.
191  */
192 struct GST_BlacklistCheck {
193   /**
194    * This is a linked list.
195    */
196   struct GST_BlacklistCheck *next;
197
198   /**
199    * This is a linked list.
200    */
201   struct GST_BlacklistCheck *prev;
202
203   /**
204    * Peer being checked.
205    */
206   struct GNUNET_PeerIdentity peer;
207
208   /**
209    * Continuation to call with the result.
210    */
211   GST_BlacklistTestContinuation cont;
212
213   /**
214    * Closure for @e cont.
215    */
216   void *cont_cls;
217
218   /**
219    * Address for #GST_blacklist_abort_matching(), can be NULL.
220    */
221   struct GNUNET_HELLO_Address *address;
222
223   /**
224    * Session for #GST_blacklist_abort_matching(), can be NULL.
225    */
226   struct GNUNET_ATS_Session *session;
227
228   /**
229    * Our current position in the blacklisters list.
230    */
231   struct TransportClient *bl_pos;
232
233   /**
234    * Current task performing the check.
235    */
236   struct GNUNET_SCHEDULER_Task *task;
237 };
238
239
240 /**
241  * Context for address to string operations
242  */
243 struct AddressToStringContext {
244   /**
245    * This is a doubly-linked list.
246    */
247   struct AddressToStringContext *next;
248
249   /**
250    * This is a doubly-linked list.
251    */
252   struct AddressToStringContext *prev;
253
254   /**
255    * Client that made the request.
256    */
257   struct TransportClient *tc;
258 };
259
260
261 /**
262  * Closure for #handle_send_transmit_continuation()
263  */
264 struct SendTransmitContinuationContext {
265   /**
266    * Client that made the request.
267    */
268   struct TransportClient *tc;
269
270   /**
271    * Peer that was the target.
272    */
273   struct GNUNET_PeerIdentity target;
274
275   /**
276    * At what time did we receive the message?
277    */
278   struct GNUNET_TIME_Absolute send_time;
279
280   /**
281    * Unique ID, for logging.
282    */
283   unsigned long long uuid;
284
285   /**
286    * Set to #GNUNET_YES if the connection for @e target goes
287    * down and we thus must no longer send the
288    * #GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK message.
289    */
290   int down;
291 };
292
293
294 /**
295  * Head of linked list of all clients to this service.
296  */
297 static struct TransportClient *clients_head;
298
299 /**
300  * Tail of linked list of all clients to this service.
301  */
302 static struct TransportClient *clients_tail;
303
304 /**
305  * Map of peer identities to active send transmit continuation
306  * contexts. Used to flag contexts as 'dead' when a connection goes
307  * down. Values are of type `struct SendTransmitContinuationContext
308  * *`.
309  */
310 static struct GNUNET_CONTAINER_MultiPeerMap *active_stccs;
311
312 /**
313  * Head of linked list of all pending address iterations
314  */
315 static struct AddressToStringContext *a2s_head;
316
317 /**
318  * Tail of linked list of all pending address iterations
319  */
320 static struct AddressToStringContext *a2s_tail;
321
322 /**
323  * Head of DLL of active blacklisting queries.
324  */
325 static struct GST_BlacklistCheck *bc_head;
326
327 /**
328  * Tail of DLL of active blacklisting queries.
329  */
330 static struct GST_BlacklistCheck *bc_tail;
331
332 /**
333  * Hashmap of blacklisted peers.  Values are of type 'char *' (transport names),
334  * can be NULL if we have no static blacklist.
335  */
336 static struct GNUNET_CONTAINER_MultiPeerMap *blacklist;
337
338 /**
339  * Notification context, to send updates on changes to active plugin
340  * connections.
341  */
342 static struct GNUNET_NotificationContext *plugin_nc;
343
344 /**
345  * Plugin monitoring client we are currently syncing, NULL if all
346  * monitoring clients are in sync.
347  */
348 static struct TransportClient *sync_client;
349
350 /**
351  * Peer identity that is all zeros, used as a way to indicate
352  * "all peers".  Used for comparissons.
353  */
354 static struct GNUNET_PeerIdentity all_zeros;
355
356 /**
357  * Statistics handle.
358  */
359 struct GNUNET_STATISTICS_Handle *GST_stats;
360
361 /**
362  * Configuration handle.
363  */
364 const struct GNUNET_CONFIGURATION_Handle *GST_cfg;
365
366 /**
367  * Configuration handle.
368  */
369 struct GNUNET_PeerIdentity GST_my_identity;
370
371 /**
372  * Handle to peerinfo service.
373  */
374 struct GNUNET_PEERINFO_Handle *GST_peerinfo;
375
376 /**
377  * Our private key.
378  */
379 struct GNUNET_CRYPTO_EddsaPrivateKey *GST_my_private_key;
380
381 /**
382  * ATS scheduling handle.
383  */
384 struct GNUNET_ATS_SchedulingHandle *GST_ats;
385
386 /**
387  * ATS connectivity handle.
388  */
389 struct GNUNET_ATS_ConnectivityHandle *GST_ats_connect;
390
391 /**
392  * Hello address expiration
393  */
394 struct GNUNET_TIME_Relative hello_expiration;
395
396 /**
397  * Head of DLL of asynchronous tasks to kill sessions.
398  */
399 static struct GNUNET_ATS_SessionKiller *sk_head;
400
401 /**
402  * Tail of DLL of asynchronous tasks to kill sessions.
403  */
404 static struct GNUNET_ATS_SessionKiller *sk_tail;
405
406 /**
407  * Interface scanner determines our LAN address range(s).
408  */
409 struct GNUNET_NT_InterfaceScanner *GST_is;
410
411 /**
412  * Queue the given message for transmission to the given client
413  *
414  * @param tc target of the message
415  * @param msg message to transmit
416  * @param may_drop #GNUNET_YES if the message can be dropped
417  */
418 static void
419 unicast(struct TransportClient *tc,
420         const struct GNUNET_MessageHeader *msg,
421         int may_drop)
422 {
423   struct GNUNET_MQ_Envelope *env;
424
425   if ((GNUNET_MQ_get_length(tc->mq) >= MAX_PENDING) &&
426       (GNUNET_YES == may_drop))
427     {
428       GNUNET_log(
429         GNUNET_ERROR_TYPE_DEBUG,
430         "Dropping message of type %u and size %u, have %u/%u messages pending\n",
431         ntohs(msg->type),
432         ntohs(msg->size),
433         GNUNET_MQ_get_length(tc->mq),
434         MAX_PENDING);
435       GNUNET_STATISTICS_update(GST_stats,
436                                gettext_noop(
437                                  "# messages dropped due to slow client"),
438                                1,
439                                GNUNET_NO);
440       return;
441     }
442   env = GNUNET_MQ_msg_copy(msg);
443   GNUNET_MQ_send(tc->mq, env);
444 }
445
446
447 /**
448  * Called whenever a client connects.  Allocates our
449  * data structures associated with that client.
450  *
451  * @param cls closure, NULL
452  * @param client identification of the client
453  * @param mq message queue for the client
454  * @return our `struct TransportClient`
455  */
456 static void *
457 client_connect_cb(void *cls,
458                   struct GNUNET_SERVICE_Client *client,
459                   struct GNUNET_MQ_Handle *mq)
460 {
461   struct TransportClient *tc;
462
463   tc = GNUNET_new(struct TransportClient);
464   tc->client = client;
465   tc->mq = mq;
466   GNUNET_CONTAINER_DLL_insert(clients_head, clients_tail, tc);
467   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Client %p connected\n", tc);
468   return tc;
469 }
470
471
472 /**
473  * Perform next action in the blacklist check.
474  *
475  * @param cls the `struct BlacklistCheck*`
476  */
477 static void
478 do_blacklist_check(void *cls);
479
480
481 /**
482  * Mark the peer as down so we don't call the continuation
483  * context in the future.
484  *
485  * @param cls a `struct TransportClient`
486  * @param peer a peer we are sending to
487  * @param value a `struct SendTransmitContinuationContext` to mark
488  * @return #GNUNET_OK (continue to iterate)
489  */
490 static int
491 mark_match_down(void *cls, const struct GNUNET_PeerIdentity *peer, void *value)
492 {
493   struct TransportClient *tc = cls;
494   struct SendTransmitContinuationContext *stcc = value;
495
496   if (tc == stcc->tc)
497     {
498       stcc->down = GNUNET_YES;
499       stcc->tc = NULL;
500     }
501   return GNUNET_OK;
502 }
503
504
505 /**
506  * Called whenever a client is disconnected.  Frees our
507  * resources associated with that client.
508  *
509  * @param cls closure, NULL
510  * @param client identification of the client
511  * @param app_ctx our `struct TransportClient`
512  */
513 static void
514 client_disconnect_cb(void *cls,
515                      struct GNUNET_SERVICE_Client *client,
516                      void *app_ctx)
517 {
518   struct TransportClient *tc = app_ctx;
519   struct GST_BlacklistCheck *bc;
520
521   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
522              "Client %p disconnected, cleaning up.\n",
523              tc);
524   GNUNET_CONTAINER_multipeermap_iterate(active_stccs, &mark_match_down, tc);
525   for (struct AddressToStringContext *cur = a2s_head; NULL != cur;
526        cur = cur->next)
527     {
528       if (cur->tc == tc)
529         cur->tc = NULL;
530     }
531   GNUNET_CONTAINER_DLL_remove(clients_head, clients_tail, tc);
532   switch (tc->type)
533     {
534     case CT_NONE:
535       break;
536
537     case CT_CORE:
538       break;
539
540     case CT_MONITOR:
541       break;
542
543     case CT_BLACKLIST:
544       for (bc = bc_head; NULL != bc; bc = bc->next)
545         {
546           if (bc->bl_pos != tc)
547             continue;
548           bc->bl_pos = tc->next;
549           if (NULL == bc->task)
550             bc->task = GNUNET_SCHEDULER_add_now(&do_blacklist_check, bc);
551         }
552       break;
553
554     case CT_CORE_NO_HANDLERS:
555       break;
556     }
557   GNUNET_free(tc);
558 }
559
560
561 /**
562  * Function called for each of our connected neighbours.  Notify the
563  * client about the existing neighbour.
564  *
565  * @param cls the `struct TransportClient *` to notify
566  * @param peer identity of the neighbour
567  * @param address the address
568  * @param state the current state of the peer
569  * @param state_timeout the time out for the state
570  * @param bandwidth_in inbound bandwidth in NBO
571  * @param bandwidth_out outbound bandwidth in NBO
572  */
573 static void
574 notify_client_about_neighbour(void *cls,
575                               const struct GNUNET_PeerIdentity *peer,
576                               const struct GNUNET_HELLO_Address *address,
577                               enum GNUNET_TRANSPORT_PeerState state,
578                               struct GNUNET_TIME_Absolute state_timeout,
579                               struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in,
580                               struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out)
581 {
582   struct TransportClient *tc = cls;
583   struct ConnectInfoMessage cim;
584
585   if (GNUNET_NO == GST_neighbours_test_connected(peer))
586     return;
587   cim.header.size = htons(sizeof(struct ConnectInfoMessage));
588   cim.header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
589   cim.id = *peer;
590   cim.quota_out = bandwidth_out;
591   unicast(tc, &cim.header, GNUNET_NO);
592 }
593
594
595 /**
596  * Initialize a normal client.  We got a start message from this
597  * client, add it to the list of clients for broadcasting of inbound
598  * messages.
599  *
600  * @param cls the client
601  * @param start the start message that was sent
602  */
603 static void
604 handle_client_start(void *cls, const struct StartMessage *start)
605 {
606   struct TransportClient *tc = cls;
607   const struct GNUNET_MessageHeader *hello;
608   uint32_t options;
609
610   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Client %p sent START\n", tc);
611   options = ntohl(start->options);
612   if ((0 != (1 & options)) &&
613       (0 != memcmp(&start->self,
614                    &GST_my_identity,
615                    sizeof(struct GNUNET_PeerIdentity))))
616     {
617       /* client thinks this is a different peer, reject */
618       GNUNET_break(0);
619       GNUNET_SERVICE_client_drop(tc->client);
620       return;
621     }
622   if (CT_NONE != tc->type)
623     {
624       GNUNET_break(0);
625       GNUNET_SERVICE_client_drop(tc->client);
626       return;
627     }
628   if (0 != (2 & options))
629     tc->type = CT_CORE;
630   else
631     tc->type = CT_CORE_NO_HANDLERS;
632   hello = GST_hello_get();
633   if (NULL != hello)
634     unicast(tc, hello, GNUNET_NO);
635   GST_neighbours_iterate(&notify_client_about_neighbour, tc);
636   GNUNET_SERVICE_client_continue(tc->client);
637 }
638
639
640 /**
641  * Client sent us a HELLO.  Check the request.
642  *
643  * @param cls the client
644  * @param message the HELLO message
645  */
646 static int
647 check_client_hello(void *cls, const struct GNUNET_MessageHeader *message)
648 {
649   return GNUNET_OK; /* FIXME: check here? */
650 }
651
652
653 /**
654  * Client sent us a HELLO.  Process the request.
655  *
656  * @param cls the client
657  * @param message the HELLO message
658  */
659 static void
660 handle_client_hello(void *cls, const struct GNUNET_MessageHeader *message)
661 {
662   struct TransportClient *tc = cls;
663
664   GNUNET_log(GNUNET_ERROR_TYPE_INFO, "Received HELLO message\n");
665   GST_validation_handle_hello(message);
666   GNUNET_SERVICE_client_continue(tc->client);
667 }
668
669
670 /**
671  * Function called after the transmission is done.  Notify the client that it is
672  * OK to send the next message.
673  *
674  * @param cls closure
675  * @param success #GNUNET_OK on success, #GNUNET_NO on failure, #GNUNET_SYSERR if we're not connected
676  * @param bytes_payload bytes payload sent
677  * @param bytes_on_wire bytes sent on wire
678  */
679 static void
680 handle_send_transmit_continuation(void *cls,
681                                   int success,
682                                   size_t bytes_payload,
683                                   size_t bytes_on_wire)
684 {
685   struct SendTransmitContinuationContext *stcc = cls;
686   struct SendOkMessage send_ok_msg;
687   struct GNUNET_TIME_Relative delay;
688   const struct GNUNET_HELLO_Address *addr;
689
690   delay = GNUNET_TIME_absolute_get_duration(stcc->send_time);
691   addr = GST_neighbour_get_current_address(&stcc->target);
692   if (delay.rel_value_us > GNUNET_CONSTANTS_LATENCY_WARN.rel_value_us)
693     GNUNET_log(GNUNET_ERROR_TYPE_WARNING,
694                "It took us %s to send %u/%u bytes to %s (%d, %s)\n",
695                GNUNET_STRINGS_relative_time_to_string(delay, 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   else
702     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
703                "It took us %s to send %u/%u bytes to %s (%d, %s)\n",
704                GNUNET_STRINGS_relative_time_to_string(delay, GNUNET_YES),
705                (unsigned int)bytes_payload,
706                (unsigned int)bytes_on_wire,
707                GNUNET_i2s(&stcc->target),
708                success,
709                (NULL != addr) ? addr->transport_name : "%");
710
711   if (GNUNET_NO == stcc->down)
712     {
713       /* Only send confirmation if we are still connected */
714       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
715                  "Sending SEND_OK for transmission request %llu\n",
716                  stcc->uuid);
717       send_ok_msg.header.size = htons(sizeof(send_ok_msg));
718       send_ok_msg.header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK);
719       send_ok_msg.bytes_msg = htonl(bytes_payload);
720       send_ok_msg.bytes_physical = htonl(bytes_on_wire);
721       send_ok_msg.success = htonl(success);
722       send_ok_msg.peer = stcc->target;
723       unicast(stcc->tc, &send_ok_msg.header, GNUNET_NO);
724     }
725   GNUNET_assert(
726     GNUNET_OK ==
727     GNUNET_CONTAINER_multipeermap_remove(active_stccs, &stcc->target, stcc));
728   GNUNET_free(stcc);
729 }
730
731
732 /**
733  * Client asked for transmission to a peer.  Process the request.
734  *
735  * @param cls the client
736  * @param obm the send message that was sent
737  */
738 static int
739 check_client_send(void *cls, const struct OutboundMessage *obm)
740 {
741   uint16_t size;
742   const struct GNUNET_MessageHeader *obmm;
743
744   size = ntohs(obm->header.size) - sizeof(struct OutboundMessage);
745   if (size < sizeof(struct GNUNET_MessageHeader))
746     {
747       GNUNET_break(0);
748       return GNUNET_SYSERR;
749     }
750   obmm = (const struct GNUNET_MessageHeader *)&obm[1];
751   if (size != ntohs(obmm->size))
752     {
753       GNUNET_break(0);
754       return GNUNET_SYSERR;
755     }
756   return GNUNET_OK;
757 }
758
759
760 /**
761  * Client asked for transmission to a peer.  Process the request.
762  *
763  * @param cls the client
764  * @param obm the send message that was sent
765  */
766 static void
767 handle_client_send(void *cls, const struct OutboundMessage *obm)
768 {
769   static unsigned long long uuid_gen;
770   struct TransportClient *tc = cls;
771   const struct GNUNET_MessageHeader *obmm;
772   struct SendTransmitContinuationContext *stcc;
773
774   obmm = (const struct GNUNET_MessageHeader *)&obm[1];
775   if (GNUNET_NO == GST_neighbours_test_connected(&obm->peer))
776     {
777       /* not connected, not allowed to send; can happen due to asynchronous operations */
778       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
779                  "Could not send message to peer `%s': not connected\n",
780                  GNUNET_i2s(&obm->peer));
781       GNUNET_STATISTICS_update(
782         GST_stats,
783         gettext_noop("# bytes payload dropped (other peer was not connected)"),
784         ntohs(obmm->size),
785         GNUNET_NO);
786       GNUNET_SERVICE_client_continue(tc->client);
787       return;
788     }
789   GNUNET_log(
790     GNUNET_ERROR_TYPE_DEBUG,
791     "Received SEND request %llu for `%s' and first message of type %u and total size %u\n",
792     uuid_gen,
793     GNUNET_i2s(&obm->peer),
794     ntohs(obmm->type),
795     ntohs(obmm->size));
796   GNUNET_SERVICE_client_continue(tc->client);
797
798   stcc = GNUNET_new(struct SendTransmitContinuationContext);
799   stcc->target = obm->peer;
800   stcc->tc = tc;
801   stcc->send_time = GNUNET_TIME_absolute_get();
802   stcc->uuid = uuid_gen++;
803   (void)GNUNET_CONTAINER_multipeermap_put(
804     active_stccs,
805     &stcc->target,
806     stcc,
807     GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
808   GST_manipulation_send(&obm->peer,
809                         obmm,
810                         ntohs(obmm->size),
811                         GNUNET_TIME_relative_ntoh(obm->timeout),
812                         &handle_send_transmit_continuation,
813                         stcc);
814 }
815
816
817 /**
818  * Take the given address and append it to the set of results sent back to
819  * the client.  This function may be called serveral times for a single
820  * conversion.   The last invocation will be with a @a address of
821  * NULL and a @a res of #GNUNET_OK.  Thus, to indicate conversion
822  * errors, the callback might be called first with @a address NULL and
823  * @a res being #GNUNET_SYSERR.  In that case, there will still be a
824  * subsequent call later with @a address NULL and @a res #GNUNET_OK.
825  *
826  * @param cls the `struct AddressToStringContext`
827  * @param buf text to transmit (contains the human-readable address, or NULL)
828  * @param res #GNUNET_OK if conversion was successful, #GNUNET_SYSERR on error,
829  *            never #GNUNET_NO
830  */
831 static void
832 transmit_address_to_client(void *cls, const char *buf, int res)
833 {
834   struct AddressToStringContext *actx = cls;
835   struct GNUNET_MQ_Envelope *env;
836   struct AddressToStringResultMessage *atsm;
837   size_t slen;
838
839   GNUNET_assert((GNUNET_OK == res) || (GNUNET_SYSERR == res));
840   if (NULL == actx->tc)
841     return;
842   if (NULL == buf)
843     {
844       env = GNUNET_MQ_msg(atsm,
845                           GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_TO_STRING_REPLY);
846       if (GNUNET_OK == res)
847         {
848           /* this was the last call, transmit */
849           atsm->res = htonl(GNUNET_OK);
850           atsm->addr_len = htonl(0);
851           GNUNET_MQ_send(actx->tc->mq, env);
852           GNUNET_CONTAINER_DLL_remove(a2s_head, a2s_tail, actx);
853           GNUNET_free(actx);
854           return;
855         }
856       if (GNUNET_SYSERR == res)
857         {
858           /* address conversion failed, but there will be more callbacks */
859           atsm->res = htonl(GNUNET_SYSERR);
860           atsm->addr_len = htonl(0);
861           GNUNET_MQ_send(actx->tc->mq, env);
862           return;
863         }
864     }
865   GNUNET_assert(GNUNET_OK == res);
866   /* succesful conversion, append*/
867   slen = strlen(buf) + 1;
868   env =
869     GNUNET_MQ_msg_extra(atsm,
870                         slen,
871                         GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_TO_STRING_REPLY);
872   atsm->res = htonl(GNUNET_YES);
873   atsm->addr_len = htonl(slen);
874   GNUNET_memcpy(&atsm[1], buf, slen);
875   GNUNET_MQ_send(actx->tc->mq, env);
876 }
877
878
879 /**
880  * Client asked to resolve an address.  Check the request.
881  *
882  * @param cls the client
883  * @param alum the resolution request
884  * @return #GNUNET_OK if @a alum is well-formed
885  */
886 static int
887 check_client_address_to_string(void *cls,
888                                const struct AddressLookupMessage *alum)
889 {
890   const char *plugin_name;
891   const char *address;
892   uint32_t address_len;
893   uint16_t size;
894
895   size = ntohs(alum->header.size);
896   address_len = ntohs(alum->addrlen);
897   if (size <= sizeof(struct AddressLookupMessage) + address_len)
898     {
899       GNUNET_break(0);
900       return GNUNET_SYSERR;
901     }
902   address = (const char *)&alum[1];
903   plugin_name = (const char *)&address[address_len];
904   if ('\0' != plugin_name[size - sizeof(struct AddressLookupMessage) -
905                           address_len - 1])
906     {
907       GNUNET_break(0);
908       return GNUNET_SYSERR;
909     }
910   return GNUNET_OK;
911 }
912
913
914 /**
915  * Client asked to resolve an address.  Process the request.
916  *
917  * @param cls the client
918  * @param alum the resolution request
919  */
920 static void
921 handle_client_address_to_string(void *cls,
922                                 const struct AddressLookupMessage *alum)
923 {
924   struct TransportClient *tc = cls;
925   struct GNUNET_TRANSPORT_PluginFunctions *papi;
926   const char *plugin_name;
927   const char *address;
928   uint32_t address_len;
929   struct AddressToStringContext *actx;
930   struct GNUNET_MQ_Envelope *env;
931   struct AddressToStringResultMessage *atsm;
932   struct GNUNET_TIME_Relative rtimeout;
933   int32_t numeric;
934
935   address_len = ntohs(alum->addrlen);
936   address = (const char *)&alum[1];
937   plugin_name = (const char *)&address[address_len];
938   rtimeout = GNUNET_TIME_relative_ntoh(alum->timeout);
939   numeric = ntohs(alum->numeric_only);
940   papi = GST_plugins_printer_find(plugin_name);
941   if (NULL == papi)
942     {
943       GNUNET_log(GNUNET_ERROR_TYPE_WARNING,
944                  "Failed to find plugin `%s'\n",
945                  plugin_name);
946       env = GNUNET_MQ_msg(atsm,
947                           GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_TO_STRING_REPLY);
948       atsm->res = htonl(GNUNET_SYSERR);
949       atsm->addr_len = htonl(0);
950       GNUNET_MQ_send(tc->mq, env);
951       env = GNUNET_MQ_msg(atsm,
952                           GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_TO_STRING_REPLY);
953       atsm->res = htonl(GNUNET_OK);
954       atsm->addr_len = htonl(0);
955       GNUNET_MQ_send(tc->mq, env);
956       return;
957     }
958   actx = GNUNET_new(struct AddressToStringContext);
959   actx->tc = tc;
960   GNUNET_CONTAINER_DLL_insert(a2s_head, a2s_tail, actx);
961   GNUNET_SERVICE_client_disable_continue_warning(tc->client);
962   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
963              "Pretty-printing address of %u bytes using plugin `%s'\n",
964              address_len,
965              plugin_name);
966   papi->address_pretty_printer(papi->cls,
967                                plugin_name,
968                                address,
969                                address_len,
970                                numeric,
971                                rtimeout,
972                                &transmit_address_to_client,
973                                actx);
974 }
975
976
977 /**
978  * Compose #PeerIterateResponseMessage using the given peer and address.
979  *
980  * @param peer identity of the peer
981  * @param address the address, NULL on disconnect
982  * @return composed message
983  */
984 static struct PeerIterateResponseMessage *
985 compose_address_iterate_response_message(
986   const struct GNUNET_PeerIdentity *peer,
987   const struct GNUNET_HELLO_Address *address)
988 {
989   struct PeerIterateResponseMessage *msg;
990   size_t size;
991   size_t tlen;
992   size_t alen;
993   char *addr;
994
995   GNUNET_assert(NULL != peer);
996   if (NULL != address)
997     {
998       tlen = strlen(address->transport_name) + 1;
999       alen = address->address_length;
1000     }
1001   else
1002     {
1003       tlen = 0;
1004       alen = 0;
1005     }
1006   size = (sizeof(struct PeerIterateResponseMessage) + alen + tlen);
1007   msg = GNUNET_malloc(size);
1008   msg->header.size = htons(size);
1009   msg->header.type =
1010     htons(GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_PEER_RESPONSE);
1011   msg->reserved = htonl(0);
1012   msg->peer = *peer;
1013   msg->addrlen = htonl(alen);
1014   msg->pluginlen = htonl(tlen);
1015
1016   if (NULL != address)
1017     {
1018       msg->local_address_info = htonl((uint32_t)address->local_info);
1019       addr = (char *)&msg[1];
1020       GNUNET_memcpy(addr, address->address, alen);
1021       GNUNET_memcpy(&addr[alen], address->transport_name, tlen);
1022     }
1023   return msg;
1024 }
1025
1026
1027 /**
1028  * Context for #send_validation_information() and
1029  * #send_peer_information().
1030  */
1031 struct IterationContext {
1032   /**
1033    * Context to use for the transmission.
1034    */
1035   struct TransportClient *tc;
1036
1037   /**
1038    * Which peers do we care about?
1039    */
1040   struct GNUNET_PeerIdentity id;
1041
1042   /**
1043    * #GNUNET_YES if @e id should be ignored because we want all peers.
1044    */
1045   int all;
1046 };
1047
1048
1049 /**
1050  * Output information of neighbours to the given client.
1051  *
1052  * @param cls the `struct PeerIterationContext *`
1053  * @param peer identity of the neighbour
1054  * @param address the address
1055  * @param state current state this peer is in
1056  * @param state_timeout timeout for the current state of the peer
1057  * @param bandwidth_in inbound quota in NBO
1058  * @param bandwidth_out outbound quota in NBO
1059  */
1060 static void
1061 send_peer_information(void *cls,
1062                       const struct GNUNET_PeerIdentity *peer,
1063                       const struct GNUNET_HELLO_Address *address,
1064                       enum GNUNET_TRANSPORT_PeerState state,
1065                       struct GNUNET_TIME_Absolute state_timeout,
1066                       struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in,
1067                       struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out)
1068 {
1069   struct IterationContext *pc = cls;
1070   struct GNUNET_MQ_Envelope *env;
1071   struct PeerIterateResponseMessage *msg;
1072
1073   if ((GNUNET_YES != pc->all) && (0 != memcmp(peer, &pc->id, sizeof(pc->id))))
1074     return;
1075   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1076              "Sending information about `%s' using address `%s' in state `%s'\n",
1077              GNUNET_i2s(peer),
1078              (NULL != address) ? GST_plugins_a2s(address) : "<none>",
1079              GNUNET_TRANSPORT_ps2s(state));
1080   msg = compose_address_iterate_response_message(peer, address);
1081   msg->state = htonl(state);
1082   msg->state_timeout = GNUNET_TIME_absolute_hton(state_timeout);
1083   env = GNUNET_MQ_msg_copy(&msg->header);
1084   GNUNET_free(msg);
1085   GNUNET_MQ_send(pc->tc->mq, env);
1086 }
1087
1088
1089 /**
1090  * Client asked to obtain information about a specific or all peers
1091  * Process the request.
1092  *
1093  * @param cls the client
1094  * @param msg the peer address information request
1095  */
1096 static void
1097 handle_client_monitor_peers(void *cls, const struct PeerMonitorMessage *msg)
1098 {
1099   struct TransportClient *tc = cls;
1100   struct IterationContext pc;
1101
1102   if (CT_NONE != tc->type)
1103     {
1104       GNUNET_break(0);
1105       GNUNET_SERVICE_client_drop(tc->client);
1106       return;
1107     }
1108   GNUNET_SERVICE_client_disable_continue_warning(tc->client);
1109   GNUNET_SERVICE_client_mark_monitor(tc->client);
1110
1111   /* Send initial list */
1112   pc.tc = tc;
1113   if (0 == memcmp(&msg->peer, &all_zeros, sizeof(struct GNUNET_PeerIdentity)))
1114     {
1115       /* iterate over all neighbours */
1116       pc.all = GNUNET_YES;
1117       pc.id = msg->peer;
1118     }
1119   else
1120     {
1121       /* just return one neighbour */
1122       pc.all = GNUNET_NO;
1123       pc.id = msg->peer;
1124     }
1125   GST_neighbours_iterate(&send_peer_information, &pc);
1126
1127   if (GNUNET_YES != ntohl(msg->one_shot))
1128     {
1129       tc->details.monitor_peer = msg->peer;
1130       tc->type = CT_MONITOR;
1131       if (0 !=
1132           memcmp(&msg->peer, &all_zeros, sizeof(struct GNUNET_PeerIdentity)))
1133         GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1134                    "Client %p started monitoring of the peer `%s'\n",
1135                    tc,
1136                    GNUNET_i2s(&msg->peer));
1137       else
1138         GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1139                    "Client %p started monitoring all peers\n",
1140                    tc);
1141     }
1142   else
1143     {
1144       struct GNUNET_MessageHeader *msg;
1145       struct GNUNET_MQ_Envelope *env;
1146
1147       env =
1148         GNUNET_MQ_msg(msg,
1149                       GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_PEER_RESPONSE_END);
1150       GNUNET_MQ_send(tc->mq, env);
1151     }
1152 }
1153
1154
1155 /**
1156  * Function called by the plugin with information about the
1157  * current sessions managed by the plugin (for monitoring).
1158  *
1159  * @param cls closure
1160  * @param session session handle this information is about,
1161  *        NULL to indicate that we are "in sync" (initial
1162  *        iteration complete)
1163  * @param info information about the state of the session,
1164  *        NULL if @a session is also NULL and we are
1165  *        merely signalling that the initial iteration is over
1166  */
1167 static void
1168 plugin_session_info_cb(void *cls,
1169                        struct GNUNET_ATS_Session *session,
1170                        const struct GNUNET_TRANSPORT_SessionInfo *info)
1171 {
1172   struct GNUNET_MQ_Envelope *env;
1173   struct TransportPluginMonitorMessage *msg;
1174   struct GNUNET_MessageHeader *sync;
1175   size_t size;
1176   size_t slen;
1177   uint16_t alen;
1178   char *name;
1179   char *addr;
1180
1181   if (0 == GNUNET_notification_context_get_size(plugin_nc))
1182     {
1183       GST_plugins_monitor_subscribe(NULL, NULL);
1184       return;
1185     }
1186   if ((NULL == info) && (NULL == session))
1187     {
1188       /* end of initial iteration */
1189       if (NULL != sync_client)
1190         {
1191           env =
1192             GNUNET_MQ_msg(sync, GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_PLUGIN_SYNC);
1193           GNUNET_MQ_send(sync_client->mq, env);
1194           sync_client = NULL;
1195         }
1196       return;
1197     }
1198   GNUNET_assert(NULL != info);
1199   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1200              "Plugin event for peer %s on transport %s\n",
1201              GNUNET_i2s(&info->address->peer),
1202              info->address->transport_name);
1203   slen = strlen(info->address->transport_name) + 1;
1204   alen = info->address->address_length;
1205   size = sizeof(struct TransportPluginMonitorMessage) + slen + alen;
1206   if (size > UINT16_MAX)
1207     {
1208       GNUNET_break(0);
1209       return;
1210     }
1211   msg = GNUNET_malloc(size);
1212   msg->header.size = htons(size);
1213   msg->header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_PLUGIN_EVENT);
1214   msg->session_state = htons((uint16_t)info->state);
1215   msg->is_inbound = htons((int16_t)info->is_inbound);
1216   msg->msgs_pending = htonl(info->num_msg_pending);
1217   msg->bytes_pending = htonl(info->num_bytes_pending);
1218   msg->timeout = GNUNET_TIME_absolute_hton(info->session_timeout);
1219   msg->delay = GNUNET_TIME_absolute_hton(info->receive_delay);
1220   msg->peer = info->address->peer;
1221   msg->session_id = (uint64_t)(intptr_t)session;
1222   msg->plugin_name_len = htons(slen);
1223   msg->plugin_address_len = htons(alen);
1224   name = (char *)&msg[1];
1225   GNUNET_memcpy(name, info->address->transport_name, slen);
1226   addr = &name[slen];
1227   GNUNET_memcpy(addr, info->address->address, alen);
1228   if (NULL != sync_client)
1229     {
1230       struct GNUNET_MQ_Envelope *env;
1231
1232       env = GNUNET_MQ_msg_copy(&msg->header);
1233       GNUNET_MQ_send(sync_client->mq, env);
1234     }
1235   else
1236     {
1237       GNUNET_notification_context_broadcast(plugin_nc, &msg->header, GNUNET_NO);
1238     }
1239   GNUNET_free(msg);
1240 }
1241
1242
1243 /**
1244  * Client asked to obtain information about all plugin connections.
1245  *
1246  * @param cls the client
1247  * @param message the peer address information request
1248  */
1249 static void
1250 handle_client_monitor_plugins(void *cls,
1251                               const struct GNUNET_MessageHeader *message)
1252 {
1253   struct TransportClient *tc = cls;
1254
1255   GNUNET_SERVICE_client_mark_monitor(tc->client);
1256   GNUNET_SERVICE_client_disable_continue_warning(tc->client);
1257   GNUNET_notification_context_add(plugin_nc, tc->mq);
1258   GNUNET_assert(NULL == sync_client);
1259   sync_client = tc;
1260   GST_plugins_monitor_subscribe(&plugin_session_info_cb, NULL);
1261 }
1262
1263
1264 /**
1265  * Broadcast the given message to all of our clients.
1266  *
1267  * @param msg message to broadcast
1268  * @param may_drop #GNUNET_YES if the message can be dropped / is payload
1269  */
1270 void
1271 GST_clients_broadcast(const struct GNUNET_MessageHeader *msg, int may_drop)
1272 {
1273   int done;
1274
1275   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1276              "Asked to broadcast message of type %u with %u bytes\n",
1277              (unsigned int)ntohs(msg->type),
1278              (unsigned int)ntohs(msg->size));
1279   done = GNUNET_NO;
1280   for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
1281     {
1282       if (CT_NONE == tc->type)
1283         continue; /* client not yet ready */
1284       if ((GNUNET_YES == may_drop) && (CT_CORE != tc->type))
1285         continue; /* skip, this client does not care about payload */
1286       unicast(tc, msg, may_drop);
1287       done = GNUNET_YES;
1288     }
1289   if (GNUNET_NO == done)
1290     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1291                "Message of type %u not delivered, is CORE service up?\n",
1292                ntohs(msg->type));
1293 }
1294
1295
1296 /**
1297  * Broadcast the new active address to all clients monitoring the peer.
1298  *
1299  * @param peer peer this update is about (never NULL)
1300  * @param address address, NULL on disconnect
1301  * @param state the current state of the peer
1302  * @param state_timeout the time out for the state
1303  */
1304 void
1305 GST_clients_broadcast_peer_notification(
1306   const struct GNUNET_PeerIdentity *peer,
1307   const struct GNUNET_HELLO_Address *address,
1308   enum GNUNET_TRANSPORT_PeerState state,
1309   struct GNUNET_TIME_Absolute state_timeout)
1310 {
1311   struct GNUNET_MQ_Envelope *env;
1312   struct PeerIterateResponseMessage *msg;
1313
1314   msg = compose_address_iterate_response_message(peer, address);
1315   msg->state = htonl(state);
1316   msg->state_timeout = GNUNET_TIME_absolute_hton(state_timeout);
1317   for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
1318     {
1319       if (CT_MONITOR != tc->type)
1320         continue;
1321       if ((0 == memcmp(&tc->details.monitor_peer,
1322                        &all_zeros,
1323                        sizeof(struct GNUNET_PeerIdentity))) ||
1324           (0 == memcmp(&tc->details.monitor_peer,
1325                        peer,
1326                        sizeof(struct GNUNET_PeerIdentity))))
1327         {
1328           env = GNUNET_MQ_msg_copy(&msg->header);
1329           GNUNET_MQ_send(tc->mq, env);
1330         }
1331     }
1332   GNUNET_free(msg);
1333 }
1334
1335
1336 /**
1337  * Mark the peer as down so we don't call the continuation
1338  * context in the future.
1339  *
1340  * @param cls NULL
1341  * @param peer peer that got disconnected
1342  * @param value a `struct SendTransmitContinuationContext` to mark
1343  * @return #GNUNET_OK (continue to iterate)
1344  */
1345 static int
1346 mark_peer_down(void *cls, const struct GNUNET_PeerIdentity *peer, void *value)
1347 {
1348   struct SendTransmitContinuationContext *stcc = value;
1349
1350   stcc->down = GNUNET_YES;
1351   return GNUNET_OK;
1352 }
1353
1354
1355 /**
1356  * Notify all clients about a disconnect, and cancel
1357  * pending SEND_OK messages for this peer.
1358  *
1359  * @param peer peer that disconnected
1360  */
1361 void
1362 GST_clients_broadcast_disconnect(const struct GNUNET_PeerIdentity *peer)
1363 {
1364   struct DisconnectInfoMessage disconnect_msg;
1365
1366   GNUNET_CONTAINER_multipeermap_get_multiple(active_stccs,
1367                                              peer,
1368                                              &mark_peer_down,
1369                                              NULL);
1370   disconnect_msg.header.size = htons(sizeof(struct DisconnectInfoMessage));
1371   disconnect_msg.header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT);
1372   disconnect_msg.reserved = htonl(0);
1373   disconnect_msg.peer = *peer;
1374   GST_clients_broadcast(&disconnect_msg.header, GNUNET_NO);
1375 }
1376
1377
1378 /**
1379  * Transmit our HELLO message to the given (connected) neighbour.
1380  *
1381  * @param cls the 'HELLO' message
1382  * @param peer identity of the peer
1383  * @param address the address
1384  * @param state current state this peer is in
1385  * @param state_timeout timeout for the current state of the peer
1386  * @param bandwidth_in inbound quota in NBO
1387  * @param bandwidth_out outbound quota in NBO
1388  */
1389 static void
1390 transmit_our_hello(void *cls,
1391                    const struct GNUNET_PeerIdentity *peer,
1392                    const struct GNUNET_HELLO_Address *address,
1393                    enum GNUNET_TRANSPORT_PeerState state,
1394                    struct GNUNET_TIME_Absolute state_timeout,
1395                    struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in,
1396                    struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out)
1397 {
1398   const struct GNUNET_MessageHeader *hello = cls;
1399
1400   if (0 == memcmp(peer, &GST_my_identity, sizeof(struct GNUNET_PeerIdentity)))
1401     return; /* not to ourselves */
1402   if (GNUNET_NO == GST_neighbours_test_connected(peer))
1403     return;
1404
1405   GST_neighbours_send(peer,
1406                       hello,
1407                       ntohs(hello->size),
1408                       hello_expiration,
1409                       NULL,
1410                       NULL);
1411 }
1412
1413
1414 /**
1415  * My HELLO has changed. Tell everyone who should know.
1416  *
1417  * @param cls unused
1418  * @param hello new HELLO
1419  */
1420 static void
1421 process_hello_update(void *cls, const struct GNUNET_MessageHeader *hello)
1422 {
1423   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Broadcasting HELLO to clients\n");
1424   GST_clients_broadcast(hello, GNUNET_NO);
1425   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Broadcasting HELLO to neighbours\n");
1426   GST_neighbours_iterate(&transmit_our_hello, (void *)hello);
1427 }
1428
1429
1430 /**
1431  * We received some payload.  Prepare to pass it on to our clients.
1432  *
1433  * @param address address and (claimed) identity of the other peer
1434  * @param session identifier used for this session (NULL for plugins
1435  *                that do not offer bi-directional communication to the sender
1436  *                using the same "connection")
1437  * @param message the message to process
1438  * @return how long the plugin should wait until receiving more data
1439  */
1440 static struct GNUNET_TIME_Relative
1441 process_payload(const struct GNUNET_HELLO_Address *address,
1442                 struct GNUNET_ATS_Session *session,
1443                 const struct GNUNET_MessageHeader *message)
1444 {
1445   struct GNUNET_TIME_Relative ret;
1446   int do_forward;
1447   struct InboundMessage *im;
1448   size_t msg_size = ntohs(message->size);
1449   size_t size = sizeof(struct InboundMessage) + msg_size;
1450   char buf[size] GNUNET_ALIGN;
1451
1452   do_forward = GNUNET_SYSERR;
1453   ret = GST_neighbours_calculate_receive_delay(&address->peer,
1454                                                msg_size,
1455                                                &do_forward);
1456   if (!GST_neighbours_test_connected(&address->peer))
1457     {
1458       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1459                  "Discarded %u bytes type %u payload from peer `%s'\n",
1460                  (unsigned int)msg_size,
1461                  ntohs(message->type),
1462                  GNUNET_i2s(&address->peer));
1463       GNUNET_STATISTICS_update(
1464         GST_stats,
1465         gettext_noop("# bytes payload discarded due to not connected peer"),
1466         msg_size,
1467         GNUNET_NO);
1468       return ret;
1469     }
1470
1471   if (GNUNET_YES != do_forward)
1472     return ret;
1473   im = (struct InboundMessage *)buf;
1474   im->header.size = htons(size);
1475   im->header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_RECV);
1476   im->peer = address->peer;
1477   GNUNET_memcpy(&im[1], message, ntohs(message->size));
1478   GST_clients_broadcast(&im->header, GNUNET_YES);
1479   return ret;
1480 }
1481
1482
1483 /**
1484  * Task to asynchronously terminate a session.
1485  *
1486  * @param cls the `struct GNUNET_ATS_SessionKiller` with the information for the kill
1487  */
1488 static void
1489 kill_session_task(void *cls)
1490 {
1491   struct GNUNET_ATS_SessionKiller *sk = cls;
1492
1493   sk->task = NULL;
1494   GNUNET_CONTAINER_DLL_remove(sk_head, sk_tail, sk);
1495   sk->plugin->disconnect_session(sk->plugin->cls, sk->session);
1496   GNUNET_free(sk);
1497 }
1498
1499
1500 /**
1501  * Force plugin to terminate session due to communication
1502  * issue.
1503  *
1504  * @param plugin_name name of the plugin
1505  * @param session session to termiante
1506  */
1507 static void
1508 kill_session(const char *plugin_name, struct GNUNET_ATS_Session *session)
1509 {
1510   struct GNUNET_TRANSPORT_PluginFunctions *plugin;
1511   struct GNUNET_ATS_SessionKiller *sk;
1512
1513   for (sk = sk_head; NULL != sk; sk = sk->next)
1514     if (sk->session == session)
1515       return;
1516   plugin = GST_plugins_find(plugin_name);
1517   if (NULL == plugin)
1518     {
1519       GNUNET_break(0);
1520       return;
1521     }
1522   /* need to issue disconnect asynchronously */
1523   sk = GNUNET_new(struct GNUNET_ATS_SessionKiller);
1524   sk->session = session;
1525   sk->plugin = plugin;
1526   sk->task = GNUNET_SCHEDULER_add_now(&kill_session_task, sk);
1527   GNUNET_CONTAINER_DLL_insert(sk_head, sk_tail, sk);
1528 }
1529
1530
1531 /**
1532  * Black list check result for try_connect call
1533  * If connection to the peer is allowed request adddress and ???
1534  *
1535  * @param cls the message
1536  * @param peer the peer
1537  * @param address the address
1538  * @param session the session
1539  * @param result the result
1540  */
1541 static void
1542 connect_bl_check_cont(void *cls,
1543                       const struct GNUNET_PeerIdentity *peer,
1544                       const struct GNUNET_HELLO_Address *address,
1545                       struct GNUNET_ATS_Session *session,
1546                       int result)
1547 {
1548   struct GNUNET_MessageHeader *msg = cls;
1549
1550   if (GNUNET_OK == result)
1551     {
1552       /* Blacklist allows to speak to this peer, forward SYN to neighbours  */
1553       GNUNET_log(GNUNET_ERROR_TYPE_INFO,
1554                  "Received SYN message from peer `%s' at `%s'\n",
1555                  GNUNET_i2s(peer),
1556                  GST_plugins_a2s(address));
1557       if (GNUNET_OK != GST_neighbours_handle_session_syn(msg, peer))
1558         {
1559           GST_blacklist_abort_matching(address, session);
1560           kill_session(address->transport_name, session);
1561         }
1562       GNUNET_free(msg);
1563       return;
1564     }
1565   GNUNET_free(msg);
1566   if (GNUNET_SYSERR == result)
1567     return; /* check was aborted, session destroyed */
1568   /* Blacklist denies to speak to this peer */
1569   GNUNET_log(GNUNET_ERROR_TYPE_INFO,
1570              "Discarding SYN message from `%s' due to denied blacklist check\n",
1571              GNUNET_i2s(peer));
1572   kill_session(address->transport_name, session);
1573 }
1574
1575
1576 /**
1577  * Function called by the transport for each received message.
1578  *
1579  * @param cls closure, const char* with the name of the plugin we received the message from
1580  * @param address address and (claimed) identity of the other peer
1581  * @param message the message, NULL if we only care about
1582  *                learning about the delay until we should receive again
1583  * @param session identifier used for this session (NULL for plugins
1584  *                that do not offer bi-directional communication to the sender
1585  *                using the same "connection")
1586  * @return how long the plugin should wait until receiving more data
1587  *         (plugins that do not support this, can ignore the return value)
1588  */
1589 struct GNUNET_TIME_Relative
1590 GST_receive_callback(void *cls,
1591                      const struct GNUNET_HELLO_Address *address,
1592                      struct GNUNET_ATS_Session *session,
1593                      const struct GNUNET_MessageHeader *message)
1594 {
1595   const char *plugin_name = cls;
1596   struct GNUNET_TIME_Relative ret;
1597   uint16_t type;
1598
1599   ret = GNUNET_TIME_UNIT_ZERO;
1600   if (NULL == message)
1601     goto end;
1602   type = ntohs(message->type);
1603   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1604              "Received message with type %u from peer `%s' at %s\n",
1605              type,
1606              GNUNET_i2s(&address->peer),
1607              GST_plugins_a2s(address));
1608
1609   GNUNET_STATISTICS_update(GST_stats,
1610                            gettext_noop("# bytes total received"),
1611                            ntohs(message->size),
1612                            GNUNET_NO);
1613   GST_neighbours_notify_data_recv(address, message);
1614   switch (type)
1615     {
1616     case GNUNET_MESSAGE_TYPE_HELLO_LEGACY:
1617       /* Legacy HELLO message, discard  */
1618       return ret;
1619
1620     case GNUNET_MESSAGE_TYPE_HELLO:
1621       if (GNUNET_OK != GST_validation_handle_hello(message))
1622         {
1623           GNUNET_break_op(0);
1624           GST_blacklist_abort_matching(address, session);
1625         }
1626       return ret;
1627
1628     case GNUNET_MESSAGE_TYPE_TRANSPORT_PING:
1629       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1630                  "Processing PING from `%s'\n",
1631                  GST_plugins_a2s(address));
1632       if (GNUNET_OK !=
1633           GST_validation_handle_ping(&address->peer, message, address, session))
1634         {
1635           GST_blacklist_abort_matching(address, session);
1636           kill_session(plugin_name, session);
1637         }
1638       break;
1639
1640     case GNUNET_MESSAGE_TYPE_TRANSPORT_PONG:
1641       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1642                  "Processing PONG from `%s'\n",
1643                  GST_plugins_a2s(address));
1644       if (GNUNET_OK != GST_validation_handle_pong(&address->peer, message))
1645         {
1646           GNUNET_break_op(0);
1647           GST_blacklist_abort_matching(address, session);
1648           kill_session(plugin_name, session);
1649         }
1650       break;
1651
1652     case GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_SYN:
1653       /* Do blacklist check if communication with this peer is allowed */
1654       (void)GST_blacklist_test_allowed(&address->peer,
1655                                        NULL,
1656                                        &connect_bl_check_cont,
1657                                        GNUNET_copy_message(message),
1658                                        address,
1659                                        session);
1660       break;
1661
1662     case GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_SYN_ACK:
1663       if (GNUNET_OK !=
1664           GST_neighbours_handle_session_syn_ack(message, address, session))
1665         {
1666           GST_blacklist_abort_matching(address, session);
1667           kill_session(plugin_name, session);
1668         }
1669       break;
1670
1671     case GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_ACK:
1672       if (GNUNET_OK !=
1673           GST_neighbours_handle_session_ack(message, address, session))
1674         {
1675           GNUNET_break_op(0);
1676           GST_blacklist_abort_matching(address, session);
1677           kill_session(plugin_name, session);
1678         }
1679       break;
1680
1681     case GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_DISCONNECT:
1682       GST_neighbours_handle_disconnect_message(&address->peer, message);
1683       break;
1684
1685     case GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_QUOTA:
1686       GST_neighbours_handle_quota_message(&address->peer, message);
1687       break;
1688
1689     case GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_KEEPALIVE:
1690       GST_neighbours_keepalive(&address->peer, message);
1691       break;
1692
1693     case GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_KEEPALIVE_RESPONSE:
1694       GST_neighbours_keepalive_response(&address->peer, message);
1695       break;
1696
1697     default:
1698       /* should be payload */
1699       GNUNET_STATISTICS_update(GST_stats,
1700                                gettext_noop("# bytes payload received"),
1701                                ntohs(message->size),
1702                                GNUNET_NO);
1703       ret = process_payload(address, session, message);
1704       break;
1705     }
1706 end:
1707   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1708              "Allowing receive from peer %s to continue in %s\n",
1709              GNUNET_i2s(&address->peer),
1710              GNUNET_STRINGS_relative_time_to_string(ret, GNUNET_YES));
1711   return ret;
1712 }
1713
1714
1715 /**
1716  * Function that will be called for each address the transport
1717  * is aware that it might be reachable under.  Update our HELLO.
1718  *
1719  * @param cls name of the plugin (const char*)
1720  * @param add_remove should the address added (YES) or removed (NO) from the
1721  *                   set of valid addresses?
1722  * @param address the address to add or remove
1723  */
1724 static void
1725 plugin_env_address_change_notification(
1726   void *cls,
1727   int add_remove,
1728   const struct GNUNET_HELLO_Address *address)
1729 {
1730   static int addresses = 0;
1731
1732   if (GNUNET_YES == add_remove)
1733     {
1734       addresses++;
1735       GNUNET_STATISTICS_update(GST_stats, "# transport addresses", 1, GNUNET_NO);
1736     }
1737   else if (GNUNET_NO == add_remove)
1738     {
1739       if (0 == addresses)
1740         {
1741           GNUNET_break(0);
1742         }
1743       else
1744         {
1745           addresses--;
1746           GNUNET_STATISTICS_update(GST_stats,
1747                                    "# transport addresses",
1748                                    -1,
1749                                    GNUNET_NO);
1750         }
1751     }
1752   GNUNET_log(GNUNET_ERROR_TYPE_INFO,
1753              "Transport now has %u addresses to communicate\n",
1754              addresses);
1755   GST_hello_modify_addresses(add_remove, address);
1756 }
1757
1758
1759 /**
1760  * Function that will be called whenever the plugin internally
1761  * cleans up a session pointer and hence the service needs to
1762  * discard all of those sessions as well.  Plugins that do not
1763  * use sessions can simply omit calling this function and always
1764  * use NULL wherever a session pointer is needed.  This function
1765  * should be called BEFORE a potential "TransmitContinuation"
1766  * from the "TransmitFunction".
1767  *
1768  * @param cls closure
1769  * @param address which address was the session for
1770  * @param session which session is being destoyed
1771  */
1772 static void
1773 plugin_env_session_end(void *cls,
1774                        const struct GNUNET_HELLO_Address *address,
1775                        struct GNUNET_ATS_Session *session)
1776 {
1777   struct GNUNET_ATS_SessionKiller *sk;
1778
1779   if (NULL == address)
1780     {
1781       GNUNET_break(0);
1782       return;
1783     }
1784   if (NULL == session)
1785     {
1786       GNUNET_break(0);
1787       return;
1788     }
1789   GNUNET_assert(strlen(address->transport_name) > 0);
1790
1791   GNUNET_log(
1792     GNUNET_ERROR_TYPE_DEBUG,
1793     "Notification from plugin about terminated session %p from peer `%s' address `%s'\n",
1794     session,
1795     GNUNET_i2s(&address->peer),
1796     GST_plugins_a2s(address));
1797
1798   GST_neighbours_session_terminated(&address->peer, session);
1799   GST_ats_del_session(address, session);
1800   GST_blacklist_abort_matching(address, session);
1801
1802   for (sk = sk_head; NULL != sk; sk = sk->next)
1803     {
1804       if (sk->session == session)
1805         {
1806           GNUNET_CONTAINER_DLL_remove(sk_head, sk_tail, sk);
1807           GNUNET_SCHEDULER_cancel(sk->task);
1808           GNUNET_free(sk);
1809           break;
1810         }
1811     }
1812 }
1813
1814
1815 /**
1816  * Black list check result from blacklist check triggered when a
1817  * plugin gave us a new session in #plugin_env_session_start().  If
1818  * connection to the peer is disallowed, kill the session.
1819  *
1820  * @param cls NULL
1821  * @param peer the peer
1822  * @param address address associated with the request
1823  * @param session session associated with the request
1824  * @param result the result
1825  */
1826 static void
1827 plugin_env_session_start_bl_check_cont(
1828   void *cls,
1829   const struct GNUNET_PeerIdentity *peer,
1830   const struct GNUNET_HELLO_Address *address,
1831   struct GNUNET_ATS_Session *session,
1832   int result)
1833 {
1834   if (GNUNET_OK != result)
1835     {
1836       kill_session(address->transport_name, session);
1837       return;
1838     }
1839   if (GNUNET_YES !=
1840       GNUNET_HELLO_address_check_option(address,
1841                                         GNUNET_HELLO_ADDRESS_INFO_INBOUND))
1842     {
1843       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1844                  "Informing verifier about inbound session's address `%s'\n",
1845                  GST_plugins_a2s(address));
1846       GST_validation_handle_address(address);
1847     }
1848 }
1849
1850
1851 /**
1852  * Plugin tells transport service about a new inbound session
1853  *
1854  * @param cls unused
1855  * @param address the address
1856  * @param session the new session
1857  * @param scope network scope information
1858  */
1859 static void
1860 plugin_env_session_start(void *cls,
1861                          const struct GNUNET_HELLO_Address *address,
1862                          struct GNUNET_ATS_Session *session,
1863                          enum GNUNET_NetworkType scope)
1864 {
1865   struct GNUNET_ATS_Properties prop;
1866
1867   if (NULL == address)
1868     {
1869       GNUNET_break(0);
1870       return;
1871     }
1872   if (NULL == session)
1873     {
1874       GNUNET_break(0);
1875       return;
1876     }
1877   GNUNET_log(
1878     GNUNET_ERROR_TYPE_INFO,
1879     "Notification from plugin `%s' about new session from peer `%s' address `%s'\n",
1880     address->transport_name,
1881     GNUNET_i2s(&address->peer),
1882     GST_plugins_a2s(address));
1883   if (GNUNET_YES ==
1884       GNUNET_HELLO_address_check_option(address,
1885                                         GNUNET_HELLO_ADDRESS_INFO_INBOUND))
1886     {
1887       /* inbound is always new, but outbound MAY already be known, but
1888          for example for UNIX, we have symmetric connections and thus we
1889          may not know the address yet; add if necessary! */
1890       /* FIXME: maybe change API here so we just pass scope? */
1891       memset(&prop, 0, sizeof(prop));
1892       GNUNET_break(GNUNET_NT_UNSPECIFIED != scope);
1893       prop.scope = scope;
1894       GST_ats_add_inbound_address(address, session, &prop);
1895     }
1896   /* Do blacklist check if communication with this peer is allowed */
1897   (void)GST_blacklist_test_allowed(&address->peer,
1898                                    address->transport_name,
1899                                    &plugin_env_session_start_bl_check_cont,
1900                                    NULL,
1901                                    address,
1902                                    session);
1903 }
1904
1905
1906 /**
1907  * Function called by ATS to notify the callee that the
1908  * assigned bandwidth or address for a given peer was changed.  If the
1909  * callback is called with address/bandwidth assignments of zero, the
1910  * ATS disconnect function will still be called once the disconnect
1911  * actually happened.
1912  *
1913  * @param cls closure
1914  * @param peer the peer this address is intended for
1915  * @param address address to use (for peer given in address)
1916  * @param session session to use (if available)
1917  * @param bandwidth_out assigned outbound bandwidth for the connection in NBO,
1918  *      0 to disconnect from peer
1919  * @param bandwidth_in assigned inbound bandwidth for the connection in NBO,
1920  *      0 to disconnect from peer
1921  * @param ats ATS information
1922  * @param ats_count number of @a ats elements
1923  */
1924 static void
1925 ats_request_address_change(void *cls,
1926                            const struct GNUNET_PeerIdentity *peer,
1927                            const struct GNUNET_HELLO_Address *address,
1928                            struct GNUNET_ATS_Session *session,
1929                            struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out,
1930                            struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in)
1931 {
1932   uint32_t bw_in = ntohl(bandwidth_in.value__);
1933   uint32_t bw_out = ntohl(bandwidth_out.value__);
1934
1935   if (NULL == peer)
1936     {
1937       /* ATS service died, all suggestions become invalid!
1938          (but we'll keep using the allocations for a little
1939          while, to keep going while ATS restarts) */
1940       /* FIXME: We should drop all
1941          connections now, as ATS won't explicitly tell
1942          us and be unaware of ongoing resource allocations! */
1943       return;
1944     }
1945   /* ATS tells me to disconnect from peer */
1946   if ((0 == bw_in) && (0 == bw_out))
1947     {
1948       GNUNET_log(GNUNET_ERROR_TYPE_INFO,
1949                  "ATS tells me to disconnect from peer `%s'\n",
1950                  GNUNET_i2s(peer));
1951       GST_neighbours_force_disconnect(peer);
1952       return;
1953     }
1954   GNUNET_assert(NULL != address);
1955   GNUNET_STATISTICS_update(GST_stats,
1956                            "# ATS suggestions received",
1957                            1,
1958                            GNUNET_NO);
1959   GST_neighbours_switch_to_address(address,
1960                                    session,
1961                                    bandwidth_in,
1962                                    bandwidth_out);
1963 }
1964
1965
1966 /**
1967  * Closure for #test_connection_ok().
1968  */
1969 struct TestConnectionContext {
1970   /**
1971    * Is this the first neighbour we're checking?
1972    */
1973   int first;
1974
1975   /**
1976    * Handle to the blacklisting client we need to ask.
1977    */
1978   struct TransportClient *tc;
1979 };
1980
1981
1982 /**
1983  * Got the result about an existing connection from a new blacklister.
1984  * Shutdown the neighbour if necessary.
1985  *
1986  * @param cls unused
1987  * @param peer the neighbour that was investigated
1988  * @param address address associated with the request
1989  * @param session session associated with the request
1990  * @param allowed #GNUNET_OK if we can keep it,
1991  *                #GNUNET_NO if we must shutdown the connection
1992  */
1993 static void
1994 confirm_or_drop_neighbour(void *cls,
1995                           const struct GNUNET_PeerIdentity *peer,
1996                           const struct GNUNET_HELLO_Address *address,
1997                           struct GNUNET_ATS_Session *session,
1998                           int allowed)
1999 {
2000   if (GNUNET_OK == allowed)
2001     return; /* we're done */
2002   GNUNET_STATISTICS_update(GST_stats,
2003                            gettext_noop("# disconnects due to blacklist"),
2004                            1,
2005                            GNUNET_NO);
2006   GST_neighbours_force_disconnect(peer);
2007 }
2008
2009
2010 /**
2011  * Test if an existing connection is still acceptable given a new
2012  * blacklisting client.
2013  *
2014  * @param cls the `struct TestConnectionContext *`
2015  * @param peer identity of the peer
2016  * @param address the address
2017  * @param state current state this peer is in
2018  * @param state_timeout timeout for the current state of the peer
2019  * @param bandwidth_in bandwidth assigned inbound
2020  * @param bandwidth_out bandwidth assigned outbound
2021  */
2022 static void
2023 test_connection_ok(void *cls,
2024                    const struct GNUNET_PeerIdentity *peer,
2025                    const struct GNUNET_HELLO_Address *address,
2026                    enum GNUNET_TRANSPORT_PeerState state,
2027                    struct GNUNET_TIME_Absolute state_timeout,
2028                    struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in,
2029                    struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out)
2030 {
2031   struct TestConnectionContext *tcc = cls;
2032   struct GST_BlacklistCheck *bc;
2033
2034   bc = GNUNET_new(struct GST_BlacklistCheck);
2035   GNUNET_CONTAINER_DLL_insert(bc_head, bc_tail, bc);
2036   bc->peer = *peer;
2037   bc->address = GNUNET_HELLO_address_copy(address);
2038   bc->cont = &confirm_or_drop_neighbour;
2039   bc->cont_cls = NULL;
2040   bc->bl_pos = tcc->tc;
2041   if (GNUNET_YES == tcc->first)
2042     {
2043       /* all would wait for the same client, no need to
2044        * create more than just the first task right now */
2045       bc->task = GNUNET_SCHEDULER_add_now(&do_blacklist_check, bc);
2046       tcc->first = GNUNET_NO;
2047     }
2048 }
2049
2050
2051 /**
2052  * Initialize a blacklisting client.  We got a blacklist-init
2053  * message from this client, add it to the list of clients
2054  * to query for blacklisting.
2055  *
2056  * @param cls the client
2057  * @param message the blacklist-init message that was sent
2058  */
2059 static void
2060 handle_client_blacklist_init(void *cls,
2061                              const struct GNUNET_MessageHeader *message)
2062 {
2063   struct TransportClient *tc = cls;
2064   struct TestConnectionContext tcc;
2065
2066   if (CT_NONE != tc->type)
2067     {
2068       GNUNET_break(0);
2069       GNUNET_SERVICE_client_drop(tc->client);
2070       return;
2071     }
2072   GNUNET_SERVICE_client_mark_monitor(tc->client);
2073   tc->type = CT_BLACKLIST;
2074   tc->details.blacklist.call_receive_done = GNUNET_YES;
2075   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "New blacklist client %p\n", tc);
2076   /* confirm that all existing connections are OK! */
2077   tcc.tc = tc;
2078   tcc.first = GNUNET_YES;
2079   GST_neighbours_iterate(&test_connection_ok, &tcc);
2080 }
2081
2082
2083 /**
2084  * Free the given entry in the blacklist.
2085  *
2086  * @param cls unused
2087  * @param key host identity (unused)
2088  * @param value the blacklist entry
2089  * @return #GNUNET_OK (continue to iterate)
2090  */
2091 static int
2092 free_blacklist_entry(void *cls,
2093                      const struct GNUNET_PeerIdentity *key,
2094                      void *value)
2095 {
2096   char *be = value;
2097
2098   GNUNET_free_non_null(be);
2099   return GNUNET_OK;
2100 }
2101
2102
2103 /**
2104  * Set traffic metric to manipulate
2105  *
2106  * @param cls closure
2107  * @param message containing information
2108  */
2109 static void
2110 handle_client_set_metric(void *cls, const struct TrafficMetricMessage *tm)
2111 {
2112   struct TransportClient *tc = cls;
2113
2114   GST_manipulation_set_metric(tm);
2115   GNUNET_SERVICE_client_continue(tc->client);
2116 }
2117
2118
2119 /**
2120  * Function called when the service shuts down.  Unloads our plugins
2121  * and cancels pending validations.
2122  *
2123  * @param cls closure, unused
2124  */
2125 static void
2126 shutdown_task(void *cls)
2127 {
2128   struct AddressToStringContext *cur;
2129
2130   GST_neighbours_stop();
2131   GST_plugins_unload();
2132   GST_validation_stop();
2133   GST_ats_done();
2134   GNUNET_ATS_scheduling_done(GST_ats);
2135   GST_ats = NULL;
2136   GNUNET_ATS_connectivity_done(GST_ats_connect);
2137   GST_ats_connect = NULL;
2138   GNUNET_NT_scanner_done(GST_is);
2139   GST_is = NULL;
2140   while (NULL != (cur = a2s_head))
2141     {
2142       GNUNET_CONTAINER_DLL_remove(a2s_head, a2s_tail, cur);
2143       GNUNET_free(cur);
2144     }
2145   if (NULL != plugin_nc)
2146     {
2147       GNUNET_notification_context_destroy(plugin_nc);
2148       plugin_nc = NULL;
2149     }
2150   GNUNET_CONTAINER_multipeermap_destroy(active_stccs);
2151   active_stccs = NULL;
2152   if (NULL != blacklist)
2153     {
2154       GNUNET_CONTAINER_multipeermap_iterate(blacklist,
2155                                             &free_blacklist_entry,
2156                                             NULL);
2157       GNUNET_CONTAINER_multipeermap_destroy(blacklist);
2158       blacklist = NULL;
2159     }
2160   GST_hello_stop();
2161   GST_manipulation_stop();
2162
2163   if (NULL != GST_peerinfo)
2164     {
2165       GNUNET_PEERINFO_disconnect(GST_peerinfo);
2166       GST_peerinfo = NULL;
2167     }
2168   if (NULL != GST_stats)
2169     {
2170       GNUNET_STATISTICS_destroy(GST_stats, GNUNET_NO);
2171       GST_stats = NULL;
2172     }
2173   if (NULL != GST_my_private_key)
2174     {
2175       GNUNET_free(GST_my_private_key);
2176       GST_my_private_key = NULL;
2177     }
2178 }
2179
2180
2181 /**
2182  * Perform next action in the blacklist check.
2183  *
2184  * @param cls the `struct GST_BlacklistCheck *`
2185  */
2186 static void
2187 do_blacklist_check(void *cls)
2188 {
2189   struct GST_BlacklistCheck *bc = cls;
2190   struct TransportClient *tc;
2191   struct GNUNET_MQ_Envelope *env;
2192   struct BlacklistMessage *bm;
2193
2194   bc->task = NULL;
2195   while (NULL != (tc = bc->bl_pos))
2196     {
2197       if (CT_BLACKLIST == tc->type)
2198         break;
2199       bc->bl_pos = tc->next;
2200     }
2201   if (NULL == tc)
2202     {
2203       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2204                  "No other blacklist clients active, will allow neighbour `%s'\n",
2205                  GNUNET_i2s(&bc->peer));
2206
2207       bc->cont(bc->cont_cls, &bc->peer, bc->address, bc->session, GNUNET_OK);
2208       GST_blacklist_test_cancel(bc);
2209       return;
2210     }
2211   if ((NULL != tc->details.blacklist.bc) ||
2212       (GNUNET_NO != tc->details.blacklist.waiting_for_reply))
2213     return; /* someone else busy with this client */
2214   tc->details.blacklist.bc = bc;
2215   env = GNUNET_MQ_msg(bm, GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_QUERY);
2216   bm->is_allowed = htonl(0);
2217   bm->peer = bc->peer;
2218   GNUNET_MQ_send(tc->mq, env);
2219   if (GNUNET_YES == tc->details.blacklist.call_receive_done)
2220     {
2221       tc->details.blacklist.call_receive_done = GNUNET_NO;
2222       GNUNET_SERVICE_client_continue(tc->client);
2223     }
2224   tc->details.blacklist.waiting_for_reply = GNUNET_YES;
2225 }
2226
2227
2228 /**
2229  * A blacklisting client has sent us reply. Process it.
2230  *
2231  * @param cls the client
2232  * @param msg the blacklist-reply message that was sent
2233  */
2234 static void
2235 handle_client_blacklist_reply(void *cls, const struct BlacklistMessage *msg)
2236 {
2237   struct TransportClient *tc = cls;
2238   struct GST_BlacklistCheck *bc;
2239
2240   if (CT_BLACKLIST != tc->type)
2241     {
2242       GNUNET_break(0);
2243       GNUNET_SERVICE_client_drop(tc->client);
2244       return;
2245     }
2246   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2247              "Blacklist client %p sent reply for `%s'\n",
2248              tc,
2249              GNUNET_i2s(&msg->peer));
2250   bc = tc->details.blacklist.bc;
2251   tc->details.blacklist.bc = NULL;
2252   tc->details.blacklist.waiting_for_reply = GNUNET_NO;
2253   tc->details.blacklist.call_receive_done = GNUNET_YES;
2254   if (NULL != bc)
2255     {
2256       /* only run this if the blacklist check has not been
2257        * cancelled in the meantime... */
2258       GNUNET_assert(bc->bl_pos == tc);
2259       if (ntohl(msg->is_allowed) == GNUNET_SYSERR)
2260         {
2261           GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2262                      "Blacklist check failed, peer not allowed\n");
2263           /* For the duration of the continuation, make the ongoing
2264              check invisible (to avoid double-cancellation); then
2265              add it back again so we can re-use GST_blacklist_test_cancel() */
2266           GNUNET_CONTAINER_DLL_remove(bc_head, bc_tail, bc);
2267           bc->cont(bc->cont_cls, &bc->peer, bc->address, bc->session, GNUNET_NO);
2268           GNUNET_CONTAINER_DLL_insert(bc_head, bc_tail, bc);
2269           GST_blacklist_test_cancel(bc);
2270           tc->details.blacklist.call_receive_done = GNUNET_NO;
2271           GNUNET_SERVICE_client_continue(tc->client);
2272           return;
2273         }
2274       else
2275         {
2276           GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2277                      "Blacklist check succeeded, continuing with checks\n");
2278           tc->details.blacklist.call_receive_done = GNUNET_NO;
2279           GNUNET_SERVICE_client_continue(tc->client);
2280           bc->bl_pos = tc->next;
2281           bc->task = GNUNET_SCHEDULER_add_now(&do_blacklist_check, bc);
2282         }
2283     }
2284   /* check if any other blacklist checks are waiting for this blacklister */
2285   for (bc = bc_head; bc != NULL; bc = bc->next)
2286     if ((bc->bl_pos == tc) && (NULL == bc->task))
2287       {
2288         bc->task = GNUNET_SCHEDULER_add_now(&do_blacklist_check, bc);
2289         break;
2290       }
2291 }
2292
2293
2294 /**
2295  * Add the given peer to the blacklist (for the given transport).
2296  *
2297  * @param peer peer to blacklist
2298  * @param transport_name transport to blacklist for this peer, NULL for all
2299  */
2300 void
2301 GST_blacklist_add_peer(const struct GNUNET_PeerIdentity *peer,
2302                        const char *transport_name)
2303 {
2304   char *transport = NULL;
2305
2306   if (NULL != transport_name)
2307     {
2308       GNUNET_log(GNUNET_ERROR_TYPE_INFO,
2309                  "Adding peer `%s' with plugin `%s' to blacklist\n",
2310                  GNUNET_i2s(peer),
2311                  transport_name);
2312       transport = GNUNET_strdup(transport_name);
2313     }
2314   else
2315     GNUNET_log(GNUNET_ERROR_TYPE_INFO,
2316                "Adding peer `%s' with all plugins to blacklist\n",
2317                GNUNET_i2s(peer));
2318   if (NULL == blacklist)
2319     blacklist =
2320       GNUNET_CONTAINER_multipeermap_create(TRANSPORT_BLACKLIST_HT_SIZE,
2321                                            GNUNET_NO);
2322
2323   GNUNET_CONTAINER_multipeermap_put(blacklist,
2324                                     peer,
2325                                     transport,
2326                                     GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
2327 }
2328
2329
2330 /**
2331  * Abort blacklist if @a address and @a session match.
2332  *
2333  * @param address address used to abort matching checks
2334  * @param session session used to abort matching checks
2335  */
2336 void
2337 GST_blacklist_abort_matching(const struct GNUNET_HELLO_Address *address,
2338                              struct GNUNET_ATS_Session *session)
2339 {
2340   struct GST_BlacklistCheck *bc;
2341   struct GST_BlacklistCheck *n;
2342
2343   n = bc_head;
2344   while (NULL != (bc = n))
2345     {
2346       n = bc->next;
2347       if ((bc->session == session) &&
2348           (0 == GNUNET_HELLO_address_cmp(bc->address, address)))
2349         {
2350           bc->cont(bc->cont_cls,
2351                    &bc->peer,
2352                    bc->address,
2353                    bc->session,
2354                    GNUNET_SYSERR);
2355           GST_blacklist_test_cancel(bc);
2356         }
2357     }
2358 }
2359
2360
2361 /**
2362  * Test if the given blacklist entry matches.  If so,
2363  * abort the iteration.
2364  *
2365  * @param cls the transport name to match (const char*)
2366  * @param key the key (unused)
2367  * @param value the 'char *' (name of a blacklisted transport)
2368  * @return #GNUNET_OK if the entry does not match, #GNUNET_NO if it matches
2369  */
2370 static int
2371 test_blacklisted(void *cls, const struct GNUNET_PeerIdentity *key, void *value)
2372 {
2373   const char *transport_name = cls;
2374   char *be = value;
2375
2376   /* Blacklist entry be:
2377    *  (NULL == be): peer is blacklisted with all plugins
2378    *  (NULL != be): peer is blacklisted for a specific plugin
2379    *
2380    * If (NULL != transport_name) we look for a transport specific entry:
2381    *  if (transport_name == be) forbidden
2382    *
2383    */
2384
2385   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2386              "Comparing BL request for peer `%4s':`%s' with BL entry: `%s'\n",
2387              GNUNET_i2s(key),
2388              (NULL == transport_name) ? "unspecified" : transport_name,
2389              (NULL == be) ? "all plugins" : be);
2390   /* all plugins for this peer were blacklisted: disallow */
2391   if (NULL == value)
2392     return GNUNET_NO;
2393
2394   /* blacklist check for specific transport */
2395   if ((NULL != transport_name) && (NULL != value))
2396     {
2397       if (0 == strcmp(transport_name, be))
2398         return GNUNET_NO; /* plugin is blacklisted! */
2399     }
2400   return GNUNET_OK;
2401 }
2402
2403
2404 /**
2405  * Test if a peer/transport combination is blacklisted.
2406  *
2407  * @param peer the identity of the peer to test
2408  * @param transport_name name of the transport to test, never NULL
2409  * @param cont function to call with result
2410  * @param cont_cls closure for @a cont
2411  * @param address address to pass back to @a cont, can be NULL
2412  * @param session session to pass back to @a cont, can be NULL
2413  * @return handle to the blacklist check, NULL if the decision
2414  *        was made instantly and @a cont was already called
2415  */
2416 struct GST_BlacklistCheck *
2417 GST_blacklist_test_allowed(const struct GNUNET_PeerIdentity *peer,
2418                            const char *transport_name,
2419                            GST_BlacklistTestContinuation cont,
2420                            void *cont_cls,
2421                            const struct GNUNET_HELLO_Address *address,
2422                            struct GNUNET_ATS_Session *session)
2423 {
2424   struct GST_BlacklistCheck *bc;
2425   struct TransportClient *tc;
2426
2427   GNUNET_assert(NULL != peer);
2428   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2429              "Blacklist check for peer `%s':%s\n",
2430              GNUNET_i2s(peer),
2431              (NULL != transport_name) ? transport_name : "unspecified");
2432
2433   /* Check local blacklist by iterating over hashmap
2434    * If iteration is aborted, we found a matching blacklist entry */
2435   if ((NULL != blacklist) &&
2436       (GNUNET_SYSERR ==
2437        GNUNET_CONTAINER_multipeermap_get_multiple(blacklist,
2438                                                   peer,
2439                                                   &test_blacklisted,
2440                                                   (void *)transport_name)))
2441     {
2442       /* Disallowed by config, disapprove instantly */
2443       GNUNET_STATISTICS_update(GST_stats,
2444                                gettext_noop("# disconnects due to blacklist"),
2445                                1,
2446                                GNUNET_NO);
2447       GNUNET_log(GNUNET_ERROR_TYPE_INFO,
2448                  _("Disallowing connection to peer `%s' on transport %s\n"),
2449                  GNUNET_i2s(peer),
2450                  (NULL != transport_name) ? transport_name : "unspecified");
2451       if (NULL != cont)
2452         cont(cont_cls, peer, address, session, GNUNET_NO);
2453       return NULL;
2454     }
2455
2456   for (tc = clients_head; NULL != tc; tc = tc->next)
2457     if (CT_BLACKLIST == tc->type)
2458       break;
2459   if (NULL == tc)
2460     {
2461       /* no blacklist clients, approve instantly */
2462       if (NULL != cont)
2463         cont(cont_cls, peer, address, session, GNUNET_OK);
2464       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2465                  "Allowing connection to peer `%s' %s\n",
2466                  GNUNET_i2s(peer),
2467                  (NULL != transport_name) ? transport_name : "");
2468       return NULL;
2469     }
2470
2471   /* need to query blacklist clients */
2472   bc = GNUNET_new(struct GST_BlacklistCheck);
2473   GNUNET_CONTAINER_DLL_insert(bc_head, bc_tail, bc);
2474   bc->peer = *peer;
2475   bc->address = GNUNET_HELLO_address_copy(address);
2476   bc->session = session;
2477   bc->cont = cont;
2478   bc->cont_cls = cont_cls;
2479   bc->bl_pos = tc;
2480   bc->task = GNUNET_SCHEDULER_add_now(&do_blacklist_check, bc);
2481   return bc;
2482 }
2483
2484
2485 /**
2486  * Cancel a blacklist check.
2487  *
2488  * @param bc check to cancel
2489  */
2490 void
2491 GST_blacklist_test_cancel(struct GST_BlacklistCheck *bc)
2492 {
2493   GNUNET_CONTAINER_DLL_remove(bc_head, bc_tail, bc);
2494   if (NULL != bc->bl_pos)
2495     {
2496       if ((CT_BLACKLIST == bc->bl_pos->type) &&
2497           (bc->bl_pos->details.blacklist.bc == bc))
2498         {
2499           /* we're at the head of the queue, remove us! */
2500           bc->bl_pos->details.blacklist.bc = NULL;
2501         }
2502     }
2503   if (NULL != bc->task)
2504     {
2505       GNUNET_SCHEDULER_cancel(bc->task);
2506       bc->task = NULL;
2507     }
2508   GNUNET_free_non_null(bc->address);
2509   GNUNET_free(bc);
2510 }
2511
2512
2513 /**
2514  * Function to iterate over options in the blacklisting section for a peer.
2515  *
2516  * @param cls closure
2517  * @param section name of the section
2518  * @param option name of the option
2519  * @param value value of the option
2520  */
2521 static void
2522 blacklist_cfg_iter(void *cls,
2523                    const char *section,
2524                    const char *option,
2525                    const char *value)
2526 {
2527   unsigned int *res = cls;
2528   struct GNUNET_PeerIdentity peer;
2529   char *plugs;
2530   char *pos;
2531
2532   if (GNUNET_OK !=
2533       GNUNET_CRYPTO_eddsa_public_key_from_string(option,
2534                                                  strlen(option),
2535                                                  &peer.public_key))
2536     return;
2537
2538   if ((NULL == value) || (0 == strcmp(value, "")))
2539     {
2540       /* Blacklist whole peer */
2541       GST_blacklist_add_peer(&peer, NULL);
2542       GNUNET_log(GNUNET_ERROR_TYPE_INFO,
2543                  _("Adding blacklisting entry for peer `%s'\n"),
2544                  GNUNET_i2s(&peer));
2545     }
2546   else
2547     {
2548       plugs = GNUNET_strdup(value);
2549       for (pos = strtok(plugs, " "); pos != NULL; pos = strtok(NULL, " "))
2550         {
2551           GNUNET_log(GNUNET_ERROR_TYPE_INFO,
2552                      _("Adding blacklisting entry for peer `%s':`%s'\n"),
2553                      GNUNET_i2s(&peer),
2554                      pos);
2555           GST_blacklist_add_peer(&peer, pos);
2556         }
2557       GNUNET_free(plugs);
2558     }
2559   (*res)++;
2560 }
2561
2562
2563 /**
2564  * Read blacklist configuration
2565  *
2566  * @param cfg the configuration handle
2567  * @param my_id my peer identity
2568  */
2569 static void
2570 read_blacklist_configuration(const struct GNUNET_CONFIGURATION_Handle *cfg,
2571                              const struct GNUNET_PeerIdentity *my_id)
2572 {
2573   char cfg_sect[512];
2574   unsigned int res = 0;
2575
2576   GNUNET_snprintf(cfg_sect,
2577                   sizeof(cfg_sect),
2578                   "transport-blacklist-%s",
2579                   GNUNET_i2s_full(my_id));
2580   GNUNET_CONFIGURATION_iterate_section_values(cfg,
2581                                               cfg_sect,
2582                                               &blacklist_cfg_iter,
2583                                               &res);
2584   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2585              "Loaded %u blacklisting entries from configuration\n",
2586              res);
2587 }
2588
2589
2590 /**
2591  * Initiate transport service.
2592  *
2593  * @param cls closure
2594  * @param c configuration to use
2595  * @param service the initialized service
2596  */
2597 static void
2598 run(void *cls,
2599     const struct GNUNET_CONFIGURATION_Handle *c,
2600     struct GNUNET_SERVICE_Handle *service)
2601 {
2602   char *keyfile;
2603   struct GNUNET_CRYPTO_EddsaPrivateKey *pk;
2604   long long unsigned int max_fd_cfg;
2605   int max_fd_rlimit;
2606   int max_fd;
2607   int friend_only;
2608
2609   /* setup globals */
2610   GST_cfg = c;
2611   if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename(c,
2612                                                            "PEER",
2613                                                            "PRIVATE_KEY",
2614                                                            &keyfile))
2615     {
2616       GNUNET_log(
2617         GNUNET_ERROR_TYPE_ERROR,
2618         _(
2619           "Transport service is lacking key configuration settings. Exiting.\n"));
2620       GNUNET_SCHEDULER_shutdown();
2621       return;
2622     }
2623   if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_time(c,
2624                                                        "transport",
2625                                                        "HELLO_EXPIRATION",
2626                                                        &hello_expiration))
2627     {
2628       hello_expiration = GNUNET_CONSTANTS_HELLO_ADDRESS_EXPIRATION;
2629     }
2630   pk = GNUNET_CRYPTO_eddsa_key_create_from_file(keyfile);
2631   GNUNET_free(keyfile);
2632   GNUNET_assert(NULL != pk);
2633   GST_my_private_key = pk;
2634
2635   GST_stats = GNUNET_STATISTICS_create("transport", GST_cfg);
2636   GST_peerinfo = GNUNET_PEERINFO_connect(GST_cfg);
2637   GNUNET_CRYPTO_eddsa_key_get_public(GST_my_private_key,
2638                                      &GST_my_identity.public_key);
2639   GNUNET_assert(NULL != GST_my_private_key);
2640
2641   GNUNET_log(GNUNET_ERROR_TYPE_INFO,
2642              "My identity is `%s'\n",
2643              GNUNET_i2s_full(&GST_my_identity));
2644
2645   GNUNET_SCHEDULER_add_shutdown(&shutdown_task, NULL);
2646   if (NULL == GST_peerinfo)
2647     {
2648       GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
2649                  _("Could not access PEERINFO service.  Exiting.\n"));
2650       GNUNET_SCHEDULER_shutdown();
2651       return;
2652     }
2653
2654   max_fd_rlimit = 0;
2655 #if HAVE_GETRLIMIT
2656   {
2657     struct rlimit r_file;
2658
2659     if (0 == getrlimit(RLIMIT_NOFILE, &r_file))
2660       {
2661         max_fd_rlimit = r_file.rlim_cur;
2662         GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2663                    "Maximum number of open files was: %u/%u\n",
2664                    (unsigned int)r_file.rlim_cur,
2665                    (unsigned int)r_file.rlim_max);
2666       }
2667     max_fd_rlimit =
2668       (9 * max_fd_rlimit) / 10; /* Keep 10% for rest of transport */
2669   }
2670 #endif
2671   if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number(GST_cfg,
2672                                                          "transport",
2673                                                          "MAX_FD",
2674                                                          &max_fd_cfg))
2675     max_fd_cfg = max_fd_rlimit;
2676
2677   if (max_fd_cfg > max_fd_rlimit)
2678     max_fd = max_fd_cfg;
2679   else
2680     max_fd = max_fd_rlimit;
2681   if (max_fd < DEFAULT_MAX_FDS)
2682     max_fd = DEFAULT_MAX_FDS;
2683
2684   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2685              "Limiting number of sockets to %u: validation %u, neighbors: %u\n",
2686              max_fd,
2687              (max_fd / 3),
2688              (max_fd / 3) * 2);
2689
2690   friend_only =
2691     GNUNET_CONFIGURATION_get_value_yesno(GST_cfg, "topology", "FRIENDS-ONLY");
2692   if (GNUNET_SYSERR == friend_only)
2693     friend_only = GNUNET_NO; /* According to topology defaults */
2694   /* start subsystems */
2695   /* Disable DSTJ peer */
2696   {
2697     struct GNUNET_PeerIdentity dstj;
2698     const char *ds = "DSTJBRRKZ8TBW3FGK6B0M5QXWT9WYNZ45H5MCV4HY7ST64Q8T9F0";
2699
2700     GNUNET_assert(
2701       GNUNET_OK ==
2702       GNUNET_CRYPTO_eddsa_public_key_from_string(ds,
2703                                                  strlen(ds),
2704                                                  &dstj.public_key));
2705     GST_blacklist_add_peer(&dstj, NULL);
2706   }
2707   read_blacklist_configuration(GST_cfg, &GST_my_identity);
2708   GST_is = GNUNET_NT_scanner_init();
2709   GST_ats_connect = GNUNET_ATS_connectivity_init(GST_cfg);
2710   GST_ats =
2711     GNUNET_ATS_scheduling_init(GST_cfg, &ats_request_address_change, NULL);
2712   GST_ats_init();
2713   GST_manipulation_init();
2714   GST_plugins_load(&GST_manipulation_recv,
2715                    &plugin_env_address_change_notification,
2716                    &plugin_env_session_start,
2717                    &plugin_env_session_end);
2718   GST_hello_start(friend_only, &process_hello_update, NULL);
2719   GST_neighbours_start((max_fd / 3) * 2);
2720   active_stccs = GNUNET_CONTAINER_multipeermap_create(128, GNUNET_YES);
2721   plugin_nc = GNUNET_notification_context_create(0);
2722   GST_validation_start((max_fd / 3));
2723 }
2724
2725
2726 /**
2727  * Define "main" method using service macro.
2728  */
2729 GNUNET_SERVICE_MAIN(
2730   "transport",
2731   GNUNET_SERVICE_OPTION_NONE,
2732   &run,
2733   &client_connect_cb,
2734   &client_disconnect_cb,
2735   NULL,
2736   GNUNET_MQ_hd_fixed_size(client_start,
2737                           GNUNET_MESSAGE_TYPE_TRANSPORT_START,
2738                           struct StartMessage,
2739                           NULL),
2740   GNUNET_MQ_hd_var_size(client_hello,
2741                         GNUNET_MESSAGE_TYPE_HELLO,
2742                         struct GNUNET_MessageHeader,
2743                         NULL),
2744   GNUNET_MQ_hd_var_size(client_send,
2745                         GNUNET_MESSAGE_TYPE_TRANSPORT_SEND,
2746                         struct OutboundMessage,
2747                         NULL),
2748   GNUNET_MQ_hd_var_size(client_address_to_string,
2749                         GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_TO_STRING,
2750                         struct AddressLookupMessage,
2751                         NULL),
2752   GNUNET_MQ_hd_fixed_size(client_monitor_peers,
2753                           GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_PEER_REQUEST,
2754                           struct PeerMonitorMessage,
2755                           NULL),
2756   GNUNET_MQ_hd_fixed_size(client_blacklist_init,
2757                           GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_INIT,
2758                           struct GNUNET_MessageHeader,
2759                           NULL),
2760   GNUNET_MQ_hd_fixed_size(client_blacklist_reply,
2761                           GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_REPLY,
2762                           struct BlacklistMessage,
2763                           NULL),
2764   GNUNET_MQ_hd_fixed_size(client_set_metric,
2765                           GNUNET_MESSAGE_TYPE_TRANSPORT_TRAFFIC_METRIC,
2766                           struct TrafficMetricMessage,
2767                           NULL),
2768   GNUNET_MQ_hd_fixed_size(client_monitor_plugins,
2769                           GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_PLUGIN_START,
2770                           struct GNUNET_MessageHeader,
2771                           NULL),
2772   GNUNET_MQ_handler_end());
2773
2774
2775 /* end of file gnunet-service-transport.c */