eca62a8cad704907ba486fc25d2d751e44604a03
[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_service.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 ac address class the address belongs to
949  * @param addr either the previous or the new public IP address
950  * @param addrlen actual length of @a addr
951  */
952 static void
953 tcp_nat_port_map_callback (void *cls,
954                            int add_remove,
955                            enum GNUNET_NAT_AddressClass ac,
956                            const struct sockaddr *addr,
957                            socklen_t addrlen)
958 {
959   struct Plugin *plugin = cls;
960   struct GNUNET_HELLO_Address *address;
961   struct IPv4TcpAddress t4;
962   struct IPv6TcpAddress t6;
963   void *arg;
964   size_t args;
965
966   LOG (GNUNET_ERROR_TYPE_INFO,
967        "NAT notification to %s address `%s'\n",
968        (GNUNET_YES == add_remove) ? "add" : "remove",
969        GNUNET_a2s (addr, addrlen));
970   /* convert 'addr' to our internal format */
971   switch (addr->sa_family)
972   {
973   case AF_INET:
974     GNUNET_assert(addrlen == sizeof(struct sockaddr_in));
975     memset (&t4, 0, sizeof(t4));
976     t4.options = htonl (plugin->myoptions);
977     t4.ipv4_addr = ((struct sockaddr_in *) addr)->sin_addr.s_addr;
978     t4.t4_port = ((struct sockaddr_in *) addr)->sin_port;
979     arg = &t4;
980     args = sizeof (t4);
981     break;
982   case AF_INET6:
983     GNUNET_assert(addrlen == sizeof(struct sockaddr_in6));
984     memset (&t6, 0, sizeof(t6));
985     GNUNET_memcpy (&t6.ipv6_addr,
986                    &((struct sockaddr_in6 *) addr)->sin6_addr,
987                    sizeof(struct in6_addr));
988     t6.options = htonl (plugin->myoptions);
989     t6.t6_port = ((struct sockaddr_in6 *) addr)->sin6_port;
990     arg = &t6;
991     args = sizeof (t6);
992     break;
993   default:
994     GNUNET_break(0);
995     return;
996   }
997   /* modify our published address list */
998   GNUNET_assert ((args == sizeof (struct IPv4TcpAddress)) ||
999                  (args == sizeof (struct IPv6TcpAddress)));
1000   /* TODO: use 'ac' here in the future... */
1001   address = GNUNET_HELLO_address_allocate (plugin->env->my_identity,
1002                                            PLUGIN_NAME,
1003                                            arg,
1004                                            args,
1005                                            GNUNET_HELLO_ADDRESS_INFO_NONE);
1006   plugin->env->notify_address (plugin->env->cls,
1007                                add_remove,
1008                                address);
1009   GNUNET_HELLO_address_free (address);
1010 }
1011
1012
1013 /**
1014  * Function called for a quick conversion of the binary address to
1015  * a numeric address.  Note that the caller must not free the
1016  * address and that the next call to this function is allowed
1017  * to override the address again.
1018  *
1019  * @param cls closure (`struct Plugin*`)
1020  * @param addr binary address
1021  * @param addrlen length of @a addr
1022  * @return string representing the same address
1023  */
1024 static const char *
1025 tcp_plugin_address_to_string (void *cls,
1026                               const void *addr,
1027                               size_t addrlen)
1028 {
1029   static char rbuf[INET6_ADDRSTRLEN + 12];
1030   char buf[INET6_ADDRSTRLEN];
1031   const void *sb;
1032   struct in_addr a4;
1033   struct in6_addr a6;
1034   const struct IPv4TcpAddress *t4;
1035   const struct IPv6TcpAddress *t6;
1036   int af;
1037   uint16_t port;
1038   uint32_t options;
1039
1040   switch (addrlen)
1041   {
1042   case sizeof(struct IPv6TcpAddress):
1043     t6 = addr;
1044     af = AF_INET6;
1045     port = ntohs (t6->t6_port);
1046     options = ntohl (t6->options);
1047     GNUNET_memcpy (&a6, &t6->ipv6_addr, sizeof(a6));
1048     sb = &a6;
1049     break;
1050   case sizeof(struct IPv4TcpAddress):
1051     t4 = addr;
1052     af = AF_INET;
1053     port = ntohs (t4->t4_port);
1054     options = ntohl (t4->options);
1055     GNUNET_memcpy (&a4, &t4->ipv4_addr, sizeof(a4));
1056     sb = &a4;
1057     break;
1058   default:
1059     LOG (GNUNET_ERROR_TYPE_WARNING,
1060          _("Unexpected address length: %u bytes\n"),
1061          (unsigned int) addrlen);
1062     return NULL ;
1063   }
1064   if (NULL == inet_ntop (af, sb, buf, INET6_ADDRSTRLEN))
1065   {
1066     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
1067                          "inet_ntop");
1068     return NULL ;
1069   }
1070   GNUNET_snprintf (rbuf, sizeof(rbuf),
1071                    (af == AF_INET6) ? "%s.%u.[%s]:%u" : "%s.%u.%s:%u",
1072                    PLUGIN_NAME,
1073                    options,
1074                    buf,
1075                    port);
1076   return rbuf;
1077 }
1078
1079
1080 /**
1081  * Function called to convert a string address to
1082  * a binary address.
1083  *
1084  * @param cls closure (`struct Plugin*`)
1085  * @param addr string address
1086  * @param addrlen length of the address
1087  * @param buf location to store the buffer
1088  * @param added location to store the number of bytes in the buffer.
1089  *        If the function returns #GNUNET_SYSERR, its contents are undefined.
1090  * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure
1091  */
1092 static int
1093 tcp_plugin_string_to_address (void *cls,
1094                               const char *addr,
1095                               uint16_t addrlen,
1096                               void **buf,
1097                               size_t *added)
1098 {
1099   struct sockaddr_storage socket_address;
1100   char *address;
1101   char *plugin;
1102   char *optionstr;
1103   uint32_t options;
1104
1105   /* Format tcp.options.address:port */
1106   address = NULL;
1107   plugin = NULL;
1108   optionstr = NULL;
1109   if ((NULL == addr) || (0 == addrlen))
1110   {
1111     GNUNET_break(0);
1112     return GNUNET_SYSERR;
1113   }
1114   if ('\0' != addr[addrlen - 1])
1115   {
1116     GNUNET_break(0);
1117     return GNUNET_SYSERR;
1118   }
1119   if (strlen (addr) != addrlen - 1)
1120   {
1121     GNUNET_break(0);
1122     return GNUNET_SYSERR;
1123   }
1124   plugin = GNUNET_strdup (addr);
1125   optionstr = strchr (plugin, '.');
1126   if (NULL == optionstr)
1127   {
1128     GNUNET_break(0);
1129     GNUNET_free(plugin);
1130     return GNUNET_SYSERR;
1131   }
1132   optionstr[0] = '\0';
1133   optionstr++;
1134   options = atol (optionstr);
1135   address = strchr (optionstr, '.');
1136   if (NULL == address)
1137   {
1138     GNUNET_break(0);
1139     GNUNET_free(plugin);
1140     return GNUNET_SYSERR;
1141   }
1142   address[0] = '\0';
1143   address++;
1144
1145   if (GNUNET_OK !=
1146       GNUNET_STRINGS_to_address_ip (address,
1147                                     strlen (address),
1148                                     &socket_address))
1149   {
1150     GNUNET_break(0);
1151     GNUNET_free(plugin);
1152     return GNUNET_SYSERR;
1153   }
1154
1155   GNUNET_free(plugin);
1156   switch (socket_address.ss_family)
1157   {
1158   case AF_INET:
1159   {
1160     struct IPv4TcpAddress *t4;
1161     struct sockaddr_in *in4 = (struct sockaddr_in *) &socket_address;
1162     t4 = GNUNET_new (struct IPv4TcpAddress);
1163     t4->options = htonl (options);
1164     t4->ipv4_addr = in4->sin_addr.s_addr;
1165     t4->t4_port = in4->sin_port;
1166     *buf = t4;
1167     *added = sizeof(struct IPv4TcpAddress);
1168     return GNUNET_OK;
1169   }
1170   case AF_INET6:
1171   {
1172     struct IPv6TcpAddress *t6;
1173     struct sockaddr_in6 *in6 = (struct sockaddr_in6 *) &socket_address;
1174     t6 = GNUNET_new (struct IPv6TcpAddress);
1175     t6->options = htonl (options);
1176     t6->ipv6_addr = in6->sin6_addr;
1177     t6->t6_port = in6->sin6_port;
1178     *buf = t6;
1179     *added = sizeof(struct IPv6TcpAddress);
1180     return GNUNET_OK;
1181   }
1182   default:
1183     return GNUNET_SYSERR;
1184   }
1185 }
1186
1187
1188 /**
1189  * Find the session handle for the given client.
1190  * Currently uses both the hashmap and the client
1191  * context, as the client context is new and the
1192  * logic still needs to be tested.
1193  *
1194  * @param plugin the plugin
1195  * @param client which client to find the session handle for
1196  * @return NULL if no matching session exists
1197  */
1198 static struct GNUNET_ATS_Session *
1199 lookup_session_by_client (struct Plugin *plugin,
1200                           struct GNUNET_SERVER_Client *client)
1201 {
1202   return GNUNET_SERVER_client_get_user_context (client,
1203                                                 struct GNUNET_ATS_Session);
1204 }
1205
1206
1207 /**
1208  * Functions with this signature are called whenever we need
1209  * to close a session due to a disconnect or failure to
1210  * establish a connection.
1211  *
1212  * @param cls the `struct Plugin`
1213  * @param session session to close down
1214  * @return #GNUNET_OK on success
1215  */
1216 static int
1217 tcp_plugin_disconnect_session (void *cls,
1218                                struct GNUNET_ATS_Session *session)
1219 {
1220   struct Plugin *plugin = cls;
1221   struct PendingMessage *pm;
1222
1223   LOG (GNUNET_ERROR_TYPE_DEBUG,
1224        "Disconnecting session of peer `%s' address `%s'\n",
1225        GNUNET_i2s (&session->target),
1226        tcp_plugin_address_to_string (session->plugin,
1227                                      session->address->address,
1228                                      session->address->address_length));
1229
1230   if (NULL != session->timeout_task)
1231   {
1232     GNUNET_SCHEDULER_cancel (session->timeout_task);
1233     session->timeout_task = NULL;
1234     session->timeout = GNUNET_TIME_UNIT_ZERO_ABS;
1235   }
1236
1237   if (GNUNET_YES ==
1238       GNUNET_CONTAINER_multipeermap_remove (plugin->sessionmap,
1239                                             &session->target,
1240                                             session))
1241   {
1242     GNUNET_STATISTICS_update (session->plugin->env->stats,
1243                               gettext_noop ("# TCP sessions active"),
1244                               -1,
1245                               GNUNET_NO);
1246   }
1247   else
1248   {
1249     GNUNET_assert (GNUNET_YES ==
1250                    GNUNET_CONTAINER_multipeermap_remove (plugin->nat_wait_conns,
1251                                                          &session->target,
1252                                                          session));
1253   }
1254   if (NULL != session->client)
1255     GNUNET_SERVER_client_set_user_context (session->client,
1256                                            NULL);
1257
1258   /* clean up state */
1259   if (NULL != session->transmit_handle)
1260   {
1261     GNUNET_SERVER_notify_transmit_ready_cancel (session->transmit_handle);
1262     session->transmit_handle = NULL;
1263   }
1264   session->plugin->env->session_end (session->plugin->env->cls,
1265                                      session->address,
1266                                      session);
1267
1268   if (NULL != session->nat_connection_timeout)
1269   {
1270     GNUNET_SCHEDULER_cancel (session->nat_connection_timeout);
1271     session->nat_connection_timeout = NULL;
1272   }
1273
1274   while (NULL != (pm = session->pending_messages_head))
1275   {
1276     LOG (GNUNET_ERROR_TYPE_DEBUG,
1277          (NULL != pm->transmit_cont)
1278          ? "Could not deliver message to `%s' at %s.\n"
1279          : "Could not deliver message to `%s' at %s, notifying.\n",
1280          GNUNET_i2s (&session->target),
1281          tcp_plugin_address_to_string (session->plugin,
1282                                        session->address->address,
1283                                        session->address->address_length));
1284     GNUNET_STATISTICS_update (session->plugin->env->stats,
1285                               gettext_noop ("# bytes currently in TCP buffers"),
1286                               -(int64_t) pm->message_size, GNUNET_NO);
1287     GNUNET_STATISTICS_update (session->plugin->env->stats,
1288                               gettext_noop ("# bytes discarded by TCP (disconnect)"),
1289                               pm->message_size,
1290                               GNUNET_NO);
1291     GNUNET_CONTAINER_DLL_remove (session->pending_messages_head,
1292                                  session->pending_messages_tail,
1293                                  pm);
1294     GNUNET_assert (0 < session->msgs_in_queue);
1295     session->msgs_in_queue--;
1296     GNUNET_assert (pm->message_size <= session->bytes_in_queue);
1297     session->bytes_in_queue -= pm->message_size;
1298     if (NULL != pm->transmit_cont)
1299       pm->transmit_cont (pm->transmit_cont_cls,
1300                          &session->target,
1301                          GNUNET_SYSERR,
1302                          pm->message_size,
1303                          0);
1304     GNUNET_free (pm);
1305   }
1306   GNUNET_assert (0 == session->msgs_in_queue);
1307   GNUNET_assert (0 == session->bytes_in_queue);
1308   notify_session_monitor (session->plugin,
1309                           session,
1310                           GNUNET_TRANSPORT_SS_DONE);
1311
1312   if (NULL != session->receive_delay_task)
1313   {
1314     GNUNET_SCHEDULER_cancel (session->receive_delay_task);
1315     session->receive_delay_task = NULL;
1316   }
1317   if (NULL != session->client)
1318   {
1319     GNUNET_SERVER_client_disconnect (session->client);
1320     session->client = NULL;
1321   }
1322   GNUNET_HELLO_address_free (session->address);
1323   GNUNET_assert (NULL == session->transmit_handle);
1324   GNUNET_free (session);
1325   return GNUNET_OK;
1326 }
1327
1328
1329 /**
1330  * Function that is called to get the keepalive factor.
1331  * #GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT is divided by this number to
1332  * calculate the interval between keepalive packets.
1333  *
1334  * @param cls closure with the `struct Plugin`
1335  * @return keepalive factor
1336  */
1337 static unsigned int
1338 tcp_plugin_query_keepalive_factor (void *cls)
1339 {
1340   return 3;
1341 }
1342
1343
1344 /**
1345  * Session was idle for too long, so disconnect it
1346  *
1347  * @param cls the `struct GNUNET_ATS_Session` of the idle session
1348  */
1349 static void
1350 session_timeout (void *cls)
1351 {
1352   struct GNUNET_ATS_Session *s = cls;
1353   struct GNUNET_TIME_Relative left;
1354
1355   s->timeout_task = NULL;
1356   left = GNUNET_TIME_absolute_get_remaining (s->timeout);
1357   if (0 != left.rel_value_us)
1358   {
1359     /* not actually our turn yet, but let's at least update
1360        the monitor, it may think we're about to die ... */
1361     notify_session_monitor (s->plugin,
1362                             s,
1363                             GNUNET_TRANSPORT_SS_UPDATE);
1364     s->timeout_task = GNUNET_SCHEDULER_add_delayed (left,
1365                                                     &session_timeout,
1366                                                     s);
1367     return;
1368   }
1369   LOG (GNUNET_ERROR_TYPE_DEBUG,
1370        "Session %p was idle for %s, disconnecting\n",
1371        s,
1372        GNUNET_STRINGS_relative_time_to_string (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
1373                                                GNUNET_YES));
1374   /* call session destroy function */
1375   tcp_plugin_disconnect_session (s->plugin,
1376                                  s);
1377 }
1378
1379
1380 /**
1381  * Increment session timeout due to activity.
1382  *
1383  * @param s session to increment timeout for
1384  */
1385 static void
1386 reschedule_session_timeout (struct GNUNET_ATS_Session *s)
1387 {
1388   GNUNET_assert (NULL != s->timeout_task);
1389   s->timeout = GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1390 }
1391
1392
1393 /**
1394  * Create a new session.  Also queues a welcome message.
1395  *
1396  * @param plugin the plugin
1397  * @param address the address to create the session for
1398  * @param scope network scope the address is from
1399  * @param client client to use, reference counter must have already been increased
1400  * @param is_nat this a NAT session, we should wait for a client to
1401  *               connect to us from an address, then assign that to
1402  *               the session
1403  * @return new session object
1404  */
1405 static struct GNUNET_ATS_Session *
1406 create_session (struct Plugin *plugin,
1407                 const struct GNUNET_HELLO_Address *address,
1408                 enum GNUNET_ATS_Network_Type scope,
1409                 struct GNUNET_SERVER_Client *client,
1410                 int is_nat)
1411 {
1412   struct GNUNET_ATS_Session *session;
1413   struct PendingMessage *pm;
1414
1415   if (GNUNET_YES != is_nat)
1416     GNUNET_assert (NULL != client);
1417   else
1418     GNUNET_assert (NULL == client);
1419
1420   LOG (GNUNET_ERROR_TYPE_DEBUG,
1421        "Creating new session for peer `%4s' at address %s\n",
1422        GNUNET_i2s (&address->peer),
1423        tcp_plugin_address_to_string (plugin,
1424                                      address->address,
1425                                      address->address_length));
1426   session = GNUNET_new (struct GNUNET_ATS_Session);
1427   session->last_activity = GNUNET_TIME_absolute_get ();
1428   session->plugin = plugin;
1429   session->is_nat = is_nat;
1430   if (NULL != client)
1431   {
1432     session->client = client;
1433     GNUNET_SERVER_client_set_user_context (client,
1434                                            session);
1435   }
1436   session->address = GNUNET_HELLO_address_copy (address);
1437   session->target = address->peer;
1438   session->expecting_welcome = GNUNET_YES;
1439   session->scope = scope;
1440   pm = GNUNET_malloc (sizeof (struct PendingMessage) +
1441                       sizeof (struct WelcomeMessage));
1442   pm->msg = (const char *) &pm[1];
1443   pm->message_size = sizeof(struct WelcomeMessage);
1444   GNUNET_memcpy (&pm[1],
1445           &plugin->my_welcome,
1446           sizeof(struct WelcomeMessage));
1447   pm->timeout = GNUNET_TIME_UNIT_FOREVER_ABS;
1448   GNUNET_STATISTICS_update (plugin->env->stats,
1449                             gettext_noop ("# bytes currently in TCP buffers"),
1450                             pm->message_size,
1451                             GNUNET_NO);
1452   GNUNET_CONTAINER_DLL_insert (session->pending_messages_head,
1453                                session->pending_messages_tail,
1454                                pm);
1455   session->msgs_in_queue++;
1456   session->bytes_in_queue += pm->message_size;
1457   session->timeout = GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1458   session->timeout_task = GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
1459                                                         &session_timeout,
1460                                                         session);
1461   notify_session_monitor (session->plugin,
1462                           session,
1463                           GNUNET_TRANSPORT_SS_INIT);
1464   if (GNUNET_YES != is_nat)
1465   {
1466     GNUNET_STATISTICS_update (plugin->env->stats,
1467                               gettext_noop ("# TCP sessions active"),
1468                               1,
1469                               GNUNET_NO);
1470     notify_session_monitor (session->plugin,
1471                             session,
1472                             GNUNET_TRANSPORT_SS_UP);
1473   }
1474   else
1475   {
1476     notify_session_monitor (session->plugin,
1477                             session,
1478                             GNUNET_TRANSPORT_SS_HANDSHAKE);
1479   }
1480   return session;
1481 }
1482
1483
1484 /**
1485  * If we have pending messages, ask the server to
1486  * transmit them (schedule the respective tasks, etc.)
1487  *
1488  * @param session for which session should we do this
1489  */
1490 static void
1491 process_pending_messages (struct GNUNET_ATS_Session *session);
1492
1493
1494 /**
1495  * Function called to notify a client about the socket
1496  * being ready to queue more data.  "buf" will be
1497  * NULL and "size" zero if the socket was closed for
1498  * writing in the meantime.
1499  *
1500  * @param cls closure
1501  * @param size number of bytes available in @a buf
1502  * @param buf where the callee should write the message
1503  * @return number of bytes written to @a buf
1504  */
1505 static size_t
1506 do_transmit (void *cls,
1507              size_t size,
1508              void *buf)
1509 {
1510   struct GNUNET_ATS_Session *session = cls;
1511   struct GNUNET_PeerIdentity pid;
1512   struct Plugin *plugin;
1513   struct PendingMessage *pos;
1514   struct PendingMessage *hd;
1515   struct PendingMessage *tl;
1516   struct GNUNET_TIME_Absolute now;
1517   char *cbuf;
1518   size_t ret;
1519
1520   session->transmit_handle = NULL;
1521   plugin = session->plugin;
1522   if (NULL == buf)
1523   {
1524     LOG (GNUNET_ERROR_TYPE_DEBUG,
1525          "Timeout trying to transmit to peer `%4s', discarding message queue.\n",
1526          GNUNET_i2s (&session->target));
1527     /* timeout; cancel all messages that have already expired */
1528     hd = NULL;
1529     tl = NULL;
1530     ret = 0;
1531     now = GNUNET_TIME_absolute_get ();
1532     while ( (NULL != (pos = session->pending_messages_head)) &&
1533             (pos->timeout.abs_value_us <= now.abs_value_us) )
1534     {
1535       GNUNET_CONTAINER_DLL_remove (session->pending_messages_head,
1536                                    session->pending_messages_tail,
1537                                    pos);
1538       GNUNET_assert (0 < session->msgs_in_queue);
1539       session->msgs_in_queue--;
1540       GNUNET_assert (pos->message_size <= session->bytes_in_queue);
1541       session->bytes_in_queue -= pos->message_size;
1542       LOG (GNUNET_ERROR_TYPE_DEBUG,
1543            "Failed to transmit %u byte message to `%4s'.\n",
1544            pos->message_size,
1545            GNUNET_i2s (&session->target));
1546       ret += pos->message_size;
1547       GNUNET_CONTAINER_DLL_insert_after (hd,
1548                                          tl,
1549                                          tl,
1550                                          pos);
1551     }
1552     /* do this call before callbacks (so that if callbacks destroy
1553      * session, they have a chance to cancel actions done by this
1554      * call) */
1555     process_pending_messages (session);
1556     pid = session->target;
1557     /* no do callbacks and do not use session again since
1558      * the callbacks may abort the session */
1559     while (NULL != (pos = hd))
1560     {
1561       GNUNET_CONTAINER_DLL_remove (hd,
1562                                    tl,
1563                                    pos);
1564       if (NULL != pos->transmit_cont)
1565         pos->transmit_cont (pos->transmit_cont_cls,
1566                             &pid,
1567                             GNUNET_SYSERR,
1568                             pos->message_size,
1569                             0);
1570       GNUNET_free (pos);
1571     }
1572     GNUNET_STATISTICS_update (plugin->env->stats,
1573                               gettext_noop ("# bytes currently in TCP buffers"), -(int64_t) ret,
1574                               GNUNET_NO);
1575     GNUNET_STATISTICS_update (plugin->env->stats,
1576                               gettext_noop ("# bytes discarded by TCP (timeout)"),
1577                               ret,
1578                               GNUNET_NO);
1579     if (0 < ret)
1580       notify_session_monitor (session->plugin,
1581                               session,
1582                               GNUNET_TRANSPORT_SS_UPDATE);
1583     return 0;
1584   }
1585   /* copy all pending messages that would fit */
1586   ret = 0;
1587   cbuf = buf;
1588   hd = NULL;
1589   tl = NULL;
1590   while (NULL != (pos = session->pending_messages_head))
1591   {
1592     if (ret + pos->message_size > size)
1593       break;
1594     GNUNET_CONTAINER_DLL_remove (session->pending_messages_head,
1595                                  session->pending_messages_tail,
1596                                  pos);
1597     GNUNET_assert (0 < session->msgs_in_queue);
1598     session->msgs_in_queue--;
1599     GNUNET_assert (pos->message_size <= session->bytes_in_queue);
1600     session->bytes_in_queue -= pos->message_size;
1601     GNUNET_assert(size >= pos->message_size);
1602     LOG (GNUNET_ERROR_TYPE_DEBUG,
1603          "Transmitting message of type %u size %u to peer %s at %s\n",
1604          ntohs (((struct GNUNET_MessageHeader *) pos->msg)->type),
1605          pos->message_size,
1606          GNUNET_i2s (&session->target),
1607          tcp_plugin_address_to_string (session->plugin,
1608                                        session->address->address,
1609                                        session->address->address_length));
1610     /* FIXME: this GNUNET_memcpy can be up to 7% of our total runtime */
1611     GNUNET_memcpy (cbuf,
1612             pos->msg,
1613             pos->message_size);
1614     cbuf += pos->message_size;
1615     ret += pos->message_size;
1616     size -= pos->message_size;
1617     GNUNET_CONTAINER_DLL_insert_tail (hd,
1618                                       tl,
1619                                       pos);
1620   }
1621   notify_session_monitor (session->plugin,
1622                           session,
1623                           GNUNET_TRANSPORT_SS_UPDATE);
1624   /* schedule 'continuation' before callbacks so that callbacks that
1625    * cancel everything don't cause us to use a session that no longer
1626    * exists... */
1627   process_pending_messages (session);
1628   session->last_activity = GNUNET_TIME_absolute_get ();
1629   pid = session->target;
1630   /* we'll now call callbacks that may cancel the session; hence
1631    * we should not use 'session' after this point */
1632   while (NULL != (pos = hd))
1633   {
1634     GNUNET_CONTAINER_DLL_remove (hd, tl, pos);
1635     if (NULL != pos->transmit_cont)
1636       pos->transmit_cont (pos->transmit_cont_cls,
1637                           &pid,
1638                           GNUNET_OK,
1639                           pos->message_size,
1640                           pos->message_size); /* FIXME: include TCP overhead */
1641     GNUNET_free (pos);
1642   }
1643   GNUNET_assert (NULL == hd);
1644   GNUNET_assert (NULL == tl);
1645   GNUNET_STATISTICS_update (plugin->env->stats,
1646                             gettext_noop ("# bytes currently in TCP buffers"),
1647                             - (int64_t) ret,
1648                             GNUNET_NO);
1649   GNUNET_STATISTICS_update (plugin->env->stats,
1650                             gettext_noop ("# bytes transmitted via TCP"),
1651                             ret,
1652                             GNUNET_NO);
1653   return ret;
1654 }
1655
1656
1657 /**
1658  * If we have pending messages, ask the server to
1659  * transmit them (schedule the respective tasks, etc.)
1660  *
1661  * @param session for which session should we do this
1662  */
1663 static void
1664 process_pending_messages (struct GNUNET_ATS_Session *session)
1665 {
1666   struct PendingMessage *pm;
1667
1668   GNUNET_assert (NULL != session->client);
1669   if (NULL != session->transmit_handle)
1670     return;
1671   if (NULL == (pm = session->pending_messages_head))
1672     return;
1673
1674   session->transmit_handle
1675     = GNUNET_SERVER_notify_transmit_ready (session->client,
1676                                            pm->message_size,
1677                                            GNUNET_TIME_absolute_get_remaining (pm->timeout),
1678                                            &do_transmit,
1679                                            session);
1680 }
1681
1682
1683 /**
1684  * Function that can be used by the transport service to transmit
1685  * a message using the plugin.   Note that in the case of a
1686  * peer disconnecting, the continuation MUST be called
1687  * prior to the disconnect notification itself.  This function
1688  * will be called with this peer's HELLO message to initiate
1689  * a fresh connection to another peer.
1690  *
1691  * @param cls closure
1692  * @param session which session must be used
1693  * @param msgbuf the message to transmit
1694  * @param msgbuf_size number of bytes in @a msgbuf
1695  * @param priority how important is the message (most plugins will
1696  *                 ignore message priority and just FIFO)
1697  * @param to how long to wait at most for the transmission (does not
1698  *                require plugins to discard the message after the timeout,
1699  *                just advisory for the desired delay; most plugins will ignore
1700  *                this as well)
1701  * @param cont continuation to call once the message has
1702  *        been transmitted (or if the transport is ready
1703  *        for the next transmission call; or if the
1704  *        peer disconnected...); can be NULL
1705  * @param cont_cls closure for @a cont
1706  * @return number of bytes used (on the physical network, with overheads);
1707  *         -1 on hard errors (i.e. address invalid); 0 is a legal value
1708  *         and does NOT mean that the message was not transmitted (DV)
1709  */
1710 static ssize_t
1711 tcp_plugin_send (void *cls,
1712                  struct GNUNET_ATS_Session *session,
1713                  const char *msgbuf,
1714                  size_t msgbuf_size,
1715                  unsigned int priority,
1716                  struct GNUNET_TIME_Relative to,
1717                  GNUNET_TRANSPORT_TransmitContinuation cont,
1718                  void *cont_cls)
1719 {
1720   struct Plugin * plugin = cls;
1721   struct PendingMessage *pm;
1722
1723   /* create new message entry */
1724   pm = GNUNET_malloc (sizeof (struct PendingMessage) + msgbuf_size);
1725   pm->msg = (const char *) &pm[1];
1726   GNUNET_memcpy (&pm[1], msgbuf, msgbuf_size);
1727   pm->message_size = msgbuf_size;
1728   pm->timeout = GNUNET_TIME_relative_to_absolute (to);
1729   pm->transmit_cont = cont;
1730   pm->transmit_cont_cls = cont_cls;
1731
1732   LOG(GNUNET_ERROR_TYPE_DEBUG,
1733       "Asked to transmit %u bytes to `%s', added message to list.\n",
1734       msgbuf_size,
1735       GNUNET_i2s (&session->target));
1736
1737   if (GNUNET_YES ==
1738       GNUNET_CONTAINER_multipeermap_contains_value (plugin->sessionmap,
1739                                                     &session->target,
1740                                                     session))
1741   {
1742     GNUNET_assert (NULL != session->client);
1743     GNUNET_SERVER_client_set_timeout (session->client,
1744                                       GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1745     GNUNET_STATISTICS_update (plugin->env->stats,
1746                               gettext_noop ("# bytes currently in TCP buffers"),
1747                               msgbuf_size,
1748                               GNUNET_NO);
1749
1750     /* append pm to pending_messages list */
1751     GNUNET_CONTAINER_DLL_insert_tail (session->pending_messages_head,
1752                                       session->pending_messages_tail,
1753                                       pm);
1754     notify_session_monitor (session->plugin,
1755                             session,
1756                             GNUNET_TRANSPORT_SS_UPDATE);
1757     session->msgs_in_queue++;
1758     session->bytes_in_queue += pm->message_size;
1759     process_pending_messages (session);
1760     return msgbuf_size;
1761   }
1762   if (GNUNET_YES ==
1763       GNUNET_CONTAINER_multipeermap_contains_value (plugin->nat_wait_conns,
1764                                                     &session->target,
1765                                                     session))
1766   {
1767     LOG (GNUNET_ERROR_TYPE_DEBUG,
1768          "This NAT WAIT session for peer `%s' is not yet ready!\n",
1769          GNUNET_i2s (&session->target));
1770     GNUNET_STATISTICS_update (plugin->env->stats,
1771                               gettext_noop ("# bytes currently in TCP buffers"), msgbuf_size,
1772                               GNUNET_NO);
1773     /* append pm to pending_messages list */
1774     GNUNET_CONTAINER_DLL_insert_tail (session->pending_messages_head,
1775                                       session->pending_messages_tail,
1776                                       pm);
1777     session->msgs_in_queue++;
1778     session->bytes_in_queue += pm->message_size;
1779     notify_session_monitor (session->plugin,
1780                             session,
1781                             GNUNET_TRANSPORT_SS_HANDSHAKE);
1782     return msgbuf_size;
1783   }
1784   LOG (GNUNET_ERROR_TYPE_ERROR,
1785        "Invalid session %p\n",
1786        session);
1787   if (NULL != cont)
1788     cont (cont_cls,
1789           &session->target,
1790           GNUNET_SYSERR,
1791           pm->message_size,
1792           0);
1793   GNUNET_break (0);
1794   GNUNET_free (pm);
1795   return GNUNET_SYSERR; /* session does not exist here */
1796 }
1797
1798
1799 /**
1800  * Closure for #session_lookup_it().
1801  */
1802 struct GNUNET_ATS_SessionItCtx
1803 {
1804   /**
1805    * Address we are looking for.
1806    */
1807   const struct GNUNET_HELLO_Address *address;
1808
1809   /**
1810    * Where to store the session (if we found it).
1811    */
1812   struct GNUNET_ATS_Session *result;
1813
1814 };
1815
1816
1817 /**
1818  * Look for a session by address.
1819  *
1820  * @param cls the `struct GNUNET_ATS_SessionItCtx`
1821  * @param key unused
1822  * @param value a `struct GNUNET_ATS_Session`
1823  * @return #GNUNET_YES to continue looking, #GNUNET_NO if we found the session
1824  */
1825 static int
1826 session_lookup_it (void *cls,
1827                    const struct GNUNET_PeerIdentity *key,
1828                    void *value)
1829 {
1830   struct GNUNET_ATS_SessionItCtx *si_ctx = cls;
1831   struct GNUNET_ATS_Session *session = value;
1832
1833   if (0 !=
1834       GNUNET_HELLO_address_cmp (si_ctx->address,
1835                                 session->address))
1836     return GNUNET_YES;
1837   si_ctx->result = session;
1838   return GNUNET_NO;
1839 }
1840
1841
1842 /**
1843  * Task cleaning up a NAT connection attempt after timeout
1844  *
1845  * @param cls the `struct GNUNET_ATS_Session`
1846  */
1847 static void
1848 nat_connect_timeout (void *cls)
1849 {
1850   struct GNUNET_ATS_Session *session = cls;
1851
1852   session->nat_connection_timeout = NULL;
1853   LOG (GNUNET_ERROR_TYPE_DEBUG,
1854        "NAT WAIT connection to `%4s' at `%s' could not be established, removing session\n",
1855        GNUNET_i2s (&session->target),
1856        tcp_plugin_address_to_string (session->plugin,
1857                                      session->address->address,
1858                                      session->address->address_length));
1859   tcp_plugin_disconnect_session (session->plugin,
1860                                  session);
1861 }
1862
1863
1864 /**
1865  * Function that will be called whenever the transport service wants to
1866  * notify the plugin that a session is still active and in use and
1867  * therefore the session timeout for this session has to be updated
1868  *
1869  * @param cls closure
1870  * @param peer which peer was the session for
1871  * @param session which session is being updated
1872  */
1873 static void
1874 tcp_plugin_update_session_timeout (void *cls,
1875                                    const struct GNUNET_PeerIdentity *peer,
1876                                    struct GNUNET_ATS_Session *session)
1877 {
1878   reschedule_session_timeout (session);
1879 }
1880
1881
1882 /**
1883  * Task to signal the server that we can continue
1884  * receiving from the TCP client now.
1885  *
1886  * @param cls the `struct GNUNET_ATS_Session *`
1887  */
1888 static void
1889 delayed_done (void *cls)
1890 {
1891   struct GNUNET_ATS_Session *session = cls;
1892
1893   session->receive_delay_task = NULL;
1894   reschedule_session_timeout (session);
1895   GNUNET_SERVER_receive_done (session->client,
1896                               GNUNET_OK);
1897 }
1898
1899
1900 /**
1901  * Function that will be called whenever the transport service wants to
1902  * notify the plugin that the inbound quota changed and that the plugin
1903  * should update it's delay for the next receive value
1904  *
1905  * @param cls closure
1906  * @param peer which peer was the session for
1907  * @param session which session is being updated
1908  * @param delay new delay to use for receiving
1909  */
1910 static void
1911 tcp_plugin_update_inbound_delay (void *cls,
1912                                  const struct GNUNET_PeerIdentity *peer,
1913                                  struct GNUNET_ATS_Session *session,
1914                                  struct GNUNET_TIME_Relative delay)
1915 {
1916   if (NULL == session->receive_delay_task)
1917     return;
1918   LOG (GNUNET_ERROR_TYPE_DEBUG,
1919        "New inbound delay %s\n",
1920        GNUNET_STRINGS_relative_time_to_string (delay,
1921                                                GNUNET_NO));
1922   session->receive_delay = GNUNET_TIME_relative_to_absolute (delay);
1923   GNUNET_SCHEDULER_cancel (session->receive_delay_task);
1924   session->receive_delay_task = GNUNET_SCHEDULER_add_delayed (delay,
1925                                                               &delayed_done,
1926                                                               session);
1927 }
1928
1929
1930 /**
1931  * Create a new session to transmit data to the target
1932  * This session will used to send data to this peer and the plugin will
1933  * notify us by calling the env->session_end function
1934  *
1935  * @param cls closure
1936  * @param address the address to use
1937  * @return the session if the address is valid, NULL otherwise
1938  */
1939 static struct GNUNET_ATS_Session *
1940 tcp_plugin_get_session (void *cls,
1941                         const struct GNUNET_HELLO_Address *address)
1942 {
1943   struct Plugin *plugin = cls;
1944   struct GNUNET_ATS_Session *session = NULL;
1945   int af;
1946   const void *sb;
1947   size_t sbs;
1948   struct GNUNET_CONNECTION_Handle *sa;
1949   struct sockaddr_in a4;
1950   struct sockaddr_in6 a6;
1951   const struct IPv4TcpAddress *t4;
1952   const struct IPv6TcpAddress *t6;
1953   unsigned int options;
1954   enum GNUNET_ATS_Network_Type net_type;
1955   unsigned int is_natd = GNUNET_NO;
1956   size_t addrlen;
1957 #ifdef TCP_STEALTH
1958   struct GNUNET_NETWORK_Handle *s;
1959 #endif
1960
1961   addrlen = address->address_length;
1962   LOG (GNUNET_ERROR_TYPE_DEBUG,
1963        "Trying to get session for `%s' address of peer `%s'\n",
1964        tcp_plugin_address_to_string (plugin,
1965                                      address->address,
1966                                      address->address_length),
1967        GNUNET_i2s (&address->peer));
1968
1969   if (GNUNET_HELLO_address_check_option (address,
1970                                          GNUNET_HELLO_ADDRESS_INFO_INBOUND))
1971   {
1972     GNUNET_break (0);
1973     return NULL;
1974   }
1975
1976   /* look for existing session */
1977   if (GNUNET_YES ==
1978       GNUNET_CONTAINER_multipeermap_contains (plugin->sessionmap,
1979                                               &address->peer))
1980   {
1981     struct GNUNET_ATS_SessionItCtx si_ctx;
1982
1983     si_ctx.address = address;
1984     si_ctx.result = NULL;
1985     GNUNET_CONTAINER_multipeermap_get_multiple (plugin->sessionmap,
1986                                                 &address->peer,
1987                                                 &session_lookup_it,
1988                                                 &si_ctx);
1989     if (NULL != si_ctx.result)
1990     {
1991       session = si_ctx.result;
1992       LOG (GNUNET_ERROR_TYPE_DEBUG,
1993            "Found existing session for `%s' address `%s'\n",
1994            GNUNET_i2s (&address->peer),
1995            tcp_plugin_address_to_string (plugin,
1996                                          address->address,
1997                                          address->address_length));
1998       return session;
1999     }
2000   }
2001
2002   if (addrlen == sizeof(struct IPv6TcpAddress))
2003   {
2004     GNUNET_assert (NULL != address->address); /* make static analysis happy */
2005     t6 = address->address;
2006     options = t6->options;
2007     af = AF_INET6;
2008     memset (&a6, 0, sizeof(a6));
2009 #if HAVE_SOCKADDR_IN_SIN_LEN
2010     a6.sin6_len = sizeof (a6);
2011 #endif
2012     a6.sin6_family = AF_INET6;
2013     a6.sin6_port = t6->t6_port;
2014     if (t6->t6_port == 0)
2015       is_natd = GNUNET_YES;
2016     GNUNET_memcpy (&a6.sin6_addr, &t6->ipv6_addr, sizeof(struct in6_addr));
2017     sb = &a6;
2018     sbs = sizeof(a6);
2019   }
2020   else if (addrlen == sizeof(struct IPv4TcpAddress))
2021   {
2022     GNUNET_assert(NULL != address->address); /* make static analysis happy */
2023     t4 = address->address;
2024     options = t4->options;
2025     af = AF_INET;
2026     memset (&a4, 0, sizeof(a4));
2027 #if HAVE_SOCKADDR_IN_SIN_LEN
2028     a4.sin_len = sizeof (a4);
2029 #endif
2030     a4.sin_family = AF_INET;
2031     a4.sin_port = t4->t4_port;
2032     if (t4->t4_port == 0)
2033       is_natd = GNUNET_YES;
2034     a4.sin_addr.s_addr = t4->ipv4_addr;
2035     sb = &a4;
2036     sbs = sizeof(a4);
2037   }
2038   else
2039   {
2040     GNUNET_STATISTICS_update (plugin->env->stats,
2041                               gettext_noop ("# requests to create session with invalid address"),
2042                               1,
2043                               GNUNET_NO);
2044     return NULL;
2045   }
2046
2047   net_type = plugin->env->get_address_type (plugin->env->cls,
2048                                             sb,
2049                                             sbs);
2050   GNUNET_break (net_type != GNUNET_ATS_NET_UNSPECIFIED);
2051
2052   if ( (is_natd == GNUNET_YES) &&
2053        (addrlen == sizeof(struct IPv6TcpAddress)) )
2054   {
2055     /* NAT client only works with IPv4 addresses */
2056     return NULL;
2057   }
2058
2059   if (plugin->cur_connections >= plugin->max_connections)
2060   {
2061     /* saturated */
2062     return NULL;
2063   }
2064
2065   if ( (is_natd == GNUNET_YES) &&
2066        (GNUNET_YES ==
2067         GNUNET_CONTAINER_multipeermap_contains (plugin->nat_wait_conns,
2068                                                 &address->peer)))
2069   {
2070     /* Only do one NAT punch attempt per peer identity */
2071     return NULL;
2072   }
2073
2074   if ( (is_natd == GNUNET_YES) &&
2075        (NULL != plugin->nat) &&
2076        (GNUNET_NO ==
2077         GNUNET_CONTAINER_multipeermap_contains (plugin->nat_wait_conns,
2078                                                 &address->peer)))
2079   {
2080     struct sockaddr_in local_sa;
2081     
2082     LOG (GNUNET_ERROR_TYPE_DEBUG,
2083          "Found valid IPv4 NAT address (creating session)!\n");
2084     session = create_session (plugin,
2085                               address,
2086                               net_type,
2087                               NULL,
2088                               GNUNET_YES);
2089     session->nat_connection_timeout = GNUNET_SCHEDULER_add_delayed (NAT_TIMEOUT,
2090                                                                     &nat_connect_timeout,
2091                                                                     session);
2092     GNUNET_assert (GNUNET_OK ==
2093                    GNUNET_CONTAINER_multipeermap_put (plugin->nat_wait_conns,
2094                                                       &session->target,
2095                                                       session,
2096                                                       GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
2097
2098     LOG (GNUNET_ERROR_TYPE_DEBUG,
2099          "Created NAT WAIT connection to `%s' at `%s'\n",
2100          GNUNET_i2s (&session->target),
2101          GNUNET_a2s (sb, sbs));
2102     memset (&local_sa,
2103             0,
2104             sizeof (local_sa));
2105     local_sa.sin_family = AF_INET;
2106     local_sa.sin_port = htons (plugin->open_port);
2107     /* We leave sin_address at 0, let the kernel figure it out,
2108        even if our bind() is more specific.  (May want to reconsider
2109        later.) */
2110     if (GNUNET_OK ==
2111         GNUNET_NAT_request_reversal (plugin->nat,
2112                                      &local_sa,
2113                                      &a4))
2114       return session;
2115     LOG (GNUNET_ERROR_TYPE_DEBUG,
2116          "Running NAT client for `%s' at `%s' failed\n",
2117          GNUNET_i2s (&session->target),
2118          GNUNET_a2s (sb, sbs));
2119     tcp_plugin_disconnect_session (plugin,
2120                                    session);
2121     return NULL;
2122   }
2123
2124   /* create new outbound session */
2125   if (0 != (options & TCP_OPTIONS_TCP_STEALTH))
2126   {
2127 #ifdef TCP_STEALTH
2128     s = GNUNET_NETWORK_socket_create (af, SOCK_STREAM, 0);
2129     if (NULL == s)
2130     {
2131       GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK,
2132                            "socket");
2133       sa = NULL;
2134     }
2135     else
2136     {
2137       if ( (GNUNET_OK !=
2138             GNUNET_NETWORK_socket_setsockopt (s,
2139                                               IPPROTO_TCP,
2140                                               TCP_STEALTH,
2141                                               &session->target,
2142                                               sizeof (struct GNUNET_PeerIdentity))) ||
2143            (GNUNET_OK !=
2144             GNUNET_NETWORK_socket_setsockopt (s,
2145                                               IPPROTO_TCP,
2146                                               TCP_STEALTH_INTEGRITY,
2147                                               &plugin->my_welcome,
2148                                               sizeof (struct WelcomeMessage))) )
2149       {
2150         /* TCP STEALTH not supported by kernel */
2151         GNUNET_break (GNUNET_OK ==
2152                       GNUNET_NETWORK_socket_close (s));
2153         sa = NULL;
2154       }
2155       else
2156       {
2157         sa = GNUNET_CONNECTION_connect_socket (s, sb, sbs);
2158       }
2159     }
2160 #else
2161     sa = NULL;
2162 #endif
2163   }
2164   else
2165   {
2166     sa = GNUNET_CONNECTION_create_from_sockaddr (af, sb, sbs);
2167   }
2168   if (NULL == sa)
2169   {
2170     LOG (GNUNET_ERROR_TYPE_DEBUG,
2171          "Failed to create connection to `%4s' at `%s'\n",
2172          GNUNET_i2s (&address->peer),
2173          GNUNET_a2s (sb, sbs));
2174     return NULL;
2175   }
2176   LOG (GNUNET_ERROR_TYPE_DEBUG,
2177        "Asked to transmit to `%4s', creating fresh session using address `%s'.\n",
2178        GNUNET_i2s (&address->peer),
2179        GNUNET_a2s (sb, sbs));
2180
2181   session = create_session (plugin,
2182                             address,
2183                             net_type,
2184                             GNUNET_SERVER_connect_socket (plugin->server,
2185                                                           sa),
2186                             GNUNET_NO);
2187   (void) GNUNET_CONTAINER_multipeermap_put (plugin->sessionmap,
2188                                             &session->target,
2189                                             session,
2190                                             GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
2191   /* Send TCP Welcome */
2192   process_pending_messages (session);
2193
2194   return session;
2195 }
2196
2197
2198 /**
2199  * We have been asked to destroy all connections to a particular peer.
2200  * This function is called on each applicable session and must tear it
2201  * down.
2202  *
2203  * @param cls the `struct Plugin *`
2204  * @param key the peer which the session belongs to (unused)
2205  * @param value the `struct GNUNET_ATS_Session`
2206  * @return #GNUNET_YES (continue to iterate)
2207  */
2208 static int
2209 session_disconnect_it (void *cls,
2210                        const struct GNUNET_PeerIdentity *key,
2211                        void *value)
2212 {
2213   struct Plugin *plugin = cls;
2214   struct GNUNET_ATS_Session *session = value;
2215
2216   GNUNET_STATISTICS_update (session->plugin->env->stats,
2217                             gettext_noop ("# transport-service disconnect requests for TCP"),
2218                             1,
2219                             GNUNET_NO);
2220   tcp_plugin_disconnect_session (plugin,
2221                                  session);
2222   return GNUNET_YES;
2223 }
2224
2225
2226 /**
2227  * Function that can be called to force a disconnect from the
2228  * specified neighbour.  This should also cancel all previously
2229  * scheduled transmissions.  Obviously the transmission may have been
2230  * partially completed already, which is OK.  The plugin is supposed
2231  * to close the connection (if applicable) and no longer call the
2232  * transmit continuation(s).
2233  *
2234  * Finally, plugin MUST NOT call the services's receive function to
2235  * notify the service that the connection to the specified target was
2236  * closed after a getting this call.
2237  *
2238  * @param cls closure
2239  * @param target peer for which the last transmission is
2240  *        to be cancelled
2241  */
2242 static void
2243 tcp_plugin_disconnect (void *cls,
2244                        const struct GNUNET_PeerIdentity *target)
2245 {
2246   struct Plugin *plugin = cls;
2247
2248   LOG (GNUNET_ERROR_TYPE_DEBUG,
2249        "Disconnecting peer `%4s'\n",
2250        GNUNET_i2s (target));
2251   GNUNET_CONTAINER_multipeermap_get_multiple (plugin->sessionmap,
2252                                               target,
2253                                               &session_disconnect_it,
2254                                               plugin);
2255   GNUNET_CONTAINER_multipeermap_get_multiple (plugin->nat_wait_conns,
2256                                               target,
2257                                               &session_disconnect_it,
2258                                               plugin);
2259 }
2260
2261
2262 /**
2263  * We are processing an address pretty printing request and finished
2264  * the IP resolution (if applicable).  Append our port and forward the
2265  * result.  If called with @a hostname NULL, we are done and should
2266  * clean up the pretty printer (otherwise, there might be multiple
2267  * hostnames for the IP address and we might receive more).
2268  *
2269  * @param cls the `struct PrettyPrinterContext *`
2270  * @param hostname hostname part of the address
2271  */
2272 static void
2273 append_port (void *cls,
2274              const char *hostname)
2275 {
2276   struct PrettyPrinterContext *ppc = cls;
2277   struct Plugin *plugin = ppc->plugin;
2278   char *ret;
2279
2280   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2281               "append_port called with hostname `%s'\n",
2282               hostname);
2283   if (NULL == hostname)
2284   {
2285     /* Final call, done */
2286     ppc->resolver_handle = NULL;
2287     GNUNET_CONTAINER_DLL_remove (plugin->ppc_dll_head,
2288                                  plugin->ppc_dll_tail,
2289                                  ppc);
2290     ppc->asc (ppc->asc_cls,
2291               NULL,
2292               GNUNET_OK);
2293     GNUNET_free (ppc);
2294     return;
2295   }
2296   if (GNUNET_YES == ppc->ipv6)
2297     GNUNET_asprintf (&ret,
2298                      "%s.%u.[%s]:%d",
2299                      PLUGIN_NAME,
2300                      ppc->options,
2301                      hostname,
2302                      ppc->port);
2303   else
2304     GNUNET_asprintf (&ret,
2305                      "%s.%u.%s:%d",
2306                      PLUGIN_NAME,
2307                      ppc->options,
2308                      hostname,
2309                      ppc->port);
2310   ppc->asc (ppc->asc_cls,
2311             ret,
2312             GNUNET_OK);
2313   GNUNET_free (ret);
2314 }
2315
2316
2317 /**
2318  * Convert the transports address to a nice, human-readable format.
2319  *
2320  * @param cls closure with the `struct Plugin`
2321  * @param type name of the transport that generated the address
2322  * @param addr one of the addresses of the host, NULL for the last address
2323  *        the specific address format depends on the transport
2324  * @param addrlen length of the @a addr
2325  * @param numeric should (IP) addresses be displayed in numeric form?
2326  * @param timeout after how long should we give up?
2327  * @param asc function to call on each string
2328  * @param asc_cls closure for @a asc
2329  */
2330 static void
2331 tcp_plugin_address_pretty_printer (void *cls,
2332                                    const char *type,
2333                                    const void *addr,
2334                                    size_t addrlen,
2335                                    int numeric,
2336                                    struct GNUNET_TIME_Relative timeout,
2337                                    GNUNET_TRANSPORT_AddressStringCallback asc,
2338                                    void *asc_cls)
2339 {
2340   struct Plugin *plugin = cls;
2341   struct PrettyPrinterContext *ppc;
2342   const void *sb;
2343   size_t sbs;
2344   struct sockaddr_in a4;
2345   struct sockaddr_in6 a6;
2346   const struct IPv4TcpAddress *t4;
2347   const struct IPv6TcpAddress *t6;
2348   uint16_t port;
2349   uint32_t options;
2350
2351   if (sizeof(struct IPv6TcpAddress) == addrlen)
2352   {
2353     t6 = addr;
2354     memset (&a6, 0, sizeof(a6));
2355     a6.sin6_family = AF_INET6;
2356     a6.sin6_port = t6->t6_port;
2357     GNUNET_memcpy (&a6.sin6_addr, &t6->ipv6_addr, sizeof(struct in6_addr));
2358     port = ntohs (t6->t6_port);
2359     options = ntohl (t6->options);
2360     sb = &a6;
2361     sbs = sizeof(a6);
2362   }
2363   else if (sizeof(struct IPv4TcpAddress) == addrlen)
2364   {
2365     t4 = addr;
2366     memset (&a4, 0, sizeof(a4));
2367     a4.sin_family = AF_INET;
2368     a4.sin_port = t4->t4_port;
2369     a4.sin_addr.s_addr = t4->ipv4_addr;
2370     port = ntohs (t4->t4_port);
2371     options = ntohl (t4->options);
2372     sb = &a4;
2373     sbs = sizeof(a4);
2374   }
2375   else
2376   {
2377     /* invalid address */
2378     LOG (GNUNET_ERROR_TYPE_WARNING,
2379          _("Unexpected address length: %u bytes\n"),
2380          (unsigned int) addrlen);
2381     asc (asc_cls, NULL, GNUNET_SYSERR);
2382     asc (asc_cls, NULL, GNUNET_OK);
2383     return;
2384   }
2385   ppc = GNUNET_new (struct PrettyPrinterContext);
2386   ppc->plugin = plugin;
2387   if (addrlen == sizeof(struct IPv6TcpAddress))
2388     ppc->ipv6 = GNUNET_YES;
2389   else
2390     ppc->ipv6 = GNUNET_NO;
2391   ppc->asc = asc;
2392   ppc->asc_cls = asc_cls;
2393   ppc->port = port;
2394   ppc->options = options;
2395   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2396               "Starting DNS reverse lookup\n");
2397   ppc->resolver_handle = GNUNET_RESOLVER_hostname_get (sb,
2398                                                        sbs,
2399                                                        ! numeric,
2400                                                        timeout,
2401                                                        &append_port,
2402                                                        ppc);
2403   if (NULL == ppc->resolver_handle)
2404   {
2405     GNUNET_break (0);
2406     GNUNET_free (ppc);
2407     return;
2408   }
2409   GNUNET_CONTAINER_DLL_insert (plugin->ppc_dll_head,
2410                                plugin->ppc_dll_tail,
2411                                ppc);
2412 }
2413
2414
2415 /**
2416  * Function that will be called to check if a binary address for this
2417  * plugin is well-formed and corresponds to an address for THIS peer
2418  * (as per our configuration).  Naturally, if absolutely necessary,
2419  * plugins can be a bit conservative in their answer, but in general
2420  * plugins should make sure that the address does not redirect
2421  * traffic to a 3rd party that might try to man-in-the-middle our
2422  * traffic.
2423  *
2424  * @param cls closure, our `struct Plugin *`
2425  * @param addr pointer to the address
2426  * @param addrlen length of @a addr
2427  * @return #GNUNET_OK if this is a plausible address for this peer
2428  *         and transport, #GNUNET_SYSERR if not
2429  */
2430 static int
2431 tcp_plugin_check_address (void *cls,
2432                           const void *addr,
2433                           size_t addrlen)
2434 {
2435   struct Plugin *plugin = cls;
2436   const struct IPv4TcpAddress *v4;
2437   const struct IPv6TcpAddress *v6;
2438
2439   if ( (addrlen != sizeof(struct IPv4TcpAddress)) &&
2440        (addrlen != sizeof(struct IPv6TcpAddress)) )
2441   {
2442     GNUNET_break_op (0);
2443     return GNUNET_SYSERR;
2444   }
2445
2446   if (addrlen == sizeof(struct IPv4TcpAddress))
2447   {
2448     struct sockaddr_in s4;
2449     
2450     v4 = (const struct IPv4TcpAddress *) addr;
2451     if (0 != memcmp (&v4->options,
2452                      &plugin->myoptions,
2453                      sizeof(uint32_t)))
2454     {
2455       GNUNET_break (0);
2456       return GNUNET_SYSERR;
2457     }
2458     memset (&s4, 0, sizeof (s4));
2459     s4.sin_family = AF_INET;
2460 #if HAVE_SOCKADDR_IN_SIN_LEN
2461     s4.sin_len = sizeof (s4);
2462 #endif
2463     s4.sin_port = v4->t4_port;
2464     s4.sin_addr.s_addr = v4->ipv4_addr;
2465     
2466     if (GNUNET_OK !=
2467         GNUNET_NAT_test_address (plugin->nat,
2468                                  &s4,
2469                                  sizeof (struct sockaddr_in)))
2470       return GNUNET_SYSERR;
2471   }
2472   else
2473   {
2474     struct sockaddr_in6 s6;
2475     
2476     v6 = (const struct IPv6TcpAddress *) addr;
2477     if (IN6_IS_ADDR_LINKLOCAL (&v6->ipv6_addr))
2478     {
2479       GNUNET_break_op (0);
2480       return GNUNET_SYSERR;
2481     }
2482     if (0 != memcmp (&v6->options,
2483                      &plugin->myoptions,
2484                      sizeof (uint32_t)))
2485     {
2486       GNUNET_break (0);
2487       return GNUNET_SYSERR;
2488     }
2489     memset (&s6, 0, sizeof (s6));
2490     s6.sin6_family = AF_INET6;
2491 #if HAVE_SOCKADDR_IN_SIN_LEN
2492     s6.sin6_len = sizeof (s6);
2493 #endif
2494     s6.sin6_port = v6->t6_port;
2495     s6.sin6_addr = v6->ipv6_addr;
2496
2497     if (GNUNET_OK !=
2498         GNUNET_NAT_test_address (plugin->nat,
2499                                  &s6,
2500                                  sizeof(struct sockaddr_in6)))
2501       return GNUNET_SYSERR;
2502   }
2503   return GNUNET_OK;
2504 }
2505
2506
2507 /**
2508  * We've received a nat probe from this peer via TCP.  Finish
2509  * creating the client session and resume sending of queued
2510  * messages.
2511  *
2512  * @param cls closure
2513  * @param client identification of the client
2514  * @param message the actual message
2515  */
2516 static void
2517 handle_tcp_nat_probe (void *cls,
2518                       struct GNUNET_SERVER_Client *client,
2519                       const struct GNUNET_MessageHeader *message)
2520 {
2521   struct Plugin *plugin = cls;
2522   struct GNUNET_ATS_Session *session;
2523   const struct TCP_NAT_ProbeMessage *tcp_nat_probe;
2524   size_t alen;
2525   void *vaddr;
2526   struct IPv4TcpAddress *t4;
2527   struct IPv6TcpAddress *t6;
2528   const struct sockaddr_in *s4;
2529   const struct sockaddr_in6 *s6;
2530
2531   LOG (GNUNET_ERROR_TYPE_DEBUG,
2532        "Received NAT probe\n");
2533   /* We have received a TCP NAT probe, meaning we (hopefully) initiated
2534    * a connection to this peer by running gnunet-nat-client.  This peer
2535    * received the punch message and now wants us to use the new connection
2536    * as the default for that peer.  Do so and then send a WELCOME message
2537    * so we can really be connected!
2538    */
2539   if (ntohs (message->size) != sizeof(struct TCP_NAT_ProbeMessage))
2540   {
2541     GNUNET_break_op(0);
2542     GNUNET_SERVER_receive_done (client,
2543                                 GNUNET_SYSERR);
2544     return;
2545   }
2546
2547   tcp_nat_probe = (const struct TCP_NAT_ProbeMessage *) message;
2548   if (0 == memcmp (&tcp_nat_probe->clientIdentity, plugin->env->my_identity,
2549           sizeof(struct GNUNET_PeerIdentity)))
2550   {
2551     /* refuse connections from ourselves */
2552     GNUNET_SERVER_receive_done (client,
2553                                 GNUNET_SYSERR);
2554     return;
2555   }
2556
2557   session = GNUNET_CONTAINER_multipeermap_get (plugin->nat_wait_conns,
2558                                                &tcp_nat_probe->clientIdentity);
2559   if (NULL == session)
2560   {
2561     LOG (GNUNET_ERROR_TYPE_DEBUG,
2562          "Did NOT find session for NAT probe!\n");
2563     GNUNET_SERVER_receive_done (client,
2564                                 GNUNET_OK);
2565     return;
2566   }
2567   LOG (GNUNET_ERROR_TYPE_DEBUG,
2568        "Found session for NAT probe!\n");
2569
2570   if (NULL != session->nat_connection_timeout)
2571   {
2572     GNUNET_SCHEDULER_cancel (session->nat_connection_timeout);
2573     session->nat_connection_timeout = NULL;
2574   }
2575
2576   if (GNUNET_OK !=
2577       GNUNET_SERVER_client_get_address (client,
2578                                         &vaddr,
2579                                         &alen))
2580   {
2581     GNUNET_break(0);
2582     GNUNET_SERVER_receive_done (client,
2583                                 GNUNET_SYSERR);
2584     tcp_plugin_disconnect_session (plugin,
2585                                    session);
2586     return;
2587   }
2588   GNUNET_assert (GNUNET_YES ==
2589                  GNUNET_CONTAINER_multipeermap_remove (plugin->nat_wait_conns,
2590                                                        &tcp_nat_probe->clientIdentity,
2591                                                        session));
2592   GNUNET_SERVER_client_set_user_context (client,
2593                                          session);
2594   (void) GNUNET_CONTAINER_multipeermap_put (plugin->sessionmap,
2595                                             &session->target,
2596                                             session,
2597                                             GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
2598   session->last_activity = GNUNET_TIME_absolute_get ();
2599   LOG (GNUNET_ERROR_TYPE_DEBUG,
2600        "Found address `%s' for incoming connection\n",
2601        GNUNET_a2s (vaddr, alen));
2602   switch (((const struct sockaddr *) vaddr)->sa_family)
2603   {
2604   case AF_INET:
2605     s4 = vaddr;
2606     t4 = GNUNET_new (struct IPv4TcpAddress);
2607     t4->options = htonl (TCP_OPTIONS_NONE);
2608     t4->t4_port = s4->sin_port;
2609     t4->ipv4_addr = s4->sin_addr.s_addr;
2610     session->address = GNUNET_HELLO_address_allocate (&tcp_nat_probe->clientIdentity,
2611                                                       PLUGIN_NAME,
2612                                                       &t4,
2613                                                       sizeof(struct IPv4TcpAddress),
2614                                                       GNUNET_HELLO_ADDRESS_INFO_NONE);
2615     break;
2616   case AF_INET6:
2617     s6 = vaddr;
2618     t6 = GNUNET_new (struct IPv6TcpAddress);
2619     t6->options = htonl (TCP_OPTIONS_NONE);
2620     t6->t6_port = s6->sin6_port;
2621     GNUNET_memcpy (&t6->ipv6_addr, &s6->sin6_addr, sizeof(struct in6_addr));
2622     session->address = GNUNET_HELLO_address_allocate (&tcp_nat_probe->clientIdentity,
2623                                                       PLUGIN_NAME,
2624                                                       &t6,
2625                                                       sizeof(struct IPv6TcpAddress),
2626                                                       GNUNET_HELLO_ADDRESS_INFO_NONE);
2627     break;
2628   default:
2629     GNUNET_break_op(0);
2630     LOG(GNUNET_ERROR_TYPE_DEBUG,
2631         "Bad address for incoming connection!\n");
2632     GNUNET_free(vaddr);
2633     GNUNET_SERVER_receive_done (client,
2634                                 GNUNET_SYSERR);
2635     tcp_plugin_disconnect_session (plugin,
2636                                    session);
2637     return;
2638   }
2639   GNUNET_free (vaddr);
2640   GNUNET_break (NULL == session->client);
2641   session->client = client;
2642   GNUNET_STATISTICS_update (plugin->env->stats,
2643                             gettext_noop ("# TCP sessions active"),
2644                             1,
2645                             GNUNET_NO);
2646   process_pending_messages (session);
2647   GNUNET_SERVER_receive_done (client,
2648                               GNUNET_OK);
2649 }
2650
2651
2652 /**
2653  * We've received a welcome from this peer via TCP.  Possibly create a
2654  * fresh client record and send back our welcome.
2655  *
2656  * @param cls closure
2657  * @param client identification of the client
2658  * @param message the actual message
2659  */
2660 static void
2661 handle_tcp_welcome (void *cls,
2662                     struct GNUNET_SERVER_Client *client,
2663                     const struct GNUNET_MessageHeader *message)
2664 {
2665   struct Plugin *plugin = cls;
2666   const struct WelcomeMessage *wm = (const struct WelcomeMessage *) message;
2667   struct GNUNET_HELLO_Address *address;
2668   struct GNUNET_ATS_Session *session;
2669   size_t alen;
2670   void *vaddr;
2671   struct IPv4TcpAddress t4;
2672   struct IPv6TcpAddress t6;
2673   const struct sockaddr_in *s4;
2674   const struct sockaddr_in6 *s6;
2675
2676   if (0 == memcmp (&wm->clientIdentity,
2677                    plugin->env->my_identity,
2678                    sizeof(struct GNUNET_PeerIdentity)))
2679   {
2680     /* refuse connections from ourselves */
2681     GNUNET_SERVER_receive_done (client,
2682                                 GNUNET_SYSERR);
2683     if (GNUNET_OK ==
2684         GNUNET_SERVER_client_get_address (client,
2685                                           &vaddr,
2686                                           &alen))
2687     {
2688       LOG (GNUNET_ERROR_TYPE_INFO,
2689            "Received WELCOME message from my own identity `%4s' on address `%s'\n",
2690            GNUNET_i2s (&wm->clientIdentity),
2691            GNUNET_a2s (vaddr, alen));
2692       GNUNET_free(vaddr);
2693     }
2694     return;
2695   }
2696
2697   LOG(GNUNET_ERROR_TYPE_DEBUG,
2698       "Received WELCOME message from `%4s' %p\n",
2699       GNUNET_i2s (&wm->clientIdentity),
2700       client);
2701   GNUNET_STATISTICS_update (plugin->env->stats,
2702                             gettext_noop ("# TCP WELCOME messages received"),
2703                             1,
2704                             GNUNET_NO);
2705   session = lookup_session_by_client (plugin, client);
2706   if (NULL != session)
2707   {
2708     if (GNUNET_OK ==
2709         GNUNET_SERVER_client_get_address (client, &vaddr, &alen))
2710     {
2711       LOG (GNUNET_ERROR_TYPE_DEBUG,
2712            "Found existing session %p for peer `%s'\n",
2713            session,
2714            GNUNET_a2s (vaddr, alen));
2715       GNUNET_free (vaddr);
2716     }
2717   }
2718   else
2719   {
2720     if (GNUNET_OK ==
2721         GNUNET_SERVER_client_get_address (client, &vaddr, &alen))
2722     {
2723       if (alen == sizeof(struct sockaddr_in))
2724       {
2725         s4 = vaddr;
2726         memset (&t4, '\0', sizeof (t4));
2727         t4.options = htonl (TCP_OPTIONS_NONE);
2728         t4.t4_port = s4->sin_port;
2729         t4.ipv4_addr = s4->sin_addr.s_addr;
2730         address = GNUNET_HELLO_address_allocate (&wm->clientIdentity,
2731                                                  PLUGIN_NAME,
2732                                                  &t4,
2733                                                  sizeof(t4),
2734                                                  GNUNET_HELLO_ADDRESS_INFO_INBOUND);
2735       }
2736       else if (alen == sizeof(struct sockaddr_in6))
2737       {
2738         s6 = vaddr;
2739         memset (&t6, '\0', sizeof (t6));
2740         t6.options = htonl (TCP_OPTIONS_NONE);
2741         t6.t6_port = s6->sin6_port;
2742         GNUNET_memcpy (&t6.ipv6_addr, &s6->sin6_addr, sizeof(struct in6_addr));
2743         address = GNUNET_HELLO_address_allocate (&wm->clientIdentity,
2744                                                  PLUGIN_NAME,
2745                                                  &t6,
2746                                                  sizeof (t6),
2747                                                  GNUNET_HELLO_ADDRESS_INFO_INBOUND);
2748       }
2749       else
2750       {
2751         GNUNET_break (0);
2752         GNUNET_free_non_null (vaddr);
2753         GNUNET_SERVER_receive_done (client,
2754                                     GNUNET_SYSERR);
2755         return;
2756       }
2757       session = create_session (plugin,
2758                                 address,
2759                                 plugin->env->get_address_type (plugin->env->cls,
2760                                                                vaddr,
2761                                                                alen),
2762                                 client,
2763                                 GNUNET_NO);
2764       GNUNET_break (GNUNET_ATS_NET_UNSPECIFIED != session->scope);
2765       GNUNET_HELLO_address_free (address);
2766       LOG (GNUNET_ERROR_TYPE_DEBUG,
2767            "Creating new%s session %p for peer `%s' client %p\n",
2768            GNUNET_HELLO_address_check_option (session->address,
2769                                               GNUNET_HELLO_ADDRESS_INFO_INBOUND)
2770            ? " inbound" : "",
2771            session,
2772            tcp_plugin_address_to_string (plugin,
2773                                          session->address->address,
2774                                          session->address->address_length),
2775            client);
2776       GNUNET_free (vaddr);
2777       (void) GNUNET_CONTAINER_multipeermap_put (plugin->sessionmap,
2778                                                 &session->target,
2779                                                 session,
2780                                                 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
2781       /* Notify transport and ATS about new session */
2782       plugin->env->session_start (plugin->env->cls,
2783                                   session->address,
2784                                   session,
2785                                   session->scope);
2786     }
2787     else
2788     {
2789       LOG(GNUNET_ERROR_TYPE_DEBUG,
2790           "Did not obtain TCP socket address for incoming connection\n");
2791       GNUNET_break(0);
2792       GNUNET_SERVER_receive_done (client,
2793                                   GNUNET_SYSERR);
2794       return;
2795     }
2796   }
2797
2798   if (session->expecting_welcome != GNUNET_YES)
2799   {
2800     GNUNET_break_op(0);
2801     GNUNET_SERVER_receive_done (client,
2802                                 GNUNET_SYSERR);
2803     GNUNET_break(0);
2804     return;
2805   }
2806   session->last_activity = GNUNET_TIME_absolute_get ();
2807   session->expecting_welcome = GNUNET_NO;
2808
2809   process_pending_messages (session);
2810   GNUNET_SERVER_client_set_timeout (client,
2811                                     GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2812   GNUNET_SERVER_receive_done (client,
2813                               GNUNET_OK);
2814 }
2815
2816
2817 /**
2818  * We've received data for this peer via TCP.  Unbox,
2819  * compute latency and forward.
2820  *
2821  * @param cls closure
2822  * @param client identification of the client
2823  * @param message the actual message
2824  */
2825 static void
2826 handle_tcp_data (void *cls,
2827                  struct GNUNET_SERVER_Client *client,
2828                  const struct GNUNET_MessageHeader *message)
2829 {
2830   struct Plugin *plugin = cls;
2831   struct GNUNET_ATS_Session *session;
2832   struct GNUNET_TIME_Relative delay;
2833   uint16_t type;
2834
2835   type = ntohs (message->type);
2836   if ( (GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_WELCOME == type) ||
2837        (GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_NAT_PROBE == type) )
2838   {
2839     /* We don't want to propagate WELCOME and NAT Probe messages up! */
2840     GNUNET_SERVER_receive_done (client,
2841                                 GNUNET_OK);
2842     return;
2843   }
2844   session = lookup_session_by_client (plugin, client);
2845   if (NULL == session)
2846   {
2847     /* No inbound session found */
2848     void *vaddr;
2849     size_t alen;
2850
2851     GNUNET_SERVER_client_get_address (client,
2852                                       &vaddr,
2853                                       &alen);
2854     LOG (GNUNET_ERROR_TYPE_ERROR,
2855          "Received unexpected %u bytes of type %u from `%s'\n",
2856          (unsigned int) ntohs (message->size),
2857          (unsigned int) ntohs (message->type),
2858          GNUNET_a2s (vaddr,
2859                      alen));
2860     GNUNET_break_op(0);
2861     GNUNET_SERVER_receive_done (client,
2862                                 GNUNET_SYSERR);
2863     GNUNET_free_non_null (vaddr);
2864     return;
2865   }
2866   if (GNUNET_YES == session->expecting_welcome)
2867   {
2868     /* Session is expecting WELCOME message */
2869     void *vaddr;
2870     size_t alen;
2871
2872     GNUNET_SERVER_client_get_address (client, &vaddr, &alen);
2873     LOG (GNUNET_ERROR_TYPE_ERROR,
2874          "Received unexpected %u bytes of type %u from `%s'\n",
2875          (unsigned int) ntohs (message->size),
2876          (unsigned int) ntohs (message->type),
2877          GNUNET_a2s (vaddr, alen));
2878     GNUNET_break_op(0);
2879     GNUNET_SERVER_receive_done (client,
2880                                 GNUNET_SYSERR);
2881     GNUNET_free_non_null (vaddr);
2882     return;
2883   }
2884
2885   session->last_activity = GNUNET_TIME_absolute_get ();
2886   LOG (GNUNET_ERROR_TYPE_DEBUG,
2887        "Passing %u bytes of type %u from `%4s' to transport service.\n",
2888        (unsigned int) ntohs (message->size),
2889        (unsigned int) ntohs (message->type),
2890        GNUNET_i2s (&session->target));
2891
2892   GNUNET_STATISTICS_update (plugin->env->stats,
2893                             gettext_noop ("# bytes received via TCP"),
2894                             ntohs (message->size),
2895                             GNUNET_NO);
2896
2897   GNUNET_assert (GNUNET_CONTAINER_multipeermap_contains_value (plugin->sessionmap,
2898                                                                &session->target,
2899                                                                session));
2900   delay = plugin->env->receive (plugin->env->cls,
2901                                 session->address,
2902                                 session,
2903                                 message);
2904   reschedule_session_timeout (session);
2905   if (0 == delay.rel_value_us)
2906   {
2907     GNUNET_SERVER_receive_done (client,
2908                                 GNUNET_OK);
2909   }
2910   else
2911   {
2912     LOG (GNUNET_ERROR_TYPE_DEBUG,
2913          "Throttling receiving from `%s' for %s\n",
2914          GNUNET_i2s (&session->target),
2915          GNUNET_STRINGS_relative_time_to_string (delay,
2916                                                  GNUNET_YES));
2917     GNUNET_SERVER_disable_receive_done_warning (client);
2918     GNUNET_assert (NULL == session->receive_delay_task);
2919     session->receive_delay_task = GNUNET_SCHEDULER_add_delayed (delay,
2920                                                                 &delayed_done,
2921                                                                 session);
2922   }
2923 }
2924
2925
2926 /**
2927  * Function called whenever a peer is connected on the "SERVER" level.
2928  * Increments number of active connections and suspends server if we
2929  * have reached the limit.
2930  *
2931  * @param cls closure
2932  * @param client identification of the client
2933  */
2934 static void
2935 connect_notify (void *cls,
2936                 struct GNUNET_SERVER_Client *client)
2937 {
2938   struct Plugin *plugin = cls;
2939
2940   if (NULL == client)
2941     return;
2942   plugin->cur_connections++;
2943   GNUNET_STATISTICS_set (plugin->env->stats,
2944                          gettext_noop ("# TCP server connections active"),
2945                          plugin->cur_connections,
2946                          GNUNET_NO);
2947   GNUNET_STATISTICS_update (plugin->env->stats,
2948                             gettext_noop ("# TCP server connect events"),
2949                             1,
2950                             GNUNET_NO);
2951   if (plugin->cur_connections != plugin->max_connections)
2952     return;
2953   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2954               _("TCP connection limit reached, suspending server\n"));
2955   GNUNET_STATISTICS_update (plugin->env->stats,
2956                             gettext_noop ("# TCP service suspended"),
2957                             1,
2958                             GNUNET_NO);
2959   GNUNET_SERVER_suspend (plugin->server); /* Maximum number of connections rechead */
2960 }
2961
2962
2963 /**
2964  * Function called whenever a peer is disconnected on the "SERVER"
2965  * level.  Cleans up the connection, decrements number of active
2966  * connections and if applicable resumes listening.
2967  *
2968  * @param cls closure
2969  * @param client identification of the client
2970  */
2971 static void
2972 disconnect_notify (void *cls,
2973                    struct GNUNET_SERVER_Client *client)
2974 {
2975   struct Plugin *plugin = cls;
2976   struct GNUNET_ATS_Session *session;
2977
2978   if (NULL == client)
2979     return;
2980   GNUNET_assert (plugin->cur_connections >= 1);
2981   plugin->cur_connections--;
2982   session = lookup_session_by_client (plugin,
2983                                       client);
2984   if (NULL == session)
2985     return; /* unknown, nothing to do */
2986   LOG (GNUNET_ERROR_TYPE_DEBUG,
2987        "Destroying session of `%4s' with %s due to network-level disconnect.\n",
2988        GNUNET_i2s (&session->target),
2989        tcp_plugin_address_to_string (session->plugin,
2990                                      session->address->address,
2991                                      session->address->address_length));
2992
2993   if (plugin->cur_connections == plugin->max_connections)
2994   {
2995     GNUNET_STATISTICS_update (session->plugin->env->stats,
2996                               gettext_noop ("# TCP service resumed"),
2997                               1,
2998                               GNUNET_NO);
2999     GNUNET_SERVER_resume (plugin->server); /* Resume server  */
3000   }
3001   GNUNET_STATISTICS_set (plugin->env->stats,
3002                          gettext_noop ("# TCP server connections active"),
3003                          plugin->cur_connections,
3004                          GNUNET_NO);
3005   GNUNET_STATISTICS_update (session->plugin->env->stats,
3006                             gettext_noop ("# network-level TCP disconnect events"),
3007                             1,
3008                             GNUNET_NO);
3009   tcp_plugin_disconnect_session (plugin,
3010                                  session);
3011 }
3012
3013
3014 /**
3015  * We can now send a probe message, copy into buffer to really send.
3016  *
3017  * @param cls closure, a `struct TCPProbeContext`
3018  * @param size max size to copy
3019  * @param buf buffer to copy message to
3020  * @return number of bytes copied into @a buf
3021  */
3022 static size_t
3023 notify_send_probe (void *cls,
3024                    size_t size,
3025                    void *buf)
3026 {
3027   struct TCPProbeContext *tcp_probe_ctx = cls;
3028   struct Plugin *plugin = tcp_probe_ctx->plugin;
3029   size_t ret;
3030
3031   tcp_probe_ctx->transmit_handle = NULL;
3032   GNUNET_CONTAINER_DLL_remove (plugin->probe_head,
3033                                plugin->probe_tail,
3034                                tcp_probe_ctx);
3035   if (NULL == buf)
3036   {
3037     GNUNET_CONNECTION_destroy (tcp_probe_ctx->sock);
3038     GNUNET_free(tcp_probe_ctx);
3039     return 0;
3040   }
3041   GNUNET_assert(size >= sizeof(tcp_probe_ctx->message));
3042   GNUNET_memcpy (buf,
3043           &tcp_probe_ctx->message,
3044           sizeof(tcp_probe_ctx->message));
3045   GNUNET_SERVER_connect_socket (tcp_probe_ctx->plugin->server,
3046                                 tcp_probe_ctx->sock);
3047   ret = sizeof(tcp_probe_ctx->message);
3048   GNUNET_free (tcp_probe_ctx);
3049   return ret;
3050 }
3051
3052
3053 /**
3054  * Function called by the NAT subsystem suggesting another peer wants
3055  * to connect to us via connection reversal.  Try to connect back to the
3056  * given IP.
3057  *
3058  * @param cls closure
3059  * @param addr address to try
3060  * @param addrlen number of bytes in @a addr
3061  */
3062 static void
3063 try_connection_reversal (void *cls,
3064                          const struct sockaddr *addr,
3065                          socklen_t addrlen)
3066 {
3067   struct Plugin *plugin = cls;
3068   struct GNUNET_CONNECTION_Handle *sock;
3069   struct TCPProbeContext *tcp_probe_ctx;
3070
3071   /**
3072    * We have received an ICMP response, ostensibly from a peer
3073    * that wants to connect to us! Send a message to establish a connection.
3074    */
3075   sock = GNUNET_CONNECTION_create_from_sockaddr (AF_INET,
3076                                                  addr,
3077                                                  addrlen);
3078   if (NULL == sock)
3079   {
3080     /* failed for some odd reason (out of sockets?); ignore attempt */
3081     return;
3082   }
3083
3084   tcp_probe_ctx = GNUNET_new (struct TCPProbeContext);
3085   tcp_probe_ctx->message.header.size
3086     = htons (sizeof (struct TCP_NAT_ProbeMessage));
3087   tcp_probe_ctx->message.header.type
3088     = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_NAT_PROBE);
3089   tcp_probe_ctx->message.clientIdentity
3090     = *plugin->env->my_identity;
3091   tcp_probe_ctx->plugin = plugin;
3092   tcp_probe_ctx->sock = sock;
3093   GNUNET_CONTAINER_DLL_insert (plugin->probe_head,
3094                                plugin->probe_tail,
3095                                tcp_probe_ctx);
3096   tcp_probe_ctx->transmit_handle
3097     = GNUNET_CONNECTION_notify_transmit_ready (sock,
3098                                                ntohs (tcp_probe_ctx->message.header.size),
3099                                                GNUNET_TIME_UNIT_FOREVER_REL,
3100                                                &notify_send_probe,
3101                                                tcp_probe_ctx);
3102 }
3103
3104
3105 /**
3106  * Function obtain the network type for a session
3107  *
3108  * @param cls closure (`struct Plugin *`)
3109  * @param session the session
3110  * @return the network type in HBO or #GNUNET_SYSERR
3111  */
3112 static enum GNUNET_ATS_Network_Type
3113 tcp_plugin_get_network (void *cls,
3114                         struct GNUNET_ATS_Session *session)
3115 {
3116   return session->scope;
3117 }
3118
3119
3120 /**
3121  * Function obtain the network type for an address.
3122  *
3123  * @param cls closure (`struct Plugin *`)
3124  * @param address the address
3125  * @return the network type
3126  */
3127 static enum GNUNET_ATS_Network_Type
3128 tcp_plugin_get_network_for_address (void *cls,
3129                                     const struct GNUNET_HELLO_Address *address)
3130 {
3131   struct Plugin *plugin = cls;
3132   size_t addrlen;
3133   struct sockaddr_in a4;
3134   struct sockaddr_in6 a6;
3135   const struct IPv4TcpAddress *t4;
3136   const struct IPv6TcpAddress *t6;
3137   const void *sb;
3138   size_t sbs;
3139
3140   addrlen = address->address_length;
3141   if (addrlen == sizeof(struct IPv6TcpAddress))
3142   {
3143     GNUNET_assert (NULL != address->address); /* make static analysis happy */
3144     t6 = address->address;
3145     memset (&a6, 0, sizeof(a6));
3146 #if HAVE_SOCKADDR_IN_SIN_LEN
3147     a6.sin6_len = sizeof (a6);
3148 #endif
3149     a6.sin6_family = AF_INET6;
3150     a6.sin6_port = t6->t6_port;
3151     GNUNET_memcpy (&a6.sin6_addr, &t6->ipv6_addr, sizeof(struct in6_addr));
3152     sb = &a6;
3153     sbs = sizeof(a6);
3154   }
3155   else if (addrlen == sizeof(struct IPv4TcpAddress))
3156   {
3157     GNUNET_assert (NULL != address->address); /* make static analysis happy */
3158     t4 = address->address;
3159     memset (&a4, 0, sizeof(a4));
3160 #if HAVE_SOCKADDR_IN_SIN_LEN
3161     a4.sin_len = sizeof (a4);
3162 #endif
3163     a4.sin_family = AF_INET;
3164     a4.sin_port = t4->t4_port;
3165     a4.sin_addr.s_addr = t4->ipv4_addr;
3166     sb = &a4;
3167     sbs = sizeof(a4);
3168   }
3169   else
3170   {
3171     GNUNET_break (0);
3172     return GNUNET_ATS_NET_UNSPECIFIED;
3173   }
3174   return plugin->env->get_address_type (plugin->env->cls,
3175                                         sb,
3176                                         sbs);
3177 }
3178
3179
3180 /**
3181  * Return information about the given session to the
3182  * monitor callback.
3183  *
3184  * @param cls the `struct Plugin` with the monitor callback (`sic`)
3185  * @param peer peer we send information about
3186  * @param value our `struct GNUNET_ATS_Session` to send information about
3187  * @return #GNUNET_OK (continue to iterate)
3188  */
3189 static int
3190 send_session_info_iter (void *cls,
3191                         const struct GNUNET_PeerIdentity *peer,
3192                         void *value)
3193 {
3194   struct Plugin *plugin = cls;
3195   struct GNUNET_ATS_Session *session = value;
3196
3197   notify_session_monitor (plugin,
3198                           session,
3199                           GNUNET_TRANSPORT_SS_INIT);
3200   /* FIXME: cannot tell if this is up or not from current
3201      session state... */
3202   notify_session_monitor (plugin,
3203                           session,
3204                           GNUNET_TRANSPORT_SS_UP);
3205   return GNUNET_OK;
3206 }
3207
3208
3209 /**
3210  * Begin monitoring sessions of a plugin.  There can only
3211  * be one active monitor per plugin (i.e. if there are
3212  * multiple monitors, the transport service needs to
3213  * multiplex the generated events over all of them).
3214  *
3215  * @param cls closure of the plugin
3216  * @param sic callback to invoke, NULL to disable monitor;
3217  *            plugin will being by iterating over all active
3218  *            sessions immediately and then enter monitor mode
3219  * @param sic_cls closure for @a sic
3220  */
3221 static void
3222 tcp_plugin_setup_monitor (void *cls,
3223                           GNUNET_TRANSPORT_SessionInfoCallback sic,
3224                           void *sic_cls)
3225 {
3226   struct Plugin *plugin = cls;
3227
3228   plugin->sic = sic;
3229   plugin->sic_cls = sic_cls;
3230   if (NULL != sic)
3231   {
3232     GNUNET_CONTAINER_multipeermap_iterate (plugin->sessionmap,
3233                                            &send_session_info_iter,
3234                                            plugin);
3235     /* signal end of first iteration */
3236     sic (sic_cls, NULL, NULL);
3237   }
3238 }
3239
3240
3241 /**
3242  * Entry point for the plugin.
3243  *
3244  * @param cls closure, the `struct GNUNET_TRANSPORT_PluginEnvironment *`
3245  * @return the `struct GNUNET_TRANSPORT_PluginFunctions *` or NULL on error
3246  */
3247 void *
3248 libgnunet_plugin_transport_tcp_init (void *cls)
3249 {
3250   static const struct GNUNET_SERVER_MessageHandler my_handlers[] = {
3251     { &handle_tcp_welcome, NULL,
3252       GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_WELCOME,
3253       sizeof(struct WelcomeMessage) },
3254     { &handle_tcp_nat_probe, NULL,
3255       GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_NAT_PROBE,
3256       sizeof(struct TCP_NAT_ProbeMessage) },
3257     { &handle_tcp_data, NULL,
3258       GNUNET_MESSAGE_TYPE_ALL, 0 },
3259     { NULL, NULL, 0, 0 }
3260   };
3261   struct GNUNET_TRANSPORT_PluginEnvironment *env = cls;
3262   struct GNUNET_TRANSPORT_PluginFunctions *api;
3263   struct Plugin *plugin;
3264   struct GNUNET_SERVICE_Context *service;
3265   unsigned long long aport;
3266   unsigned long long bport;
3267   unsigned long long max_connections;
3268   unsigned int i;
3269   struct GNUNET_TIME_Relative idle_timeout;
3270 #ifdef TCP_STEALTH
3271   struct GNUNET_NETWORK_Handle *const*lsocks;
3272 #endif
3273   int ret;
3274   int ret_s;
3275   struct sockaddr **addrs;
3276   socklen_t *addrlens;
3277
3278   if (NULL == env->receive)
3279   {
3280     /* run in 'stub' mode (i.e. as part of gnunet-peerinfo), don't fully
3281      initialze the plugin or the API */
3282     api = GNUNET_new (struct GNUNET_TRANSPORT_PluginFunctions);
3283     api->cls = NULL;
3284     api->address_pretty_printer = &tcp_plugin_address_pretty_printer;
3285     api->address_to_string = &tcp_plugin_address_to_string;
3286     api->string_to_address = &tcp_plugin_string_to_address;
3287     return api;
3288   }
3289
3290   GNUNET_assert (NULL != env->cfg);
3291   if (GNUNET_OK !=
3292       GNUNET_CONFIGURATION_get_value_number (env->cfg,
3293                                              "transport-tcp",
3294                                              "MAX_CONNECTIONS",
3295                                              &max_connections))
3296     max_connections = 128;
3297
3298   aport = 0;
3299   if ((GNUNET_OK !=
3300        GNUNET_CONFIGURATION_get_value_number (env->cfg, "transport-tcp",
3301                                               "PORT", &bport)) ||
3302       (bport > 65535) ||
3303       ((GNUNET_OK ==
3304         GNUNET_CONFIGURATION_get_value_number (env->cfg, "transport-tcp",
3305                                                "ADVERTISED-PORT", &aport)) &&
3306        (aport > 65535) ))
3307   {
3308     LOG(GNUNET_ERROR_TYPE_ERROR,
3309         _("Require valid port number for service `%s' in configuration!\n"),
3310         "transport-tcp");
3311     return NULL ;
3312   }
3313   if (0 == aport)
3314     aport = bport;
3315   if (0 == bport)
3316     aport = 0;
3317   if (0 != bport)
3318   {
3319     service = GNUNET_SERVICE_start ("transport-tcp",
3320                                     env->cfg,
3321                                     GNUNET_SERVICE_OPTION_NONE);
3322     if (NULL == service)
3323     {
3324       LOG (GNUNET_ERROR_TYPE_WARNING,
3325            _("Failed to start service.\n"));
3326       return NULL;
3327     }
3328   }
3329   else
3330     service = NULL;
3331
3332   api = NULL;
3333   plugin = GNUNET_new (struct Plugin);
3334   plugin->sessionmap = GNUNET_CONTAINER_multipeermap_create (max_connections,
3335                                                              GNUNET_YES);
3336   plugin->max_connections = max_connections;
3337   plugin->open_port = bport;
3338   plugin->adv_port = aport;
3339   plugin->env = env;
3340   plugin->my_welcome.header.size = htons (sizeof(struct WelcomeMessage));
3341   plugin->my_welcome.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_WELCOME);
3342   plugin->my_welcome.clientIdentity = *plugin->env->my_identity;
3343
3344   if ( (NULL != service) &&
3345        (GNUNET_YES ==
3346         GNUNET_CONFIGURATION_get_value_yesno (env->cfg,
3347                                               "transport-tcp",
3348                                               "TCP_STEALTH")) )
3349   {
3350 #ifdef TCP_STEALTH
3351     plugin->myoptions |= TCP_OPTIONS_TCP_STEALTH;
3352     lsocks = GNUNET_SERVICE_get_listen_sockets (service);
3353     if (NULL != lsocks)
3354     {
3355       uint32_t len = sizeof (struct WelcomeMessage);
3356
3357       for (i=0;NULL!=lsocks[i];i++)
3358       {
3359         if ( (GNUNET_OK !=
3360               GNUNET_NETWORK_socket_setsockopt (lsocks[i],
3361                                                 IPPROTO_TCP,
3362                                                 TCP_STEALTH,
3363                                                 env->my_identity,
3364                                                 sizeof (struct GNUNET_PeerIdentity))) ||
3365              (GNUNET_OK !=
3366               GNUNET_NETWORK_socket_setsockopt (lsocks[i],
3367                                                 IPPROTO_TCP,
3368                                                 TCP_STEALTH_INTEGRITY_LEN,
3369                                                 &len,
3370                                                 sizeof (len))) )
3371         {
3372           /* TCP STEALTH not supported by kernel */
3373           GNUNET_assert (0 == i);
3374           GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3375                       _("TCP_STEALTH not supported on this platform.\n"));
3376           goto die;
3377         }
3378       }
3379     }
3380 #else
3381     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3382                 _("TCP_STEALTH not supported on this platform.\n"));
3383     goto die;
3384 #endif
3385   }
3386
3387   if ( (NULL != service) &&
3388        (GNUNET_SYSERR !=
3389         (ret_s =
3390          get_server_addresses ("transport-tcp",
3391                                env->cfg,
3392                                &addrs,
3393                                &addrlens))))
3394   {
3395     for (ret = ret_s-1; ret >= 0; ret--)
3396       LOG (GNUNET_ERROR_TYPE_INFO,
3397            "Binding to address `%s'\n",
3398            GNUNET_a2s (addrs[ret], addrlens[ret]));
3399     plugin->nat
3400       = GNUNET_NAT_register (env->cfg,
3401                              "transport-tcp",
3402                              IPPROTO_TCP,
3403                              (unsigned int) ret_s,
3404                              (const struct sockaddr **) addrs,
3405                              addrlens,
3406                              &tcp_nat_port_map_callback,
3407                              &try_connection_reversal,
3408                              plugin);
3409     for (ret = ret_s -1; ret >= 0; ret--)
3410       GNUNET_free (addrs[ret]);
3411     GNUNET_free_non_null (addrs);
3412     GNUNET_free_non_null (addrlens);
3413   }
3414   else
3415   {
3416     plugin->nat = GNUNET_NAT_register (plugin->env->cfg,
3417                                        "transport-tcp",
3418                                        IPPROTO_TCP,
3419                                        0,
3420                                        NULL,
3421                                        NULL,
3422                                        NULL,
3423                                        &try_connection_reversal,
3424                                        plugin);
3425   }
3426   api = GNUNET_new (struct GNUNET_TRANSPORT_PluginFunctions);
3427   api->cls = plugin;
3428   api->send = &tcp_plugin_send;
3429   api->get_session = &tcp_plugin_get_session;
3430   api->disconnect_session = &tcp_plugin_disconnect_session;
3431   api->query_keepalive_factor = &tcp_plugin_query_keepalive_factor;
3432   api->disconnect_peer = &tcp_plugin_disconnect;
3433   api->address_pretty_printer = &tcp_plugin_address_pretty_printer;
3434   api->check_address = &tcp_plugin_check_address;
3435   api->address_to_string = &tcp_plugin_address_to_string;
3436   api->string_to_address = &tcp_plugin_string_to_address;
3437   api->get_network = &tcp_plugin_get_network;
3438   api->get_network_for_address = &tcp_plugin_get_network_for_address;
3439   api->update_session_timeout = &tcp_plugin_update_session_timeout;
3440   api->update_inbound_delay = &tcp_plugin_update_inbound_delay;
3441   api->setup_monitor = &tcp_plugin_setup_monitor;
3442   plugin->service = service;
3443   if (NULL != service)
3444   {
3445     plugin->server = GNUNET_SERVICE_get_server (service);
3446   }
3447   else
3448   {
3449     if (GNUNET_OK !=
3450         GNUNET_CONFIGURATION_get_value_time (env->cfg,
3451                                              "transport-tcp",
3452                                              "TIMEOUT",
3453                                              &idle_timeout))
3454     {
3455       GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
3456                                  "transport-tcp",
3457                                  "TIMEOUT");
3458       goto die;
3459     }
3460     plugin->server
3461       = GNUNET_SERVER_create_with_sockets (NULL,
3462                                            plugin,
3463                                            NULL,
3464                                            idle_timeout,
3465                                            GNUNET_YES);
3466   }
3467   plugin->handlers = GNUNET_malloc (sizeof (my_handlers));
3468   GNUNET_memcpy (plugin->handlers,
3469                  my_handlers,
3470                  sizeof(my_handlers));
3471   for (i = 0;i < sizeof(my_handlers) / sizeof(struct GNUNET_SERVER_MessageHandler);i++)
3472     plugin->handlers[i].callback_cls = plugin;
3473
3474   GNUNET_SERVER_add_handlers (plugin->server,
3475                               plugin->handlers);
3476   GNUNET_SERVER_connect_notify (plugin->server,
3477                                 &connect_notify,
3478                                 plugin);
3479   GNUNET_SERVER_disconnect_notify (plugin->server,
3480                                    &disconnect_notify,
3481                                    plugin);
3482   plugin->nat_wait_conns = GNUNET_CONTAINER_multipeermap_create (16,
3483                                                                  GNUNET_YES);
3484   if (0 != bport)
3485     LOG (GNUNET_ERROR_TYPE_INFO,
3486          _("TCP transport listening on port %llu\n"),
3487          bport);
3488   else
3489     LOG (GNUNET_ERROR_TYPE_INFO,
3490          _("TCP transport not listening on any port (client only)\n"));
3491   if ( (aport != bport) &&
3492        (0 != bport) )
3493     LOG (GNUNET_ERROR_TYPE_INFO,
3494          _("TCP transport advertises itself as being on port %llu\n"),
3495          aport);
3496   /* Initially set connections to 0 */
3497   GNUNET_STATISTICS_set (plugin->env->stats,
3498                          gettext_noop ("# TCP sessions active"),
3499                          0,
3500                          GNUNET_NO);
3501   return api;
3502
3503  die:
3504   if (NULL != plugin->nat)
3505     GNUNET_NAT_unregister (plugin->nat);
3506   GNUNET_CONTAINER_multipeermap_destroy (plugin->sessionmap);
3507   if (NULL != service)
3508     GNUNET_SERVICE_stop (service);
3509   GNUNET_free (plugin);
3510   GNUNET_free_non_null (api);
3511   return NULL;
3512 }
3513
3514
3515 /**
3516  * Exit point from the plugin.
3517  *
3518  * @param cls the `struct GNUNET_TRANSPORT_PluginFunctions`
3519  * @return NULL
3520  */
3521 void *
3522 libgnunet_plugin_transport_tcp_done (void *cls)
3523 {
3524   struct GNUNET_TRANSPORT_PluginFunctions *api = cls;
3525   struct Plugin *plugin = api->cls;
3526   struct TCPProbeContext *tcp_probe;
3527   struct PrettyPrinterContext *cur;
3528   struct PrettyPrinterContext *next;
3529
3530   if (NULL == plugin)
3531   {
3532     GNUNET_free(api);
3533     return NULL ;
3534   }
3535   LOG (GNUNET_ERROR_TYPE_DEBUG,
3536        "Shutting down TCP plugin\n");
3537
3538   /* Removing leftover sessions */
3539   GNUNET_CONTAINER_multipeermap_iterate (plugin->sessionmap,
3540                                          &session_disconnect_it,
3541                                          plugin);
3542   /* Removing leftover NAT sessions */
3543   GNUNET_CONTAINER_multipeermap_iterate (plugin->nat_wait_conns,
3544                                          &session_disconnect_it,
3545                                          plugin);
3546
3547   for (cur = plugin->ppc_dll_head; NULL != cur; cur = next)
3548   {
3549     next = cur->next;
3550     GNUNET_CONTAINER_DLL_remove (plugin->ppc_dll_head,
3551                                  plugin->ppc_dll_tail,
3552                                  cur);
3553     GNUNET_RESOLVER_request_cancel (cur->resolver_handle);
3554     cur->asc (cur->asc_cls,
3555               NULL,
3556               GNUNET_OK);
3557     GNUNET_free (cur);
3558   }
3559
3560   if (NULL != plugin->service)
3561     GNUNET_SERVICE_stop (plugin->service);
3562   else
3563     GNUNET_SERVER_destroy (plugin->server);
3564   GNUNET_free (plugin->handlers);
3565   if (NULL != plugin->nat)
3566     GNUNET_NAT_unregister (plugin->nat);
3567   while (NULL != (tcp_probe = plugin->probe_head))
3568   {
3569     GNUNET_CONTAINER_DLL_remove (plugin->probe_head,
3570                                  plugin->probe_tail,
3571                                  tcp_probe);
3572     GNUNET_CONNECTION_destroy (tcp_probe->sock);
3573     GNUNET_free (tcp_probe);
3574   }
3575   GNUNET_CONTAINER_multipeermap_destroy (plugin->nat_wait_conns);
3576   GNUNET_CONTAINER_multipeermap_destroy (plugin->sessionmap);
3577   GNUNET_break (0 == plugin->cur_connections);
3578   GNUNET_free (plugin);
3579   GNUNET_free (api);
3580   return NULL;
3581 }
3582
3583 /* end of plugin_transport_tcp.c */