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