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