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