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