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