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