(no commit message)
[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  * How long until we give up on transmitting the welcome message?
47  */
48 #define HOSTNAME_RESOLVE_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
49
50
51 /**
52  * Initial handshake message for a session.
53  */
54 struct WelcomeMessage
55 {
56   /**
57    * Type is GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_WELCOME.
58    */
59   struct GNUNET_MessageHeader header;
60
61   /**
62    * Identity of the node connecting (TCP client)
63    */
64   struct GNUNET_PeerIdentity clientIdentity;
65
66 };
67
68
69 /**
70  * Basically a WELCOME message, but with the purpose
71  * of giving the waiting peer a client handle to use
72  */
73 struct TCP_NAT_ProbeMessage
74 {
75   /**
76    * Type is GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_NAT_PROBE.
77    */
78   struct GNUNET_MessageHeader header;
79
80   /**
81    * Identity of the sender of the message.
82    */
83   struct GNUNET_PeerIdentity clientIdentity;
84
85 };
86
87
88 /**
89  * Context for sending a NAT probe via TCP.
90  */
91 struct TCPProbeContext
92 {
93
94   /**
95    * Active probes are kept in a DLL.
96    */
97   struct TCPProbeContext *next;
98
99   /**
100    * Active probes are kept in a DLL.
101    */
102   struct TCPProbeContext *prev;
103
104   /**
105    * Probe connection.
106    */
107   struct GNUNET_CONNECTION_Handle *sock;
108
109   /**
110    * Message to be sent.
111    */
112   struct TCP_NAT_ProbeMessage message;
113
114   /**
115    * Handle to the transmission.
116    */
117   struct GNUNET_CONNECTION_TransmitHandle *transmit_handle;
118
119   /**
120    * Transport plugin handle.
121    */
122   struct Plugin *plugin;
123 };
124
125
126 /**
127  * Network format for IPv4 addresses.
128  */
129 struct IPv4TcpAddress
130 {
131   /**
132    * IPv4 address, in network byte order.
133    */
134   uint32_t ipv4_addr GNUNET_PACKED;
135
136   /**
137    * Port number, in network byte order.
138    */
139   uint16_t t_port GNUNET_PACKED;
140
141 };
142
143
144 /**
145  * Network format for IPv6 addresses.
146  */
147 struct IPv6TcpAddress
148 {
149   /**
150    * IPv6 address.
151    */
152   struct in6_addr ipv6_addr GNUNET_PACKED;
153
154   /**
155    * Port number, in network byte order.
156    */
157   uint16_t t6_port GNUNET_PACKED;
158
159 };
160
161
162 /**
163  * Encapsulation of all of the state of the plugin.
164  */
165 struct Plugin;
166
167
168 /**
169  * Local network addresses (actual IP address follows this struct).
170  * PORT is NOT included!
171  */
172 struct LocalAddrList
173 {
174
175   /**
176    * This is a doubly linked list.
177    */
178   struct LocalAddrList *next;
179
180   /**
181    * This is a doubly linked list.
182    */
183   struct LocalAddrList *prev;
184
185   /**
186    * Link to plugin.
187    */
188   struct Plugin *plugin;
189
190   /**
191    * Handle to NAT holes we've tried to punch for this address.
192    */
193   struct GNUNET_NAT_Handle *nat;
194
195   /**
196    * Pointer to a 'struct IPv4/V6TcpAddress' describing our external IP and port
197    * as obtained from the NAT by automatic port mapping.
198    */
199   void *external_nat_address;
200
201   /**
202    * Number of bytes in 'external_nat_address'
203    */
204   size_t ena_size;
205
206   /**
207    * Number of bytes of the address that follow
208    */
209   size_t size;
210
211 };
212
213
214 /**
215  * Information kept for each message that is yet to
216  * be transmitted.
217  */
218 struct PendingMessage
219 {
220
221   /**
222    * This is a doubly-linked list.
223    */
224   struct PendingMessage *next;
225
226   /**
227    * This is a doubly-linked list.
228    */
229   struct PendingMessage *prev;
230
231   /**
232    * The pending message
233    */
234   const char *msg;
235
236   /**
237    * Continuation function to call once the message
238    * has been sent.  Can be NULL if there is no
239    * continuation to call.
240    */
241   GNUNET_TRANSPORT_TransmitContinuation transmit_cont;
242
243   /**
244    * Closure for transmit_cont.
245    */
246   void *transmit_cont_cls;
247
248   /**
249    * Timeout value for the pending message.
250    */
251   struct GNUNET_TIME_Absolute timeout;
252
253   /**
254    * So that the gnunet-service-transport can group messages together,
255    * these pending messages need to accept a message buffer and size
256    * instead of just a GNUNET_MessageHeader.
257    */
258   size_t message_size;
259
260 };
261
262
263 /**
264  * Session handle for TCP connections.
265  */
266 struct Session
267 {
268
269   /**
270    * API requirement.
271    */
272   struct SessionHeader header;
273
274   /**
275    * Stored in a linked list.
276    */
277   struct Session *next;
278
279   /**
280    * Pointer to the global plugin struct.
281    */
282   struct Plugin *plugin;
283
284   /**
285    * The client (used to identify this connection)
286    */
287   struct GNUNET_SERVER_Client *client;
288
289   /**
290    * Messages currently pending for transmission
291    * to this peer, if any.
292    */
293   struct PendingMessage *pending_messages_head;
294
295   /**
296    * Messages currently pending for transmission
297    * to this peer, if any.
298    */
299   struct PendingMessage *pending_messages_tail;
300
301   /**
302    * Handle for pending transmission request.
303    */
304   struct GNUNET_CONNECTION_TransmitHandle *transmit_handle;
305
306   /**
307    * To whom are we talking to (set to our identity
308    * if we are still waiting for the welcome message)
309    */
310   struct GNUNET_PeerIdentity target;
311
312   /**
313    * ID of task used to delay receiving more to throttle sender.
314    */
315   GNUNET_SCHEDULER_TaskIdentifier receive_delay_task;
316
317   /**
318    * Address of the other peer (either based on our 'connect'
319    * call or on our 'accept' call).
320    */
321   void *connect_addr;
322
323   /**
324    * Last activity on this connection.  Used to select preferred
325    * connection.
326    */
327   struct GNUNET_TIME_Absolute last_activity;
328
329   /**
330    * Length of connect_addr.
331    */
332   size_t connect_alen;
333
334   /**
335    * Are we still expecting the welcome message? (GNUNET_YES/GNUNET_NO)
336    */
337   int expecting_welcome;
338
339   /**
340    * Was this a connection that was inbound (we accepted)? (GNUNET_YES/GNUNET_NO)
341    */
342   int inbound;
343
344   /**
345    * Was this session created using NAT traversal?
346    */
347   int is_nat;
348
349 };
350
351
352 /**
353  * Encapsulation of all of the state of the plugin.
354  */
355 struct Plugin
356 {
357   /**
358    * Our environment.
359    */
360   struct GNUNET_TRANSPORT_PluginEnvironment *env;
361
362   /**
363    * The listen socket.
364    */
365   struct GNUNET_CONNECTION_Handle *lsock;
366
367   /**
368    * stdout pipe handle for the gnunet-nat-server process
369    */
370   struct GNUNET_DISK_PipeHandle *server_stdout;
371
372   /**
373    * stdout file handle (for reading) for the gnunet-nat-server process
374    */
375   const struct GNUNET_DISK_FileHandle *server_stdout_handle;
376
377   /**
378    * ID of select gnunet-nat-server stdout read task
379    */
380   GNUNET_SCHEDULER_TaskIdentifier server_read_task;
381
382   /**
383    * The process id of the server process (if behind NAT)
384    */
385   struct GNUNET_OS_Process *server_proc;
386
387   /**
388    * List of open TCP sessions.
389    */
390   struct Session *sessions;
391
392   /**
393    * Handle to the network service.
394    */
395   struct GNUNET_SERVICE_Context *service;
396
397   /**
398    * Handle to the server for this service.
399    */
400   struct GNUNET_SERVER_Handle *server;
401
402   /**
403    * Copy of the handler array where the closures are
404    * set to this struct's instance.
405    */
406   struct GNUNET_SERVER_MessageHandler *handlers;
407
408   /**
409    * Handle for request of hostname resolution, non-NULL if pending.
410    */
411   struct GNUNET_RESOLVER_RequestHandle *hostname_dns;
412
413   /**
414    * Map of peers we have tried to contact behind a NAT
415    */
416   struct GNUNET_CONTAINER_MultiHashMap *nat_wait_conns;
417
418   /**
419    * The external address given to us by the user.  Used for HELLOs
420    * and address validation.
421    */
422   char *external_address;
423
424   /**
425    * The internal address given to us by the user (or discovered).
426    * Used for NAT traversal (ICMP method), but not as a 'validateable'
427    * address in HELLOs.
428    */
429   char *internal_address;
430
431   /**
432    * Address given for us to bind to (ONLY).
433    */
434   char *bind_address;
435
436   /**
437    * List of our IP addresses.
438    */
439   struct LocalAddrList *lal_head;
440
441   /**
442    * Tail of our IP address list.
443    */
444   struct LocalAddrList *lal_tail;
445
446   /**
447    * List of active TCP probes.
448    */
449   struct TCPProbeContext *probe_head;
450
451   /**
452    * List of active TCP probes.
453    */
454   struct TCPProbeContext *probe_tail;
455
456   /**
457    * ID of task used to update our addresses when one expires.
458    */
459   GNUNET_SCHEDULER_TaskIdentifier address_update_task;
460
461   /**
462    * Port that we are actually listening on.
463    */
464   uint16_t open_port;
465
466   /**
467    * Port that the user said we would have visible to the
468    * rest of the world.
469    */
470   uint16_t adv_port;
471
472   /**
473    * Is this transport configured to be behind a NAT?
474    */
475   int behind_nat;
476
477   /**
478    * Is this transport configured to allow connections to NAT'd peers?
479    */
480   int allow_nat;
481
482   /**
483    * Are we allowed to try UPnP/PMP for NAT traversal?
484    */
485   int allow_upnp;
486
487 };
488
489
490 /**
491  * Our external IP address/port mapping has changed.
492  *
493  * @param cls closure, the 'struct LocalAddrList'
494  * @param add_remove GNUNET_YES to mean the new public IP address, GNUNET_NO to mean
495  *     the previous (now invalid) one
496  * @param addr either the previous or the new public IP address
497  * @param addrlen actual lenght of the address
498  */
499 static void
500 nat_port_map_callback (void *cls,
501                        int add_remove,
502                        const struct sockaddr *addr,
503                        socklen_t addrlen)
504 {
505   struct LocalAddrList *lal = cls;
506   struct Plugin *plugin = lal->plugin;
507   int af;
508   struct IPv4TcpAddress t4;
509   struct IPv6TcpAddress t6;
510   void *arg;
511   uint16_t args;
512
513   /* convert 'addr' to our internal format */
514   af = addr->sa_family;
515   switch (af)
516     {
517     case AF_INET:
518       t4.ipv4_addr = ((struct sockaddr_in *) addr)->sin_addr.s_addr;
519       t6.t6_port = ((struct sockaddr_in *) addr)->sin_port;
520       arg = &t4;
521       args = sizeof (t4);
522       break;
523     case AF_INET6:
524       memcpy (&t6.ipv6_addr,
525               &((struct sockaddr_in6 *) addr)->sin6_addr,
526               sizeof (struct in6_addr));
527       t6.t6_port = ((struct sockaddr_in6 *) addr)->sin6_port;
528       arg = &t6;
529       args = sizeof (t6);    
530       break;
531     default:
532       GNUNET_break (0);
533       return;
534     } 
535
536   /* modify our published address list */
537   if (GNUNET_YES == add_remove)
538     {
539       plugin->env->notify_address (plugin->env->cls,
540                                    "tcp",
541                                    arg, args, GNUNET_TIME_UNIT_FOREVER_REL);
542       GNUNET_free_non_null (lal->external_nat_address);
543       lal->external_nat_address = GNUNET_memdup (arg, args);
544       lal->ena_size = args;
545     }
546   else
547     {
548       plugin->env->notify_address (plugin->env->cls,
549                                    "tcp",
550                                    arg, args, GNUNET_TIME_UNIT_ZERO);
551       GNUNET_free_non_null (lal->external_nat_address);
552       lal->ena_size = 0;
553     }
554 }
555
556
557 /**
558  * Add the given address to the list of 'local' addresses, thereby
559  * making it a 'legal' address for this peer to have.  
560  * 
561  * @param plugin the plugin
562  * @param arg the address, either an IPv4 or an IPv6 IP address
563  * @param arg_size number of bytes in arg
564  */
565 static void
566 add_to_address_list (struct Plugin *plugin,
567                      const void *arg,
568                      size_t arg_size)
569 {
570   struct LocalAddrList *lal;
571   struct sockaddr_in v4;
572   struct sockaddr_in6 v6;
573   const struct sockaddr *sa;
574   socklen_t salen;
575
576   lal = plugin->lal_head;
577   while (NULL != lal)
578     {
579       if ( (lal->size == arg_size) &&
580            (0 == memcmp (&lal[1], arg, arg_size)) )
581         return;
582       lal = lal->next;
583     }
584   lal = GNUNET_malloc (sizeof (struct LocalAddrList) + arg_size);
585   lal->plugin = plugin;
586   lal->size = arg_size;
587   memcpy (&lal[1], arg, arg_size);
588   GNUNET_CONTAINER_DLL_insert (plugin->lal_head,
589                                plugin->lal_tail,
590                                lal);
591   if (plugin->open_port == 0)
592     return; /* we're not listening at all... */
593   if (arg_size == sizeof (struct in_addr))
594     {
595       memset (&v4, 0, sizeof (v4));
596       v4.sin_family = AF_INET;
597       v4.sin_port = htons (plugin->open_port);
598       memcpy (&v4.sin_addr, arg, arg_size);
599 #if HAVE_SOCKADDR_IN_SIN_LEN
600       v4.sin_len = sizeof (struct sockaddr_in);
601 #endif
602       sa = (const struct sockaddr*) &v4;
603       salen = sizeof (v4);
604     }
605   else if (arg_size == sizeof (struct in6_addr))
606     {     
607       memset (&v6, 0, sizeof (v6));
608       v6.sin6_family = AF_INET6;
609       v6.sin6_port = htons (plugin->open_port);
610       memcpy (&v6.sin6_addr, arg, arg_size);
611 #if HAVE_SOCKADDR_IN_SIN_LEN
612       v6.sin6_len = sizeof (struct sockaddr_in6);
613 #endif
614       sa = (const struct sockaddr*) &v6;
615       salen = sizeof (v6);
616     }
617   else
618     {
619       GNUNET_break (0);
620       return;
621     }
622   if (plugin->allow_upnp)
623     lal->nat = GNUNET_NAT_register (sa, salen,
624                                     &nat_port_map_callback,
625                                     lal);
626 }
627
628
629 /**
630  * Check if the given address is in the list of 'local' addresses.
631  * 
632  * @param plugin the plugin
633  * @param arg the address, either an IPv4 or an IPv6 IP address
634  * @param arg_size number of bytes in arg
635  * @return GNUNET_OK if this is one of our IPs, GNUNET_SYSERR if not
636  */
637 static int
638 check_local_addr (struct Plugin *plugin,
639                   const void *arg,
640                   size_t arg_size)
641 {
642   struct LocalAddrList *lal;
643
644   lal = plugin->lal_head;
645   while (NULL != lal)
646     {
647       if ( (lal->size == arg_size) &&
648            (0 == memcmp (&lal[1], arg, arg_size)) )
649         return GNUNET_OK;
650       lal = lal->next;
651     }
652   return GNUNET_SYSERR;
653 }
654
655
656 /**
657  * Check if the given address is in the list of 'mapped' addresses.
658  * 
659  * @param plugin the plugin
660  * @param arg the address, either a 'struct IPv4TcpAddress' or a 'struct IPv6TcpAddress'
661  * @param arg_size number of bytes in arg
662  * @return GNUNET_OK if this is one of our IPs, GNUNET_SYSERR if not
663  */
664 static int
665 check_mapped_addr (struct Plugin *plugin,
666                    const void *arg,
667                    size_t arg_size)
668 {
669   struct LocalAddrList *lal;
670
671   lal = plugin->lal_head;
672   while (NULL != lal)
673     {
674       if ( (lal->ena_size == arg_size) &&
675            (0 == memcmp (lal->external_nat_address, arg, arg_size)) )
676         return GNUNET_OK;
677       lal = lal->next;
678     }
679   return GNUNET_SYSERR;
680 }
681
682
683 /**
684  * Function called for a quick conversion of the binary address to
685  * a numeric address.  Note that the caller must not free the
686  * address and that the next call to this function is allowed
687  * to override the address again.
688  *
689  * @param cls closure ('struct Plugin*')
690  * @param addr binary address
691  * @param addrlen length of the address
692  * @return string representing the same address
693  */
694 static const char*
695 tcp_address_to_string (void *cls,
696                        const void *addr,
697                        size_t addrlen)
698 {
699   static char rbuf[INET6_ADDRSTRLEN + 12];
700   char buf[INET6_ADDRSTRLEN];
701   const void *sb;
702   struct in_addr a4;
703   struct in6_addr a6;
704   const struct IPv4TcpAddress *t4;
705   const struct IPv6TcpAddress *t6;
706   int af;
707   uint16_t port;
708
709   if (addrlen == sizeof (struct IPv6TcpAddress))
710     {
711       t6 = addr;
712       af = AF_INET6;
713       port = ntohs (t6->t6_port);
714       memcpy (&a6, &t6->ipv6_addr, sizeof (a6));
715       sb = &a6;
716     }
717   else if (addrlen == sizeof (struct IPv4TcpAddress))
718     {
719       t4 = addr;
720       af = AF_INET;
721       port = ntohs (t4->t_port);
722       memcpy (&a4, &t4->ipv4_addr, sizeof (a4));
723       sb = &a4;
724     }
725   else
726     {
727       GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR,
728                        "tcp",
729                        _("Unexpected address length: %u\n"),
730                        addrlen);
731       GNUNET_break (0);
732       return NULL;
733     }
734   if (NULL == inet_ntop (af, sb, buf, INET6_ADDRSTRLEN))
735     {
736       GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "inet_ntop");
737       return NULL;
738     }
739   GNUNET_snprintf (rbuf,
740                    sizeof (rbuf),
741                    (af == AF_INET6) ? "[%s]:%u" : "%s:%u",
742                    buf,
743                    port);
744   return rbuf;
745 }
746
747
748 /**
749  * Find the session handle for the given client.
750  *
751  * @param plugin the plugin
752  * @param client which client to find the session handle for
753  * @return NULL if no matching session exists
754  */
755 static struct Session *
756 find_session_by_client (struct Plugin *plugin,
757                         const struct GNUNET_SERVER_Client *client)
758 {
759   struct Session *ret;
760
761   ret = plugin->sessions;
762   while ((ret != NULL) && (client != ret->client))
763     ret = ret->next;
764   return ret;
765 }
766
767
768 /**
769  * Create a new session.  Also queues a welcome message.
770  *
771  * @param plugin the plugin
772  * @param target peer to connect to
773  * @param client client to use
774  * @param is_nat this a NAT session, we should wait for a client to
775  *               connect to us from an address, then assign that to
776  *               the session
777  * @return new session object
778  */
779 static struct Session *
780 create_session (struct Plugin *plugin,
781                 const struct GNUNET_PeerIdentity *target,
782                 struct GNUNET_SERVER_Client *client, 
783                 int is_nat)
784 {
785   struct Session *ret;
786   struct PendingMessage *pm;
787   struct WelcomeMessage welcome;
788
789   if (is_nat != GNUNET_YES)
790     GNUNET_assert (client != NULL);
791   else
792     GNUNET_assert (client == NULL);
793 #if DEBUG_TCP
794   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
795                    "tcp",
796                    "Creating new session for peer `%4s'\n",
797                    GNUNET_i2s (target));
798 #endif
799   ret = GNUNET_malloc (sizeof (struct Session));
800   ret->last_activity = GNUNET_TIME_absolute_get ();
801   ret->plugin = plugin;
802   ret->is_nat = is_nat;
803   if (is_nat != GNUNET_YES) /* If not a NAT WAIT conn, add it to global list */
804     {
805       ret->next = plugin->sessions;
806       plugin->sessions = ret;
807     }
808   ret->client = client;
809   ret->target = *target;
810   ret->expecting_welcome = GNUNET_YES;
811   pm = GNUNET_malloc (sizeof (struct PendingMessage) + sizeof (struct WelcomeMessage));
812   pm->msg = (const char*) &pm[1];
813   pm->message_size = sizeof (struct WelcomeMessage);
814   welcome.header.size = htons (sizeof (struct WelcomeMessage));
815   welcome.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_WELCOME);
816   welcome.clientIdentity = *plugin->env->my_identity;
817   memcpy (&pm[1], &welcome, sizeof (welcome));
818   pm->timeout = GNUNET_TIME_UNIT_FOREVER_ABS;
819   GNUNET_STATISTICS_update (plugin->env->stats,
820                             gettext_noop ("# bytes currently in TCP buffers"),
821                             pm->message_size,
822                             GNUNET_NO);
823   GNUNET_CONTAINER_DLL_insert (ret->pending_messages_head,
824                                ret->pending_messages_tail,
825                                pm);
826   if (is_nat != GNUNET_YES)
827     GNUNET_STATISTICS_update (plugin->env->stats,
828                               gettext_noop ("# TCP sessions active"),
829                               1,
830                               GNUNET_NO);
831   return ret;
832 }
833
834
835 /**
836  * If we have pending messages, ask the server to
837  * transmit them (schedule the respective tasks, etc.)
838  *
839  * @param session for which session should we do this
840  */
841 static void process_pending_messages (struct Session *session);
842
843
844 /**
845  * Function called to notify a client about the socket
846  * being ready to queue more data.  "buf" will be
847  * NULL and "size" zero if the socket was closed for
848  * writing in the meantime.
849  *
850  * @param cls closure
851  * @param size number of bytes available in buf
852  * @param buf where the callee should write the message
853  * @return number of bytes written to buf
854  */
855 static size_t
856 do_transmit (void *cls, size_t size, void *buf)
857 {
858   struct Session *session = cls;
859   struct GNUNET_PeerIdentity pid;
860   struct Plugin *plugin;
861   struct PendingMessage *pos;
862   struct PendingMessage *hd;
863   struct PendingMessage *tl;
864   struct GNUNET_TIME_Absolute now;
865   char *cbuf;
866   size_t ret;
867
868   session->transmit_handle = NULL;
869   plugin = session->plugin;
870   if (buf == NULL)
871     {
872 #if DEBUG_TCP
873       GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
874                        "tcp",
875                        "Timeout trying to transmit to peer `%4s', discarding message queue.\n",
876                        GNUNET_i2s (&session->target));
877 #endif
878       /* timeout; cancel all messages that have already expired */
879       hd = NULL;
880       tl = NULL;
881       ret = 0;
882       now = GNUNET_TIME_absolute_get ();
883       while ( (NULL != (pos = session->pending_messages_head)) &&
884               (pos->timeout.abs_value <= now.abs_value) )
885         {
886           GNUNET_CONTAINER_DLL_remove (session->pending_messages_head,
887                                        session->pending_messages_tail,
888                                        pos);
889 #if DEBUG_TCP
890           GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
891                            "tcp",
892                            "Failed to transmit %u byte message to `%4s'.\n",
893                            pos->message_size,
894                            GNUNET_i2s (&session->target));
895 #endif
896           ret += pos->message_size;
897           GNUNET_CONTAINER_DLL_insert_after (hd, tl, tl, pos);
898         }
899       /* do this call before callbacks (so that if callbacks destroy
900          session, they have a chance to cancel actions done by this
901          call) */
902       process_pending_messages (session);
903       pid = session->target;
904       /* no do callbacks and do not use session again since
905          the callbacks may abort the session */
906       while (NULL != (pos = hd))
907         {
908           GNUNET_CONTAINER_DLL_remove (hd, tl, pos);
909           if (pos->transmit_cont != NULL)
910             pos->transmit_cont (pos->transmit_cont_cls,
911                                 &pid, GNUNET_SYSERR);
912           GNUNET_free (pos);
913         }
914       GNUNET_STATISTICS_update (plugin->env->stats,
915                                 gettext_noop ("# bytes currently in TCP buffers"),
916                                 - (int64_t) ret,
917                                 GNUNET_NO);
918       GNUNET_STATISTICS_update (plugin->env->stats,
919                                 gettext_noop ("# bytes discarded by TCP (timeout)"),
920                                 ret,
921                                 GNUNET_NO);
922       return 0;
923     }
924   /* copy all pending messages that would fit */
925   ret = 0;
926   cbuf = buf;
927   hd = NULL;
928   tl = NULL;
929   while (NULL != (pos = session->pending_messages_head))
930     {
931       if (ret + pos->message_size > size)
932         break;
933       GNUNET_CONTAINER_DLL_remove (session->pending_messages_head,
934                                    session->pending_messages_tail,
935                                    pos);
936       GNUNET_assert (size >= pos->message_size);
937       /* FIXME: this memcpy can be up to 7% of our total runtime */
938       memcpy (cbuf, pos->msg, pos->message_size);
939       cbuf += pos->message_size;
940       ret += pos->message_size;
941       size -= pos->message_size;
942       GNUNET_CONTAINER_DLL_insert_after (hd, tl, tl, pos);
943     }
944   /* schedule 'continuation' before callbacks so that callbacks that
945      cancel everything don't cause us to use a session that no longer
946      exists... */
947   process_pending_messages (session);
948   session->last_activity = GNUNET_TIME_absolute_get ();
949   pid = session->target;
950   /* we'll now call callbacks that may cancel the session; hence
951      we should not use 'session' after this point */
952   while (NULL != (pos = hd))
953     {
954       GNUNET_CONTAINER_DLL_remove (hd, tl, pos);
955       if (pos->transmit_cont != NULL)
956         pos->transmit_cont (pos->transmit_cont_cls,
957                             &pid, GNUNET_OK);
958       GNUNET_free (pos);
959     }
960   GNUNET_assert (hd == NULL);
961   GNUNET_assert (tl == NULL);
962 #if DEBUG_TCP > 1
963   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
964                    "tcp",
965                    "Transmitting %u bytes\n", 
966                    ret);
967 #endif
968   GNUNET_STATISTICS_update (plugin->env->stats,
969                             gettext_noop ("# bytes currently in TCP buffers"),
970                             - (int64_t) ret,
971                             GNUNET_NO);
972   GNUNET_STATISTICS_update (plugin->env->stats,
973                             gettext_noop ("# bytes transmitted via TCP"),
974                             ret,
975                             GNUNET_NO);
976   return ret;
977 }
978
979
980 /**
981  * If we have pending messages, ask the server to
982  * transmit them (schedule the respective tasks, etc.)
983  *
984  * @param session for which session should we do this
985  */
986 static void
987 process_pending_messages (struct Session *session)
988 {
989   struct PendingMessage *pm;
990
991   GNUNET_assert (session->client != NULL);
992   if (session->transmit_handle != NULL)
993     return;
994   if (NULL == (pm = session->pending_messages_head))
995     return;
996
997   session->transmit_handle
998     = GNUNET_SERVER_notify_transmit_ready (session->client,
999                                            pm->message_size,
1000                                            GNUNET_TIME_absolute_get_remaining
1001                                            (pm->timeout),
1002                                            &do_transmit, session);
1003 }
1004
1005
1006 /**
1007  * Functions with this signature are called whenever we need
1008  * to close a session due to a disconnect or failure to
1009  * establish a connection.
1010  *
1011  * @param session session to close down
1012  */
1013 static void
1014 disconnect_session (struct Session *session)
1015 {
1016   struct Session *prev;
1017   struct Session *pos;
1018   struct PendingMessage *pm;
1019
1020 #if DEBUG_TCP
1021   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
1022                    "tcp",
1023                    "Disconnecting from `%4s' at %s.\n",
1024                    GNUNET_i2s (&session->target),
1025                    (session->connect_addr != NULL) ?
1026                    tcp_address_to_string (session->plugin,
1027                                           session->connect_addr,
1028                                           session->connect_alen) : "*");
1029 #endif
1030   /* remove from session list */
1031   prev = NULL;
1032   pos = session->plugin->sessions;
1033   while (pos != session)
1034     {
1035       prev = pos;
1036       pos = pos->next;
1037     }
1038   if (prev == NULL)
1039     session->plugin->sessions = session->next;
1040   else
1041     prev->next = session->next;
1042   session->plugin->env->session_end (session->plugin->env->cls,
1043                                      &session->target,
1044                                      session);
1045   /* clean up state */
1046   if (session->transmit_handle != NULL)
1047     {
1048       GNUNET_CONNECTION_notify_transmit_ready_cancel
1049         (session->transmit_handle);
1050       session->transmit_handle = NULL;
1051     }
1052   while (NULL != (pm = session->pending_messages_head))
1053     {
1054 #if DEBUG_TCP
1055       GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
1056                        "tcp",
1057                        pm->transmit_cont != NULL
1058                        ? "Could not deliver message to `%4s'.\n"
1059                        : "Could not deliver message to `%4s', notifying.\n",
1060                        GNUNET_i2s (&session->target));
1061 #endif
1062       GNUNET_STATISTICS_update (session->plugin->env->stats,
1063                                 gettext_noop ("# bytes currently in TCP buffers"),
1064                                 - (int64_t) pm->message_size,
1065                                 GNUNET_NO);
1066       GNUNET_STATISTICS_update (session->plugin->env->stats,
1067                                 gettext_noop ("# bytes discarded by TCP (disconnect)"),
1068                                 pm->message_size,
1069                                 GNUNET_NO);
1070       GNUNET_CONTAINER_DLL_remove (session->pending_messages_head,
1071                                    session->pending_messages_tail,
1072                                    pm);
1073       if (NULL != pm->transmit_cont)
1074         pm->transmit_cont (pm->transmit_cont_cls,
1075                            &session->target, GNUNET_SYSERR);
1076       GNUNET_free (pm);
1077     }
1078   GNUNET_break (session->client != NULL);
1079   if (session->receive_delay_task != GNUNET_SCHEDULER_NO_TASK)
1080     {
1081       GNUNET_SCHEDULER_cancel (session->receive_delay_task);
1082       if (session->client != NULL)
1083         GNUNET_SERVER_receive_done (session->client,
1084                                     GNUNET_SYSERR);     
1085     }
1086   if (session->client != NULL)  
1087     GNUNET_SERVER_client_drop (session->client);
1088   GNUNET_STATISTICS_update (session->plugin->env->stats,
1089                             gettext_noop ("# TCP sessions active"),
1090                             -1,
1091                             GNUNET_NO);
1092   GNUNET_free_non_null (session->connect_addr);
1093   GNUNET_free (session);
1094 }
1095
1096
1097 /**
1098  * Given two otherwise equivalent sessions, pick the better one.
1099  *
1100  * @param s1 one session (also default)
1101  * @param s2 other session
1102  * @return "better" session (more active)
1103  */
1104 static struct Session *
1105 select_better_session (struct Session *s1,
1106                        struct Session *s2)
1107 {
1108   if (s1 == NULL)
1109     return s2;
1110   if (s2 == NULL)
1111     return s1;
1112   if ( (s1->expecting_welcome == GNUNET_NO) &&
1113        (s2->expecting_welcome == GNUNET_YES) )
1114     return s1;
1115   if ( (s1->expecting_welcome == GNUNET_YES) &&
1116        (s2->expecting_welcome == GNUNET_NO) )
1117     return s2;
1118   if (s1->last_activity.abs_value < s2->last_activity.abs_value)
1119     return s2;
1120   if (s1->last_activity.abs_value > s2->last_activity.abs_value)
1121     return s1;
1122   if ( (GNUNET_YES == s1->inbound) &&
1123        (GNUNET_NO  == s2->inbound) )
1124     return s1;
1125   if ( (GNUNET_NO  == s1->inbound) &&
1126        (GNUNET_YES == s2->inbound) )
1127     return s2;
1128   return s1;
1129 }
1130
1131
1132 /**
1133  * We learned about a peer (possibly behind NAT) so run the
1134  * gnunet-nat-client to send dummy ICMP responses.
1135  *
1136  * @param plugin the plugin for this transport
1137  * @param addr the address of the peer (IPv4-only)
1138  */
1139 static void
1140 run_gnunet_nat_client (struct Plugin *plugin, 
1141                        const struct sockaddr_in *sa)
1142 {
1143   char inet4[INET_ADDRSTRLEN];
1144   char port_as_string[6];
1145   struct GNUNET_OS_Process *proc;
1146
1147   if (plugin->internal_address == NULL)
1148     {
1149       GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING,
1150                        "tcp",
1151                        _("Internal IP address not known, cannot use ICMP NAT traversal method\n"));
1152       return;
1153     }
1154   GNUNET_assert (sa->sin_family == AF_INET);
1155   if (NULL == inet_ntop (AF_INET,
1156                          &sa->sin_addr,
1157                          inet4, INET_ADDRSTRLEN))
1158     {
1159       GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "inet_ntop");
1160       return;
1161     }
1162   GNUNET_snprintf(port_as_string, 
1163                   sizeof (port_as_string),
1164                   "%d", 
1165                   plugin->adv_port);
1166 #if DEBUG_TCP_NAT
1167   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
1168                    "tcp",
1169                    _("Running gnunet-nat-client %s %s %u\n"), 
1170                    plugin->internal_address,
1171                    inet4,
1172                    (unsigned int) plugin->adv_port);
1173 #endif
1174   proc = GNUNET_OS_start_process (NULL, 
1175                                   NULL, 
1176                                   "gnunet-nat-client",
1177                                   "gnunet-nat-client",
1178                                   plugin->internal_address, 
1179                                   inet4,
1180                                   port_as_string, 
1181                                   NULL);
1182   /* we know that the gnunet-nat-client will terminate virtually
1183      instantly */
1184   GNUNET_OS_process_wait (proc);
1185   GNUNET_OS_process_close (proc);
1186 }
1187
1188
1189 /**
1190  * Function that can be used by the transport service to transmit
1191  * a message using the plugin.   Note that in the case of a
1192  * peer disconnecting, the continuation MUST be called
1193  * prior to the disconnect notification itself.  This function
1194  * will be called with this peer's HELLO message to initiate
1195  * a fresh connection to another peer.
1196  *
1197  * @param cls closure
1198  * @param target who should receive this message
1199  * @param msg the message to transmit
1200  * @param msgbuf_size number of bytes in 'msg'
1201  * @param priority how important is the message (most plugins will
1202  *                 ignore message priority and just FIFO)
1203  * @param timeout how long to wait at most for the transmission (does not
1204  *                require plugins to discard the message after the timeout,
1205  *                just advisory for the desired delay; most plugins will ignore
1206  *                this as well)
1207  * @param session which session must be used (or NULL for "any")
1208  * @param addr the address to use (can be NULL if the plugin
1209  *                is "on its own" (i.e. re-use existing TCP connection))
1210  * @param addrlen length of the address in bytes
1211  * @param force_address GNUNET_YES if the plugin MUST use the given address,
1212  *                GNUNET_NO means the plugin may use any other address and
1213  *                GNUNET_SYSERR means that only reliable existing
1214  *                bi-directional connections should be used (regardless
1215  *                of address)
1216  * @param cont continuation to call once the message has
1217  *        been transmitted (or if the transport is ready
1218  *        for the next transmission call; or if the
1219  *        peer disconnected...); can be NULL
1220  * @param cont_cls closure for cont
1221  * @return number of bytes used (on the physical network, with overheads);
1222  *         -1 on hard errors (i.e. address invalid); 0 is a legal value
1223  *         and does NOT mean that the message was not transmitted (DV and NAT)
1224  */
1225 static ssize_t
1226 tcp_plugin_send (void *cls,
1227                  const struct GNUNET_PeerIdentity *target,
1228                  const char *msg,
1229                  size_t msgbuf_size,
1230                  uint32_t priority,
1231                  struct GNUNET_TIME_Relative timeout,
1232                  struct Session *session,
1233                  const void *addr,
1234                  size_t addrlen,
1235                  int force_address,
1236                  GNUNET_TRANSPORT_TransmitContinuation cont, void *cont_cls)
1237 {
1238   struct Plugin *plugin = cls;
1239   struct Session *cand_session;
1240   struct Session *next;
1241   struct PendingMessage *pm;
1242   struct GNUNET_CONNECTION_Handle *sa;
1243   int af;
1244   const void *sb;
1245   size_t sbs;
1246   struct sockaddr_in a4;
1247   struct sockaddr_in6 a6;
1248   const struct IPv4TcpAddress *t4;
1249   const struct IPv6TcpAddress *t6;
1250   unsigned int is_natd;
1251
1252   GNUNET_STATISTICS_update (plugin->env->stats,
1253                             gettext_noop ("# bytes TCP was asked to transmit"),
1254                             msgbuf_size,
1255                             GNUNET_NO);
1256   /* FIXME: we could do this cheaper with a hash table
1257      where we could restrict the iteration to entries that match
1258      the target peer... */
1259   is_natd = GNUNET_NO;
1260   if (session == NULL)
1261     {
1262       cand_session = NULL;
1263       next = plugin->sessions;
1264       while (NULL != (session = next))
1265         {
1266           next = session->next;
1267           GNUNET_assert (session->client != NULL);
1268           if (0 != memcmp (target,
1269                            &session->target,
1270                            sizeof (struct GNUNET_PeerIdentity)))
1271             continue;
1272           if ( ( (GNUNET_SYSERR == force_address) &&
1273                  (session->expecting_welcome == GNUNET_NO) ) ||
1274                (GNUNET_NO == force_address) )
1275             {
1276               cand_session = select_better_session (cand_session,
1277                                                     session);
1278               continue;
1279             }
1280           if (GNUNET_SYSERR == force_address)
1281             continue;
1282           GNUNET_break (GNUNET_YES == force_address);
1283           if (addr == NULL)
1284             {
1285               GNUNET_break (0);
1286               break;
1287             }
1288           if ( (addrlen != session->connect_alen) && 
1289                (session->is_nat == GNUNET_NO) )
1290             continue;
1291           if ((0 != memcmp (session->connect_addr,
1292                            addr,
1293                            addrlen)) && (session->is_nat == GNUNET_NO))
1294             continue;
1295           cand_session = select_better_session (cand_session,
1296                                                 session);       
1297         }
1298       session = cand_session;
1299     }
1300   if ( (session == NULL) &&
1301        (addr == NULL) )
1302     {
1303 #if DEBUG_TCP
1304       GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
1305                        "tcp",
1306                        "Asked to transmit to `%4s' without address and I have no existing connection (failing).\n",
1307                        GNUNET_i2s (target));
1308 #endif
1309       GNUNET_STATISTICS_update (plugin->env->stats,
1310                                 gettext_noop ("# bytes discarded by TCP (no address and no connection)"),
1311                                 msgbuf_size,
1312                                 GNUNET_NO);
1313       return -1;
1314     }
1315   if (session == NULL)
1316     {
1317       if (addrlen == sizeof (struct IPv6TcpAddress))
1318         {
1319           t6 = addr;
1320           af = AF_INET6;
1321           memset (&a6, 0, sizeof (a6));
1322 #if HAVE_SOCKADDR_IN_SIN_LEN
1323           a6.sin6_len = sizeof (a6);
1324 #endif
1325           a6.sin6_family = AF_INET6;
1326           a6.sin6_port = t6->t6_port;
1327           if (t6->t6_port == 0)
1328             is_natd = GNUNET_YES;
1329           memcpy (&a6.sin6_addr,
1330                   &t6->ipv6_addr,
1331                   sizeof (struct in6_addr));
1332           sb = &a6;
1333           sbs = sizeof (a6);
1334         }
1335       else if (addrlen == sizeof (struct IPv4TcpAddress))
1336         {
1337           t4 = addr;
1338           af = AF_INET;
1339           memset (&a4, 0, sizeof (a4));
1340 #if HAVE_SOCKADDR_IN_SIN_LEN
1341           a4.sin_len = sizeof (a4);
1342 #endif
1343           a4.sin_family = AF_INET;
1344           a4.sin_port = t4->t_port;
1345           if (t4->t_port == 0)
1346             is_natd = GNUNET_YES;
1347           a4.sin_addr.s_addr = t4->ipv4_addr;
1348           sb = &a4;
1349           sbs = sizeof (a4);
1350         }
1351       else
1352         {
1353           GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR,
1354                            "tcp",
1355                            _("Address of unexpected length: %u\n"),
1356                            addrlen);
1357           GNUNET_break (0);
1358           return -1;
1359         }
1360
1361       if ((is_natd == GNUNET_YES) && (addrlen == sizeof (struct IPv6TcpAddress)))
1362         return -1; /* NAT client only works with IPv4 addresses */
1363
1364
1365       if ((plugin->allow_nat == GNUNET_YES) && (is_natd == GNUNET_YES) &&
1366            (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains(plugin->nat_wait_conns, &target->hashPubKey)))
1367         {
1368 #if DEBUG_TCP_NAT
1369           GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
1370                            "tcp",
1371                            _("Found valid IPv4 NAT address (creating session)!\n"));
1372 #endif
1373           session = create_session (plugin,
1374                                     target,
1375                                     NULL, 
1376                                     GNUNET_YES);
1377
1378           /* create new message entry */
1379           pm = GNUNET_malloc (sizeof (struct PendingMessage) + msgbuf_size);
1380           /* FIXME: the memset of this malloc can be up to 2% of our total runtime */
1381           pm->msg = (const char*) &pm[1];
1382           memcpy (&pm[1], msg, msgbuf_size);
1383           /* FIXME: this memcpy can be up to 7% of our total run-time
1384              (for transport service) */
1385           pm->message_size = msgbuf_size;
1386           pm->timeout = GNUNET_TIME_relative_to_absolute (timeout);
1387           pm->transmit_cont = cont;
1388           pm->transmit_cont_cls = cont_cls;
1389
1390           /* append pm to pending_messages list */
1391           GNUNET_CONTAINER_DLL_insert_after (session->pending_messages_head,
1392                                              session->pending_messages_tail,
1393                                              session->pending_messages_tail,
1394                                              pm);
1395
1396           GNUNET_assert(GNUNET_CONTAINER_multihashmap_put(plugin->nat_wait_conns,
1397                                                           &target->hashPubKey,
1398                                                           session, 
1399                                                           GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY) == GNUNET_OK);
1400 #if DEBUG_TCP_NAT
1401           GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
1402                            "tcp",
1403                            "Created NAT WAIT connection to `%4s' at `%s'\n",
1404                            GNUNET_i2s (target),
1405                            GNUNET_a2s (sb, sbs));
1406 #endif
1407           run_gnunet_nat_client (plugin, &a4);
1408           return 0;
1409         }
1410       if ( (plugin->allow_nat == GNUNET_YES) && 
1411            (is_natd == GNUNET_YES) && 
1412            (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains(plugin->nat_wait_conns, &target->hashPubKey)) )
1413         {
1414           /* Only do one NAT punch attempt per peer identity */
1415           return -1;
1416         }
1417       sa = GNUNET_CONNECTION_create_from_sockaddr (af, sb, sbs);
1418       if (sa == NULL)
1419         {
1420 #if DEBUG_TCP
1421           GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
1422                            "tcp",
1423                            "Failed to create connection to `%4s' at `%s'\n",
1424                            GNUNET_i2s (target),
1425                            GNUNET_a2s (sb, sbs));
1426 #endif
1427           GNUNET_STATISTICS_update (plugin->env->stats,
1428                                     gettext_noop ("# bytes discarded by TCP (failed to connect)"),
1429                                     msgbuf_size,
1430                                     GNUNET_NO);
1431           return -1;
1432         }
1433 #if DEBUG_TCP_NAT
1434       GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
1435                        "tcp",
1436                        "Asked to transmit to `%4s', creating fresh session using address `%s'.\n",
1437                        GNUNET_i2s (target),
1438                        GNUNET_a2s (sb, sbs));
1439 #endif
1440       session = create_session (plugin,
1441                                 target,
1442                                 GNUNET_SERVER_connect_socket (plugin->server,
1443                                                               sa), 
1444                                 GNUNET_NO);
1445       session->connect_addr = GNUNET_malloc (addrlen);
1446       memcpy (session->connect_addr,
1447               addr,
1448               addrlen);
1449       session->connect_alen = addrlen;
1450     }
1451   GNUNET_assert (session != NULL);
1452   GNUNET_assert (session->client != NULL);
1453   GNUNET_STATISTICS_update (plugin->env->stats,
1454                             gettext_noop ("# bytes currently in TCP buffers"),
1455                             msgbuf_size,
1456                             GNUNET_NO);
1457   /* create new message entry */
1458   pm = GNUNET_malloc (sizeof (struct PendingMessage) + msgbuf_size);
1459   pm->msg = (const char*) &pm[1];
1460   memcpy (&pm[1], msg, msgbuf_size);
1461   pm->message_size = msgbuf_size;
1462   pm->timeout = GNUNET_TIME_relative_to_absolute (timeout);
1463   pm->transmit_cont = cont;
1464   pm->transmit_cont_cls = cont_cls;
1465
1466   /* append pm to pending_messages list */
1467   GNUNET_CONTAINER_DLL_insert_after (session->pending_messages_head,
1468                                      session->pending_messages_tail,
1469                                      session->pending_messages_tail,
1470                                      pm);
1471 #if DEBUG_TCP
1472   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
1473                    "tcp",
1474                    "Asked to transmit %u bytes to `%s', added message to list.\n",
1475                    msgbuf_size,
1476                    GNUNET_i2s (target));
1477 #endif
1478   process_pending_messages (session);
1479   return msgbuf_size;
1480 }
1481
1482
1483 /**
1484  * Function that can be called to force a disconnect from the
1485  * specified neighbour.  This should also cancel all previously
1486  * scheduled transmissions.  Obviously the transmission may have been
1487  * partially completed already, which is OK.  The plugin is supposed
1488  * to close the connection (if applicable) and no longer call the
1489  * transmit continuation(s).
1490  *
1491  * Finally, plugin MUST NOT call the services's receive function to
1492  * notify the service that the connection to the specified target was
1493  * closed after a getting this call.
1494  *
1495  * @param cls closure
1496  * @param target peer for which the last transmission is
1497  *        to be cancelled
1498  */
1499 static void
1500 tcp_plugin_disconnect (void *cls,
1501                        const struct GNUNET_PeerIdentity *target)
1502 {
1503   struct Plugin *plugin = cls;
1504   struct Session *session;
1505   struct Session *next;
1506   struct PendingMessage *pm;
1507
1508 #if DEBUG_TCP
1509   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
1510                    "tcp",
1511                    "Asked to cancel session with `%4s'\n",
1512                    GNUNET_i2s (target));
1513 #endif
1514   next = plugin->sessions;
1515   while (NULL != (session = next))
1516     {
1517       next = session->next;
1518       if (0 != memcmp (target,
1519                        &session->target,
1520                        sizeof (struct GNUNET_PeerIdentity)))
1521         continue;
1522       pm = session->pending_messages_head;
1523       while (pm != NULL)
1524         {
1525           pm->transmit_cont = NULL;
1526           pm->transmit_cont_cls = NULL;
1527           pm = pm->next;
1528         }
1529       disconnect_session (session);
1530     }
1531 }
1532
1533
1534 /**
1535  * Context for address to string conversion.
1536  */
1537 struct PrettyPrinterContext
1538 {
1539   /**
1540    * Function to call with the result.
1541    */
1542   GNUNET_TRANSPORT_AddressStringCallback asc;
1543
1544   /**
1545    * Clsoure for 'asc'.
1546    */
1547   void *asc_cls;
1548
1549   /**
1550    * Port to add after the IP address.
1551    */
1552   uint16_t port;
1553 };
1554
1555
1556 /**
1557  * Append our port and forward the result.
1558  *
1559  * @param cls the 'struct PrettyPrinterContext*'
1560  * @param hostname hostname part of the address
1561  */
1562 static void
1563 append_port (void *cls, const char *hostname)
1564 {
1565   struct PrettyPrinterContext *ppc = cls;
1566   char *ret;
1567
1568   if (hostname == NULL)
1569     {
1570       ppc->asc (ppc->asc_cls, NULL);
1571       GNUNET_free (ppc);
1572       return;
1573     }
1574   GNUNET_asprintf (&ret, "%s:%d", hostname, ppc->port);
1575   ppc->asc (ppc->asc_cls, ret);
1576   GNUNET_free (ret);
1577 }
1578
1579
1580 /**
1581  * Convert the transports address to a nice, human-readable
1582  * format.
1583  *
1584  * @param cls closure
1585  * @param type name of the transport that generated the address
1586  * @param addr one of the addresses of the host, NULL for the last address
1587  *        the specific address format depends on the transport
1588  * @param addrlen length of the address
1589  * @param numeric should (IP) addresses be displayed in numeric form?
1590  * @param timeout after how long should we give up?
1591  * @param asc function to call on each string
1592  * @param asc_cls closure for asc
1593  */
1594 static void
1595 tcp_plugin_address_pretty_printer (void *cls,
1596                                    const char *type,
1597                                    const void *addr,
1598                                    size_t addrlen,
1599                                    int numeric,
1600                                    struct GNUNET_TIME_Relative timeout,
1601                                    GNUNET_TRANSPORT_AddressStringCallback asc,
1602                                    void *asc_cls)
1603 {
1604   struct Plugin *plugin = cls;
1605   struct PrettyPrinterContext *ppc;
1606   const void *sb;
1607   size_t sbs;
1608   struct sockaddr_in a4;
1609   struct sockaddr_in6 a6;
1610   const struct IPv4TcpAddress *t4;
1611   const struct IPv6TcpAddress *t6;
1612   uint16_t port;
1613
1614   if (addrlen == sizeof (struct IPv6TcpAddress))
1615     {
1616       t6 = addr;
1617       memset (&a6, 0, sizeof (a6));
1618       a6.sin6_family = AF_INET6;
1619       a6.sin6_port = t6->t6_port;
1620       memcpy (&a6.sin6_addr,
1621               &t6->ipv6_addr,
1622               sizeof (struct in6_addr));
1623       port = ntohs (t6->t6_port);
1624       sb = &a6;
1625       sbs = sizeof (a6);
1626     }
1627   else if (addrlen == sizeof (struct IPv4TcpAddress))
1628     {
1629       t4 = addr;
1630       memset (&a4, 0, sizeof (a4));
1631       a4.sin_family = AF_INET;
1632       a4.sin_port = t4->t_port;
1633       a4.sin_addr.s_addr = t4->ipv4_addr;
1634       port = ntohs (t4->t_port);
1635       sb = &a4;
1636       sbs = sizeof (a4);
1637     }
1638   else
1639     {
1640       /* invalid address */
1641       GNUNET_break_op (0);
1642       asc (asc_cls, NULL);
1643       return;
1644     }
1645   ppc = GNUNET_malloc (sizeof (struct PrettyPrinterContext));
1646   ppc->asc = asc;
1647   ppc->asc_cls = asc_cls;
1648   ppc->port = port;
1649   GNUNET_RESOLVER_hostname_get (plugin->env->cfg,
1650                                 sb,
1651                                 sbs,
1652                                 !numeric, timeout, &append_port, ppc);
1653 }
1654
1655
1656 /**
1657  * Check if the given port is plausible (must be either our listen
1658  * port or our advertised port), or any port if we are behind NAT
1659  * and do not have a port open.  If it is neither, we return
1660  * GNUNET_SYSERR.
1661  *
1662  * @param plugin global variables
1663  * @param in_port port number to check
1664  * @return GNUNET_OK if port is either open_port or adv_port
1665  */
1666 static int
1667 check_port (struct Plugin *plugin, 
1668             uint16_t in_port)
1669 {
1670   if ((in_port == plugin->adv_port) || (in_port == plugin->open_port))
1671     return GNUNET_OK;
1672   return GNUNET_SYSERR;
1673 }
1674
1675
1676 /**
1677  * Function that will be called to check if a binary address for this
1678  * plugin is well-formed and corresponds to an address for THIS peer
1679  * (as per our configuration).  Naturally, if absolutely necessary,
1680  * plugins can be a bit conservative in their answer, but in general
1681  * plugins should make sure that the address does not redirect
1682  * traffic to a 3rd party that might try to man-in-the-middle our
1683  * traffic.
1684  *
1685  * @param cls closure, our 'struct Plugin*'
1686  * @param addr pointer to the address
1687  * @param addrlen length of addr
1688  * @return GNUNET_OK if this is a plausible address for this peer
1689  *         and transport, GNUNET_SYSERR if not
1690  */
1691 static int
1692 tcp_plugin_check_address (void *cls,
1693                           const void *addr,
1694                           size_t addrlen)
1695 {
1696   struct Plugin *plugin = cls;
1697   struct IPv4TcpAddress *v4;
1698   struct IPv6TcpAddress *v6;
1699
1700   if ((addrlen != sizeof (struct IPv4TcpAddress)) &&
1701       (addrlen != sizeof (struct IPv6TcpAddress)))
1702     {
1703       GNUNET_break_op (0);
1704       return GNUNET_SYSERR;
1705     }
1706   if (addrlen == sizeof (struct IPv4TcpAddress))
1707     {
1708       v4 = (struct IPv4TcpAddress *) addr;
1709       if (GNUNET_OK ==
1710           check_mapped_addr (plugin, v4, sizeof (struct IPv4TcpAddress)))
1711         return GNUNET_OK;
1712       if (GNUNET_OK !=
1713           check_port (plugin, ntohs (v4->t_port)))
1714         return GNUNET_SYSERR;
1715       if (GNUNET_OK !=
1716           check_local_addr (plugin, &v4->ipv4_addr, sizeof (struct in_addr)))
1717         return GNUNET_SYSERR;   
1718     }
1719   else
1720     {
1721       v6 = (struct IPv6TcpAddress *) addr;
1722       if (IN6_IS_ADDR_LINKLOCAL (&v6->ipv6_addr))
1723         {
1724           GNUNET_break_op (0);
1725           return GNUNET_SYSERR;
1726         }
1727       if (GNUNET_OK ==
1728           check_mapped_addr (plugin, v6, sizeof (struct IPv6TcpAddress)))
1729         return GNUNET_OK;
1730       if (GNUNET_OK !=
1731           check_port (plugin, ntohs (v6->t6_port)))
1732         return GNUNET_SYSERR;
1733       if (GNUNET_OK !=
1734           check_local_addr (plugin, &v6->ipv6_addr, sizeof (struct in6_addr)))
1735         return GNUNET_SYSERR;
1736     }
1737   return GNUNET_OK;
1738 }
1739
1740
1741 /**
1742  * We've received a nat probe from this peer via TCP.  Finish
1743  * creating the client session and resume sending of queued
1744  * messages.
1745  *
1746  * @param cls closure
1747  * @param client identification of the client
1748  * @param message the actual message
1749  */
1750 static void
1751 handle_tcp_nat_probe (void *cls,
1752                       struct GNUNET_SERVER_Client *client,
1753                       const struct GNUNET_MessageHeader *message)
1754 {
1755   struct Plugin *plugin = cls;
1756   struct Session *session;
1757   const struct TCP_NAT_ProbeMessage *tcp_nat_probe;
1758   size_t alen;
1759   void *vaddr;
1760   struct IPv4TcpAddress *t4;
1761   struct IPv6TcpAddress *t6;
1762   const struct sockaddr_in *s4;
1763   const struct sockaddr_in6 *s6;
1764
1765 #if DEBUG_TCP_NAT
1766   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, 
1767                    "tcp",
1768                    "received tcp NAT probe\n");
1769 #endif
1770   /* We have received a TCP NAT probe, meaning we (hopefully) initiated
1771    * a connection to this peer by running gnunet-nat-client.  This peer
1772    * received the punch message and now wants us to use the new connection
1773    * as the default for that peer.  Do so and then send a WELCOME message
1774    * so we can really be connected!
1775    */
1776   if (ntohs(message->size) != sizeof(struct TCP_NAT_ProbeMessage))
1777     {
1778       GNUNET_break_op(0);
1779       return;
1780     }
1781   tcp_nat_probe = (const struct TCP_NAT_ProbeMessage *)message;
1782   session = GNUNET_CONTAINER_multihashmap_get(plugin->nat_wait_conns, 
1783                                               &tcp_nat_probe->clientIdentity.hashPubKey);
1784   if (session == NULL)
1785     {
1786 #if DEBUG_TCP_NAT
1787       GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
1788                        "tcp",
1789                        "Did NOT find session for NAT probe!\n");
1790 #endif
1791       GNUNET_SERVER_receive_done (client, GNUNET_OK);
1792       return;
1793     }
1794 #if DEBUG_TCP_NAT
1795   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, 
1796                    "tcp",
1797                    "Found session for NAT probe!\n");
1798 #endif
1799   GNUNET_assert(GNUNET_CONTAINER_multihashmap_remove(plugin->nat_wait_conns, 
1800                                                      &tcp_nat_probe->clientIdentity.hashPubKey,
1801                                                      session) == GNUNET_YES);
1802   if (GNUNET_OK !=
1803       GNUNET_SERVER_client_get_address (client, &vaddr, &alen))
1804     {
1805       GNUNET_break (0);
1806       GNUNET_free (session);
1807       GNUNET_SERVER_receive_done (client, GNUNET_OK);
1808       return;
1809     }
1810
1811   GNUNET_SERVER_client_keep (client);
1812   session->client = client;
1813   session->last_activity = GNUNET_TIME_absolute_get ();
1814   session->inbound = GNUNET_NO;
1815
1816 #if DEBUG_TCP_NAT
1817   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
1818                    "tcp",
1819                    "Found address `%s' for incoming connection\n",
1820                    GNUNET_a2s (vaddr, alen));
1821 #endif
1822   switch (((const struct sockaddr *)vaddr)->sa_family)
1823     {
1824     case AF_INET:
1825       s4 = vaddr;
1826       t4 = GNUNET_malloc (sizeof (struct IPv4TcpAddress));
1827       t4->t_port = s4->sin_port;
1828       t4->ipv4_addr = s4->sin_addr.s_addr;
1829       session->connect_addr = t4;
1830       session->connect_alen = sizeof (struct IPv4TcpAddress);
1831       break;
1832     case AF_INET6:    
1833       s6 = vaddr;
1834       t6 = GNUNET_malloc (sizeof (struct IPv6TcpAddress));
1835       t6->t6_port = s6->sin6_port;
1836       memcpy (&t6->ipv6_addr,
1837               &s6->sin6_addr,
1838               sizeof (struct in6_addr));
1839       session->connect_addr = t6;
1840       session->connect_alen = sizeof (struct IPv6TcpAddress);
1841       break;
1842     default:
1843       GNUNET_break_op (0);
1844 #if DEBUG_TCP_NAT
1845       GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
1846                        "tcp",
1847                        "Bad address for incoming connection!\n");
1848 #endif
1849       GNUNET_free (vaddr);
1850       GNUNET_SERVER_client_drop (client);
1851       GNUNET_free (session);
1852       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1853       return;
1854     }
1855   GNUNET_free (vaddr);
1856   
1857   session->next = plugin->sessions;
1858   plugin->sessions = session;
1859   GNUNET_STATISTICS_update (plugin->env->stats,
1860                             gettext_noop ("# TCP sessions active"),
1861                             1,
1862                             GNUNET_NO);
1863   process_pending_messages (session);
1864   GNUNET_SERVER_receive_done (client, GNUNET_OK);
1865 }
1866
1867
1868 /**
1869  * We've received a welcome from this peer via TCP.  Possibly create a
1870  * fresh client record and send back our welcome.
1871  *
1872  * @param cls closure
1873  * @param client identification of the client
1874  * @param message the actual message
1875  */
1876 static void
1877 handle_tcp_welcome (void *cls,
1878                     struct GNUNET_SERVER_Client *client,
1879                     const struct GNUNET_MessageHeader *message)
1880 {
1881   struct Plugin *plugin = cls;
1882   const struct WelcomeMessage *wm = (const struct WelcomeMessage *) message;
1883   struct Session *session;
1884   size_t alen;
1885   void *vaddr;
1886   struct IPv4TcpAddress *t4;
1887   struct IPv6TcpAddress *t6;
1888   const struct sockaddr_in *s4;
1889   const struct sockaddr_in6 *s6;
1890
1891 #if DEBUG_TCP
1892   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
1893                    "tcp",
1894                    "Received %s message from `%4s'.\n",
1895                    "WELCOME",
1896                    GNUNET_i2s (&wm->clientIdentity));
1897 #endif
1898   GNUNET_STATISTICS_update (plugin->env->stats,
1899                             gettext_noop ("# TCP WELCOME messages received"),
1900                             1,
1901                             GNUNET_NO);
1902   session = find_session_by_client (plugin, client);
1903
1904   if (session == NULL)
1905     {
1906 #if DEBUG_TCP_NAT
1907       GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
1908                        "tcp",
1909                        "Received %s message from a `%4s', creating new session\n",
1910                        "WELCOME",
1911                        GNUNET_i2s (&wm->clientIdentity));
1912 #endif
1913       GNUNET_SERVER_client_keep (client);
1914       session = create_session (plugin,
1915                                 &wm->clientIdentity,
1916                                 client,
1917                                 GNUNET_NO);
1918       session->inbound = GNUNET_YES;
1919       if (GNUNET_OK ==
1920           GNUNET_SERVER_client_get_address (client, &vaddr, &alen))
1921         {
1922 #if DEBUG_TCP_NAT
1923           GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
1924                            "tcp",
1925                            "Found address `%s' for incoming connection\n",
1926                            GNUNET_a2s (vaddr, alen));
1927 #endif
1928           if (alen == sizeof (struct sockaddr_in))
1929             {
1930               s4 = vaddr;
1931               t4 = GNUNET_malloc (sizeof (struct IPv4TcpAddress));
1932               t4->t_port = s4->sin_port;
1933               t4->ipv4_addr = s4->sin_addr.s_addr;
1934               session->connect_addr = t4;
1935               session->connect_alen = sizeof (struct IPv4TcpAddress);
1936             }
1937           else if (alen == sizeof (struct sockaddr_in6))
1938             {
1939               s6 = vaddr;
1940               t6 = GNUNET_malloc (sizeof (struct IPv6TcpAddress));
1941               t6->t6_port = s6->sin6_port;
1942               memcpy (&t6->ipv6_addr,
1943                       &s6->sin6_addr,
1944                       sizeof (struct in6_addr));
1945               session->connect_addr = t6;
1946               session->connect_alen = sizeof (struct IPv6TcpAddress);
1947             }
1948
1949           GNUNET_free (vaddr);
1950         }
1951       else
1952         {
1953 #if DEBUG_TCP
1954           GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
1955                            "tcp",
1956                            "Did not obtain TCP socket address for incoming connection\n");
1957 #endif
1958         }
1959       process_pending_messages (session);
1960     }
1961   else
1962     {
1963 #if DEBUG_TCP_NAT
1964     if (GNUNET_OK ==
1965         GNUNET_SERVER_client_get_address (client, &vaddr, &alen))
1966       {
1967         GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
1968                          "tcp",
1969                          "Found address `%s' (already have session)\n",
1970                          GNUNET_a2s (vaddr, alen));
1971       }
1972 #endif
1973     }
1974
1975   if (session->expecting_welcome != GNUNET_YES)
1976     {
1977       GNUNET_break_op (0);
1978       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1979       return;
1980     }
1981   session->last_activity = GNUNET_TIME_absolute_get ();
1982   session->expecting_welcome = GNUNET_NO;
1983   GNUNET_SERVER_receive_done (client, GNUNET_OK);
1984 }
1985
1986
1987 /**
1988  * Task to signal the server that we can continue
1989  * receiving from the TCP client now.
1990  *
1991  * @param cls the 'struct Session*'
1992  * @param tc task context (unused)
1993  */
1994 static void
1995 delayed_done (void *cls, 
1996               const struct GNUNET_SCHEDULER_TaskContext *tc)
1997 {
1998   struct Session *session = cls;
1999   struct GNUNET_TIME_Relative delay;
2000
2001   session->receive_delay_task = GNUNET_SCHEDULER_NO_TASK;
2002   delay = session->plugin->env->receive (session->plugin->env->cls,
2003                                          &session->target,
2004                                          NULL, 0,
2005                                          session,
2006                                          NULL, 0);
2007   if (delay.rel_value == 0)
2008     GNUNET_SERVER_receive_done (session->client, GNUNET_OK);
2009   else
2010     session->receive_delay_task =
2011       GNUNET_SCHEDULER_add_delayed (delay, &delayed_done, session);
2012 }
2013
2014
2015 /**
2016  * We've received data for this peer via TCP.  Unbox,
2017  * compute latency and forward.
2018  *
2019  * @param cls closure
2020  * @param client identification of the client
2021  * @param message the actual message
2022  */
2023 static void
2024 handle_tcp_data (void *cls,
2025                  struct GNUNET_SERVER_Client *client,
2026                  const struct GNUNET_MessageHeader *message)
2027 {
2028   struct Plugin *plugin = cls;
2029   struct Session *session;
2030   struct GNUNET_TIME_Relative delay;
2031   uint16_t type;
2032
2033   type = ntohs (message->type);
2034   if ( (GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_WELCOME == type) || 
2035        (GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_NAT_PROBE == type) )
2036     {
2037       /* We don't want to propagate WELCOME and NAT Probe messages up! */
2038       GNUNET_SERVER_receive_done (client, GNUNET_OK);
2039       return;
2040     }
2041   session = find_session_by_client (plugin, client);
2042   if ( (NULL == session) || (GNUNET_YES == session->expecting_welcome) )
2043     {
2044       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2045       return;
2046     }
2047   session->last_activity = GNUNET_TIME_absolute_get ();
2048 #if DEBUG_TCP > 1
2049   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
2050                    "tcp",
2051                    "Passing %u bytes of type %u from `%4s' to transport service.\n",
2052                    (unsigned int) ntohs (message->size),
2053                    (unsigned int) ntohs (message->type),
2054                    GNUNET_i2s (&session->target));
2055 #endif
2056   GNUNET_STATISTICS_update (plugin->env->stats,
2057                             gettext_noop ("# bytes received via TCP"),
2058                             ntohs (message->size),
2059                             GNUNET_NO);
2060   delay = plugin->env->receive (plugin->env->cls, &session->target, message, 1,
2061                                 session,
2062                                 (GNUNET_YES == session->inbound) ? NULL : session->connect_addr,
2063                                 (GNUNET_YES == session->inbound) ? 0 : session->connect_alen);
2064   if (delay.rel_value == 0)
2065     GNUNET_SERVER_receive_done (client, GNUNET_OK);
2066   else
2067     session->receive_delay_task =
2068       GNUNET_SCHEDULER_add_delayed (delay, &delayed_done, session);
2069 }
2070
2071
2072 /**
2073  * Functions with this signature are called whenever a peer
2074  * is disconnected on the network level.
2075  *
2076  * @param cls closure
2077  * @param client identification of the client
2078  */
2079 static void
2080 disconnect_notify (void *cls,
2081                    struct GNUNET_SERVER_Client *client)
2082 {
2083   struct Plugin *plugin = cls;
2084   struct Session *session;
2085
2086   if (client == NULL)
2087     return;
2088   session = find_session_by_client (plugin, client);
2089   if (session == NULL)
2090     return;                     /* unknown, nothing to do */
2091 #if DEBUG_TCP
2092   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
2093                    "tcp",
2094                    "Destroying session of `%4s' with %s due to network-level disconnect.\n",
2095                    GNUNET_i2s (&session->target),
2096                    (session->connect_addr != NULL) ?
2097                    tcp_address_to_string (session->plugin,
2098                                           session->connect_addr,
2099                                           session->connect_alen) : "*");
2100 #endif
2101   disconnect_session (session);
2102 }
2103
2104
2105 /**
2106  * Add the IP of our network interface to the list of
2107  * our internal IP addresses.
2108  *
2109  * @param cls the 'struct Plugin*'
2110  * @param name name of the interface
2111  * @param isDefault do we think this may be our default interface
2112  * @param addr address of the interface
2113  * @param addrlen number of bytes in addr
2114  * @return GNUNET_OK to continue iterating
2115  */
2116 static int
2117 process_interfaces (void *cls,
2118                     const char *name,
2119                     int isDefault,
2120                     const struct sockaddr *addr, socklen_t addrlen)
2121 {
2122   struct Plugin *plugin = cls;
2123   int af;
2124   struct IPv4TcpAddress t4;
2125   struct IPv6TcpAddress t6;
2126   struct IPv4TcpAddress t4_nat;
2127   struct IPv6TcpAddress t6_nat;
2128   void *arg;
2129   uint16_t args;
2130   void *arg_nat;
2131   char buf[INET_ADDRSTRLEN];
2132
2133   af = addr->sa_family;
2134   arg_nat = NULL;
2135   switch (af)
2136     {
2137     case AF_INET:
2138       t4.ipv4_addr = ((struct sockaddr_in *) addr)->sin_addr.s_addr;
2139       GNUNET_assert (NULL != inet_ntop(AF_INET, 
2140                                        &t4.ipv4_addr, 
2141                                        buf, 
2142                                        sizeof (buf)));
2143       if ( (plugin->bind_address != NULL) && 
2144            (0 != strcmp(buf, plugin->bind_address)) )
2145         {
2146 #if DEBUG_TCP
2147           GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, 
2148                            "tcp",
2149                            "Not notifying transport of address `%s' (redundant)\n",
2150                            GNUNET_a2s (addr, addrlen));
2151 #endif
2152           return GNUNET_OK;
2153         }
2154       if ( (plugin->internal_address == NULL) &&
2155            (isDefault) )        
2156         plugin->internal_address = GNUNET_strdup (buf); 
2157       add_to_address_list (plugin, &t4.ipv4_addr, sizeof (struct in_addr));
2158       if (plugin->behind_nat == GNUNET_YES) 
2159         {
2160           /* Also advertise as NAT (with port 0) */
2161           t4_nat.ipv4_addr = ((struct sockaddr_in *) addr)->sin_addr.s_addr;
2162           t4_nat.t_port = htons(0);
2163           arg_nat = &t4_nat;
2164         }       
2165       t4.t_port = htons (plugin->adv_port);     
2166       arg = &t4;
2167       args = sizeof (t4);
2168       break;
2169     case AF_INET6:      
2170       if ( (IN6_IS_ADDR_LINKLOCAL (&((struct sockaddr_in6 *) addr)->sin6_addr)) || 
2171            (GNUNET_YES == GNUNET_CONFIGURATION_get_value_yesno(plugin->env->cfg, 
2172                                                                "transport-tcp", 
2173                                                                "DISABLEV6")) )
2174         {
2175           /* skip link local addresses */
2176           return GNUNET_OK;
2177         }
2178       memcpy (&t6.ipv6_addr,
2179               &((struct sockaddr_in6 *) addr)->sin6_addr,
2180               sizeof (struct in6_addr));
2181       add_to_address_list (plugin, 
2182                            &t6.ipv6_addr, 
2183                            sizeof (struct in6_addr));
2184       if (plugin->behind_nat == GNUNET_YES)
2185         {
2186           /* Also advertise as NAT (with port 0) */
2187           memcpy (&t6_nat.ipv6_addr,
2188                   &((struct sockaddr_in6 *) addr)->sin6_addr,
2189                   sizeof (struct in6_addr));
2190           t6_nat.t6_port = htons(0);
2191           arg_nat = &t6;
2192         }
2193       t6.t6_port = htons (plugin->adv_port);
2194       arg = &t6;
2195       args = sizeof (t6);
2196       break;
2197     default:
2198       GNUNET_break (0);
2199       return GNUNET_OK;
2200     }
2201 #if DEBUG_TCP
2202   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
2203                    "tcp",
2204                    "Found address `%s' (%s) len %d\n",
2205                    GNUNET_a2s (addr, addrlen), name, args);
2206 #endif
2207   plugin->env->notify_address (plugin->env->cls,
2208                                "tcp",
2209                                arg, args, GNUNET_TIME_UNIT_FOREVER_REL);
2210
2211   if (arg_nat != NULL)
2212     {
2213       GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
2214                        "tcp",
2215                        _("Found address `%s' (%s) len %d\n"),
2216                        GNUNET_a2s (addr, addrlen), name, args);
2217       plugin->env->notify_address (plugin->env->cls,
2218                                    "tcp",
2219                                    arg_nat, args, GNUNET_TIME_UNIT_FOREVER_REL);
2220     }
2221
2222   return GNUNET_OK;
2223 }
2224
2225
2226 /**
2227  * Function called by the resolver for each address obtained from DNS
2228  * for our own hostname.  Add the addresses to the list of our
2229  * external IP addresses.
2230  *
2231  * @param cls closure
2232  * @param addr one of the addresses of the host, NULL for the last address
2233  * @param addrlen length of the address
2234  */
2235 static void
2236 process_hostname_ips (void *cls,
2237                       const struct sockaddr *addr, socklen_t addrlen)
2238 {
2239   struct Plugin *plugin = cls;
2240
2241   if (addr == NULL)
2242     {
2243       plugin->hostname_dns = NULL;
2244       return;
2245     }
2246   /* FIXME: Can we figure out our external address here so it doesn't need to be user specified? */
2247   process_interfaces (plugin, "<hostname>", GNUNET_YES, addr, addrlen);
2248 }
2249
2250
2251 /**
2252  * We can now send a probe message, copy into buffer to really send.
2253  *
2254  * @param cls closure, a struct TCPProbeContext
2255  * @param size max size to copy
2256  * @param buf buffer to copy message to
2257  * @return number of bytes copied into buf
2258  */
2259 static size_t
2260 notify_send_probe (void *cls,
2261                    size_t size,
2262                    void *buf)
2263 {
2264   struct TCPProbeContext *tcp_probe_ctx = cls;
2265   struct Plugin *plugin = tcp_probe_ctx->plugin;
2266   size_t ret;
2267
2268   tcp_probe_ctx->transmit_handle = NULL;
2269   GNUNET_CONTAINER_DLL_remove (plugin->probe_head,
2270                                plugin->probe_tail,
2271                                tcp_probe_ctx);
2272   if (buf == NULL)
2273     {
2274       GNUNET_CONNECTION_destroy (tcp_probe_ctx->sock, GNUNET_NO);
2275       GNUNET_free(tcp_probe_ctx);
2276       return 0;    
2277     }
2278   GNUNET_assert(size >= sizeof(tcp_probe_ctx->message));
2279   memcpy(buf, &tcp_probe_ctx->message, sizeof(tcp_probe_ctx->message));
2280   GNUNET_SERVER_connect_socket (tcp_probe_ctx->plugin->server,
2281                                 tcp_probe_ctx->sock);
2282   ret = sizeof(tcp_probe_ctx->message);
2283   GNUNET_free(tcp_probe_ctx);
2284   return ret;
2285 }
2286
2287
2288 /**
2289  * We have been notified that gnunet-nat-server has written something to stdout.
2290  * Handle the output, then reschedule this function to be called again once
2291  * more is available.
2292  *
2293  * @param cls the plugin handle
2294  * @param tc the scheduling context
2295  */
2296 static void
2297 tcp_plugin_server_read (void *cls, 
2298                         const struct GNUNET_SCHEDULER_TaskContext *tc)
2299 {
2300   struct Plugin *plugin = cls;
2301   char mybuf[40];
2302   ssize_t bytes;
2303   size_t i;
2304   int port;
2305   const char *port_start;
2306   struct sockaddr_in sin_addr;
2307   struct TCPProbeContext *tcp_probe_ctx;
2308   struct GNUNET_CONNECTION_Handle *sock;
2309
2310   if (tc->reason == GNUNET_SCHEDULER_REASON_SHUTDOWN)
2311     return;
2312   memset (mybuf, 0, sizeof(mybuf));
2313   bytes = GNUNET_DISK_file_read(plugin->server_stdout_handle, 
2314                                 mybuf,
2315                                 sizeof(mybuf));
2316   if (bytes < 1)
2317     {
2318 #if DEBUG_TCP_NAT
2319       GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
2320                        "tcp",
2321                        "Finished reading from server stdout with code: %d\n", 
2322                        bytes);
2323 #endif
2324       return;
2325     }
2326
2327   port_start = NULL;
2328   for (i = 0; i < sizeof(mybuf); i++)
2329     {
2330       if (mybuf[i] == '\n')
2331         {
2332           mybuf[i] = '\0';
2333           break;
2334         }
2335       if ( (mybuf[i] == ':') && (i + 1 < sizeof(mybuf)) )
2336         {
2337           mybuf[i] = '\0';
2338           port_start = &mybuf[i + 1];
2339         }
2340     }
2341
2342   /* construct socket address of sender */
2343   memset (&sin_addr, 0, sizeof (sin_addr));
2344   sin_addr.sin_family = AF_INET;
2345   sin_addr.sin_port = htons((uint16_t) port);
2346 #if HAVE_SOCKADDR_IN_SIN_LEN
2347   sin_addr.sin_len = sizeof (sin_addr);
2348 #endif
2349   if ( (NULL == port_start) ||
2350        (1 != sscanf (port_start, "%d", &port)) ||
2351        (-1 == inet_pton(AF_INET, mybuf, &sin_addr.sin_addr)) )
2352     {
2353       /* should we restart gnunet-nat-server? */
2354       GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING,
2355                        "tcp",
2356                        _("gnunet-nat-server generated malformed address `%s'\n"),
2357                        mybuf);
2358       plugin->server_read_task 
2359         = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
2360                                           plugin->server_stdout_handle,
2361                                           &tcp_plugin_server_read, 
2362                                           plugin);
2363       return;
2364     }
2365
2366 #if DEBUG_TCP_NAT
2367   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
2368                    "tcp",
2369                    "gnunet-nat-server read: %s:%d\n", 
2370                    mybuf, port);
2371 #endif
2372
2373   /**
2374    * We have received an ICMP response, ostensibly from a peer
2375    * that wants to connect to us! Send a message to establish a connection.
2376    */
2377   sock = GNUNET_CONNECTION_create_from_sockaddr (AF_INET, 
2378                                                  (const struct sockaddr *)&sin_addr,
2379                                                  sizeof (sin_addr));
2380   if (sock == NULL)
2381     {
2382       /* failed for some odd reason (out of sockets?); ignore attempt */
2383       plugin->server_read_task =
2384           GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
2385                                           plugin->server_stdout_handle, 
2386                                           &tcp_plugin_server_read, 
2387                                           plugin);
2388       return;
2389     }
2390
2391   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
2392                    "Sending TCP probe message to `%s:%u'!\n", 
2393                    mybuf,
2394                    (unsigned int) port);  
2395   /* FIXME: do we need to track these probe context objects so that
2396      we can clean them up on plugin unload? */
2397   tcp_probe_ctx
2398     = GNUNET_malloc(sizeof(struct TCPProbeContext));
2399   tcp_probe_ctx->message.header.size
2400     = htons(sizeof(struct TCP_NAT_ProbeMessage));
2401   tcp_probe_ctx->message.header.type
2402     = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_NAT_PROBE);
2403   memcpy (&tcp_probe_ctx->message.clientIdentity,
2404           plugin->env->my_identity,
2405           sizeof(struct GNUNET_PeerIdentity));
2406   tcp_probe_ctx->plugin = plugin;
2407   tcp_probe_ctx->sock = sock;
2408   GNUNET_CONTAINER_DLL_insert (plugin->probe_head,
2409                                plugin->probe_tail,
2410                                tcp_probe_ctx);
2411   tcp_probe_ctx->transmit_handle 
2412     = GNUNET_CONNECTION_notify_transmit_ready (sock,
2413                                                ntohs (tcp_probe_ctx->message.header.size),
2414                                                GNUNET_TIME_UNIT_FOREVER_REL,
2415                                                &notify_send_probe, tcp_probe_ctx);
2416   
2417   plugin->server_read_task =
2418       GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
2419                                       plugin->server_stdout_handle,
2420                                       &tcp_plugin_server_read,
2421                                       plugin);
2422 }
2423
2424
2425 /**
2426  * Start the gnunet-nat-server process for users behind NAT.
2427  *
2428  * @param plugin the transport plugin
2429  * @return GNUNET_YES if process was started, GNUNET_SYSERR on error
2430  */
2431 static int
2432 tcp_transport_start_nat_server (struct Plugin *plugin)
2433 {
2434   if (plugin->internal_address == NULL)
2435     return GNUNET_SYSERR;
2436   plugin->server_stdout = GNUNET_DISK_pipe (GNUNET_YES,
2437                                             GNUNET_NO,
2438                                             GNUNET_YES);
2439   if (plugin->server_stdout == NULL)
2440     return GNUNET_SYSERR;
2441 #if DEBUG_TCP_NAT
2442   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
2443                    "tcp"
2444                    "Starting %s %s\n", 
2445                    "gnunet-nat-server", 
2446                    plugin->internal_address);
2447 #endif
2448   /* Start the server process */
2449   plugin->server_proc = GNUNET_OS_start_process (NULL,
2450                                                  plugin->server_stdout,
2451                                                  "gnunet-nat-server", 
2452                                                  "gnunet-nat-server", 
2453                                                  plugin->internal_address, 
2454                                                  NULL);
2455   if (plugin->server_proc == NULL)
2456     {
2457       GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING,
2458                        "tcp",
2459                        _("Failed to start %s\n"),
2460                        "gnunet-nat-server");
2461       GNUNET_DISK_pipe_close (plugin->server_stdout);
2462       plugin->server_stdout = NULL;    
2463       return GNUNET_SYSERR;
2464     }
2465   /* Close the write end of the read pipe */
2466   GNUNET_DISK_pipe_close_end(plugin->server_stdout, 
2467                              GNUNET_DISK_PIPE_END_WRITE);
2468   plugin->server_stdout_handle 
2469     = GNUNET_DISK_pipe_handle (plugin->server_stdout, 
2470                                GNUNET_DISK_PIPE_END_READ);
2471   plugin->server_read_task 
2472     = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
2473                                       plugin->server_stdout_handle,
2474                                       &tcp_plugin_server_read, 
2475                                       plugin);
2476   return GNUNET_YES;
2477 }
2478
2479
2480 /**
2481  * Return the actual path to a file found in the current
2482  * PATH environment variable.
2483  *
2484  * @param binary the name of the file to find
2485  * @return path to binary, NULL if not found
2486  */
2487 static char *
2488 get_path_from_PATH (const char *binary)
2489 {
2490   char *path;
2491   char *pos;
2492   char *end;
2493   char *buf;
2494   const char *p;
2495
2496   p = getenv ("PATH");
2497   if (p == NULL)
2498     {
2499       GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR,
2500                        "tcp",
2501                        _("PATH environment variable is unset.\n"));
2502       return NULL;
2503     }
2504   path = GNUNET_strdup (p);     /* because we write on it */
2505   buf = GNUNET_malloc (strlen (path) + 20);
2506   pos = path;
2507
2508   while (NULL != (end = strchr (pos, PATH_SEPARATOR)))
2509     {
2510       *end = '\0';
2511       sprintf (buf, "%s/%s", pos, binary);
2512       if (GNUNET_DISK_file_test (buf) == GNUNET_YES)
2513         {
2514           GNUNET_free (path);
2515           return buf;
2516         }
2517       pos = end + 1;
2518     }
2519   sprintf (buf, "%s/%s", pos, binary);
2520   if (GNUNET_DISK_file_test (buf) == GNUNET_YES)
2521     {
2522       GNUNET_free (path);
2523       return buf;
2524     }
2525   GNUNET_free (buf);
2526   GNUNET_free (path);
2527   return NULL;
2528 }
2529
2530
2531 /**
2532  * Check whether the suid bit is set on a file.
2533  * Attempts to find the file using the current
2534  * PATH environment variable as a search path.
2535  *
2536  * @param binary the name of the file to check
2537  * @return GNUNET_YES if the file is SUID, 
2538  *         GNUNET_NO if not, 
2539  *         GNUNET_SYSERR on error
2540  */
2541 static int
2542 check_gnunet_nat_binary (const char *binary)
2543 {
2544   struct stat statbuf;
2545   char *p;
2546 #ifdef MINGW
2547   SOCKET rawsock;
2548   char *binaryexe;
2549
2550   GNUNET_asprintf (&binaryexe, "%s.exe", binary);
2551   p = get_path_from_PATH (binaryexe);
2552   free (binaryexe);
2553 #else
2554   p = get_path_from_PATH (binary);
2555 #endif
2556   if (p == NULL)
2557     {
2558       GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR,
2559                        "tcp",
2560                        _("Could not find binary `%s' in PATH!\n"),
2561                        binary);
2562       return GNUNET_NO;
2563     }
2564   if (0 != STAT (p, &statbuf))
2565     {
2566       GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 
2567                   _("stat (%s) failed: %s\n"), 
2568                   p,
2569                   STRERROR (errno));
2570       GNUNET_free (p);
2571       return GNUNET_SYSERR;
2572     }
2573   GNUNET_free (p);
2574 #ifndef MINGW
2575   if ( (0 != (statbuf.st_mode & S_ISUID)) &&
2576        (statbuf.st_uid == 0) )
2577     return GNUNET_YES;
2578   return GNUNET_NO;
2579 #else
2580   rawsock = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP);
2581   if (INVALID_SOCKET == rawsock)
2582     {
2583       DWORD err = GetLastError ();
2584       GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, 
2585                        "tcp",
2586                        "socket (AF_INET, SOCK_RAW, IPPROTO_ICMP) failed! GLE = %d\n", err);
2587       return GNUNET_NO; /* not running as administrator */
2588     }
2589   closesocket (rawsock);
2590   return GNUNET_YES;
2591 #endif
2592 }
2593
2594
2595 /**
2596  * Entry point for the plugin.
2597  *
2598  * @param cls closure, the 'struct GNUNET_TRANSPORT_PluginEnvironment*'
2599  * @return the 'struct GNUNET_TRANSPORT_PluginFunctions*' or NULL on error
2600  */
2601 void *
2602 libgnunet_plugin_transport_tcp_init (void *cls)
2603 {
2604   static const struct GNUNET_SERVER_MessageHandler my_handlers[] = {
2605     {&handle_tcp_welcome, NULL, GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_WELCOME,
2606      sizeof (struct WelcomeMessage)},
2607     {&handle_tcp_nat_probe, NULL, GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_NAT_PROBE, sizeof (struct TCP_NAT_ProbeMessage)},
2608     {&handle_tcp_data, NULL, GNUNET_MESSAGE_TYPE_ALL, 0},
2609     {NULL, NULL, 0, 0}
2610   };
2611   struct GNUNET_TRANSPORT_PluginEnvironment *env = cls;
2612   struct GNUNET_TRANSPORT_PluginFunctions *api;
2613   struct Plugin *plugin;
2614   struct GNUNET_SERVICE_Context *service;
2615   unsigned long long aport;
2616   unsigned long long bport;
2617   unsigned int i;
2618   int behind_nat;
2619   int allow_nat;
2620   char *internal_address;
2621   char *external_address;
2622   struct sockaddr_in in_addr;
2623   struct IPv4TcpAddress t4;
2624   struct GNUNET_TIME_Relative idle_timeout;
2625
2626   behind_nat = GNUNET_CONFIGURATION_get_value_yesno (env->cfg,
2627                                                      "transport-tcp",
2628                                                      "BEHIND_NAT");
2629   if ( (GNUNET_YES == behind_nat) &&
2630        (GNUNET_YES != check_gnunet_nat_binary("gnunet-nat-server")) )
2631     {
2632       behind_nat = GNUNET_NO;
2633       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2634                   _("Configuration requires `%s', but binary is not installed properly (SUID bit not set).  Option disabled.\n"),
2635                   "gnunet-nat-server");        
2636     }
2637
2638   allow_nat = GNUNET_CONFIGURATION_get_value_yesno (env->cfg,
2639                                                     "transport-tcp",
2640                                                     "ALLOW_NAT");
2641   if ( (GNUNET_YES == allow_nat) &&
2642        (GNUNET_YES != check_gnunet_nat_binary("gnunet-nat-client")) )
2643     {
2644       allow_nat = GNUNET_NO;
2645       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2646                   _("Configuration requires `%s', but binary is not installed properly (SUID bit not set).  Option disabled.\n"),
2647                   "gnunet-nat-client"); 
2648     }
2649   
2650   external_address = NULL;
2651   if (GNUNET_OK ==
2652       GNUNET_CONFIGURATION_have_value (env->cfg,
2653                                        "transport-tcp",
2654                                        "EXTERNAL_ADDRESS"))
2655     {
2656       (void) GNUNET_CONFIGURATION_get_value_string (env->cfg,
2657                                                     "transport-tcp",
2658                                                     "EXTERNAL_ADDRESS",
2659                                                     &external_address);
2660     }
2661
2662   if ( (external_address != NULL) && 
2663        (inet_pton(AF_INET, external_address, &in_addr.sin_addr) != 1) ) 
2664     {
2665       GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING,
2666                        "tcp",
2667                        _("Malformed %s `%s' given in configuration!\n"), 
2668                        "EXTERNAL_ADDRESS",
2669                        external_address);
2670       return NULL;   
2671     }
2672
2673   internal_address = NULL;
2674   if (GNUNET_OK ==
2675       GNUNET_CONFIGURATION_have_value (env->cfg,
2676                                        "transport-tcp",
2677                                        "INTERNAL_ADDRESS"))
2678     {
2679       (void) GNUNET_CONFIGURATION_get_value_string (env->cfg,
2680                                                     "transport-tcp",
2681                                                     "INTERNAL_ADDRESS",
2682                                                     &internal_address);
2683     }
2684
2685   if ( (internal_address != NULL) && 
2686        (inet_pton(AF_INET, internal_address, &in_addr.sin_addr) != 1) )
2687     {
2688       GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING,
2689                        "tcp",
2690                        _("Malformed %s `%s' given in configuration!\n"), 
2691                        "INTERNAL_ADDRESS",
2692                        internal_address);      
2693       GNUNET_free_non_null(internal_address);
2694       GNUNET_free_non_null(external_address);
2695       return NULL;
2696     }
2697
2698   aport = 0;
2699   if ( (GNUNET_OK !=
2700         GNUNET_CONFIGURATION_get_value_number (env->cfg,
2701                                                "transport-tcp",
2702                                                "PORT",
2703                                                &bport)) ||
2704        (bport > 65535) ||
2705        ((GNUNET_OK ==
2706          GNUNET_CONFIGURATION_get_value_number (env->cfg,
2707                                                 "transport-tcp",
2708                                                 "ADVERTISED-PORT",
2709                                                 &aport)) && 
2710         (aport > 65535)) )
2711     {
2712       GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR,
2713                        "tcp",
2714                        _("Require valid port number for service `%s' in configuration!\n"),
2715                        "transport-tcp");
2716       GNUNET_free_non_null(external_address);
2717       GNUNET_free_non_null(internal_address);
2718       return NULL;
2719     }
2720
2721   if (aport == 0)
2722     aport = bport;
2723   if (bport == 0)
2724     aport = 0;
2725
2726   if (bport != 0)
2727     {
2728       service = GNUNET_SERVICE_start ("transport-tcp", env->cfg);
2729       if (service == NULL)
2730         {
2731           GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING,
2732                            "tcp",
2733                            _("Failed to start service.\n"));
2734           return NULL;
2735         }
2736     }
2737   else
2738     service = NULL;
2739
2740   plugin = GNUNET_malloc (sizeof (struct Plugin));
2741   plugin->open_port = bport;
2742   plugin->adv_port = aport;
2743   plugin->external_address = external_address;
2744   plugin->internal_address = internal_address;
2745   plugin->behind_nat = behind_nat;
2746   plugin->allow_nat = allow_nat;
2747   plugin->allow_upnp = GNUNET_CONFIGURATION_get_value_yesno (env->cfg,
2748                                                              "transport-tcp",
2749                                                              "ENABLE_UPNP");
2750   plugin->env = env;
2751   plugin->lsock = NULL;
2752   api = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_PluginFunctions));
2753   api->cls = plugin;
2754   api->send = &tcp_plugin_send;
2755   api->disconnect = &tcp_plugin_disconnect;
2756   api->address_pretty_printer = &tcp_plugin_address_pretty_printer;
2757   api->check_address = &tcp_plugin_check_address;
2758   api->address_to_string = &tcp_address_to_string;
2759   plugin->service = service;
2760   if (service != NULL)   
2761     {
2762       plugin->server = GNUNET_SERVICE_get_server (service);
2763     }
2764   else
2765     {
2766       if (GNUNET_OK !=
2767           GNUNET_CONFIGURATION_get_value_time (env->cfg,
2768                                                "transport-tcp",
2769                                                "TIMEOUT",
2770                                                &idle_timeout))
2771         {
2772           GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR,
2773                            "tcp",
2774                            _("Failed to find option %s in section %s!\n"),
2775                            "TIMEOUT",
2776                            "transport-tcp");
2777           GNUNET_free_non_null(external_address);
2778           GNUNET_free_non_null(internal_address);
2779           GNUNET_free (api);
2780           return NULL;
2781         }
2782       plugin->server = GNUNET_SERVER_create_with_sockets (NULL, NULL, NULL,
2783                                                           idle_timeout, GNUNET_YES);
2784     }
2785   plugin->handlers = GNUNET_malloc (sizeof (my_handlers));
2786   memcpy (plugin->handlers, my_handlers, sizeof (my_handlers));
2787   for (i = 0;
2788        i < sizeof (my_handlers) / sizeof (struct GNUNET_SERVER_MessageHandler);
2789        i++)
2790     plugin->handlers[i].callback_cls = plugin;
2791   GNUNET_SERVER_add_handlers (plugin->server, plugin->handlers);
2792   GNUNET_SERVER_disconnect_notify (plugin->server,
2793                                    &disconnect_notify,
2794                                    plugin);    
2795   GNUNET_OS_network_interfaces_list (&process_interfaces, plugin);
2796
2797   if ( (plugin->behind_nat == GNUNET_YES) &&
2798        (GNUNET_YES != tcp_transport_start_nat_server(plugin)) )
2799     {
2800       GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR,
2801                        "tcp",
2802                        _("Failed to start %s required for NAT in %s!\n"),
2803                        "gnunet-nat-server"
2804                        "transport-tcp");
2805       GNUNET_free_non_null(external_address);
2806       GNUNET_free_non_null(internal_address);
2807       if (service != NULL)
2808         GNUNET_SERVICE_stop (service);
2809       else
2810         GNUNET_SERVER_destroy (plugin->server);
2811       GNUNET_free (api);
2812       return NULL;
2813     }
2814
2815   if (allow_nat == GNUNET_YES)
2816     {
2817       plugin->nat_wait_conns = GNUNET_CONTAINER_multihashmap_create(16);
2818       GNUNET_assert (plugin->nat_wait_conns != NULL);
2819     }
2820
2821   if (bport != 0)
2822     GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, 
2823                      "tcp",
2824                      _("TCP transport listening on port %llu\n"), 
2825                      bport);
2826   else
2827     GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, 
2828                      "tcp",
2829                      _("TCP transport not listening on any port (client only)\n"));
2830   if (aport != bport)
2831     GNUNET_log_from (GNUNET_ERROR_TYPE_INFO,
2832                      "tcp",
2833                      _("TCP transport advertises itself as being on port %llu\n"),
2834                      aport);
2835
2836   if (GNUNET_YES == GNUNET_CONFIGURATION_get_value_string (env->cfg,
2837                                                            "transport-tcp", 
2838                                                            "BINDTO", 
2839                                                            &plugin->bind_address))
2840     {
2841       GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, 
2842                        "tcp",
2843                        _("Binding TCP plugin to specific address: `%s'\n"), 
2844                        plugin->bind_address);
2845     }
2846
2847   plugin->hostname_dns = GNUNET_RESOLVER_hostname_resolve (env->cfg,
2848                                                            AF_UNSPEC,
2849                                                            HOSTNAME_RESOLVE_TIMEOUT,
2850                                                            &process_hostname_ips,
2851                                                            plugin);
2852
2853   if ( (plugin->external_address != NULL) && 
2854        (inet_pton(AF_INET,
2855                   plugin->external_address, 
2856                   &t4.ipv4_addr) == 1) )
2857     {
2858       if (plugin->behind_nat == GNUNET_YES) 
2859         {
2860           GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, 
2861                            "tcp",
2862                            "Notifying transport of address %s:0\n", 
2863                            plugin->external_address);
2864           t4.t_port = htons(0);
2865         }
2866       else
2867         {
2868           t4.t_port = htons(plugin->adv_port);
2869           GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, 
2870                            "tcp",
2871                            "Notifying transport of address %s:%d\n",
2872                            plugin->external_address, 
2873                            plugin->adv_port);
2874         }
2875       add_to_address_list (plugin, &t4.ipv4_addr, sizeof (struct in_addr));
2876       plugin->env->notify_address (plugin->env->cls,
2877                                    "tcp",
2878                                    &t4, sizeof(t4), GNUNET_TIME_UNIT_FOREVER_REL);
2879     }
2880   return api;
2881 }
2882
2883
2884 /**
2885  * Exit point from the plugin.
2886  */
2887 void *
2888 libgnunet_plugin_transport_tcp_done (void *cls)
2889 {
2890   struct GNUNET_TRANSPORT_PluginFunctions *api = cls;
2891   struct Plugin *plugin = api->cls;
2892   struct Session *session;
2893   struct LocalAddrList *lal;
2894   struct TCPProbeContext *tcp_probe;
2895
2896   while (NULL != (session = plugin->sessions))
2897     disconnect_session (session);
2898   if (NULL != plugin->hostname_dns)
2899     {
2900       GNUNET_RESOLVER_request_cancel (plugin->hostname_dns);
2901       plugin->hostname_dns = NULL;
2902     }
2903   if (plugin->service != NULL)
2904     GNUNET_SERVICE_stop (plugin->service);
2905   else
2906     GNUNET_SERVER_destroy (plugin->server);
2907   GNUNET_free (plugin->handlers);
2908   while (NULL != (lal = plugin->lal_head))
2909     {
2910       GNUNET_CONTAINER_DLL_remove (plugin->lal_head,
2911                                    plugin->lal_tail,
2912                                    lal);
2913       if (lal->nat != NULL)
2914         GNUNET_NAT_unregister (lal->nat);
2915       GNUNET_free_non_null (lal->external_nat_address);
2916       GNUNET_free (lal);
2917     }
2918   while (NULL != (tcp_probe = plugin->probe_head))
2919     {
2920       GNUNET_CONTAINER_DLL_remove (plugin->probe_head,
2921                                    plugin->probe_tail,
2922                                    tcp_probe);
2923       GNUNET_CONNECTION_destroy (tcp_probe->sock, GNUNET_NO);
2924       GNUNET_free (tcp_probe);
2925     }
2926
2927   if (plugin->behind_nat == GNUNET_YES)
2928     {
2929       if (0 != GNUNET_OS_process_kill (plugin->server_proc, SIGTERM))
2930         GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill");
2931       GNUNET_OS_process_wait (plugin->server_proc);
2932       GNUNET_OS_process_close (plugin->server_proc);
2933       plugin->server_proc = NULL;
2934     }
2935   GNUNET_free_non_null(plugin->bind_address);
2936   GNUNET_free (plugin);
2937   GNUNET_free (api);
2938   return NULL;
2939 }
2940
2941 /* end of plugin_transport_tcp.c */