last step to new cadet api
[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_UN_SUN_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 `%s' 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 `%s', 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 `%s'.\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     /* This is a bit of a hack, limiting TCP to never allow more than
2001        one TCP connection to any given peer at the same time.
2002        Without this, peers sometimes disagree about which of the TCP
2003        connections they should use, causing one side to believe that
2004        they transmit successfully, while the other receives nothing. */
2005     return NULL; /* Refuse to have more than one TCP connection per
2006                     peer pair at the same time. */
2007   }
2008
2009   if (addrlen == sizeof(struct IPv6TcpAddress))
2010   {
2011     GNUNET_assert (NULL != address->address); /* make static analysis happy */
2012     t6 = address->address;
2013     options = t6->options;
2014     af = AF_INET6;
2015     memset (&a6, 0, sizeof(a6));
2016 #if HAVE_SOCKADDR_IN_SIN_LEN
2017     a6.sin6_len = sizeof (a6);
2018 #endif
2019     a6.sin6_family = AF_INET6;
2020     a6.sin6_port = t6->t6_port;
2021     if (t6->t6_port == 0)
2022       is_natd = GNUNET_YES;
2023     GNUNET_memcpy (&a6.sin6_addr, &t6->ipv6_addr, sizeof(struct in6_addr));
2024     sb = &a6;
2025     sbs = sizeof(a6);
2026   }
2027   else if (addrlen == sizeof(struct IPv4TcpAddress))
2028   {
2029     GNUNET_assert(NULL != address->address); /* make static analysis happy */
2030     t4 = address->address;
2031     options = t4->options;
2032     af = AF_INET;
2033     memset (&a4, 0, sizeof(a4));
2034 #if HAVE_SOCKADDR_IN_SIN_LEN
2035     a4.sin_len = sizeof (a4);
2036 #endif
2037     a4.sin_family = AF_INET;
2038     a4.sin_port = t4->t4_port;
2039     if (t4->t4_port == 0)
2040       is_natd = GNUNET_YES;
2041     a4.sin_addr.s_addr = t4->ipv4_addr;
2042     sb = &a4;
2043     sbs = sizeof(a4);
2044   }
2045   else
2046   {
2047     GNUNET_STATISTICS_update (plugin->env->stats,
2048                               gettext_noop ("# requests to create session with invalid address"),
2049                               1,
2050                               GNUNET_NO);
2051     return NULL;
2052   }
2053
2054   net_type = plugin->env->get_address_type (plugin->env->cls,
2055                                             sb,
2056                                             sbs);
2057   GNUNET_break (net_type != GNUNET_ATS_NET_UNSPECIFIED);
2058
2059   if ( (is_natd == GNUNET_YES) &&
2060        (addrlen == sizeof(struct IPv6TcpAddress)) )
2061   {
2062     /* NAT client only works with IPv4 addresses */
2063     return NULL;
2064   }
2065
2066   if (plugin->cur_connections >= plugin->max_connections)
2067   {
2068     /* saturated */
2069     return NULL;
2070   }
2071
2072   if ( (is_natd == GNUNET_YES) &&
2073        (GNUNET_YES ==
2074         GNUNET_CONTAINER_multipeermap_contains (plugin->nat_wait_conns,
2075                                                 &address->peer)))
2076   {
2077     /* Only do one NAT punch attempt per peer identity */
2078     return NULL;
2079   }
2080
2081   if ( (is_natd == GNUNET_YES) &&
2082        (NULL != plugin->nat) &&
2083        (GNUNET_NO ==
2084         GNUNET_CONTAINER_multipeermap_contains (plugin->nat_wait_conns,
2085                                                 &address->peer)))
2086   {
2087     struct sockaddr_in local_sa;
2088
2089     LOG (GNUNET_ERROR_TYPE_DEBUG,
2090          "Found valid IPv4 NAT address (creating session)!\n");
2091     session = create_session (plugin,
2092                               address,
2093                               net_type,
2094                               NULL,
2095                               GNUNET_YES);
2096     session->nat_connection_timeout = GNUNET_SCHEDULER_add_delayed (NAT_TIMEOUT,
2097                                                                     &nat_connect_timeout,
2098                                                                     session);
2099     GNUNET_assert (GNUNET_OK ==
2100                    GNUNET_CONTAINER_multipeermap_put (plugin->nat_wait_conns,
2101                                                       &session->target,
2102                                                       session,
2103                                                       GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
2104
2105     LOG (GNUNET_ERROR_TYPE_DEBUG,
2106          "Created NAT WAIT connection to `%s' at `%s'\n",
2107          GNUNET_i2s (&session->target),
2108          GNUNET_a2s (sb, sbs));
2109     memset (&local_sa,
2110             0,
2111             sizeof (local_sa));
2112     local_sa.sin_family = AF_INET;
2113     local_sa.sin_port = htons (plugin->open_port);
2114     /* We leave sin_address at 0, let the kernel figure it out,
2115        even if our bind() is more specific.  (May want to reconsider
2116        later.) */
2117     if (GNUNET_OK ==
2118         GNUNET_NAT_request_reversal (plugin->nat,
2119                                      &local_sa,
2120                                      &a4))
2121       return session;
2122     LOG (GNUNET_ERROR_TYPE_DEBUG,
2123          "Running NAT client for `%s' at `%s' failed\n",
2124          GNUNET_i2s (&session->target),
2125          GNUNET_a2s (sb, sbs));
2126     tcp_plugin_disconnect_session (plugin,
2127                                    session);
2128     return NULL;
2129   }
2130
2131   /* create new outbound session */
2132   if (0 != (options & TCP_OPTIONS_TCP_STEALTH))
2133   {
2134 #ifdef TCP_STEALTH
2135     s = GNUNET_NETWORK_socket_create (af, SOCK_STREAM, 0);
2136     if (NULL == s)
2137     {
2138       GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK,
2139                            "socket");
2140       sa = NULL;
2141     }
2142     else
2143     {
2144       if ( (GNUNET_OK !=
2145             GNUNET_NETWORK_socket_setsockopt (s,
2146                                               IPPROTO_TCP,
2147                                               TCP_STEALTH,
2148                                               &session->target,
2149                                               sizeof (struct GNUNET_PeerIdentity))) ||
2150            (GNUNET_OK !=
2151             GNUNET_NETWORK_socket_setsockopt (s,
2152                                               IPPROTO_TCP,
2153                                               TCP_STEALTH_INTEGRITY,
2154                                               &plugin->my_welcome,
2155                                               sizeof (struct WelcomeMessage))) )
2156       {
2157         /* TCP STEALTH not supported by kernel */
2158         GNUNET_break (GNUNET_OK ==
2159                       GNUNET_NETWORK_socket_close (s));
2160         sa = NULL;
2161       }
2162       else
2163       {
2164         sa = GNUNET_CONNECTION_connect_socket (s, sb, sbs);
2165       }
2166     }
2167 #else
2168     sa = NULL;
2169 #endif
2170   }
2171   else
2172   {
2173     sa = GNUNET_CONNECTION_create_from_sockaddr (af, sb, sbs);
2174   }
2175   if (NULL == sa)
2176   {
2177     LOG (GNUNET_ERROR_TYPE_DEBUG,
2178          "Failed to create connection to `%s' at `%s'\n",
2179          GNUNET_i2s (&address->peer),
2180          GNUNET_a2s (sb, sbs));
2181     return NULL;
2182   }
2183   LOG (GNUNET_ERROR_TYPE_DEBUG,
2184        "Asked to transmit to `%s', creating fresh session using address `%s'.\n",
2185        GNUNET_i2s (&address->peer),
2186        GNUNET_a2s (sb, sbs));
2187
2188   session = create_session (plugin,
2189                             address,
2190                             net_type,
2191                             GNUNET_SERVER_connect_socket (plugin->server,
2192                                                           sa),
2193                             GNUNET_NO);
2194   (void) GNUNET_CONTAINER_multipeermap_put (plugin->sessionmap,
2195                                             &session->target,
2196                                             session,
2197                                             GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
2198   /* Send TCP Welcome */
2199   process_pending_messages (session);
2200
2201   return session;
2202 }
2203
2204
2205 /**
2206  * We have been asked to destroy all connections to a particular peer.
2207  * This function is called on each applicable session and must tear it
2208  * down.
2209  *
2210  * @param cls the `struct Plugin *`
2211  * @param key the peer which the session belongs to (unused)
2212  * @param value the `struct GNUNET_ATS_Session`
2213  * @return #GNUNET_YES (continue to iterate)
2214  */
2215 static int
2216 session_disconnect_it (void *cls,
2217                        const struct GNUNET_PeerIdentity *key,
2218                        void *value)
2219 {
2220   struct Plugin *plugin = cls;
2221   struct GNUNET_ATS_Session *session = value;
2222
2223   GNUNET_STATISTICS_update (session->plugin->env->stats,
2224                             gettext_noop ("# transport-service disconnect requests for TCP"),
2225                             1,
2226                             GNUNET_NO);
2227   tcp_plugin_disconnect_session (plugin,
2228                                  session);
2229   return GNUNET_YES;
2230 }
2231
2232
2233 /**
2234  * Function that can be called to force a disconnect from the
2235  * specified neighbour.  This should also cancel all previously
2236  * scheduled transmissions.  Obviously the transmission may have been
2237  * partially completed already, which is OK.  The plugin is supposed
2238  * to close the connection (if applicable) and no longer call the
2239  * transmit continuation(s).
2240  *
2241  * Finally, plugin MUST NOT call the services's receive function to
2242  * notify the service that the connection to the specified target was
2243  * closed after a getting this call.
2244  *
2245  * @param cls closure
2246  * @param target peer for which the last transmission is
2247  *        to be cancelled
2248  */
2249 static void
2250 tcp_plugin_disconnect (void *cls,
2251                        const struct GNUNET_PeerIdentity *target)
2252 {
2253   struct Plugin *plugin = cls;
2254
2255   LOG (GNUNET_ERROR_TYPE_DEBUG,
2256        "Disconnecting peer `%s'\n",
2257        GNUNET_i2s (target));
2258   GNUNET_CONTAINER_multipeermap_get_multiple (plugin->sessionmap,
2259                                               target,
2260                                               &session_disconnect_it,
2261                                               plugin);
2262   GNUNET_CONTAINER_multipeermap_get_multiple (plugin->nat_wait_conns,
2263                                               target,
2264                                               &session_disconnect_it,
2265                                               plugin);
2266 }
2267
2268
2269 /**
2270  * We are processing an address pretty printing request and finished
2271  * the IP resolution (if applicable).  Append our port and forward the
2272  * result.  If called with @a hostname NULL, we are done and should
2273  * clean up the pretty printer (otherwise, there might be multiple
2274  * hostnames for the IP address and we might receive more).
2275  *
2276  * @param cls the `struct PrettyPrinterContext *`
2277  * @param hostname hostname part of the address
2278  */
2279 static void
2280 append_port (void *cls,
2281              const char *hostname)
2282 {
2283   struct PrettyPrinterContext *ppc = cls;
2284   struct Plugin *plugin = ppc->plugin;
2285   char *ret;
2286
2287   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2288               "append_port called with hostname `%s'\n",
2289               hostname);
2290   if (NULL == hostname)
2291   {
2292     /* Final call, done */
2293     ppc->resolver_handle = NULL;
2294     GNUNET_CONTAINER_DLL_remove (plugin->ppc_dll_head,
2295                                  plugin->ppc_dll_tail,
2296                                  ppc);
2297     ppc->asc (ppc->asc_cls,
2298               NULL,
2299               GNUNET_OK);
2300     GNUNET_free (ppc);
2301     return;
2302   }
2303   if (GNUNET_YES == ppc->ipv6)
2304     GNUNET_asprintf (&ret,
2305                      "%s.%u.[%s]:%d",
2306                      PLUGIN_NAME,
2307                      ppc->options,
2308                      hostname,
2309                      ppc->port);
2310   else
2311     GNUNET_asprintf (&ret,
2312                      "%s.%u.%s:%d",
2313                      PLUGIN_NAME,
2314                      ppc->options,
2315                      hostname,
2316                      ppc->port);
2317   ppc->asc (ppc->asc_cls,
2318             ret,
2319             GNUNET_OK);
2320   GNUNET_free (ret);
2321 }
2322
2323
2324 /**
2325  * Convert the transports address to a nice, human-readable format.
2326  *
2327  * @param cls closure with the `struct Plugin`
2328  * @param type name of the transport that generated the address
2329  * @param addr one of the addresses of the host, NULL for the last address
2330  *        the specific address format depends on the transport
2331  * @param addrlen length of the @a addr
2332  * @param numeric should (IP) addresses be displayed in numeric form?
2333  * @param timeout after how long should we give up?
2334  * @param asc function to call on each string
2335  * @param asc_cls closure for @a asc
2336  */
2337 static void
2338 tcp_plugin_address_pretty_printer (void *cls,
2339                                    const char *type,
2340                                    const void *addr,
2341                                    size_t addrlen,
2342                                    int numeric,
2343                                    struct GNUNET_TIME_Relative timeout,
2344                                    GNUNET_TRANSPORT_AddressStringCallback asc,
2345                                    void *asc_cls)
2346 {
2347   struct Plugin *plugin = cls;
2348   struct PrettyPrinterContext *ppc;
2349   const void *sb;
2350   size_t sbs;
2351   struct sockaddr_in a4;
2352   struct sockaddr_in6 a6;
2353   const struct IPv4TcpAddress *t4;
2354   const struct IPv6TcpAddress *t6;
2355   uint16_t port;
2356   uint32_t options;
2357
2358   if (sizeof(struct IPv6TcpAddress) == addrlen)
2359   {
2360     t6 = addr;
2361     memset (&a6, 0, sizeof(a6));
2362     a6.sin6_family = AF_INET6;
2363     a6.sin6_port = t6->t6_port;
2364     GNUNET_memcpy (&a6.sin6_addr, &t6->ipv6_addr, sizeof(struct in6_addr));
2365     port = ntohs (t6->t6_port);
2366     options = ntohl (t6->options);
2367     sb = &a6;
2368     sbs = sizeof(a6);
2369   }
2370   else if (sizeof(struct IPv4TcpAddress) == addrlen)
2371   {
2372     t4 = addr;
2373     memset (&a4, 0, sizeof(a4));
2374     a4.sin_family = AF_INET;
2375     a4.sin_port = t4->t4_port;
2376     a4.sin_addr.s_addr = t4->ipv4_addr;
2377     port = ntohs (t4->t4_port);
2378     options = ntohl (t4->options);
2379     sb = &a4;
2380     sbs = sizeof(a4);
2381   }
2382   else
2383   {
2384     /* invalid address */
2385     LOG (GNUNET_ERROR_TYPE_WARNING,
2386          _("Unexpected address length: %u bytes\n"),
2387          (unsigned int) addrlen);
2388     asc (asc_cls, NULL, GNUNET_SYSERR);
2389     asc (asc_cls, NULL, GNUNET_OK);
2390     return;
2391   }
2392   ppc = GNUNET_new (struct PrettyPrinterContext);
2393   ppc->plugin = plugin;
2394   if (addrlen == sizeof(struct IPv6TcpAddress))
2395     ppc->ipv6 = GNUNET_YES;
2396   else
2397     ppc->ipv6 = GNUNET_NO;
2398   ppc->asc = asc;
2399   ppc->asc_cls = asc_cls;
2400   ppc->port = port;
2401   ppc->options = options;
2402   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2403               "Starting DNS reverse lookup\n");
2404   ppc->resolver_handle = GNUNET_RESOLVER_hostname_get (sb,
2405                                                        sbs,
2406                                                        ! numeric,
2407                                                        timeout,
2408                                                        &append_port,
2409                                                        ppc);
2410   if (NULL == ppc->resolver_handle)
2411   {
2412     GNUNET_break (0);
2413     GNUNET_free (ppc);
2414     return;
2415   }
2416   GNUNET_CONTAINER_DLL_insert (plugin->ppc_dll_head,
2417                                plugin->ppc_dll_tail,
2418                                ppc);
2419 }
2420
2421
2422 /**
2423  * Function that will be called to check if a binary address for this
2424  * plugin is well-formed and corresponds to an address for THIS peer
2425  * (as per our configuration).  Naturally, if absolutely necessary,
2426  * plugins can be a bit conservative in their answer, but in general
2427  * plugins should make sure that the address does not redirect
2428  * traffic to a 3rd party that might try to man-in-the-middle our
2429  * traffic.
2430  *
2431  * @param cls closure, our `struct Plugin *`
2432  * @param addr pointer to the address
2433  * @param addrlen length of @a addr
2434  * @return #GNUNET_OK if this is a plausible address for this peer
2435  *         and transport, #GNUNET_SYSERR if not
2436  */
2437 static int
2438 tcp_plugin_check_address (void *cls,
2439                           const void *addr,
2440                           size_t addrlen)
2441 {
2442   struct Plugin *plugin = cls;
2443   const struct IPv4TcpAddress *v4;
2444   const struct IPv6TcpAddress *v6;
2445
2446   if ( (addrlen != sizeof(struct IPv4TcpAddress)) &&
2447        (addrlen != sizeof(struct IPv6TcpAddress)) )
2448   {
2449     GNUNET_break_op (0);
2450     return GNUNET_SYSERR;
2451   }
2452
2453   if (addrlen == sizeof(struct IPv4TcpAddress))
2454   {
2455     struct sockaddr_in s4;
2456
2457     v4 = (const struct IPv4TcpAddress *) addr;
2458     if (0 != memcmp (&v4->options,
2459                      &plugin->myoptions,
2460                      sizeof(uint32_t)))
2461     {
2462       GNUNET_break (0);
2463       return GNUNET_SYSERR;
2464     }
2465     memset (&s4, 0, sizeof (s4));
2466     s4.sin_family = AF_INET;
2467 #if HAVE_SOCKADDR_IN_SIN_LEN
2468     s4.sin_len = sizeof (s4);
2469 #endif
2470     s4.sin_port = v4->t4_port;
2471     s4.sin_addr.s_addr = v4->ipv4_addr;
2472
2473     if (GNUNET_OK !=
2474         GNUNET_NAT_test_address (plugin->nat,
2475                                  &s4,
2476                                  sizeof (struct sockaddr_in)))
2477       return GNUNET_SYSERR;
2478   }
2479   else
2480   {
2481     struct sockaddr_in6 s6;
2482
2483     v6 = (const struct IPv6TcpAddress *) addr;
2484     if (IN6_IS_ADDR_LINKLOCAL (&v6->ipv6_addr))
2485     {
2486       GNUNET_break_op (0);
2487       return GNUNET_SYSERR;
2488     }
2489     if (0 != memcmp (&v6->options,
2490                      &plugin->myoptions,
2491                      sizeof (uint32_t)))
2492     {
2493       GNUNET_break (0);
2494       return GNUNET_SYSERR;
2495     }
2496     memset (&s6, 0, sizeof (s6));
2497     s6.sin6_family = AF_INET6;
2498 #if HAVE_SOCKADDR_IN_SIN_LEN
2499     s6.sin6_len = sizeof (s6);
2500 #endif
2501     s6.sin6_port = v6->t6_port;
2502     s6.sin6_addr = v6->ipv6_addr;
2503
2504     if (GNUNET_OK !=
2505         GNUNET_NAT_test_address (plugin->nat,
2506                                  &s6,
2507                                  sizeof(struct sockaddr_in6)))
2508       return GNUNET_SYSERR;
2509   }
2510   return GNUNET_OK;
2511 }
2512
2513
2514 /**
2515  * We've received a nat probe from this peer via TCP.  Finish
2516  * creating the client session and resume sending of queued
2517  * messages.
2518  *
2519  * @param cls closure
2520  * @param client identification of the client
2521  * @param message the actual message
2522  */
2523 static void
2524 handle_tcp_nat_probe (void *cls,
2525                       struct GNUNET_SERVER_Client *client,
2526                       const struct GNUNET_MessageHeader *message)
2527 {
2528   struct Plugin *plugin = cls;
2529   struct GNUNET_ATS_Session *session;
2530   const struct TCP_NAT_ProbeMessage *tcp_nat_probe;
2531   size_t alen;
2532   void *vaddr;
2533   struct IPv4TcpAddress *t4;
2534   struct IPv6TcpAddress *t6;
2535   const struct sockaddr_in *s4;
2536   const struct sockaddr_in6 *s6;
2537
2538   LOG (GNUNET_ERROR_TYPE_DEBUG,
2539        "Received NAT probe\n");
2540   /* We have received a TCP NAT probe, meaning we (hopefully) initiated
2541    * a connection to this peer by running gnunet-nat-client.  This peer
2542    * received the punch message and now wants us to use the new connection
2543    * as the default for that peer.  Do so and then send a WELCOME message
2544    * so we can really be connected!
2545    */
2546   if (ntohs (message->size) != sizeof(struct TCP_NAT_ProbeMessage))
2547   {
2548     GNUNET_break_op(0);
2549     GNUNET_SERVER_receive_done (client,
2550                                 GNUNET_SYSERR);
2551     return;
2552   }
2553
2554   tcp_nat_probe = (const struct TCP_NAT_ProbeMessage *) message;
2555   if (0 == memcmp (&tcp_nat_probe->clientIdentity, plugin->env->my_identity,
2556           sizeof(struct GNUNET_PeerIdentity)))
2557   {
2558     /* refuse connections from ourselves */
2559     GNUNET_SERVER_receive_done (client,
2560                                 GNUNET_SYSERR);
2561     return;
2562   }
2563
2564   session = GNUNET_CONTAINER_multipeermap_get (plugin->nat_wait_conns,
2565                                                &tcp_nat_probe->clientIdentity);
2566   if (NULL == session)
2567   {
2568     LOG (GNUNET_ERROR_TYPE_DEBUG,
2569          "Did NOT find session for NAT probe!\n");
2570     GNUNET_SERVER_receive_done (client,
2571                                 GNUNET_OK);
2572     return;
2573   }
2574   LOG (GNUNET_ERROR_TYPE_DEBUG,
2575        "Found session for NAT probe!\n");
2576
2577   if (NULL != session->nat_connection_timeout)
2578   {
2579     GNUNET_SCHEDULER_cancel (session->nat_connection_timeout);
2580     session->nat_connection_timeout = NULL;
2581   }
2582
2583   if (GNUNET_OK !=
2584       GNUNET_SERVER_client_get_address (client,
2585                                         &vaddr,
2586                                         &alen))
2587   {
2588     GNUNET_break(0);
2589     GNUNET_SERVER_receive_done (client,
2590                                 GNUNET_SYSERR);
2591     tcp_plugin_disconnect_session (plugin,
2592                                    session);
2593     return;
2594   }
2595   GNUNET_assert (GNUNET_YES ==
2596                  GNUNET_CONTAINER_multipeermap_remove (plugin->nat_wait_conns,
2597                                                        &tcp_nat_probe->clientIdentity,
2598                                                        session));
2599   GNUNET_SERVER_client_set_user_context (client,
2600                                          session);
2601   (void) GNUNET_CONTAINER_multipeermap_put (plugin->sessionmap,
2602                                             &session->target,
2603                                             session,
2604                                             GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
2605   session->last_activity = GNUNET_TIME_absolute_get ();
2606   LOG (GNUNET_ERROR_TYPE_DEBUG,
2607        "Found address `%s' for incoming connection\n",
2608        GNUNET_a2s (vaddr, alen));
2609   switch (((const struct sockaddr *) vaddr)->sa_family)
2610   {
2611   case AF_INET:
2612     s4 = vaddr;
2613     t4 = GNUNET_new (struct IPv4TcpAddress);
2614     t4->options = htonl (TCP_OPTIONS_NONE);
2615     t4->t4_port = s4->sin_port;
2616     t4->ipv4_addr = s4->sin_addr.s_addr;
2617     session->address = GNUNET_HELLO_address_allocate (&tcp_nat_probe->clientIdentity,
2618                                                       PLUGIN_NAME,
2619                                                       &t4,
2620                                                       sizeof(struct IPv4TcpAddress),
2621                                                       GNUNET_HELLO_ADDRESS_INFO_NONE);
2622     break;
2623   case AF_INET6:
2624     s6 = vaddr;
2625     t6 = GNUNET_new (struct IPv6TcpAddress);
2626     t6->options = htonl (TCP_OPTIONS_NONE);
2627     t6->t6_port = s6->sin6_port;
2628     GNUNET_memcpy (&t6->ipv6_addr, &s6->sin6_addr, sizeof(struct in6_addr));
2629     session->address = GNUNET_HELLO_address_allocate (&tcp_nat_probe->clientIdentity,
2630                                                       PLUGIN_NAME,
2631                                                       &t6,
2632                                                       sizeof(struct IPv6TcpAddress),
2633                                                       GNUNET_HELLO_ADDRESS_INFO_NONE);
2634     break;
2635   default:
2636     GNUNET_break_op(0);
2637     LOG(GNUNET_ERROR_TYPE_DEBUG,
2638         "Bad address for incoming connection!\n");
2639     GNUNET_free(vaddr);
2640     GNUNET_SERVER_receive_done (client,
2641                                 GNUNET_SYSERR);
2642     tcp_plugin_disconnect_session (plugin,
2643                                    session);
2644     return;
2645   }
2646   GNUNET_free (vaddr);
2647   GNUNET_break (NULL == session->client);
2648   session->client = client;
2649   GNUNET_STATISTICS_update (plugin->env->stats,
2650                             gettext_noop ("# TCP sessions active"),
2651                             1,
2652                             GNUNET_NO);
2653   process_pending_messages (session);
2654   GNUNET_SERVER_receive_done (client,
2655                               GNUNET_OK);
2656 }
2657
2658
2659 /**
2660  * We've received a welcome from this peer via TCP.  Possibly create a
2661  * fresh client record and send back our welcome.
2662  *
2663  * @param cls closure
2664  * @param client identification of the client
2665  * @param message the actual message
2666  */
2667 static void
2668 handle_tcp_welcome (void *cls,
2669                     struct GNUNET_SERVER_Client *client,
2670                     const struct GNUNET_MessageHeader *message)
2671 {
2672   struct Plugin *plugin = cls;
2673   const struct WelcomeMessage *wm = (const struct WelcomeMessage *) message;
2674   struct GNUNET_HELLO_Address *address;
2675   struct GNUNET_ATS_Session *session;
2676   size_t alen;
2677   void *vaddr;
2678   struct IPv4TcpAddress t4;
2679   struct IPv6TcpAddress t6;
2680   const struct sockaddr_in *s4;
2681   const struct sockaddr_in6 *s6;
2682
2683   if (0 == memcmp (&wm->clientIdentity,
2684                    plugin->env->my_identity,
2685                    sizeof(struct GNUNET_PeerIdentity)))
2686   {
2687     /* refuse connections from ourselves */
2688     GNUNET_SERVER_receive_done (client,
2689                                 GNUNET_SYSERR);
2690     if (GNUNET_OK ==
2691         GNUNET_SERVER_client_get_address (client,
2692                                           &vaddr,
2693                                           &alen))
2694     {
2695       LOG (GNUNET_ERROR_TYPE_INFO,
2696            "Received WELCOME message from my own identity `%s' on address `%s'\n",
2697            GNUNET_i2s (&wm->clientIdentity),
2698            GNUNET_a2s (vaddr, alen));
2699       GNUNET_free (vaddr);
2700     }
2701     return;
2702   }
2703
2704   if (GNUNET_OK ==
2705       GNUNET_SERVER_client_get_address (client,
2706                                         &vaddr,
2707                                         &alen))
2708   {
2709     LOG(GNUNET_ERROR_TYPE_DEBUG,
2710         "Received WELCOME message from `%s' on address `%s'\n",
2711         GNUNET_i2s (&wm->clientIdentity),
2712         GNUNET_a2s (vaddr, alen));
2713     GNUNET_free (vaddr);
2714   }
2715   GNUNET_STATISTICS_update (plugin->env->stats,
2716                             gettext_noop ("# TCP WELCOME messages received"),
2717                             1,
2718                             GNUNET_NO);
2719   session = lookup_session_by_client (plugin,
2720                                       client);
2721   if (NULL != session)
2722   {
2723     if (GNUNET_OK ==
2724         GNUNET_SERVER_client_get_address (client,
2725                                           &vaddr,
2726                                           &alen))
2727     {
2728       LOG (GNUNET_ERROR_TYPE_DEBUG,
2729            "Found existing session %p for peer `%s'\n",
2730            session,
2731            GNUNET_a2s (vaddr, alen));
2732       GNUNET_free (vaddr);
2733     }
2734   }
2735   else
2736   {
2737     if (GNUNET_OK ==
2738         GNUNET_SERVER_client_get_address (client, &vaddr, &alen))
2739     {
2740       if (alen == sizeof(struct sockaddr_in))
2741       {
2742         s4 = vaddr;
2743         memset (&t4, '\0', sizeof (t4));
2744         t4.options = htonl (TCP_OPTIONS_NONE);
2745         t4.t4_port = s4->sin_port;
2746         t4.ipv4_addr = s4->sin_addr.s_addr;
2747         address = GNUNET_HELLO_address_allocate (&wm->clientIdentity,
2748                                                  PLUGIN_NAME,
2749                                                  &t4,
2750                                                  sizeof(t4),
2751                                                  GNUNET_HELLO_ADDRESS_INFO_INBOUND);
2752       }
2753       else if (alen == sizeof(struct sockaddr_in6))
2754       {
2755         s6 = vaddr;
2756         memset (&t6, '\0', sizeof (t6));
2757         t6.options = htonl (TCP_OPTIONS_NONE);
2758         t6.t6_port = s6->sin6_port;
2759         GNUNET_memcpy (&t6.ipv6_addr, &s6->sin6_addr, sizeof(struct in6_addr));
2760         address = GNUNET_HELLO_address_allocate (&wm->clientIdentity,
2761                                                  PLUGIN_NAME,
2762                                                  &t6,
2763                                                  sizeof (t6),
2764                                                  GNUNET_HELLO_ADDRESS_INFO_INBOUND);
2765       }
2766       else
2767       {
2768         GNUNET_break (0);
2769         GNUNET_free_non_null (vaddr);
2770         GNUNET_SERVER_receive_done (client,
2771                                     GNUNET_SYSERR);
2772         return;
2773       }
2774       session = create_session (plugin,
2775                                 address,
2776                                 plugin->env->get_address_type (plugin->env->cls,
2777                                                                vaddr,
2778                                                                alen),
2779                                 client,
2780                                 GNUNET_NO);
2781       GNUNET_break (GNUNET_ATS_NET_UNSPECIFIED != session->scope);
2782       GNUNET_HELLO_address_free (address);
2783       LOG (GNUNET_ERROR_TYPE_DEBUG,
2784            "Creating new%s session %p for peer `%s' client %p\n",
2785            GNUNET_HELLO_address_check_option (session->address,
2786                                               GNUNET_HELLO_ADDRESS_INFO_INBOUND)
2787            ? " inbound" : "",
2788            session,
2789            tcp_plugin_address_to_string (plugin,
2790                                          session->address->address,
2791                                          session->address->address_length),
2792            client);
2793       GNUNET_free (vaddr);
2794       (void) GNUNET_CONTAINER_multipeermap_put (plugin->sessionmap,
2795                                                 &session->target,
2796                                                 session,
2797                                                 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
2798       /* Notify transport and ATS about new session */
2799       plugin->env->session_start (plugin->env->cls,
2800                                   session->address,
2801                                   session,
2802                                   session->scope);
2803     }
2804     else
2805     {
2806       LOG(GNUNET_ERROR_TYPE_DEBUG,
2807           "Did not obtain TCP socket address for incoming connection\n");
2808       GNUNET_break(0);
2809       GNUNET_SERVER_receive_done (client,
2810                                   GNUNET_SYSERR);
2811       return;
2812     }
2813   }
2814
2815   if (GNUNET_YES != session->expecting_welcome)
2816   {
2817     GNUNET_break_op (0);
2818     GNUNET_SERVER_receive_done (client,
2819                                 GNUNET_SYSERR);
2820     return;
2821   }
2822   session->last_activity = GNUNET_TIME_absolute_get ();
2823   session->expecting_welcome = GNUNET_NO;
2824
2825   process_pending_messages (session);
2826   GNUNET_SERVER_client_set_timeout (client,
2827                                     GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2828   GNUNET_SERVER_receive_done (client,
2829                               GNUNET_OK);
2830 }
2831
2832
2833 /**
2834  * We've received data for this peer via TCP.  Unbox,
2835  * compute latency and forward.
2836  *
2837  * @param cls closure
2838  * @param client identification of the client
2839  * @param message the actual message
2840  */
2841 static void
2842 handle_tcp_data (void *cls,
2843                  struct GNUNET_SERVER_Client *client,
2844                  const struct GNUNET_MessageHeader *message)
2845 {
2846   struct Plugin *plugin = cls;
2847   struct GNUNET_ATS_Session *session;
2848   struct GNUNET_TIME_Relative delay;
2849   uint16_t type;
2850
2851   type = ntohs (message->type);
2852   if ( (GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_WELCOME == type) ||
2853        (GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_NAT_PROBE == type) )
2854   {
2855     /* We don't want to propagate WELCOME and NAT Probe messages up! */
2856     GNUNET_SERVER_receive_done (client,
2857                                 GNUNET_OK);
2858     return;
2859   }
2860   session = lookup_session_by_client (plugin, client);
2861   if (NULL == session)
2862   {
2863     /* No inbound session found */
2864     void *vaddr;
2865     size_t alen;
2866
2867     GNUNET_SERVER_client_get_address (client,
2868                                       &vaddr,
2869                                       &alen);
2870     LOG (GNUNET_ERROR_TYPE_ERROR,
2871          "Received unexpected %u bytes of type %u from `%s'\n",
2872          (unsigned int) ntohs (message->size),
2873          (unsigned int) ntohs (message->type),
2874          GNUNET_a2s (vaddr,
2875                      alen));
2876     GNUNET_break_op(0);
2877     GNUNET_SERVER_receive_done (client,
2878                                 GNUNET_SYSERR);
2879     GNUNET_free_non_null (vaddr);
2880     return;
2881   }
2882   if (GNUNET_YES == session->expecting_welcome)
2883   {
2884     /* Session is expecting WELCOME message */
2885     void *vaddr;
2886     size_t alen;
2887
2888     GNUNET_SERVER_client_get_address (client,
2889                                       &vaddr,
2890                                       &alen);
2891     LOG (GNUNET_ERROR_TYPE_ERROR,
2892          "Received unexpected %u bytes of type %u from `%s'\n",
2893          (unsigned int) ntohs (message->size),
2894          (unsigned int) ntohs (message->type),
2895          GNUNET_a2s (vaddr, alen));
2896     GNUNET_break_op(0);
2897     GNUNET_SERVER_receive_done (client,
2898                                 GNUNET_SYSERR);
2899     GNUNET_free_non_null (vaddr);
2900     return;
2901   }
2902
2903   session->last_activity = GNUNET_TIME_absolute_get ();
2904   {
2905     void *vaddr;
2906     size_t alen;
2907
2908     GNUNET_SERVER_client_get_address (client,
2909                                       &vaddr,
2910                                       &alen);
2911     LOG (GNUNET_ERROR_TYPE_DEBUG,
2912          "Passing %u bytes of type %u from `%s' at %s to transport service.\n",
2913          (unsigned int) ntohs (message->size),
2914          (unsigned int) ntohs (message->type),
2915          GNUNET_i2s (&session->target),
2916          GNUNET_a2s (vaddr, alen));
2917     GNUNET_free_non_null (vaddr);
2918   }
2919
2920   GNUNET_STATISTICS_update (plugin->env->stats,
2921                             gettext_noop ("# bytes received via TCP"),
2922                             ntohs (message->size),
2923                             GNUNET_NO);
2924
2925   GNUNET_assert (GNUNET_CONTAINER_multipeermap_contains_value (plugin->sessionmap,
2926                                                                &session->target,
2927                                                                session));
2928   delay = plugin->env->receive (plugin->env->cls,
2929                                 session->address,
2930                                 session,
2931                                 message);
2932   reschedule_session_timeout (session);
2933   if (0 == delay.rel_value_us)
2934   {
2935     GNUNET_SERVER_receive_done (client,
2936                                 GNUNET_OK);
2937   }
2938   else
2939   {
2940     LOG (GNUNET_ERROR_TYPE_DEBUG,
2941          "Throttling receiving from `%s' for %s\n",
2942          GNUNET_i2s (&session->target),
2943          GNUNET_STRINGS_relative_time_to_string (delay,
2944                                                  GNUNET_YES));
2945     GNUNET_SERVER_disable_receive_done_warning (client);
2946     GNUNET_assert (NULL == session->receive_delay_task);
2947     session->receive_delay_task = GNUNET_SCHEDULER_add_delayed (delay,
2948                                                                 &delayed_done,
2949                                                                 session);
2950   }
2951 }
2952
2953
2954 /**
2955  * Function called whenever a peer is connected on the "SERVER" level.
2956  * Increments number of active connections and suspends server if we
2957  * have reached the limit.
2958  *
2959  * @param cls closure
2960  * @param client identification of the client
2961  */
2962 static void
2963 connect_notify (void *cls,
2964                 struct GNUNET_SERVER_Client *client)
2965 {
2966   struct Plugin *plugin = cls;
2967
2968   if (NULL == client)
2969     return;
2970   plugin->cur_connections++;
2971   GNUNET_STATISTICS_set (plugin->env->stats,
2972                          gettext_noop ("# TCP server connections active"),
2973                          plugin->cur_connections,
2974                          GNUNET_NO);
2975   GNUNET_STATISTICS_update (plugin->env->stats,
2976                             gettext_noop ("# TCP server connect events"),
2977                             1,
2978                             GNUNET_NO);
2979   if (plugin->cur_connections != plugin->max_connections)
2980     return;
2981   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2982               _("TCP connection limit reached, suspending server\n"));
2983   GNUNET_STATISTICS_update (plugin->env->stats,
2984                             gettext_noop ("# TCP service suspended"),
2985                             1,
2986                             GNUNET_NO);
2987   GNUNET_SERVER_suspend (plugin->server); /* Maximum number of connections rechead */
2988 }
2989
2990
2991 /**
2992  * Function called whenever a peer is disconnected on the "SERVER"
2993  * level.  Cleans up the connection, decrements number of active
2994  * connections and if applicable resumes listening.
2995  *
2996  * @param cls closure
2997  * @param client identification of the client
2998  */
2999 static void
3000 disconnect_notify (void *cls,
3001                    struct GNUNET_SERVER_Client *client)
3002 {
3003   struct Plugin *plugin = cls;
3004   struct GNUNET_ATS_Session *session;
3005
3006   if (NULL == client)
3007     return;
3008   GNUNET_assert (plugin->cur_connections >= 1);
3009   plugin->cur_connections--;
3010   session = lookup_session_by_client (plugin,
3011                                       client);
3012   if (NULL == session)
3013     return; /* unknown, nothing to do */
3014   LOG (GNUNET_ERROR_TYPE_DEBUG,
3015        "Destroying session of `%s' with %s due to network-level disconnect.\n",
3016        GNUNET_i2s (&session->target),
3017        tcp_plugin_address_to_string (session->plugin,
3018                                      session->address->address,
3019                                      session->address->address_length));
3020
3021   if (plugin->cur_connections == plugin->max_connections)
3022   {
3023     GNUNET_STATISTICS_update (session->plugin->env->stats,
3024                               gettext_noop ("# TCP service resumed"),
3025                               1,
3026                               GNUNET_NO);
3027     GNUNET_SERVER_resume (plugin->server); /* Resume server  */
3028   }
3029   GNUNET_STATISTICS_set (plugin->env->stats,
3030                          gettext_noop ("# TCP server connections active"),
3031                          plugin->cur_connections,
3032                          GNUNET_NO);
3033   GNUNET_STATISTICS_update (session->plugin->env->stats,
3034                             gettext_noop ("# network-level TCP disconnect events"),
3035                             1,
3036                             GNUNET_NO);
3037   tcp_plugin_disconnect_session (plugin,
3038                                  session);
3039 }
3040
3041
3042 /**
3043  * We can now send a probe message, copy into buffer to really send.
3044  *
3045  * @param cls closure, a `struct TCPProbeContext`
3046  * @param size max size to copy
3047  * @param buf buffer to copy message to
3048  * @return number of bytes copied into @a buf
3049  */
3050 static size_t
3051 notify_send_probe (void *cls,
3052                    size_t size,
3053                    void *buf)
3054 {
3055   struct TCPProbeContext *tcp_probe_ctx = cls;
3056   struct Plugin *plugin = tcp_probe_ctx->plugin;
3057   size_t ret;
3058
3059   tcp_probe_ctx->transmit_handle = NULL;
3060   GNUNET_CONTAINER_DLL_remove (plugin->probe_head,
3061                                plugin->probe_tail,
3062                                tcp_probe_ctx);
3063   if (NULL == buf)
3064   {
3065     GNUNET_CONNECTION_destroy (tcp_probe_ctx->sock);
3066     GNUNET_free(tcp_probe_ctx);
3067     return 0;
3068   }
3069   GNUNET_assert(size >= sizeof(tcp_probe_ctx->message));
3070   GNUNET_memcpy (buf,
3071           &tcp_probe_ctx->message,
3072           sizeof(tcp_probe_ctx->message));
3073   GNUNET_SERVER_connect_socket (tcp_probe_ctx->plugin->server,
3074                                 tcp_probe_ctx->sock);
3075   ret = sizeof(tcp_probe_ctx->message);
3076   GNUNET_free (tcp_probe_ctx);
3077   return ret;
3078 }
3079
3080
3081 /**
3082  * Function called by the NAT subsystem suggesting another peer wants
3083  * to connect to us via connection reversal.  Try to connect back to the
3084  * given IP.
3085  *
3086  * @param cls closure
3087  * @param addr address to try
3088  * @param addrlen number of bytes in @a addr
3089  */
3090 static void
3091 try_connection_reversal (void *cls,
3092                          const struct sockaddr *addr,
3093                          socklen_t addrlen)
3094 {
3095   struct Plugin *plugin = cls;
3096   struct GNUNET_CONNECTION_Handle *sock;
3097   struct TCPProbeContext *tcp_probe_ctx;
3098
3099   /**
3100    * We have received an ICMP response, ostensibly from a peer
3101    * that wants to connect to us! Send a message to establish a connection.
3102    */
3103   sock = GNUNET_CONNECTION_create_from_sockaddr (AF_INET,
3104                                                  addr,
3105                                                  addrlen);
3106   if (NULL == sock)
3107   {
3108     /* failed for some odd reason (out of sockets?); ignore attempt */
3109     return;
3110   }
3111
3112   tcp_probe_ctx = GNUNET_new (struct TCPProbeContext);
3113   tcp_probe_ctx->message.header.size
3114     = htons (sizeof (struct TCP_NAT_ProbeMessage));
3115   tcp_probe_ctx->message.header.type
3116     = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_NAT_PROBE);
3117   tcp_probe_ctx->message.clientIdentity
3118     = *plugin->env->my_identity;
3119   tcp_probe_ctx->plugin = plugin;
3120   tcp_probe_ctx->sock = sock;
3121   GNUNET_CONTAINER_DLL_insert (plugin->probe_head,
3122                                plugin->probe_tail,
3123                                tcp_probe_ctx);
3124   tcp_probe_ctx->transmit_handle
3125     = GNUNET_CONNECTION_notify_transmit_ready (sock,
3126                                                ntohs (tcp_probe_ctx->message.header.size),
3127                                                GNUNET_TIME_UNIT_FOREVER_REL,
3128                                                &notify_send_probe,
3129                                                tcp_probe_ctx);
3130 }
3131
3132
3133 /**
3134  * Function obtain the network type for a session
3135  *
3136  * @param cls closure (`struct Plugin *`)
3137  * @param session the session
3138  * @return the network type in HBO or #GNUNET_SYSERR
3139  */
3140 static enum GNUNET_ATS_Network_Type
3141 tcp_plugin_get_network (void *cls,
3142                         struct GNUNET_ATS_Session *session)
3143 {
3144   return session->scope;
3145 }
3146
3147
3148 /**
3149  * Function obtain the network type for an address.
3150  *
3151  * @param cls closure (`struct Plugin *`)
3152  * @param address the address
3153  * @return the network type
3154  */
3155 static enum GNUNET_ATS_Network_Type
3156 tcp_plugin_get_network_for_address (void *cls,
3157                                     const struct GNUNET_HELLO_Address *address)
3158 {
3159   struct Plugin *plugin = cls;
3160   size_t addrlen;
3161   struct sockaddr_in a4;
3162   struct sockaddr_in6 a6;
3163   const struct IPv4TcpAddress *t4;
3164   const struct IPv6TcpAddress *t6;
3165   const void *sb;
3166   size_t sbs;
3167
3168   addrlen = address->address_length;
3169   if (addrlen == sizeof(struct IPv6TcpAddress))
3170   {
3171     GNUNET_assert (NULL != address->address); /* make static analysis happy */
3172     t6 = address->address;
3173     memset (&a6, 0, sizeof(a6));
3174 #if HAVE_SOCKADDR_IN_SIN_LEN
3175     a6.sin6_len = sizeof (a6);
3176 #endif
3177     a6.sin6_family = AF_INET6;
3178     a6.sin6_port = t6->t6_port;
3179     GNUNET_memcpy (&a6.sin6_addr, &t6->ipv6_addr, sizeof(struct in6_addr));
3180     sb = &a6;
3181     sbs = sizeof(a6);
3182   }
3183   else if (addrlen == sizeof(struct IPv4TcpAddress))
3184   {
3185     GNUNET_assert (NULL != address->address); /* make static analysis happy */
3186     t4 = address->address;
3187     memset (&a4, 0, sizeof(a4));
3188 #if HAVE_SOCKADDR_IN_SIN_LEN
3189     a4.sin_len = sizeof (a4);
3190 #endif
3191     a4.sin_family = AF_INET;
3192     a4.sin_port = t4->t4_port;
3193     a4.sin_addr.s_addr = t4->ipv4_addr;
3194     sb = &a4;
3195     sbs = sizeof(a4);
3196   }
3197   else
3198   {
3199     GNUNET_break (0);
3200     return GNUNET_ATS_NET_UNSPECIFIED;
3201   }
3202   return plugin->env->get_address_type (plugin->env->cls,
3203                                         sb,
3204                                         sbs);
3205 }
3206
3207
3208 /**
3209  * Return information about the given session to the
3210  * monitor callback.
3211  *
3212  * @param cls the `struct Plugin` with the monitor callback (`sic`)
3213  * @param peer peer we send information about
3214  * @param value our `struct GNUNET_ATS_Session` to send information about
3215  * @return #GNUNET_OK (continue to iterate)
3216  */
3217 static int
3218 send_session_info_iter (void *cls,
3219                         const struct GNUNET_PeerIdentity *peer,
3220                         void *value)
3221 {
3222   struct Plugin *plugin = cls;
3223   struct GNUNET_ATS_Session *session = value;
3224
3225   notify_session_monitor (plugin,
3226                           session,
3227                           GNUNET_TRANSPORT_SS_INIT);
3228   /* FIXME: cannot tell if this is up or not from current
3229      session state... */
3230   notify_session_monitor (plugin,
3231                           session,
3232                           GNUNET_TRANSPORT_SS_UP);
3233   return GNUNET_OK;
3234 }
3235
3236
3237 /**
3238  * Begin monitoring sessions of a plugin.  There can only
3239  * be one active monitor per plugin (i.e. if there are
3240  * multiple monitors, the transport service needs to
3241  * multiplex the generated events over all of them).
3242  *
3243  * @param cls closure of the plugin
3244  * @param sic callback to invoke, NULL to disable monitor;
3245  *            plugin will being by iterating over all active
3246  *            sessions immediately and then enter monitor mode
3247  * @param sic_cls closure for @a sic
3248  */
3249 static void
3250 tcp_plugin_setup_monitor (void *cls,
3251                           GNUNET_TRANSPORT_SessionInfoCallback sic,
3252                           void *sic_cls)
3253 {
3254   struct Plugin *plugin = cls;
3255
3256   plugin->sic = sic;
3257   plugin->sic_cls = sic_cls;
3258   if (NULL != sic)
3259   {
3260     GNUNET_CONTAINER_multipeermap_iterate (plugin->sessionmap,
3261                                            &send_session_info_iter,
3262                                            plugin);
3263     /* signal end of first iteration */
3264     sic (sic_cls, NULL, NULL);
3265   }
3266 }
3267
3268
3269 /**
3270  * Entry point for the plugin.
3271  *
3272  * @param cls closure, the `struct GNUNET_TRANSPORT_PluginEnvironment *`
3273  * @return the `struct GNUNET_TRANSPORT_PluginFunctions *` or NULL on error
3274  */
3275 void *
3276 libgnunet_plugin_transport_tcp_init (void *cls)
3277 {
3278   static const struct GNUNET_SERVER_MessageHandler my_handlers[] = {
3279     { &handle_tcp_welcome, NULL,
3280       GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_WELCOME,
3281       sizeof(struct WelcomeMessage) },
3282     { &handle_tcp_nat_probe, NULL,
3283       GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_NAT_PROBE,
3284       sizeof(struct TCP_NAT_ProbeMessage) },
3285     { &handle_tcp_data, NULL,
3286       GNUNET_MESSAGE_TYPE_ALL, 0 },
3287     { NULL, NULL, 0, 0 }
3288   };
3289   struct GNUNET_TRANSPORT_PluginEnvironment *env = cls;
3290   struct GNUNET_TRANSPORT_PluginFunctions *api;
3291   struct Plugin *plugin;
3292   struct GNUNET_SERVICE_Context *service;
3293   unsigned long long aport;
3294   unsigned long long bport;
3295   unsigned long long max_connections;
3296   unsigned int i;
3297   struct GNUNET_TIME_Relative idle_timeout;
3298 #ifdef TCP_STEALTH
3299   struct GNUNET_NETWORK_Handle *const*lsocks;
3300 #endif
3301   int ret;
3302   int ret_s;
3303   struct sockaddr **addrs;
3304   socklen_t *addrlens;
3305
3306   if (NULL == env->receive)
3307   {
3308     /* run in 'stub' mode (i.e. as part of gnunet-peerinfo), don't fully
3309      initialze the plugin or the API */
3310     api = GNUNET_new (struct GNUNET_TRANSPORT_PluginFunctions);
3311     api->cls = NULL;
3312     api->address_pretty_printer = &tcp_plugin_address_pretty_printer;
3313     api->address_to_string = &tcp_plugin_address_to_string;
3314     api->string_to_address = &tcp_plugin_string_to_address;
3315     return api;
3316   }
3317
3318   GNUNET_assert (NULL != env->cfg);
3319   if (GNUNET_OK !=
3320       GNUNET_CONFIGURATION_get_value_number (env->cfg,
3321                                              "transport-tcp",
3322                                              "MAX_CONNECTIONS",
3323                                              &max_connections))
3324     max_connections = 128;
3325
3326   aport = 0;
3327   if ((GNUNET_OK !=
3328        GNUNET_CONFIGURATION_get_value_number (env->cfg, "transport-tcp",
3329                                               "PORT", &bport)) ||
3330       (bport > 65535) ||
3331       ((GNUNET_OK ==
3332         GNUNET_CONFIGURATION_get_value_number (env->cfg, "transport-tcp",
3333                                                "ADVERTISED-PORT", &aport)) &&
3334        (aport > 65535) ))
3335   {
3336     LOG(GNUNET_ERROR_TYPE_ERROR,
3337         _("Require valid port number for service `%s' in configuration!\n"),
3338         "transport-tcp");
3339     return NULL ;
3340   }
3341   if (0 == aport)
3342     aport = bport;
3343   if (0 == bport)
3344     aport = 0;
3345   if (0 != bport)
3346   {
3347     service = GNUNET_SERVICE_start ("transport-tcp",
3348                                     env->cfg,
3349                                     GNUNET_SERVICE_OPTION_NONE);
3350     if (NULL == service)
3351     {
3352       LOG (GNUNET_ERROR_TYPE_WARNING,
3353            _("Failed to start service.\n"));
3354       return NULL;
3355     }
3356   }
3357   else
3358     service = NULL;
3359
3360   api = NULL;
3361   plugin = GNUNET_new (struct Plugin);
3362   plugin->sessionmap = GNUNET_CONTAINER_multipeermap_create (max_connections,
3363                                                              GNUNET_YES);
3364   plugin->max_connections = max_connections;
3365   plugin->open_port = bport;
3366   plugin->adv_port = aport;
3367   plugin->env = env;
3368   plugin->my_welcome.header.size = htons (sizeof(struct WelcomeMessage));
3369   plugin->my_welcome.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_WELCOME);
3370   plugin->my_welcome.clientIdentity = *plugin->env->my_identity;
3371
3372   if ( (NULL != service) &&
3373        (GNUNET_YES ==
3374         GNUNET_CONFIGURATION_get_value_yesno (env->cfg,
3375                                               "transport-tcp",
3376                                               "TCP_STEALTH")) )
3377   {
3378 #ifdef TCP_STEALTH
3379     plugin->myoptions |= TCP_OPTIONS_TCP_STEALTH;
3380     lsocks = GNUNET_SERVICE_get_listen_sockets (service);
3381     if (NULL != lsocks)
3382     {
3383       uint32_t len = sizeof (struct WelcomeMessage);
3384
3385       for (i=0;NULL!=lsocks[i];i++)
3386       {
3387         if ( (GNUNET_OK !=
3388               GNUNET_NETWORK_socket_setsockopt (lsocks[i],
3389                                                 IPPROTO_TCP,
3390                                                 TCP_STEALTH,
3391                                                 env->my_identity,
3392                                                 sizeof (struct GNUNET_PeerIdentity))) ||
3393              (GNUNET_OK !=
3394               GNUNET_NETWORK_socket_setsockopt (lsocks[i],
3395                                                 IPPROTO_TCP,
3396                                                 TCP_STEALTH_INTEGRITY_LEN,
3397                                                 &len,
3398                                                 sizeof (len))) )
3399         {
3400           /* TCP STEALTH not supported by kernel */
3401           GNUNET_assert (0 == i);
3402           GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3403                       _("TCP_STEALTH not supported on this platform.\n"));
3404           goto die;
3405         }
3406       }
3407     }
3408 #else
3409     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3410                 _("TCP_STEALTH not supported on this platform.\n"));
3411     goto die;
3412 #endif
3413   }
3414
3415   if ( (NULL != service) &&
3416        (GNUNET_SYSERR !=
3417         (ret_s =
3418          get_server_addresses ("transport-tcp",
3419                                env->cfg,
3420                                &addrs,
3421                                &addrlens))))
3422   {
3423     for (ret = ret_s-1; ret >= 0; ret--)
3424       LOG (GNUNET_ERROR_TYPE_INFO,
3425            "Binding to address `%s'\n",
3426            GNUNET_a2s (addrs[ret], addrlens[ret]));
3427     plugin->nat
3428       = GNUNET_NAT_register (env->cfg,
3429                              "transport-tcp",
3430                              IPPROTO_TCP,
3431                              (unsigned int) ret_s,
3432                              (const struct sockaddr **) addrs,
3433                              addrlens,
3434                              &tcp_nat_port_map_callback,
3435                              &try_connection_reversal,
3436                              plugin);
3437     for (ret = ret_s -1; ret >= 0; ret--)
3438       GNUNET_free (addrs[ret]);
3439     GNUNET_free_non_null (addrs);
3440     GNUNET_free_non_null (addrlens);
3441   }
3442   else
3443   {
3444     plugin->nat = GNUNET_NAT_register (plugin->env->cfg,
3445                                        "transport-tcp",
3446                                        IPPROTO_TCP,
3447                                        0,
3448                                        NULL,
3449                                        NULL,
3450                                        NULL,
3451                                        &try_connection_reversal,
3452                                        plugin);
3453   }
3454   api = GNUNET_new (struct GNUNET_TRANSPORT_PluginFunctions);
3455   api->cls = plugin;
3456   api->send = &tcp_plugin_send;
3457   api->get_session = &tcp_plugin_get_session;
3458   api->disconnect_session = &tcp_plugin_disconnect_session;
3459   api->query_keepalive_factor = &tcp_plugin_query_keepalive_factor;
3460   api->disconnect_peer = &tcp_plugin_disconnect;
3461   api->address_pretty_printer = &tcp_plugin_address_pretty_printer;
3462   api->check_address = &tcp_plugin_check_address;
3463   api->address_to_string = &tcp_plugin_address_to_string;
3464   api->string_to_address = &tcp_plugin_string_to_address;
3465   api->get_network = &tcp_plugin_get_network;
3466   api->get_network_for_address = &tcp_plugin_get_network_for_address;
3467   api->update_session_timeout = &tcp_plugin_update_session_timeout;
3468   api->update_inbound_delay = &tcp_plugin_update_inbound_delay;
3469   api->setup_monitor = &tcp_plugin_setup_monitor;
3470   plugin->service = service;
3471   if (NULL != service)
3472   {
3473     plugin->server = GNUNET_SERVICE_get_server (service);
3474   }
3475   else
3476   {
3477     if (GNUNET_OK !=
3478         GNUNET_CONFIGURATION_get_value_time (env->cfg,
3479                                              "transport-tcp",
3480                                              "TIMEOUT",
3481                                              &idle_timeout))
3482     {
3483       GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
3484                                  "transport-tcp",
3485                                  "TIMEOUT");
3486       goto die;
3487     }
3488     plugin->server
3489       = GNUNET_SERVER_create_with_sockets (NULL,
3490                                            plugin,
3491                                            NULL,
3492                                            idle_timeout,
3493                                            GNUNET_YES);
3494   }
3495   plugin->handlers = GNUNET_malloc (sizeof (my_handlers));
3496   GNUNET_memcpy (plugin->handlers,
3497                  my_handlers,
3498                  sizeof(my_handlers));
3499   for (i = 0;i < sizeof(my_handlers) / sizeof(struct GNUNET_SERVER_MessageHandler);i++)
3500     plugin->handlers[i].callback_cls = plugin;
3501
3502   GNUNET_SERVER_add_handlers (plugin->server,
3503                               plugin->handlers);
3504   GNUNET_SERVER_connect_notify (plugin->server,
3505                                 &connect_notify,
3506                                 plugin);
3507   GNUNET_SERVER_disconnect_notify (plugin->server,
3508                                    &disconnect_notify,
3509                                    plugin);
3510   plugin->nat_wait_conns = GNUNET_CONTAINER_multipeermap_create (16,
3511                                                                  GNUNET_YES);
3512   if (0 != bport)
3513     LOG (GNUNET_ERROR_TYPE_INFO,
3514          _("TCP transport listening on port %llu\n"),
3515          bport);
3516   else
3517     LOG (GNUNET_ERROR_TYPE_INFO,
3518          _("TCP transport not listening on any port (client only)\n"));
3519   if ( (aport != bport) &&
3520        (0 != bport) )
3521     LOG (GNUNET_ERROR_TYPE_INFO,
3522          _("TCP transport advertises itself as being on port %llu\n"),
3523          aport);
3524   /* Initially set connections to 0 */
3525   GNUNET_STATISTICS_set (plugin->env->stats,
3526                          gettext_noop ("# TCP sessions active"),
3527                          0,
3528                          GNUNET_NO);
3529   return api;
3530
3531  die:
3532   if (NULL != plugin->nat)
3533     GNUNET_NAT_unregister (plugin->nat);
3534   GNUNET_CONTAINER_multipeermap_destroy (plugin->sessionmap);
3535   if (NULL != service)
3536     GNUNET_SERVICE_stop (service);
3537   GNUNET_free (plugin);
3538   GNUNET_free_non_null (api);
3539   return NULL;
3540 }
3541
3542
3543 /**
3544  * Exit point from the plugin.
3545  *
3546  * @param cls the `struct GNUNET_TRANSPORT_PluginFunctions`
3547  * @return NULL
3548  */
3549 void *
3550 libgnunet_plugin_transport_tcp_done (void *cls)
3551 {
3552   struct GNUNET_TRANSPORT_PluginFunctions *api = cls;
3553   struct Plugin *plugin = api->cls;
3554   struct TCPProbeContext *tcp_probe;
3555   struct PrettyPrinterContext *cur;
3556   struct PrettyPrinterContext *next;
3557
3558   if (NULL == plugin)
3559   {
3560     GNUNET_free(api);
3561     return NULL ;
3562   }
3563   LOG (GNUNET_ERROR_TYPE_DEBUG,
3564        "Shutting down TCP plugin\n");
3565
3566   /* Removing leftover sessions */
3567   GNUNET_CONTAINER_multipeermap_iterate (plugin->sessionmap,
3568                                          &session_disconnect_it,
3569                                          plugin);
3570   /* Removing leftover NAT sessions */
3571   GNUNET_CONTAINER_multipeermap_iterate (plugin->nat_wait_conns,
3572                                          &session_disconnect_it,
3573                                          plugin);
3574
3575   for (cur = plugin->ppc_dll_head; NULL != cur; cur = next)
3576   {
3577     next = cur->next;
3578     GNUNET_CONTAINER_DLL_remove (plugin->ppc_dll_head,
3579                                  plugin->ppc_dll_tail,
3580                                  cur);
3581     GNUNET_RESOLVER_request_cancel (cur->resolver_handle);
3582     cur->asc (cur->asc_cls,
3583               NULL,
3584               GNUNET_OK);
3585     GNUNET_free (cur);
3586   }
3587
3588   if (NULL != plugin->service)
3589     GNUNET_SERVICE_stop (plugin->service);
3590   else
3591     GNUNET_SERVER_destroy (plugin->server);
3592   GNUNET_free (plugin->handlers);
3593   if (NULL != plugin->nat)
3594     GNUNET_NAT_unregister (plugin->nat);
3595   while (NULL != (tcp_probe = plugin->probe_head))
3596   {
3597     GNUNET_CONTAINER_DLL_remove (plugin->probe_head,
3598                                  plugin->probe_tail,
3599                                  tcp_probe);
3600     GNUNET_CONNECTION_destroy (tcp_probe->sock);
3601     GNUNET_free (tcp_probe);
3602   }
3603   GNUNET_CONTAINER_multipeermap_destroy (plugin->nat_wait_conns);
3604   GNUNET_CONTAINER_multipeermap_destroy (plugin->sessionmap);
3605   GNUNET_break (0 == plugin->cur_connections);
3606   GNUNET_free (plugin);
3607   GNUNET_free (api);
3608   return NULL;
3609 }
3610
3611 /* end of plugin_transport_tcp.c */