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