fixing #3683: proper counting of TCP connections
[oweals/gnunet.git] / src / transport / plugin_transport_tcp.c
1 /*
2   This file is part of GNUnet
3   Copyright (C) 2002--2015 Christian Grothoff (and other contributing authors)
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., 59 Temple Place - Suite 330,
18   Boston, MA 02111-1307, USA.
19  */
20 /**
21  * @file transport/plugin_transport_tcp.c
22  * @brief Implementation of the TCP transport service
23  * @author Christian Grothoff
24  */
25 #include "platform.h"
26 #include "gnunet_hello_lib.h"
27 #include "gnunet_constants.h"
28 #include "gnunet_util_lib.h"
29 #include "gnunet_nat_lib.h"
30 #include "gnunet_protocols.h"
31 #include "gnunet_resolver_service.h"
32 #include "gnunet_signatures.h"
33 #include "gnunet_statistics_service.h"
34 #include "gnunet_transport_service.h"
35 #include "gnunet_transport_plugin.h"
36 #include "transport.h"
37
38 #define LOG(kind,...) GNUNET_log_from (kind, "transport-tcp",__VA_ARGS__)
39
40 #define PLUGIN_NAME "tcp"
41
42 /**
43  * How long until we give up on establishing an NAT connection?
44  * Must be > 4 RTT
45  */
46 #define NAT_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10)
47
48 GNUNET_NETWORK_STRUCT_BEGIN
49
50
51 /**
52  * Initial handshake message for a session.
53  */
54 struct WelcomeMessage
55 {
56   /**
57    * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_WELCOME.
58    */
59   struct GNUNET_MessageHeader header;
60
61   /**
62    * Identity of the node connecting (TCP client)
63    */
64   struct GNUNET_PeerIdentity clientIdentity;
65
66 };
67
68 /**
69  * Basically a WELCOME message, but with the purpose
70  * of giving the waiting peer a client handle to use
71  */
72 struct TCP_NAT_ProbeMessage
73 {
74   /**
75    * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_NAT_PROBE.
76    */
77   struct GNUNET_MessageHeader header;
78
79   /**
80    * Identity of the sender of the message.
81    */
82   struct GNUNET_PeerIdentity clientIdentity;
83
84 };
85 GNUNET_NETWORK_STRUCT_END
86
87 /**
88  * Context for sending a NAT probe via TCP.
89  */
90 struct TCPProbeContext
91 {
92
93   /**
94    * Active probes are kept in a DLL.
95    */
96   struct TCPProbeContext *next;
97
98   /**
99    * Active probes are kept in a DLL.
100    */
101   struct TCPProbeContext *prev;
102
103   /**
104    * Probe connection.
105    */
106   struct GNUNET_CONNECTION_Handle *sock;
107
108   /**
109    * Message to be sent.
110    */
111   struct TCP_NAT_ProbeMessage message;
112
113   /**
114    * Handle to the transmission.
115    */
116   struct GNUNET_CONNECTION_TransmitHandle *transmit_handle;
117
118   /**
119    * Transport plugin handle.
120    */
121   struct Plugin *plugin;
122 };
123
124 /**
125  * Bits in the `options` field of TCP addresses.
126  */
127 enum TcpAddressOptions
128 {
129
130   /**
131    * No bits set.
132    */
133   TCP_OPTIONS_NONE = 0,
134
135   /**
136    * See #HTTP_OPTIONS_VERIFY_CERTIFICATE.
137    */
138   TCP_OPTIONS_RESERVED = 1,
139
140   /**
141    * Enable TCP Stealth-style port knocking.
142    */
143   TCP_OPTIONS_TCP_STEALTH = 2
144 };
145
146 GNUNET_NETWORK_STRUCT_BEGIN
147
148 /**
149  * Network format for IPv4 addresses.
150  */
151 struct IPv4TcpAddress
152 {
153   /**
154    * Optional options and flags for this address,
155    * see `enum TcpAddressOptions`
156    */
157   uint32_t options;
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;
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 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    * Handle for (DYN)DNS lookup of our external IP.
467    */
468   struct GNUNET_RESOLVER_RequestHandle *ext_dns;
469
470   /**
471    * Function to call about session status changes.
472    */
473   GNUNET_TRANSPORT_SessionInfoCallback sic;
474
475   /**
476    * Closure for @e sic.
477    */
478   void *sic_cls;
479
480   /**
481    * ID of task used to update our addresses when one expires.
482    */
483   struct GNUNET_SCHEDULER_Task *address_update_task;
484
485   /**
486    * Running pretty printers: head
487    */
488   struct PrettyPrinterContext *ppc_dll_head;
489
490   /**
491    * Running pretty printers: tail
492    */
493   struct PrettyPrinterContext *ppc_dll_tail;
494
495   /**
496    * Welcome message used by this peer.
497    */
498   struct WelcomeMessage my_welcome;
499
500   /**
501    * How many more TCP sessions are we allowed to open right now?
502    */
503   unsigned long long max_connections;
504
505   /**
506    * How many more TCP sessions do we have right now?
507    */
508   unsigned long long cur_connections;
509
510   /**
511    * Address options
512    */
513   uint32_t myoptions;
514
515   /**
516    * Port that we are actually listening on.
517    */
518   uint16_t open_port;
519
520   /**
521    * Port that the user said we would have visible to the
522    * rest of the world.
523    */
524   uint16_t adv_port;
525
526 };
527
528
529 /**
530  * If a session monitor is attached, notify it about the new
531  * session state.
532  *
533  * @param plugin our plugin
534  * @param session session that changed state
535  * @param state new state of the session
536  */
537 static void
538 notify_session_monitor (struct Plugin *plugin,
539                         struct Session *session,
540                         enum GNUNET_TRANSPORT_SessionState state)
541 {
542   struct GNUNET_TRANSPORT_SessionInfo info;
543
544   if (NULL == plugin->sic)
545     return;
546   memset (&info, 0, sizeof (info));
547   info.state = state;
548   info.is_inbound = (0 != (GNUNET_HELLO_ADDRESS_INFO_INBOUND & session->address->local_info))
549     ? GNUNET_YES
550     : GNUNET_NO;
551   info.num_msg_pending = session->msgs_in_queue;
552   info.num_bytes_pending = session->bytes_in_queue;
553   if (NULL != session->receive_delay_task)
554     info.receive_delay = session->receive_delay;
555   info.session_timeout = session->timeout;
556   info.address = session->address;
557   plugin->sic (plugin->sic_cls,
558                session,
559                &info);
560 }
561
562
563 /**
564  * Our external IP address/port mapping has changed.
565  *
566  * @param cls closure, the `struct Plugin`
567  * @param add_remove #GNUNET_YES to mean the new public IP address, #GNUNET_NO to mean
568  *     the previous (now invalid) one
569  * @param addr either the previous or the new public IP address
570  * @param addrlen actual length of @a addr
571  */
572 static void
573 tcp_nat_port_map_callback (void *cls,
574                            int add_remove,
575                            const struct sockaddr *addr,
576                            socklen_t addrlen)
577 {
578   struct Plugin *plugin = cls;
579   struct GNUNET_HELLO_Address *address;
580   struct IPv4TcpAddress t4;
581   struct IPv6TcpAddress t6;
582   void *arg;
583   size_t args;
584
585   LOG(GNUNET_ERROR_TYPE_INFO,
586       "NAT notification to %s address `%s'\n",
587       (GNUNET_YES == add_remove) ? "add" : "remove",
588       GNUNET_a2s (addr, addrlen));
589   /* convert 'addr' to our internal format */
590   switch (addr->sa_family)
591   {
592   case AF_INET:
593     GNUNET_assert(addrlen == sizeof(struct sockaddr_in));
594     memset (&t4, 0, sizeof(t4));
595     t4.options = htonl (plugin->myoptions);
596     t4.ipv4_addr = ((struct sockaddr_in *) addr)->sin_addr.s_addr;
597     t4.t4_port = ((struct sockaddr_in *) addr)->sin_port;
598     arg = &t4;
599     args = sizeof (t4);
600     break;
601   case AF_INET6:
602     GNUNET_assert(addrlen == sizeof(struct sockaddr_in6));
603     memset (&t6, 0, sizeof(t6));
604     memcpy (&t6.ipv6_addr, &((struct sockaddr_in6 *) addr)->sin6_addr,
605         sizeof(struct in6_addr));
606     t6.options = htonl (plugin->myoptions);
607     t6.t6_port = ((struct sockaddr_in6 *) addr)->sin6_port;
608     arg = &t6;
609     args = sizeof (t6);
610     break;
611   default:
612     GNUNET_break(0);
613     return;
614   }
615   /* modify our published address list */
616   GNUNET_assert ((args == sizeof (struct IPv4TcpAddress)) ||
617       (args == sizeof (struct IPv6TcpAddress)));
618   address = GNUNET_HELLO_address_allocate (plugin->env->my_identity,
619       PLUGIN_NAME, arg, args, GNUNET_HELLO_ADDRESS_INFO_NONE);
620   plugin->env->notify_address (plugin->env->cls, add_remove, address);
621   GNUNET_HELLO_address_free(address);
622 }
623
624
625 /**
626  * Function called for a quick conversion of the binary address to
627  * a numeric address.  Note that the caller must not free the
628  * address and that the next call to this function is allowed
629  * to override the address again.
630  *
631  * @param cls closure (`struct Plugin*`)
632  * @param addr binary address
633  * @param addrlen length of @a addr
634  * @return string representing the same address
635  */
636 static const char *
637 tcp_plugin_address_to_string (void *cls,
638                               const void *addr,
639                               size_t addrlen)
640 {
641   static char rbuf[INET6_ADDRSTRLEN + 12];
642   char buf[INET6_ADDRSTRLEN];
643   const void *sb;
644   struct in_addr a4;
645   struct in6_addr a6;
646   const struct IPv4TcpAddress *t4;
647   const struct IPv6TcpAddress *t6;
648   int af;
649   uint16_t port;
650   uint32_t options;
651
652   switch (addrlen)
653   {
654   case sizeof(struct IPv6TcpAddress):
655     t6 = addr;
656     af = AF_INET6;
657     port = ntohs (t6->t6_port);
658     options = ntohl (t6->options);
659     memcpy (&a6, &t6->ipv6_addr, sizeof(a6));
660     sb = &a6;
661     break;
662   case sizeof(struct IPv4TcpAddress):
663     t4 = addr;
664     af = AF_INET;
665     port = ntohs (t4->t4_port);
666     options = ntohl (t4->options);
667     memcpy (&a4, &t4->ipv4_addr, sizeof(a4));
668     sb = &a4;
669     break;
670   default:
671     LOG (GNUNET_ERROR_TYPE_WARNING,
672          _("Unexpected address length: %u bytes\n"),
673          (unsigned int) addrlen);
674     return NULL ;
675   }
676   if (NULL == inet_ntop (af, sb, buf, INET6_ADDRSTRLEN))
677   {
678     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
679                          "inet_ntop");
680     return NULL ;
681   }
682   GNUNET_snprintf (rbuf, sizeof(rbuf),
683                    (af == AF_INET6) ? "%s.%u.[%s]:%u" : "%s.%u.%s:%u",
684                    PLUGIN_NAME,
685                    options,
686                    buf,
687                    port);
688   return rbuf;
689 }
690
691
692 /**
693  * Function called to convert a string address to
694  * a binary address.
695  *
696  * @param cls closure (`struct Plugin*`)
697  * @param addr string address
698  * @param addrlen length of the address
699  * @param buf location to store the buffer
700  * @param added location to store the number of bytes in the buffer.
701  *        If the function returns #GNUNET_SYSERR, its contents are undefined.
702  * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure
703  */
704 static int
705 tcp_plugin_string_to_address (void *cls,
706                               const char *addr,
707                               uint16_t addrlen,
708                               void **buf,
709                               size_t *added)
710 {
711   struct sockaddr_storage socket_address;
712   char *address;
713   char *plugin;
714   char *optionstr;
715   uint32_t options;
716
717   /* Format tcp.options.address:port */
718   address = NULL;
719   plugin = NULL;
720   optionstr = NULL;
721   if ((NULL == addr) || (0 == addrlen))
722   {
723     GNUNET_break(0);
724     return GNUNET_SYSERR;
725   }
726   if ('\0' != addr[addrlen - 1])
727   {
728     GNUNET_break(0);
729     return GNUNET_SYSERR;
730   }
731   if (strlen (addr) != addrlen - 1)
732   {
733     GNUNET_break(0);
734     return GNUNET_SYSERR;
735   }
736   plugin = GNUNET_strdup (addr);
737   optionstr = strchr (plugin, '.');
738   if (NULL == optionstr)
739   {
740     GNUNET_break(0);
741     GNUNET_free(plugin);
742     return GNUNET_SYSERR;
743   }
744   optionstr[0] = '\0';
745   optionstr++;
746   options = atol (optionstr);
747   address = strchr (optionstr, '.');
748   if (NULL == address)
749   {
750     GNUNET_break(0);
751     GNUNET_free(plugin);
752     return GNUNET_SYSERR;
753   }
754   address[0] = '\0';
755   address++;
756
757   if (GNUNET_OK != 
758       GNUNET_STRINGS_to_address_ip (address,
759                                     strlen (address),
760                                     &socket_address))
761   {
762     GNUNET_break(0);
763     GNUNET_free(plugin);
764     return GNUNET_SYSERR;
765   }
766
767   GNUNET_free(plugin);
768   switch (socket_address.ss_family)
769   {
770   case AF_INET:
771   {
772     struct IPv4TcpAddress *t4;
773     struct sockaddr_in *in4 = (struct sockaddr_in *) &socket_address;
774     t4 = GNUNET_new (struct IPv4TcpAddress);
775     t4->options = htonl (options);
776     t4->ipv4_addr = in4->sin_addr.s_addr;
777     t4->t4_port = in4->sin_port;
778     *buf = t4;
779     *added = sizeof(struct IPv4TcpAddress);
780     return GNUNET_OK;
781   }
782   case AF_INET6:
783   {
784     struct IPv6TcpAddress *t6;
785     struct sockaddr_in6 *in6 = (struct sockaddr_in6 *) &socket_address;
786     t6 = GNUNET_new (struct IPv6TcpAddress);
787     t6->options = htonl (options);
788     t6->ipv6_addr = in6->sin6_addr;
789     t6->t6_port = in6->sin6_port;
790     *buf = t6;
791     *added = sizeof(struct IPv6TcpAddress);
792     return GNUNET_OK;
793   }
794   default:
795     return GNUNET_SYSERR;
796   }
797 }
798
799
800 /**
801  * Find the session handle for the given client.
802  * Currently uses both the hashmap and the client
803  * context, as the client context is new and the
804  * logic still needs to be tested.
805  *
806  * @param plugin the plugin
807  * @param client which client to find the session handle for
808  * @return NULL if no matching session exists
809  */
810 static struct Session *
811 lookup_session_by_client (struct Plugin *plugin,
812                           struct GNUNET_SERVER_Client *client)
813 {
814   return GNUNET_SERVER_client_get_user_context (client, struct Session);
815 }
816
817
818 /**
819  * Functions with this signature are called whenever we need
820  * to close a session due to a disconnect or failure to
821  * establish a connection.
822  *
823  * @param cls the `struct Plugin`
824  * @param session session to close down
825  * @return #GNUNET_OK on success
826  */
827 static int
828 tcp_plugin_disconnect_session (void *cls,
829                                struct Session *session)
830 {
831   struct Plugin *plugin = cls;
832   struct PendingMessage *pm;
833
834   LOG (GNUNET_ERROR_TYPE_DEBUG,
835        "Disconnecting session of peer `%s' address `%s'\n",
836        GNUNET_i2s (&session->target),
837        tcp_plugin_address_to_string (session->plugin,
838                                      session->address->address,
839                                      session->address->address_length));
840
841   if (NULL != session->timeout_task)
842   {
843     GNUNET_SCHEDULER_cancel (session->timeout_task);
844     session->timeout_task = NULL;
845     session->timeout = GNUNET_TIME_UNIT_ZERO_ABS;
846   }
847
848   if (GNUNET_YES ==
849       GNUNET_CONTAINER_multipeermap_remove (plugin->sessionmap,
850                                             &session->target,
851                                             session))
852   {
853     GNUNET_STATISTICS_update (session->plugin->env->stats,
854                               gettext_noop ("# TCP sessions active"), 
855                               -1,
856                               GNUNET_NO);
857   }
858   else
859   {
860     GNUNET_assert (GNUNET_YES ==
861                    GNUNET_CONTAINER_multipeermap_remove (plugin->nat_wait_conns,
862                                                          &session->target,
863                                                          session));
864   }
865   if (NULL != session->client)
866     GNUNET_SERVER_client_set_user_context (session->client,
867                                            NULL);
868
869   /* clean up state */
870   if (NULL != session->transmit_handle)
871   {
872     GNUNET_SERVER_notify_transmit_ready_cancel (session->transmit_handle);
873     session->transmit_handle = NULL;
874   }
875   session->plugin->env->session_end (session->plugin->env->cls,
876                                      session->address,
877                                      session);
878
879   if (NULL != session->nat_connection_timeout)
880   {
881     GNUNET_SCHEDULER_cancel (session->nat_connection_timeout);
882     session->nat_connection_timeout = NULL;
883   }
884
885   while (NULL != (pm = session->pending_messages_head))
886   {
887     LOG (GNUNET_ERROR_TYPE_DEBUG,
888          (NULL != pm->transmit_cont)
889          ? "Could not deliver message to `%s' at %s.\n"
890          : "Could not deliver message to `%s' at %s, notifying.\n",
891          GNUNET_i2s (&session->target),
892          tcp_plugin_address_to_string (session->plugin,
893                                        session->address->address,
894                                        session->address->address_length));
895     GNUNET_STATISTICS_update (session->plugin->env->stats,
896                               gettext_noop ("# bytes currently in TCP buffers"),
897                               -(int64_t) pm->message_size, GNUNET_NO);
898     GNUNET_STATISTICS_update (session->plugin->env->stats,
899                               gettext_noop ("# bytes discarded by TCP (disconnect)"),
900                               pm->message_size,
901                               GNUNET_NO);
902     GNUNET_CONTAINER_DLL_remove (session->pending_messages_head,
903                                  session->pending_messages_tail,
904                                  pm);
905     GNUNET_assert (0 < session->msgs_in_queue);
906     session->msgs_in_queue--;
907     GNUNET_assert (pm->message_size <= session->bytes_in_queue);
908     session->bytes_in_queue -= pm->message_size;
909     if (NULL != pm->transmit_cont)
910       pm->transmit_cont (pm->transmit_cont_cls,
911                          &session->target,
912                          GNUNET_SYSERR,
913                          pm->message_size,
914                          0);
915     GNUNET_free (pm);
916   }
917   GNUNET_assert (0 == session->msgs_in_queue);
918   GNUNET_assert (0 == session->bytes_in_queue);
919   notify_session_monitor (session->plugin,
920                           session,
921                           GNUNET_TRANSPORT_SS_DONE);
922
923   if (NULL != session->receive_delay_task)
924   {
925     GNUNET_SCHEDULER_cancel (session->receive_delay_task);
926     if (NULL != session->client)
927       GNUNET_SERVER_receive_done (session->client, GNUNET_SYSERR);
928   }
929   if (NULL != session->client)
930   {
931     GNUNET_SERVER_client_disconnect (session->client);
932     GNUNET_SERVER_client_drop (session->client);
933     session->client = NULL;
934   }
935   GNUNET_HELLO_address_free (session->address);
936   GNUNET_assert(NULL == session->transmit_handle);
937   GNUNET_free(session);
938   return GNUNET_OK;
939 }
940
941
942 /**
943  * Function that is called to get the keepalive factor.
944  * #GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT is divided by this number to
945  * calculate the interval between keepalive packets.
946  *
947  * @param cls closure with the `struct Plugin`
948  * @return keepalive factor
949  */
950 static unsigned int
951 tcp_plugin_query_keepalive_factor (void *cls)
952 {
953   return 3;
954 }
955
956
957 /**
958  * Session was idle for too long, so disconnect it
959  *
960  * @param cls the `struct Session` of the idle session
961  * @param tc scheduler context
962  */
963 static void
964 session_timeout (void *cls,
965                  const struct GNUNET_SCHEDULER_TaskContext *tc)
966 {
967   struct Session *s = cls;
968   struct GNUNET_TIME_Relative left;
969
970   s->timeout_task = NULL;
971   left = GNUNET_TIME_absolute_get_remaining (s->timeout);
972   if (0 != left.rel_value_us)
973   {
974     /* not actually our turn yet, but let's at least update
975        the monitor, it may think we're about to die ... */
976     notify_session_monitor (s->plugin,
977                             s,
978                             GNUNET_TRANSPORT_SS_UPDATE);
979     s->timeout_task = GNUNET_SCHEDULER_add_delayed (left,
980                                                     &session_timeout,
981                                                     s);
982     return;
983   }
984   LOG (GNUNET_ERROR_TYPE_DEBUG,
985        "Session %p was idle for %s, disconnecting\n",
986        s,
987        GNUNET_STRINGS_relative_time_to_string (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
988                                                GNUNET_YES));
989   /* call session destroy function */
990   tcp_plugin_disconnect_session (s->plugin, 
991                                  s);
992 }
993
994
995 /**
996  * Increment session timeout due to activity.
997  *
998  * @param s session to increment timeout for
999  */
1000 static void
1001 reschedule_session_timeout (struct Session *s)
1002 {
1003   GNUNET_assert (NULL != s->timeout_task);
1004   s->timeout = GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1005 }
1006
1007
1008 /**
1009  * Create a new session.  Also queues a welcome message.
1010  *
1011  * @param plugin the plugin
1012  * @param address the address to create the session for
1013  * @param client client to use, reference counter must have already been increased
1014  * @param is_nat this a NAT session, we should wait for a client to
1015  *               connect to us from an address, then assign that to
1016  *               the session
1017  * @return new session object
1018  */
1019 static struct Session *
1020 create_session (struct Plugin *plugin,
1021                 const struct GNUNET_HELLO_Address *address,
1022                 struct GNUNET_SERVER_Client *client,
1023                 int is_nat)
1024 {
1025   struct Session *session;
1026   struct PendingMessage *pm;
1027
1028   if (GNUNET_YES != is_nat)
1029     GNUNET_assert (NULL != client);
1030   else
1031     GNUNET_assert (NULL == client);
1032
1033   LOG (GNUNET_ERROR_TYPE_DEBUG,
1034        "Creating new session for peer `%4s' at address %s\n",
1035        GNUNET_i2s (&address->peer),
1036        tcp_plugin_address_to_string (plugin,
1037                                      address->address,
1038                                      address->address_length));
1039   session = GNUNET_new (struct Session);
1040   session->last_activity = GNUNET_TIME_absolute_get ();
1041   session->plugin = plugin;
1042   session->is_nat = is_nat;
1043   session->client = client;
1044   session->address = GNUNET_HELLO_address_copy (address);
1045   session->target = address->peer;
1046   session->expecting_welcome = GNUNET_YES;
1047   session->scope = GNUNET_ATS_NET_UNSPECIFIED;
1048   pm = GNUNET_malloc (sizeof (struct PendingMessage) +
1049                       sizeof (struct WelcomeMessage));
1050   pm->msg = (const char *) &pm[1];
1051   pm->message_size = sizeof(struct WelcomeMessage);
1052   memcpy (&pm[1],
1053           &plugin->my_welcome,
1054           sizeof(struct WelcomeMessage));
1055   pm->timeout = GNUNET_TIME_UNIT_FOREVER_ABS;
1056   GNUNET_STATISTICS_update (plugin->env->stats,
1057                             gettext_noop ("# bytes currently in TCP buffers"),
1058                             pm->message_size,
1059                             GNUNET_NO);
1060   GNUNET_CONTAINER_DLL_insert (session->pending_messages_head,
1061                                session->pending_messages_tail,
1062                                pm);
1063   session->msgs_in_queue++;
1064   session->bytes_in_queue += pm->message_size;
1065   session->timeout = GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1066   session->timeout_task = GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
1067                                                         &session_timeout,
1068                                                         session);
1069   notify_session_monitor (session->plugin,
1070                           session,
1071                           GNUNET_TRANSPORT_SS_INIT);
1072   if (GNUNET_YES != is_nat)
1073   {
1074     GNUNET_STATISTICS_update (plugin->env->stats,
1075                               gettext_noop ("# TCP sessions active"),
1076                               1,
1077                               GNUNET_NO);
1078     notify_session_monitor (session->plugin,
1079                             session,
1080                             GNUNET_TRANSPORT_SS_UP);
1081   }
1082   else
1083   {
1084     notify_session_monitor (session->plugin,
1085                             session,
1086                             GNUNET_TRANSPORT_SS_HANDSHAKE);
1087   }
1088   return session;
1089 }
1090
1091
1092 /**
1093  * If we have pending messages, ask the server to
1094  * transmit them (schedule the respective tasks, etc.)
1095  *
1096  * @param session for which session should we do this
1097  */
1098 static void
1099 process_pending_messages (struct Session *session);
1100
1101
1102 /**
1103  * Function called to notify a client about the socket
1104  * being ready to queue more data.  "buf" will be
1105  * NULL and "size" zero if the socket was closed for
1106  * writing in the meantime.
1107  *
1108  * @param cls closure
1109  * @param size number of bytes available in @a buf
1110  * @param buf where the callee should write the message
1111  * @return number of bytes written to @a buf
1112  */
1113 static size_t
1114 do_transmit (void *cls, 
1115              size_t size,
1116              void *buf)
1117 {
1118   struct Session *session = cls;
1119   struct GNUNET_PeerIdentity pid;
1120   struct Plugin *plugin;
1121   struct PendingMessage *pos;
1122   struct PendingMessage *hd;
1123   struct PendingMessage *tl;
1124   struct GNUNET_TIME_Absolute now;
1125   char *cbuf;
1126   size_t ret;
1127
1128   session->transmit_handle = NULL;
1129   plugin = session->plugin;
1130   if (NULL == buf)
1131   {
1132     LOG (GNUNET_ERROR_TYPE_DEBUG,
1133          "Timeout trying to transmit to peer `%4s', discarding message queue.\n",
1134          GNUNET_i2s (&session->target));
1135     /* timeout; cancel all messages that have already expired */
1136     hd = NULL;
1137     tl = NULL;
1138     ret = 0;
1139     now = GNUNET_TIME_absolute_get ();
1140     while ( (NULL != (pos = session->pending_messages_head)) &&
1141             (pos->timeout.abs_value_us <= now.abs_value_us) )
1142     {
1143       GNUNET_CONTAINER_DLL_remove (session->pending_messages_head,
1144                                    session->pending_messages_tail,
1145                                    pos);
1146       GNUNET_assert (0 < session->msgs_in_queue);
1147       session->msgs_in_queue--;
1148       GNUNET_assert (pos->message_size <= session->bytes_in_queue);
1149       session->bytes_in_queue -= pos->message_size;
1150       LOG (GNUNET_ERROR_TYPE_DEBUG,
1151            "Failed to transmit %u byte message to `%4s'.\n",
1152            pos->message_size,
1153            GNUNET_i2s (&session->target));
1154       ret += pos->message_size;
1155       GNUNET_CONTAINER_DLL_insert_after (hd,
1156                                          tl,
1157                                          tl,
1158                                          pos);
1159     }
1160     /* do this call before callbacks (so that if callbacks destroy
1161      * session, they have a chance to cancel actions done by this
1162      * call) */
1163     process_pending_messages (session);
1164     pid = session->target;
1165     /* no do callbacks and do not use session again since
1166      * the callbacks may abort the session */
1167     while (NULL != (pos = hd))
1168     {
1169       GNUNET_CONTAINER_DLL_remove (hd,
1170                                    tl,
1171                                    pos);
1172       if (NULL != pos->transmit_cont)
1173         pos->transmit_cont (pos->transmit_cont_cls,
1174                             &pid,
1175                             GNUNET_SYSERR,
1176                             pos->message_size,
1177                             0);
1178       GNUNET_free (pos);
1179     }
1180     GNUNET_STATISTICS_update (plugin->env->stats,
1181                               gettext_noop ("# bytes currently in TCP buffers"), -(int64_t) ret,
1182                               GNUNET_NO);
1183     GNUNET_STATISTICS_update (plugin->env->stats,
1184                               gettext_noop ("# bytes discarded by TCP (timeout)"),
1185                               ret,
1186                               GNUNET_NO);
1187     if (0 < ret)
1188       notify_session_monitor (session->plugin,
1189                               session,
1190                               GNUNET_TRANSPORT_SS_UPDATE);
1191     return 0;
1192   }
1193   /* copy all pending messages that would fit */
1194   ret = 0;
1195   cbuf = buf;
1196   hd = NULL;
1197   tl = NULL;
1198   while (NULL != (pos = session->pending_messages_head))
1199   {
1200     if (ret + pos->message_size > size)
1201       break;
1202     GNUNET_CONTAINER_DLL_remove (session->pending_messages_head,
1203                                  session->pending_messages_tail,
1204                                  pos);
1205     GNUNET_assert (0 < session->msgs_in_queue);
1206     session->msgs_in_queue--;
1207     GNUNET_assert (pos->message_size <= session->bytes_in_queue);
1208     session->bytes_in_queue -= pos->message_size;
1209     GNUNET_assert(size >= pos->message_size);
1210     LOG (GNUNET_ERROR_TYPE_DEBUG,
1211          "Transmitting message of type %u size %u to peer %s at %s\n",
1212          ntohs (((struct GNUNET_MessageHeader *) pos->msg)->type),
1213          pos->message_size,
1214          GNUNET_i2s (&session->target),
1215          tcp_plugin_address_to_string (session->plugin,
1216                                        session->address->address,
1217                                        session->address->address_length));
1218     /* FIXME: this memcpy can be up to 7% of our total runtime */
1219     memcpy (cbuf,
1220             pos->msg,
1221             pos->message_size);
1222     cbuf += pos->message_size;
1223     ret += pos->message_size;
1224     size -= pos->message_size;
1225     GNUNET_CONTAINER_DLL_insert_tail (hd,
1226                                       tl,
1227                                       pos);
1228   }
1229   notify_session_monitor (session->plugin,
1230                           session,
1231                           GNUNET_TRANSPORT_SS_UPDATE);
1232   /* schedule 'continuation' before callbacks so that callbacks that
1233    * cancel everything don't cause us to use a session that no longer
1234    * exists... */
1235   process_pending_messages (session);
1236   session->last_activity = GNUNET_TIME_absolute_get ();
1237   pid = session->target;
1238   /* we'll now call callbacks that may cancel the session; hence
1239    * we should not use 'session' after this point */
1240   while (NULL != (pos = hd))
1241   {
1242     GNUNET_CONTAINER_DLL_remove (hd, tl, pos);
1243     if (NULL != pos->transmit_cont)
1244       pos->transmit_cont (pos->transmit_cont_cls,
1245                           &pid,
1246                           GNUNET_OK,
1247                           pos->message_size,
1248                           pos->message_size); /* FIXME: include TCP overhead */
1249     GNUNET_free (pos);
1250   }
1251   GNUNET_assert (NULL == hd);
1252   GNUNET_assert (NULL == tl);
1253   GNUNET_STATISTICS_update (plugin->env->stats,
1254                             gettext_noop ("# bytes currently in TCP buffers"),
1255                             - (int64_t) ret,
1256                             GNUNET_NO);
1257   GNUNET_STATISTICS_update (plugin->env->stats,
1258                             gettext_noop ("# bytes transmitted via TCP"),
1259                             ret,
1260                             GNUNET_NO);
1261   return ret;
1262 }
1263
1264
1265 /**
1266  * If we have pending messages, ask the server to
1267  * transmit them (schedule the respective tasks, etc.)
1268  *
1269  * @param session for which session should we do this
1270  */
1271 static void
1272 process_pending_messages (struct Session *session)
1273 {
1274   struct PendingMessage *pm;
1275
1276   GNUNET_assert (NULL != session->client);
1277   if (NULL != session->transmit_handle)
1278     return;
1279   if (NULL == (pm = session->pending_messages_head))
1280     return;
1281
1282   session->transmit_handle = GNUNET_SERVER_notify_transmit_ready (session->client,
1283                                                                   pm->message_size,
1284                                                                   GNUNET_TIME_absolute_get_remaining (pm->timeout),
1285                                                                   &do_transmit,
1286                                                                   session);
1287 }
1288
1289
1290 /**
1291  * Function that can be used by the transport service to transmit
1292  * a message using the plugin.   Note that in the case of a
1293  * peer disconnecting, the continuation MUST be called
1294  * prior to the disconnect notification itself.  This function
1295  * will be called with this peer's HELLO message to initiate
1296  * a fresh connection to another peer.
1297  *
1298  * @param cls closure
1299  * @param session which session must be used
1300  * @param msgbuf the message to transmit
1301  * @param msgbuf_size number of bytes in @a msgbuf
1302  * @param priority how important is the message (most plugins will
1303  *                 ignore message priority and just FIFO)
1304  * @param to how long to wait at most for the transmission (does not
1305  *                require plugins to discard the message after the timeout,
1306  *                just advisory for the desired delay; most plugins will ignore
1307  *                this as well)
1308  * @param cont continuation to call once the message has
1309  *        been transmitted (or if the transport is ready
1310  *        for the next transmission call; or if the
1311  *        peer disconnected...); can be NULL
1312  * @param cont_cls closure for @a cont
1313  * @return number of bytes used (on the physical network, with overheads);
1314  *         -1 on hard errors (i.e. address invalid); 0 is a legal value
1315  *         and does NOT mean that the message was not transmitted (DV)
1316  */
1317 static ssize_t
1318 tcp_plugin_send (void *cls,
1319                  struct Session *session,
1320                  const char *msgbuf,
1321                  size_t msgbuf_size,
1322                  unsigned int priority,
1323                  struct GNUNET_TIME_Relative to,
1324                  GNUNET_TRANSPORT_TransmitContinuation cont,
1325                  void *cont_cls)
1326 {
1327   struct Plugin * plugin = cls;
1328   struct PendingMessage *pm;
1329
1330   /* create new message entry */
1331   pm = GNUNET_malloc (sizeof (struct PendingMessage) + msgbuf_size);
1332   pm->msg = (const char *) &pm[1];
1333   memcpy (&pm[1], msgbuf, msgbuf_size);
1334   pm->message_size = msgbuf_size;
1335   pm->timeout = GNUNET_TIME_relative_to_absolute (to);
1336   pm->transmit_cont = cont;
1337   pm->transmit_cont_cls = cont_cls;
1338
1339   LOG(GNUNET_ERROR_TYPE_DEBUG,
1340       "Asked to transmit %u bytes to `%s', added message to list.\n",
1341       msgbuf_size,
1342       GNUNET_i2s (&session->target));
1343
1344   if (GNUNET_YES ==
1345       GNUNET_CONTAINER_multipeermap_contains_value (plugin->sessionmap,
1346                                                     &session->target,
1347                                                     session))
1348   {
1349     GNUNET_assert (NULL != session->client);
1350     GNUNET_SERVER_client_set_timeout (session->client,
1351                                       GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1352     GNUNET_STATISTICS_update (plugin->env->stats,
1353                               gettext_noop ("# bytes currently in TCP buffers"),
1354                               msgbuf_size,
1355                               GNUNET_NO);
1356
1357     /* append pm to pending_messages list */
1358     GNUNET_CONTAINER_DLL_insert_tail (session->pending_messages_head,
1359                                       session->pending_messages_tail,
1360                                       pm);
1361     notify_session_monitor (session->plugin,
1362                             session,
1363                             GNUNET_TRANSPORT_SS_UPDATE);
1364     session->msgs_in_queue++;
1365     session->bytes_in_queue += pm->message_size;
1366     process_pending_messages (session);
1367     return msgbuf_size;
1368   }
1369   if (GNUNET_YES ==
1370       GNUNET_CONTAINER_multipeermap_contains_value (plugin->nat_wait_conns,
1371                                                     &session->target,
1372                                                     session))
1373   {
1374     LOG (GNUNET_ERROR_TYPE_DEBUG,
1375          "This NAT WAIT session for peer `%s' is not yet ready!\n",
1376          GNUNET_i2s (&session->target));
1377     GNUNET_STATISTICS_update (plugin->env->stats,
1378                               gettext_noop ("# bytes currently in TCP buffers"), msgbuf_size,
1379                               GNUNET_NO);
1380     /* append pm to pending_messages list */
1381     GNUNET_CONTAINER_DLL_insert_tail (session->pending_messages_head,
1382                                       session->pending_messages_tail,
1383                                       pm);
1384     session->msgs_in_queue++;
1385     session->bytes_in_queue += pm->message_size;
1386     notify_session_monitor (session->plugin,
1387                             session,
1388                             GNUNET_TRANSPORT_SS_HANDSHAKE);
1389     return msgbuf_size;
1390   }
1391   LOG (GNUNET_ERROR_TYPE_ERROR,
1392        "Invalid session %p\n",
1393        session);
1394   if (NULL != cont)
1395     cont (cont_cls,
1396           &session->target,
1397           GNUNET_SYSERR,
1398           pm->message_size,
1399           0);
1400   GNUNET_break (0);
1401   GNUNET_free (pm);
1402   return GNUNET_SYSERR; /* session does not exist here */
1403 }
1404
1405
1406 /**
1407  * Closure for #session_lookup_it().
1408  */
1409 struct SessionItCtx
1410 {
1411   /**
1412    * Address we are looking for.
1413    */
1414   const struct GNUNET_HELLO_Address *address;
1415
1416   /**
1417    * Where to store the session (if we found it).
1418    */
1419   struct Session *result;
1420
1421 };
1422
1423
1424 /**
1425  * Look for a session by address.
1426  *
1427  * @param cls the `struct SessionItCtx`
1428  * @param key unused
1429  * @param value a `struct Session`
1430  * @return #GNUNET_YES to continue looking, #GNUNET_NO if we found the session
1431  */
1432 static int
1433 session_lookup_it (void *cls,
1434                    const struct GNUNET_PeerIdentity *key,
1435                    void *value)
1436 {
1437   struct SessionItCtx *si_ctx = cls;
1438   struct Session *session = value;
1439
1440   if (0 !=
1441       GNUNET_HELLO_address_cmp (si_ctx->address,
1442                                 session->address))
1443     return GNUNET_YES;
1444   si_ctx->result = session;
1445   return GNUNET_NO;
1446 }
1447
1448
1449 /**
1450  * Task cleaning up a NAT connection attempt after timeout
1451  *
1452  * @param cls the `struct Session`
1453  * @param tc scheduler context (unused)
1454  */
1455 static void
1456 nat_connect_timeout (void *cls,
1457                      const struct GNUNET_SCHEDULER_TaskContext *tc)
1458 {
1459   struct Session *session = cls;
1460
1461   session->nat_connection_timeout = NULL;
1462   LOG (GNUNET_ERROR_TYPE_DEBUG,
1463        "NAT WAIT connection to `%4s' at `%s' could not be established, removing session\n",
1464        GNUNET_i2s (&session->target),
1465        tcp_plugin_address_to_string (session->plugin,
1466                                      session->address->address,
1467                                      session->address->address_length));
1468   tcp_plugin_disconnect_session (session->plugin,
1469                                  session);
1470 }
1471
1472
1473 /**
1474  * Function that will be called whenever the transport service wants to
1475  * notify the plugin that a session is still active and in use and
1476  * therefore the session timeout for this session has to be updated
1477  *
1478  * @param cls closure
1479  * @param peer which peer was the session for
1480  * @param session which session is being updated
1481  */
1482 static void
1483 tcp_plugin_update_session_timeout (void *cls,
1484                                    const struct GNUNET_PeerIdentity *peer,
1485                                    struct Session *session)
1486 {
1487   reschedule_session_timeout (session);
1488 }
1489
1490
1491 /**
1492  * Task to signal the server that we can continue
1493  * receiving from the TCP client now.
1494  *
1495  * @param cls the `struct Session *`
1496  * @param tc task context (unused)
1497  */
1498 static void
1499 delayed_done (void *cls,
1500               const struct GNUNET_SCHEDULER_TaskContext *tc)
1501 {
1502   struct Session *session = cls;
1503
1504   session->receive_delay_task = NULL;
1505   reschedule_session_timeout (session);
1506   GNUNET_SERVER_receive_done (session->client, 
1507                               GNUNET_OK);
1508 }
1509
1510
1511 /**
1512  * Function that will be called whenever the transport service wants to
1513  * notify the plugin that the inbound quota changed and that the plugin
1514  * should update it's delay for the next receive value
1515  *
1516  * @param cls closure
1517  * @param peer which peer was the session for
1518  * @param session which session is being updated
1519  * @param delay new delay to use for receiving
1520  */
1521 static void
1522 tcp_plugin_update_inbound_delay (void *cls,
1523                                  const struct GNUNET_PeerIdentity *peer,
1524                                  struct Session *session,
1525                                  struct GNUNET_TIME_Relative delay)
1526 {
1527   if (NULL == session->receive_delay_task)
1528     return;
1529   LOG (GNUNET_ERROR_TYPE_DEBUG,
1530        "New inbound delay %s\n",
1531        GNUNET_STRINGS_relative_time_to_string (delay,
1532                                                GNUNET_NO));
1533   session->receive_delay = GNUNET_TIME_relative_to_absolute (delay);
1534   GNUNET_SCHEDULER_cancel (session->receive_delay_task);
1535   session->receive_delay_task = GNUNET_SCHEDULER_add_delayed (delay,
1536                                                               &delayed_done,
1537                                                               session);
1538 }
1539
1540
1541 /**
1542  * Create a new session to transmit data to the target
1543  * This session will used to send data to this peer and the plugin will
1544  * notify us by calling the env->session_end function
1545  *
1546  * @param cls closure
1547  * @param address the address to use
1548  * @return the session if the address is valid, NULL otherwise
1549  */
1550 static struct Session *
1551 tcp_plugin_get_session (void *cls,
1552                         const struct GNUNET_HELLO_Address *address)
1553 {
1554   struct Plugin *plugin = cls;
1555   struct Session *session = NULL;
1556   int af;
1557   const void *sb;
1558   size_t sbs;
1559   struct GNUNET_CONNECTION_Handle *sa;
1560   struct sockaddr_in a4;
1561   struct sockaddr_in6 a6;
1562   const struct IPv4TcpAddress *t4;
1563   const struct IPv6TcpAddress *t6;
1564   unsigned int options;
1565   enum GNUNET_ATS_Network_Type net_type;
1566   unsigned int is_natd = GNUNET_NO;
1567   size_t addrlen;
1568 #ifdef TCP_STEALTH
1569   struct GNUNET_NETWORK_Handle *s;
1570 #endif
1571
1572   addrlen = address->address_length;
1573   LOG (GNUNET_ERROR_TYPE_DEBUG,
1574        "Trying to get session for `%s' address of peer `%s'\n",
1575        tcp_plugin_address_to_string (plugin,
1576                                      address->address,
1577                                      address->address_length),
1578        GNUNET_i2s (&address->peer));
1579
1580   if (GNUNET_HELLO_address_check_option (address,
1581                                          GNUNET_HELLO_ADDRESS_INFO_INBOUND))
1582   {
1583     GNUNET_break (0);
1584     return NULL;
1585   }
1586
1587   /* look for existing session */
1588   if (GNUNET_YES ==
1589       GNUNET_CONTAINER_multipeermap_contains (plugin->sessionmap,
1590                                               &address->peer))
1591   {
1592     struct SessionItCtx si_ctx;
1593
1594     si_ctx.address = address;
1595     si_ctx.result = NULL;
1596     GNUNET_CONTAINER_multipeermap_get_multiple (plugin->sessionmap,
1597                                                 &address->peer,
1598                                                 &session_lookup_it, 
1599                                                 &si_ctx);
1600     if (NULL != si_ctx.result)
1601     {
1602       session = si_ctx.result;
1603       LOG (GNUNET_ERROR_TYPE_DEBUG,
1604            "Found existing session for `%s' address `%s'\n",
1605            GNUNET_i2s (&address->peer),
1606            tcp_plugin_address_to_string (plugin,
1607                                          address->address,
1608                                          address->address_length));
1609       return session;
1610     }
1611   }
1612
1613   if (addrlen == sizeof(struct IPv6TcpAddress))
1614   {
1615     GNUNET_assert (NULL != address->address); /* make static analysis happy */
1616     t6 = address->address;
1617     options = t6->options;
1618     af = AF_INET6;
1619     memset (&a6, 0, sizeof(a6));
1620 #if HAVE_SOCKADDR_IN_SIN_LEN
1621     a6.sin6_len = sizeof (a6);
1622 #endif
1623     a6.sin6_family = AF_INET6;
1624     a6.sin6_port = t6->t6_port;
1625     if (t6->t6_port == 0)
1626       is_natd = GNUNET_YES;
1627     memcpy (&a6.sin6_addr, &t6->ipv6_addr, sizeof(struct in6_addr));
1628     sb = &a6;
1629     sbs = sizeof(a6);
1630   }
1631   else if (addrlen == sizeof(struct IPv4TcpAddress))
1632   {
1633     GNUNET_assert(NULL != address->address); /* make static analysis happy */
1634     t4 = address->address;
1635     options = t4->options;
1636     af = AF_INET;
1637     memset (&a4, 0, sizeof(a4));
1638 #if HAVE_SOCKADDR_IN_SIN_LEN
1639     a4.sin_len = sizeof (a4);
1640 #endif
1641     a4.sin_family = AF_INET;
1642     a4.sin_port = t4->t4_port;
1643     if (t4->t4_port == 0)
1644       is_natd = GNUNET_YES;
1645     a4.sin_addr.s_addr = t4->ipv4_addr;
1646     sb = &a4;
1647     sbs = sizeof(a4);
1648   }
1649   else
1650   {
1651     GNUNET_STATISTICS_update (plugin->env->stats,
1652                               gettext_noop ("# requests to create session with invalid address"),
1653                               1,
1654                               GNUNET_NO);
1655     return NULL;
1656   }
1657
1658   net_type = plugin->env->get_address_type (plugin->env->cls,
1659                                             sb,
1660                                             sbs);
1661   GNUNET_break (net_type != GNUNET_ATS_NET_UNSPECIFIED);
1662
1663   if ( (is_natd == GNUNET_YES) && 
1664        (addrlen == sizeof(struct IPv6TcpAddress)) )
1665   {
1666     /* NAT client only works with IPv4 addresses */
1667     return NULL;
1668   }
1669
1670   if (plugin->cur_connections >= plugin->max_connections)
1671   {
1672     /* saturated */
1673     return NULL;
1674   }
1675
1676   if ( (is_natd == GNUNET_YES) &&
1677        (GNUNET_YES == 
1678         GNUNET_CONTAINER_multipeermap_contains (plugin->nat_wait_conns,
1679                                                 &address->peer)))
1680   {
1681     /* Only do one NAT punch attempt per peer identity */
1682     return NULL;
1683   }
1684
1685   if ( (is_natd == GNUNET_YES) &&
1686        (NULL != plugin->nat) &&
1687        (GNUNET_NO ==
1688         GNUNET_CONTAINER_multipeermap_contains (plugin->nat_wait_conns,
1689                                                 &address->peer)))
1690   {
1691     LOG (GNUNET_ERROR_TYPE_DEBUG,
1692          "Found valid IPv4 NAT address (creating session)!\n");
1693     session = create_session (plugin,
1694                               address,
1695                               NULL,
1696                               GNUNET_YES);
1697     session->scope = net_type;
1698     session->nat_connection_timeout = GNUNET_SCHEDULER_add_delayed (NAT_TIMEOUT,
1699                                                                     &nat_connect_timeout,
1700                                                                     session);
1701     GNUNET_assert(GNUNET_OK ==
1702                   GNUNET_CONTAINER_multipeermap_put (plugin->nat_wait_conns,
1703                                                      &session->target,
1704                                                      session,
1705                                                      GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1706
1707     LOG (GNUNET_ERROR_TYPE_DEBUG,
1708          "Created NAT WAIT connection to `%4s' at `%s'\n",
1709          GNUNET_i2s (&session->target),
1710          GNUNET_a2s (sb, sbs));
1711     if (GNUNET_OK == GNUNET_NAT_run_client (plugin->nat, &a4))
1712     {
1713       return session;
1714     }
1715     else
1716     {
1717       LOG(GNUNET_ERROR_TYPE_DEBUG,
1718           "Running NAT client for `%4s' at `%s' failed\n",
1719           GNUNET_i2s (&session->target),
1720           GNUNET_a2s (sb, sbs));
1721       tcp_plugin_disconnect_session (plugin,
1722                                      session);
1723       return NULL;
1724     }
1725   }
1726
1727   /* create new outbound session */
1728   if (0 != (options & TCP_OPTIONS_TCP_STEALTH))
1729   {
1730 #ifdef TCP_STEALTH
1731     s = GNUNET_NETWORK_socket_create (af, SOCK_STREAM, 0);
1732     if (NULL == s)
1733     {
1734       GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK,
1735                            "socket");
1736       sa = NULL;
1737     }
1738     else
1739     {
1740       if ( (GNUNET_OK !=
1741             GNUNET_NETWORK_socket_setsockopt (s,
1742                                               IPPROTO_TCP,
1743                                               TCP_STEALTH,
1744                                               &session->target,
1745                                               sizeof (struct GNUNET_PeerIdentity))) ||
1746            (GNUNET_OK !=
1747             GNUNET_NETWORK_socket_setsockopt (s,
1748                                               IPPROTO_TCP,
1749                                               TCP_STEALTH_INTEGRITY,
1750                                               &plugin->my_welcome,
1751                                               sizeof (struct WelcomeMessage))) )
1752       {
1753         /* TCP STEALTH not supported by kernel */
1754         GNUNET_break (GNUNET_OK ==
1755                       GNUNET_NETWORK_socket_close (s));
1756         sa = NULL;
1757       }
1758       else
1759       {
1760         sa = GNUNET_CONNECTION_connect_socket (s, sb, sbs);
1761       }
1762     }
1763 #else
1764     sa = NULL;
1765 #endif
1766   }
1767   else
1768   {
1769     sa = GNUNET_CONNECTION_create_from_sockaddr (af, sb, sbs);
1770   }
1771   if (NULL == sa)
1772   {
1773     LOG (GNUNET_ERROR_TYPE_DEBUG,
1774          "Failed to create connection to `%4s' at `%s'\n",
1775          GNUNET_i2s (&address->peer),
1776          GNUNET_a2s (sb, sbs));
1777     return NULL;
1778   }
1779   LOG (GNUNET_ERROR_TYPE_DEBUG,
1780        "Asked to transmit to `%4s', creating fresh session using address `%s'.\n",
1781        GNUNET_i2s (&address->peer),
1782        GNUNET_a2s (sb, sbs));
1783
1784   session = create_session (plugin,
1785                             address,
1786                             GNUNET_SERVER_connect_socket (plugin->server, sa),
1787                             GNUNET_NO);
1788   session->scope = net_type;
1789   GNUNET_SERVER_client_set_user_context (session->client,
1790                                          session);
1791   GNUNET_CONTAINER_multipeermap_put (plugin->sessionmap,
1792                                      &session->target,
1793                                      session,
1794                                      GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
1795   /* Send TCP Welcome */
1796   process_pending_messages (session);
1797
1798   return session;
1799 }
1800
1801
1802 /**
1803  * We have been asked to destroy all connections to a particular peer.
1804  * This function is called on each applicable session and must tear it
1805  * down.
1806  *
1807  * @param cls the `struct Plugin *`
1808  * @param key the peer which the session belongs to (unused)
1809  * @param value the `struct Session`
1810  * @return #GNUNET_YES (continue to iterate)
1811  */ 
1812 static int
1813 session_disconnect_it (void *cls,
1814                        const struct GNUNET_PeerIdentity *key,
1815                        void *value)
1816 {
1817   struct Plugin *plugin = cls;
1818   struct Session *session = value;
1819
1820   GNUNET_STATISTICS_update (session->plugin->env->stats,
1821                             gettext_noop ("# transport-service disconnect requests for TCP"),
1822                             1,
1823                             GNUNET_NO);
1824   tcp_plugin_disconnect_session (plugin,
1825                                  session);
1826   return GNUNET_YES;
1827 }
1828
1829
1830 /**
1831  * Function that can be called to force a disconnect from the
1832  * specified neighbour.  This should also cancel all previously
1833  * scheduled transmissions.  Obviously the transmission may have been
1834  * partially completed already, which is OK.  The plugin is supposed
1835  * to close the connection (if applicable) and no longer call the
1836  * transmit continuation(s).
1837  *
1838  * Finally, plugin MUST NOT call the services's receive function to
1839  * notify the service that the connection to the specified target was
1840  * closed after a getting this call.
1841  *
1842  * @param cls closure
1843  * @param target peer for which the last transmission is
1844  *        to be cancelled
1845  */
1846 static void
1847 tcp_plugin_disconnect (void *cls,
1848                        const struct GNUNET_PeerIdentity *target)
1849 {
1850   struct Plugin *plugin = cls;
1851
1852   LOG (GNUNET_ERROR_TYPE_DEBUG,
1853        "Disconnecting peer `%4s'\n",
1854        GNUNET_i2s (target));
1855   GNUNET_CONTAINER_multipeermap_get_multiple (plugin->sessionmap,
1856                                               target,
1857                                               &session_disconnect_it,
1858                                               plugin);
1859   GNUNET_CONTAINER_multipeermap_get_multiple (plugin->nat_wait_conns,
1860                                               target,
1861                                               &session_disconnect_it,
1862                                               plugin);
1863 }
1864
1865
1866 /**
1867  * We are processing an address pretty printing request and finished
1868  * the IP resolution (if applicable).  Append our port and forward the
1869  * result.  If called with @a hostname NULL, we are done and should
1870  * clean up the pretty printer (otherwise, there might be multiple
1871  * hostnames for the IP address and we might receive more).
1872  *
1873  * @param cls the `struct PrettyPrinterContext *`
1874  * @param hostname hostname part of the address
1875  */
1876 static void
1877 append_port (void *cls,
1878              const char *hostname)
1879 {
1880   struct PrettyPrinterContext *ppc = cls;
1881   struct Plugin *plugin = ppc->plugin;
1882   char *ret;
1883
1884   if (NULL == hostname)
1885   {
1886     /* Final call, done */
1887     ppc->resolver_handle = NULL;
1888     GNUNET_CONTAINER_DLL_remove (plugin->ppc_dll_head,
1889                                  plugin->ppc_dll_tail,
1890                                  ppc);
1891     ppc->asc (ppc->asc_cls,
1892               NULL,
1893               GNUNET_OK);
1894     GNUNET_free (ppc);
1895     return;
1896   }
1897   if (GNUNET_YES == ppc->ipv6)
1898     GNUNET_asprintf (&ret,
1899                      "%s.%u.[%s]:%d",
1900                      PLUGIN_NAME,
1901                      ppc->options,
1902                      hostname,
1903                      ppc->port);
1904   else
1905     GNUNET_asprintf (&ret,
1906                      "%s.%u.%s:%d",
1907                      PLUGIN_NAME,
1908                      ppc->options,
1909                      hostname,
1910                      ppc->port);
1911   ppc->asc (ppc->asc_cls,
1912             ret,
1913             GNUNET_OK);
1914   GNUNET_free (ret);
1915 }
1916
1917
1918 /**
1919  * Convert the transports address to a nice, human-readable format.
1920  *
1921  * @param cls closure with the `struct Plugin`
1922  * @param type name of the transport that generated the address
1923  * @param addr one of the addresses of the host, NULL for the last address
1924  *        the specific address format depends on the transport
1925  * @param addrlen length of the @a addr
1926  * @param numeric should (IP) addresses be displayed in numeric form?
1927  * @param timeout after how long should we give up?
1928  * @param asc function to call on each string
1929  * @param asc_cls closure for @a asc
1930  */
1931 static void
1932 tcp_plugin_address_pretty_printer (void *cls,
1933                                    const char *type,
1934                                    const void *addr,
1935                                    size_t addrlen,
1936                                    int numeric,
1937                                    struct GNUNET_TIME_Relative timeout,
1938                                    GNUNET_TRANSPORT_AddressStringCallback asc,
1939                                    void *asc_cls)
1940 {
1941   struct Plugin *plugin = cls;
1942   struct PrettyPrinterContext *ppc;
1943   const void *sb;
1944   size_t sbs;
1945   struct sockaddr_in a4;
1946   struct sockaddr_in6 a6;
1947   const struct IPv4TcpAddress *t4;
1948   const struct IPv6TcpAddress *t6;
1949   uint16_t port;
1950   uint32_t options;
1951
1952   if (sizeof(struct IPv6TcpAddress) == addrlen)
1953   {
1954     t6 = addr;
1955     memset (&a6, 0, sizeof(a6));
1956     a6.sin6_family = AF_INET6;
1957     a6.sin6_port = t6->t6_port;
1958     memcpy (&a6.sin6_addr, &t6->ipv6_addr, sizeof(struct in6_addr));
1959     port = ntohs (t6->t6_port);
1960     options = ntohl (t6->options);
1961     sb = &a6;
1962     sbs = sizeof(a6);
1963   }
1964   else if (sizeof(struct IPv4TcpAddress) == addrlen)
1965   {
1966     t4 = addr;
1967     memset (&a4, 0, sizeof(a4));
1968     a4.sin_family = AF_INET;
1969     a4.sin_port = t4->t4_port;
1970     a4.sin_addr.s_addr = t4->ipv4_addr;
1971     port = ntohs (t4->t4_port);
1972     options = ntohl (t4->options);
1973     sb = &a4;
1974     sbs = sizeof(a4);
1975   }
1976   else
1977   {
1978     /* invalid address */
1979     asc (asc_cls, NULL, GNUNET_SYSERR);
1980     asc (asc_cls, NULL, GNUNET_OK);
1981     return;
1982   }
1983   ppc = GNUNET_new (struct PrettyPrinterContext);
1984   ppc->plugin = plugin;
1985   if (addrlen == sizeof(struct IPv6TcpAddress))
1986     ppc->ipv6 = GNUNET_YES;
1987   else
1988     ppc->ipv6 = GNUNET_NO;
1989   ppc->asc = asc;
1990   ppc->asc_cls = asc_cls;
1991   ppc->port = port;
1992   ppc->options = options;
1993   ppc->resolver_handle = GNUNET_RESOLVER_hostname_get (sb,
1994                                                        sbs,
1995                                                        ! numeric,
1996                                                        timeout,
1997                                                        &append_port, ppc);
1998   if (NULL == ppc->resolver_handle)
1999   {
2000     GNUNET_break (0);
2001     GNUNET_free (ppc);
2002     return;
2003   }
2004   GNUNET_CONTAINER_DLL_insert (plugin->ppc_dll_head,
2005                                plugin->ppc_dll_tail,
2006                                ppc);
2007 }
2008
2009
2010 /**
2011  * Check if the given port is plausible (must be either our listen
2012  * port or our advertised port), or any port if we are behind NAT
2013  * and do not have a port open.  If it is neither, we return
2014  * #GNUNET_SYSERR.
2015  *
2016  * @param plugin global variables
2017  * @param in_port port number to check
2018  * @return #GNUNET_OK if port is either open_port or adv_port
2019  */
2020 static int
2021 check_port (struct Plugin *plugin, 
2022             uint16_t in_port)
2023 {
2024   if ( (in_port == plugin->adv_port) || 
2025        (in_port == plugin->open_port) )
2026     return GNUNET_OK;
2027   return GNUNET_SYSERR;
2028 }
2029
2030
2031 /**
2032  * Function that will be called to check if a binary address for this
2033  * plugin is well-formed and corresponds to an address for THIS peer
2034  * (as per our configuration).  Naturally, if absolutely necessary,
2035  * plugins can be a bit conservative in their answer, but in general
2036  * plugins should make sure that the address does not redirect
2037  * traffic to a 3rd party that might try to man-in-the-middle our
2038  * traffic.
2039  *
2040  * @param cls closure, our `struct Plugin *`
2041  * @param addr pointer to the address
2042  * @param addrlen length of @a addr
2043  * @return #GNUNET_OK if this is a plausible address for this peer
2044  *         and transport, #GNUNET_SYSERR if not
2045  */
2046 static int
2047 tcp_plugin_check_address (void *cls, 
2048                           const void *addr,
2049                           size_t addrlen)
2050 {
2051   struct Plugin *plugin = cls;
2052   const struct IPv4TcpAddress *v4;
2053   const struct IPv6TcpAddress *v6;
2054
2055   if ( (addrlen != sizeof(struct IPv4TcpAddress)) &&
2056        (addrlen != sizeof(struct IPv6TcpAddress)) )
2057   {
2058     GNUNET_break_op (0);
2059     return GNUNET_SYSERR;
2060   }
2061
2062   if (addrlen == sizeof(struct IPv4TcpAddress))
2063   {
2064     v4 = (const struct IPv4TcpAddress *) addr;
2065     if (0 != memcmp (&v4->options,
2066                      &plugin->myoptions,
2067                      sizeof(uint32_t)))
2068     {
2069       GNUNET_break (0);
2070       return GNUNET_SYSERR;
2071     }
2072     if (GNUNET_OK != check_port (plugin,
2073                                  ntohs (v4->t4_port)))
2074       return GNUNET_SYSERR;
2075     if (GNUNET_OK !=
2076         GNUNET_NAT_test_address (plugin->nat,
2077                                  &v4->ipv4_addr,
2078                                  sizeof (struct in_addr)))
2079       return GNUNET_SYSERR;
2080   }
2081   else
2082   {
2083     v6 = (const struct IPv6TcpAddress *) addr;
2084     if (IN6_IS_ADDR_LINKLOCAL (&v6->ipv6_addr))
2085     {
2086       GNUNET_break_op (0);
2087       return GNUNET_SYSERR;
2088     }
2089     if (0 != memcmp (&v6->options,
2090                      &plugin->myoptions,
2091                      sizeof (uint32_t)))
2092     {
2093       GNUNET_break (0);
2094       return GNUNET_SYSERR;
2095     }
2096     if (GNUNET_OK != check_port (plugin, 
2097                                  ntohs (v6->t6_port)))
2098       return GNUNET_SYSERR;
2099     if (GNUNET_OK != 
2100         GNUNET_NAT_test_address (plugin->nat,
2101                                  &v6->ipv6_addr,
2102                                  sizeof(struct in6_addr)))
2103       return GNUNET_SYSERR;
2104   }
2105   return GNUNET_OK;
2106 }
2107
2108
2109 /**
2110  * We've received a nat probe from this peer via TCP.  Finish
2111  * creating the client session and resume sending of queued
2112  * messages.
2113  *
2114  * @param cls closure
2115  * @param client identification of the client
2116  * @param message the actual message
2117  */
2118 static void
2119 handle_tcp_nat_probe (void *cls,
2120                       struct GNUNET_SERVER_Client *client,
2121                       const struct GNUNET_MessageHeader *message)
2122 {
2123   struct Plugin *plugin = cls;
2124   struct Session *session;
2125   const struct TCP_NAT_ProbeMessage *tcp_nat_probe;
2126   size_t alen;
2127   void *vaddr;
2128   struct IPv4TcpAddress *t4;
2129   struct IPv6TcpAddress *t6;
2130   const struct sockaddr_in *s4;
2131   const struct sockaddr_in6 *s6;
2132
2133   LOG (GNUNET_ERROR_TYPE_DEBUG,
2134        "Received NAT probe\n");
2135   /* We have received a TCP NAT probe, meaning we (hopefully) initiated
2136    * a connection to this peer by running gnunet-nat-client.  This peer
2137    * received the punch message and now wants us to use the new connection
2138    * as the default for that peer.  Do so and then send a WELCOME message
2139    * so we can really be connected!
2140    */
2141   if (ntohs (message->size) != sizeof(struct TCP_NAT_ProbeMessage))
2142   {
2143     GNUNET_break_op(0);
2144     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2145     return;
2146   }
2147
2148   tcp_nat_probe = (const struct TCP_NAT_ProbeMessage *) message;
2149   if (0 == memcmp (&tcp_nat_probe->clientIdentity, plugin->env->my_identity,
2150           sizeof(struct GNUNET_PeerIdentity)))
2151   {
2152     /* refuse connections from ourselves */
2153     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2154     return;
2155   }
2156
2157   session = GNUNET_CONTAINER_multipeermap_get (plugin->nat_wait_conns,
2158                                                &tcp_nat_probe->clientIdentity);
2159   if (NULL == session)
2160   {
2161     LOG (GNUNET_ERROR_TYPE_DEBUG,
2162          "Did NOT find session for NAT probe!\n");
2163     GNUNET_SERVER_receive_done (client, GNUNET_OK);
2164     return;
2165   }
2166   LOG (GNUNET_ERROR_TYPE_DEBUG,
2167        "Found session for NAT probe!\n");
2168
2169   if (NULL != session->nat_connection_timeout)
2170   {
2171     GNUNET_SCHEDULER_cancel (session->nat_connection_timeout);
2172     session->nat_connection_timeout = NULL;
2173   }
2174
2175   if (GNUNET_OK != 
2176       GNUNET_SERVER_client_get_address (client, 
2177                                         &vaddr,
2178                                         &alen))
2179   {
2180     GNUNET_break(0);
2181     GNUNET_SERVER_receive_done (client, 
2182                                 GNUNET_SYSERR);
2183     tcp_plugin_disconnect_session (plugin,
2184                                    session);
2185     return;
2186   }
2187   GNUNET_assert (GNUNET_YES ==
2188                  GNUNET_CONTAINER_multipeermap_remove (plugin->nat_wait_conns,
2189                                                        &tcp_nat_probe->clientIdentity, 
2190                                                        session));
2191   GNUNET_SERVER_client_set_user_context (client,
2192                                          session);
2193   (void) GNUNET_CONTAINER_multipeermap_put (plugin->sessionmap,
2194                                             &session->target,
2195                                             session, 
2196                                             GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
2197   session->last_activity = GNUNET_TIME_absolute_get ();
2198   LOG (GNUNET_ERROR_TYPE_DEBUG,
2199        "Found address `%s' for incoming connection\n",
2200        GNUNET_a2s (vaddr, alen));
2201   switch (((const struct sockaddr *) vaddr)->sa_family)
2202   {
2203   case AF_INET:
2204     s4 = vaddr;
2205     t4 = GNUNET_new (struct IPv4TcpAddress);
2206     t4->options = htonl (TCP_OPTIONS_NONE);
2207     t4->t4_port = s4->sin_port;
2208     t4->ipv4_addr = s4->sin_addr.s_addr;
2209     session->address = GNUNET_HELLO_address_allocate (&tcp_nat_probe->clientIdentity,
2210                                                       PLUGIN_NAME,
2211                                                       &t4,
2212                                                       sizeof(struct IPv4TcpAddress),
2213                                                       GNUNET_HELLO_ADDRESS_INFO_NONE);
2214     break;
2215   case AF_INET6:
2216     s6 = vaddr;
2217     t6 = GNUNET_new (struct IPv6TcpAddress);
2218     t6->options = htonl (TCP_OPTIONS_NONE);
2219     t6->t6_port = s6->sin6_port;
2220     memcpy (&t6->ipv6_addr, &s6->sin6_addr, sizeof(struct in6_addr));
2221     session->address = GNUNET_HELLO_address_allocate (&tcp_nat_probe->clientIdentity,
2222                                                       PLUGIN_NAME,
2223                                                       &t6,
2224                                                       sizeof(struct IPv6TcpAddress),
2225                                                       GNUNET_HELLO_ADDRESS_INFO_NONE);
2226     break;
2227   default:
2228     GNUNET_break_op(0);
2229     LOG(GNUNET_ERROR_TYPE_DEBUG,
2230         "Bad address for incoming connection!\n");
2231     GNUNET_free(vaddr);
2232     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2233     tcp_plugin_disconnect_session (plugin,
2234                                    session);
2235     return;
2236   }
2237   GNUNET_free (vaddr);
2238   GNUNET_break (NULL == session->client);
2239   GNUNET_SERVER_client_keep (client);
2240   session->client = client;
2241   GNUNET_STATISTICS_update (plugin->env->stats,
2242                             gettext_noop ("# TCP sessions active"),
2243                             1, 
2244                             GNUNET_NO);
2245   process_pending_messages (session);
2246   GNUNET_SERVER_receive_done (client, 
2247                               GNUNET_OK);
2248 }
2249
2250
2251 /**
2252  * We've received a welcome from this peer via TCP.  Possibly create a
2253  * fresh client record and send back our welcome.
2254  *
2255  * @param cls closure
2256  * @param client identification of the client
2257  * @param message the actual message
2258  */
2259 static void
2260 handle_tcp_welcome (void *cls,
2261                     struct GNUNET_SERVER_Client *client,
2262                     const struct GNUNET_MessageHeader *message)
2263 {
2264   struct Plugin *plugin = cls;
2265   const struct WelcomeMessage *wm = (const struct WelcomeMessage *) message;
2266   struct GNUNET_HELLO_Address *address;
2267   struct Session *session;
2268   size_t alen;
2269   void *vaddr;
2270   struct IPv4TcpAddress t4;
2271   struct IPv6TcpAddress t6;
2272   const struct sockaddr_in *s4;
2273   const struct sockaddr_in6 *s6;
2274
2275   if (0 == memcmp (&wm->clientIdentity,
2276                    plugin->env->my_identity,
2277                    sizeof(struct GNUNET_PeerIdentity)))
2278   {
2279     /* refuse connections from ourselves */
2280     GNUNET_SERVER_receive_done (client,
2281                                 GNUNET_SYSERR);
2282     if (GNUNET_OK ==
2283         GNUNET_SERVER_client_get_address (client,
2284                                           &vaddr,
2285                                           &alen))
2286     {
2287       LOG (GNUNET_ERROR_TYPE_INFO,
2288            "Received WELCOME message from my own identity `%4s' on address `%s'\n",
2289            GNUNET_i2s (&wm->clientIdentity),
2290            GNUNET_a2s (vaddr, alen));
2291       GNUNET_free(vaddr);
2292     }
2293     return;
2294   }
2295
2296   LOG(GNUNET_ERROR_TYPE_DEBUG,
2297       "Received WELCOME message from `%4s' %p\n",
2298       GNUNET_i2s (&wm->clientIdentity),
2299       client);
2300   GNUNET_STATISTICS_update (plugin->env->stats,
2301                             gettext_noop ("# TCP WELCOME messages received"),
2302                             1,
2303                             GNUNET_NO);
2304   session = lookup_session_by_client (plugin, client);
2305   if (NULL != session)
2306   {
2307     if (GNUNET_OK ==
2308         GNUNET_SERVER_client_get_address (client, &vaddr, &alen))
2309     {
2310       LOG (GNUNET_ERROR_TYPE_DEBUG,
2311            "Found existing session %p for peer `%s'\n",
2312            session,
2313            GNUNET_a2s (vaddr, alen));
2314       GNUNET_free (vaddr);
2315     }
2316   }
2317   else
2318   {
2319     GNUNET_SERVER_client_keep (client);
2320     if (GNUNET_OK ==
2321         GNUNET_SERVER_client_get_address (client, &vaddr, &alen))
2322     {
2323       if (alen == sizeof(struct sockaddr_in))
2324       {
2325         s4 = vaddr;
2326         memset (&t4, '\0', sizeof (t4));
2327         t4.options = htonl (TCP_OPTIONS_NONE);
2328         t4.t4_port = s4->sin_port;
2329         t4.ipv4_addr = s4->sin_addr.s_addr;
2330         address = GNUNET_HELLO_address_allocate (&wm->clientIdentity,
2331                                                  PLUGIN_NAME,
2332                                                  &t4,
2333                                                  sizeof(t4),
2334                                                  GNUNET_HELLO_ADDRESS_INFO_INBOUND);
2335       }
2336       else if (alen == sizeof(struct sockaddr_in6))
2337       {
2338         s6 = vaddr;
2339         memset (&t6, '\0', sizeof (t6));
2340         t6.options = htonl (TCP_OPTIONS_NONE);
2341         t6.t6_port = s6->sin6_port;
2342         memcpy (&t6.ipv6_addr, &s6->sin6_addr, sizeof(struct in6_addr));
2343         address = GNUNET_HELLO_address_allocate (&wm->clientIdentity,
2344                                                  PLUGIN_NAME,
2345                                                  &t6,
2346                                                  sizeof (t6),
2347                                                  GNUNET_HELLO_ADDRESS_INFO_INBOUND);
2348       }
2349       else
2350       {
2351         GNUNET_break (0);
2352         GNUNET_free_non_null (vaddr);
2353         return;
2354       }
2355       session = create_session (plugin,
2356                                 address,
2357                                 client,
2358                                 GNUNET_NO);
2359       GNUNET_HELLO_address_free (address);
2360       session->scope
2361         = plugin->env->get_address_type (plugin->env->cls,
2362                                          vaddr,
2363                                          alen);
2364       LOG (GNUNET_ERROR_TYPE_DEBUG,
2365            "Creating new%s session %p for peer `%s' client %p\n",
2366            GNUNET_HELLO_address_check_option (session->address,
2367                                               GNUNET_HELLO_ADDRESS_INFO_INBOUND)
2368            ? " inbound" : "",
2369            session,
2370            tcp_plugin_address_to_string (plugin,
2371                                          session->address->address,
2372                                          session->address->address_length),
2373            client);
2374       GNUNET_free (vaddr);
2375       GNUNET_SERVER_client_set_user_context (session->client, session);
2376       GNUNET_CONTAINER_multipeermap_put (plugin->sessionmap,
2377                                          &session->target,
2378                                          session,
2379                                          GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
2380       /* Notify transport and ATS about new session */
2381       plugin->env->session_start (plugin->env->cls,
2382                                   session->address,
2383                                   session,
2384                                   session->scope);
2385       notify_session_monitor (plugin,
2386                               session,
2387                               GNUNET_TRANSPORT_SS_INIT);
2388     }
2389     else
2390     {
2391       LOG(GNUNET_ERROR_TYPE_DEBUG,
2392           "Did not obtain TCP socket address for incoming connection\n");
2393       GNUNET_break(0);
2394       return;
2395     }
2396   }
2397
2398   if (session->expecting_welcome != GNUNET_YES)
2399   {
2400     GNUNET_break_op(0);
2401     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2402     GNUNET_break(0);
2403     return;
2404   }
2405   session->last_activity = GNUNET_TIME_absolute_get ();
2406   session->expecting_welcome = GNUNET_NO;
2407
2408   process_pending_messages (session);
2409   GNUNET_SERVER_client_set_timeout (client,
2410       GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2411   GNUNET_SERVER_receive_done (client, GNUNET_OK);
2412 }
2413
2414
2415 /**
2416  * We've received data for this peer via TCP.  Unbox,
2417  * compute latency and forward.
2418  *
2419  * @param cls closure
2420  * @param client identification of the client
2421  * @param message the actual message
2422  */
2423 static void
2424 handle_tcp_data (void *cls,
2425                  struct GNUNET_SERVER_Client *client,
2426                  const struct GNUNET_MessageHeader *message)
2427 {
2428   struct Plugin *plugin = cls;
2429   struct Session *session;
2430   struct GNUNET_TIME_Relative delay;
2431   uint16_t type;
2432
2433   type = ntohs (message->type);
2434   if ( (GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_WELCOME == type) ||
2435        (GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_NAT_PROBE == type) )
2436   {
2437     /* We don't want to propagate WELCOME and NAT Probe messages up! */
2438     GNUNET_SERVER_receive_done (client,
2439                                 GNUNET_OK);
2440     return;
2441   }
2442   session = lookup_session_by_client (plugin, client);
2443   if (NULL == session)
2444   {
2445     /* No inbound session found */
2446     void *vaddr;
2447     size_t alen;
2448
2449     GNUNET_SERVER_client_get_address (client,
2450                                       &vaddr,
2451                                       &alen);
2452     LOG (GNUNET_ERROR_TYPE_ERROR,
2453          "Received unexpected %u bytes of type %u from `%s'\n",
2454          (unsigned int) ntohs (message->size),
2455          (unsigned int) ntohs (message->type),
2456          GNUNET_a2s (vaddr,
2457                      alen));
2458     GNUNET_break_op(0);
2459     GNUNET_SERVER_receive_done (client,
2460                                 GNUNET_SYSERR);
2461     GNUNET_free_non_null (vaddr);
2462     return;
2463   }
2464   if (GNUNET_YES == session->expecting_welcome)
2465   {
2466     /* Session is expecting WELCOME message */
2467     void *vaddr;
2468     size_t alen;
2469
2470     GNUNET_SERVER_client_get_address (client, &vaddr, &alen);
2471     LOG (GNUNET_ERROR_TYPE_ERROR,
2472          "Received unexpected %u bytes of type %u from `%s'\n",
2473          (unsigned int) ntohs (message->size),
2474          (unsigned int) ntohs (message->type),
2475          GNUNET_a2s (vaddr, alen));
2476     GNUNET_break_op(0);
2477     GNUNET_SERVER_receive_done (client,
2478                                 GNUNET_SYSERR);
2479     GNUNET_free_non_null (vaddr);
2480     return;
2481   }
2482
2483   session->last_activity = GNUNET_TIME_absolute_get ();
2484   LOG (GNUNET_ERROR_TYPE_DEBUG,
2485        "Passing %u bytes of type %u from `%4s' to transport service.\n",
2486        (unsigned int) ntohs (message->size),
2487        (unsigned int) ntohs (message->type),
2488        GNUNET_i2s (&session->target));
2489
2490   GNUNET_STATISTICS_update (plugin->env->stats,
2491                             gettext_noop ("# bytes received via TCP"),
2492                             ntohs (message->size),
2493                             GNUNET_NO);
2494
2495   GNUNET_assert (GNUNET_CONTAINER_multipeermap_contains_value (plugin->sessionmap,
2496                                                                &session->target,
2497                                                                session));
2498   delay = plugin->env->receive (plugin->env->cls,
2499                                 session->address,
2500                                 session,
2501                                 message);
2502   reschedule_session_timeout (session);
2503   if (0 == delay.rel_value_us)
2504   {
2505     GNUNET_SERVER_receive_done (client, GNUNET_OK);
2506   }
2507   else
2508   {
2509     LOG(GNUNET_ERROR_TYPE_DEBUG,
2510         "Throttling receiving from `%s' for %s\n",
2511         GNUNET_i2s (&session->target),
2512         GNUNET_STRINGS_relative_time_to_string (delay, GNUNET_YES));
2513     GNUNET_SERVER_disable_receive_done_warning (client);
2514     session->receive_delay_task = GNUNET_SCHEDULER_add_delayed (delay,
2515         &delayed_done, session);
2516   }
2517 }
2518
2519
2520 /**
2521  * Function called whenever a peer is connected on the "SERVER" level.
2522  * Increments number of active connections and suspends server if we
2523  * have reached the limit.
2524  *
2525  * @param cls closure
2526  * @param client identification of the client
2527  */
2528 static void
2529 connect_notify (void *cls,
2530                 struct GNUNET_SERVER_Client *client)
2531 {
2532   struct Plugin *plugin = cls;
2533
2534   plugin->cur_connections++;
2535   if (plugin->cur_connections != plugin->max_connections)
2536     return;
2537   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2538               _("TCP connection limit reached, suspending server\n"));
2539   GNUNET_STATISTICS_update (plugin->env->stats,
2540                             gettext_noop ("# TCP service suspended"),
2541                             1,
2542                             GNUNET_NO);
2543   GNUNET_SERVER_suspend (plugin->server); /* Maximum number of connections rechead */
2544 }
2545
2546
2547 /**
2548  * Function called whenever a peer is disconnected on the "SERVER"
2549  * level.  Cleans up the connection, decrements number of active
2550  * connections and if applicable resumes listening.
2551  *
2552  * @param cls closure
2553  * @param client identification of the client
2554  */
2555 static void
2556 disconnect_notify (void *cls,
2557                    struct GNUNET_SERVER_Client *client)
2558 {
2559   struct Plugin *plugin = cls;
2560   struct Session *session;
2561
2562   if (NULL == client)
2563     return;
2564   session = lookup_session_by_client (plugin, client);
2565   if (NULL == session)
2566     return; /* unknown, nothing to do */
2567   LOG (GNUNET_ERROR_TYPE_DEBUG,
2568        "Destroying session of `%4s' with %s due to network-level disconnect.\n",
2569        GNUNET_i2s (&session->target),
2570        tcp_plugin_address_to_string (session->plugin,
2571                                      session->address->address,
2572                                      session->address->address_length));
2573
2574   if (plugin->cur_connections == plugin->max_connections)
2575   {
2576     GNUNET_STATISTICS_update (session->plugin->env->stats,
2577                               gettext_noop ("# TCP service resumed"),
2578                               1,
2579                               GNUNET_NO);
2580     GNUNET_SERVER_resume (plugin->server); /* Resume server  */
2581   }
2582   GNUNET_assert (plugin->cur_connections >= 1);
2583   plugin->cur_connections--;
2584   GNUNET_STATISTICS_update (session->plugin->env->stats,
2585                             gettext_noop ("# network-level TCP disconnect events"),
2586                             1,
2587                             GNUNET_NO);
2588   tcp_plugin_disconnect_session (plugin, 
2589                                  session);
2590 }
2591
2592
2593 /**
2594  * We can now send a probe message, copy into buffer to really send.
2595  *
2596  * @param cls closure, a `struct TCPProbeContext`
2597  * @param size max size to copy
2598  * @param buf buffer to copy message to
2599  * @return number of bytes copied into @a buf
2600  */
2601 static size_t
2602 notify_send_probe (void *cls,
2603                    size_t size,
2604                    void *buf)
2605 {
2606   struct TCPProbeContext *tcp_probe_ctx = cls;
2607   struct Plugin *plugin = tcp_probe_ctx->plugin;
2608   size_t ret;
2609
2610   tcp_probe_ctx->transmit_handle = NULL;
2611   GNUNET_CONTAINER_DLL_remove (plugin->probe_head,
2612                                plugin->probe_tail,
2613                                tcp_probe_ctx);
2614   if (NULL == buf)
2615   {
2616     GNUNET_CONNECTION_destroy (tcp_probe_ctx->sock);
2617     GNUNET_free(tcp_probe_ctx);
2618     return 0;
2619   }
2620   GNUNET_assert(size >= sizeof(tcp_probe_ctx->message));
2621   memcpy (buf, 
2622           &tcp_probe_ctx->message, 
2623           sizeof(tcp_probe_ctx->message));
2624   GNUNET_SERVER_connect_socket (tcp_probe_ctx->plugin->server,
2625                                 tcp_probe_ctx->sock);
2626   ret = sizeof(tcp_probe_ctx->message);
2627   GNUNET_free (tcp_probe_ctx);
2628   return ret;
2629 }
2630
2631
2632 /**
2633  * Function called by the NAT subsystem suggesting another peer wants
2634  * to connect to us via connection reversal.  Try to connect back to the
2635  * given IP.
2636  *
2637  * @param cls closure
2638  * @param addr address to try
2639  * @param addrlen number of bytes in @a addr
2640  */
2641 static void
2642 try_connection_reversal (void *cls,
2643                          const struct sockaddr *addr,
2644                          socklen_t addrlen)
2645 {
2646   struct Plugin *plugin = cls;
2647   struct GNUNET_CONNECTION_Handle *sock;
2648   struct TCPProbeContext *tcp_probe_ctx;
2649
2650   /**
2651    * We have received an ICMP response, ostensibly from a peer
2652    * that wants to connect to us! Send a message to establish a connection.
2653    */
2654   sock = GNUNET_CONNECTION_create_from_sockaddr (AF_INET, 
2655                                                  addr,
2656                                                  addrlen);
2657   if (NULL == sock)
2658   {
2659     /* failed for some odd reason (out of sockets?); ignore attempt */
2660     return;
2661   }
2662
2663   tcp_probe_ctx = GNUNET_new (struct TCPProbeContext);
2664   tcp_probe_ctx->message.header.size
2665     = htons (sizeof (struct TCP_NAT_ProbeMessage));
2666   tcp_probe_ctx->message.header.type
2667     = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_NAT_PROBE);
2668   tcp_probe_ctx->message.clientIdentity
2669     = *plugin->env->my_identity;
2670   tcp_probe_ctx->plugin = plugin;
2671   tcp_probe_ctx->sock = sock;
2672   GNUNET_CONTAINER_DLL_insert (plugin->probe_head,
2673                                plugin->probe_tail,
2674                                tcp_probe_ctx);
2675   tcp_probe_ctx->transmit_handle
2676     = GNUNET_CONNECTION_notify_transmit_ready (sock,
2677                                                ntohs (tcp_probe_ctx->message.header.size),
2678                                                GNUNET_TIME_UNIT_FOREVER_REL,
2679                                                &notify_send_probe,
2680                                                tcp_probe_ctx);
2681 }
2682
2683
2684 /**
2685  * Function obtain the network type for a session
2686  *
2687  * @param cls closure (`struct Plugin *`)
2688  * @param session the session
2689  * @return the network type in HBO or #GNUNET_SYSERR
2690  */
2691 static enum GNUNET_ATS_Network_Type
2692 tcp_plugin_get_network (void *cls,
2693                         struct Session *session)
2694 {
2695   return session->scope;
2696 }
2697
2698
2699 /**
2700  * Return information about the given session to the
2701  * monitor callback.
2702  *
2703  * @param cls the `struct Plugin` with the monitor callback (`sic`)
2704  * @param peer peer we send information about
2705  * @param value our `struct Session` to send information about
2706  * @return #GNUNET_OK (continue to iterate)
2707  */
2708 static int
2709 send_session_info_iter (void *cls,
2710                         const struct GNUNET_PeerIdentity *peer,
2711                         void *value)
2712 {
2713   struct Plugin *plugin = cls;
2714   struct Session *session = value;
2715
2716   notify_session_monitor (plugin,
2717                           session,
2718                           GNUNET_TRANSPORT_SS_INIT);
2719   /* FIXME: cannot tell if this is up or not from current
2720      session state... */
2721   notify_session_monitor (plugin,
2722                           session,
2723                           GNUNET_TRANSPORT_SS_UP);
2724   return GNUNET_OK;
2725 }
2726
2727
2728 /**
2729  * Begin monitoring sessions of a plugin.  There can only
2730  * be one active monitor per plugin (i.e. if there are
2731  * multiple monitors, the transport service needs to
2732  * multiplex the generated events over all of them).
2733  *
2734  * @param cls closure of the plugin
2735  * @param sic callback to invoke, NULL to disable monitor;
2736  *            plugin will being by iterating over all active
2737  *            sessions immediately and then enter monitor mode
2738  * @param sic_cls closure for @a sic
2739  */
2740 static void
2741 tcp_plugin_setup_monitor (void *cls,
2742                           GNUNET_TRANSPORT_SessionInfoCallback sic,
2743                           void *sic_cls)
2744 {
2745   struct Plugin *plugin = cls;
2746
2747   plugin->sic = sic;
2748   plugin->sic_cls = sic_cls;
2749   if (NULL != sic)
2750   {
2751     GNUNET_CONTAINER_multipeermap_iterate (plugin->sessionmap,
2752                                            &send_session_info_iter,
2753                                            plugin);
2754     /* signal end of first iteration */
2755     sic (sic_cls, NULL, NULL);
2756   }
2757 }
2758
2759
2760 /**
2761  * Entry point for the plugin.
2762  *
2763  * @param cls closure, the `struct GNUNET_TRANSPORT_PluginEnvironment *`
2764  * @return the `struct GNUNET_TRANSPORT_PluginFunctions *` or NULL on error
2765  */
2766 void *
2767 libgnunet_plugin_transport_tcp_init (void *cls)
2768 {
2769   static const struct GNUNET_SERVER_MessageHandler my_handlers[] = {
2770     { &handle_tcp_welcome, NULL,
2771       GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_WELCOME,
2772       sizeof(struct WelcomeMessage) },
2773     { &handle_tcp_nat_probe, NULL,
2774       GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_NAT_PROBE,
2775       sizeof(struct TCP_NAT_ProbeMessage) },
2776     { &handle_tcp_data, NULL,
2777       GNUNET_MESSAGE_TYPE_ALL, 0 },
2778     { NULL, NULL, 0, 0 }
2779   };
2780   struct GNUNET_TRANSPORT_PluginEnvironment *env = cls;
2781   struct GNUNET_TRANSPORT_PluginFunctions *api;
2782   struct Plugin *plugin;
2783   struct GNUNET_SERVICE_Context *service;
2784   unsigned long long aport;
2785   unsigned long long bport;
2786   unsigned long long max_connections;
2787   unsigned int i;
2788   struct GNUNET_TIME_Relative idle_timeout;
2789 #ifdef TCP_STEALTH
2790   struct GNUNET_NETWORK_Handle *const*lsocks;
2791 #endif
2792   int ret;
2793   int ret_s;
2794   struct sockaddr **addrs;
2795   socklen_t *addrlens;
2796
2797   if (NULL == env->receive)
2798   {
2799     /* run in 'stub' mode (i.e. as part of gnunet-peerinfo), don't fully
2800      initialze the plugin or the API */
2801     api = GNUNET_new (struct GNUNET_TRANSPORT_PluginFunctions);
2802     api->cls = NULL;
2803     api->address_pretty_printer = &tcp_plugin_address_pretty_printer;
2804     api->address_to_string = &tcp_plugin_address_to_string;
2805     api->string_to_address = &tcp_plugin_string_to_address;
2806     return api;
2807   }
2808
2809   GNUNET_assert (NULL != env->cfg);
2810   if (GNUNET_OK !=
2811       GNUNET_CONFIGURATION_get_value_number (env->cfg,
2812                                              "transport-tcp",
2813                                              "MAX_CONNECTIONS",
2814                                              &max_connections))
2815     max_connections = 128;
2816
2817   aport = 0;
2818   if ((GNUNET_OK !=
2819        GNUNET_CONFIGURATION_get_value_number (env->cfg, "transport-tcp",
2820                                               "PORT", &bport)) ||
2821       (bport > 65535) ||
2822       ((GNUNET_OK ==
2823         GNUNET_CONFIGURATION_get_value_number (env->cfg, "transport-tcp",
2824                                                "ADVERTISED-PORT", &aport)) &&
2825        (aport > 65535) ))
2826   {
2827     LOG(GNUNET_ERROR_TYPE_ERROR,
2828         _("Require valid port number for service `%s' in configuration!\n"),
2829         "transport-tcp");
2830     return NULL ;
2831   }
2832   if (0 == aport)
2833     aport = bport;
2834   if (0 == bport)
2835     aport = 0;
2836   if (0 != bport)
2837   {
2838     service = GNUNET_SERVICE_start ("transport-tcp",
2839                                     env->cfg,
2840                                     GNUNET_SERVICE_OPTION_NONE);
2841     if (NULL == service)
2842     {
2843       LOG (GNUNET_ERROR_TYPE_WARNING,
2844            _("Failed to start service.\n"));
2845       return NULL;
2846     }
2847   }
2848   else
2849     service = NULL;
2850
2851   api = NULL;
2852   plugin = GNUNET_new (struct Plugin);
2853   plugin->sessionmap = GNUNET_CONTAINER_multipeermap_create (max_connections,
2854                                                              GNUNET_YES);
2855   plugin->max_connections = max_connections;
2856   plugin->open_port = bport;
2857   plugin->adv_port = aport;
2858   plugin->env = env;
2859   plugin->my_welcome.header.size = htons (sizeof(struct WelcomeMessage));
2860   plugin->my_welcome.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_WELCOME);
2861   plugin->my_welcome.clientIdentity = *plugin->env->my_identity;
2862
2863   if ( (NULL != service) &&
2864        (GNUNET_YES ==
2865         GNUNET_CONFIGURATION_get_value_yesno (env->cfg,
2866                                               "transport-tcp",
2867                                               "TCP_STEALTH")) )
2868   {
2869 #ifdef TCP_STEALTH
2870     plugin->myoptions |= TCP_OPTIONS_TCP_STEALTH;
2871     lsocks = GNUNET_SERVICE_get_listen_sockets (service);
2872     if (NULL != lsocks)
2873     {
2874       uint32_t len = sizeof (struct WelcomeMessage);
2875
2876       for (i=0;NULL!=lsocks[i];i++)
2877       {
2878         if ( (GNUNET_OK !=
2879               GNUNET_NETWORK_socket_setsockopt (lsocks[i],
2880                                                 IPPROTO_TCP,
2881                                                 TCP_STEALTH,
2882                                                 env->my_identity,
2883                                                 sizeof (struct GNUNET_PeerIdentity))) ||
2884              (GNUNET_OK !=
2885               GNUNET_NETWORK_socket_setsockopt (lsocks[i],
2886                                                 IPPROTO_TCP,
2887                                                 TCP_STEALTH_INTEGRITY_LEN,
2888                                                 &len,
2889                                                 sizeof (len))) )
2890         {
2891           /* TCP STEALTH not supported by kernel */
2892           GNUNET_assert (0 == i);
2893           GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2894                       _("TCP_STEALTH not supported on this platform.\n"));
2895           goto die;
2896         }
2897       }
2898     }
2899 #else
2900     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2901                 _("TCP_STEALTH not supported on this platform.\n"));
2902     goto die;
2903 #endif
2904   }
2905
2906   if ( (NULL != service) &&
2907        (GNUNET_SYSERR !=
2908         (ret_s =
2909          GNUNET_SERVICE_get_server_addresses ("transport-tcp",
2910                                               env->cfg,
2911                                               &addrs,
2912                                               &addrlens))))
2913   {
2914     for (ret = ret_s-1; ret >= 0; ret--)
2915       LOG (GNUNET_ERROR_TYPE_INFO,
2916            "Binding to address `%s'\n",
2917            GNUNET_a2s (addrs[ret], addrlens[ret]));
2918     plugin->nat
2919       = GNUNET_NAT_register (env->cfg,
2920                              GNUNET_YES,
2921                              aport,
2922                              (unsigned int) ret_s,
2923                              (const struct sockaddr **) addrs, addrlens,
2924                              &tcp_nat_port_map_callback,
2925                              &try_connection_reversal,
2926                              plugin);
2927     for (ret = ret_s -1; ret >= 0; ret--)
2928       GNUNET_free (addrs[ret]);
2929     GNUNET_free_non_null (addrs);
2930     GNUNET_free_non_null (addrlens);
2931   }
2932   else
2933   {
2934     plugin->nat = GNUNET_NAT_register (plugin->env->cfg,
2935                                        GNUNET_YES,
2936                                        0,
2937                                        0,
2938                                        NULL,
2939                                        NULL,
2940                                        NULL,
2941                                        &try_connection_reversal,
2942                                        plugin);
2943   }
2944   api = GNUNET_new (struct GNUNET_TRANSPORT_PluginFunctions);
2945   api->cls = plugin;
2946   api->send = &tcp_plugin_send;
2947   api->get_session = &tcp_plugin_get_session;
2948   api->disconnect_session = &tcp_plugin_disconnect_session;
2949   api->query_keepalive_factor = &tcp_plugin_query_keepalive_factor;
2950   api->disconnect_peer = &tcp_plugin_disconnect;
2951   api->address_pretty_printer = &tcp_plugin_address_pretty_printer;
2952   api->check_address = &tcp_plugin_check_address;
2953   api->address_to_string = &tcp_plugin_address_to_string;
2954   api->string_to_address = &tcp_plugin_string_to_address;
2955   api->get_network = &tcp_plugin_get_network;
2956   api->update_session_timeout = &tcp_plugin_update_session_timeout;
2957   api->update_inbound_delay = &tcp_plugin_update_inbound_delay;
2958   api->setup_monitor = &tcp_plugin_setup_monitor;
2959   plugin->service = service;
2960   if (NULL != service)
2961   {
2962     plugin->server = GNUNET_SERVICE_get_server (service);
2963   }
2964   else
2965   {
2966     if (GNUNET_OK !=
2967         GNUNET_CONFIGURATION_get_value_time (env->cfg,
2968                                              "transport-tcp",
2969                                              "TIMEOUT",
2970                                              &idle_timeout))
2971     {
2972       GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
2973                                  "transport-tcp",
2974                                  "TIMEOUT");
2975       goto die;
2976     }
2977     plugin->server
2978       = GNUNET_SERVER_create_with_sockets (NULL,
2979                                            plugin, 
2980                                            NULL,
2981                                            idle_timeout, 
2982                                            GNUNET_YES);
2983   }
2984   plugin->handlers = GNUNET_malloc (sizeof (my_handlers));
2985   memcpy (plugin->handlers, my_handlers, sizeof(my_handlers));
2986   for (i = 0;i < sizeof(my_handlers) / sizeof(struct GNUNET_SERVER_MessageHandler);i++)
2987     plugin->handlers[i].callback_cls = plugin;
2988
2989   GNUNET_SERVER_add_handlers (plugin->server,
2990                               plugin->handlers);
2991   GNUNET_SERVER_connect_notify (plugin->server,
2992                                 &connect_notify,
2993                                 plugin);
2994   GNUNET_SERVER_disconnect_notify (plugin->server,
2995                                    &disconnect_notify,
2996                                    plugin);
2997   plugin->nat_wait_conns = GNUNET_CONTAINER_multipeermap_create (16,
2998                                                                  GNUNET_YES);
2999   if (0 != bport)
3000     LOG (GNUNET_ERROR_TYPE_INFO,
3001          _("TCP transport listening on port %llu\n"),
3002          bport);
3003   else
3004     LOG (GNUNET_ERROR_TYPE_INFO,
3005          _("TCP transport not listening on any port (client only)\n"));
3006   if ( (aport != bport) &&
3007        (0 != bport) )
3008     LOG (GNUNET_ERROR_TYPE_INFO,
3009          _("TCP transport advertises itself as being on port %llu\n"),
3010          aport);
3011   /* Initially set connections to 0 */
3012   GNUNET_STATISTICS_set (plugin->env->stats,
3013                          gettext_noop ("# TCP sessions active"),
3014                          0,
3015                          GNUNET_NO);
3016   return api;
3017
3018  die:
3019   if (NULL != plugin->nat)
3020     GNUNET_NAT_unregister (plugin->nat);
3021   GNUNET_CONTAINER_multipeermap_destroy (plugin->sessionmap);
3022   if (NULL != service)
3023     GNUNET_SERVICE_stop (service);
3024   GNUNET_free (plugin);
3025   GNUNET_free_non_null (api);
3026   return NULL;
3027 }
3028
3029
3030 /**
3031  * Exit point from the plugin.
3032  *
3033  * @param cls the `struct GNUNET_TRANSPORT_PluginFunctions`
3034  * @return NULL
3035  */
3036 void *
3037 libgnunet_plugin_transport_tcp_done (void *cls)
3038 {
3039   struct GNUNET_TRANSPORT_PluginFunctions *api = cls;
3040   struct Plugin *plugin = api->cls;
3041   struct TCPProbeContext *tcp_probe;
3042   struct PrettyPrinterContext *cur;
3043   struct PrettyPrinterContext *next;
3044
3045   if (NULL == plugin)
3046   {
3047     GNUNET_free(api);
3048     return NULL ;
3049   }
3050   LOG (GNUNET_ERROR_TYPE_DEBUG,
3051        "Shutting down TCP plugin\n");
3052
3053   /* Removing leftover sessions */
3054   GNUNET_CONTAINER_multipeermap_iterate (plugin->sessionmap,
3055                                          &session_disconnect_it,
3056                                          plugin);
3057   /* Removing leftover NAT sessions */
3058   GNUNET_CONTAINER_multipeermap_iterate (plugin->nat_wait_conns,
3059                                          &session_disconnect_it,
3060                                          plugin);
3061
3062   for (cur = plugin->ppc_dll_head; NULL != cur; cur = next)
3063   {
3064     next = cur->next;
3065     GNUNET_CONTAINER_DLL_remove (plugin->ppc_dll_head,
3066                                  plugin->ppc_dll_tail,
3067                                  cur);
3068     GNUNET_RESOLVER_request_cancel (cur->resolver_handle);
3069     cur->asc (cur->asc_cls,
3070               NULL, 
3071               GNUNET_OK);
3072     GNUNET_free (cur);
3073   }
3074
3075   if (NULL != plugin->service)
3076     GNUNET_SERVICE_stop (plugin->service);
3077   else
3078     GNUNET_SERVER_destroy (plugin->server);
3079   GNUNET_free(plugin->handlers);
3080   if (NULL != plugin->nat)
3081     GNUNET_NAT_unregister (plugin->nat);
3082   while (NULL != (tcp_probe = plugin->probe_head))
3083   {
3084     GNUNET_CONTAINER_DLL_remove (plugin->probe_head,
3085                                  plugin->probe_tail,
3086                                  tcp_probe);
3087     GNUNET_CONNECTION_destroy (tcp_probe->sock);
3088     GNUNET_free(tcp_probe);
3089   }
3090   GNUNET_CONTAINER_multipeermap_destroy (plugin->nat_wait_conns);
3091   GNUNET_CONTAINER_multipeermap_destroy (plugin->sessionmap);
3092   GNUNET_free(plugin);
3093   GNUNET_free(api);
3094   return NULL;
3095 }
3096
3097 /* end of plugin_transport_tcp.c */