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