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