-simplify logic
[oweals/gnunet.git] / src / transport / plugin_transport_tcp.c
1 /*
2   This file is part of GNUnet
3   Copyright (C) 2002--2015 Christian Grothoff (and other contributing authors)
4
5   GNUnet is free software; you can redistribute it and/or modify
6   it under the terms of the GNU General Public License as published
7   by the Free Software Foundation; either version 3, or (at your
8   option) any later version.
9
10   GNUnet is distributed in the hope that it will be useful, but
11   WITHOUT ANY WARRANTY; without even the implied warranty of
12   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13   General Public License for more details.
14
15   You should have received a copy of the GNU General Public License
16   along with GNUnet; see the file COPYING.  If not, write to the
17   Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18   Boston, MA 02111-1307, USA.
19  */
20 /**
21  * @file transport/plugin_transport_tcp.c
22  * @brief Implementation of the TCP transport service
23  * @author Christian Grothoff
24  */
25 #include "platform.h"
26 #include "gnunet_hello_lib.h"
27 #include "gnunet_constants.h"
28 #include "gnunet_util_lib.h"
29 #include "gnunet_nat_lib.h"
30 #include "gnunet_protocols.h"
31 #include "gnunet_resolver_service.h"
32 #include "gnunet_signatures.h"
33 #include "gnunet_statistics_service.h"
34 #include "gnunet_transport_service.h"
35 #include "gnunet_transport_plugin.h"
36 #include "transport.h"
37
38 #define LOG(kind,...) GNUNET_log_from (kind, "transport-tcp",__VA_ARGS__)
39
40 #define PLUGIN_NAME "tcp"
41
42 /**
43  * How long until we give up on establishing an NAT connection?
44  * Must be > 4 RTT
45  */
46 #define NAT_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10)
47
48 GNUNET_NETWORK_STRUCT_BEGIN
49
50
51 /**
52  * Initial handshake message for a session.
53  */
54 struct WelcomeMessage
55 {
56   /**
57    * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_WELCOME.
58    */
59   struct GNUNET_MessageHeader header;
60
61   /**
62    * Identity of the node connecting (TCP client)
63    */
64   struct GNUNET_PeerIdentity clientIdentity;
65
66 };
67
68 /**
69  * Basically a WELCOME message, but with the purpose
70  * of giving the waiting peer a client handle to use
71  */
72 struct TCP_NAT_ProbeMessage
73 {
74   /**
75    * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_NAT_PROBE.
76    */
77   struct GNUNET_MessageHeader header;
78
79   /**
80    * Identity of the sender of the message.
81    */
82   struct GNUNET_PeerIdentity clientIdentity;
83
84 };
85 GNUNET_NETWORK_STRUCT_END
86
87 /**
88  * Context for sending a NAT probe via TCP.
89  */
90 struct TCPProbeContext
91 {
92
93   /**
94    * Active probes are kept in a DLL.
95    */
96   struct TCPProbeContext *next;
97
98   /**
99    * Active probes are kept in a DLL.
100    */
101   struct TCPProbeContext *prev;
102
103   /**
104    * Probe connection.
105    */
106   struct GNUNET_CONNECTION_Handle *sock;
107
108   /**
109    * Message to be sent.
110    */
111   struct TCP_NAT_ProbeMessage message;
112
113   /**
114    * Handle to the transmission.
115    */
116   struct GNUNET_CONNECTION_TransmitHandle *transmit_handle;
117
118   /**
119    * Transport plugin handle.
120    */
121   struct Plugin *plugin;
122 };
123
124 /**
125  * Bits in the `options` field of TCP addresses.
126  */
127 enum TcpAddressOptions
128 {
129
130   /**
131    * No bits set.
132    */
133   TCP_OPTIONS_NONE = 0,
134
135   /**
136    * See #HTTP_OPTIONS_VERIFY_CERTIFICATE.
137    */
138   TCP_OPTIONS_RESERVED = 1,
139
140   /**
141    * Enable TCP Stealth-style port knocking.
142    */
143   TCP_OPTIONS_TCP_STEALTH = 2
144 };
145
146 GNUNET_NETWORK_STRUCT_BEGIN
147
148 /**
149  * Network format for IPv4 addresses.
150  */
151 struct IPv4TcpAddress
152 {
153   /**
154    * Optional options and flags for this address,
155    * see `enum TcpAddressOptions`
156    */
157   uint32_t options;
158
159   /**
160    * IPv4 address, in network byte order.
161    */
162   uint32_t ipv4_addr GNUNET_PACKED;
163
164   /**
165    * Port number, in network byte order.
166    */
167   uint16_t t4_port GNUNET_PACKED;
168
169 };
170
171 /**
172  * Network format for IPv6 addresses.
173  */
174 struct IPv6TcpAddress
175 {
176   /**
177    * Optional flags for this address
178    * see `enum TcpAddressOptions`
179    */
180   uint32_t options;
181
182   /**
183    * IPv6 address.
184    */
185   struct in6_addr ipv6_addr GNUNET_PACKED;
186
187   /**
188    * Port number, in network byte order.
189    */
190   uint16_t t6_port GNUNET_PACKED;
191
192 };
193 GNUNET_NETWORK_STRUCT_END
194
195 /**
196  * Encapsulation of all of the state of the plugin.
197  */
198 struct Plugin;
199
200 /**
201  * Information kept for each message that is yet to
202  * be transmitted.
203  */
204 struct PendingMessage
205 {
206
207   /**
208    * This is a doubly-linked list.
209    */
210   struct PendingMessage *next;
211
212   /**
213    * This is a doubly-linked list.
214    */
215   struct PendingMessage *prev;
216
217   /**
218    * The pending message
219    */
220   const char *msg;
221
222   /**
223    * Continuation function to call once the message
224    * has been sent.  Can be NULL if there is no
225    * continuation to call.
226    */
227   GNUNET_TRANSPORT_TransmitContinuation transmit_cont;
228
229   /**
230    * Closure for @e transmit_cont.
231    */
232   void *transmit_cont_cls;
233
234   /**
235    * Timeout value for the pending message.
236    */
237   struct GNUNET_TIME_Absolute timeout;
238
239   /**
240    * So that the gnunet-service-transport can group messages together,
241    * these pending messages need to accept a message buffer and size
242    * instead of just a `struct GNUNET_MessageHeader`.
243    */
244   size_t message_size;
245
246 };
247
248 /**
249  * Session handle for TCP connections.
250  */
251 struct Session
252 {
253   /**
254    * To whom are we talking to (set to our identity
255    * if we are still waiting for the welcome message)
256    */
257   struct GNUNET_PeerIdentity target;
258
259   /**
260    * Pointer to the global plugin struct.
261    */
262   struct Plugin *plugin;
263
264   /**
265    * The client (used to identify this connection)
266    */
267   struct GNUNET_SERVER_Client *client;
268
269   /**
270    * Task cleaning up a NAT client connection establishment attempt;
271    */
272   struct GNUNET_SCHEDULER_Task *nat_connection_timeout;
273
274   /**
275    * Messages currently pending for transmission
276    * to this peer, if any.
277    */
278   struct PendingMessage *pending_messages_head;
279
280   /**
281    * Messages currently pending for transmission
282    * to this peer, if any.
283    */
284   struct PendingMessage *pending_messages_tail;
285
286   /**
287    * Handle for pending transmission request.
288    */
289   struct GNUNET_SERVER_TransmitHandle *transmit_handle;
290
291   /**
292    * Address of the other peer.
293    */
294   struct GNUNET_HELLO_Address *address;
295
296   /**
297    * ID of task used to delay receiving more to throttle sender.
298    */
299   struct GNUNET_SCHEDULER_Task *receive_delay_task;
300
301   /**
302    * Session timeout task
303    */
304   struct GNUNET_SCHEDULER_Task *timeout_task;
305
306   /**
307    * When will this session time out?
308    */
309   struct GNUNET_TIME_Absolute timeout;
310
311   /**
312    * When will we continue to read from the socket?
313    * (used to enforce inbound quota).
314    */
315   struct GNUNET_TIME_Absolute receive_delay;
316
317   /**
318    * Last activity on this connection.  Used to select preferred
319    * connection.
320    */
321   struct GNUNET_TIME_Absolute last_activity;
322
323   /**
324    * Number of bytes waiting for transmission to this peer.
325    */
326   unsigned long long bytes_in_queue;
327
328   /**
329    * Number of messages waiting for transmission to this peer.
330    */
331   unsigned int msgs_in_queue;
332
333   /**
334    * Network type of the address.
335    */
336   enum GNUNET_ATS_Network_Type scope;
337
338   /**
339    * Are we still expecting the welcome message? (#GNUNET_YES/#GNUNET_NO)
340    */
341   int expecting_welcome;
342
343   /**
344    * Was this session created using NAT traversal?
345    */
346   int is_nat;
347
348 };
349
350
351 /**
352  * Context for address to string conversion, closure
353  * for #append_port().
354  */
355 struct PrettyPrinterContext
356 {
357   /**
358    * DLL
359    */
360   struct PrettyPrinterContext *next;
361
362   /**
363    * DLL
364    */
365   struct PrettyPrinterContext *prev;
366
367   /**
368    * Our plugin.
369    */
370   struct Plugin *plugin;
371
372   /**
373    * Timeout task
374    */
375   struct GNUNET_SCHEDULER_Task *timeout_task;
376
377   /**
378    * Resolver handle
379    */
380   struct GNUNET_RESOLVER_RequestHandle *resolver_handle;
381
382   /**
383    * Function to call with the result.
384    */
385   GNUNET_TRANSPORT_AddressStringCallback asc;
386
387   /**
388    * Clsoure for @e asc.
389    */
390   void *asc_cls;
391
392   /**
393    * IPv6 address
394    */
395   int ipv6;
396
397   /**
398    * Options
399    */
400   uint32_t options;
401
402   /**
403    * Port to add after the IP address.
404    */
405   uint16_t port;
406 };
407
408
409 /**
410  * Encapsulation of all of the state of the plugin.
411  */
412 struct Plugin
413 {
414   /**
415    * Our environment.
416    */
417   struct GNUNET_TRANSPORT_PluginEnvironment *env;
418
419   /**
420    * The listen socket.
421    */
422   struct GNUNET_CONNECTION_Handle *lsock;
423
424   /**
425    * Our handle to the NAT module.
426    */
427   struct GNUNET_NAT_Handle *nat;
428
429   /**
430    * Map from peer identities to sessions for the given peer.
431    */
432   struct GNUNET_CONTAINER_MultiPeerMap *sessionmap;
433
434   /**
435    * Handle to the network service.
436    */
437   struct GNUNET_SERVICE_Context *service;
438
439   /**
440    * Handle to the server for this service.
441    */
442   struct GNUNET_SERVER_Handle *server;
443
444   /**
445    * Copy of the handler array where the closures are
446    * set to this struct's instance.
447    */
448   struct GNUNET_SERVER_MessageHandler *handlers;
449
450   /**
451    * Map of peers we have tried to contact behind a NAT
452    */
453   struct GNUNET_CONTAINER_MultiPeerMap *nat_wait_conns;
454
455   /**
456    * List of active TCP probes.
457    */
458   struct TCPProbeContext *probe_head;
459
460   /**
461    * List of active TCP probes.
462    */
463   struct TCPProbeContext *probe_tail;
464
465   /**
466    * Handle for (DYN)DNS lookup of our external IP.
467    */
468   struct GNUNET_RESOLVER_RequestHandle *ext_dns;
469
470   /**
471    * Function to call about session status changes.
472    */
473   GNUNET_TRANSPORT_SessionInfoCallback sic;
474
475   /**
476    * Closure for @e sic.
477    */
478   void *sic_cls;
479
480   /**
481    * ID of task used to update our addresses when one expires.
482    */
483   struct GNUNET_SCHEDULER_Task *address_update_task;
484
485   /**
486    * Running pretty printers: head
487    */
488   struct PrettyPrinterContext *ppc_dll_head;
489
490   /**
491    * Running pretty printers: tail
492    */
493   struct PrettyPrinterContext *ppc_dll_tail;
494
495   /**
496    * Welcome message used by this peer.
497    */
498   struct WelcomeMessage my_welcome;
499
500   /**
501    * How many more TCP sessions are we allowed to open right now?
502    */
503   unsigned long long max_connections;
504
505   /**
506    * How many more TCP sessions do we have right now?
507    */
508   unsigned long long cur_connections;
509
510   /**
511    * Address options
512    */
513   uint32_t myoptions;
514
515   /**
516    * Port that we are actually listening on.
517    */
518   uint16_t open_port;
519
520   /**
521    * Port that the user said we would have visible to the
522    * rest of the world.
523    */
524   uint16_t adv_port;
525
526 };
527
528
529 /**
530  * If a session monitor is attached, notify it about the new
531  * session state.
532  *
533  * @param plugin our plugin
534  * @param session session that changed state
535  * @param state new state of the session
536  */
537 static void
538 notify_session_monitor (struct Plugin *plugin,
539                         struct Session *session,
540                         enum GNUNET_TRANSPORT_SessionState state)
541 {
542   struct GNUNET_TRANSPORT_SessionInfo info;
543
544   if (NULL == plugin->sic)
545     return;
546   memset (&info, 0, sizeof (info));
547   info.state = state;
548   info.is_inbound = (0 != (GNUNET_HELLO_ADDRESS_INFO_INBOUND & session->address->local_info))
549     ? GNUNET_YES
550     : GNUNET_NO;
551   info.num_msg_pending = session->msgs_in_queue;
552   info.num_bytes_pending = session->bytes_in_queue;
553   if (NULL != session->receive_delay_task)
554     info.receive_delay = session->receive_delay;
555   info.session_timeout = session->timeout;
556   info.address = session->address;
557   plugin->sic (plugin->sic_cls,
558                session,
559                &info);
560 }
561
562
563 /**
564  * Our external IP address/port mapping has changed.
565  *
566  * @param cls closure, the `struct Plugin`
567  * @param add_remove #GNUNET_YES to mean the new public IP address, #GNUNET_NO to mean
568  *     the previous (now invalid) one
569  * @param addr either the previous or the new public IP address
570  * @param addrlen actual length of @a addr
571  */
572 static void
573 tcp_nat_port_map_callback (void *cls,
574                            int add_remove,
575                            const struct sockaddr *addr,
576                            socklen_t addrlen)
577 {
578   struct Plugin *plugin = cls;
579   struct GNUNET_HELLO_Address *address;
580   struct IPv4TcpAddress t4;
581   struct IPv6TcpAddress t6;
582   void *arg;
583   size_t args;
584
585   LOG(GNUNET_ERROR_TYPE_INFO,
586       "NAT notification to %s address `%s'\n",
587       (GNUNET_YES == add_remove) ? "add" : "remove",
588       GNUNET_a2s (addr, addrlen));
589   /* convert 'addr' to our internal format */
590   switch (addr->sa_family)
591   {
592   case AF_INET:
593     GNUNET_assert(addrlen == sizeof(struct sockaddr_in));
594     memset (&t4, 0, sizeof(t4));
595     t4.options = htonl (plugin->myoptions);
596     t4.ipv4_addr = ((struct sockaddr_in *) addr)->sin_addr.s_addr;
597     t4.t4_port = ((struct sockaddr_in *) addr)->sin_port;
598     arg = &t4;
599     args = sizeof (t4);
600     break;
601   case AF_INET6:
602     GNUNET_assert(addrlen == sizeof(struct sockaddr_in6));
603     memset (&t6, 0, sizeof(t6));
604     memcpy (&t6.ipv6_addr, &((struct sockaddr_in6 *) addr)->sin6_addr,
605         sizeof(struct in6_addr));
606     t6.options = htonl (plugin->myoptions);
607     t6.t6_port = ((struct sockaddr_in6 *) addr)->sin6_port;
608     arg = &t6;
609     args = sizeof (t6);
610     break;
611   default:
612     GNUNET_break(0);
613     return;
614   }
615   /* modify our published address list */
616   GNUNET_assert ((args == sizeof (struct IPv4TcpAddress)) ||
617       (args == sizeof (struct IPv6TcpAddress)));
618   address = GNUNET_HELLO_address_allocate (plugin->env->my_identity,
619       PLUGIN_NAME, arg, args, GNUNET_HELLO_ADDRESS_INFO_NONE);
620   plugin->env->notify_address (plugin->env->cls, add_remove, address);
621   GNUNET_HELLO_address_free(address);
622 }
623
624
625 /**
626  * Function called for a quick conversion of the binary address to
627  * a numeric address.  Note that the caller must not free the
628  * address and that the next call to this function is allowed
629  * to override the address again.
630  *
631  * @param cls closure (`struct Plugin*`)
632  * @param addr binary address
633  * @param addrlen length of @a addr
634  * @return string representing the same address
635  */
636 static const char *
637 tcp_plugin_address_to_string (void *cls,
638                               const void *addr,
639                               size_t addrlen)
640 {
641   static char rbuf[INET6_ADDRSTRLEN + 12];
642   char buf[INET6_ADDRSTRLEN];
643   const void *sb;
644   struct in_addr a4;
645   struct in6_addr a6;
646   const struct IPv4TcpAddress *t4;
647   const struct IPv6TcpAddress *t6;
648   int af;
649   uint16_t port;
650   uint32_t options;
651
652   switch (addrlen)
653   {
654   case sizeof(struct IPv6TcpAddress):
655     t6 = addr;
656     af = AF_INET6;
657     port = ntohs (t6->t6_port);
658     options = ntohl (t6->options);
659     memcpy (&a6, &t6->ipv6_addr, sizeof(a6));
660     sb = &a6;
661     break;
662   case sizeof(struct IPv4TcpAddress):
663     t4 = addr;
664     af = AF_INET;
665     port = ntohs (t4->t4_port);
666     options = ntohl (t4->options);
667     memcpy (&a4, &t4->ipv4_addr, sizeof(a4));
668     sb = &a4;
669     break;
670   default:
671     LOG (GNUNET_ERROR_TYPE_WARNING,
672          _("Unexpected address length: %u bytes\n"),
673          (unsigned int) addrlen);
674     return NULL ;
675   }
676   if (NULL == inet_ntop (af, sb, buf, INET6_ADDRSTRLEN))
677   {
678     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
679                          "inet_ntop");
680     return NULL ;
681   }
682   GNUNET_snprintf (rbuf, sizeof(rbuf),
683                    (af == AF_INET6) ? "%s.%u.[%s]:%u" : "%s.%u.%s:%u",
684                    PLUGIN_NAME,
685                    options,
686                    buf,
687                    port);
688   return rbuf;
689 }
690
691
692 /**
693  * Function called to convert a string address to
694  * a binary address.
695  *
696  * @param cls closure (`struct Plugin*`)
697  * @param addr string address
698  * @param addrlen length of the address
699  * @param buf location to store the buffer
700  * @param added location to store the number of bytes in the buffer.
701  *        If the function returns #GNUNET_SYSERR, its contents are undefined.
702  * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure
703  */
704 static int
705 tcp_plugin_string_to_address (void *cls,
706                               const char *addr,
707                               uint16_t addrlen,
708                               void **buf,
709                               size_t *added)
710 {
711   struct sockaddr_storage socket_address;
712   char *address;
713   char *plugin;
714   char *optionstr;
715   uint32_t options;
716
717   /* Format tcp.options.address:port */
718   address = NULL;
719   plugin = NULL;
720   optionstr = NULL;
721   if ((NULL == addr) || (0 == addrlen))
722   {
723     GNUNET_break(0);
724     return GNUNET_SYSERR;
725   }
726   if ('\0' != addr[addrlen - 1])
727   {
728     GNUNET_break(0);
729     return GNUNET_SYSERR;
730   }
731   if (strlen (addr) != addrlen - 1)
732   {
733     GNUNET_break(0);
734     return GNUNET_SYSERR;
735   }
736   plugin = GNUNET_strdup (addr);
737   optionstr = strchr (plugin, '.');
738   if (NULL == optionstr)
739   {
740     GNUNET_break(0);
741     GNUNET_free(plugin);
742     return GNUNET_SYSERR;
743   }
744   optionstr[0] = '\0';
745   optionstr++;
746   options = atol (optionstr);
747   address = strchr (optionstr, '.');
748   if (NULL == address)
749   {
750     GNUNET_break(0);
751     GNUNET_free(plugin);
752     return GNUNET_SYSERR;
753   }
754   address[0] = '\0';
755   address++;
756
757   if (GNUNET_OK !=
758       GNUNET_STRINGS_to_address_ip (address,
759                                     strlen (address),
760                                     &socket_address))
761   {
762     GNUNET_break(0);
763     GNUNET_free(plugin);
764     return GNUNET_SYSERR;
765   }
766
767   GNUNET_free(plugin);
768   switch (socket_address.ss_family)
769   {
770   case AF_INET:
771   {
772     struct IPv4TcpAddress *t4;
773     struct sockaddr_in *in4 = (struct sockaddr_in *) &socket_address;
774     t4 = GNUNET_new (struct IPv4TcpAddress);
775     t4->options = htonl (options);
776     t4->ipv4_addr = in4->sin_addr.s_addr;
777     t4->t4_port = in4->sin_port;
778     *buf = t4;
779     *added = sizeof(struct IPv4TcpAddress);
780     return GNUNET_OK;
781   }
782   case AF_INET6:
783   {
784     struct IPv6TcpAddress *t6;
785     struct sockaddr_in6 *in6 = (struct sockaddr_in6 *) &socket_address;
786     t6 = GNUNET_new (struct IPv6TcpAddress);
787     t6->options = htonl (options);
788     t6->ipv6_addr = in6->sin6_addr;
789     t6->t6_port = in6->sin6_port;
790     *buf = t6;
791     *added = sizeof(struct IPv6TcpAddress);
792     return GNUNET_OK;
793   }
794   default:
795     return GNUNET_SYSERR;
796   }
797 }
798
799
800 /**
801  * Find the session handle for the given client.
802  * Currently uses both the hashmap and the client
803  * context, as the client context is new and the
804  * logic still needs to be tested.
805  *
806  * @param plugin the plugin
807  * @param client which client to find the session handle for
808  * @return NULL if no matching session exists
809  */
810 static struct Session *
811 lookup_session_by_client (struct Plugin *plugin,
812                           struct GNUNET_SERVER_Client *client)
813 {
814   return GNUNET_SERVER_client_get_user_context (client,
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   if (NULL == hostname)
1891   {
1892     /* Final call, done */
1893     ppc->resolver_handle = NULL;
1894     GNUNET_CONTAINER_DLL_remove (plugin->ppc_dll_head,
1895                                  plugin->ppc_dll_tail,
1896                                  ppc);
1897     ppc->asc (ppc->asc_cls,
1898               NULL,
1899               GNUNET_OK);
1900     GNUNET_free (ppc);
1901     return;
1902   }
1903   if (GNUNET_YES == ppc->ipv6)
1904     GNUNET_asprintf (&ret,
1905                      "%s.%u.[%s]:%d",
1906                      PLUGIN_NAME,
1907                      ppc->options,
1908                      hostname,
1909                      ppc->port);
1910   else
1911     GNUNET_asprintf (&ret,
1912                      "%s.%u.%s:%d",
1913                      PLUGIN_NAME,
1914                      ppc->options,
1915                      hostname,
1916                      ppc->port);
1917   ppc->asc (ppc->asc_cls,
1918             ret,
1919             GNUNET_OK);
1920   GNUNET_free (ret);
1921 }
1922
1923
1924 /**
1925  * Convert the transports address to a nice, human-readable format.
1926  *
1927  * @param cls closure with the `struct Plugin`
1928  * @param type name of the transport that generated the address
1929  * @param addr one of the addresses of the host, NULL for the last address
1930  *        the specific address format depends on the transport
1931  * @param addrlen length of the @a addr
1932  * @param numeric should (IP) addresses be displayed in numeric form?
1933  * @param timeout after how long should we give up?
1934  * @param asc function to call on each string
1935  * @param asc_cls closure for @a asc
1936  */
1937 static void
1938 tcp_plugin_address_pretty_printer (void *cls,
1939                                    const char *type,
1940                                    const void *addr,
1941                                    size_t addrlen,
1942                                    int numeric,
1943                                    struct GNUNET_TIME_Relative timeout,
1944                                    GNUNET_TRANSPORT_AddressStringCallback asc,
1945                                    void *asc_cls)
1946 {
1947   struct Plugin *plugin = cls;
1948   struct PrettyPrinterContext *ppc;
1949   const void *sb;
1950   size_t sbs;
1951   struct sockaddr_in a4;
1952   struct sockaddr_in6 a6;
1953   const struct IPv4TcpAddress *t4;
1954   const struct IPv6TcpAddress *t6;
1955   uint16_t port;
1956   uint32_t options;
1957
1958   if (sizeof(struct IPv6TcpAddress) == addrlen)
1959   {
1960     t6 = addr;
1961     memset (&a6, 0, sizeof(a6));
1962     a6.sin6_family = AF_INET6;
1963     a6.sin6_port = t6->t6_port;
1964     memcpy (&a6.sin6_addr, &t6->ipv6_addr, sizeof(struct in6_addr));
1965     port = ntohs (t6->t6_port);
1966     options = ntohl (t6->options);
1967     sb = &a6;
1968     sbs = sizeof(a6);
1969   }
1970   else if (sizeof(struct IPv4TcpAddress) == addrlen)
1971   {
1972     t4 = addr;
1973     memset (&a4, 0, sizeof(a4));
1974     a4.sin_family = AF_INET;
1975     a4.sin_port = t4->t4_port;
1976     a4.sin_addr.s_addr = t4->ipv4_addr;
1977     port = ntohs (t4->t4_port);
1978     options = ntohl (t4->options);
1979     sb = &a4;
1980     sbs = sizeof(a4);
1981   }
1982   else
1983   {
1984     /* invalid address */
1985     asc (asc_cls, NULL, GNUNET_SYSERR);
1986     asc (asc_cls, NULL, GNUNET_OK);
1987     return;
1988   }
1989   ppc = GNUNET_new (struct PrettyPrinterContext);
1990   ppc->plugin = plugin;
1991   if (addrlen == sizeof(struct IPv6TcpAddress))
1992     ppc->ipv6 = GNUNET_YES;
1993   else
1994     ppc->ipv6 = GNUNET_NO;
1995   ppc->asc = asc;
1996   ppc->asc_cls = asc_cls;
1997   ppc->port = port;
1998   ppc->options = options;
1999   ppc->resolver_handle = GNUNET_RESOLVER_hostname_get (sb,
2000                                                        sbs,
2001                                                        ! numeric,
2002                                                        timeout,
2003                                                        &append_port, ppc);
2004   if (NULL == ppc->resolver_handle)
2005   {
2006     GNUNET_break (0);
2007     GNUNET_free (ppc);
2008     return;
2009   }
2010   GNUNET_CONTAINER_DLL_insert (plugin->ppc_dll_head,
2011                                plugin->ppc_dll_tail,
2012                                ppc);
2013 }
2014
2015
2016 /**
2017  * Check if the given port is plausible (must be either our listen
2018  * port or our advertised port), or any port if we are behind NAT
2019  * and do not have a port open.  If it is neither, we return
2020  * #GNUNET_SYSERR.
2021  *
2022  * @param plugin global variables
2023  * @param in_port port number to check
2024  * @return #GNUNET_OK if port is either open_port or adv_port
2025  */
2026 static int
2027 check_port (struct Plugin *plugin,
2028             uint16_t in_port)
2029 {
2030   if ( (in_port == plugin->adv_port) ||
2031        (in_port == plugin->open_port) )
2032     return GNUNET_OK;
2033   return GNUNET_SYSERR;
2034 }
2035
2036
2037 /**
2038  * Function that will be called to check if a binary address for this
2039  * plugin is well-formed and corresponds to an address for THIS peer
2040  * (as per our configuration).  Naturally, if absolutely necessary,
2041  * plugins can be a bit conservative in their answer, but in general
2042  * plugins should make sure that the address does not redirect
2043  * traffic to a 3rd party that might try to man-in-the-middle our
2044  * traffic.
2045  *
2046  * @param cls closure, our `struct Plugin *`
2047  * @param addr pointer to the address
2048  * @param addrlen length of @a addr
2049  * @return #GNUNET_OK if this is a plausible address for this peer
2050  *         and transport, #GNUNET_SYSERR if not
2051  */
2052 static int
2053 tcp_plugin_check_address (void *cls,
2054                           const void *addr,
2055                           size_t addrlen)
2056 {
2057   struct Plugin *plugin = cls;
2058   const struct IPv4TcpAddress *v4;
2059   const struct IPv6TcpAddress *v6;
2060
2061   if ( (addrlen != sizeof(struct IPv4TcpAddress)) &&
2062        (addrlen != sizeof(struct IPv6TcpAddress)) )
2063   {
2064     GNUNET_break_op (0);
2065     return GNUNET_SYSERR;
2066   }
2067
2068   if (addrlen == sizeof(struct IPv4TcpAddress))
2069   {
2070     v4 = (const struct IPv4TcpAddress *) addr;
2071     if (0 != memcmp (&v4->options,
2072                      &plugin->myoptions,
2073                      sizeof(uint32_t)))
2074     {
2075       GNUNET_break (0);
2076       return GNUNET_SYSERR;
2077     }
2078     if (GNUNET_OK != check_port (plugin,
2079                                  ntohs (v4->t4_port)))
2080       return GNUNET_SYSERR;
2081     if (GNUNET_OK !=
2082         GNUNET_NAT_test_address (plugin->nat,
2083                                  &v4->ipv4_addr,
2084                                  sizeof (struct in_addr)))
2085       return GNUNET_SYSERR;
2086   }
2087   else
2088   {
2089     v6 = (const struct IPv6TcpAddress *) addr;
2090     if (IN6_IS_ADDR_LINKLOCAL (&v6->ipv6_addr))
2091     {
2092       GNUNET_break_op (0);
2093       return GNUNET_SYSERR;
2094     }
2095     if (0 != memcmp (&v6->options,
2096                      &plugin->myoptions,
2097                      sizeof (uint32_t)))
2098     {
2099       GNUNET_break (0);
2100       return GNUNET_SYSERR;
2101     }
2102     if (GNUNET_OK != check_port (plugin,
2103                                  ntohs (v6->t6_port)))
2104       return GNUNET_SYSERR;
2105     if (GNUNET_OK !=
2106         GNUNET_NAT_test_address (plugin->nat,
2107                                  &v6->ipv6_addr,
2108                                  sizeof(struct in6_addr)))
2109       return GNUNET_SYSERR;
2110   }
2111   return GNUNET_OK;
2112 }
2113
2114
2115 /**
2116  * We've received a nat probe from this peer via TCP.  Finish
2117  * creating the client session and resume sending of queued
2118  * messages.
2119  *
2120  * @param cls closure
2121  * @param client identification of the client
2122  * @param message the actual message
2123  */
2124 static void
2125 handle_tcp_nat_probe (void *cls,
2126                       struct GNUNET_SERVER_Client *client,
2127                       const struct GNUNET_MessageHeader *message)
2128 {
2129   struct Plugin *plugin = cls;
2130   struct Session *session;
2131   const struct TCP_NAT_ProbeMessage *tcp_nat_probe;
2132   size_t alen;
2133   void *vaddr;
2134   struct IPv4TcpAddress *t4;
2135   struct IPv6TcpAddress *t6;
2136   const struct sockaddr_in *s4;
2137   const struct sockaddr_in6 *s6;
2138
2139   LOG (GNUNET_ERROR_TYPE_DEBUG,
2140        "Received NAT probe\n");
2141   /* We have received a TCP NAT probe, meaning we (hopefully) initiated
2142    * a connection to this peer by running gnunet-nat-client.  This peer
2143    * received the punch message and now wants us to use the new connection
2144    * as the default for that peer.  Do so and then send a WELCOME message
2145    * so we can really be connected!
2146    */
2147   if (ntohs (message->size) != sizeof(struct TCP_NAT_ProbeMessage))
2148   {
2149     GNUNET_break_op(0);
2150     GNUNET_SERVER_receive_done (client,
2151                                 GNUNET_SYSERR);
2152     return;
2153   }
2154
2155   tcp_nat_probe = (const struct TCP_NAT_ProbeMessage *) message;
2156   if (0 == memcmp (&tcp_nat_probe->clientIdentity, plugin->env->my_identity,
2157           sizeof(struct GNUNET_PeerIdentity)))
2158   {
2159     /* refuse connections from ourselves */
2160     GNUNET_SERVER_receive_done (client,
2161                                 GNUNET_SYSERR);
2162     return;
2163   }
2164
2165   session = GNUNET_CONTAINER_multipeermap_get (plugin->nat_wait_conns,
2166                                                &tcp_nat_probe->clientIdentity);
2167   if (NULL == session)
2168   {
2169     LOG (GNUNET_ERROR_TYPE_DEBUG,
2170          "Did NOT find session for NAT probe!\n");
2171     GNUNET_SERVER_receive_done (client,
2172                                 GNUNET_OK);
2173     return;
2174   }
2175   LOG (GNUNET_ERROR_TYPE_DEBUG,
2176        "Found session for NAT probe!\n");
2177
2178   if (NULL != session->nat_connection_timeout)
2179   {
2180     GNUNET_SCHEDULER_cancel (session->nat_connection_timeout);
2181     session->nat_connection_timeout = NULL;
2182   }
2183
2184   if (GNUNET_OK !=
2185       GNUNET_SERVER_client_get_address (client,
2186                                         &vaddr,
2187                                         &alen))
2188   {
2189     GNUNET_break(0);
2190     GNUNET_SERVER_receive_done (client,
2191                                 GNUNET_SYSERR);
2192     tcp_plugin_disconnect_session (plugin,
2193                                    session);
2194     return;
2195   }
2196   GNUNET_assert (GNUNET_YES ==
2197                  GNUNET_CONTAINER_multipeermap_remove (plugin->nat_wait_conns,
2198                                                        &tcp_nat_probe->clientIdentity,
2199                                                        session));
2200   GNUNET_SERVER_client_set_user_context (client,
2201                                          session);
2202   (void) GNUNET_CONTAINER_multipeermap_put (plugin->sessionmap,
2203                                             &session->target,
2204                                             session,
2205                                             GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
2206   session->last_activity = GNUNET_TIME_absolute_get ();
2207   LOG (GNUNET_ERROR_TYPE_DEBUG,
2208        "Found address `%s' for incoming connection\n",
2209        GNUNET_a2s (vaddr, alen));
2210   switch (((const struct sockaddr *) vaddr)->sa_family)
2211   {
2212   case AF_INET:
2213     s4 = vaddr;
2214     t4 = GNUNET_new (struct IPv4TcpAddress);
2215     t4->options = htonl (TCP_OPTIONS_NONE);
2216     t4->t4_port = s4->sin_port;
2217     t4->ipv4_addr = s4->sin_addr.s_addr;
2218     session->address = GNUNET_HELLO_address_allocate (&tcp_nat_probe->clientIdentity,
2219                                                       PLUGIN_NAME,
2220                                                       &t4,
2221                                                       sizeof(struct IPv4TcpAddress),
2222                                                       GNUNET_HELLO_ADDRESS_INFO_NONE);
2223     break;
2224   case AF_INET6:
2225     s6 = vaddr;
2226     t6 = GNUNET_new (struct IPv6TcpAddress);
2227     t6->options = htonl (TCP_OPTIONS_NONE);
2228     t6->t6_port = s6->sin6_port;
2229     memcpy (&t6->ipv6_addr, &s6->sin6_addr, sizeof(struct in6_addr));
2230     session->address = GNUNET_HELLO_address_allocate (&tcp_nat_probe->clientIdentity,
2231                                                       PLUGIN_NAME,
2232                                                       &t6,
2233                                                       sizeof(struct IPv6TcpAddress),
2234                                                       GNUNET_HELLO_ADDRESS_INFO_NONE);
2235     break;
2236   default:
2237     GNUNET_break_op(0);
2238     LOG(GNUNET_ERROR_TYPE_DEBUG,
2239         "Bad address for incoming connection!\n");
2240     GNUNET_free(vaddr);
2241     GNUNET_SERVER_receive_done (client,
2242                                 GNUNET_SYSERR);
2243     tcp_plugin_disconnect_session (plugin,
2244                                    session);
2245     return;
2246   }
2247   GNUNET_free (vaddr);
2248   GNUNET_break (NULL == session->client);
2249   session->client = client;
2250   GNUNET_STATISTICS_update (plugin->env->stats,
2251                             gettext_noop ("# TCP sessions active"),
2252                             1,
2253                             GNUNET_NO);
2254   process_pending_messages (session);
2255   GNUNET_SERVER_receive_done (client,
2256                               GNUNET_OK);
2257 }
2258
2259
2260 /**
2261  * We've received a welcome from this peer via TCP.  Possibly create a
2262  * fresh client record and send back our welcome.
2263  *
2264  * @param cls closure
2265  * @param client identification of the client
2266  * @param message the actual message
2267  */
2268 static void
2269 handle_tcp_welcome (void *cls,
2270                     struct GNUNET_SERVER_Client *client,
2271                     const struct GNUNET_MessageHeader *message)
2272 {
2273   struct Plugin *plugin = cls;
2274   const struct WelcomeMessage *wm = (const struct WelcomeMessage *) message;
2275   struct GNUNET_HELLO_Address *address;
2276   struct Session *session;
2277   size_t alen;
2278   void *vaddr;
2279   struct IPv4TcpAddress t4;
2280   struct IPv6TcpAddress t6;
2281   const struct sockaddr_in *s4;
2282   const struct sockaddr_in6 *s6;
2283
2284   if (0 == memcmp (&wm->clientIdentity,
2285                    plugin->env->my_identity,
2286                    sizeof(struct GNUNET_PeerIdentity)))
2287   {
2288     /* refuse connections from ourselves */
2289     GNUNET_SERVER_receive_done (client,
2290                                 GNUNET_SYSERR);
2291     if (GNUNET_OK ==
2292         GNUNET_SERVER_client_get_address (client,
2293                                           &vaddr,
2294                                           &alen))
2295     {
2296       LOG (GNUNET_ERROR_TYPE_INFO,
2297            "Received WELCOME message from my own identity `%4s' on address `%s'\n",
2298            GNUNET_i2s (&wm->clientIdentity),
2299            GNUNET_a2s (vaddr, alen));
2300       GNUNET_free(vaddr);
2301     }
2302     return;
2303   }
2304
2305   LOG(GNUNET_ERROR_TYPE_DEBUG,
2306       "Received WELCOME message from `%4s' %p\n",
2307       GNUNET_i2s (&wm->clientIdentity),
2308       client);
2309   GNUNET_STATISTICS_update (plugin->env->stats,
2310                             gettext_noop ("# TCP WELCOME messages received"),
2311                             1,
2312                             GNUNET_NO);
2313   session = lookup_session_by_client (plugin, client);
2314   if (NULL != session)
2315   {
2316     if (GNUNET_OK ==
2317         GNUNET_SERVER_client_get_address (client, &vaddr, &alen))
2318     {
2319       LOG (GNUNET_ERROR_TYPE_DEBUG,
2320            "Found existing session %p for peer `%s'\n",
2321            session,
2322            GNUNET_a2s (vaddr, alen));
2323       GNUNET_free (vaddr);
2324     }
2325   }
2326   else
2327   {
2328     if (GNUNET_OK ==
2329         GNUNET_SERVER_client_get_address (client, &vaddr, &alen))
2330     {
2331       if (alen == sizeof(struct sockaddr_in))
2332       {
2333         s4 = vaddr;
2334         memset (&t4, '\0', sizeof (t4));
2335         t4.options = htonl (TCP_OPTIONS_NONE);
2336         t4.t4_port = s4->sin_port;
2337         t4.ipv4_addr = s4->sin_addr.s_addr;
2338         address = GNUNET_HELLO_address_allocate (&wm->clientIdentity,
2339                                                  PLUGIN_NAME,
2340                                                  &t4,
2341                                                  sizeof(t4),
2342                                                  GNUNET_HELLO_ADDRESS_INFO_INBOUND);
2343       }
2344       else if (alen == sizeof(struct sockaddr_in6))
2345       {
2346         s6 = vaddr;
2347         memset (&t6, '\0', sizeof (t6));
2348         t6.options = htonl (TCP_OPTIONS_NONE);
2349         t6.t6_port = s6->sin6_port;
2350         memcpy (&t6.ipv6_addr, &s6->sin6_addr, sizeof(struct in6_addr));
2351         address = GNUNET_HELLO_address_allocate (&wm->clientIdentity,
2352                                                  PLUGIN_NAME,
2353                                                  &t6,
2354                                                  sizeof (t6),
2355                                                  GNUNET_HELLO_ADDRESS_INFO_INBOUND);
2356       }
2357       else
2358       {
2359         GNUNET_break (0);
2360         GNUNET_free_non_null (vaddr);
2361         GNUNET_SERVER_receive_done (client,
2362                                     GNUNET_SYSERR);
2363         return;
2364       }
2365       session = create_session (plugin,
2366                                 address,
2367                                 plugin->env->get_address_type (plugin->env->cls,
2368                                                                vaddr,
2369                                                                alen),
2370                                 client,
2371                                 GNUNET_NO);
2372       GNUNET_break (GNUNET_ATS_NET_UNSPECIFIED != session->scope);
2373       GNUNET_HELLO_address_free (address);
2374       LOG (GNUNET_ERROR_TYPE_DEBUG,
2375            "Creating new%s session %p for peer `%s' client %p\n",
2376            GNUNET_HELLO_address_check_option (session->address,
2377                                               GNUNET_HELLO_ADDRESS_INFO_INBOUND)
2378            ? " inbound" : "",
2379            session,
2380            tcp_plugin_address_to_string (plugin,
2381                                          session->address->address,
2382                                          session->address->address_length),
2383            client);
2384       GNUNET_free (vaddr);
2385       (void) GNUNET_CONTAINER_multipeermap_put (plugin->sessionmap,
2386                                                 &session->target,
2387                                                 session,
2388                                                 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
2389       /* Notify transport and ATS about new session */
2390       plugin->env->session_start (plugin->env->cls,
2391                                   session->address,
2392                                   session,
2393                                   session->scope);
2394     }
2395     else
2396     {
2397       LOG(GNUNET_ERROR_TYPE_DEBUG,
2398           "Did not obtain TCP socket address for incoming connection\n");
2399       GNUNET_break(0);
2400       GNUNET_SERVER_receive_done (client,
2401                                   GNUNET_SYSERR);
2402       return;
2403     }
2404   }
2405
2406   if (session->expecting_welcome != GNUNET_YES)
2407   {
2408     GNUNET_break_op(0);
2409     GNUNET_SERVER_receive_done (client,
2410                                 GNUNET_SYSERR);
2411     GNUNET_break(0);
2412     return;
2413   }
2414   session->last_activity = GNUNET_TIME_absolute_get ();
2415   session->expecting_welcome = GNUNET_NO;
2416
2417   process_pending_messages (session);
2418   GNUNET_SERVER_client_set_timeout (client,
2419                                     GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2420   GNUNET_SERVER_receive_done (client,
2421                               GNUNET_OK);
2422 }
2423
2424
2425 /**
2426  * We've received data for this peer via TCP.  Unbox,
2427  * compute latency and forward.
2428  *
2429  * @param cls closure
2430  * @param client identification of the client
2431  * @param message the actual message
2432  */
2433 static void
2434 handle_tcp_data (void *cls,
2435                  struct GNUNET_SERVER_Client *client,
2436                  const struct GNUNET_MessageHeader *message)
2437 {
2438   struct Plugin *plugin = cls;
2439   struct Session *session;
2440   struct GNUNET_TIME_Relative delay;
2441   uint16_t type;
2442
2443   type = ntohs (message->type);
2444   if ( (GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_WELCOME == type) ||
2445        (GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_NAT_PROBE == type) )
2446   {
2447     /* We don't want to propagate WELCOME and NAT Probe messages up! */
2448     GNUNET_SERVER_receive_done (client,
2449                                 GNUNET_OK);
2450     return;
2451   }
2452   session = lookup_session_by_client (plugin, client);
2453   if (NULL == session)
2454   {
2455     /* No inbound session found */
2456     void *vaddr;
2457     size_t alen;
2458
2459     GNUNET_SERVER_client_get_address (client,
2460                                       &vaddr,
2461                                       &alen);
2462     LOG (GNUNET_ERROR_TYPE_ERROR,
2463          "Received unexpected %u bytes of type %u from `%s'\n",
2464          (unsigned int) ntohs (message->size),
2465          (unsigned int) ntohs (message->type),
2466          GNUNET_a2s (vaddr,
2467                      alen));
2468     GNUNET_break_op(0);
2469     GNUNET_SERVER_receive_done (client,
2470                                 GNUNET_SYSERR);
2471     GNUNET_free_non_null (vaddr);
2472     return;
2473   }
2474   if (GNUNET_YES == session->expecting_welcome)
2475   {
2476     /* Session is expecting WELCOME message */
2477     void *vaddr;
2478     size_t alen;
2479
2480     GNUNET_SERVER_client_get_address (client, &vaddr, &alen);
2481     LOG (GNUNET_ERROR_TYPE_ERROR,
2482          "Received unexpected %u bytes of type %u from `%s'\n",
2483          (unsigned int) ntohs (message->size),
2484          (unsigned int) ntohs (message->type),
2485          GNUNET_a2s (vaddr, alen));
2486     GNUNET_break_op(0);
2487     GNUNET_SERVER_receive_done (client,
2488                                 GNUNET_SYSERR);
2489     GNUNET_free_non_null (vaddr);
2490     return;
2491   }
2492
2493   session->last_activity = GNUNET_TIME_absolute_get ();
2494   LOG (GNUNET_ERROR_TYPE_DEBUG,
2495        "Passing %u bytes of type %u from `%4s' to transport service.\n",
2496        (unsigned int) ntohs (message->size),
2497        (unsigned int) ntohs (message->type),
2498        GNUNET_i2s (&session->target));
2499
2500   GNUNET_STATISTICS_update (plugin->env->stats,
2501                             gettext_noop ("# bytes received via TCP"),
2502                             ntohs (message->size),
2503                             GNUNET_NO);
2504
2505   GNUNET_assert (GNUNET_CONTAINER_multipeermap_contains_value (plugin->sessionmap,
2506                                                                &session->target,
2507                                                                session));
2508   delay = plugin->env->receive (plugin->env->cls,
2509                                 session->address,
2510                                 session,
2511                                 message);
2512   reschedule_session_timeout (session);
2513   if (0 == delay.rel_value_us)
2514   {
2515     GNUNET_SERVER_receive_done (client,
2516                                 GNUNET_OK);
2517   }
2518   else
2519   {
2520     LOG (GNUNET_ERROR_TYPE_DEBUG,
2521          "Throttling receiving from `%s' for %s\n",
2522          GNUNET_i2s (&session->target),
2523          GNUNET_STRINGS_relative_time_to_string (delay,
2524                                                  GNUNET_YES));
2525     GNUNET_SERVER_disable_receive_done_warning (client);
2526     GNUNET_assert (NULL == session->receive_delay_task);
2527     session->receive_delay_task = GNUNET_SCHEDULER_add_delayed (delay,
2528                                                                 &delayed_done,
2529                                                                 session);
2530   }
2531 }
2532
2533
2534 /**
2535  * Function called whenever a peer is connected on the "SERVER" level.
2536  * Increments number of active connections and suspends server if we
2537  * have reached the limit.
2538  *
2539  * @param cls closure
2540  * @param client identification of the client
2541  */
2542 static void
2543 connect_notify (void *cls,
2544                 struct GNUNET_SERVER_Client *client)
2545 {
2546   struct Plugin *plugin = cls;
2547
2548   plugin->cur_connections++;
2549   GNUNET_STATISTICS_set (plugin->env->stats,
2550                          gettext_noop ("# TCP server connections active"),
2551                          plugin->cur_connections,
2552                          GNUNET_NO);
2553   GNUNET_STATISTICS_update (plugin->env->stats,
2554                             gettext_noop ("# TCP server connect events"),
2555                             1,
2556                             GNUNET_NO);
2557   if (plugin->cur_connections != plugin->max_connections)
2558     return;
2559   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2560               _("TCP connection limit reached, suspending server\n"));
2561   GNUNET_STATISTICS_update (plugin->env->stats,
2562                             gettext_noop ("# TCP service suspended"),
2563                             1,
2564                             GNUNET_NO);
2565   GNUNET_SERVER_suspend (plugin->server); /* Maximum number of connections rechead */
2566 }
2567
2568
2569 /**
2570  * Function called whenever a peer is disconnected on the "SERVER"
2571  * level.  Cleans up the connection, decrements number of active
2572  * connections and if applicable resumes listening.
2573  *
2574  * @param cls closure
2575  * @param client identification of the client
2576  */
2577 static void
2578 disconnect_notify (void *cls,
2579                    struct GNUNET_SERVER_Client *client)
2580 {
2581   struct Plugin *plugin = cls;
2582   struct Session *session;
2583
2584   if (NULL == client)
2585     return;
2586   session = lookup_session_by_client (plugin, client);
2587   if (NULL == session)
2588     return; /* unknown, nothing to do */
2589   LOG (GNUNET_ERROR_TYPE_DEBUG,
2590        "Destroying session of `%4s' with %s due to network-level disconnect.\n",
2591        GNUNET_i2s (&session->target),
2592        tcp_plugin_address_to_string (session->plugin,
2593                                      session->address->address,
2594                                      session->address->address_length));
2595
2596   if (plugin->cur_connections == plugin->max_connections)
2597   {
2598     GNUNET_STATISTICS_update (session->plugin->env->stats,
2599                               gettext_noop ("# TCP service resumed"),
2600                               1,
2601                               GNUNET_NO);
2602     GNUNET_SERVER_resume (plugin->server); /* Resume server  */
2603   }
2604   GNUNET_assert (plugin->cur_connections >= 1);
2605   plugin->cur_connections--;
2606   GNUNET_STATISTICS_set (plugin->env->stats,
2607                          gettext_noop ("# TCP server connections active"),
2608                          plugin->cur_connections,
2609                          GNUNET_NO);
2610   GNUNET_STATISTICS_update (session->plugin->env->stats,
2611                             gettext_noop ("# network-level TCP disconnect events"),
2612                             1,
2613                             GNUNET_NO);
2614   tcp_plugin_disconnect_session (plugin,
2615                                  session);
2616 }
2617
2618
2619 /**
2620  * We can now send a probe message, copy into buffer to really send.
2621  *
2622  * @param cls closure, a `struct TCPProbeContext`
2623  * @param size max size to copy
2624  * @param buf buffer to copy message to
2625  * @return number of bytes copied into @a buf
2626  */
2627 static size_t
2628 notify_send_probe (void *cls,
2629                    size_t size,
2630                    void *buf)
2631 {
2632   struct TCPProbeContext *tcp_probe_ctx = cls;
2633   struct Plugin *plugin = tcp_probe_ctx->plugin;
2634   size_t ret;
2635
2636   tcp_probe_ctx->transmit_handle = NULL;
2637   GNUNET_CONTAINER_DLL_remove (plugin->probe_head,
2638                                plugin->probe_tail,
2639                                tcp_probe_ctx);
2640   if (NULL == buf)
2641   {
2642     GNUNET_CONNECTION_destroy (tcp_probe_ctx->sock);
2643     GNUNET_free(tcp_probe_ctx);
2644     return 0;
2645   }
2646   GNUNET_assert(size >= sizeof(tcp_probe_ctx->message));
2647   memcpy (buf,
2648           &tcp_probe_ctx->message,
2649           sizeof(tcp_probe_ctx->message));
2650   GNUNET_SERVER_connect_socket (tcp_probe_ctx->plugin->server,
2651                                 tcp_probe_ctx->sock);
2652   ret = sizeof(tcp_probe_ctx->message);
2653   GNUNET_free (tcp_probe_ctx);
2654   return ret;
2655 }
2656
2657
2658 /**
2659  * Function called by the NAT subsystem suggesting another peer wants
2660  * to connect to us via connection reversal.  Try to connect back to the
2661  * given IP.
2662  *
2663  * @param cls closure
2664  * @param addr address to try
2665  * @param addrlen number of bytes in @a addr
2666  */
2667 static void
2668 try_connection_reversal (void *cls,
2669                          const struct sockaddr *addr,
2670                          socklen_t addrlen)
2671 {
2672   struct Plugin *plugin = cls;
2673   struct GNUNET_CONNECTION_Handle *sock;
2674   struct TCPProbeContext *tcp_probe_ctx;
2675
2676   /**
2677    * We have received an ICMP response, ostensibly from a peer
2678    * that wants to connect to us! Send a message to establish a connection.
2679    */
2680   sock = GNUNET_CONNECTION_create_from_sockaddr (AF_INET,
2681                                                  addr,
2682                                                  addrlen);
2683   if (NULL == sock)
2684   {
2685     /* failed for some odd reason (out of sockets?); ignore attempt */
2686     return;
2687   }
2688
2689   tcp_probe_ctx = GNUNET_new (struct TCPProbeContext);
2690   tcp_probe_ctx->message.header.size
2691     = htons (sizeof (struct TCP_NAT_ProbeMessage));
2692   tcp_probe_ctx->message.header.type
2693     = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_NAT_PROBE);
2694   tcp_probe_ctx->message.clientIdentity
2695     = *plugin->env->my_identity;
2696   tcp_probe_ctx->plugin = plugin;
2697   tcp_probe_ctx->sock = sock;
2698   GNUNET_CONTAINER_DLL_insert (plugin->probe_head,
2699                                plugin->probe_tail,
2700                                tcp_probe_ctx);
2701   tcp_probe_ctx->transmit_handle
2702     = GNUNET_CONNECTION_notify_transmit_ready (sock,
2703                                                ntohs (tcp_probe_ctx->message.header.size),
2704                                                GNUNET_TIME_UNIT_FOREVER_REL,
2705                                                &notify_send_probe,
2706                                                tcp_probe_ctx);
2707 }
2708
2709
2710 /**
2711  * Function obtain the network type for a session
2712  *
2713  * @param cls closure (`struct Plugin *`)
2714  * @param session the session
2715  * @return the network type in HBO or #GNUNET_SYSERR
2716  */
2717 static enum GNUNET_ATS_Network_Type
2718 tcp_plugin_get_network (void *cls,
2719                         struct Session *session)
2720 {
2721   return session->scope;
2722 }
2723
2724
2725 /**
2726  * Return information about the given session to the
2727  * monitor callback.
2728  *
2729  * @param cls the `struct Plugin` with the monitor callback (`sic`)
2730  * @param peer peer we send information about
2731  * @param value our `struct Session` to send information about
2732  * @return #GNUNET_OK (continue to iterate)
2733  */
2734 static int
2735 send_session_info_iter (void *cls,
2736                         const struct GNUNET_PeerIdentity *peer,
2737                         void *value)
2738 {
2739   struct Plugin *plugin = cls;
2740   struct Session *session = value;
2741
2742   notify_session_monitor (plugin,
2743                           session,
2744                           GNUNET_TRANSPORT_SS_INIT);
2745   /* FIXME: cannot tell if this is up or not from current
2746      session state... */
2747   notify_session_monitor (plugin,
2748                           session,
2749                           GNUNET_TRANSPORT_SS_UP);
2750   return GNUNET_OK;
2751 }
2752
2753
2754 /**
2755  * Begin monitoring sessions of a plugin.  There can only
2756  * be one active monitor per plugin (i.e. if there are
2757  * multiple monitors, the transport service needs to
2758  * multiplex the generated events over all of them).
2759  *
2760  * @param cls closure of the plugin
2761  * @param sic callback to invoke, NULL to disable monitor;
2762  *            plugin will being by iterating over all active
2763  *            sessions immediately and then enter monitor mode
2764  * @param sic_cls closure for @a sic
2765  */
2766 static void
2767 tcp_plugin_setup_monitor (void *cls,
2768                           GNUNET_TRANSPORT_SessionInfoCallback sic,
2769                           void *sic_cls)
2770 {
2771   struct Plugin *plugin = cls;
2772
2773   plugin->sic = sic;
2774   plugin->sic_cls = sic_cls;
2775   if (NULL != sic)
2776   {
2777     GNUNET_CONTAINER_multipeermap_iterate (plugin->sessionmap,
2778                                            &send_session_info_iter,
2779                                            plugin);
2780     /* signal end of first iteration */
2781     sic (sic_cls, NULL, NULL);
2782   }
2783 }
2784
2785
2786 /**
2787  * Entry point for the plugin.
2788  *
2789  * @param cls closure, the `struct GNUNET_TRANSPORT_PluginEnvironment *`
2790  * @return the `struct GNUNET_TRANSPORT_PluginFunctions *` or NULL on error
2791  */
2792 void *
2793 libgnunet_plugin_transport_tcp_init (void *cls)
2794 {
2795   static const struct GNUNET_SERVER_MessageHandler my_handlers[] = {
2796     { &handle_tcp_welcome, NULL,
2797       GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_WELCOME,
2798       sizeof(struct WelcomeMessage) },
2799     { &handle_tcp_nat_probe, NULL,
2800       GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_NAT_PROBE,
2801       sizeof(struct TCP_NAT_ProbeMessage) },
2802     { &handle_tcp_data, NULL,
2803       GNUNET_MESSAGE_TYPE_ALL, 0 },
2804     { NULL, NULL, 0, 0 }
2805   };
2806   struct GNUNET_TRANSPORT_PluginEnvironment *env = cls;
2807   struct GNUNET_TRANSPORT_PluginFunctions *api;
2808   struct Plugin *plugin;
2809   struct GNUNET_SERVICE_Context *service;
2810   unsigned long long aport;
2811   unsigned long long bport;
2812   unsigned long long max_connections;
2813   unsigned int i;
2814   struct GNUNET_TIME_Relative idle_timeout;
2815 #ifdef TCP_STEALTH
2816   struct GNUNET_NETWORK_Handle *const*lsocks;
2817 #endif
2818   int ret;
2819   int ret_s;
2820   struct sockaddr **addrs;
2821   socklen_t *addrlens;
2822
2823   if (NULL == env->receive)
2824   {
2825     /* run in 'stub' mode (i.e. as part of gnunet-peerinfo), don't fully
2826      initialze the plugin or the API */
2827     api = GNUNET_new (struct GNUNET_TRANSPORT_PluginFunctions);
2828     api->cls = NULL;
2829     api->address_pretty_printer = &tcp_plugin_address_pretty_printer;
2830     api->address_to_string = &tcp_plugin_address_to_string;
2831     api->string_to_address = &tcp_plugin_string_to_address;
2832     return api;
2833   }
2834
2835   GNUNET_assert (NULL != env->cfg);
2836   if (GNUNET_OK !=
2837       GNUNET_CONFIGURATION_get_value_number (env->cfg,
2838                                              "transport-tcp",
2839                                              "MAX_CONNECTIONS",
2840                                              &max_connections))
2841     max_connections = 128;
2842
2843   aport = 0;
2844   if ((GNUNET_OK !=
2845        GNUNET_CONFIGURATION_get_value_number (env->cfg, "transport-tcp",
2846                                               "PORT", &bport)) ||
2847       (bport > 65535) ||
2848       ((GNUNET_OK ==
2849         GNUNET_CONFIGURATION_get_value_number (env->cfg, "transport-tcp",
2850                                                "ADVERTISED-PORT", &aport)) &&
2851        (aport > 65535) ))
2852   {
2853     LOG(GNUNET_ERROR_TYPE_ERROR,
2854         _("Require valid port number for service `%s' in configuration!\n"),
2855         "transport-tcp");
2856     return NULL ;
2857   }
2858   if (0 == aport)
2859     aport = bport;
2860   if (0 == bport)
2861     aport = 0;
2862   if (0 != bport)
2863   {
2864     service = GNUNET_SERVICE_start ("transport-tcp",
2865                                     env->cfg,
2866                                     GNUNET_SERVICE_OPTION_NONE);
2867     if (NULL == service)
2868     {
2869       LOG (GNUNET_ERROR_TYPE_WARNING,
2870            _("Failed to start service.\n"));
2871       return NULL;
2872     }
2873   }
2874   else
2875     service = NULL;
2876
2877   api = NULL;
2878   plugin = GNUNET_new (struct Plugin);
2879   plugin->sessionmap = GNUNET_CONTAINER_multipeermap_create (max_connections,
2880                                                              GNUNET_YES);
2881   plugin->max_connections = max_connections;
2882   plugin->open_port = bport;
2883   plugin->adv_port = aport;
2884   plugin->env = env;
2885   plugin->my_welcome.header.size = htons (sizeof(struct WelcomeMessage));
2886   plugin->my_welcome.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_WELCOME);
2887   plugin->my_welcome.clientIdentity = *plugin->env->my_identity;
2888
2889   if ( (NULL != service) &&
2890        (GNUNET_YES ==
2891         GNUNET_CONFIGURATION_get_value_yesno (env->cfg,
2892                                               "transport-tcp",
2893                                               "TCP_STEALTH")) )
2894   {
2895 #ifdef TCP_STEALTH
2896     plugin->myoptions |= TCP_OPTIONS_TCP_STEALTH;
2897     lsocks = GNUNET_SERVICE_get_listen_sockets (service);
2898     if (NULL != lsocks)
2899     {
2900       uint32_t len = sizeof (struct WelcomeMessage);
2901
2902       for (i=0;NULL!=lsocks[i];i++)
2903       {
2904         if ( (GNUNET_OK !=
2905               GNUNET_NETWORK_socket_setsockopt (lsocks[i],
2906                                                 IPPROTO_TCP,
2907                                                 TCP_STEALTH,
2908                                                 env->my_identity,
2909                                                 sizeof (struct GNUNET_PeerIdentity))) ||
2910              (GNUNET_OK !=
2911               GNUNET_NETWORK_socket_setsockopt (lsocks[i],
2912                                                 IPPROTO_TCP,
2913                                                 TCP_STEALTH_INTEGRITY_LEN,
2914                                                 &len,
2915                                                 sizeof (len))) )
2916         {
2917           /* TCP STEALTH not supported by kernel */
2918           GNUNET_assert (0 == i);
2919           GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2920                       _("TCP_STEALTH not supported on this platform.\n"));
2921           goto die;
2922         }
2923       }
2924     }
2925 #else
2926     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2927                 _("TCP_STEALTH not supported on this platform.\n"));
2928     goto die;
2929 #endif
2930   }
2931
2932   if ( (NULL != service) &&
2933        (GNUNET_SYSERR !=
2934         (ret_s =
2935          GNUNET_SERVICE_get_server_addresses ("transport-tcp",
2936                                               env->cfg,
2937                                               &addrs,
2938                                               &addrlens))))
2939   {
2940     for (ret = ret_s-1; ret >= 0; ret--)
2941       LOG (GNUNET_ERROR_TYPE_INFO,
2942            "Binding to address `%s'\n",
2943            GNUNET_a2s (addrs[ret], addrlens[ret]));
2944     plugin->nat
2945       = GNUNET_NAT_register (env->cfg,
2946                              GNUNET_YES,
2947                              aport,
2948                              (unsigned int) ret_s,
2949                              (const struct sockaddr **) addrs, addrlens,
2950                              &tcp_nat_port_map_callback,
2951                              &try_connection_reversal,
2952                              plugin);
2953     for (ret = ret_s -1; ret >= 0; ret--)
2954       GNUNET_free (addrs[ret]);
2955     GNUNET_free_non_null (addrs);
2956     GNUNET_free_non_null (addrlens);
2957   }
2958   else
2959   {
2960     plugin->nat = GNUNET_NAT_register (plugin->env->cfg,
2961                                        GNUNET_YES,
2962                                        0,
2963                                        0,
2964                                        NULL,
2965                                        NULL,
2966                                        NULL,
2967                                        &try_connection_reversal,
2968                                        plugin);
2969   }
2970   api = GNUNET_new (struct GNUNET_TRANSPORT_PluginFunctions);
2971   api->cls = plugin;
2972   api->send = &tcp_plugin_send;
2973   api->get_session = &tcp_plugin_get_session;
2974   api->disconnect_session = &tcp_plugin_disconnect_session;
2975   api->query_keepalive_factor = &tcp_plugin_query_keepalive_factor;
2976   api->disconnect_peer = &tcp_plugin_disconnect;
2977   api->address_pretty_printer = &tcp_plugin_address_pretty_printer;
2978   api->check_address = &tcp_plugin_check_address;
2979   api->address_to_string = &tcp_plugin_address_to_string;
2980   api->string_to_address = &tcp_plugin_string_to_address;
2981   api->get_network = &tcp_plugin_get_network;
2982   api->update_session_timeout = &tcp_plugin_update_session_timeout;
2983   api->update_inbound_delay = &tcp_plugin_update_inbound_delay;
2984   api->setup_monitor = &tcp_plugin_setup_monitor;
2985   plugin->service = service;
2986   if (NULL != service)
2987   {
2988     plugin->server = GNUNET_SERVICE_get_server (service);
2989   }
2990   else
2991   {
2992     if (GNUNET_OK !=
2993         GNUNET_CONFIGURATION_get_value_time (env->cfg,
2994                                              "transport-tcp",
2995                                              "TIMEOUT",
2996                                              &idle_timeout))
2997     {
2998       GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
2999                                  "transport-tcp",
3000                                  "TIMEOUT");
3001       goto die;
3002     }
3003     plugin->server
3004       = GNUNET_SERVER_create_with_sockets (NULL,
3005                                            plugin,
3006                                            NULL,
3007                                            idle_timeout,
3008                                            GNUNET_YES);
3009   }
3010   plugin->handlers = GNUNET_malloc (sizeof (my_handlers));
3011   memcpy (plugin->handlers, my_handlers, sizeof(my_handlers));
3012   for (i = 0;i < sizeof(my_handlers) / sizeof(struct GNUNET_SERVER_MessageHandler);i++)
3013     plugin->handlers[i].callback_cls = plugin;
3014
3015   GNUNET_SERVER_add_handlers (plugin->server,
3016                               plugin->handlers);
3017   GNUNET_SERVER_connect_notify (plugin->server,
3018                                 &connect_notify,
3019                                 plugin);
3020   GNUNET_SERVER_disconnect_notify (plugin->server,
3021                                    &disconnect_notify,
3022                                    plugin);
3023   plugin->nat_wait_conns = GNUNET_CONTAINER_multipeermap_create (16,
3024                                                                  GNUNET_YES);
3025   if (0 != bport)
3026     LOG (GNUNET_ERROR_TYPE_INFO,
3027          _("TCP transport listening on port %llu\n"),
3028          bport);
3029   else
3030     LOG (GNUNET_ERROR_TYPE_INFO,
3031          _("TCP transport not listening on any port (client only)\n"));
3032   if ( (aport != bport) &&
3033        (0 != bport) )
3034     LOG (GNUNET_ERROR_TYPE_INFO,
3035          _("TCP transport advertises itself as being on port %llu\n"),
3036          aport);
3037   /* Initially set connections to 0 */
3038   GNUNET_STATISTICS_set (plugin->env->stats,
3039                          gettext_noop ("# TCP sessions active"),
3040                          0,
3041                          GNUNET_NO);
3042   return api;
3043
3044  die:
3045   if (NULL != plugin->nat)
3046     GNUNET_NAT_unregister (plugin->nat);
3047   GNUNET_CONTAINER_multipeermap_destroy (plugin->sessionmap);
3048   if (NULL != service)
3049     GNUNET_SERVICE_stop (service);
3050   GNUNET_free (plugin);
3051   GNUNET_free_non_null (api);
3052   return NULL;
3053 }
3054
3055
3056 /**
3057  * Exit point from the plugin.
3058  *
3059  * @param cls the `struct GNUNET_TRANSPORT_PluginFunctions`
3060  * @return NULL
3061  */
3062 void *
3063 libgnunet_plugin_transport_tcp_done (void *cls)
3064 {
3065   struct GNUNET_TRANSPORT_PluginFunctions *api = cls;
3066   struct Plugin *plugin = api->cls;
3067   struct TCPProbeContext *tcp_probe;
3068   struct PrettyPrinterContext *cur;
3069   struct PrettyPrinterContext *next;
3070
3071   if (NULL == plugin)
3072   {
3073     GNUNET_free(api);
3074     return NULL ;
3075   }
3076   LOG (GNUNET_ERROR_TYPE_DEBUG,
3077        "Shutting down TCP plugin\n");
3078
3079   /* Removing leftover sessions */
3080   GNUNET_CONTAINER_multipeermap_iterate (plugin->sessionmap,
3081                                          &session_disconnect_it,
3082                                          plugin);
3083   /* Removing leftover NAT sessions */
3084   GNUNET_CONTAINER_multipeermap_iterate (plugin->nat_wait_conns,
3085                                          &session_disconnect_it,
3086                                          plugin);
3087
3088   for (cur = plugin->ppc_dll_head; NULL != cur; cur = next)
3089   {
3090     next = cur->next;
3091     GNUNET_CONTAINER_DLL_remove (plugin->ppc_dll_head,
3092                                  plugin->ppc_dll_tail,
3093                                  cur);
3094     GNUNET_RESOLVER_request_cancel (cur->resolver_handle);
3095     cur->asc (cur->asc_cls,
3096               NULL,
3097               GNUNET_OK);
3098     GNUNET_free (cur);
3099   }
3100
3101   if (NULL != plugin->service)
3102     GNUNET_SERVICE_stop (plugin->service);
3103   else
3104     GNUNET_SERVER_destroy (plugin->server);
3105   GNUNET_free (plugin->handlers);
3106   if (NULL != plugin->nat)
3107     GNUNET_NAT_unregister (plugin->nat);
3108   while (NULL != (tcp_probe = plugin->probe_head))
3109   {
3110     GNUNET_CONTAINER_DLL_remove (plugin->probe_head,
3111                                  plugin->probe_tail,
3112                                  tcp_probe);
3113     GNUNET_CONNECTION_destroy (tcp_probe->sock);
3114     GNUNET_free (tcp_probe);
3115   }
3116   GNUNET_CONTAINER_multipeermap_destroy (plugin->nat_wait_conns);
3117   GNUNET_CONTAINER_multipeermap_destroy (plugin->sessionmap);
3118   GNUNET_break (0 == plugin->cur_connections);
3119   GNUNET_free (plugin);
3120   GNUNET_free (api);
3121   return NULL;
3122 }
3123
3124 /* end of plugin_transport_tcp.c */