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