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