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