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