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