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