remove dead assignments
[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_MultiHashMap *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_MultiHashMap *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_multihashmap_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_multihashmap_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_HashCode * 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_multihashmap_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_multihashmap_remove (plugin->sessionmap, &session->target.hashPubKey, 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_multihashmap_remove (plugin->nat_wait_conns, &session->target.hashPubKey, 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 int session_it (void *cls,
1097                const struct GNUNET_HashCode * key,
1098                void *value)
1099 {
1100   struct FindSessionContext *res = cls;
1101   if (res->s == value)
1102   {
1103     res->res = GNUNET_OK;
1104     return GNUNET_NO;
1105   }
1106   else
1107     return GNUNET_YES;
1108 }
1109
1110 int find_session (struct Plugin *plugin, struct Session *session)
1111 {
1112   struct FindSessionContext session_map_res;
1113   struct FindSessionContext nat_map_res;
1114
1115   session_map_res.s = session;
1116   session_map_res.res = GNUNET_SYSERR;
1117   GNUNET_CONTAINER_multihashmap_iterate (plugin->sessionmap, &session_it, &session_map_res);
1118
1119   nat_map_res.s = session;
1120   nat_map_res.res = GNUNET_SYSERR;
1121   GNUNET_CONTAINER_multihashmap_iterate (plugin->nat_wait_conns, &session_it, &nat_map_res);
1122
1123   if ((session_map_res.res == GNUNET_SYSERR) && (nat_map_res.res == GNUNET_SYSERR))
1124   {
1125     GNUNET_break (0);
1126     return GNUNET_SYSERR;
1127   }
1128   return GNUNET_OK;
1129 }
1130
1131
1132 /**
1133  * Function that can be used by the transport service to transmit
1134  * a message using the plugin.   Note that in the case of a
1135  * peer disconnecting, the continuation MUST be called
1136  * prior to the disconnect notification itself.  This function
1137  * will be called with this peer's HELLO message to initiate
1138  * a fresh connection to another peer.
1139  *
1140  * @param cls closure
1141  * @param session which session must be used
1142  * @param msgbuf the message to transmit
1143  * @param msgbuf_size number of bytes in 'msgbuf'
1144  * @param priority how important is the message (most plugins will
1145  *                 ignore message priority and just FIFO)
1146  * @param to how long to wait at most for the transmission (does not
1147  *                require plugins to discard the message after the timeout,
1148  *                just advisory for the desired delay; most plugins will ignore
1149  *                this as well)
1150  * @param cont continuation to call once the message has
1151  *        been transmitted (or if the transport is ready
1152  *        for the next transmission call; or if the
1153  *        peer disconnected...); can be NULL
1154  * @param cont_cls closure for cont
1155  * @return number of bytes used (on the physical network, with overheads);
1156  *         -1 on hard errors (i.e. address invalid); 0 is a legal value
1157  *         and does NOT mean that the message was not transmitted (DV)
1158  */
1159 static ssize_t
1160 tcp_plugin_send (void *cls,
1161     struct Session *session,
1162     const char *msgbuf, size_t msgbuf_size,
1163     unsigned int priority,
1164     struct GNUNET_TIME_Relative to,
1165     GNUNET_TRANSPORT_TransmitContinuation cont, void *cont_cls)
1166 {
1167   struct Plugin * plugin = cls;
1168   struct PendingMessage *pm;
1169
1170   GNUNET_assert (NULL != plugin);
1171   GNUNET_assert (NULL != session);
1172
1173   if (GNUNET_SYSERR == find_session(plugin, session))
1174   {
1175       LOG (GNUNET_ERROR_TYPE_ERROR,
1176            _("Trying to send with invalid session %p\n"));
1177       return GNUNET_SYSERR;
1178   }
1179
1180   /* create new message entry */
1181   pm = GNUNET_malloc (sizeof (struct PendingMessage) + msgbuf_size);
1182   pm->msg = (const char *) &pm[1];
1183   memcpy (&pm[1], msgbuf, msgbuf_size);
1184   pm->message_size = msgbuf_size;
1185   pm->timeout = GNUNET_TIME_relative_to_absolute (to);
1186   pm->transmit_cont = cont;
1187   pm->transmit_cont_cls = cont_cls;
1188
1189   LOG (GNUNET_ERROR_TYPE_DEBUG, 
1190        "Asked to transmit %u bytes to `%s', added message to list.\n",
1191        msgbuf_size, GNUNET_i2s (&session->target));
1192
1193   if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains_value (plugin->sessionmap, 
1194                                                                   &session->target.hashPubKey, 
1195                                                                   session))
1196   {
1197     GNUNET_assert (session->client != NULL);
1198     reschedule_session_timeout (session);
1199     GNUNET_SERVER_client_set_timeout (session->client,
1200                                       GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1201     GNUNET_STATISTICS_update (plugin->env->stats,
1202                               gettext_noop ("# bytes currently in TCP buffers"),
1203                               msgbuf_size, GNUNET_NO);
1204
1205     /* append pm to pending_messages list */
1206     GNUNET_CONTAINER_DLL_insert_tail (session->pending_messages_head,
1207                                       session->pending_messages_tail, pm);
1208
1209     process_pending_messages (session);
1210     return msgbuf_size;
1211   }
1212   else if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains_value(plugin->nat_wait_conns, &session->target.hashPubKey, session))
1213   {
1214     LOG (GNUNET_ERROR_TYPE_DEBUG, 
1215          "This NAT WAIT session for peer `%s' is not yet ready!\n",
1216          GNUNET_i2s (&session->target));
1217     reschedule_session_timeout (session);
1218     GNUNET_STATISTICS_update (plugin->env->stats,
1219                               gettext_noop ("# bytes currently in TCP buffers"),
1220                               msgbuf_size, GNUNET_NO);
1221
1222     /* append pm to pending_messages list */
1223     GNUNET_CONTAINER_DLL_insert_tail (session->pending_messages_head,
1224                                       session->pending_messages_tail, pm);
1225     return msgbuf_size;
1226   }
1227   else
1228   {
1229     LOG (GNUNET_ERROR_TYPE_ERROR,
1230          "Invalid session %p\n", session);
1231     if (NULL != cont)
1232       cont (cont_cls, &session->target, GNUNET_SYSERR, pm->message_size, 0);
1233     GNUNET_break (0);
1234     GNUNET_free (pm);
1235     return GNUNET_SYSERR; /* session does not exist here */
1236   }
1237 }
1238
1239
1240 struct SessionItCtx
1241 {
1242   void *addr;
1243   size_t addrlen;
1244   struct Session *result;
1245 };
1246
1247
1248 static int 
1249 session_lookup_it (void *cls,
1250                    const struct GNUNET_HashCode *key,
1251                    void *value)
1252 {
1253   struct SessionItCtx * si_ctx = cls;
1254   struct Session * session = value;
1255 #if 0
1256   char * a1 = strdup (tcp_address_to_string(NULL, session->addr, session->addrlen));
1257   char * a2 = strdup (tcp_address_to_string(NULL, si_ctx->addr, si_ctx->addrlen));
1258   LOG (GNUNET_ERROR_TYPE_DEBUG,
1259        "Comparing: %s %u <-> %s %u\n",
1260        a1,
1261        session->addrlen,
1262        a2,
1263        si_ctx->addrlen);
1264   GNUNET_free (a1);
1265   GNUNET_free (a2);
1266 #endif
1267   if (session->addrlen != si_ctx->addrlen)
1268   {
1269     return GNUNET_YES;
1270   }
1271   if (0 != memcmp (session->addr, si_ctx->addr, si_ctx->addrlen))
1272   {
1273     return GNUNET_YES;
1274   }
1275 #if 0
1276   a1 = strdup (tcp_address_to_string(NULL, session->addr, session->addrlen));
1277   a2 = strdup (tcp_address_to_string(NULL, si_ctx->addr, si_ctx->addrlen));
1278   LOG (GNUNET_ERROR_TYPE_DEBUG,
1279        "Comparing: %s %u <-> %s %u , OK!\n",
1280        a1,
1281        session->addrlen,
1282        a2,
1283        si_ctx->addrlen);
1284   GNUNET_free (a1);
1285   GNUNET_free (a2);
1286 #endif
1287   /* Found existing session */
1288   si_ctx->result = session;
1289   return GNUNET_NO;
1290 }
1291
1292
1293 /**
1294  * Task cleaning up a NAT connection attempt after timeout
1295  */
1296 static void
1297 nat_connect_timeout (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1298 {
1299   struct Session *session = cls;
1300
1301   session->nat_connection_timeout = GNUNET_SCHEDULER_NO_TASK;
1302   LOG (GNUNET_ERROR_TYPE_DEBUG,
1303        "NAT WAIT connection to `%4s' at `%s' could not be established, removing session\n",
1304        GNUNET_i2s (&session->target), tcp_address_to_string(NULL, session->addr, session->addrlen));
1305   disconnect_session (session);
1306 }
1307
1308
1309 /**
1310  * Create a new session to transmit data to the target
1311  * This session will used to send data to this peer and the plugin will
1312  * notify us by calling the env->session_end function
1313  *
1314  * @param cls closure
1315  * @param address pointer to the GNUNET_HELLO_Address
1316  * @return the session if the address is valid, NULL otherwise
1317  */
1318 static struct Session *
1319 tcp_plugin_get_session (void *cls,
1320                         const struct GNUNET_HELLO_Address *address)
1321 {
1322   struct Plugin *plugin = cls;
1323   struct Session *session = NULL;
1324   int af;
1325   const void *sb;
1326   size_t sbs;
1327   struct GNUNET_CONNECTION_Handle *sa;
1328   struct sockaddr_in a4;
1329   struct sockaddr_in6 a6;
1330   const struct IPv4TcpAddress *t4;
1331   const struct IPv6TcpAddress *t6;
1332   struct GNUNET_ATS_Information ats;
1333   unsigned int is_natd = GNUNET_NO;
1334   size_t addrlen;
1335
1336   GNUNET_assert (plugin != NULL);
1337   GNUNET_assert (address != NULL);
1338   addrlen = address->address_length;
1339   LOG (GNUNET_ERROR_TYPE_DEBUG, 
1340        "Trying to get session for `%s' address of peer `%s'\n",
1341        tcp_address_to_string(NULL, address->address, address->address_length),
1342        GNUNET_i2s (&address->peer));
1343
1344   /* look for existing session */
1345   if (GNUNET_YES == 
1346       GNUNET_CONTAINER_multihashmap_contains (plugin->sessionmap, 
1347                                               &address->peer.hashPubKey))
1348   {
1349     struct SessionItCtx si_ctx;
1350
1351     si_ctx.addr = (void *) address->address;
1352     si_ctx.addrlen = address->address_length;
1353
1354     si_ctx.result = NULL;
1355
1356     GNUNET_CONTAINER_multihashmap_get_multiple (plugin->sessionmap, 
1357                                                 &address->peer.hashPubKey, 
1358                                                 &session_lookup_it, &si_ctx);
1359     if (si_ctx.result != NULL)
1360     {
1361       session = si_ctx.result;
1362       LOG (GNUNET_ERROR_TYPE_DEBUG,
1363            "Found existing session for `%s' address `%s' session %p\n",
1364            GNUNET_i2s (&address->peer),
1365            tcp_address_to_string(NULL, address->address, address->address_length),
1366            session);
1367       return session;
1368     }
1369     LOG (GNUNET_ERROR_TYPE_DEBUG,
1370          "Existing sessions did not match address `%s' or peer `%s'\n",
1371          tcp_address_to_string(NULL, address->address, address->address_length),
1372          GNUNET_i2s (&address->peer));
1373   }
1374
1375   if (addrlen == sizeof (struct IPv6TcpAddress))
1376   {
1377     GNUNET_assert (NULL != address->address);     /* make static analysis happy */
1378     t6 = address->address;
1379     af = AF_INET6;
1380     memset (&a6, 0, sizeof (a6));
1381 #if HAVE_SOCKADDR_IN_SIN_LEN
1382     a6.sin6_len = sizeof (a6);
1383 #endif
1384     a6.sin6_family = AF_INET6;
1385     a6.sin6_port = t6->t6_port;
1386     if (t6->t6_port == 0)
1387       is_natd = GNUNET_YES;
1388     memcpy (&a6.sin6_addr, &t6->ipv6_addr, sizeof (struct in6_addr));
1389     sb = &a6;
1390     sbs = sizeof (a6);
1391   }
1392   else if (addrlen == sizeof (struct IPv4TcpAddress))
1393   {
1394     GNUNET_assert (NULL != address->address);     /* make static analysis happy */
1395     t4 = address->address;
1396     af = AF_INET;
1397     memset (&a4, 0, sizeof (a4));
1398 #if HAVE_SOCKADDR_IN_SIN_LEN
1399     a4.sin_len = sizeof (a4);
1400 #endif
1401     a4.sin_family = AF_INET;
1402     a4.sin_port = t4->t4_port;
1403     if (t4->t4_port == 0)
1404       is_natd = GNUNET_YES;
1405     a4.sin_addr.s_addr = t4->ipv4_addr;
1406     sb = &a4;
1407     sbs = sizeof (a4);
1408   }
1409   else
1410   {
1411     GNUNET_STATISTICS_update (plugin->env->stats,
1412                               gettext_noop
1413                               ("# requests to create session with invalid address"),
1414                               1, GNUNET_NO);
1415     return NULL;
1416   }
1417
1418   ats = plugin->env->get_address_type (plugin->env->cls, sb ,sbs);
1419
1420   if ((is_natd == GNUNET_YES) && (addrlen == sizeof (struct IPv6TcpAddress)))
1421   {
1422     /* NAT client only works with IPv4 addresses */
1423     return NULL;
1424   }
1425
1426   if (plugin->cur_connections >= plugin->max_connections)
1427   {
1428     /* saturated */
1429     return NULL;
1430   }
1431
1432   if ((is_natd == GNUNET_YES) &&
1433       (GNUNET_YES ==
1434        GNUNET_CONTAINER_multihashmap_contains (plugin->nat_wait_conns,
1435                                                &address->peer.hashPubKey)))
1436   {
1437     /* Only do one NAT punch attempt per peer identity */
1438      return NULL;
1439   }
1440
1441   if ((is_natd == GNUNET_YES) && (NULL != plugin->nat) &&
1442       (GNUNET_NO ==
1443        GNUNET_CONTAINER_multihashmap_contains (plugin->nat_wait_conns,
1444                                                &address->peer.hashPubKey)))
1445   {
1446     LOG (GNUNET_ERROR_TYPE_DEBUG, 
1447          "Found valid IPv4 NAT address (creating session)!\n") ;
1448     session = create_session (plugin, &address->peer, NULL, GNUNET_YES);
1449     session->addrlen = 0;
1450     session->addr = NULL;
1451     session->ats_address_network_type = ats.value;
1452     session->nat_connection_timeout = GNUNET_SCHEDULER_add_delayed (NAT_TIMEOUT,
1453                                                                     &nat_connect_timeout,
1454                                                                     session);
1455     GNUNET_assert (session != NULL);
1456     GNUNET_assert (GNUNET_OK ==
1457                    GNUNET_CONTAINER_multihashmap_put (plugin->nat_wait_conns, 
1458                                                       &session->target.hashPubKey, 
1459                                                       session,
1460                                                       GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1461
1462     LOG (GNUNET_ERROR_TYPE_DEBUG, 
1463          "Created NAT WAIT connection to `%4s' at `%s'\n",
1464          GNUNET_i2s (&session->target), GNUNET_a2s (sb, sbs));
1465
1466     if (GNUNET_OK == GNUNET_NAT_run_client (plugin->nat, &a4))
1467       return session;
1468     else
1469     {
1470       LOG (GNUNET_ERROR_TYPE_DEBUG, 
1471            "Running NAT client for `%4s' at `%s' failed\n",
1472            GNUNET_i2s (&session->target), GNUNET_a2s (sb, sbs));
1473       disconnect_session (session);
1474       return NULL;
1475     }
1476   }
1477
1478   /* create new outbound session */
1479   GNUNET_assert (plugin->cur_connections <= plugin->max_connections);
1480   sa = GNUNET_CONNECTION_create_from_sockaddr (af, sb, sbs);
1481   if (sa == NULL)
1482   {
1483     LOG (GNUNET_ERROR_TYPE_DEBUG, 
1484          "Failed to create connection to `%4s' at `%s'\n",
1485          GNUNET_i2s (&address->peer), GNUNET_a2s (sb, sbs));
1486     return NULL;
1487   }
1488   plugin->cur_connections++;
1489   if (plugin->cur_connections == plugin->max_connections)
1490         GNUNET_SERVER_suspend (plugin->server); /* Maximum number of connections rechead */
1491
1492   LOG (GNUNET_ERROR_TYPE_DEBUG,
1493        "Asked to transmit to `%4s', creating fresh session using address `%s'.\n",
1494        GNUNET_i2s (&address->peer), GNUNET_a2s (sb, sbs));
1495
1496   session = create_session (plugin,
1497                             &address->peer,
1498                             GNUNET_SERVER_connect_socket (plugin->server, sa),
1499                             GNUNET_NO);
1500   session->addr = GNUNET_malloc (addrlen);
1501   memcpy (session->addr, address->address, addrlen);
1502   session->addrlen = addrlen;
1503   session->ats_address_network_type = ats.value;
1504
1505   GNUNET_CONTAINER_multihashmap_put (plugin->sessionmap, 
1506                                      &session->target.hashPubKey, 
1507                                      session, GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
1508   inc_sessions (plugin, session, __LINE__);
1509   LOG (GNUNET_ERROR_TYPE_DEBUG,
1510        "Creating new session for `%s' address `%s' session %p\n",
1511        GNUNET_i2s (&address->peer),
1512        tcp_address_to_string(NULL, address->address, address->address_length),
1513        session);
1514   /* Send TCP Welcome */
1515   process_pending_messages (session);
1516
1517   return session;
1518 }
1519
1520
1521 static int 
1522 session_disconnect_it (void *cls,
1523                        const struct GNUNET_HashCode * key,
1524                        void *value)
1525 {
1526   struct Session *session = value;
1527
1528   GNUNET_STATISTICS_update (session->plugin->env->stats,
1529                             gettext_noop
1530                             ("# transport-service disconnect requests for TCP"),
1531                             1, GNUNET_NO);
1532   disconnect_session (session);
1533   return GNUNET_YES;
1534 }
1535
1536
1537 /**
1538  * Function that can be called to force a disconnect from the
1539  * specified neighbour.  This should also cancel all previously
1540  * scheduled transmissions.  Obviously the transmission may have been
1541  * partially completed already, which is OK.  The plugin is supposed
1542  * to close the connection (if applicable) and no longer call the
1543  * transmit continuation(s).
1544  *
1545  * Finally, plugin MUST NOT call the services's receive function to
1546  * notify the service that the connection to the specified target was
1547  * closed after a getting this call.
1548  *
1549  * @param cls closure
1550  * @param target peer for which the last transmission is
1551  *        to be cancelled
1552  */
1553 static void
1554 tcp_plugin_disconnect (void *cls, const struct GNUNET_PeerIdentity *target)
1555 {
1556   struct Plugin *plugin = cls;
1557
1558   LOG (GNUNET_ERROR_TYPE_DEBUG, 
1559        "Disconnecting peer `%4s'\n", GNUNET_i2s (target));
1560   GNUNET_CONTAINER_multihashmap_get_multiple (plugin->sessionmap, &target->hashPubKey, &session_disconnect_it, plugin);
1561   GNUNET_CONTAINER_multihashmap_get_multiple (plugin->nat_wait_conns, &target->hashPubKey, &session_disconnect_it, plugin);
1562 }
1563
1564
1565 /**
1566  * Running pretty printers: head
1567  */
1568 static struct PrettyPrinterContext *ppc_dll_head;
1569
1570 /**
1571  * Running pretty printers: tail
1572  */
1573 static struct PrettyPrinterContext *ppc_dll_tail;
1574
1575 /**
1576  * Context for address to string conversion.
1577  */
1578 struct PrettyPrinterContext
1579 {
1580         /**
1581          * DLL
1582          */
1583         struct PrettyPrinterContext *next;
1584
1585         /**
1586          * DLL
1587          */
1588         struct PrettyPrinterContext *prev;
1589
1590         /**
1591          * Timeout task
1592          */
1593         GNUNET_SCHEDULER_TaskIdentifier timeout_task;
1594
1595         /**
1596          * Resolver handle
1597          */
1598         struct GNUNET_RESOLVER_RequestHandle *resolver_handle;
1599
1600   /**
1601    * Function to call with the result.
1602    */
1603   GNUNET_TRANSPORT_AddressStringCallback asc;
1604
1605   /**
1606    * Clsoure for 'asc'.
1607    */
1608   void *asc_cls;
1609
1610   /**
1611    * Port to add after the IP address.
1612    */
1613   uint16_t port;
1614
1615   /**
1616    * IPv6 address
1617    */
1618   int ipv6;
1619
1620   /**
1621    * Options
1622    */
1623   uint32_t options;
1624 };
1625
1626
1627
1628 void
1629 ppc_cancel_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1630 {
1631         int count = 0;
1632   struct PrettyPrinterContext *ppc = cls;
1633   struct PrettyPrinterContext *cur;
1634         for (cur = ppc_dll_head; (NULL != cur); cur = cur->next)
1635         {
1636                 if (cur != ppc)
1637                         count++;
1638         }
1639
1640         // GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Cancel request %p, %u pending\n", ppc, count);
1641         ppc->timeout_task = GNUNET_SCHEDULER_NO_TASK;
1642         if (NULL != ppc->resolver_handle)
1643         {
1644                 GNUNET_RESOLVER_request_cancel (ppc->resolver_handle);
1645                 ppc->resolver_handle = NULL;
1646         }
1647
1648         GNUNET_CONTAINER_DLL_remove (ppc_dll_head, ppc_dll_tail, ppc);
1649         GNUNET_free (ppc);
1650 }
1651
1652
1653 /**
1654  * Append our port and forward the result.
1655  *
1656  * @param cls the 'struct PrettyPrinterContext*'
1657  * @param hostname hostname part of the address
1658  */
1659 static void
1660 append_port (void *cls, const char *hostname)
1661 {
1662   struct PrettyPrinterContext *ppc = cls;
1663   struct PrettyPrinterContext *cur;
1664   char *ret;
1665   int count = 0;
1666
1667         for (cur = ppc_dll_head; (NULL != cur); cur = cur->next)
1668         {
1669                 if (cur != ppc)
1670                         count++;
1671         }
1672         //GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Callback request %p == %s, %u pending\n", ppc, hostname, count);
1673   if (hostname == NULL)
1674   {
1675     ppc->asc (ppc->asc_cls, NULL);
1676     GNUNET_CONTAINER_DLL_remove (ppc_dll_head, ppc_dll_tail, ppc);
1677     GNUNET_SCHEDULER_cancel (ppc->timeout_task);
1678     ppc->timeout_task = GNUNET_SCHEDULER_NO_TASK;
1679     ppc->resolver_handle = NULL;
1680     //GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Done request %p, %u pending\n", ppc, count);
1681     GNUNET_free (ppc);
1682     return;
1683   }
1684   for (cur = ppc_dll_head; (NULL != cur); cur = cur->next)
1685   {
1686         if (cur == ppc)
1687                 break;
1688   }
1689   if (NULL == cur)
1690   {
1691         GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Invalid callback for PPC %p \n", ppc);
1692         return;
1693   }
1694
1695   if (GNUNET_YES == ppc->ipv6)
1696     GNUNET_asprintf (&ret, "%s.%u.[%s]:%d", PLUGIN_NAME, ppc->options, hostname, ppc->port);
1697   else
1698     GNUNET_asprintf (&ret, "%s.%u.%s:%d", PLUGIN_NAME, ppc->options, hostname, ppc->port);
1699   ppc->asc (ppc->asc_cls, ret);
1700   GNUNET_free (ret);
1701 }
1702
1703
1704 /**
1705  * Convert the transports address to a nice, human-readable
1706  * format.
1707  *
1708  * @param cls closure
1709  * @param type name of the transport that generated the address
1710  * @param addr one of the addresses of the host, NULL for the last address
1711  *        the specific address format depends on the transport
1712  * @param addrlen length of the address
1713  * @param numeric should (IP) addresses be displayed in numeric form?
1714  * @param timeout after how long should we give up?
1715  * @param asc function to call on each string
1716  * @param asc_cls closure for asc
1717  */
1718 static void
1719 tcp_plugin_address_pretty_printer (void *cls, const char *type,
1720                                    const void *addr, size_t addrlen,
1721                                    int numeric,
1722                                    struct GNUNET_TIME_Relative timeout,
1723                                    GNUNET_TRANSPORT_AddressStringCallback asc,
1724                                    void *asc_cls)
1725 {
1726   struct PrettyPrinterContext *ppc;
1727   const void *sb;
1728   size_t sbs;
1729   struct sockaddr_in a4;
1730   struct sockaddr_in6 a6;
1731   const struct IPv4TcpAddress *t4;
1732   const struct IPv6TcpAddress *t6;
1733   uint16_t port;
1734   uint32_t options;
1735
1736   if (addrlen == sizeof (struct IPv6TcpAddress))
1737   {
1738     t6 = addr;
1739     memset (&a6, 0, sizeof (a6));
1740     a6.sin6_family = AF_INET6;
1741     a6.sin6_port = t6->t6_port;
1742     memcpy (&a6.sin6_addr, &t6->ipv6_addr, sizeof (struct in6_addr));
1743     port = ntohs (t6->t6_port);
1744     options = ntohl (t6->options);
1745     sb = &a6;
1746     sbs = sizeof (a6);
1747   }
1748   else if (addrlen == sizeof (struct IPv4TcpAddress))
1749   {
1750     t4 = addr;
1751     memset (&a4, 0, sizeof (a4));
1752     a4.sin_family = AF_INET;
1753     a4.sin_port = t4->t4_port;
1754     a4.sin_addr.s_addr = t4->ipv4_addr;
1755     port = ntohs (t4->t4_port);
1756     options = ntohl (t4->options);
1757     sb = &a4;
1758     sbs = sizeof (a4);
1759   }
1760   else if (0 == addrlen)
1761   {
1762     asc (asc_cls, TRANSPORT_SESSION_INBOUND_STRING);
1763     asc (asc_cls, NULL);
1764     return;
1765   }
1766   else
1767   {
1768     /* invalid address */
1769     GNUNET_break_op (0);
1770     asc (asc_cls, NULL);
1771     return;
1772   }
1773   ppc = GNUNET_malloc (sizeof (struct PrettyPrinterContext));
1774   if (addrlen == sizeof (struct IPv6TcpAddress))
1775     ppc->ipv6 = GNUNET_YES;
1776   else
1777     ppc->ipv6 = GNUNET_NO;
1778   ppc->asc = asc;
1779   ppc->asc_cls = asc_cls;
1780   ppc->port = port;
1781   ppc->options = options;
1782   ppc->timeout_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply(timeout, 2),
1783                 &ppc_cancel_task, ppc);
1784         ppc->resolver_handle =  GNUNET_RESOLVER_hostname_get (sb, sbs, !numeric,
1785                         timeout, &append_port, ppc);
1786         if (NULL != ppc->resolver_handle)
1787         {
1788                 //GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Adding request %p\n", ppc);
1789                 GNUNET_CONTAINER_DLL_insert (ppc_dll_head, ppc_dll_tail, ppc);
1790         }
1791         else
1792         {
1793                 GNUNET_break (0);
1794                 GNUNET_free (ppc);
1795         }
1796 }
1797
1798
1799 /**
1800  * Check if the given port is plausible (must be either our listen
1801  * port or our advertised port), or any port if we are behind NAT
1802  * and do not have a port open.  If it is neither, we return
1803  * GNUNET_SYSERR.
1804  *
1805  * @param plugin global variables
1806  * @param in_port port number to check
1807  * @return GNUNET_OK if port is either open_port or adv_port
1808  */
1809 static int
1810 check_port (struct Plugin *plugin, uint16_t in_port)
1811 {
1812   if ((in_port == plugin->adv_port) || (in_port == plugin->open_port))
1813     return GNUNET_OK;
1814   return GNUNET_SYSERR;
1815 }
1816
1817
1818 /**
1819  * Function that will be called to check if a binary address for this
1820  * plugin is well-formed and corresponds to an address for THIS peer
1821  * (as per our configuration).  Naturally, if absolutely necessary,
1822  * plugins can be a bit conservative in their answer, but in general
1823  * plugins should make sure that the address does not redirect
1824  * traffic to a 3rd party that might try to man-in-the-middle our
1825  * traffic.
1826  *
1827  * @param cls closure, our 'struct Plugin*'
1828  * @param addr pointer to the address
1829  * @param addrlen length of addr
1830  * @return GNUNET_OK if this is a plausible address for this peer
1831  *         and transport, GNUNET_SYSERR if not
1832  */
1833 static int
1834 tcp_plugin_check_address (void *cls, const void *addr, size_t addrlen)
1835 {
1836   struct Plugin *plugin = cls;
1837   struct IPv4TcpAddress *v4;
1838   struct IPv6TcpAddress *v6;
1839
1840   if ((addrlen != sizeof (struct IPv4TcpAddress)) &&
1841       (addrlen != sizeof (struct IPv6TcpAddress)))
1842   {
1843
1844
1845         return GNUNET_SYSERR;
1846   }
1847
1848   if (addrlen == sizeof (struct IPv4TcpAddress))
1849   {
1850     v4 = (struct IPv4TcpAddress *) addr;
1851     if (0 != memcmp (&v4->options, &myoptions, sizeof (myoptions)))
1852     {
1853         GNUNET_break (0);
1854         return GNUNET_SYSERR;
1855     }
1856     if (GNUNET_OK != check_port (plugin, ntohs (v4->t4_port)))
1857       return GNUNET_SYSERR;
1858     if (GNUNET_OK !=
1859         GNUNET_NAT_test_address (plugin->nat, &v4->ipv4_addr,
1860                                  sizeof (struct in_addr)))
1861       return GNUNET_SYSERR;
1862   }
1863   else
1864   {
1865     v6 = (struct IPv6TcpAddress *) addr;
1866     if (IN6_IS_ADDR_LINKLOCAL (&v6->ipv6_addr))
1867     {
1868       GNUNET_break_op (0);
1869       return GNUNET_SYSERR;
1870     }
1871     if (0 != memcmp (&v6->options, &myoptions, sizeof (myoptions)))
1872     {
1873         GNUNET_break (0);
1874         return GNUNET_SYSERR;
1875     }
1876     if (GNUNET_OK != check_port (plugin, ntohs (v6->t6_port)))
1877       return GNUNET_SYSERR;
1878     if (GNUNET_OK !=
1879         GNUNET_NAT_test_address (plugin->nat, &v6->ipv6_addr,
1880                                  sizeof (struct in6_addr)))
1881       return GNUNET_SYSERR;
1882   }
1883   return GNUNET_OK;
1884 }
1885
1886
1887 /**
1888  * We've received a nat probe from this peer via TCP.  Finish
1889  * creating the client session and resume sending of queued
1890  * messages.
1891  *
1892  * @param cls closure
1893  * @param client identification of the client
1894  * @param message the actual message
1895  */
1896 static void
1897 handle_tcp_nat_probe (void *cls, struct GNUNET_SERVER_Client *client,
1898                       const struct GNUNET_MessageHeader *message)
1899 {
1900   struct Plugin *plugin = cls;
1901   struct Session *session;
1902   const struct TCP_NAT_ProbeMessage *tcp_nat_probe;
1903   size_t alen;
1904   void *vaddr;
1905   struct IPv4TcpAddress *t4;
1906   struct IPv6TcpAddress *t6;
1907   const struct sockaddr_in *s4;
1908   const struct sockaddr_in6 *s6;
1909
1910   LOG (GNUNET_ERROR_TYPE_DEBUG, "Received NAT probe\n");
1911
1912   /* We have received a TCP NAT probe, meaning we (hopefully) initiated
1913    * a connection to this peer by running gnunet-nat-client.  This peer
1914    * received the punch message and now wants us to use the new connection
1915    * as the default for that peer.  Do so and then send a WELCOME message
1916    * so we can really be connected!
1917    */
1918   if (ntohs (message->size) != sizeof (struct TCP_NAT_ProbeMessage))
1919   {
1920     GNUNET_break_op (0);
1921     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1922     return;
1923   }
1924
1925   tcp_nat_probe = (const struct TCP_NAT_ProbeMessage *) message;
1926   if (0 ==
1927       memcmp (&tcp_nat_probe->clientIdentity, plugin->env->my_identity,
1928               sizeof (struct GNUNET_PeerIdentity)))
1929   {
1930     /* refuse connections from ourselves */
1931     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1932     return;
1933   }
1934
1935   session =
1936       GNUNET_CONTAINER_multihashmap_get (plugin->nat_wait_conns,
1937                                          &tcp_nat_probe->
1938                                          clientIdentity.hashPubKey);
1939   if (session == NULL)
1940   {
1941     LOG (GNUNET_ERROR_TYPE_DEBUG, 
1942          "Did NOT find session for NAT probe!\n");
1943     GNUNET_SERVER_receive_done (client, GNUNET_OK);
1944     return;
1945   }
1946   LOG (GNUNET_ERROR_TYPE_DEBUG, 
1947        "Found session for NAT probe!\n");
1948
1949   if (session->nat_connection_timeout != GNUNET_SCHEDULER_NO_TASK)
1950   {
1951     GNUNET_SCHEDULER_cancel (session->nat_connection_timeout);
1952     session->nat_connection_timeout = GNUNET_SCHEDULER_NO_TASK;
1953   }
1954
1955   if (GNUNET_OK != GNUNET_SERVER_client_get_address (client, &vaddr, &alen))
1956   {
1957     GNUNET_break (0);
1958     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1959     disconnect_session (session);
1960     return;
1961   }
1962   GNUNET_assert (GNUNET_CONTAINER_multihashmap_remove
1963                  (plugin->nat_wait_conns,
1964                   &tcp_nat_probe->clientIdentity.hashPubKey,
1965                   session) == GNUNET_YES);
1966   GNUNET_CONTAINER_multihashmap_put (plugin->sessionmap,
1967                                      &session->target.hashPubKey, session, 
1968                                      GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);  
1969   session->last_activity = GNUNET_TIME_absolute_get ();
1970   session->inbound = GNUNET_NO;
1971   LOG (GNUNET_ERROR_TYPE_DEBUG, 
1972        "Found address `%s' for incoming connection\n",
1973        GNUNET_a2s (vaddr, alen));
1974   switch (((const struct sockaddr *) vaddr)->sa_family)
1975   {
1976   case AF_INET:
1977     s4 = vaddr;
1978     t4 = GNUNET_malloc (sizeof (struct IPv4TcpAddress));
1979     t4->options = 0;
1980     t4->t4_port = s4->sin_port;
1981     t4->ipv4_addr = s4->sin_addr.s_addr;
1982     session->addr = t4;
1983     session->addrlen = sizeof (struct IPv4TcpAddress);
1984     break;
1985   case AF_INET6:
1986     s6 = vaddr;
1987     t6 = GNUNET_malloc (sizeof (struct IPv6TcpAddress));
1988     t6->options = 0;
1989     t6->t6_port = s6->sin6_port;
1990     memcpy (&t6->ipv6_addr, &s6->sin6_addr, sizeof (struct in6_addr));
1991     session->addr = t6;
1992     session->addrlen = sizeof (struct IPv6TcpAddress);
1993     break;
1994   default:
1995     GNUNET_break_op (0);
1996     LOG (GNUNET_ERROR_TYPE_DEBUG, 
1997          "Bad address for incoming connection!\n");
1998     GNUNET_free (vaddr);
1999     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2000     disconnect_session (session);
2001     return;
2002   }
2003   GNUNET_free (vaddr);
2004   GNUNET_break (NULL == session->client);
2005   GNUNET_SERVER_client_keep (client);
2006   session->client = client;
2007   inc_sessions (plugin, session, __LINE__);
2008   GNUNET_STATISTICS_update (plugin->env->stats,
2009                             gettext_noop ("# TCP sessions active"), 1,
2010                             GNUNET_NO);
2011   process_pending_messages (session);
2012   GNUNET_SERVER_receive_done (client, GNUNET_OK);
2013 }
2014
2015
2016 /**
2017  * We've received a welcome from this peer via TCP.  Possibly create a
2018  * fresh client record and send back our welcome.
2019  *
2020  * @param cls closure
2021  * @param client identification of the client
2022  * @param message the actual message
2023  */
2024 static void
2025 handle_tcp_welcome (void *cls, struct GNUNET_SERVER_Client *client,
2026                     const struct GNUNET_MessageHeader *message)
2027 {
2028   struct Plugin *plugin = cls;
2029   const struct WelcomeMessage *wm = (const struct WelcomeMessage *) message;
2030   struct Session *session;
2031   size_t alen;
2032   void *vaddr;
2033   struct IPv4TcpAddress *t4;
2034   struct IPv6TcpAddress *t6;
2035   const struct sockaddr_in *s4;
2036   const struct sockaddr_in6 *s6;
2037   struct GNUNET_ATS_Information ats;
2038
2039   if (0 ==
2040       memcmp (&wm->clientIdentity, plugin->env->my_identity,
2041               sizeof (struct GNUNET_PeerIdentity)))
2042   {
2043     /* refuse connections from ourselves */
2044     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2045     if (GNUNET_OK == GNUNET_SERVER_client_get_address (client, &vaddr, &alen))
2046     {
2047         LOG (GNUNET_ERROR_TYPE_WARNING,
2048          "Received %s message from my own identity `%4s' on address `%s'\n",
2049          "WELCOME", GNUNET_i2s (&wm->clientIdentity), GNUNET_a2s (vaddr, alen));
2050         GNUNET_free (vaddr);
2051     }
2052     GNUNET_break_op (0);
2053     return;
2054   }
2055   LOG (GNUNET_ERROR_TYPE_DEBUG,
2056        "Received %s message from `%4s' %p\n", "WELCOME",
2057        GNUNET_i2s (&wm->clientIdentity), client);
2058   GNUNET_STATISTICS_update (plugin->env->stats,
2059                             gettext_noop ("# TCP WELCOME messages received"), 1,
2060                             GNUNET_NO);
2061   session = lookup_session_by_client (plugin, client);
2062   if (session != NULL)
2063   {
2064     if (GNUNET_OK == GNUNET_SERVER_client_get_address (client, &vaddr, &alen))
2065     {
2066       LOG (GNUNET_ERROR_TYPE_DEBUG,
2067            "Found existing session %p for peer `%s'\n",
2068            session,
2069            GNUNET_a2s (vaddr, alen));
2070       GNUNET_free (vaddr);
2071     }
2072   }
2073   else
2074   {
2075     GNUNET_SERVER_client_keep (client);
2076     if (plugin->service != NULL) /* Otherwise value is incremented in tcp_access_check */
2077         plugin->cur_connections++;
2078     if (plugin->cur_connections == plugin->max_connections)
2079         GNUNET_SERVER_suspend (plugin->server); /* Maximum number of connections rechead */
2080
2081     session = create_session (plugin, &wm->clientIdentity, client, GNUNET_NO);
2082     session->inbound = GNUNET_YES;
2083     if (GNUNET_OK == GNUNET_SERVER_client_get_address (client, &vaddr, &alen))
2084     {
2085       if (alen == sizeof (struct sockaddr_in))
2086       {
2087         s4 = vaddr;
2088         t4 = GNUNET_malloc (sizeof (struct IPv4TcpAddress));
2089         t4->options = htonl (0);
2090         t4->t4_port = s4->sin_port;
2091         t4->ipv4_addr = s4->sin_addr.s_addr;
2092         session->addr = t4;
2093         session->addrlen = sizeof (struct IPv4TcpAddress);
2094       }
2095       else if (alen == sizeof (struct sockaddr_in6))
2096       {
2097         s6 = vaddr;
2098         t6 = GNUNET_malloc (sizeof (struct IPv6TcpAddress));
2099         t6->options = htonl (0);
2100         t6->t6_port = s6->sin6_port;
2101         memcpy (&t6->ipv6_addr, &s6->sin6_addr, sizeof (struct in6_addr));
2102         session->addr = t6;
2103         session->addrlen = sizeof (struct IPv6TcpAddress);
2104       }
2105
2106       ats = plugin->env->get_address_type (plugin->env->cls, vaddr ,alen);
2107       session->ats_address_network_type = ats.value;
2108       LOG (GNUNET_ERROR_TYPE_DEBUG,
2109      "Creating new session %p for peer `%s'\n",
2110      session,
2111      GNUNET_a2s (vaddr, alen));
2112       GNUNET_free (vaddr);
2113       GNUNET_CONTAINER_multihashmap_put (plugin->sessionmap,
2114                                        &session->target.hashPubKey,
2115                                        session,
2116                                        GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
2117       inc_sessions (plugin, session, __LINE__);
2118     }
2119     else
2120     {
2121       LOG (GNUNET_ERROR_TYPE_DEBUG, 
2122            "Did not obtain TCP socket address for incoming connection\n");
2123       GNUNET_break (0);
2124     }
2125   }
2126
2127   if (session->expecting_welcome != GNUNET_YES)
2128   {
2129     GNUNET_break_op (0);
2130     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2131     GNUNET_break (0);
2132     return;
2133   }
2134   session->last_activity = GNUNET_TIME_absolute_get ();
2135   session->expecting_welcome = GNUNET_NO;
2136
2137   /* Notify transport and ATS about new session */
2138   if (GNUNET_YES == session->inbound)
2139   {
2140         plugin->env->session_start (NULL, &wm->clientIdentity, PLUGIN_NAME,
2141                 (GNUNET_YES == session->inbound) ? NULL : session->addr,
2142                   (GNUNET_YES == session->inbound) ? 0 : session->addrlen,
2143                   session, &ats, 1);
2144   }
2145
2146   process_pending_messages (session);
2147
2148   GNUNET_SERVER_client_set_timeout (client,
2149                                     GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2150   GNUNET_SERVER_receive_done (client, GNUNET_OK);
2151 }
2152
2153
2154 /**
2155  * Task to signal the server that we can continue
2156  * receiving from the TCP client now.
2157  *
2158  * @param cls the 'struct Session*'
2159  * @param tc task context (unused)
2160  */
2161 static void
2162 delayed_done (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
2163 {
2164   struct Session *session = cls;
2165
2166   session->receive_delay_task = GNUNET_SCHEDULER_NO_TASK;
2167   reschedule_session_timeout (session);
2168
2169   GNUNET_SERVER_receive_done (session->client, GNUNET_OK);
2170 }
2171
2172
2173 /**
2174  * We've received data for this peer via TCP.  Unbox,
2175  * compute latency and forward.
2176  *
2177  * @param cls closure
2178  * @param client identification of the client
2179  * @param message the actual message
2180  */
2181 static void
2182 handle_tcp_data (void *cls, struct GNUNET_SERVER_Client *client,
2183                  const struct GNUNET_MessageHeader *message)
2184 {
2185   struct Plugin *plugin = cls;
2186   struct Session *session;
2187   struct GNUNET_TIME_Relative delay;
2188   uint16_t type;
2189
2190   type = ntohs (message->type);
2191   if ((GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_WELCOME == type) ||
2192       (GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_NAT_PROBE == type))
2193   {
2194     /* We don't want to propagate WELCOME and NAT Probe messages up! */
2195     GNUNET_SERVER_receive_done (client, GNUNET_OK);
2196     return;
2197   }
2198   session = lookup_session_by_client (plugin, client);
2199   if (NULL == session)
2200   {
2201     /* No inbound session found */
2202     void *vaddr;
2203     size_t alen;
2204     
2205     GNUNET_SERVER_client_get_address (client, &vaddr, &alen);
2206     LOG (GNUNET_ERROR_TYPE_ERROR, 
2207          "Received unexpected %u bytes of type %u from `%s'\n",
2208          (unsigned int) ntohs (message->size),
2209          (unsigned int) ntohs (message->type),
2210          GNUNET_a2s(vaddr, alen));
2211     GNUNET_break_op (0);
2212     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2213     GNUNET_free_non_null(vaddr);
2214     return;
2215   }
2216   else if (GNUNET_YES == session->expecting_welcome)
2217   {
2218     /* Session is expecting WELCOME message */
2219     void *vaddr;
2220     size_t alen;
2221
2222     GNUNET_SERVER_client_get_address (client, &vaddr, &alen);
2223     LOG (GNUNET_ERROR_TYPE_ERROR, 
2224          "Received unexpected %u bytes of type %u from `%s'\n",
2225          (unsigned int) ntohs (message->size),
2226          (unsigned int) ntohs (message->type),
2227          GNUNET_a2s(vaddr, alen));
2228     GNUNET_break_op (0);
2229     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2230     GNUNET_free_non_null(vaddr);
2231     return;
2232   }
2233
2234   session->last_activity = GNUNET_TIME_absolute_get ();
2235   LOG (GNUNET_ERROR_TYPE_DEBUG, 
2236                    "Passing %u bytes of type %u from `%4s' to transport service.\n",
2237                    (unsigned int) ntohs (message->size),
2238                    (unsigned int) ntohs (message->type),
2239                    GNUNET_i2s (&session->target));
2240
2241   GNUNET_STATISTICS_update (plugin->env->stats,
2242                             gettext_noop ("# bytes received via TCP"),
2243                             ntohs (message->size), GNUNET_NO);
2244   struct GNUNET_ATS_Information distance;
2245
2246   distance.type = htonl (GNUNET_ATS_NETWORK_TYPE);
2247   distance.value = session->ats_address_network_type;
2248   GNUNET_break (ntohl(session->ats_address_network_type) != GNUNET_ATS_NET_UNSPECIFIED);
2249
2250   GNUNET_assert (GNUNET_CONTAINER_multihashmap_contains_value (plugin->sessionmap,
2251       &session->target.hashPubKey,
2252       session));
2253
2254   delay = plugin->env->receive (plugin->env->cls,
2255                                 &session->target,
2256                                 message,
2257                                 session,
2258                                 (GNUNET_YES == session->inbound) ? NULL : session->addr,
2259                                 (GNUNET_YES == session->inbound) ? 0 : session->addrlen);
2260   plugin->env->update_address_metrics (plugin->env->cls,
2261                 &session->target,
2262                 (GNUNET_YES == session->inbound) ? NULL : session->addr,
2263                   (GNUNET_YES == session->inbound) ? 0 : session->addrlen,
2264                   session, &distance, 1);
2265
2266   reschedule_session_timeout (session);
2267
2268   if (0 == delay.rel_value_us)
2269   {
2270     GNUNET_SERVER_receive_done (client, GNUNET_OK);
2271   }
2272   else
2273   {
2274     LOG (GNUNET_ERROR_TYPE_DEBUG, 
2275          "Throttling receiving from `%s' for %s\n",
2276          GNUNET_i2s (&session->target),
2277          GNUNET_STRINGS_relative_time_to_string (delay, GNUNET_YES));
2278     GNUNET_SERVER_disable_receive_done_warning (client);
2279     session->receive_delay_task =
2280         GNUNET_SCHEDULER_add_delayed (delay, &delayed_done, session);
2281   }
2282 }
2283
2284
2285 /**
2286  * Functions with this signature are called whenever a peer
2287  * is disconnected on the network level.
2288  *
2289  * @param cls closure
2290  * @param client identification of the client
2291  */
2292 static void
2293 disconnect_notify (void *cls, struct GNUNET_SERVER_Client *client)
2294 {
2295   struct Plugin *plugin = cls;
2296   struct Session *session;
2297
2298   if (client == NULL)
2299     return;
2300   session = lookup_session_by_client (plugin, client);
2301   if (session == NULL)
2302     return;                     /* unknown, nothing to do */
2303   LOG (GNUNET_ERROR_TYPE_DEBUG,
2304        "Destroying session of `%4s' with %s due to network-level disconnect.\n",
2305        GNUNET_i2s (&session->target),
2306        (session->addr !=
2307         NULL) ? tcp_address_to_string (session->plugin,
2308                                        session->addr,
2309                                        session->addrlen) :
2310        "*");
2311
2312   if (plugin->cur_connections == plugin->max_connections)
2313         GNUNET_SERVER_resume (plugin->server); /* Resume server  */
2314
2315   if (plugin->cur_connections < 1)
2316         GNUNET_break (0);
2317   else
2318         plugin->cur_connections--;
2319
2320   GNUNET_STATISTICS_update (session->plugin->env->stats,
2321                             gettext_noop
2322                             ("# network-level TCP disconnect events"), 1,
2323                             GNUNET_NO);
2324   disconnect_session (session);
2325 }
2326
2327
2328 /**
2329  * We can now send a probe message, copy into buffer to really send.
2330  *
2331  * @param cls closure, a struct TCPProbeContext
2332  * @param size max size to copy
2333  * @param buf buffer to copy message to
2334  * @return number of bytes copied into buf
2335  */
2336 static size_t
2337 notify_send_probe (void *cls, size_t size, void *buf)
2338 {
2339   struct TCPProbeContext *tcp_probe_ctx = cls;
2340   struct Plugin *plugin = tcp_probe_ctx->plugin;
2341   size_t ret;
2342
2343   tcp_probe_ctx->transmit_handle = NULL;
2344   GNUNET_CONTAINER_DLL_remove (plugin->probe_head, plugin->probe_tail,
2345                                tcp_probe_ctx);
2346   if (buf == NULL)
2347   {
2348     GNUNET_CONNECTION_destroy (tcp_probe_ctx->sock);
2349     GNUNET_free (tcp_probe_ctx);
2350     return 0;
2351   }
2352   GNUNET_assert (size >= sizeof (tcp_probe_ctx->message));
2353   memcpy (buf, &tcp_probe_ctx->message, sizeof (tcp_probe_ctx->message));
2354   GNUNET_SERVER_connect_socket (tcp_probe_ctx->plugin->server,
2355                                 tcp_probe_ctx->sock);
2356   ret = sizeof (tcp_probe_ctx->message);
2357   GNUNET_free (tcp_probe_ctx);
2358   return ret;
2359 }
2360
2361
2362 /**
2363  * Function called by the NAT subsystem suggesting another peer wants
2364  * to connect to us via connection reversal.  Try to connect back to the
2365  * given IP.
2366  *
2367  * @param cls closure
2368  * @param addr address to try
2369  * @param addrlen number of bytes in addr
2370  */
2371 static void
2372 try_connection_reversal (void *cls, const struct sockaddr *addr,
2373                          socklen_t addrlen)
2374 {
2375   struct Plugin *plugin = cls;
2376   struct GNUNET_CONNECTION_Handle *sock;
2377   struct TCPProbeContext *tcp_probe_ctx;
2378
2379   /**
2380    * We have received an ICMP response, ostensibly from a peer
2381    * that wants to connect to us! Send a message to establish a connection.
2382    */
2383   sock = GNUNET_CONNECTION_create_from_sockaddr (AF_INET, addr, addrlen);
2384   if (sock == NULL)
2385   {
2386     /* failed for some odd reason (out of sockets?); ignore attempt */
2387     return;
2388   }
2389
2390   /* FIXME: do we need to track these probe context objects so that
2391    * we can clean them up on plugin unload? */
2392   tcp_probe_ctx = GNUNET_malloc (sizeof (struct TCPProbeContext));
2393   tcp_probe_ctx->message.header.size =
2394       htons (sizeof (struct TCP_NAT_ProbeMessage));
2395   tcp_probe_ctx->message.header.type =
2396       htons (GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_NAT_PROBE);
2397   memcpy (&tcp_probe_ctx->message.clientIdentity, plugin->env->my_identity,
2398           sizeof (struct GNUNET_PeerIdentity));
2399   tcp_probe_ctx->plugin = plugin;
2400   tcp_probe_ctx->sock = sock;
2401   GNUNET_CONTAINER_DLL_insert (plugin->probe_head, plugin->probe_tail,
2402                                tcp_probe_ctx);
2403   tcp_probe_ctx->transmit_handle =
2404       GNUNET_CONNECTION_notify_transmit_ready (sock,
2405                                                ntohs (tcp_probe_ctx->
2406                                                       message.header.size),
2407                                                GNUNET_TIME_UNIT_FOREVER_REL,
2408                                                &notify_send_probe,
2409                                                tcp_probe_ctx);
2410
2411 }
2412
2413
2414 /**
2415  * Session was idle, so disconnect it
2416  */
2417 static void
2418 session_timeout (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
2419 {
2420   GNUNET_assert (NULL != cls);
2421   struct Session *s = cls;
2422
2423   s->timeout_task = GNUNET_SCHEDULER_NO_TASK;
2424   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2425               "Session %p was idle for %s, disconnecting\n",
2426               s,
2427               GNUNET_STRINGS_relative_time_to_string (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
2428                                                       GNUNET_YES));
2429   /* call session destroy function */
2430   disconnect_session(s);
2431 }
2432
2433
2434 /**
2435  * Start session timeout
2436  */
2437 static void
2438 start_session_timeout (struct Session *s)
2439 {
2440   GNUNET_assert (NULL != s);
2441   GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == s->timeout_task);
2442   s->timeout_task =  GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
2443                                                    &session_timeout,
2444                                                    s);
2445   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2446               "Timeout for session %p set to %s\n",
2447               s,  
2448               GNUNET_STRINGS_relative_time_to_string (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
2449                                                       GNUNET_YES));
2450 }
2451
2452
2453 /**
2454  * Increment session timeout due to activity
2455  */
2456 static void
2457 reschedule_session_timeout (struct Session *s)
2458 {
2459   GNUNET_assert (NULL != s);
2460   GNUNET_assert (GNUNET_SCHEDULER_NO_TASK != s->timeout_task);
2461
2462   GNUNET_SCHEDULER_cancel (s->timeout_task);
2463   s->timeout_task =  GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
2464                                                    &session_timeout,
2465                                                    s);
2466   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2467               "Timeout rescheduled for session %p set to %s\n",
2468               s, 
2469               GNUNET_STRINGS_relative_time_to_string (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
2470                                                       GNUNET_YES));
2471 }
2472
2473
2474 /**
2475  * Cancel timeout
2476  */
2477 static void
2478 stop_session_timeout (struct Session *s)
2479 {
2480   GNUNET_assert (NULL != s);
2481
2482   if (GNUNET_SCHEDULER_NO_TASK != s->timeout_task)
2483   {
2484     GNUNET_SCHEDULER_cancel (s->timeout_task);
2485     s->timeout_task = GNUNET_SCHEDULER_NO_TASK;
2486     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2487                 "Timeout stopped for session %p canceled\n",
2488                 s);
2489   }
2490 }
2491
2492 /**
2493  * Function obtain the network type for a session
2494  *
2495  * @param cls closure ('struct Plugin*')
2496  * @param session the session
2497  * @return the network type in HBO or GNUNET_SYSERR
2498  */
2499 static enum GNUNET_ATS_Network_Type
2500 tcp_get_network (void *cls,
2501                  struct Session *session)
2502 {
2503   GNUNET_assert (NULL != session);
2504   return ntohl (session->ats_address_network_type);
2505 }
2506
2507
2508 /**
2509  * Entry point for the plugin.
2510  *
2511  * @param cls closure, the 'struct GNUNET_TRANSPORT_PluginEnvironment*'
2512  * @return the 'struct GNUNET_TRANSPORT_PluginFunctions*' or NULL on error
2513  */
2514 void *
2515 libgnunet_plugin_transport_tcp_init (void *cls)
2516 {
2517   static const struct GNUNET_SERVER_MessageHandler my_handlers[] = {
2518     {&handle_tcp_welcome, NULL, GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_WELCOME,
2519      sizeof (struct WelcomeMessage)},
2520     {&handle_tcp_nat_probe, NULL, GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_NAT_PROBE,
2521      sizeof (struct TCP_NAT_ProbeMessage)},
2522     {&handle_tcp_data, NULL, GNUNET_MESSAGE_TYPE_ALL, 0},
2523     {NULL, NULL, 0, 0}
2524   };
2525   struct GNUNET_TRANSPORT_PluginEnvironment *env = cls;
2526   struct GNUNET_TRANSPORT_PluginFunctions *api;
2527   struct Plugin *plugin;
2528   struct GNUNET_SERVICE_Context *service;
2529   unsigned long long aport;
2530   unsigned long long bport;
2531   unsigned long long max_connections;
2532   unsigned int i;
2533   struct GNUNET_TIME_Relative idle_timeout;
2534   int ret;
2535   int ret_s;
2536   struct sockaddr **addrs;
2537   socklen_t *addrlens;
2538
2539
2540   if (NULL == env->receive)
2541   {
2542     /* run in 'stub' mode (i.e. as part of gnunet-peerinfo), don't fully
2543        initialze the plugin or the API */
2544     api = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_PluginFunctions));
2545     api->cls = NULL;
2546     api->address_pretty_printer = &tcp_plugin_address_pretty_printer;
2547     api->address_to_string = &tcp_address_to_string;
2548     api->string_to_address = &tcp_string_to_address;
2549     return api;
2550   }
2551
2552   GNUNET_assert (NULL != env->cfg);
2553   if (GNUNET_OK !=
2554       GNUNET_CONFIGURATION_get_value_number (env->cfg, "transport-tcp",
2555                                              "MAX_CONNECTIONS",
2556                                              &max_connections))
2557     max_connections = 128;
2558
2559   aport = 0;
2560   if ((GNUNET_OK !=
2561        GNUNET_CONFIGURATION_get_value_number (env->cfg, "transport-tcp", "PORT",
2562                                               &bport)) || (bport > 65535) ||
2563       ((GNUNET_OK ==
2564         GNUNET_CONFIGURATION_get_value_number (env->cfg, "transport-tcp",
2565                                                "ADVERTISED-PORT", &aport)) &&
2566        (aport > 65535)))
2567   {
2568     LOG (GNUNET_ERROR_TYPE_ERROR, 
2569          _
2570          ("Require valid port number for service `%s' in configuration!\n"),
2571          "transport-tcp");
2572     return NULL;
2573   }
2574   if (aport == 0)
2575     aport = bport;
2576   if (bport == 0)
2577     aport = 0;
2578   if (bport != 0)
2579   {
2580     service = GNUNET_SERVICE_start ("transport-tcp", env->cfg, GNUNET_SERVICE_OPTION_NONE);
2581     if (service == NULL)
2582     {
2583       LOG (GNUNET_ERROR_TYPE_WARNING,
2584            _("Failed to start service.\n"));
2585       return NULL;
2586     }
2587   }
2588   else
2589     service = NULL;
2590
2591   /* Initialize my flags */
2592   myoptions = 0;
2593
2594   plugin = GNUNET_malloc (sizeof (struct Plugin));
2595   plugin->sessionmap = GNUNET_CONTAINER_multihashmap_create (max_connections, GNUNET_YES);
2596   plugin->max_connections = max_connections;
2597   plugin->cur_connections = 0;
2598   plugin->open_port = bport;
2599   plugin->adv_port = aport;
2600   plugin->env = env;
2601   plugin->lsock = NULL;
2602   if ((service != NULL) &&
2603       (GNUNET_SYSERR !=
2604        (ret_s =
2605         GNUNET_SERVICE_get_server_addresses ("transport-tcp", env->cfg, &addrs,
2606                                              &addrlens))))
2607   {
2608     for (ret = ret_s-1; ret >= 0; ret--)
2609       LOG (GNUNET_ERROR_TYPE_INFO,
2610            "Binding to address `%s'\n", 
2611            GNUNET_a2s (addrs[ret], addrlens[ret]));
2612     plugin->nat =
2613         GNUNET_NAT_register (env->cfg, GNUNET_YES, aport, (unsigned int) ret_s,
2614                              (const struct sockaddr **) addrs, addrlens,
2615                              &tcp_nat_port_map_callback,
2616                              &try_connection_reversal, plugin);
2617     for (ret = ret_s -1; ret >= 0; ret--)
2618     {
2619       GNUNET_assert (addrs[ret] != NULL);
2620       GNUNET_free (addrs[ret]);
2621     }
2622     GNUNET_free_non_null (addrs);
2623     GNUNET_free_non_null (addrlens);
2624   }
2625   else
2626   {
2627     plugin->nat = GNUNET_NAT_register (plugin->env->cfg,
2628                                        GNUNET_YES, 0, 0, NULL, NULL, NULL,
2629                                        &try_connection_reversal, plugin);
2630   }
2631   api = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_PluginFunctions));
2632   api->cls = plugin;
2633   api->send = &tcp_plugin_send;
2634   api->get_session = &tcp_plugin_get_session;
2635
2636   api->disconnect = &tcp_plugin_disconnect;
2637   api->address_pretty_printer = &tcp_plugin_address_pretty_printer;
2638   api->check_address = &tcp_plugin_check_address;
2639   api->address_to_string = &tcp_address_to_string;
2640   api->string_to_address = &tcp_string_to_address;
2641   api->get_network = &tcp_get_network;
2642   plugin->service = service;
2643   if (service != NULL)
2644   {
2645     plugin->server = GNUNET_SERVICE_get_server (service);
2646   }
2647   else
2648   {
2649     if (GNUNET_OK !=
2650         GNUNET_CONFIGURATION_get_value_time (env->cfg, "transport-tcp",
2651                                              "TIMEOUT", &idle_timeout))
2652     {
2653       GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
2654                                  "transport-tcp", "TIMEOUT");
2655       if (plugin->nat != NULL)
2656         GNUNET_NAT_unregister (plugin->nat);
2657       GNUNET_free (plugin);
2658       GNUNET_free (api);
2659       return NULL;
2660     }
2661     plugin->server =
2662         GNUNET_SERVER_create_with_sockets (&plugin_tcp_access_check, plugin,
2663                                            NULL, idle_timeout, GNUNET_YES);
2664   }
2665   plugin->handlers = GNUNET_malloc (sizeof (my_handlers));
2666   memcpy (plugin->handlers, my_handlers, sizeof (my_handlers));
2667   for (i = 0;
2668        i < sizeof (my_handlers) / sizeof (struct GNUNET_SERVER_MessageHandler);
2669        i++)
2670     plugin->handlers[i].callback_cls = plugin;
2671
2672   GNUNET_SERVER_add_handlers (plugin->server, plugin->handlers);
2673   GNUNET_SERVER_disconnect_notify (plugin->server, &disconnect_notify, plugin);
2674   plugin->nat_wait_conns = GNUNET_CONTAINER_multihashmap_create (16, GNUNET_YES);
2675   if (bport != 0)
2676     LOG (GNUNET_ERROR_TYPE_INFO, 
2677          _("TCP transport listening on port %llu\n"), bport);
2678   else
2679     LOG (GNUNET_ERROR_TYPE_INFO, 
2680          _
2681          ("TCP transport not listening on any port (client only)\n"));
2682   if (aport != bport)
2683     LOG (GNUNET_ERROR_TYPE_INFO, 
2684                      _
2685                      ("TCP transport advertises itself as being on port %llu\n"),
2686                      aport);
2687   /* Initially set connections to 0 */
2688   GNUNET_assert (NULL != plugin->env->stats);
2689   GNUNET_STATISTICS_set (plugin->env->stats,
2690                         gettext_noop ("# TCP sessions active"), 0,
2691                         GNUNET_NO);
2692   return api;
2693 }
2694
2695
2696 /**
2697  * Exit point from the plugin.
2698  */
2699 void *
2700 libgnunet_plugin_transport_tcp_done (void *cls)
2701 {
2702   struct GNUNET_TRANSPORT_PluginFunctions *api = cls;
2703   struct Plugin *plugin = api->cls;
2704   struct TCPProbeContext *tcp_probe;
2705   struct PrettyPrinterContext *cur;
2706   struct PrettyPrinterContext *next;
2707
2708   if (NULL == plugin)
2709   {
2710     GNUNET_free (api);
2711     return NULL;
2712   }
2713   LOG (GNUNET_ERROR_TYPE_DEBUG, "Shutting down TCP plugin\n");
2714
2715   /* Removing leftover sessions */
2716   GNUNET_CONTAINER_multihashmap_iterate(plugin->sessionmap, &session_disconnect_it, NULL);
2717   /* Removing leftover NAT sessions */
2718   GNUNET_CONTAINER_multihashmap_iterate(plugin->nat_wait_conns, &session_disconnect_it, NULL);
2719
2720   next = ppc_dll_head;
2721   for (cur = next; NULL != cur; cur = next)
2722   {
2723         next = cur->next;
2724         GNUNET_CONTAINER_DLL_remove (ppc_dll_head, ppc_dll_tail, cur);
2725         if (NULL != cur->resolver_handle)
2726                 GNUNET_RESOLVER_request_cancel (cur->resolver_handle);
2727         GNUNET_SCHEDULER_cancel (cur->timeout_task);
2728         GNUNET_free (cur);
2729         GNUNET_break (0);
2730   }
2731
2732   if (plugin->service != NULL)
2733     GNUNET_SERVICE_stop (plugin->service);
2734   else
2735     GNUNET_SERVER_destroy (plugin->server);
2736   GNUNET_free (plugin->handlers);
2737   if (plugin->nat != NULL)
2738     GNUNET_NAT_unregister (plugin->nat);
2739   while (NULL != (tcp_probe = plugin->probe_head))
2740   {
2741     GNUNET_CONTAINER_DLL_remove (plugin->probe_head, plugin->probe_tail,
2742                                  tcp_probe);
2743     GNUNET_CONNECTION_destroy (tcp_probe->sock);
2744     GNUNET_free (tcp_probe);
2745   }
2746   GNUNET_CONTAINER_multihashmap_destroy (plugin->nat_wait_conns);
2747   GNUNET_CONTAINER_multihashmap_destroy (plugin->sessionmap);
2748   GNUNET_free (plugin);
2749   GNUNET_free (api);
2750   return NULL;
2751 }
2752
2753 /* end of plugin_transport_tcp.c */