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