79c70138f7d15cec8a0f1d360c14189899a9bb98
[oweals/gnunet.git] / src / transport / plugin_transport_tcp.c
1 /*
2   This file is part of GNUnet
3   Copyright (C) 2002--2015 GNUnet e.V.
4
5   GNUnet is free software; you can redistribute it and/or modify
6   it under the terms of the GNU General Public License as published
7   by the Free Software Foundation; either version 3, or (at your
8   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   General Public License for more details.
14
15   You should have received a copy of the GNU General Public License
16   along with GNUnet; see the file COPYING.  If not, write to the
17   Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18   Boston, MA 02110-1301, USA.
19  */
20 /**
21  * @file transport/plugin_transport_tcp.c
22  * @brief Implementation of the TCP transport service
23  * @author Christian Grothoff
24  */
25 #include "platform.h"
26 #include "gnunet_hello_lib.h"
27 #include "gnunet_constants.h"
28 #include "gnunet_util_lib.h"
29 #include "gnunet_nat_lib.h"
30 #include "gnunet_protocols.h"
31 #include "gnunet_resolver_service.h"
32 #include "gnunet_signatures.h"
33 #include "gnunet_statistics_service.h"
34 #include "gnunet_transport_service.h"
35 #include "gnunet_transport_plugin.h"
36 #include "transport.h"
37
38 #define LOG(kind,...) GNUNET_log_from (kind, "transport-tcp",__VA_ARGS__)
39
40 #define PLUGIN_NAME "tcp"
41
42 /**
43  * How long until we give up on establishing an NAT connection?
44  * Must be > 4 RTT
45  */
46 #define NAT_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10)
47
48 GNUNET_NETWORK_STRUCT_BEGIN
49
50
51 /**
52  * Initial handshake message for a session.
53  */
54 struct WelcomeMessage
55 {
56   /**
57    * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_WELCOME.
58    */
59   struct GNUNET_MessageHeader header;
60
61   /**
62    * Identity of the node connecting (TCP client)
63    */
64   struct GNUNET_PeerIdentity clientIdentity;
65
66 };
67
68 /**
69  * Basically a WELCOME message, but with the purpose
70  * of giving the waiting peer a client handle to use
71  */
72 struct TCP_NAT_ProbeMessage
73 {
74   /**
75    * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_NAT_PROBE.
76    */
77   struct GNUNET_MessageHeader header;
78
79   /**
80    * Identity of the sender of the message.
81    */
82   struct GNUNET_PeerIdentity clientIdentity;
83
84 };
85 GNUNET_NETWORK_STRUCT_END
86
87 /**
88  * Context for sending a NAT probe via TCP.
89  */
90 struct TCPProbeContext
91 {
92
93   /**
94    * Active probes are kept in a DLL.
95    */
96   struct TCPProbeContext *next;
97
98   /**
99    * Active probes are kept in a DLL.
100    */
101   struct TCPProbeContext *prev;
102
103   /**
104    * Probe connection.
105    */
106   struct GNUNET_CONNECTION_Handle *sock;
107
108   /**
109    * Message to be sent.
110    */
111   struct TCP_NAT_ProbeMessage message;
112
113   /**
114    * Handle to the transmission.
115    */
116   struct GNUNET_CONNECTION_TransmitHandle *transmit_handle;
117
118   /**
119    * Transport plugin handle.
120    */
121   struct Plugin *plugin;
122 };
123
124 /**
125  * Bits in the `options` field of TCP addresses.
126  */
127 enum TcpAddressOptions
128 {
129
130   /**
131    * No bits set.
132    */
133   TCP_OPTIONS_NONE = 0,
134
135   /**
136    * See #HTTP_OPTIONS_VERIFY_CERTIFICATE.
137    */
138   TCP_OPTIONS_RESERVED = 1,
139
140   /**
141    * Enable TCP Stealth-style port knocking.
142    */
143   TCP_OPTIONS_TCP_STEALTH = 2
144 };
145
146 GNUNET_NETWORK_STRUCT_BEGIN
147
148 /**
149  * Network format for IPv4 addresses.
150  */
151 struct IPv4TcpAddress
152 {
153   /**
154    * Optional options and flags for this address,
155    * see `enum TcpAddressOptions`
156    */
157   uint32_t options GNUNET_PACKED;
158
159   /**
160    * IPv4 address, in network byte order.
161    */
162   uint32_t ipv4_addr GNUNET_PACKED;
163
164   /**
165    * Port number, in network byte order.
166    */
167   uint16_t t4_port GNUNET_PACKED;
168
169 };
170
171 /**
172  * Network format for IPv6 addresses.
173  */
174 struct IPv6TcpAddress
175 {
176   /**
177    * Optional flags for this address
178    * see `enum TcpAddressOptions`
179    */
180   uint32_t options GNUNET_PACKED;
181
182   /**
183    * IPv6 address.
184    */
185   struct in6_addr ipv6_addr GNUNET_PACKED;
186
187   /**
188    * Port number, in network byte order.
189    */
190   uint16_t t6_port GNUNET_PACKED;
191
192 };
193 GNUNET_NETWORK_STRUCT_END
194
195 /**
196  * Encapsulation of all of the state of the plugin.
197  */
198 struct Plugin;
199
200 /**
201  * Information kept for each message that is yet to
202  * be transmitted.
203  */
204 struct PendingMessage
205 {
206
207   /**
208    * This is a doubly-linked list.
209    */
210   struct PendingMessage *next;
211
212   /**
213    * This is a doubly-linked list.
214    */
215   struct PendingMessage *prev;
216
217   /**
218    * The pending message
219    */
220   const char *msg;
221
222   /**
223    * Continuation function to call once the message
224    * has been sent.  Can be NULL if there is no
225    * continuation to call.
226    */
227   GNUNET_TRANSPORT_TransmitContinuation transmit_cont;
228
229   /**
230    * Closure for @e transmit_cont.
231    */
232   void *transmit_cont_cls;
233
234   /**
235    * Timeout value for the pending message.
236    */
237   struct GNUNET_TIME_Absolute timeout;
238
239   /**
240    * So that the gnunet-service-transport can group messages together,
241    * these pending messages need to accept a message buffer and size
242    * instead of just a `struct GNUNET_MessageHeader`.
243    */
244   size_t message_size;
245
246 };
247
248 /**
249  * Session handle for TCP connections.
250  */
251 struct GNUNET_ATS_Session
252 {
253   /**
254    * To whom are we talking to (set to our identity
255    * if we are still waiting for the welcome message)
256    */
257   struct GNUNET_PeerIdentity target;
258
259   /**
260    * Pointer to the global plugin struct.
261    */
262   struct Plugin *plugin;
263
264   /**
265    * The client (used to identify this connection)
266    */
267   struct GNUNET_SERVER_Client *client;
268
269   /**
270    * Task cleaning up a NAT client connection establishment attempt;
271    */
272   struct GNUNET_SCHEDULER_Task *nat_connection_timeout;
273
274   /**
275    * Messages currently pending for transmission
276    * to this peer, if any.
277    */
278   struct PendingMessage *pending_messages_head;
279
280   /**
281    * Messages currently pending for transmission
282    * to this peer, if any.
283    */
284   struct PendingMessage *pending_messages_tail;
285
286   /**
287    * Handle for pending transmission request.
288    */
289   struct GNUNET_SERVER_TransmitHandle *transmit_handle;
290
291   /**
292    * Address of the other peer.
293    */
294   struct GNUNET_HELLO_Address *address;
295
296   /**
297    * ID of task used to delay receiving more to throttle sender.
298    */
299   struct GNUNET_SCHEDULER_Task *receive_delay_task;
300
301   /**
302    * Session timeout task
303    */
304   struct GNUNET_SCHEDULER_Task *timeout_task;
305
306   /**
307    * When will this session time out?
308    */
309   struct GNUNET_TIME_Absolute timeout;
310
311   /**
312    * When will we continue to read from the socket?
313    * (used to enforce inbound quota).
314    */
315   struct GNUNET_TIME_Absolute receive_delay;
316
317   /**
318    * Last activity on this connection.  Used to select preferred
319    * connection.
320    */
321   struct GNUNET_TIME_Absolute last_activity;
322
323   /**
324    * Number of bytes waiting for transmission to this peer.
325    */
326   unsigned long long bytes_in_queue;
327
328   /**
329    * Number of messages waiting for transmission to this peer.
330    */
331   unsigned int msgs_in_queue;
332
333   /**
334    * Network type of the address.
335    */
336   enum GNUNET_ATS_Network_Type scope;
337
338   /**
339    * Are we still expecting the welcome message? (#GNUNET_YES/#GNUNET_NO)
340    */
341   int expecting_welcome;
342
343   /**
344    * Was this session created using NAT traversal?
345    */
346   int is_nat;
347
348 };
349
350
351 /**
352  * Context for address to string conversion, closure
353  * for #append_port().
354  */
355 struct PrettyPrinterContext
356 {
357   /**
358    * DLL
359    */
360   struct PrettyPrinterContext *next;
361
362   /**
363    * DLL
364    */
365   struct PrettyPrinterContext *prev;
366
367   /**
368    * Our plugin.
369    */
370   struct Plugin *plugin;
371
372   /**
373    * Timeout task
374    */
375   struct GNUNET_SCHEDULER_Task *timeout_task;
376
377   /**
378    * Resolver handle
379    */
380   struct GNUNET_RESOLVER_RequestHandle *resolver_handle;
381
382   /**
383    * Function to call with the result.
384    */
385   GNUNET_TRANSPORT_AddressStringCallback asc;
386
387   /**
388    * Clsoure for @e asc.
389    */
390   void *asc_cls;
391
392   /**
393    * IPv6 address
394    */
395   int ipv6;
396
397   /**
398    * Options
399    */
400   uint32_t options;
401
402   /**
403    * Port to add after the IP address.
404    */
405   uint16_t port;
406 };
407
408
409 /**
410  * Encapsulation of all of the state of the plugin.
411  */
412 struct Plugin
413 {
414   /**
415    * Our environment.
416    */
417   struct GNUNET_TRANSPORT_PluginEnvironment *env;
418
419   /**
420    * The listen socket.
421    */
422   struct GNUNET_CONNECTION_Handle *lsock;
423
424   /**
425    * Our handle to the NAT module.
426    */
427   struct GNUNET_NAT_Handle *nat;
428
429   /**
430    * Map from peer identities to sessions for the given peer.
431    */
432   struct GNUNET_CONTAINER_MultiPeerMap *sessionmap;
433
434   /**
435    * Handle to the network service.
436    */
437   struct GNUNET_SERVICE_Context *service;
438
439   /**
440    * Handle to the server for this service.
441    */
442   struct GNUNET_SERVER_Handle *server;
443
444   /**
445    * Copy of the handler array where the closures are
446    * set to this struct's instance.
447    */
448   struct GNUNET_SERVER_MessageHandler *handlers;
449
450   /**
451    * Map of peers we have tried to contact behind a NAT
452    */
453   struct GNUNET_CONTAINER_MultiPeerMap *nat_wait_conns;
454
455   /**
456    * List of active TCP probes.
457    */
458   struct TCPProbeContext *probe_head;
459
460   /**
461    * List of active TCP probes.
462    */
463   struct TCPProbeContext *probe_tail;
464
465   /**
466    * Function to call about session status changes.
467    */
468   GNUNET_TRANSPORT_SessionInfoCallback sic;
469
470   /**
471    * Closure for @e sic.
472    */
473   void *sic_cls;
474
475   /**
476    * ID of task used to update our addresses when one expires.
477    */
478   struct GNUNET_SCHEDULER_Task *address_update_task;
479
480   /**
481    * Running pretty printers: head
482    */
483   struct PrettyPrinterContext *ppc_dll_head;
484
485   /**
486    * Running pretty printers: tail
487    */
488   struct PrettyPrinterContext *ppc_dll_tail;
489
490   /**
491    * Welcome message used by this peer.
492    */
493   struct WelcomeMessage my_welcome;
494
495   /**
496    * How many more TCP sessions are we allowed to open right now?
497    */
498   unsigned long long max_connections;
499
500   /**
501    * How many more TCP sessions do we have right now?
502    */
503   unsigned long long cur_connections;
504
505   /**
506    * Address options
507    */
508   uint32_t myoptions;
509
510   /**
511    * Port that we are actually listening on.
512    */
513   uint16_t open_port;
514
515   /**
516    * Port that the user said we would have visible to the
517    * rest of the world.
518    */
519   uint16_t adv_port;
520
521 };
522
523
524 /* begin of ancient copy-and-pasted code that should be
525    specialized for TCP ...*/
526 /**
527  * Add the given UNIX domain path as an address to the
528  * list (as the first entry).
529  *
530  * @param saddrs array to update
531  * @param saddrlens where to store the address length
532  * @param unixpath path to add
533  * @param abstract #GNUNET_YES to add an abstract UNIX domain socket.  This
534  *          parameter is ignore on systems other than LINUX
535  */
536 static void
537 add_unixpath (struct sockaddr **saddrs,
538               socklen_t *saddrlens,
539               const char *unixpath,
540               int abstract)
541 {
542 #ifdef AF_UNIX
543   struct sockaddr_un *un;
544
545   un = GNUNET_new (struct sockaddr_un);
546   un->sun_family = AF_UNIX;
547   strncpy (un->sun_path, unixpath, sizeof (un->sun_path) - 1);
548 #ifdef LINUX
549   if (GNUNET_YES == abstract)
550     un->sun_path[0] = '\0';
551 #endif
552 #if HAVE_SOCKADDR_IN_SIN_LEN
553   un->sun_len = (u_char) sizeof (struct sockaddr_un);
554 #endif
555   *saddrs = (struct sockaddr *) un;
556   *saddrlens = sizeof (struct sockaddr_un);
557 #else
558   /* this function should never be called
559    * unless AF_UNIX is defined! */
560   GNUNET_assert (0);
561 #endif
562 }
563
564
565 /**
566  * Get the list of addresses that a server for the given service
567  * should bind to.
568  *
569  * @param service_name name of the service
570  * @param cfg configuration (which specifies the addresses)
571  * @param addrs set (call by reference) to an array of pointers to the
572  *              addresses the server should bind to and listen on; the
573  *              array will be NULL-terminated (on success)
574  * @param addr_lens set (call by reference) to an array of the lengths
575  *              of the respective `struct sockaddr` struct in the @a addrs
576  *              array (on success)
577  * @return number of addresses found on success,
578  *              #GNUNET_SYSERR if the configuration
579  *              did not specify reasonable finding information or
580  *              if it specified a hostname that could not be resolved;
581  *              #GNUNET_NO if the number of addresses configured is
582  *              zero (in this case, `*addrs` and `*addr_lens` will be
583  *              set to NULL).
584  */
585 static int
586 get_server_addresses (const char *service_name,
587                       const struct GNUNET_CONFIGURATION_Handle *cfg,
588                       struct sockaddr ***addrs,
589                       socklen_t ** addr_lens)
590 {
591   int disablev6;
592   struct GNUNET_NETWORK_Handle *desc;
593   unsigned long long port;
594   char *unixpath;
595   struct addrinfo hints;
596   struct addrinfo *res;
597   struct addrinfo *pos;
598   struct addrinfo *next;
599   unsigned int i;
600   int resi;
601   int ret;
602   int abstract;
603   struct sockaddr **saddrs;
604   socklen_t *saddrlens;
605   char *hostname;
606
607   *addrs = NULL;
608   *addr_lens = NULL;
609   desc = NULL;
610   if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "DISABLEV6"))
611   {
612     if (GNUNET_SYSERR ==
613         (disablev6 =
614          GNUNET_CONFIGURATION_get_value_yesno (cfg, service_name, "DISABLEV6")))
615       return GNUNET_SYSERR;
616   }
617   else
618     disablev6 = GNUNET_NO;
619
620   if (! disablev6)
621   {
622     /* probe IPv6 support */
623     desc = GNUNET_NETWORK_socket_create (PF_INET6, SOCK_STREAM, 0);
624     if (NULL == desc)
625     {
626       if ((ENOBUFS == errno) || (ENOMEM == errno) || (ENFILE == errno) ||
627           (EACCES == errno))
628       {
629         GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "socket");
630         return GNUNET_SYSERR;
631       }
632       LOG (GNUNET_ERROR_TYPE_INFO,
633            _("Disabling IPv6 support for service `%s', failed to create IPv6 socket: %s\n"),
634            service_name, STRERROR (errno));
635       disablev6 = GNUNET_YES;
636     }
637     else
638     {
639       GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (desc));
640       desc = NULL;
641     }
642   }
643
644   port = 0;
645   if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "PORT"))
646   {
647     if (GNUNET_OK !=
648         GNUNET_CONFIGURATION_get_value_number (cfg, service_name,
649                                                "PORT", &port))
650     {
651       LOG (GNUNET_ERROR_TYPE_ERROR,
652            _("Require valid port number for service `%s' in configuration!\n"),
653            service_name);
654     }
655     if (port > 65535)
656     {
657       LOG (GNUNET_ERROR_TYPE_ERROR,
658            _("Require valid port number for service `%s' in configuration!\n"),
659            service_name);
660       return GNUNET_SYSERR;
661     }
662   }
663
664   if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "BINDTO"))
665   {
666     GNUNET_break (GNUNET_OK ==
667                   GNUNET_CONFIGURATION_get_value_string (cfg, service_name,
668                                                          "BINDTO", &hostname));
669   }
670   else
671     hostname = NULL;
672
673   unixpath = NULL;
674   abstract = GNUNET_NO;
675 #ifdef AF_UNIX
676   if ((GNUNET_YES ==
677        GNUNET_CONFIGURATION_have_value (cfg, service_name, "UNIXPATH")) &&
678       (GNUNET_OK ==
679        GNUNET_CONFIGURATION_get_value_filename (cfg, service_name, "UNIXPATH",
680                                               &unixpath)) &&
681       (0 < strlen (unixpath)))
682   {
683     /* probe UNIX support */
684     struct sockaddr_un s_un;
685
686     if (strlen (unixpath) >= sizeof (s_un.sun_path))
687     {
688       LOG (GNUNET_ERROR_TYPE_WARNING,
689            _("UNIXPATH `%s' too long, maximum length is %llu\n"), unixpath,
690            (unsigned long long) sizeof (s_un.sun_path));
691       unixpath = GNUNET_NETWORK_shorten_unixpath (unixpath);
692       LOG (GNUNET_ERROR_TYPE_INFO,
693            _("Using `%s' instead\n"),
694            unixpath);
695     }
696 #ifdef LINUX
697     abstract = GNUNET_CONFIGURATION_get_value_yesno (cfg,
698                                                      "TESTING",
699                                                      "USE_ABSTRACT_SOCKETS");
700     if (GNUNET_SYSERR == abstract)
701       abstract = GNUNET_NO;
702 #endif
703     if ((GNUNET_YES != abstract)
704         && (GNUNET_OK !=
705             GNUNET_DISK_directory_create_for_file (unixpath)))
706       GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
707                                 "mkdir",
708                                 unixpath);
709   }
710   if (NULL != unixpath)
711   {
712     desc = GNUNET_NETWORK_socket_create (AF_UNIX, SOCK_STREAM, 0);
713     if (NULL == desc)
714     {
715       if ((ENOBUFS == errno) || (ENOMEM == errno) || (ENFILE == errno) ||
716           (EACCES == errno))
717       {
718         GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "socket");
719         GNUNET_free_non_null (hostname);
720         GNUNET_free (unixpath);
721         return GNUNET_SYSERR;
722       }
723       LOG (GNUNET_ERROR_TYPE_INFO,
724            _("Disabling UNIX domain socket support for service `%s', failed to create UNIX domain socket: %s\n"),
725            service_name,
726            STRERROR (errno));
727       GNUNET_free (unixpath);
728       unixpath = NULL;
729     }
730     else
731     {
732       GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (desc));
733       desc = NULL;
734     }
735   }
736 #endif
737
738   if ((0 == port) && (NULL == unixpath))
739   {
740     LOG (GNUNET_ERROR_TYPE_ERROR,
741          _("Have neither PORT nor UNIXPATH for service `%s', but one is required\n"),
742          service_name);
743     GNUNET_free_non_null (hostname);
744     return GNUNET_SYSERR;
745   }
746   if (0 == port)
747   {
748     saddrs = GNUNET_malloc (2 * sizeof (struct sockaddr *));
749     saddrlens = GNUNET_malloc (2 * sizeof (socklen_t));
750     add_unixpath (saddrs, saddrlens, unixpath, abstract);
751     GNUNET_free_non_null (unixpath);
752     GNUNET_free_non_null (hostname);
753     *addrs = saddrs;
754     *addr_lens = saddrlens;
755     return 1;
756   }
757
758   if (NULL != hostname)
759   {
760     LOG (GNUNET_ERROR_TYPE_DEBUG,
761          "Resolving `%s' since that is where `%s' will bind to.\n",
762          hostname,
763          service_name);
764     memset (&hints, 0, sizeof (struct addrinfo));
765     if (disablev6)
766       hints.ai_family = AF_INET;
767     hints.ai_protocol = IPPROTO_TCP;
768     if ((0 != (ret = getaddrinfo (hostname, NULL, &hints, &res))) ||
769         (NULL == res))
770     {
771       LOG (GNUNET_ERROR_TYPE_ERROR,
772            _("Failed to resolve `%s': %s\n"),
773            hostname,
774            gai_strerror (ret));
775       GNUNET_free (hostname);
776       GNUNET_free_non_null (unixpath);
777       return GNUNET_SYSERR;
778     }
779     next = res;
780     i = 0;
781     while (NULL != (pos = next))
782     {
783       next = pos->ai_next;
784       if ((disablev6) && (pos->ai_family == AF_INET6))
785         continue;
786       i++;
787     }
788     if (0 == i)
789     {
790       LOG (GNUNET_ERROR_TYPE_ERROR,
791            _("Failed to find %saddress for `%s'.\n"),
792            disablev6 ? "IPv4 " : "",
793            hostname);
794       freeaddrinfo (res);
795       GNUNET_free (hostname);
796       GNUNET_free_non_null (unixpath);
797       return GNUNET_SYSERR;
798     }
799     resi = i;
800     if (NULL != unixpath)
801       resi++;
802     saddrs = GNUNET_malloc ((resi + 1) * sizeof (struct sockaddr *));
803     saddrlens = GNUNET_malloc ((resi + 1) * sizeof (socklen_t));
804     i = 0;
805     if (NULL != unixpath)
806     {
807       add_unixpath (saddrs, saddrlens, unixpath, abstract);
808       i++;
809     }
810     next = res;
811     while (NULL != (pos = next))
812     {
813       next = pos->ai_next;
814       if ((disablev6) && (AF_INET6 == pos->ai_family))
815         continue;
816       if ((IPPROTO_TCP != pos->ai_protocol) && (0 != pos->ai_protocol))
817         continue;               /* not TCP */
818       if ((SOCK_STREAM != pos->ai_socktype) && (0 != pos->ai_socktype))
819         continue;               /* huh? */
820       LOG (GNUNET_ERROR_TYPE_DEBUG, "Service `%s' will bind to `%s'\n",
821            service_name, GNUNET_a2s (pos->ai_addr, pos->ai_addrlen));
822       if (AF_INET == pos->ai_family)
823       {
824         GNUNET_assert (sizeof (struct sockaddr_in) == pos->ai_addrlen);
825         saddrlens[i] = pos->ai_addrlen;
826         saddrs[i] = GNUNET_malloc (saddrlens[i]);
827         GNUNET_memcpy (saddrs[i], pos->ai_addr, saddrlens[i]);
828         ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
829       }
830       else
831       {
832         GNUNET_assert (AF_INET6 == pos->ai_family);
833         GNUNET_assert (sizeof (struct sockaddr_in6) == pos->ai_addrlen);
834         saddrlens[i] = pos->ai_addrlen;
835         saddrs[i] = GNUNET_malloc (saddrlens[i]);
836         GNUNET_memcpy (saddrs[i], pos->ai_addr, saddrlens[i]);
837         ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port);
838       }
839       i++;
840     }
841     GNUNET_free (hostname);
842     freeaddrinfo (res);
843     resi = i;
844   }
845   else
846   {
847     /* will bind against everything, just set port */
848     if (disablev6)
849     {
850       /* V4-only */
851       resi = 1;
852       if (NULL != unixpath)
853         resi++;
854       i = 0;
855       saddrs = GNUNET_malloc ((resi + 1) * sizeof (struct sockaddr *));
856       saddrlens = GNUNET_malloc ((resi + 1) * sizeof (socklen_t));
857       if (NULL != unixpath)
858       {
859         add_unixpath (saddrs, saddrlens, unixpath, abstract);
860         i++;
861       }
862       saddrlens[i] = sizeof (struct sockaddr_in);
863       saddrs[i] = GNUNET_malloc (saddrlens[i]);
864 #if HAVE_SOCKADDR_IN_SIN_LEN
865       ((struct sockaddr_in *) saddrs[i])->sin_len = saddrlens[i];
866 #endif
867       ((struct sockaddr_in *) saddrs[i])->sin_family = AF_INET;
868       ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
869     }
870     else
871     {
872       /* dual stack */
873       resi = 2;
874       if (NULL != unixpath)
875         resi++;
876       saddrs = GNUNET_malloc ((resi + 1) * sizeof (struct sockaddr *));
877       saddrlens = GNUNET_malloc ((resi + 1) * sizeof (socklen_t));
878       i = 0;
879       if (NULL != unixpath)
880       {
881         add_unixpath (saddrs, saddrlens, unixpath, abstract);
882         i++;
883       }
884       saddrlens[i] = sizeof (struct sockaddr_in6);
885       saddrs[i] = GNUNET_malloc (saddrlens[i]);
886 #if HAVE_SOCKADDR_IN_SIN_LEN
887       ((struct sockaddr_in6 *) saddrs[i])->sin6_len = saddrlens[0];
888 #endif
889       ((struct sockaddr_in6 *) saddrs[i])->sin6_family = AF_INET6;
890       ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port);
891       i++;
892       saddrlens[i] = sizeof (struct sockaddr_in);
893       saddrs[i] = GNUNET_malloc (saddrlens[i]);
894 #if HAVE_SOCKADDR_IN_SIN_LEN
895       ((struct sockaddr_in *) saddrs[i])->sin_len = saddrlens[1];
896 #endif
897       ((struct sockaddr_in *) saddrs[i])->sin_family = AF_INET;
898       ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
899     }
900   }
901   GNUNET_free_non_null (unixpath);
902   *addrs = saddrs;
903   *addr_lens = saddrlens;
904   return resi;
905 }
906 /* end ancient copy-and-paste */
907
908
909 /**
910  * If a session monitor is attached, notify it about the new
911  * session state.
912  *
913  * @param plugin our plugin
914  * @param session session that changed state
915  * @param state new state of the session
916  */
917 static void
918 notify_session_monitor (struct Plugin *plugin,
919                         struct GNUNET_ATS_Session *session,
920                         enum GNUNET_TRANSPORT_SessionState state)
921 {
922   struct GNUNET_TRANSPORT_SessionInfo info;
923
924   if (NULL == plugin->sic)
925     return;
926   memset (&info, 0, sizeof (info));
927   info.state = state;
928   info.is_inbound = GNUNET_HELLO_address_check_option (session->address,
929                                          GNUNET_HELLO_ADDRESS_INFO_INBOUND);
930   info.num_msg_pending = session->msgs_in_queue;
931   info.num_bytes_pending = session->bytes_in_queue;
932   if (NULL != session->receive_delay_task)
933     info.receive_delay = session->receive_delay;
934   info.session_timeout = session->timeout;
935   info.address = session->address;
936   plugin->sic (plugin->sic_cls,
937                session,
938                &info);
939 }
940
941
942 /**
943  * Our external IP address/port mapping has changed.
944  *
945  * @param cls closure, the `struct Plugin`
946  * @param add_remove #GNUNET_YES to mean the new public IP address, #GNUNET_NO to mean
947  *     the previous (now invalid) one
948  * @param addr either the previous or the new public IP address
949  * @param addrlen actual length of @a addr
950  */
951 static void
952 tcp_nat_port_map_callback (void *cls,
953                            int add_remove,
954                            const struct sockaddr *addr,
955                            socklen_t addrlen)
956 {
957   struct Plugin *plugin = cls;
958   struct GNUNET_HELLO_Address *address;
959   struct IPv4TcpAddress t4;
960   struct IPv6TcpAddress t6;
961   void *arg;
962   size_t args;
963
964   LOG(GNUNET_ERROR_TYPE_INFO,
965       "NAT notification to %s address `%s'\n",
966       (GNUNET_YES == add_remove) ? "add" : "remove",
967       GNUNET_a2s (addr, addrlen));
968   /* convert 'addr' to our internal format */
969   switch (addr->sa_family)
970   {
971   case AF_INET:
972     GNUNET_assert(addrlen == sizeof(struct sockaddr_in));
973     memset (&t4, 0, sizeof(t4));
974     t4.options = htonl (plugin->myoptions);
975     t4.ipv4_addr = ((struct sockaddr_in *) addr)->sin_addr.s_addr;
976     t4.t4_port = ((struct sockaddr_in *) addr)->sin_port;
977     arg = &t4;
978     args = sizeof (t4);
979     break;
980   case AF_INET6:
981     GNUNET_assert(addrlen == sizeof(struct sockaddr_in6));
982     memset (&t6, 0, sizeof(t6));
983     GNUNET_memcpy (&t6.ipv6_addr, &((struct sockaddr_in6 *) addr)->sin6_addr,
984         sizeof(struct in6_addr));
985     t6.options = htonl (plugin->myoptions);
986     t6.t6_port = ((struct sockaddr_in6 *) addr)->sin6_port;
987     arg = &t6;
988     args = sizeof (t6);
989     break;
990   default:
991     GNUNET_break(0);
992     return;
993   }
994   /* modify our published address list */
995   GNUNET_assert ((args == sizeof (struct IPv4TcpAddress)) ||
996       (args == sizeof (struct IPv6TcpAddress)));
997   address = GNUNET_HELLO_address_allocate (plugin->env->my_identity,
998       PLUGIN_NAME, arg, args, GNUNET_HELLO_ADDRESS_INFO_NONE);
999   plugin->env->notify_address (plugin->env->cls, add_remove, address);
1000   GNUNET_HELLO_address_free(address);
1001 }
1002
1003
1004 /**
1005  * Function called for a quick conversion of the binary address to
1006  * a numeric address.  Note that the caller must not free the
1007  * address and that the next call to this function is allowed
1008  * to override the address again.
1009  *
1010  * @param cls closure (`struct Plugin*`)
1011  * @param addr binary address
1012  * @param addrlen length of @a addr
1013  * @return string representing the same address
1014  */
1015 static const char *
1016 tcp_plugin_address_to_string (void *cls,
1017                               const void *addr,
1018                               size_t addrlen)
1019 {
1020   static char rbuf[INET6_ADDRSTRLEN + 12];
1021   char buf[INET6_ADDRSTRLEN];
1022   const void *sb;
1023   struct in_addr a4;
1024   struct in6_addr a6;
1025   const struct IPv4TcpAddress *t4;
1026   const struct IPv6TcpAddress *t6;
1027   int af;
1028   uint16_t port;
1029   uint32_t options;
1030
1031   switch (addrlen)
1032   {
1033   case sizeof(struct IPv6TcpAddress):
1034     t6 = addr;
1035     af = AF_INET6;
1036     port = ntohs (t6->t6_port);
1037     options = ntohl (t6->options);
1038     GNUNET_memcpy (&a6, &t6->ipv6_addr, sizeof(a6));
1039     sb = &a6;
1040     break;
1041   case sizeof(struct IPv4TcpAddress):
1042     t4 = addr;
1043     af = AF_INET;
1044     port = ntohs (t4->t4_port);
1045     options = ntohl (t4->options);
1046     GNUNET_memcpy (&a4, &t4->ipv4_addr, sizeof(a4));
1047     sb = &a4;
1048     break;
1049   default:
1050     LOG (GNUNET_ERROR_TYPE_WARNING,
1051          _("Unexpected address length: %u bytes\n"),
1052          (unsigned int) addrlen);
1053     return NULL ;
1054   }
1055   if (NULL == inet_ntop (af, sb, buf, INET6_ADDRSTRLEN))
1056   {
1057     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
1058                          "inet_ntop");
1059     return NULL ;
1060   }
1061   GNUNET_snprintf (rbuf, sizeof(rbuf),
1062                    (af == AF_INET6) ? "%s.%u.[%s]:%u" : "%s.%u.%s:%u",
1063                    PLUGIN_NAME,
1064                    options,
1065                    buf,
1066                    port);
1067   return rbuf;
1068 }
1069
1070
1071 /**
1072  * Function called to convert a string address to
1073  * a binary address.
1074  *
1075  * @param cls closure (`struct Plugin*`)
1076  * @param addr string address
1077  * @param addrlen length of the address
1078  * @param buf location to store the buffer
1079  * @param added location to store the number of bytes in the buffer.
1080  *        If the function returns #GNUNET_SYSERR, its contents are undefined.
1081  * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure
1082  */
1083 static int
1084 tcp_plugin_string_to_address (void *cls,
1085                               const char *addr,
1086                               uint16_t addrlen,
1087                               void **buf,
1088                               size_t *added)
1089 {
1090   struct sockaddr_storage socket_address;
1091   char *address;
1092   char *plugin;
1093   char *optionstr;
1094   uint32_t options;
1095
1096   /* Format tcp.options.address:port */
1097   address = NULL;
1098   plugin = NULL;
1099   optionstr = NULL;
1100   if ((NULL == addr) || (0 == addrlen))
1101   {
1102     GNUNET_break(0);
1103     return GNUNET_SYSERR;
1104   }
1105   if ('\0' != addr[addrlen - 1])
1106   {
1107     GNUNET_break(0);
1108     return GNUNET_SYSERR;
1109   }
1110   if (strlen (addr) != addrlen - 1)
1111   {
1112     GNUNET_break(0);
1113     return GNUNET_SYSERR;
1114   }
1115   plugin = GNUNET_strdup (addr);
1116   optionstr = strchr (plugin, '.');
1117   if (NULL == optionstr)
1118   {
1119     GNUNET_break(0);
1120     GNUNET_free(plugin);
1121     return GNUNET_SYSERR;
1122   }
1123   optionstr[0] = '\0';
1124   optionstr++;
1125   options = atol (optionstr);
1126   address = strchr (optionstr, '.');
1127   if (NULL == address)
1128   {
1129     GNUNET_break(0);
1130     GNUNET_free(plugin);
1131     return GNUNET_SYSERR;
1132   }
1133   address[0] = '\0';
1134   address++;
1135
1136   if (GNUNET_OK !=
1137       GNUNET_STRINGS_to_address_ip (address,
1138                                     strlen (address),
1139                                     &socket_address))
1140   {
1141     GNUNET_break(0);
1142     GNUNET_free(plugin);
1143     return GNUNET_SYSERR;
1144   }
1145
1146   GNUNET_free(plugin);
1147   switch (socket_address.ss_family)
1148   {
1149   case AF_INET:
1150   {
1151     struct IPv4TcpAddress *t4;
1152     struct sockaddr_in *in4 = (struct sockaddr_in *) &socket_address;
1153     t4 = GNUNET_new (struct IPv4TcpAddress);
1154     t4->options = htonl (options);
1155     t4->ipv4_addr = in4->sin_addr.s_addr;
1156     t4->t4_port = in4->sin_port;
1157     *buf = t4;
1158     *added = sizeof(struct IPv4TcpAddress);
1159     return GNUNET_OK;
1160   }
1161   case AF_INET6:
1162   {
1163     struct IPv6TcpAddress *t6;
1164     struct sockaddr_in6 *in6 = (struct sockaddr_in6 *) &socket_address;
1165     t6 = GNUNET_new (struct IPv6TcpAddress);
1166     t6->options = htonl (options);
1167     t6->ipv6_addr = in6->sin6_addr;
1168     t6->t6_port = in6->sin6_port;
1169     *buf = t6;
1170     *added = sizeof(struct IPv6TcpAddress);
1171     return GNUNET_OK;
1172   }
1173   default:
1174     return GNUNET_SYSERR;
1175   }
1176 }
1177
1178
1179 /**
1180  * Find the session handle for the given client.
1181  * Currently uses both the hashmap and the client
1182  * context, as the client context is new and the
1183  * logic still needs to be tested.
1184  *
1185  * @param plugin the plugin
1186  * @param client which client to find the session handle for
1187  * @return NULL if no matching session exists
1188  */
1189 static struct GNUNET_ATS_Session *
1190 lookup_session_by_client (struct Plugin *plugin,
1191                           struct GNUNET_SERVER_Client *client)
1192 {
1193   return GNUNET_SERVER_client_get_user_context (client,
1194                                                 struct GNUNET_ATS_Session);
1195 }
1196
1197
1198 /**
1199  * Functions with this signature are called whenever we need
1200  * to close a session due to a disconnect or failure to
1201  * establish a connection.
1202  *
1203  * @param cls the `struct Plugin`
1204  * @param session session to close down
1205  * @return #GNUNET_OK on success
1206  */
1207 static int
1208 tcp_plugin_disconnect_session (void *cls,
1209                                struct GNUNET_ATS_Session *session)
1210 {
1211   struct Plugin *plugin = cls;
1212   struct PendingMessage *pm;
1213
1214   LOG (GNUNET_ERROR_TYPE_DEBUG,
1215        "Disconnecting session of peer `%s' address `%s'\n",
1216        GNUNET_i2s (&session->target),
1217        tcp_plugin_address_to_string (session->plugin,
1218                                      session->address->address,
1219                                      session->address->address_length));
1220
1221   if (NULL != session->timeout_task)
1222   {
1223     GNUNET_SCHEDULER_cancel (session->timeout_task);
1224     session->timeout_task = NULL;
1225     session->timeout = GNUNET_TIME_UNIT_ZERO_ABS;
1226   }
1227
1228   if (GNUNET_YES ==
1229       GNUNET_CONTAINER_multipeermap_remove (plugin->sessionmap,
1230                                             &session->target,
1231                                             session))
1232   {
1233     GNUNET_STATISTICS_update (session->plugin->env->stats,
1234                               gettext_noop ("# TCP sessions active"),
1235                               -1,
1236                               GNUNET_NO);
1237   }
1238   else
1239   {
1240     GNUNET_assert (GNUNET_YES ==
1241                    GNUNET_CONTAINER_multipeermap_remove (plugin->nat_wait_conns,
1242                                                          &session->target,
1243                                                          session));
1244   }
1245   if (NULL != session->client)
1246     GNUNET_SERVER_client_set_user_context (session->client,
1247                                            NULL);
1248
1249   /* clean up state */
1250   if (NULL != session->transmit_handle)
1251   {
1252     GNUNET_SERVER_notify_transmit_ready_cancel (session->transmit_handle);
1253     session->transmit_handle = NULL;
1254   }
1255   session->plugin->env->session_end (session->plugin->env->cls,
1256                                      session->address,
1257                                      session);
1258
1259   if (NULL != session->nat_connection_timeout)
1260   {
1261     GNUNET_SCHEDULER_cancel (session->nat_connection_timeout);
1262     session->nat_connection_timeout = NULL;
1263   }
1264
1265   while (NULL != (pm = session->pending_messages_head))
1266   {
1267     LOG (GNUNET_ERROR_TYPE_DEBUG,
1268          (NULL != pm->transmit_cont)
1269          ? "Could not deliver message to `%s' at %s.\n"
1270          : "Could not deliver message to `%s' at %s, notifying.\n",
1271          GNUNET_i2s (&session->target),
1272          tcp_plugin_address_to_string (session->plugin,
1273                                        session->address->address,
1274                                        session->address->address_length));
1275     GNUNET_STATISTICS_update (session->plugin->env->stats,
1276                               gettext_noop ("# bytes currently in TCP buffers"),
1277                               -(int64_t) pm->message_size, GNUNET_NO);
1278     GNUNET_STATISTICS_update (session->plugin->env->stats,
1279                               gettext_noop ("# bytes discarded by TCP (disconnect)"),
1280                               pm->message_size,
1281                               GNUNET_NO);
1282     GNUNET_CONTAINER_DLL_remove (session->pending_messages_head,
1283                                  session->pending_messages_tail,
1284                                  pm);
1285     GNUNET_assert (0 < session->msgs_in_queue);
1286     session->msgs_in_queue--;
1287     GNUNET_assert (pm->message_size <= session->bytes_in_queue);
1288     session->bytes_in_queue -= pm->message_size;
1289     if (NULL != pm->transmit_cont)
1290       pm->transmit_cont (pm->transmit_cont_cls,
1291                          &session->target,
1292                          GNUNET_SYSERR,
1293                          pm->message_size,
1294                          0);
1295     GNUNET_free (pm);
1296   }
1297   GNUNET_assert (0 == session->msgs_in_queue);
1298   GNUNET_assert (0 == session->bytes_in_queue);
1299   notify_session_monitor (session->plugin,
1300                           session,
1301                           GNUNET_TRANSPORT_SS_DONE);
1302
1303   if (NULL != session->receive_delay_task)
1304   {
1305     GNUNET_SCHEDULER_cancel (session->receive_delay_task);
1306     session->receive_delay_task = NULL;
1307   }
1308   if (NULL != session->client)
1309   {
1310     GNUNET_SERVER_client_disconnect (session->client);
1311     session->client = NULL;
1312   }
1313   GNUNET_HELLO_address_free (session->address);
1314   GNUNET_assert (NULL == session->transmit_handle);
1315   GNUNET_free (session);
1316   return GNUNET_OK;
1317 }
1318
1319
1320 /**
1321  * Function that is called to get the keepalive factor.
1322  * #GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT is divided by this number to
1323  * calculate the interval between keepalive packets.
1324  *
1325  * @param cls closure with the `struct Plugin`
1326  * @return keepalive factor
1327  */
1328 static unsigned int
1329 tcp_plugin_query_keepalive_factor (void *cls)
1330 {
1331   return 3;
1332 }
1333
1334
1335 /**
1336  * Session was idle for too long, so disconnect it
1337  *
1338  * @param cls the `struct GNUNET_ATS_Session` of the idle session
1339  */
1340 static void
1341 session_timeout (void *cls)
1342 {
1343   struct GNUNET_ATS_Session *s = cls;
1344   struct GNUNET_TIME_Relative left;
1345
1346   s->timeout_task = NULL;
1347   left = GNUNET_TIME_absolute_get_remaining (s->timeout);
1348   if (0 != left.rel_value_us)
1349   {
1350     /* not actually our turn yet, but let's at least update
1351        the monitor, it may think we're about to die ... */
1352     notify_session_monitor (s->plugin,
1353                             s,
1354                             GNUNET_TRANSPORT_SS_UPDATE);
1355     s->timeout_task = GNUNET_SCHEDULER_add_delayed (left,
1356                                                     &session_timeout,
1357                                                     s);
1358     return;
1359   }
1360   LOG (GNUNET_ERROR_TYPE_DEBUG,
1361        "Session %p was idle for %s, disconnecting\n",
1362        s,
1363        GNUNET_STRINGS_relative_time_to_string (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
1364                                                GNUNET_YES));
1365   /* call session destroy function */
1366   tcp_plugin_disconnect_session (s->plugin,
1367                                  s);
1368 }
1369
1370
1371 /**
1372  * Increment session timeout due to activity.
1373  *
1374  * @param s session to increment timeout for
1375  */
1376 static void
1377 reschedule_session_timeout (struct GNUNET_ATS_Session *s)
1378 {
1379   GNUNET_assert (NULL != s->timeout_task);
1380   s->timeout = GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1381 }
1382
1383
1384 /**
1385  * Create a new session.  Also queues a welcome message.
1386  *
1387  * @param plugin the plugin
1388  * @param address the address to create the session for
1389  * @param scope network scope the address is from
1390  * @param client client to use, reference counter must have already been increased
1391  * @param is_nat this a NAT session, we should wait for a client to
1392  *               connect to us from an address, then assign that to
1393  *               the session
1394  * @return new session object
1395  */
1396 static struct GNUNET_ATS_Session *
1397 create_session (struct Plugin *plugin,
1398                 const struct GNUNET_HELLO_Address *address,
1399                 enum GNUNET_ATS_Network_Type scope,
1400                 struct GNUNET_SERVER_Client *client,
1401                 int is_nat)
1402 {
1403   struct GNUNET_ATS_Session *session;
1404   struct PendingMessage *pm;
1405
1406   if (GNUNET_YES != is_nat)
1407     GNUNET_assert (NULL != client);
1408   else
1409     GNUNET_assert (NULL == client);
1410
1411   LOG (GNUNET_ERROR_TYPE_DEBUG,
1412        "Creating new session for peer `%4s' at address %s\n",
1413        GNUNET_i2s (&address->peer),
1414        tcp_plugin_address_to_string (plugin,
1415                                      address->address,
1416                                      address->address_length));
1417   session = GNUNET_new (struct GNUNET_ATS_Session);
1418   session->last_activity = GNUNET_TIME_absolute_get ();
1419   session->plugin = plugin;
1420   session->is_nat = is_nat;
1421   if (NULL != client)
1422   {
1423     session->client = client;
1424     GNUNET_SERVER_client_set_user_context (client,
1425                                            session);
1426   }
1427   session->address = GNUNET_HELLO_address_copy (address);
1428   session->target = address->peer;
1429   session->expecting_welcome = GNUNET_YES;
1430   session->scope = scope;
1431   pm = GNUNET_malloc (sizeof (struct PendingMessage) +
1432                       sizeof (struct WelcomeMessage));
1433   pm->msg = (const char *) &pm[1];
1434   pm->message_size = sizeof(struct WelcomeMessage);
1435   GNUNET_memcpy (&pm[1],
1436           &plugin->my_welcome,
1437           sizeof(struct WelcomeMessage));
1438   pm->timeout = GNUNET_TIME_UNIT_FOREVER_ABS;
1439   GNUNET_STATISTICS_update (plugin->env->stats,
1440                             gettext_noop ("# bytes currently in TCP buffers"),
1441                             pm->message_size,
1442                             GNUNET_NO);
1443   GNUNET_CONTAINER_DLL_insert (session->pending_messages_head,
1444                                session->pending_messages_tail,
1445                                pm);
1446   session->msgs_in_queue++;
1447   session->bytes_in_queue += pm->message_size;
1448   session->timeout = GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1449   session->timeout_task = GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
1450                                                         &session_timeout,
1451                                                         session);
1452   notify_session_monitor (session->plugin,
1453                           session,
1454                           GNUNET_TRANSPORT_SS_INIT);
1455   if (GNUNET_YES != is_nat)
1456   {
1457     GNUNET_STATISTICS_update (plugin->env->stats,
1458                               gettext_noop ("# TCP sessions active"),
1459                               1,
1460                               GNUNET_NO);
1461     notify_session_monitor (session->plugin,
1462                             session,
1463                             GNUNET_TRANSPORT_SS_UP);
1464   }
1465   else
1466   {
1467     notify_session_monitor (session->plugin,
1468                             session,
1469                             GNUNET_TRANSPORT_SS_HANDSHAKE);
1470   }
1471   return session;
1472 }
1473
1474
1475 /**
1476  * If we have pending messages, ask the server to
1477  * transmit them (schedule the respective tasks, etc.)
1478  *
1479  * @param session for which session should we do this
1480  */
1481 static void
1482 process_pending_messages (struct GNUNET_ATS_Session *session);
1483
1484
1485 /**
1486  * Function called to notify a client about the socket
1487  * being ready to queue more data.  "buf" will be
1488  * NULL and "size" zero if the socket was closed for
1489  * writing in the meantime.
1490  *
1491  * @param cls closure
1492  * @param size number of bytes available in @a buf
1493  * @param buf where the callee should write the message
1494  * @return number of bytes written to @a buf
1495  */
1496 static size_t
1497 do_transmit (void *cls,
1498              size_t size,
1499              void *buf)
1500 {
1501   struct GNUNET_ATS_Session *session = cls;
1502   struct GNUNET_PeerIdentity pid;
1503   struct Plugin *plugin;
1504   struct PendingMessage *pos;
1505   struct PendingMessage *hd;
1506   struct PendingMessage *tl;
1507   struct GNUNET_TIME_Absolute now;
1508   char *cbuf;
1509   size_t ret;
1510
1511   session->transmit_handle = NULL;
1512   plugin = session->plugin;
1513   if (NULL == buf)
1514   {
1515     LOG (GNUNET_ERROR_TYPE_DEBUG,
1516          "Timeout trying to transmit to peer `%4s', discarding message queue.\n",
1517          GNUNET_i2s (&session->target));
1518     /* timeout; cancel all messages that have already expired */
1519     hd = NULL;
1520     tl = NULL;
1521     ret = 0;
1522     now = GNUNET_TIME_absolute_get ();
1523     while ( (NULL != (pos = session->pending_messages_head)) &&
1524             (pos->timeout.abs_value_us <= now.abs_value_us) )
1525     {
1526       GNUNET_CONTAINER_DLL_remove (session->pending_messages_head,
1527                                    session->pending_messages_tail,
1528                                    pos);
1529       GNUNET_assert (0 < session->msgs_in_queue);
1530       session->msgs_in_queue--;
1531       GNUNET_assert (pos->message_size <= session->bytes_in_queue);
1532       session->bytes_in_queue -= pos->message_size;
1533       LOG (GNUNET_ERROR_TYPE_DEBUG,
1534            "Failed to transmit %u byte message to `%4s'.\n",
1535            pos->message_size,
1536            GNUNET_i2s (&session->target));
1537       ret += pos->message_size;
1538       GNUNET_CONTAINER_DLL_insert_after (hd,
1539                                          tl,
1540                                          tl,
1541                                          pos);
1542     }
1543     /* do this call before callbacks (so that if callbacks destroy
1544      * session, they have a chance to cancel actions done by this
1545      * call) */
1546     process_pending_messages (session);
1547     pid = session->target;
1548     /* no do callbacks and do not use session again since
1549      * the callbacks may abort the session */
1550     while (NULL != (pos = hd))
1551     {
1552       GNUNET_CONTAINER_DLL_remove (hd,
1553                                    tl,
1554                                    pos);
1555       if (NULL != pos->transmit_cont)
1556         pos->transmit_cont (pos->transmit_cont_cls,
1557                             &pid,
1558                             GNUNET_SYSERR,
1559                             pos->message_size,
1560                             0);
1561       GNUNET_free (pos);
1562     }
1563     GNUNET_STATISTICS_update (plugin->env->stats,
1564                               gettext_noop ("# bytes currently in TCP buffers"), -(int64_t) ret,
1565                               GNUNET_NO);
1566     GNUNET_STATISTICS_update (plugin->env->stats,
1567                               gettext_noop ("# bytes discarded by TCP (timeout)"),
1568                               ret,
1569                               GNUNET_NO);
1570     if (0 < ret)
1571       notify_session_monitor (session->plugin,
1572                               session,
1573                               GNUNET_TRANSPORT_SS_UPDATE);
1574     return 0;
1575   }
1576   /* copy all pending messages that would fit */
1577   ret = 0;
1578   cbuf = buf;
1579   hd = NULL;
1580   tl = NULL;
1581   while (NULL != (pos = session->pending_messages_head))
1582   {
1583     if (ret + pos->message_size > size)
1584       break;
1585     GNUNET_CONTAINER_DLL_remove (session->pending_messages_head,
1586                                  session->pending_messages_tail,
1587                                  pos);
1588     GNUNET_assert (0 < session->msgs_in_queue);
1589     session->msgs_in_queue--;
1590     GNUNET_assert (pos->message_size <= session->bytes_in_queue);
1591     session->bytes_in_queue -= pos->message_size;
1592     GNUNET_assert(size >= pos->message_size);
1593     LOG (GNUNET_ERROR_TYPE_DEBUG,
1594          "Transmitting message of type %u size %u to peer %s at %s\n",
1595          ntohs (((struct GNUNET_MessageHeader *) pos->msg)->type),
1596          pos->message_size,
1597          GNUNET_i2s (&session->target),
1598          tcp_plugin_address_to_string (session->plugin,
1599                                        session->address->address,
1600                                        session->address->address_length));
1601     /* FIXME: this GNUNET_memcpy can be up to 7% of our total runtime */
1602     GNUNET_memcpy (cbuf,
1603             pos->msg,
1604             pos->message_size);
1605     cbuf += pos->message_size;
1606     ret += pos->message_size;
1607     size -= pos->message_size;
1608     GNUNET_CONTAINER_DLL_insert_tail (hd,
1609                                       tl,
1610                                       pos);
1611   }
1612   notify_session_monitor (session->plugin,
1613                           session,
1614                           GNUNET_TRANSPORT_SS_UPDATE);
1615   /* schedule 'continuation' before callbacks so that callbacks that
1616    * cancel everything don't cause us to use a session that no longer
1617    * exists... */
1618   process_pending_messages (session);
1619   session->last_activity = GNUNET_TIME_absolute_get ();
1620   pid = session->target;
1621   /* we'll now call callbacks that may cancel the session; hence
1622    * we should not use 'session' after this point */
1623   while (NULL != (pos = hd))
1624   {
1625     GNUNET_CONTAINER_DLL_remove (hd, tl, pos);
1626     if (NULL != pos->transmit_cont)
1627       pos->transmit_cont (pos->transmit_cont_cls,
1628                           &pid,
1629                           GNUNET_OK,
1630                           pos->message_size,
1631                           pos->message_size); /* FIXME: include TCP overhead */
1632     GNUNET_free (pos);
1633   }
1634   GNUNET_assert (NULL == hd);
1635   GNUNET_assert (NULL == tl);
1636   GNUNET_STATISTICS_update (plugin->env->stats,
1637                             gettext_noop ("# bytes currently in TCP buffers"),
1638                             - (int64_t) ret,
1639                             GNUNET_NO);
1640   GNUNET_STATISTICS_update (plugin->env->stats,
1641                             gettext_noop ("# bytes transmitted via TCP"),
1642                             ret,
1643                             GNUNET_NO);
1644   return ret;
1645 }
1646
1647
1648 /**
1649  * If we have pending messages, ask the server to
1650  * transmit them (schedule the respective tasks, etc.)
1651  *
1652  * @param session for which session should we do this
1653  */
1654 static void
1655 process_pending_messages (struct GNUNET_ATS_Session *session)
1656 {
1657   struct PendingMessage *pm;
1658
1659   GNUNET_assert (NULL != session->client);
1660   if (NULL != session->transmit_handle)
1661     return;
1662   if (NULL == (pm = session->pending_messages_head))
1663     return;
1664
1665   session->transmit_handle
1666     = GNUNET_SERVER_notify_transmit_ready (session->client,
1667                                            pm->message_size,
1668                                            GNUNET_TIME_absolute_get_remaining (pm->timeout),
1669                                            &do_transmit,
1670                                            session);
1671 }
1672
1673
1674 /**
1675  * Function that can be used by the transport service to transmit
1676  * a message using the plugin.   Note that in the case of a
1677  * peer disconnecting, the continuation MUST be called
1678  * prior to the disconnect notification itself.  This function
1679  * will be called with this peer's HELLO message to initiate
1680  * a fresh connection to another peer.
1681  *
1682  * @param cls closure
1683  * @param session which session must be used
1684  * @param msgbuf the message to transmit
1685  * @param msgbuf_size number of bytes in @a msgbuf
1686  * @param priority how important is the message (most plugins will
1687  *                 ignore message priority and just FIFO)
1688  * @param to how long to wait at most for the transmission (does not
1689  *                require plugins to discard the message after the timeout,
1690  *                just advisory for the desired delay; most plugins will ignore
1691  *                this as well)
1692  * @param cont continuation to call once the message has
1693  *        been transmitted (or if the transport is ready
1694  *        for the next transmission call; or if the
1695  *        peer disconnected...); can be NULL
1696  * @param cont_cls closure for @a cont
1697  * @return number of bytes used (on the physical network, with overheads);
1698  *         -1 on hard errors (i.e. address invalid); 0 is a legal value
1699  *         and does NOT mean that the message was not transmitted (DV)
1700  */
1701 static ssize_t
1702 tcp_plugin_send (void *cls,
1703                  struct GNUNET_ATS_Session *session,
1704                  const char *msgbuf,
1705                  size_t msgbuf_size,
1706                  unsigned int priority,
1707                  struct GNUNET_TIME_Relative to,
1708                  GNUNET_TRANSPORT_TransmitContinuation cont,
1709                  void *cont_cls)
1710 {
1711   struct Plugin * plugin = cls;
1712   struct PendingMessage *pm;
1713
1714   /* create new message entry */
1715   pm = GNUNET_malloc (sizeof (struct PendingMessage) + msgbuf_size);
1716   pm->msg = (const char *) &pm[1];
1717   GNUNET_memcpy (&pm[1], msgbuf, msgbuf_size);
1718   pm->message_size = msgbuf_size;
1719   pm->timeout = GNUNET_TIME_relative_to_absolute (to);
1720   pm->transmit_cont = cont;
1721   pm->transmit_cont_cls = cont_cls;
1722
1723   LOG(GNUNET_ERROR_TYPE_DEBUG,
1724       "Asked to transmit %u bytes to `%s', added message to list.\n",
1725       msgbuf_size,
1726       GNUNET_i2s (&session->target));
1727
1728   if (GNUNET_YES ==
1729       GNUNET_CONTAINER_multipeermap_contains_value (plugin->sessionmap,
1730                                                     &session->target,
1731                                                     session))
1732   {
1733     GNUNET_assert (NULL != session->client);
1734     GNUNET_SERVER_client_set_timeout (session->client,
1735                                       GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1736     GNUNET_STATISTICS_update (plugin->env->stats,
1737                               gettext_noop ("# bytes currently in TCP buffers"),
1738                               msgbuf_size,
1739                               GNUNET_NO);
1740
1741     /* append pm to pending_messages list */
1742     GNUNET_CONTAINER_DLL_insert_tail (session->pending_messages_head,
1743                                       session->pending_messages_tail,
1744                                       pm);
1745     notify_session_monitor (session->plugin,
1746                             session,
1747                             GNUNET_TRANSPORT_SS_UPDATE);
1748     session->msgs_in_queue++;
1749     session->bytes_in_queue += pm->message_size;
1750     process_pending_messages (session);
1751     return msgbuf_size;
1752   }
1753   if (GNUNET_YES ==
1754       GNUNET_CONTAINER_multipeermap_contains_value (plugin->nat_wait_conns,
1755                                                     &session->target,
1756                                                     session))
1757   {
1758     LOG (GNUNET_ERROR_TYPE_DEBUG,
1759          "This NAT WAIT session for peer `%s' is not yet ready!\n",
1760          GNUNET_i2s (&session->target));
1761     GNUNET_STATISTICS_update (plugin->env->stats,
1762                               gettext_noop ("# bytes currently in TCP buffers"), msgbuf_size,
1763                               GNUNET_NO);
1764     /* append pm to pending_messages list */
1765     GNUNET_CONTAINER_DLL_insert_tail (session->pending_messages_head,
1766                                       session->pending_messages_tail,
1767                                       pm);
1768     session->msgs_in_queue++;
1769     session->bytes_in_queue += pm->message_size;
1770     notify_session_monitor (session->plugin,
1771                             session,
1772                             GNUNET_TRANSPORT_SS_HANDSHAKE);
1773     return msgbuf_size;
1774   }
1775   LOG (GNUNET_ERROR_TYPE_ERROR,
1776        "Invalid session %p\n",
1777        session);
1778   if (NULL != cont)
1779     cont (cont_cls,
1780           &session->target,
1781           GNUNET_SYSERR,
1782           pm->message_size,
1783           0);
1784   GNUNET_break (0);
1785   GNUNET_free (pm);
1786   return GNUNET_SYSERR; /* session does not exist here */
1787 }
1788
1789
1790 /**
1791  * Closure for #session_lookup_it().
1792  */
1793 struct GNUNET_ATS_SessionItCtx
1794 {
1795   /**
1796    * Address we are looking for.
1797    */
1798   const struct GNUNET_HELLO_Address *address;
1799
1800   /**
1801    * Where to store the session (if we found it).
1802    */
1803   struct GNUNET_ATS_Session *result;
1804
1805 };
1806
1807
1808 /**
1809  * Look for a session by address.
1810  *
1811  * @param cls the `struct GNUNET_ATS_SessionItCtx`
1812  * @param key unused
1813  * @param value a `struct GNUNET_ATS_Session`
1814  * @return #GNUNET_YES to continue looking, #GNUNET_NO if we found the session
1815  */
1816 static int
1817 session_lookup_it (void *cls,
1818                    const struct GNUNET_PeerIdentity *key,
1819                    void *value)
1820 {
1821   struct GNUNET_ATS_SessionItCtx *si_ctx = cls;
1822   struct GNUNET_ATS_Session *session = value;
1823
1824   if (0 !=
1825       GNUNET_HELLO_address_cmp (si_ctx->address,
1826                                 session->address))
1827     return GNUNET_YES;
1828   si_ctx->result = session;
1829   return GNUNET_NO;
1830 }
1831
1832
1833 /**
1834  * Task cleaning up a NAT connection attempt after timeout
1835  *
1836  * @param cls the `struct GNUNET_ATS_Session`
1837  */
1838 static void
1839 nat_connect_timeout (void *cls)
1840 {
1841   struct GNUNET_ATS_Session *session = cls;
1842
1843   session->nat_connection_timeout = NULL;
1844   LOG (GNUNET_ERROR_TYPE_DEBUG,
1845        "NAT WAIT connection to `%4s' at `%s' could not be established, removing session\n",
1846        GNUNET_i2s (&session->target),
1847        tcp_plugin_address_to_string (session->plugin,
1848                                      session->address->address,
1849                                      session->address->address_length));
1850   tcp_plugin_disconnect_session (session->plugin,
1851                                  session);
1852 }
1853
1854
1855 /**
1856  * Function that will be called whenever the transport service wants to
1857  * notify the plugin that a session is still active and in use and
1858  * therefore the session timeout for this session has to be updated
1859  *
1860  * @param cls closure
1861  * @param peer which peer was the session for
1862  * @param session which session is being updated
1863  */
1864 static void
1865 tcp_plugin_update_session_timeout (void *cls,
1866                                    const struct GNUNET_PeerIdentity *peer,
1867                                    struct GNUNET_ATS_Session *session)
1868 {
1869   reschedule_session_timeout (session);
1870 }
1871
1872
1873 /**
1874  * Task to signal the server that we can continue
1875  * receiving from the TCP client now.
1876  *
1877  * @param cls the `struct GNUNET_ATS_Session *`
1878  */
1879 static void
1880 delayed_done (void *cls)
1881 {
1882   struct GNUNET_ATS_Session *session = cls;
1883
1884   session->receive_delay_task = NULL;
1885   reschedule_session_timeout (session);
1886   GNUNET_SERVER_receive_done (session->client,
1887                               GNUNET_OK);
1888 }
1889
1890
1891 /**
1892  * Function that will be called whenever the transport service wants to
1893  * notify the plugin that the inbound quota changed and that the plugin
1894  * should update it's delay for the next receive value
1895  *
1896  * @param cls closure
1897  * @param peer which peer was the session for
1898  * @param session which session is being updated
1899  * @param delay new delay to use for receiving
1900  */
1901 static void
1902 tcp_plugin_update_inbound_delay (void *cls,
1903                                  const struct GNUNET_PeerIdentity *peer,
1904                                  struct GNUNET_ATS_Session *session,
1905                                  struct GNUNET_TIME_Relative delay)
1906 {
1907   if (NULL == session->receive_delay_task)
1908     return;
1909   LOG (GNUNET_ERROR_TYPE_DEBUG,
1910        "New inbound delay %s\n",
1911        GNUNET_STRINGS_relative_time_to_string (delay,
1912                                                GNUNET_NO));
1913   session->receive_delay = GNUNET_TIME_relative_to_absolute (delay);
1914   GNUNET_SCHEDULER_cancel (session->receive_delay_task);
1915   session->receive_delay_task = GNUNET_SCHEDULER_add_delayed (delay,
1916                                                               &delayed_done,
1917                                                               session);
1918 }
1919
1920
1921 /**
1922  * Create a new session to transmit data to the target
1923  * This session will used to send data to this peer and the plugin will
1924  * notify us by calling the env->session_end function
1925  *
1926  * @param cls closure
1927  * @param address the address to use
1928  * @return the session if the address is valid, NULL otherwise
1929  */
1930 static struct GNUNET_ATS_Session *
1931 tcp_plugin_get_session (void *cls,
1932                         const struct GNUNET_HELLO_Address *address)
1933 {
1934   struct Plugin *plugin = cls;
1935   struct GNUNET_ATS_Session *session = NULL;
1936   int af;
1937   const void *sb;
1938   size_t sbs;
1939   struct GNUNET_CONNECTION_Handle *sa;
1940   struct sockaddr_in a4;
1941   struct sockaddr_in6 a6;
1942   const struct IPv4TcpAddress *t4;
1943   const struct IPv6TcpAddress *t6;
1944   unsigned int options;
1945   enum GNUNET_ATS_Network_Type net_type;
1946   unsigned int is_natd = GNUNET_NO;
1947   size_t addrlen;
1948 #ifdef TCP_STEALTH
1949   struct GNUNET_NETWORK_Handle *s;
1950 #endif
1951
1952   addrlen = address->address_length;
1953   LOG (GNUNET_ERROR_TYPE_DEBUG,
1954        "Trying to get session for `%s' address of peer `%s'\n",
1955        tcp_plugin_address_to_string (plugin,
1956                                      address->address,
1957                                      address->address_length),
1958        GNUNET_i2s (&address->peer));
1959
1960   if (GNUNET_HELLO_address_check_option (address,
1961                                          GNUNET_HELLO_ADDRESS_INFO_INBOUND))
1962   {
1963     GNUNET_break (0);
1964     return NULL;
1965   }
1966
1967   /* look for existing session */
1968   if (GNUNET_YES ==
1969       GNUNET_CONTAINER_multipeermap_contains (plugin->sessionmap,
1970                                               &address->peer))
1971   {
1972     struct GNUNET_ATS_SessionItCtx si_ctx;
1973
1974     si_ctx.address = address;
1975     si_ctx.result = NULL;
1976     GNUNET_CONTAINER_multipeermap_get_multiple (plugin->sessionmap,
1977                                                 &address->peer,
1978                                                 &session_lookup_it,
1979                                                 &si_ctx);
1980     if (NULL != si_ctx.result)
1981     {
1982       session = si_ctx.result;
1983       LOG (GNUNET_ERROR_TYPE_DEBUG,
1984            "Found existing session for `%s' address `%s'\n",
1985            GNUNET_i2s (&address->peer),
1986            tcp_plugin_address_to_string (plugin,
1987                                          address->address,
1988                                          address->address_length));
1989       return session;
1990     }
1991   }
1992
1993   if (addrlen == sizeof(struct IPv6TcpAddress))
1994   {
1995     GNUNET_assert (NULL != address->address); /* make static analysis happy */
1996     t6 = address->address;
1997     options = t6->options;
1998     af = AF_INET6;
1999     memset (&a6, 0, sizeof(a6));
2000 #if HAVE_SOCKADDR_IN_SIN_LEN
2001     a6.sin6_len = sizeof (a6);
2002 #endif
2003     a6.sin6_family = AF_INET6;
2004     a6.sin6_port = t6->t6_port;
2005     if (t6->t6_port == 0)
2006       is_natd = GNUNET_YES;
2007     GNUNET_memcpy (&a6.sin6_addr, &t6->ipv6_addr, sizeof(struct in6_addr));
2008     sb = &a6;
2009     sbs = sizeof(a6);
2010   }
2011   else if (addrlen == sizeof(struct IPv4TcpAddress))
2012   {
2013     GNUNET_assert(NULL != address->address); /* make static analysis happy */
2014     t4 = address->address;
2015     options = t4->options;
2016     af = AF_INET;
2017     memset (&a4, 0, sizeof(a4));
2018 #if HAVE_SOCKADDR_IN_SIN_LEN
2019     a4.sin_len = sizeof (a4);
2020 #endif
2021     a4.sin_family = AF_INET;
2022     a4.sin_port = t4->t4_port;
2023     if (t4->t4_port == 0)
2024       is_natd = GNUNET_YES;
2025     a4.sin_addr.s_addr = t4->ipv4_addr;
2026     sb = &a4;
2027     sbs = sizeof(a4);
2028   }
2029   else
2030   {
2031     GNUNET_STATISTICS_update (plugin->env->stats,
2032                               gettext_noop ("# requests to create session with invalid address"),
2033                               1,
2034                               GNUNET_NO);
2035     return NULL;
2036   }
2037
2038   net_type = plugin->env->get_address_type (plugin->env->cls,
2039                                             sb,
2040                                             sbs);
2041   GNUNET_break (net_type != GNUNET_ATS_NET_UNSPECIFIED);
2042
2043   if ( (is_natd == GNUNET_YES) &&
2044        (addrlen == sizeof(struct IPv6TcpAddress)) )
2045   {
2046     /* NAT client only works with IPv4 addresses */
2047     return NULL;
2048   }
2049
2050   if (plugin->cur_connections >= plugin->max_connections)
2051   {
2052     /* saturated */
2053     return NULL;
2054   }
2055
2056   if ( (is_natd == GNUNET_YES) &&
2057        (GNUNET_YES ==
2058         GNUNET_CONTAINER_multipeermap_contains (plugin->nat_wait_conns,
2059                                                 &address->peer)))
2060   {
2061     /* Only do one NAT punch attempt per peer identity */
2062     return NULL;
2063   }
2064
2065   if ( (is_natd == GNUNET_YES) &&
2066        (NULL != plugin->nat) &&
2067        (GNUNET_NO ==
2068         GNUNET_CONTAINER_multipeermap_contains (plugin->nat_wait_conns,
2069                                                 &address->peer)))
2070   {
2071     LOG (GNUNET_ERROR_TYPE_DEBUG,
2072          "Found valid IPv4 NAT address (creating session)!\n");
2073     session = create_session (plugin,
2074                               address,
2075                               net_type,
2076                               NULL,
2077                               GNUNET_YES);
2078     session->nat_connection_timeout = GNUNET_SCHEDULER_add_delayed (NAT_TIMEOUT,
2079                                                                     &nat_connect_timeout,
2080                                                                     session);
2081     GNUNET_assert (GNUNET_OK ==
2082                    GNUNET_CONTAINER_multipeermap_put (plugin->nat_wait_conns,
2083                                                       &session->target,
2084                                                       session,
2085                                                       GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
2086
2087     LOG (GNUNET_ERROR_TYPE_DEBUG,
2088          "Created NAT WAIT connection to `%4s' at `%s'\n",
2089          GNUNET_i2s (&session->target),
2090          GNUNET_a2s (sb, sbs));
2091     if (GNUNET_OK == GNUNET_NAT_run_client (plugin->nat, &a4))
2092     {
2093       return session;
2094     }
2095     else
2096     {
2097       LOG(GNUNET_ERROR_TYPE_DEBUG,
2098           "Running NAT client for `%4s' at `%s' failed\n",
2099           GNUNET_i2s (&session->target),
2100           GNUNET_a2s (sb, sbs));
2101       tcp_plugin_disconnect_session (plugin,
2102                                      session);
2103       return NULL;
2104     }
2105   }
2106
2107   /* create new outbound session */
2108   if (0 != (options & TCP_OPTIONS_TCP_STEALTH))
2109   {
2110 #ifdef TCP_STEALTH
2111     s = GNUNET_NETWORK_socket_create (af, SOCK_STREAM, 0);
2112     if (NULL == s)
2113     {
2114       GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK,
2115                            "socket");
2116       sa = NULL;
2117     }
2118     else
2119     {
2120       if ( (GNUNET_OK !=
2121             GNUNET_NETWORK_socket_setsockopt (s,
2122                                               IPPROTO_TCP,
2123                                               TCP_STEALTH,
2124                                               &session->target,
2125                                               sizeof (struct GNUNET_PeerIdentity))) ||
2126            (GNUNET_OK !=
2127             GNUNET_NETWORK_socket_setsockopt (s,
2128                                               IPPROTO_TCP,
2129                                               TCP_STEALTH_INTEGRITY,
2130                                               &plugin->my_welcome,
2131                                               sizeof (struct WelcomeMessage))) )
2132       {
2133         /* TCP STEALTH not supported by kernel */
2134         GNUNET_break (GNUNET_OK ==
2135                       GNUNET_NETWORK_socket_close (s));
2136         sa = NULL;
2137       }
2138       else
2139       {
2140         sa = GNUNET_CONNECTION_connect_socket (s, sb, sbs);
2141       }
2142     }
2143 #else
2144     sa = NULL;
2145 #endif
2146   }
2147   else
2148   {
2149     sa = GNUNET_CONNECTION_create_from_sockaddr (af, sb, sbs);
2150   }
2151   if (NULL == sa)
2152   {
2153     LOG (GNUNET_ERROR_TYPE_DEBUG,
2154          "Failed to create connection to `%4s' at `%s'\n",
2155          GNUNET_i2s (&address->peer),
2156          GNUNET_a2s (sb, sbs));
2157     return NULL;
2158   }
2159   LOG (GNUNET_ERROR_TYPE_DEBUG,
2160        "Asked to transmit to `%4s', creating fresh session using address `%s'.\n",
2161        GNUNET_i2s (&address->peer),
2162        GNUNET_a2s (sb, sbs));
2163
2164   session = create_session (plugin,
2165                             address,
2166                             net_type,
2167                             GNUNET_SERVER_connect_socket (plugin->server,
2168                                                           sa),
2169                             GNUNET_NO);
2170   (void) GNUNET_CONTAINER_multipeermap_put (plugin->sessionmap,
2171                                             &session->target,
2172                                             session,
2173                                             GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
2174   /* Send TCP Welcome */
2175   process_pending_messages (session);
2176
2177   return session;
2178 }
2179
2180
2181 /**
2182  * We have been asked to destroy all connections to a particular peer.
2183  * This function is called on each applicable session and must tear it
2184  * down.
2185  *
2186  * @param cls the `struct Plugin *`
2187  * @param key the peer which the session belongs to (unused)
2188  * @param value the `struct GNUNET_ATS_Session`
2189  * @return #GNUNET_YES (continue to iterate)
2190  */
2191 static int
2192 session_disconnect_it (void *cls,
2193                        const struct GNUNET_PeerIdentity *key,
2194                        void *value)
2195 {
2196   struct Plugin *plugin = cls;
2197   struct GNUNET_ATS_Session *session = value;
2198
2199   GNUNET_STATISTICS_update (session->plugin->env->stats,
2200                             gettext_noop ("# transport-service disconnect requests for TCP"),
2201                             1,
2202                             GNUNET_NO);
2203   tcp_plugin_disconnect_session (plugin,
2204                                  session);
2205   return GNUNET_YES;
2206 }
2207
2208
2209 /**
2210  * Function that can be called to force a disconnect from the
2211  * specified neighbour.  This should also cancel all previously
2212  * scheduled transmissions.  Obviously the transmission may have been
2213  * partially completed already, which is OK.  The plugin is supposed
2214  * to close the connection (if applicable) and no longer call the
2215  * transmit continuation(s).
2216  *
2217  * Finally, plugin MUST NOT call the services's receive function to
2218  * notify the service that the connection to the specified target was
2219  * closed after a getting this call.
2220  *
2221  * @param cls closure
2222  * @param target peer for which the last transmission is
2223  *        to be cancelled
2224  */
2225 static void
2226 tcp_plugin_disconnect (void *cls,
2227                        const struct GNUNET_PeerIdentity *target)
2228 {
2229   struct Plugin *plugin = cls;
2230
2231   LOG (GNUNET_ERROR_TYPE_DEBUG,
2232        "Disconnecting peer `%4s'\n",
2233        GNUNET_i2s (target));
2234   GNUNET_CONTAINER_multipeermap_get_multiple (plugin->sessionmap,
2235                                               target,
2236                                               &session_disconnect_it,
2237                                               plugin);
2238   GNUNET_CONTAINER_multipeermap_get_multiple (plugin->nat_wait_conns,
2239                                               target,
2240                                               &session_disconnect_it,
2241                                               plugin);
2242 }
2243
2244
2245 /**
2246  * We are processing an address pretty printing request and finished
2247  * the IP resolution (if applicable).  Append our port and forward the
2248  * result.  If called with @a hostname NULL, we are done and should
2249  * clean up the pretty printer (otherwise, there might be multiple
2250  * hostnames for the IP address and we might receive more).
2251  *
2252  * @param cls the `struct PrettyPrinterContext *`
2253  * @param hostname hostname part of the address
2254  */
2255 static void
2256 append_port (void *cls,
2257              const char *hostname)
2258 {
2259   struct PrettyPrinterContext *ppc = cls;
2260   struct Plugin *plugin = ppc->plugin;
2261   char *ret;
2262
2263   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2264               "append_port called with hostname `%s'\n",
2265               hostname);
2266   if (NULL == hostname)
2267   {
2268     /* Final call, done */
2269     ppc->resolver_handle = NULL;
2270     GNUNET_CONTAINER_DLL_remove (plugin->ppc_dll_head,
2271                                  plugin->ppc_dll_tail,
2272                                  ppc);
2273     ppc->asc (ppc->asc_cls,
2274               NULL,
2275               GNUNET_OK);
2276     GNUNET_free (ppc);
2277     return;
2278   }
2279   if (GNUNET_YES == ppc->ipv6)
2280     GNUNET_asprintf (&ret,
2281                      "%s.%u.[%s]:%d",
2282                      PLUGIN_NAME,
2283                      ppc->options,
2284                      hostname,
2285                      ppc->port);
2286   else
2287     GNUNET_asprintf (&ret,
2288                      "%s.%u.%s:%d",
2289                      PLUGIN_NAME,
2290                      ppc->options,
2291                      hostname,
2292                      ppc->port);
2293   ppc->asc (ppc->asc_cls,
2294             ret,
2295             GNUNET_OK);
2296   GNUNET_free (ret);
2297 }
2298
2299
2300 /**
2301  * Convert the transports address to a nice, human-readable format.
2302  *
2303  * @param cls closure with the `struct Plugin`
2304  * @param type name of the transport that generated the address
2305  * @param addr one of the addresses of the host, NULL for the last address
2306  *        the specific address format depends on the transport
2307  * @param addrlen length of the @a addr
2308  * @param numeric should (IP) addresses be displayed in numeric form?
2309  * @param timeout after how long should we give up?
2310  * @param asc function to call on each string
2311  * @param asc_cls closure for @a asc
2312  */
2313 static void
2314 tcp_plugin_address_pretty_printer (void *cls,
2315                                    const char *type,
2316                                    const void *addr,
2317                                    size_t addrlen,
2318                                    int numeric,
2319                                    struct GNUNET_TIME_Relative timeout,
2320                                    GNUNET_TRANSPORT_AddressStringCallback asc,
2321                                    void *asc_cls)
2322 {
2323   struct Plugin *plugin = cls;
2324   struct PrettyPrinterContext *ppc;
2325   const void *sb;
2326   size_t sbs;
2327   struct sockaddr_in a4;
2328   struct sockaddr_in6 a6;
2329   const struct IPv4TcpAddress *t4;
2330   const struct IPv6TcpAddress *t6;
2331   uint16_t port;
2332   uint32_t options;
2333
2334   if (sizeof(struct IPv6TcpAddress) == addrlen)
2335   {
2336     t6 = addr;
2337     memset (&a6, 0, sizeof(a6));
2338     a6.sin6_family = AF_INET6;
2339     a6.sin6_port = t6->t6_port;
2340     GNUNET_memcpy (&a6.sin6_addr, &t6->ipv6_addr, sizeof(struct in6_addr));
2341     port = ntohs (t6->t6_port);
2342     options = ntohl (t6->options);
2343     sb = &a6;
2344     sbs = sizeof(a6);
2345   }
2346   else if (sizeof(struct IPv4TcpAddress) == addrlen)
2347   {
2348     t4 = addr;
2349     memset (&a4, 0, sizeof(a4));
2350     a4.sin_family = AF_INET;
2351     a4.sin_port = t4->t4_port;
2352     a4.sin_addr.s_addr = t4->ipv4_addr;
2353     port = ntohs (t4->t4_port);
2354     options = ntohl (t4->options);
2355     sb = &a4;
2356     sbs = sizeof(a4);
2357   }
2358   else
2359   {
2360     /* invalid address */
2361     LOG (GNUNET_ERROR_TYPE_WARNING,
2362          _("Unexpected address length: %u bytes\n"),
2363          (unsigned int) addrlen);
2364     asc (asc_cls, NULL, GNUNET_SYSERR);
2365     asc (asc_cls, NULL, GNUNET_OK);
2366     return;
2367   }
2368   ppc = GNUNET_new (struct PrettyPrinterContext);
2369   ppc->plugin = plugin;
2370   if (addrlen == sizeof(struct IPv6TcpAddress))
2371     ppc->ipv6 = GNUNET_YES;
2372   else
2373     ppc->ipv6 = GNUNET_NO;
2374   ppc->asc = asc;
2375   ppc->asc_cls = asc_cls;
2376   ppc->port = port;
2377   ppc->options = options;
2378   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2379               "Starting DNS reverse lookup\n");
2380   ppc->resolver_handle = GNUNET_RESOLVER_hostname_get (sb,
2381                                                        sbs,
2382                                                        ! numeric,
2383                                                        timeout,
2384                                                        &append_port,
2385                                                        ppc);
2386   if (NULL == ppc->resolver_handle)
2387   {
2388     GNUNET_break (0);
2389     GNUNET_free (ppc);
2390     return;
2391   }
2392   GNUNET_CONTAINER_DLL_insert (plugin->ppc_dll_head,
2393                                plugin->ppc_dll_tail,
2394                                ppc);
2395 }
2396
2397
2398 /**
2399  * Check if the given port is plausible (must be either our listen
2400  * port or our advertised port), or any port if we are behind NAT
2401  * and do not have a port open.  If it is neither, we return
2402  * #GNUNET_SYSERR.
2403  *
2404  * @param plugin global variables
2405  * @param in_port port number to check
2406  * @return #GNUNET_OK if port is either open_port or adv_port
2407  */
2408 static int
2409 check_port (struct Plugin *plugin,
2410             uint16_t in_port)
2411 {
2412   if ( (in_port == plugin->adv_port) ||
2413        (in_port == plugin->open_port) )
2414     return GNUNET_OK;
2415   return GNUNET_SYSERR;
2416 }
2417
2418
2419 /**
2420  * Function that will be called to check if a binary address for this
2421  * plugin is well-formed and corresponds to an address for THIS peer
2422  * (as per our configuration).  Naturally, if absolutely necessary,
2423  * plugins can be a bit conservative in their answer, but in general
2424  * plugins should make sure that the address does not redirect
2425  * traffic to a 3rd party that might try to man-in-the-middle our
2426  * traffic.
2427  *
2428  * @param cls closure, our `struct Plugin *`
2429  * @param addr pointer to the address
2430  * @param addrlen length of @a addr
2431  * @return #GNUNET_OK if this is a plausible address for this peer
2432  *         and transport, #GNUNET_SYSERR if not
2433  */
2434 static int
2435 tcp_plugin_check_address (void *cls,
2436                           const void *addr,
2437                           size_t addrlen)
2438 {
2439   struct Plugin *plugin = cls;
2440   const struct IPv4TcpAddress *v4;
2441   const struct IPv6TcpAddress *v6;
2442
2443   if ( (addrlen != sizeof(struct IPv4TcpAddress)) &&
2444        (addrlen != sizeof(struct IPv6TcpAddress)) )
2445   {
2446     GNUNET_break_op (0);
2447     return GNUNET_SYSERR;
2448   }
2449
2450   if (addrlen == sizeof(struct IPv4TcpAddress))
2451   {
2452     v4 = (const struct IPv4TcpAddress *) addr;
2453     if (0 != memcmp (&v4->options,
2454                      &plugin->myoptions,
2455                      sizeof(uint32_t)))
2456     {
2457       GNUNET_break (0);
2458       return GNUNET_SYSERR;
2459     }
2460     if (GNUNET_OK != check_port (plugin,
2461                                  ntohs (v4->t4_port)))
2462       return GNUNET_SYSERR;
2463     if (GNUNET_OK !=
2464         GNUNET_NAT_test_address (plugin->nat,
2465                                  &v4->ipv4_addr,
2466                                  sizeof (struct in_addr)))
2467       return GNUNET_SYSERR;
2468   }
2469   else
2470   {
2471     v6 = (const struct IPv6TcpAddress *) addr;
2472     if (IN6_IS_ADDR_LINKLOCAL (&v6->ipv6_addr))
2473     {
2474       GNUNET_break_op (0);
2475       return GNUNET_SYSERR;
2476     }
2477     if (0 != memcmp (&v6->options,
2478                      &plugin->myoptions,
2479                      sizeof (uint32_t)))
2480     {
2481       GNUNET_break (0);
2482       return GNUNET_SYSERR;
2483     }
2484     if (GNUNET_OK != check_port (plugin,
2485                                  ntohs (v6->t6_port)))
2486       return GNUNET_SYSERR;
2487     if (GNUNET_OK !=
2488         GNUNET_NAT_test_address (plugin->nat,
2489                                  &v6->ipv6_addr,
2490                                  sizeof(struct in6_addr)))
2491       return GNUNET_SYSERR;
2492   }
2493   return GNUNET_OK;
2494 }
2495
2496
2497 /**
2498  * We've received a nat probe from this peer via TCP.  Finish
2499  * creating the client session and resume sending of queued
2500  * messages.
2501  *
2502  * @param cls closure
2503  * @param client identification of the client
2504  * @param message the actual message
2505  */
2506 static void
2507 handle_tcp_nat_probe (void *cls,
2508                       struct GNUNET_SERVER_Client *client,
2509                       const struct GNUNET_MessageHeader *message)
2510 {
2511   struct Plugin *plugin = cls;
2512   struct GNUNET_ATS_Session *session;
2513   const struct TCP_NAT_ProbeMessage *tcp_nat_probe;
2514   size_t alen;
2515   void *vaddr;
2516   struct IPv4TcpAddress *t4;
2517   struct IPv6TcpAddress *t6;
2518   const struct sockaddr_in *s4;
2519   const struct sockaddr_in6 *s6;
2520
2521   LOG (GNUNET_ERROR_TYPE_DEBUG,
2522        "Received NAT probe\n");
2523   /* We have received a TCP NAT probe, meaning we (hopefully) initiated
2524    * a connection to this peer by running gnunet-nat-client.  This peer
2525    * received the punch message and now wants us to use the new connection
2526    * as the default for that peer.  Do so and then send a WELCOME message
2527    * so we can really be connected!
2528    */
2529   if (ntohs (message->size) != sizeof(struct TCP_NAT_ProbeMessage))
2530   {
2531     GNUNET_break_op(0);
2532     GNUNET_SERVER_receive_done (client,
2533                                 GNUNET_SYSERR);
2534     return;
2535   }
2536
2537   tcp_nat_probe = (const struct TCP_NAT_ProbeMessage *) message;
2538   if (0 == memcmp (&tcp_nat_probe->clientIdentity, plugin->env->my_identity,
2539           sizeof(struct GNUNET_PeerIdentity)))
2540   {
2541     /* refuse connections from ourselves */
2542     GNUNET_SERVER_receive_done (client,
2543                                 GNUNET_SYSERR);
2544     return;
2545   }
2546
2547   session = GNUNET_CONTAINER_multipeermap_get (plugin->nat_wait_conns,
2548                                                &tcp_nat_probe->clientIdentity);
2549   if (NULL == session)
2550   {
2551     LOG (GNUNET_ERROR_TYPE_DEBUG,
2552          "Did NOT find session for NAT probe!\n");
2553     GNUNET_SERVER_receive_done (client,
2554                                 GNUNET_OK);
2555     return;
2556   }
2557   LOG (GNUNET_ERROR_TYPE_DEBUG,
2558        "Found session for NAT probe!\n");
2559
2560   if (NULL != session->nat_connection_timeout)
2561   {
2562     GNUNET_SCHEDULER_cancel (session->nat_connection_timeout);
2563     session->nat_connection_timeout = NULL;
2564   }
2565
2566   if (GNUNET_OK !=
2567       GNUNET_SERVER_client_get_address (client,
2568                                         &vaddr,
2569                                         &alen))
2570   {
2571     GNUNET_break(0);
2572     GNUNET_SERVER_receive_done (client,
2573                                 GNUNET_SYSERR);
2574     tcp_plugin_disconnect_session (plugin,
2575                                    session);
2576     return;
2577   }
2578   GNUNET_assert (GNUNET_YES ==
2579                  GNUNET_CONTAINER_multipeermap_remove (plugin->nat_wait_conns,
2580                                                        &tcp_nat_probe->clientIdentity,
2581                                                        session));
2582   GNUNET_SERVER_client_set_user_context (client,
2583                                          session);
2584   (void) GNUNET_CONTAINER_multipeermap_put (plugin->sessionmap,
2585                                             &session->target,
2586                                             session,
2587                                             GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
2588   session->last_activity = GNUNET_TIME_absolute_get ();
2589   LOG (GNUNET_ERROR_TYPE_DEBUG,
2590        "Found address `%s' for incoming connection\n",
2591        GNUNET_a2s (vaddr, alen));
2592   switch (((const struct sockaddr *) vaddr)->sa_family)
2593   {
2594   case AF_INET:
2595     s4 = vaddr;
2596     t4 = GNUNET_new (struct IPv4TcpAddress);
2597     t4->options = htonl (TCP_OPTIONS_NONE);
2598     t4->t4_port = s4->sin_port;
2599     t4->ipv4_addr = s4->sin_addr.s_addr;
2600     session->address = GNUNET_HELLO_address_allocate (&tcp_nat_probe->clientIdentity,
2601                                                       PLUGIN_NAME,
2602                                                       &t4,
2603                                                       sizeof(struct IPv4TcpAddress),
2604                                                       GNUNET_HELLO_ADDRESS_INFO_NONE);
2605     break;
2606   case AF_INET6:
2607     s6 = vaddr;
2608     t6 = GNUNET_new (struct IPv6TcpAddress);
2609     t6->options = htonl (TCP_OPTIONS_NONE);
2610     t6->t6_port = s6->sin6_port;
2611     GNUNET_memcpy (&t6->ipv6_addr, &s6->sin6_addr, sizeof(struct in6_addr));
2612     session->address = GNUNET_HELLO_address_allocate (&tcp_nat_probe->clientIdentity,
2613                                                       PLUGIN_NAME,
2614                                                       &t6,
2615                                                       sizeof(struct IPv6TcpAddress),
2616                                                       GNUNET_HELLO_ADDRESS_INFO_NONE);
2617     break;
2618   default:
2619     GNUNET_break_op(0);
2620     LOG(GNUNET_ERROR_TYPE_DEBUG,
2621         "Bad address for incoming connection!\n");
2622     GNUNET_free(vaddr);
2623     GNUNET_SERVER_receive_done (client,
2624                                 GNUNET_SYSERR);
2625     tcp_plugin_disconnect_session (plugin,
2626                                    session);
2627     return;
2628   }
2629   GNUNET_free (vaddr);
2630   GNUNET_break (NULL == session->client);
2631   session->client = client;
2632   GNUNET_STATISTICS_update (plugin->env->stats,
2633                             gettext_noop ("# TCP sessions active"),
2634                             1,
2635                             GNUNET_NO);
2636   process_pending_messages (session);
2637   GNUNET_SERVER_receive_done (client,
2638                               GNUNET_OK);
2639 }
2640
2641
2642 /**
2643  * We've received a welcome from this peer via TCP.  Possibly create a
2644  * fresh client record and send back our welcome.
2645  *
2646  * @param cls closure
2647  * @param client identification of the client
2648  * @param message the actual message
2649  */
2650 static void
2651 handle_tcp_welcome (void *cls,
2652                     struct GNUNET_SERVER_Client *client,
2653                     const struct GNUNET_MessageHeader *message)
2654 {
2655   struct Plugin *plugin = cls;
2656   const struct WelcomeMessage *wm = (const struct WelcomeMessage *) message;
2657   struct GNUNET_HELLO_Address *address;
2658   struct GNUNET_ATS_Session *session;
2659   size_t alen;
2660   void *vaddr;
2661   struct IPv4TcpAddress t4;
2662   struct IPv6TcpAddress t6;
2663   const struct sockaddr_in *s4;
2664   const struct sockaddr_in6 *s6;
2665
2666   if (0 == memcmp (&wm->clientIdentity,
2667                    plugin->env->my_identity,
2668                    sizeof(struct GNUNET_PeerIdentity)))
2669   {
2670     /* refuse connections from ourselves */
2671     GNUNET_SERVER_receive_done (client,
2672                                 GNUNET_SYSERR);
2673     if (GNUNET_OK ==
2674         GNUNET_SERVER_client_get_address (client,
2675                                           &vaddr,
2676                                           &alen))
2677     {
2678       LOG (GNUNET_ERROR_TYPE_INFO,
2679            "Received WELCOME message from my own identity `%4s' on address `%s'\n",
2680            GNUNET_i2s (&wm->clientIdentity),
2681            GNUNET_a2s (vaddr, alen));
2682       GNUNET_free(vaddr);
2683     }
2684     return;
2685   }
2686
2687   LOG(GNUNET_ERROR_TYPE_DEBUG,
2688       "Received WELCOME message from `%4s' %p\n",
2689       GNUNET_i2s (&wm->clientIdentity),
2690       client);
2691   GNUNET_STATISTICS_update (plugin->env->stats,
2692                             gettext_noop ("# TCP WELCOME messages received"),
2693                             1,
2694                             GNUNET_NO);
2695   session = lookup_session_by_client (plugin, client);
2696   if (NULL != session)
2697   {
2698     if (GNUNET_OK ==
2699         GNUNET_SERVER_client_get_address (client, &vaddr, &alen))
2700     {
2701       LOG (GNUNET_ERROR_TYPE_DEBUG,
2702            "Found existing session %p for peer `%s'\n",
2703            session,
2704            GNUNET_a2s (vaddr, alen));
2705       GNUNET_free (vaddr);
2706     }
2707   }
2708   else
2709   {
2710     if (GNUNET_OK ==
2711         GNUNET_SERVER_client_get_address (client, &vaddr, &alen))
2712     {
2713       if (alen == sizeof(struct sockaddr_in))
2714       {
2715         s4 = vaddr;
2716         memset (&t4, '\0', sizeof (t4));
2717         t4.options = htonl (TCP_OPTIONS_NONE);
2718         t4.t4_port = s4->sin_port;
2719         t4.ipv4_addr = s4->sin_addr.s_addr;
2720         address = GNUNET_HELLO_address_allocate (&wm->clientIdentity,
2721                                                  PLUGIN_NAME,
2722                                                  &t4,
2723                                                  sizeof(t4),
2724                                                  GNUNET_HELLO_ADDRESS_INFO_INBOUND);
2725       }
2726       else if (alen == sizeof(struct sockaddr_in6))
2727       {
2728         s6 = vaddr;
2729         memset (&t6, '\0', sizeof (t6));
2730         t6.options = htonl (TCP_OPTIONS_NONE);
2731         t6.t6_port = s6->sin6_port;
2732         GNUNET_memcpy (&t6.ipv6_addr, &s6->sin6_addr, sizeof(struct in6_addr));
2733         address = GNUNET_HELLO_address_allocate (&wm->clientIdentity,
2734                                                  PLUGIN_NAME,
2735                                                  &t6,
2736                                                  sizeof (t6),
2737                                                  GNUNET_HELLO_ADDRESS_INFO_INBOUND);
2738       }
2739       else
2740       {
2741         GNUNET_break (0);
2742         GNUNET_free_non_null (vaddr);
2743         GNUNET_SERVER_receive_done (client,
2744                                     GNUNET_SYSERR);
2745         return;
2746       }
2747       session = create_session (plugin,
2748                                 address,
2749                                 plugin->env->get_address_type (plugin->env->cls,
2750                                                                vaddr,
2751                                                                alen),
2752                                 client,
2753                                 GNUNET_NO);
2754       GNUNET_break (GNUNET_ATS_NET_UNSPECIFIED != session->scope);
2755       GNUNET_HELLO_address_free (address);
2756       LOG (GNUNET_ERROR_TYPE_DEBUG,
2757            "Creating new%s session %p for peer `%s' client %p\n",
2758            GNUNET_HELLO_address_check_option (session->address,
2759                                               GNUNET_HELLO_ADDRESS_INFO_INBOUND)
2760            ? " inbound" : "",
2761            session,
2762            tcp_plugin_address_to_string (plugin,
2763                                          session->address->address,
2764                                          session->address->address_length),
2765            client);
2766       GNUNET_free (vaddr);
2767       (void) GNUNET_CONTAINER_multipeermap_put (plugin->sessionmap,
2768                                                 &session->target,
2769                                                 session,
2770                                                 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
2771       /* Notify transport and ATS about new session */
2772       plugin->env->session_start (plugin->env->cls,
2773                                   session->address,
2774                                   session,
2775                                   session->scope);
2776     }
2777     else
2778     {
2779       LOG(GNUNET_ERROR_TYPE_DEBUG,
2780           "Did not obtain TCP socket address for incoming connection\n");
2781       GNUNET_break(0);
2782       GNUNET_SERVER_receive_done (client,
2783                                   GNUNET_SYSERR);
2784       return;
2785     }
2786   }
2787
2788   if (session->expecting_welcome != GNUNET_YES)
2789   {
2790     GNUNET_break_op(0);
2791     GNUNET_SERVER_receive_done (client,
2792                                 GNUNET_SYSERR);
2793     GNUNET_break(0);
2794     return;
2795   }
2796   session->last_activity = GNUNET_TIME_absolute_get ();
2797   session->expecting_welcome = GNUNET_NO;
2798
2799   process_pending_messages (session);
2800   GNUNET_SERVER_client_set_timeout (client,
2801                                     GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2802   GNUNET_SERVER_receive_done (client,
2803                               GNUNET_OK);
2804 }
2805
2806
2807 /**
2808  * We've received data for this peer via TCP.  Unbox,
2809  * compute latency and forward.
2810  *
2811  * @param cls closure
2812  * @param client identification of the client
2813  * @param message the actual message
2814  */
2815 static void
2816 handle_tcp_data (void *cls,
2817                  struct GNUNET_SERVER_Client *client,
2818                  const struct GNUNET_MessageHeader *message)
2819 {
2820   struct Plugin *plugin = cls;
2821   struct GNUNET_ATS_Session *session;
2822   struct GNUNET_TIME_Relative delay;
2823   uint16_t type;
2824
2825   type = ntohs (message->type);
2826   if ( (GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_WELCOME == type) ||
2827        (GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_NAT_PROBE == type) )
2828   {
2829     /* We don't want to propagate WELCOME and NAT Probe messages up! */
2830     GNUNET_SERVER_receive_done (client,
2831                                 GNUNET_OK);
2832     return;
2833   }
2834   session = lookup_session_by_client (plugin, client);
2835   if (NULL == session)
2836   {
2837     /* No inbound session found */
2838     void *vaddr;
2839     size_t alen;
2840
2841     GNUNET_SERVER_client_get_address (client,
2842                                       &vaddr,
2843                                       &alen);
2844     LOG (GNUNET_ERROR_TYPE_ERROR,
2845          "Received unexpected %u bytes of type %u from `%s'\n",
2846          (unsigned int) ntohs (message->size),
2847          (unsigned int) ntohs (message->type),
2848          GNUNET_a2s (vaddr,
2849                      alen));
2850     GNUNET_break_op(0);
2851     GNUNET_SERVER_receive_done (client,
2852                                 GNUNET_SYSERR);
2853     GNUNET_free_non_null (vaddr);
2854     return;
2855   }
2856   if (GNUNET_YES == session->expecting_welcome)
2857   {
2858     /* Session is expecting WELCOME message */
2859     void *vaddr;
2860     size_t alen;
2861
2862     GNUNET_SERVER_client_get_address (client, &vaddr, &alen);
2863     LOG (GNUNET_ERROR_TYPE_ERROR,
2864          "Received unexpected %u bytes of type %u from `%s'\n",
2865          (unsigned int) ntohs (message->size),
2866          (unsigned int) ntohs (message->type),
2867          GNUNET_a2s (vaddr, alen));
2868     GNUNET_break_op(0);
2869     GNUNET_SERVER_receive_done (client,
2870                                 GNUNET_SYSERR);
2871     GNUNET_free_non_null (vaddr);
2872     return;
2873   }
2874
2875   session->last_activity = GNUNET_TIME_absolute_get ();
2876   LOG (GNUNET_ERROR_TYPE_DEBUG,
2877        "Passing %u bytes of type %u from `%4s' to transport service.\n",
2878        (unsigned int) ntohs (message->size),
2879        (unsigned int) ntohs (message->type),
2880        GNUNET_i2s (&session->target));
2881
2882   GNUNET_STATISTICS_update (plugin->env->stats,
2883                             gettext_noop ("# bytes received via TCP"),
2884                             ntohs (message->size),
2885                             GNUNET_NO);
2886
2887   GNUNET_assert (GNUNET_CONTAINER_multipeermap_contains_value (plugin->sessionmap,
2888                                                                &session->target,
2889                                                                session));
2890   delay = plugin->env->receive (plugin->env->cls,
2891                                 session->address,
2892                                 session,
2893                                 message);
2894   reschedule_session_timeout (session);
2895   if (0 == delay.rel_value_us)
2896   {
2897     GNUNET_SERVER_receive_done (client,
2898                                 GNUNET_OK);
2899   }
2900   else
2901   {
2902     LOG (GNUNET_ERROR_TYPE_DEBUG,
2903          "Throttling receiving from `%s' for %s\n",
2904          GNUNET_i2s (&session->target),
2905          GNUNET_STRINGS_relative_time_to_string (delay,
2906                                                  GNUNET_YES));
2907     GNUNET_SERVER_disable_receive_done_warning (client);
2908     GNUNET_assert (NULL == session->receive_delay_task);
2909     session->receive_delay_task = GNUNET_SCHEDULER_add_delayed (delay,
2910                                                                 &delayed_done,
2911                                                                 session);
2912   }
2913 }
2914
2915
2916 /**
2917  * Function called whenever a peer is connected on the "SERVER" level.
2918  * Increments number of active connections and suspends server if we
2919  * have reached the limit.
2920  *
2921  * @param cls closure
2922  * @param client identification of the client
2923  */
2924 static void
2925 connect_notify (void *cls,
2926                 struct GNUNET_SERVER_Client *client)
2927 {
2928   struct Plugin *plugin = cls;
2929
2930   if (NULL == client)
2931     return;
2932   plugin->cur_connections++;
2933   GNUNET_STATISTICS_set (plugin->env->stats,
2934                          gettext_noop ("# TCP server connections active"),
2935                          plugin->cur_connections,
2936                          GNUNET_NO);
2937   GNUNET_STATISTICS_update (plugin->env->stats,
2938                             gettext_noop ("# TCP server connect events"),
2939                             1,
2940                             GNUNET_NO);
2941   if (plugin->cur_connections != plugin->max_connections)
2942     return;
2943   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2944               _("TCP connection limit reached, suspending server\n"));
2945   GNUNET_STATISTICS_update (plugin->env->stats,
2946                             gettext_noop ("# TCP service suspended"),
2947                             1,
2948                             GNUNET_NO);
2949   GNUNET_SERVER_suspend (plugin->server); /* Maximum number of connections rechead */
2950 }
2951
2952
2953 /**
2954  * Function called whenever a peer is disconnected on the "SERVER"
2955  * level.  Cleans up the connection, decrements number of active
2956  * connections and if applicable resumes listening.
2957  *
2958  * @param cls closure
2959  * @param client identification of the client
2960  */
2961 static void
2962 disconnect_notify (void *cls,
2963                    struct GNUNET_SERVER_Client *client)
2964 {
2965   struct Plugin *plugin = cls;
2966   struct GNUNET_ATS_Session *session;
2967
2968   if (NULL == client)
2969     return;
2970   GNUNET_assert (plugin->cur_connections >= 1);
2971   plugin->cur_connections--;
2972   session = lookup_session_by_client (plugin,
2973                                       client);
2974   if (NULL == session)
2975     return; /* unknown, nothing to do */
2976   LOG (GNUNET_ERROR_TYPE_DEBUG,
2977        "Destroying session of `%4s' with %s due to network-level disconnect.\n",
2978        GNUNET_i2s (&session->target),
2979        tcp_plugin_address_to_string (session->plugin,
2980                                      session->address->address,
2981                                      session->address->address_length));
2982
2983   if (plugin->cur_connections == plugin->max_connections)
2984   {
2985     GNUNET_STATISTICS_update (session->plugin->env->stats,
2986                               gettext_noop ("# TCP service resumed"),
2987                               1,
2988                               GNUNET_NO);
2989     GNUNET_SERVER_resume (plugin->server); /* Resume server  */
2990   }
2991   GNUNET_STATISTICS_set (plugin->env->stats,
2992                          gettext_noop ("# TCP server connections active"),
2993                          plugin->cur_connections,
2994                          GNUNET_NO);
2995   GNUNET_STATISTICS_update (session->plugin->env->stats,
2996                             gettext_noop ("# network-level TCP disconnect events"),
2997                             1,
2998                             GNUNET_NO);
2999   tcp_plugin_disconnect_session (plugin,
3000                                  session);
3001 }
3002
3003
3004 /**
3005  * We can now send a probe message, copy into buffer to really send.
3006  *
3007  * @param cls closure, a `struct TCPProbeContext`
3008  * @param size max size to copy
3009  * @param buf buffer to copy message to
3010  * @return number of bytes copied into @a buf
3011  */
3012 static size_t
3013 notify_send_probe (void *cls,
3014                    size_t size,
3015                    void *buf)
3016 {
3017   struct TCPProbeContext *tcp_probe_ctx = cls;
3018   struct Plugin *plugin = tcp_probe_ctx->plugin;
3019   size_t ret;
3020
3021   tcp_probe_ctx->transmit_handle = NULL;
3022   GNUNET_CONTAINER_DLL_remove (plugin->probe_head,
3023                                plugin->probe_tail,
3024                                tcp_probe_ctx);
3025   if (NULL == buf)
3026   {
3027     GNUNET_CONNECTION_destroy (tcp_probe_ctx->sock);
3028     GNUNET_free(tcp_probe_ctx);
3029     return 0;
3030   }
3031   GNUNET_assert(size >= sizeof(tcp_probe_ctx->message));
3032   GNUNET_memcpy (buf,
3033           &tcp_probe_ctx->message,
3034           sizeof(tcp_probe_ctx->message));
3035   GNUNET_SERVER_connect_socket (tcp_probe_ctx->plugin->server,
3036                                 tcp_probe_ctx->sock);
3037   ret = sizeof(tcp_probe_ctx->message);
3038   GNUNET_free (tcp_probe_ctx);
3039   return ret;
3040 }
3041
3042
3043 /**
3044  * Function called by the NAT subsystem suggesting another peer wants
3045  * to connect to us via connection reversal.  Try to connect back to the
3046  * given IP.
3047  *
3048  * @param cls closure
3049  * @param addr address to try
3050  * @param addrlen number of bytes in @a addr
3051  */
3052 static void
3053 try_connection_reversal (void *cls,
3054                          const struct sockaddr *addr,
3055                          socklen_t addrlen)
3056 {
3057   struct Plugin *plugin = cls;
3058   struct GNUNET_CONNECTION_Handle *sock;
3059   struct TCPProbeContext *tcp_probe_ctx;
3060
3061   /**
3062    * We have received an ICMP response, ostensibly from a peer
3063    * that wants to connect to us! Send a message to establish a connection.
3064    */
3065   sock = GNUNET_CONNECTION_create_from_sockaddr (AF_INET,
3066                                                  addr,
3067                                                  addrlen);
3068   if (NULL == sock)
3069   {
3070     /* failed for some odd reason (out of sockets?); ignore attempt */
3071     return;
3072   }
3073
3074   tcp_probe_ctx = GNUNET_new (struct TCPProbeContext);
3075   tcp_probe_ctx->message.header.size
3076     = htons (sizeof (struct TCP_NAT_ProbeMessage));
3077   tcp_probe_ctx->message.header.type
3078     = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_NAT_PROBE);
3079   tcp_probe_ctx->message.clientIdentity
3080     = *plugin->env->my_identity;
3081   tcp_probe_ctx->plugin = plugin;
3082   tcp_probe_ctx->sock = sock;
3083   GNUNET_CONTAINER_DLL_insert (plugin->probe_head,
3084                                plugin->probe_tail,
3085                                tcp_probe_ctx);
3086   tcp_probe_ctx->transmit_handle
3087     = GNUNET_CONNECTION_notify_transmit_ready (sock,
3088                                                ntohs (tcp_probe_ctx->message.header.size),
3089                                                GNUNET_TIME_UNIT_FOREVER_REL,
3090                                                &notify_send_probe,
3091                                                tcp_probe_ctx);
3092 }
3093
3094
3095 /**
3096  * Function obtain the network type for a session
3097  *
3098  * @param cls closure (`struct Plugin *`)
3099  * @param session the session
3100  * @return the network type in HBO or #GNUNET_SYSERR
3101  */
3102 static enum GNUNET_ATS_Network_Type
3103 tcp_plugin_get_network (void *cls,
3104                         struct GNUNET_ATS_Session *session)
3105 {
3106   return session->scope;
3107 }
3108
3109
3110 /**
3111  * Function obtain the network type for an address.
3112  *
3113  * @param cls closure (`struct Plugin *`)
3114  * @param address the address
3115  * @return the network type
3116  */
3117 static enum GNUNET_ATS_Network_Type
3118 tcp_plugin_get_network_for_address (void *cls,
3119                                     const struct GNUNET_HELLO_Address *address)
3120 {
3121   struct Plugin *plugin = cls;
3122   size_t addrlen;
3123   struct sockaddr_in a4;
3124   struct sockaddr_in6 a6;
3125   const struct IPv4TcpAddress *t4;
3126   const struct IPv6TcpAddress *t6;
3127   const void *sb;
3128   size_t sbs;
3129
3130   addrlen = address->address_length;
3131   if (addrlen == sizeof(struct IPv6TcpAddress))
3132   {
3133     GNUNET_assert (NULL != address->address); /* make static analysis happy */
3134     t6 = address->address;
3135     memset (&a6, 0, sizeof(a6));
3136 #if HAVE_SOCKADDR_IN_SIN_LEN
3137     a6.sin6_len = sizeof (a6);
3138 #endif
3139     a6.sin6_family = AF_INET6;
3140     a6.sin6_port = t6->t6_port;
3141     GNUNET_memcpy (&a6.sin6_addr, &t6->ipv6_addr, sizeof(struct in6_addr));
3142     sb = &a6;
3143     sbs = sizeof(a6);
3144   }
3145   else if (addrlen == sizeof(struct IPv4TcpAddress))
3146   {
3147     GNUNET_assert (NULL != address->address); /* make static analysis happy */
3148     t4 = address->address;
3149     memset (&a4, 0, sizeof(a4));
3150 #if HAVE_SOCKADDR_IN_SIN_LEN
3151     a4.sin_len = sizeof (a4);
3152 #endif
3153     a4.sin_family = AF_INET;
3154     a4.sin_port = t4->t4_port;
3155     a4.sin_addr.s_addr = t4->ipv4_addr;
3156     sb = &a4;
3157     sbs = sizeof(a4);
3158   }
3159   else
3160   {
3161     GNUNET_break (0);
3162     return GNUNET_ATS_NET_UNSPECIFIED;
3163   }
3164   return plugin->env->get_address_type (plugin->env->cls,
3165                                         sb,
3166                                         sbs);
3167 }
3168
3169
3170 /**
3171  * Return information about the given session to the
3172  * monitor callback.
3173  *
3174  * @param cls the `struct Plugin` with the monitor callback (`sic`)
3175  * @param peer peer we send information about
3176  * @param value our `struct GNUNET_ATS_Session` to send information about
3177  * @return #GNUNET_OK (continue to iterate)
3178  */
3179 static int
3180 send_session_info_iter (void *cls,
3181                         const struct GNUNET_PeerIdentity *peer,
3182                         void *value)
3183 {
3184   struct Plugin *plugin = cls;
3185   struct GNUNET_ATS_Session *session = value;
3186
3187   notify_session_monitor (plugin,
3188                           session,
3189                           GNUNET_TRANSPORT_SS_INIT);
3190   /* FIXME: cannot tell if this is up or not from current
3191      session state... */
3192   notify_session_monitor (plugin,
3193                           session,
3194                           GNUNET_TRANSPORT_SS_UP);
3195   return GNUNET_OK;
3196 }
3197
3198
3199 /**
3200  * Begin monitoring sessions of a plugin.  There can only
3201  * be one active monitor per plugin (i.e. if there are
3202  * multiple monitors, the transport service needs to
3203  * multiplex the generated events over all of them).
3204  *
3205  * @param cls closure of the plugin
3206  * @param sic callback to invoke, NULL to disable monitor;
3207  *            plugin will being by iterating over all active
3208  *            sessions immediately and then enter monitor mode
3209  * @param sic_cls closure for @a sic
3210  */
3211 static void
3212 tcp_plugin_setup_monitor (void *cls,
3213                           GNUNET_TRANSPORT_SessionInfoCallback sic,
3214                           void *sic_cls)
3215 {
3216   struct Plugin *plugin = cls;
3217
3218   plugin->sic = sic;
3219   plugin->sic_cls = sic_cls;
3220   if (NULL != sic)
3221   {
3222     GNUNET_CONTAINER_multipeermap_iterate (plugin->sessionmap,
3223                                            &send_session_info_iter,
3224                                            plugin);
3225     /* signal end of first iteration */
3226     sic (sic_cls, NULL, NULL);
3227   }
3228 }
3229
3230
3231 /**
3232  * Entry point for the plugin.
3233  *
3234  * @param cls closure, the `struct GNUNET_TRANSPORT_PluginEnvironment *`
3235  * @return the `struct GNUNET_TRANSPORT_PluginFunctions *` or NULL on error
3236  */
3237 void *
3238 libgnunet_plugin_transport_tcp_init (void *cls)
3239 {
3240   static const struct GNUNET_SERVER_MessageHandler my_handlers[] = {
3241     { &handle_tcp_welcome, NULL,
3242       GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_WELCOME,
3243       sizeof(struct WelcomeMessage) },
3244     { &handle_tcp_nat_probe, NULL,
3245       GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_NAT_PROBE,
3246       sizeof(struct TCP_NAT_ProbeMessage) },
3247     { &handle_tcp_data, NULL,
3248       GNUNET_MESSAGE_TYPE_ALL, 0 },
3249     { NULL, NULL, 0, 0 }
3250   };
3251   struct GNUNET_TRANSPORT_PluginEnvironment *env = cls;
3252   struct GNUNET_TRANSPORT_PluginFunctions *api;
3253   struct Plugin *plugin;
3254   struct GNUNET_SERVICE_Context *service;
3255   unsigned long long aport;
3256   unsigned long long bport;
3257   unsigned long long max_connections;
3258   unsigned int i;
3259   struct GNUNET_TIME_Relative idle_timeout;
3260 #ifdef TCP_STEALTH
3261   struct GNUNET_NETWORK_Handle *const*lsocks;
3262 #endif
3263   int ret;
3264   int ret_s;
3265   struct sockaddr **addrs;
3266   socklen_t *addrlens;
3267
3268   if (NULL == env->receive)
3269   {
3270     /* run in 'stub' mode (i.e. as part of gnunet-peerinfo), don't fully
3271      initialze the plugin or the API */
3272     api = GNUNET_new (struct GNUNET_TRANSPORT_PluginFunctions);
3273     api->cls = NULL;
3274     api->address_pretty_printer = &tcp_plugin_address_pretty_printer;
3275     api->address_to_string = &tcp_plugin_address_to_string;
3276     api->string_to_address = &tcp_plugin_string_to_address;
3277     return api;
3278   }
3279
3280   GNUNET_assert (NULL != env->cfg);
3281   if (GNUNET_OK !=
3282       GNUNET_CONFIGURATION_get_value_number (env->cfg,
3283                                              "transport-tcp",
3284                                              "MAX_CONNECTIONS",
3285                                              &max_connections))
3286     max_connections = 128;
3287
3288   aport = 0;
3289   if ((GNUNET_OK !=
3290        GNUNET_CONFIGURATION_get_value_number (env->cfg, "transport-tcp",
3291                                               "PORT", &bport)) ||
3292       (bport > 65535) ||
3293       ((GNUNET_OK ==
3294         GNUNET_CONFIGURATION_get_value_number (env->cfg, "transport-tcp",
3295                                                "ADVERTISED-PORT", &aport)) &&
3296        (aport > 65535) ))
3297   {
3298     LOG(GNUNET_ERROR_TYPE_ERROR,
3299         _("Require valid port number for service `%s' in configuration!\n"),
3300         "transport-tcp");
3301     return NULL ;
3302   }
3303   if (0 == aport)
3304     aport = bport;
3305   if (0 == bport)
3306     aport = 0;
3307   if (0 != bport)
3308   {
3309     service = GNUNET_SERVICE_start ("transport-tcp",
3310                                     env->cfg,
3311                                     GNUNET_SERVICE_OPTION_NONE);
3312     if (NULL == service)
3313     {
3314       LOG (GNUNET_ERROR_TYPE_WARNING,
3315            _("Failed to start service.\n"));
3316       return NULL;
3317     }
3318   }
3319   else
3320     service = NULL;
3321
3322   api = NULL;
3323   plugin = GNUNET_new (struct Plugin);
3324   plugin->sessionmap = GNUNET_CONTAINER_multipeermap_create (max_connections,
3325                                                              GNUNET_YES);
3326   plugin->max_connections = max_connections;
3327   plugin->open_port = bport;
3328   plugin->adv_port = aport;
3329   plugin->env = env;
3330   plugin->my_welcome.header.size = htons (sizeof(struct WelcomeMessage));
3331   plugin->my_welcome.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_WELCOME);
3332   plugin->my_welcome.clientIdentity = *plugin->env->my_identity;
3333
3334   if ( (NULL != service) &&
3335        (GNUNET_YES ==
3336         GNUNET_CONFIGURATION_get_value_yesno (env->cfg,
3337                                               "transport-tcp",
3338                                               "TCP_STEALTH")) )
3339   {
3340 #ifdef TCP_STEALTH
3341     plugin->myoptions |= TCP_OPTIONS_TCP_STEALTH;
3342     lsocks = GNUNET_SERVICE_get_listen_sockets (service);
3343     if (NULL != lsocks)
3344     {
3345       uint32_t len = sizeof (struct WelcomeMessage);
3346
3347       for (i=0;NULL!=lsocks[i];i++)
3348       {
3349         if ( (GNUNET_OK !=
3350               GNUNET_NETWORK_socket_setsockopt (lsocks[i],
3351                                                 IPPROTO_TCP,
3352                                                 TCP_STEALTH,
3353                                                 env->my_identity,
3354                                                 sizeof (struct GNUNET_PeerIdentity))) ||
3355              (GNUNET_OK !=
3356               GNUNET_NETWORK_socket_setsockopt (lsocks[i],
3357                                                 IPPROTO_TCP,
3358                                                 TCP_STEALTH_INTEGRITY_LEN,
3359                                                 &len,
3360                                                 sizeof (len))) )
3361         {
3362           /* TCP STEALTH not supported by kernel */
3363           GNUNET_assert (0 == i);
3364           GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3365                       _("TCP_STEALTH not supported on this platform.\n"));
3366           goto die;
3367         }
3368       }
3369     }
3370 #else
3371     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3372                 _("TCP_STEALTH not supported on this platform.\n"));
3373     goto die;
3374 #endif
3375   }
3376
3377   if ( (NULL != service) &&
3378        (GNUNET_SYSERR !=
3379         (ret_s =
3380          get_server_addresses ("transport-tcp",
3381                                env->cfg,
3382                                &addrs,
3383                                &addrlens))))
3384   {
3385     for (ret = ret_s-1; ret >= 0; ret--)
3386       LOG (GNUNET_ERROR_TYPE_INFO,
3387            "Binding to address `%s'\n",
3388            GNUNET_a2s (addrs[ret], addrlens[ret]));
3389     plugin->nat
3390       = GNUNET_NAT_register (env->cfg,
3391                              GNUNET_YES,
3392                              aport,
3393                              (unsigned int) ret_s,
3394                              (const struct sockaddr **) addrs,
3395                              addrlens,
3396                              &tcp_nat_port_map_callback,
3397                              &try_connection_reversal,
3398                              plugin,
3399                              NULL);
3400     for (ret = ret_s -1; ret >= 0; ret--)
3401       GNUNET_free (addrs[ret]);
3402     GNUNET_free_non_null (addrs);
3403     GNUNET_free_non_null (addrlens);
3404   }
3405   else
3406   {
3407     plugin->nat = GNUNET_NAT_register (plugin->env->cfg,
3408                                        GNUNET_YES,
3409                                        0,
3410                                        0,
3411                                        NULL,
3412                                        NULL,
3413                                        NULL,
3414                                        &try_connection_reversal,
3415                                        plugin,
3416                                        NULL);
3417   }
3418   api = GNUNET_new (struct GNUNET_TRANSPORT_PluginFunctions);
3419   api->cls = plugin;
3420   api->send = &tcp_plugin_send;
3421   api->get_session = &tcp_plugin_get_session;
3422   api->disconnect_session = &tcp_plugin_disconnect_session;
3423   api->query_keepalive_factor = &tcp_plugin_query_keepalive_factor;
3424   api->disconnect_peer = &tcp_plugin_disconnect;
3425   api->address_pretty_printer = &tcp_plugin_address_pretty_printer;
3426   api->check_address = &tcp_plugin_check_address;
3427   api->address_to_string = &tcp_plugin_address_to_string;
3428   api->string_to_address = &tcp_plugin_string_to_address;
3429   api->get_network = &tcp_plugin_get_network;
3430   api->get_network_for_address = &tcp_plugin_get_network_for_address;
3431   api->update_session_timeout = &tcp_plugin_update_session_timeout;
3432   api->update_inbound_delay = &tcp_plugin_update_inbound_delay;
3433   api->setup_monitor = &tcp_plugin_setup_monitor;
3434   plugin->service = service;
3435   if (NULL != service)
3436   {
3437     plugin->server = GNUNET_SERVICE_get_server (service);
3438   }
3439   else
3440   {
3441     if (GNUNET_OK !=
3442         GNUNET_CONFIGURATION_get_value_time (env->cfg,
3443                                              "transport-tcp",
3444                                              "TIMEOUT",
3445                                              &idle_timeout))
3446     {
3447       GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
3448                                  "transport-tcp",
3449                                  "TIMEOUT");
3450       goto die;
3451     }
3452     plugin->server
3453       = GNUNET_SERVER_create_with_sockets (NULL,
3454                                            plugin,
3455                                            NULL,
3456                                            idle_timeout,
3457                                            GNUNET_YES);
3458   }
3459   plugin->handlers = GNUNET_malloc (sizeof (my_handlers));
3460   GNUNET_memcpy (plugin->handlers,
3461                  my_handlers,
3462                  sizeof(my_handlers));
3463   for (i = 0;i < sizeof(my_handlers) / sizeof(struct GNUNET_SERVER_MessageHandler);i++)
3464     plugin->handlers[i].callback_cls = plugin;
3465
3466   GNUNET_SERVER_add_handlers (plugin->server,
3467                               plugin->handlers);
3468   GNUNET_SERVER_connect_notify (plugin->server,
3469                                 &connect_notify,
3470                                 plugin);
3471   GNUNET_SERVER_disconnect_notify (plugin->server,
3472                                    &disconnect_notify,
3473                                    plugin);
3474   plugin->nat_wait_conns = GNUNET_CONTAINER_multipeermap_create (16,
3475                                                                  GNUNET_YES);
3476   if (0 != bport)
3477     LOG (GNUNET_ERROR_TYPE_INFO,
3478          _("TCP transport listening on port %llu\n"),
3479          bport);
3480   else
3481     LOG (GNUNET_ERROR_TYPE_INFO,
3482          _("TCP transport not listening on any port (client only)\n"));
3483   if ( (aport != bport) &&
3484        (0 != bport) )
3485     LOG (GNUNET_ERROR_TYPE_INFO,
3486          _("TCP transport advertises itself as being on port %llu\n"),
3487          aport);
3488   /* Initially set connections to 0 */
3489   GNUNET_STATISTICS_set (plugin->env->stats,
3490                          gettext_noop ("# TCP sessions active"),
3491                          0,
3492                          GNUNET_NO);
3493   return api;
3494
3495  die:
3496   if (NULL != plugin->nat)
3497     GNUNET_NAT_unregister (plugin->nat);
3498   GNUNET_CONTAINER_multipeermap_destroy (plugin->sessionmap);
3499   if (NULL != service)
3500     GNUNET_SERVICE_stop (service);
3501   GNUNET_free (plugin);
3502   GNUNET_free_non_null (api);
3503   return NULL;
3504 }
3505
3506
3507 /**
3508  * Exit point from the plugin.
3509  *
3510  * @param cls the `struct GNUNET_TRANSPORT_PluginFunctions`
3511  * @return NULL
3512  */
3513 void *
3514 libgnunet_plugin_transport_tcp_done (void *cls)
3515 {
3516   struct GNUNET_TRANSPORT_PluginFunctions *api = cls;
3517   struct Plugin *plugin = api->cls;
3518   struct TCPProbeContext *tcp_probe;
3519   struct PrettyPrinterContext *cur;
3520   struct PrettyPrinterContext *next;
3521
3522   if (NULL == plugin)
3523   {
3524     GNUNET_free(api);
3525     return NULL ;
3526   }
3527   LOG (GNUNET_ERROR_TYPE_DEBUG,
3528        "Shutting down TCP plugin\n");
3529
3530   /* Removing leftover sessions */
3531   GNUNET_CONTAINER_multipeermap_iterate (plugin->sessionmap,
3532                                          &session_disconnect_it,
3533                                          plugin);
3534   /* Removing leftover NAT sessions */
3535   GNUNET_CONTAINER_multipeermap_iterate (plugin->nat_wait_conns,
3536                                          &session_disconnect_it,
3537                                          plugin);
3538
3539   for (cur = plugin->ppc_dll_head; NULL != cur; cur = next)
3540   {
3541     next = cur->next;
3542     GNUNET_CONTAINER_DLL_remove (plugin->ppc_dll_head,
3543                                  plugin->ppc_dll_tail,
3544                                  cur);
3545     GNUNET_RESOLVER_request_cancel (cur->resolver_handle);
3546     cur->asc (cur->asc_cls,
3547               NULL,
3548               GNUNET_OK);
3549     GNUNET_free (cur);
3550   }
3551
3552   if (NULL != plugin->service)
3553     GNUNET_SERVICE_stop (plugin->service);
3554   else
3555     GNUNET_SERVER_destroy (plugin->server);
3556   GNUNET_free (plugin->handlers);
3557   if (NULL != plugin->nat)
3558     GNUNET_NAT_unregister (plugin->nat);
3559   while (NULL != (tcp_probe = plugin->probe_head))
3560   {
3561     GNUNET_CONTAINER_DLL_remove (plugin->probe_head,
3562                                  plugin->probe_tail,
3563                                  tcp_probe);
3564     GNUNET_CONNECTION_destroy (tcp_probe->sock);
3565     GNUNET_free (tcp_probe);
3566   }
3567   GNUNET_CONTAINER_multipeermap_destroy (plugin->nat_wait_conns);
3568   GNUNET_CONTAINER_multipeermap_destroy (plugin->sessionmap);
3569   GNUNET_break (0 == plugin->cur_connections);
3570   GNUNET_free (plugin);
3571   GNUNET_free (api);
3572   return NULL;
3573 }
3574
3575 /* end of plugin_transport_tcp.c */