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