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