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