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