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