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