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