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