glitch in the license text detected by hyazinthe, thank you!
[oweals/gnunet.git] / src / transport / plugin_transport_xt.c
1 /*
2   This file is part of GNUnet
3   Copyright (C) 2002--2015 GNUnet e.V.
4
5   GNUnet is free software: you can redistribute it and/or modify it
6   under the terms of the GNU Affero General Public License as published
7   by the Free Software Foundation, either version 3 of the License,
8   or (at your 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   Affero General Public License for more details.
14  */
15 /**
16  * @file transport/plugin_transport_xt.c
17  * @brief Implementation of the TCP transport service
18  * @author Christian Grothoff
19  */
20 #include "platform.h"
21 #include "gnunet_hello_lib.h"
22 #include "gnunet_constants.h"
23 #include "gnunet_util_lib.h"
24 #include "gnunet_nat_service.h"
25 #include "gnunet_protocols.h"
26 #include "gnunet_resolver_service.h"
27 #include "gnunet_signatures.h"
28 #include "gnunet_statistics_service.h"
29 #include "gnunet_transport_service.h"
30 #include "gnunet_transport_plugin.h"
31 #include "transport.h"
32
33 #define LOG(kind,...) GNUNET_log_from (kind, "transport-xt",__VA_ARGS__)
34
35 #define PLUGIN_NAME "xt"
36
37 /**
38  * How long until we give up on establishing an NAT connection?
39  * Must be > 4 RTT
40  */
41 #define NAT_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10)
42
43 /**
44  * Opaque handle that can be used to cancel
45  * a transmit-ready notification.
46  */
47 struct GNUNET_CONNECTION_TransmitHandle;
48
49 /**
50  * @brief handle for a server
51  */
52 struct GNUNET_SERVER_Handle;
53
54 /**
55  * @brief opaque handle for a client of the server
56  */
57 struct GNUNET_SERVER_Client;
58
59 /**
60  * @brief opaque handle server returns for aborting transmission to a client.
61  */
62 struct GNUNET_SERVER_TransmitHandle;
63
64 /**
65  * @brief handle for a network connection
66  */
67 struct GNUNET_CONNECTION_Handle;
68
69 /**
70  * @brief handle for a network service
71  */
72 struct LEGACY_SERVICE_Context;
73
74
75 /**
76  * Stops a service that was started with #GNUNET_SERVICE_start().
77  *
78  * @param srv service to stop
79  */
80 void
81 LEGACY_SERVICE_stop (struct LEGACY_SERVICE_Context *srv);
82
83
84
85 /**
86  * Function called to notify a client about the connection begin ready
87  * to queue more data.  @a buf will be NULL and @a size zero if the
88  * connection was closed for writing in the meantime.
89  *
90  * @param cls closure
91  * @param size number of bytes available in @a buf
92  * @param buf where the callee should write the message
93  * @return number of bytes written to @a buf
94  */
95 typedef size_t
96 (*GNUNET_CONNECTION_TransmitReadyNotify) (void *cls,
97                                           size_t size,
98                                           void *buf);
99
100 /**
101  * Credentials for UNIX domain sockets.
102  */
103 struct GNUNET_CONNECTION_Credentials
104 {
105   /**
106    * UID of the other end of the connection.
107    */
108   uid_t uid;
109
110   /**
111    * GID of the other end of the connection.
112    */
113   gid_t gid;
114 };
115
116
117 /**
118  * Functions with this signature are called whenever a client
119  * is disconnected on the network level.
120  *
121  * @param cls closure
122  * @param client identification of the client; NULL
123  *        for the last call when the server is destroyed
124  */
125 typedef void
126 (*GNUNET_SERVER_DisconnectCallback) (void *cls,
127                                      struct GNUNET_SERVER_Client *client);
128
129
130 /**
131  * Functions with this signature are called whenever a client
132  * is connected on the network level.
133  *
134  * @param cls closure
135  * @param client identification of the client
136  */
137 typedef void
138 (*GNUNET_SERVER_ConnectCallback) (void *cls,
139                                   struct GNUNET_SERVER_Client *client);
140
141
142
143
144 /**
145  * Function to call for access control checks.
146  *
147  * @param cls closure
148  * @param ucred credentials, if available, otherwise NULL
149  * @param addr address
150  * @param addrlen length of address
151  * @return GNUNET_YES to allow, GNUNET_NO to deny, GNUNET_SYSERR
152  *   for unknown address family (will be denied).
153  */
154 typedef int
155 (*GNUNET_CONNECTION_AccessCheck) (void *cls,
156                                   const struct
157                                   GNUNET_CONNECTION_Credentials *
158                                   ucred,
159                                   const struct sockaddr * addr,
160                                   socklen_t addrlen);
161
162 /**
163  * Callback function for data received from the network.  Note that
164  * both "available" and "err" would be 0 if the read simply timed out.
165  *
166  * @param cls closure
167  * @param buf pointer to received data
168  * @param available number of bytes availabe in "buf",
169  *        possibly 0 (on errors)
170  * @param addr address of the sender
171  * @param addrlen size of addr
172  * @param errCode value of errno (on errors receiving)
173  */
174 typedef void
175 (*GNUNET_CONNECTION_Receiver) (void *cls, const void *buf,
176                                size_t available,
177                                const struct sockaddr * addr,
178                                socklen_t addrlen, int errCode);
179
180
181
182 /**
183  * Close the connection and free associated resources.  There must
184  * not be any pending requests for reading or writing to the
185  * connection at this time.
186  *
187  * @param connection connection to destroy
188  */
189 void
190 GNUNET_CONNECTION_destroy (struct GNUNET_CONNECTION_Handle *connection);
191
192
193 /**
194  * Signature of a function to create a custom tokenizer.
195  *
196  * @param cls closure from #GNUNET_SERVER_set_callbacks
197  * @param client handle to client the tokenzier will be used for
198  * @return handle to custom tokenizer ('mst')
199  */
200 typedef void*
201 (*GNUNET_SERVER_MstCreateCallback) (void *cls,
202                                     struct GNUNET_SERVER_Client *client);
203
204
205 /**
206  * Signature of a function to destroy a custom tokenizer.
207  *
208  * @param cls closure from #GNUNET_SERVER_set_callbacks
209  * @param mst custom tokenizer handle
210  */
211 typedef void
212 (*GNUNET_SERVER_MstDestroyCallback) (void *cls,
213                                      void *mst);
214
215 /**
216  * Signature of a function to receive data for a custom tokenizer.
217  *
218  * @param cls closure from #GNUNET_SERVER_set_callbacks
219  * @param mst custom tokenizer handle
220  * @param client_identity ID of client for which this is a buffer,
221  *        can be NULL (will be passed back to 'cb')
222  * @param buf input data to add
223  * @param size number of bytes in @a buf
224  * @param purge should any excess bytes in the buffer be discarded
225  *       (i.e. for packet-based services like UDP)
226  * @param one_shot only call callback once, keep rest of message in buffer
227  * @return #GNUNET_OK if we are done processing (need more data)
228  *         #GNUNET_NO if one_shot was set and we have another message ready
229  *         #GNUNET_SYSERR if the data stream is corrupt
230  */
231 typedef int
232 (*GNUNET_SERVER_MstReceiveCallback) (void *cls, void *mst,
233                                      struct GNUNET_SERVER_Client *client,
234                                      const char *buf,
235                                      size_t size,
236                                      int purge,
237                                      int one_shot);
238 /**
239  * Functions with this signature are called whenever a message is
240  * received.
241  *
242  * @param cls closure
243  * @param client identification of the client
244  * @param message the actual message
245  */
246 typedef void
247 (*GNUNET_SERVER_MessageCallback) (void *cls,
248                                   struct GNUNET_SERVER_Client *client,
249                                   const struct GNUNET_MessageHeader *message);
250
251 /**
252  * Message handler.  Each struct specifies how to handle on particular
253  * type of message received.
254  */
255 struct GNUNET_SERVER_MessageHandler
256 {
257   /**
258    * Function to call for messages of "type".
259    */
260   GNUNET_SERVER_MessageCallback callback;
261
262   /**
263    * Closure argument for @e callback.
264    */
265   void *callback_cls;
266
267   /**
268    * Type of the message this handler covers.
269    */
270   uint16_t type;
271
272   /**
273    * Expected size of messages of this type.  Use 0 for
274    * variable-size.  If non-zero, messages of the given
275    * type will be discarded (and the connection closed)
276    * if they do not have the right size.
277    */
278   uint16_t expected_size;
279
280 };
281
282
283 /**
284  * Options for the service (bitmask).
285  */
286 enum LEGACY_SERVICE_Options
287 {
288   /**
289    * Use defaults.  Terminates all client connections and the listen
290    * sockets immediately upon receiving the shutdown signal.
291    */
292   LEGACY_SERVICE_OPTION_NONE = 0,
293
294   /**
295    * Do not trigger server shutdown on signal at all; instead, allow
296    * for the user to terminate the server explicitly when needed
297    * by calling #LEGACY_SERVICE_shutdown().
298    */
299   LEGACY_SERVICE_OPTION_MANUAL_SHUTDOWN = 1,
300
301   /**
302    * Trigger a SOFT server shutdown on signals, allowing active
303    * non-monitor clients to complete their transactions.
304    */
305   LEGACY_SERVICE_OPTION_SOFT_SHUTDOWN = 2
306 };
307
308
309
310 /**
311  * Ask the server to disconnect from the given client.  This is the
312  * same as passing #GNUNET_SYSERR to #GNUNET_SERVER_receive_done,
313  * except that it allows dropping of a client even when not handling a
314  * message from that client.
315  *
316  * @param client the client to disconnect from
317  */
318 void
319 GNUNET_SERVER_client_disconnect (struct GNUNET_SERVER_Client *client);
320
321 /**
322  * Return user context associated with the given client.
323  * Note: you should probably use the macro (call without the underscore).
324  *
325  * @param client client to query
326  * @param size number of bytes in user context struct (for verification only)
327  * @return pointer to user context
328  */
329 void *
330 GNUNET_SERVER_client_get_user_context_ (struct GNUNET_SERVER_Client *client,
331                                         size_t size);
332
333
334 /**
335  * Functions with this signature are called whenever a
336  * complete message is received by the tokenizer.
337  *
338  * Do not call #GNUNET_SERVER_mst_destroy from within
339  * the scope of this callback.
340  *
341  * @param cls closure
342  * @param client identification of the client
343  * @param message the actual message
344  * @return #GNUNET_OK on success, #GNUNET_SYSERR to stop further processing
345  */
346 typedef int
347 (*GNUNET_SERVER_MessageTokenizerCallback) (void *cls,
348                                            void *client,
349                                            const struct GNUNET_MessageHeader *message);
350
351
352 /**
353  * Create a message stream tokenizer.
354  *
355  * @param cb function to call on completed messages
356  * @param cb_cls closure for @a cb
357  * @return handle to tokenizer
358  */
359 struct GNUNET_SERVER_MessageStreamTokenizer *
360 GNUNET_SERVER_mst_create (GNUNET_SERVER_MessageTokenizerCallback cb,
361                           void *cb_cls);
362
363 /**
364  * Add incoming data to the receive buffer and call the
365  * callback for all complete messages.
366  *
367  * @param mst tokenizer to use
368  * @param client_identity ID of client for which this is a buffer,
369  *        can be NULL (will be passed back to 'cb')
370  * @param buf input data to add
371  * @param size number of bytes in @a buf
372  * @param purge should any excess bytes in the buffer be discarded
373  *       (i.e. for packet-based services like UDP)
374  * @param one_shot only call callback once, keep rest of message in buffer
375  * @return #GNUNET_OK if we are done processing (need more data)
376  *         #GNUNET_NO if one_shot was set and we have another message ready
377  *         #GNUNET_SYSERR if the data stream is corrupt
378  */
379 int
380 GNUNET_SERVER_mst_receive (struct GNUNET_SERVER_MessageStreamTokenizer *mst,
381                            void *client_identity,
382                            const char *buf, size_t size,
383                            int purge, int one_shot);
384
385
386
387 /**
388  * Destroys a tokenizer.
389  *
390  * @param mst tokenizer to destroy
391  */
392 void
393 GNUNET_SERVER_mst_destroy (struct GNUNET_SERVER_MessageStreamTokenizer *mst);
394
395
396 /**
397  * Set user context to be associated with the given client.
398  * Note: you should probably use the macro (call without the underscore).
399  *
400  * @param client client to query
401  * @param ptr pointer to user context
402  * @param size number of bytes in user context struct (for verification only)
403  */
404 void
405 GNUNET_SERVER_client_set_user_context_ (struct GNUNET_SERVER_Client *client,
406                                         void *ptr,
407                                         size_t size);
408 /**
409  * Return user context associated with the given client.
410  *
411  * @param client client to query
412  * @param type expected return type (i.e. 'struct Foo')
413  * @return pointer to user context of type 'type *'.
414  */
415 #define GNUNET_SERVER_client_get_user_context(client,type)              \
416   (type *) GNUNET_SERVER_client_get_user_context_ (client, sizeof (type))
417
418 /**
419  * Set user context to be associated with the given client.
420  *
421  * @param client client to query
422  * @param value pointer to user context
423  */
424 #define GNUNET_SERVER_client_set_user_context(client,value)             \
425   GNUNET_SERVER_client_set_user_context_ (client, value, sizeof (*value))
426
427
428
429 /**
430  * Notify us when the server has enough space to transmit
431  * a message of the given size to the given client.
432  *
433  * @param client client to transmit message to
434  * @param size requested amount of buffer space
435  * @param timeout after how long should we give up (and call
436  *        notify with buf NULL and size 0)?
437  * @param callback function to call when space is available
438  * @param callback_cls closure for @a callback
439  * @return non-NULL if the notify callback was queued; can be used
440  *           to cancel the request using
441  *           #GNUNET_SERVER_notify_transmit_ready_cancel.
442  *         NULL if we are already going to notify someone else (busy)
443  */
444 struct GNUNET_SERVER_TransmitHandle *
445 GNUNET_SERVER_notify_transmit_ready (struct GNUNET_SERVER_Client *client,
446                                      size_t size,
447                                      struct GNUNET_TIME_Relative timeout,
448                                      GNUNET_CONNECTION_TransmitReadyNotify callback,
449                                      void *callback_cls);
450
451 /**
452  * Abort transmission request.
453  *
454  * @param th request to abort
455  */
456 void
457 GNUNET_SERVER_notify_transmit_ready_cancel (struct GNUNET_SERVER_TransmitHandle *th);
458
459
460
461
462 /**
463  * Notify the server that the given client handle should
464  * be kept (keeps the connection up if possible, increments
465  * the internal reference counter).
466  *
467  * @param client the client to keep
468  */
469 void
470 GNUNET_SERVER_client_keep (struct GNUNET_SERVER_Client *client);
471
472
473 /**
474  * Notify the server that the given client handle is no
475  * longer required.  Decrements the reference counter.  If
476  * that counter reaches zero an inactive connection maybe
477  * closed.
478  *
479  * @param client the client to drop
480  */
481 void
482 GNUNET_SERVER_client_drop (struct GNUNET_SERVER_Client *client);
483
484
485 /**
486  * Function called by the service's run
487  * method to run service-specific setup code.
488  *
489  * @param cls closure
490  * @param server the initialized server
491  * @param cfg configuration to use
492  */
493 typedef void
494 (*LEGACY_SERVICE_Main) (void *cls,
495                         struct GNUNET_SERVER_Handle *server,
496                         const struct GNUNET_CONFIGURATION_Handle *cfg);
497
498
499
500 /**
501  * Suspend accepting connections from the listen socket temporarily.
502  * Resume activity using #GNUNET_SERVER_resume.
503  *
504  * @param server server to stop accepting connections.
505  */
506 void
507 GNUNET_SERVER_suspend (struct GNUNET_SERVER_Handle *server);
508
509 /**
510  * Notify us when the server has enough space to transmit
511  * a message of the given size to the given client.
512  *
513  * @param client client to transmit message to
514  * @param size requested amount of buffer space
515  * @param timeout after how long should we give up (and call
516  *        notify with buf NULL and size 0)?
517  * @param callback function to call when space is available
518  * @param callback_cls closure for @a callback
519  * @return non-NULL if the notify callback was queued; can be used
520  *           to cancel the request using
521  *           #GNUNET_SERVER_notify_transmit_ready_cancel.
522  *         NULL if we are already going to notify someone else (busy)
523  */
524 struct GNUNET_SERVER_TransmitHandle *
525 GNUNET_SERVER_notify_transmit_ready (struct GNUNET_SERVER_Client *client,
526                                      size_t size,
527                                      struct GNUNET_TIME_Relative timeout,
528                                      GNUNET_CONNECTION_TransmitReadyNotify callback,
529                                      void *callback_cls);
530
531
532 /**
533  * Add a TCP socket-based connection to the set of handles managed by
534  * this server.  Use this function for outgoing (P2P) connections that
535  * we initiated (and where this server should process incoming
536  * messages).
537  *
538  * @param server the server to use
539  * @param connection the connection to manage (client must
540  *        stop using this connection from now on)
541  * @return the client handle
542  */
543 struct GNUNET_SERVER_Client *
544 GNUNET_SERVER_connect_socket (struct GNUNET_SERVER_Handle *server,
545                               struct GNUNET_CONNECTION_Handle *connection);
546
547
548 /**
549  * Resume accepting connections from the listen socket.
550  *
551  * @param server server to resume accepting connections.
552  */
553 void
554 GNUNET_SERVER_resume (struct GNUNET_SERVER_Handle *server);
555
556 /**
557  * Free resources held by this server.
558  *
559  * @param server server to destroy
560  */
561 void
562 GNUNET_SERVER_destroy (struct GNUNET_SERVER_Handle *server);
563
564
565
566
567 #include "tcp_connection_legacy.c"
568 #include "tcp_server_mst_legacy.c"
569 #include "tcp_server_legacy.c"
570 #include "tcp_service_legacy.c"
571
572 GNUNET_NETWORK_STRUCT_BEGIN
573
574 /**
575  * Initial handshake message for a session.
576  */
577 struct WelcomeMessage
578 {
579   /**
580    * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_WELCOME.
581    */
582   struct GNUNET_MessageHeader header;
583
584   /**
585    * Identity of the node connecting (TCP client)
586    */
587   struct GNUNET_PeerIdentity clientIdentity;
588
589 };
590
591 /**
592  * Basically a WELCOME message, but with the purpose
593  * of giving the waiting peer a client handle to use
594  */
595 struct TCP_NAT_ProbeMessage
596 {
597   /**
598    * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_NAT_PROBE.
599    */
600   struct GNUNET_MessageHeader header;
601
602   /**
603    * Identity of the sender of the message.
604    */
605   struct GNUNET_PeerIdentity clientIdentity;
606
607 };
608 GNUNET_NETWORK_STRUCT_END
609
610 /**
611  * Context for sending a NAT probe via TCP.
612  */
613 struct TCPProbeContext
614 {
615
616   /**
617    * Active probes are kept in a DLL.
618    */
619   struct TCPProbeContext *next;
620
621   /**
622    * Active probes are kept in a DLL.
623    */
624   struct TCPProbeContext *prev;
625
626   /**
627    * Probe connection.
628    */
629   struct GNUNET_CONNECTION_Handle *sock;
630
631   /**
632    * Message to be sent.
633    */
634   struct TCP_NAT_ProbeMessage message;
635
636   /**
637    * Handle to the transmission.
638    */
639   struct GNUNET_CONNECTION_TransmitHandle *transmit_handle;
640
641   /**
642    * Transport plugin handle.
643    */
644   struct Plugin *plugin;
645 };
646
647 /**
648  * Bits in the `options` field of TCP addresses.
649  */
650 enum TcpAddressOptions
651 {
652
653   /**
654    * No bits set.
655    */
656   TCP_OPTIONS_NONE = 0,
657
658   /**
659    * See #HTTP_OPTIONS_VERIFY_CERTIFICATE.
660    */
661   TCP_OPTIONS_RESERVED = 1,
662
663   /**
664    * Enable TCP Stealth-style port knocking.
665    */
666   TCP_OPTIONS_TCP_STEALTH = 2
667 };
668
669 GNUNET_NETWORK_STRUCT_BEGIN
670
671 /**
672  * Network format for IPv4 addresses.
673  */
674 struct IPv4TcpAddress
675 {
676   /**
677    * Optional options and flags for this address,
678    * see `enum TcpAddressOptions`
679    */
680   uint32_t options GNUNET_PACKED;
681
682   /**
683    * IPv4 address, in network byte order.
684    */
685   uint32_t ipv4_addr GNUNET_PACKED;
686
687   /**
688    * Port number, in network byte order.
689    */
690   uint16_t t4_port GNUNET_PACKED;
691
692 };
693
694 /**
695  * Network format for IPv6 addresses.
696  */
697 struct IPv6TcpAddress
698 {
699   /**
700    * Optional flags for this address
701    * see `enum TcpAddressOptions`
702    */
703   uint32_t options GNUNET_PACKED;
704
705   /**
706    * IPv6 address.
707    */
708   struct in6_addr ipv6_addr GNUNET_PACKED;
709
710   /**
711    * Port number, in network byte order.
712    */
713   uint16_t t6_port GNUNET_PACKED;
714
715 };
716 GNUNET_NETWORK_STRUCT_END
717
718 /**
719  * Encapsulation of all of the state of the plugin.
720  */
721 struct Plugin;
722
723 /**
724  * Information kept for each message that is yet to
725  * be transmitted.
726  */
727 struct PendingMessage
728 {
729
730   /**
731    * This is a doubly-linked list.
732    */
733   struct PendingMessage *next;
734
735   /**
736    * This is a doubly-linked list.
737    */
738   struct PendingMessage *prev;
739
740   /**
741    * The pending message
742    */
743   const char *msg;
744
745   /**
746    * Continuation function to call once the message
747    * has been sent.  Can be NULL if there is no
748    * continuation to call.
749    */
750   GNUNET_TRANSPORT_TransmitContinuation transmit_cont;
751
752   /**
753    * Closure for @e transmit_cont.
754    */
755   void *transmit_cont_cls;
756
757   /**
758    * Timeout value for the pending message.
759    */
760   struct GNUNET_TIME_Absolute timeout;
761
762   /**
763    * So that the gnunet-service-transport can group messages together,
764    * these pending messages need to accept a message buffer and size
765    * instead of just a `struct GNUNET_MessageHeader`.
766    */
767   size_t message_size;
768
769 };
770
771 /**
772  * Session handle for TCP connections.
773  */
774 struct GNUNET_ATS_Session
775 {
776   /**
777    * To whom are we talking to (set to our identity
778    * if we are still waiting for the welcome message)
779    */
780   struct GNUNET_PeerIdentity target;
781
782   /**
783    * Pointer to the global plugin struct.
784    */
785   struct Plugin *plugin;
786
787   /**
788    * The client (used to identify this connection)
789    */
790   struct GNUNET_SERVER_Client *client;
791
792   /**
793    * Task cleaning up a NAT client connection establishment attempt;
794    */
795   struct GNUNET_SCHEDULER_Task *nat_connection_timeout;
796
797   /**
798    * Messages currently pending for transmission
799    * to this peer, if any.
800    */
801   struct PendingMessage *pending_messages_head;
802
803   /**
804    * Messages currently pending for transmission
805    * to this peer, if any.
806    */
807   struct PendingMessage *pending_messages_tail;
808
809   /**
810    * Handle for pending transmission request.
811    */
812   struct GNUNET_SERVER_TransmitHandle *transmit_handle;
813
814   /**
815    * Address of the other peer.
816    */
817   struct GNUNET_HELLO_Address *address;
818
819   /**
820    * ID of task used to delay receiving more to throttle sender.
821    */
822   struct GNUNET_SCHEDULER_Task *receive_delay_task;
823
824   /**
825    * Session timeout task
826    */
827   struct GNUNET_SCHEDULER_Task *timeout_task;
828
829   /**
830    * When will this session time out?
831    */
832   struct GNUNET_TIME_Absolute timeout;
833
834   /**
835    * When will we continue to read from the socket?
836    * (used to enforce inbound quota).
837    */
838   struct GNUNET_TIME_Absolute receive_delay;
839
840   /**
841    * Last activity on this connection.  Used to select preferred
842    * connection.
843    */
844   struct GNUNET_TIME_Absolute last_activity;
845
846   /**
847    * Number of bytes waiting for transmission to this peer.
848    */
849   unsigned long long bytes_in_queue;
850
851   /**
852    * Number of messages waiting for transmission to this peer.
853    */
854   unsigned int msgs_in_queue;
855
856   /**
857    * Network type of the address.
858    */
859   enum GNUNET_ATS_Network_Type scope;
860
861   /**
862    * Are we still expecting the welcome message? (#GNUNET_YES/#GNUNET_NO)
863    */
864   int expecting_welcome;
865
866   /**
867    * Was this session created using NAT traversal?
868    */
869   int is_nat;
870
871 };
872
873
874 /**
875  * Context for address to string conversion, closure
876  * for #append_port().
877  */
878 struct PrettyPrinterContext
879 {
880   /**
881    * DLL
882    */
883   struct PrettyPrinterContext *next;
884
885   /**
886    * DLL
887    */
888   struct PrettyPrinterContext *prev;
889
890   /**
891    * Our plugin.
892    */
893   struct Plugin *plugin;
894
895   /**
896    * Timeout task
897    */
898   struct GNUNET_SCHEDULER_Task *timeout_task;
899
900   /**
901    * Resolver handle
902    */
903   struct GNUNET_RESOLVER_RequestHandle *resolver_handle;
904
905   /**
906    * Function to call with the result.
907    */
908   GNUNET_TRANSPORT_AddressStringCallback asc;
909
910   /**
911    * Clsoure for @e asc.
912    */
913   void *asc_cls;
914
915   /**
916    * IPv6 address
917    */
918   int ipv6;
919
920   /**
921    * Options
922    */
923   uint32_t options;
924
925   /**
926    * Port to add after the IP address.
927    */
928   uint16_t port;
929 };
930
931
932 /**
933  * Encapsulation of all of the state of the plugin.
934  */
935 struct Plugin
936 {
937   /**
938    * Our environment.
939    */
940   struct GNUNET_TRANSPORT_PluginEnvironment *env;
941
942   /**
943    * The listen socket.
944    */
945   struct GNUNET_CONNECTION_Handle *lsock;
946
947   /**
948    * Our handle to the NAT module.
949    */
950   struct GNUNET_NAT_Handle *nat;
951
952   /**
953    * Map from peer identities to sessions for the given peer.
954    */
955   struct GNUNET_CONTAINER_MultiPeerMap *sessionmap;
956
957   /**
958    * Handle to the network service.
959    */
960   struct LEGACY_SERVICE_Context *service;
961
962   /**
963    * Handle to the server for this service.
964    */
965   struct GNUNET_SERVER_Handle *server;
966
967   /**
968    * Copy of the handler array where the closures are
969    * set to this struct's instance.
970    */
971   struct GNUNET_SERVER_MessageHandler *handlers;
972
973   /**
974    * Map of peers we have tried to contact behind a NAT
975    */
976   struct GNUNET_CONTAINER_MultiPeerMap *nat_wait_conns;
977
978   /**
979    * List of active TCP probes.
980    */
981   struct TCPProbeContext *probe_head;
982
983   /**
984    * List of active TCP probes.
985    */
986   struct TCPProbeContext *probe_tail;
987
988   /**
989    * Function to call about session status changes.
990    */
991   GNUNET_TRANSPORT_SessionInfoCallback sic;
992
993   /**
994    * Closure for @e sic.
995    */
996   void *sic_cls;
997
998   /**
999    * ID of task used to update our addresses when one expires.
1000    */
1001   struct GNUNET_SCHEDULER_Task *address_update_task;
1002
1003   /**
1004    * Running pretty printers: head
1005    */
1006   struct PrettyPrinterContext *ppc_dll_head;
1007
1008   /**
1009    * Running pretty printers: tail
1010    */
1011   struct PrettyPrinterContext *ppc_dll_tail;
1012
1013   /**
1014    * Welcome message used by this peer.
1015    */
1016   struct WelcomeMessage my_welcome;
1017
1018   /**
1019    * How many more TCP sessions are we allowed to open right now?
1020    */
1021   unsigned long long max_connections;
1022
1023   /**
1024    * How many more TCP sessions do we have right now?
1025    */
1026   unsigned long long cur_connections;
1027
1028   /**
1029    * Address options
1030    */
1031   uint32_t myoptions;
1032
1033   /**
1034    * Port that we are actually listening on.
1035    */
1036   uint16_t open_port;
1037
1038   /**
1039    * Port that the user said we would have visible to the
1040    * rest of the world.
1041    */
1042   uint16_t adv_port;
1043
1044 };
1045
1046
1047 /**
1048  * Get the list of addresses that a server for the given service
1049  * should bind to.
1050  *
1051  * @param service_name name of the service
1052  * @param cfg configuration (which specifies the addresses)
1053  * @param addrs set (call by reference) to an array of pointers to the
1054  *              addresses the server should bind to and listen on; the
1055  *              array will be NULL-terminated (on success)
1056  * @param addr_lens set (call by reference) to an array of the lengths
1057  *              of the respective `struct sockaddr` struct in the @a addrs
1058  *              array (on success)
1059  * @return number of addresses found on success,
1060  *              #GNUNET_SYSERR if the configuration
1061  *              did not specify reasonable finding information or
1062  *              if it specified a hostname that could not be resolved;
1063  *              #GNUNET_NO if the number of addresses configured is
1064  *              zero (in this case, `*addrs` and `*addr_lens` will be
1065  *              set to NULL).
1066  */
1067 static int
1068 get_server_addresses (const char *service_name,
1069                       const struct GNUNET_CONFIGURATION_Handle *cfg,
1070                       struct sockaddr ***addrs,
1071                       socklen_t ** addr_lens)
1072 {
1073   int disablev6;
1074   struct GNUNET_NETWORK_Handle *desc;
1075   unsigned long long port;
1076   char *unixpath;
1077   struct addrinfo hints;
1078   struct addrinfo *res;
1079   struct addrinfo *pos;
1080   struct addrinfo *next;
1081   unsigned int i;
1082   int resi;
1083   int ret;
1084   int abstract;
1085   struct sockaddr **saddrs;
1086   socklen_t *saddrlens;
1087   char *hostname;
1088
1089   *addrs = NULL;
1090   *addr_lens = NULL;
1091   desc = NULL;
1092   if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "DISABLEV6"))
1093   {
1094     if (GNUNET_SYSERR ==
1095         (disablev6 =
1096          GNUNET_CONFIGURATION_get_value_yesno (cfg, service_name, "DISABLEV6")))
1097       return GNUNET_SYSERR;
1098   }
1099   else
1100     disablev6 = GNUNET_NO;
1101
1102   if (! disablev6)
1103   {
1104     /* probe IPv6 support */
1105     desc = GNUNET_NETWORK_socket_create (PF_INET6, SOCK_STREAM, 0);
1106     if (NULL == desc)
1107     {
1108       if ((ENOBUFS == errno) || (ENOMEM == errno) || (ENFILE == errno) ||
1109           (EACCES == errno))
1110       {
1111         GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "socket");
1112         return GNUNET_SYSERR;
1113       }
1114       LOG (GNUNET_ERROR_TYPE_INFO,
1115            _("Disabling IPv6 support for service `%s', failed to create IPv6 socket: %s\n"),
1116            service_name, STRERROR (errno));
1117       disablev6 = GNUNET_YES;
1118     }
1119     else
1120     {
1121       GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (desc));
1122       desc = NULL;
1123     }
1124   }
1125
1126   port = 0;
1127   if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "PORT"))
1128   {
1129     if (GNUNET_OK !=
1130         GNUNET_CONFIGURATION_get_value_number (cfg, service_name,
1131                                                "PORT", &port))
1132     {
1133       LOG (GNUNET_ERROR_TYPE_ERROR,
1134            _("Require valid port number for service `%s' in configuration!\n"),
1135            service_name);
1136     }
1137     if (port > 65535)
1138     {
1139       LOG (GNUNET_ERROR_TYPE_ERROR,
1140            _("Require valid port number for service `%s' in configuration!\n"),
1141            service_name);
1142       return GNUNET_SYSERR;
1143     }
1144   }
1145
1146   if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "BINDTO"))
1147   {
1148     GNUNET_break (GNUNET_OK ==
1149                   GNUNET_CONFIGURATION_get_value_string (cfg, service_name,
1150                                                          "BINDTO", &hostname));
1151   }
1152   else
1153     hostname = NULL;
1154
1155   unixpath = NULL;
1156   abstract = GNUNET_NO;
1157 #ifdef AF_UNIX
1158   if ((GNUNET_YES ==
1159        GNUNET_CONFIGURATION_have_value (cfg, service_name, "UNIXPATH")) &&
1160       (GNUNET_OK ==
1161        GNUNET_CONFIGURATION_get_value_filename (cfg, service_name, "UNIXPATH",
1162                                               &unixpath)) &&
1163       (0 < strlen (unixpath)))
1164   {
1165     /* probe UNIX support */
1166     struct sockaddr_un s_un;
1167
1168     if (strlen (unixpath) >= sizeof (s_un.sun_path))
1169     {
1170       LOG (GNUNET_ERROR_TYPE_WARNING,
1171            _("UNIXPATH `%s' too long, maximum length is %llu\n"), unixpath,
1172            (unsigned long long) sizeof (s_un.sun_path));
1173       unixpath = GNUNET_NETWORK_shorten_unixpath (unixpath);
1174       LOG (GNUNET_ERROR_TYPE_INFO,
1175            _("Using `%s' instead\n"),
1176            unixpath);
1177     }
1178 #ifdef LINUX
1179     abstract = GNUNET_CONFIGURATION_get_value_yesno (cfg,
1180                                                      "TESTING",
1181                                                      "USE_ABSTRACT_SOCKETS");
1182     if (GNUNET_SYSERR == abstract)
1183       abstract = GNUNET_NO;
1184 #endif
1185     if ((GNUNET_YES != abstract)
1186         && (GNUNET_OK !=
1187             GNUNET_DISK_directory_create_for_file (unixpath)))
1188       GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
1189                                 "mkdir",
1190                                 unixpath);
1191   }
1192   if (NULL != unixpath)
1193   {
1194     desc = GNUNET_NETWORK_socket_create (AF_UNIX, SOCK_STREAM, 0);
1195     if (NULL == desc)
1196     {
1197       if ((ENOBUFS == errno) || (ENOMEM == errno) || (ENFILE == errno) ||
1198           (EACCES == errno))
1199       {
1200         GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "socket");
1201         GNUNET_free_non_null (hostname);
1202         GNUNET_free (unixpath);
1203         return GNUNET_SYSERR;
1204       }
1205       LOG (GNUNET_ERROR_TYPE_INFO,
1206            _("Disabling UNIX domain socket support for service `%s', failed to create UNIX domain socket: %s\n"),
1207            service_name,
1208            STRERROR (errno));
1209       GNUNET_free (unixpath);
1210       unixpath = NULL;
1211     }
1212     else
1213     {
1214       GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (desc));
1215       desc = NULL;
1216     }
1217   }
1218 #endif
1219
1220   if ((0 == port) && (NULL == unixpath))
1221   {
1222     LOG (GNUNET_ERROR_TYPE_ERROR,
1223          _("Have neither PORT nor UNIXPATH for service `%s', but one is required\n"),
1224          service_name);
1225     GNUNET_free_non_null (hostname);
1226     return GNUNET_SYSERR;
1227   }
1228   if (0 == port)
1229   {
1230     saddrs = GNUNET_malloc (2 * sizeof (struct sockaddr *));
1231     saddrlens = GNUNET_malloc (2 * sizeof (socklen_t));
1232     add_unixpath (saddrs, saddrlens, unixpath, abstract);
1233     GNUNET_free_non_null (unixpath);
1234     GNUNET_free_non_null (hostname);
1235     *addrs = saddrs;
1236     *addr_lens = saddrlens;
1237     return 1;
1238   }
1239
1240   if (NULL != hostname)
1241   {
1242     LOG (GNUNET_ERROR_TYPE_DEBUG,
1243          "Resolving `%s' since that is where `%s' will bind to.\n",
1244          hostname,
1245          service_name);
1246     memset (&hints, 0, sizeof (struct addrinfo));
1247     if (disablev6)
1248       hints.ai_family = AF_INET;
1249     hints.ai_protocol = IPPROTO_TCP;
1250     if ((0 != (ret = getaddrinfo (hostname, NULL, &hints, &res))) ||
1251         (NULL == res))
1252     {
1253       LOG (GNUNET_ERROR_TYPE_ERROR,
1254            _("Failed to resolve `%s': %s\n"),
1255            hostname,
1256            gai_strerror (ret));
1257       GNUNET_free (hostname);
1258       GNUNET_free_non_null (unixpath);
1259       return GNUNET_SYSERR;
1260     }
1261     next = res;
1262     i = 0;
1263     while (NULL != (pos = next))
1264     {
1265       next = pos->ai_next;
1266       if ((disablev6) && (pos->ai_family == AF_INET6))
1267         continue;
1268       i++;
1269     }
1270     if (0 == i)
1271     {
1272       LOG (GNUNET_ERROR_TYPE_ERROR,
1273            _("Failed to find %saddress for `%s'.\n"),
1274            disablev6 ? "IPv4 " : "",
1275            hostname);
1276       freeaddrinfo (res);
1277       GNUNET_free (hostname);
1278       GNUNET_free_non_null (unixpath);
1279       return GNUNET_SYSERR;
1280     }
1281     resi = i;
1282     if (NULL != unixpath)
1283       resi++;
1284     saddrs = GNUNET_malloc ((resi + 1) * sizeof (struct sockaddr *));
1285     saddrlens = GNUNET_malloc ((resi + 1) * sizeof (socklen_t));
1286     i = 0;
1287     if (NULL != unixpath)
1288     {
1289       add_unixpath (saddrs, saddrlens, unixpath, abstract);
1290       i++;
1291     }
1292     next = res;
1293     while (NULL != (pos = next))
1294     {
1295       next = pos->ai_next;
1296       if ((disablev6) && (AF_INET6 == pos->ai_family))
1297         continue;
1298       if ((IPPROTO_TCP != pos->ai_protocol) && (0 != pos->ai_protocol))
1299         continue;               /* not TCP */
1300       if ((SOCK_STREAM != pos->ai_socktype) && (0 != pos->ai_socktype))
1301         continue;               /* huh? */
1302       LOG (GNUNET_ERROR_TYPE_DEBUG, "Service `%s' will bind to `%s'\n",
1303            service_name, GNUNET_a2s (pos->ai_addr, pos->ai_addrlen));
1304       if (AF_INET == pos->ai_family)
1305       {
1306         GNUNET_assert (sizeof (struct sockaddr_in) == pos->ai_addrlen);
1307         saddrlens[i] = pos->ai_addrlen;
1308         saddrs[i] = GNUNET_malloc (saddrlens[i]);
1309         GNUNET_memcpy (saddrs[i], pos->ai_addr, saddrlens[i]);
1310         ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
1311       }
1312       else
1313       {
1314         GNUNET_assert (AF_INET6 == pos->ai_family);
1315         GNUNET_assert (sizeof (struct sockaddr_in6) == pos->ai_addrlen);
1316         saddrlens[i] = pos->ai_addrlen;
1317         saddrs[i] = GNUNET_malloc (saddrlens[i]);
1318         GNUNET_memcpy (saddrs[i], pos->ai_addr, saddrlens[i]);
1319         ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port);
1320       }
1321       i++;
1322     }
1323     GNUNET_free (hostname);
1324     freeaddrinfo (res);
1325     resi = i;
1326   }
1327   else
1328   {
1329     /* will bind against everything, just set port */
1330     if (disablev6)
1331     {
1332       /* V4-only */
1333       resi = 1;
1334       if (NULL != unixpath)
1335         resi++;
1336       i = 0;
1337       saddrs = GNUNET_malloc ((resi + 1) * sizeof (struct sockaddr *));
1338       saddrlens = GNUNET_malloc ((resi + 1) * sizeof (socklen_t));
1339       if (NULL != unixpath)
1340       {
1341         add_unixpath (saddrs, saddrlens, unixpath, abstract);
1342         i++;
1343       }
1344       saddrlens[i] = sizeof (struct sockaddr_in);
1345       saddrs[i] = GNUNET_malloc (saddrlens[i]);
1346 #if HAVE_SOCKADDR_IN_SIN_LEN
1347       ((struct sockaddr_in *) saddrs[i])->sin_len = saddrlens[i];
1348 #endif
1349       ((struct sockaddr_in *) saddrs[i])->sin_family = AF_INET;
1350       ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
1351     }
1352     else
1353     {
1354       /* dual stack */
1355       resi = 2;
1356       if (NULL != unixpath)
1357         resi++;
1358       saddrs = GNUNET_malloc ((resi + 1) * sizeof (struct sockaddr *));
1359       saddrlens = GNUNET_malloc ((resi + 1) * sizeof (socklen_t));
1360       i = 0;
1361       if (NULL != unixpath)
1362       {
1363         add_unixpath (saddrs, saddrlens, unixpath, abstract);
1364         i++;
1365       }
1366       saddrlens[i] = sizeof (struct sockaddr_in6);
1367       saddrs[i] = GNUNET_malloc (saddrlens[i]);
1368 #if HAVE_SOCKADDR_IN_SIN_LEN
1369       ((struct sockaddr_in6 *) saddrs[i])->sin6_len = saddrlens[0];
1370 #endif
1371       ((struct sockaddr_in6 *) saddrs[i])->sin6_family = AF_INET6;
1372       ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port);
1373       i++;
1374       saddrlens[i] = sizeof (struct sockaddr_in);
1375       saddrs[i] = GNUNET_malloc (saddrlens[i]);
1376 #if HAVE_SOCKADDR_IN_SIN_LEN
1377       ((struct sockaddr_in *) saddrs[i])->sin_len = saddrlens[1];
1378 #endif
1379       ((struct sockaddr_in *) saddrs[i])->sin_family = AF_INET;
1380       ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
1381     }
1382   }
1383   GNUNET_free_non_null (unixpath);
1384   *addrs = saddrs;
1385   *addr_lens = saddrlens;
1386   return resi;
1387 }
1388 /* end ancient copy-and-paste */
1389
1390
1391 /**
1392  * If a session monitor is attached, notify it about the new
1393  * session state.
1394  *
1395  * @param plugin our plugin
1396  * @param session session that changed state
1397  * @param state new state of the session
1398  */
1399 static void
1400 notify_session_monitor (struct Plugin *plugin,
1401                         struct GNUNET_ATS_Session *session,
1402                         enum GNUNET_TRANSPORT_SessionState state)
1403 {
1404   struct GNUNET_TRANSPORT_SessionInfo info;
1405
1406   if (NULL == plugin->sic)
1407     return;
1408   memset (&info, 0, sizeof (info));
1409   info.state = state;
1410   info.is_inbound = GNUNET_HELLO_address_check_option (session->address,
1411                                          GNUNET_HELLO_ADDRESS_INFO_INBOUND);
1412   info.num_msg_pending = session->msgs_in_queue;
1413   info.num_bytes_pending = session->bytes_in_queue;
1414   if (NULL != session->receive_delay_task)
1415     info.receive_delay = session->receive_delay;
1416   info.session_timeout = session->timeout;
1417   info.address = session->address;
1418   plugin->sic (plugin->sic_cls,
1419                session,
1420                &info);
1421 }
1422
1423
1424 /**
1425  * Our external IP address/port mapping has changed.
1426  *
1427  * @param cls closure, the `struct Plugin`
1428  * @param add_remove #GNUNET_YES to mean the new public IP address, #GNUNET_NO to mean
1429  *     the previous (now invalid) one
1430  * @param ac address class the address belongs to
1431  * @param addr either the previous or the new public IP address
1432  * @param addrlen actual length of @a addr
1433  */
1434 static void
1435 tcp_nat_port_map_callback (void *cls,
1436                            int add_remove,
1437                            enum GNUNET_NAT_AddressClass ac,
1438                            const struct sockaddr *addr,
1439                            socklen_t addrlen)
1440 {
1441   struct Plugin *plugin = cls;
1442   struct GNUNET_HELLO_Address *address;
1443   struct IPv4TcpAddress t4;
1444   struct IPv6TcpAddress t6;
1445   void *arg;
1446   size_t args;
1447
1448   if (GNUNET_NAT_AC_LOOPBACK == ac)
1449     return;
1450   if (GNUNET_NAT_AC_LAN == ac)
1451     return;
1452   if (GNUNET_NAT_AC_LAN_PRIVATE == ac)
1453     return;
1454   LOG (GNUNET_ERROR_TYPE_INFO,
1455        "NAT notification to %s address `%s'\n",
1456        (GNUNET_YES == add_remove) ? "add" : "remove",
1457        GNUNET_a2s (addr, addrlen));
1458   /* convert 'addr' to our internal format */
1459   switch (addr->sa_family)
1460   {
1461   case AF_INET:
1462     GNUNET_assert(addrlen == sizeof(struct sockaddr_in));
1463     memset (&t4, 0, sizeof(t4));
1464     t4.options = htonl (plugin->myoptions);
1465     t4.ipv4_addr = ((struct sockaddr_in *) addr)->sin_addr.s_addr;
1466     t4.t4_port = ((struct sockaddr_in *) addr)->sin_port;
1467     arg = &t4;
1468     args = sizeof (t4);
1469     break;
1470   case AF_INET6:
1471     GNUNET_assert(addrlen == sizeof(struct sockaddr_in6));
1472     memset (&t6, 0, sizeof(t6));
1473     GNUNET_memcpy (&t6.ipv6_addr,
1474                    &((struct sockaddr_in6 *) addr)->sin6_addr,
1475                    sizeof(struct in6_addr));
1476     t6.options = htonl (plugin->myoptions);
1477     t6.t6_port = ((struct sockaddr_in6 *) addr)->sin6_port;
1478     arg = &t6;
1479     args = sizeof (t6);
1480     break;
1481   default:
1482     GNUNET_break(0);
1483     return;
1484   }
1485   /* modify our published address list */
1486   GNUNET_assert ((args == sizeof (struct IPv4TcpAddress)) ||
1487                  (args == sizeof (struct IPv6TcpAddress)));
1488   /* TODO: use 'ac' here in the future... */
1489   address = GNUNET_HELLO_address_allocate (plugin->env->my_identity,
1490                                            PLUGIN_NAME,
1491                                            arg,
1492                                            args,
1493                                            GNUNET_HELLO_ADDRESS_INFO_NONE);
1494   plugin->env->notify_address (plugin->env->cls,
1495                                add_remove,
1496                                address);
1497   GNUNET_HELLO_address_free (address);
1498 }
1499
1500
1501 /**
1502  * Function called for a quick conversion of the binary address to
1503  * a numeric address.  Note that the caller must not free the
1504  * address and that the next call to this function is allowed
1505  * to override the address again.
1506  *
1507  * @param cls closure (`struct Plugin*`)
1508  * @param addr binary address
1509  * @param addrlen length of @a addr
1510  * @return string representing the same address
1511  */
1512 static const char *
1513 tcp_plugin_address_to_string (void *cls,
1514                               const void *addr,
1515                               size_t addrlen)
1516 {
1517   static char rbuf[INET6_ADDRSTRLEN + 12];
1518   char buf[INET6_ADDRSTRLEN];
1519   const void *sb;
1520   struct in_addr a4;
1521   struct in6_addr a6;
1522   const struct IPv4TcpAddress *t4;
1523   const struct IPv6TcpAddress *t6;
1524   int af;
1525   uint16_t port;
1526   uint32_t options;
1527
1528   switch (addrlen)
1529   {
1530   case sizeof(struct IPv6TcpAddress):
1531     t6 = addr;
1532     af = AF_INET6;
1533     port = ntohs (t6->t6_port);
1534     options = ntohl (t6->options);
1535     GNUNET_memcpy (&a6, &t6->ipv6_addr, sizeof(a6));
1536     sb = &a6;
1537     break;
1538   case sizeof(struct IPv4TcpAddress):
1539     t4 = addr;
1540     af = AF_INET;
1541     port = ntohs (t4->t4_port);
1542     options = ntohl (t4->options);
1543     GNUNET_memcpy (&a4, &t4->ipv4_addr, sizeof(a4));
1544     sb = &a4;
1545     break;
1546   default:
1547     LOG (GNUNET_ERROR_TYPE_WARNING,
1548          _("Unexpected address length: %u bytes\n"),
1549          (unsigned int) addrlen);
1550     return NULL ;
1551   }
1552   if (NULL == inet_ntop (af, sb, buf, INET6_ADDRSTRLEN))
1553   {
1554     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
1555                          "inet_ntop");
1556     return NULL ;
1557   }
1558   GNUNET_snprintf (rbuf, sizeof(rbuf),
1559                    (af == AF_INET6) ? "%s.%u.[%s]:%u" : "%s.%u.%s:%u",
1560                    PLUGIN_NAME,
1561                    options,
1562                    buf,
1563                    port);
1564   return rbuf;
1565 }
1566
1567
1568 /**
1569  * Function called to convert a string address to
1570  * a binary address.
1571  *
1572  * @param cls closure (`struct Plugin*`)
1573  * @param addr string address
1574  * @param addrlen length of the address
1575  * @param buf location to store the buffer
1576  * @param added location to store the number of bytes in the buffer.
1577  *        If the function returns #GNUNET_SYSERR, its contents are undefined.
1578  * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure
1579  */
1580 static int
1581 tcp_plugin_string_to_address (void *cls,
1582                               const char *addr,
1583                               uint16_t addrlen,
1584                               void **buf,
1585                               size_t *added)
1586 {
1587   struct sockaddr_storage socket_address;
1588   char *address;
1589   char *plugin;
1590   char *optionstr;
1591   uint32_t options;
1592
1593   /* Format tcp.options.address:port */
1594   address = NULL;
1595   plugin = NULL;
1596   optionstr = NULL;
1597   if ((NULL == addr) || (0 == addrlen))
1598   {
1599     GNUNET_break(0);
1600     return GNUNET_SYSERR;
1601   }
1602   if ('\0' != addr[addrlen - 1])
1603   {
1604     GNUNET_break(0);
1605     return GNUNET_SYSERR;
1606   }
1607   if (strlen (addr) != addrlen - 1)
1608   {
1609     GNUNET_break(0);
1610     return GNUNET_SYSERR;
1611   }
1612   plugin = GNUNET_strdup (addr);
1613   optionstr = strchr (plugin, '.');
1614   if (NULL == optionstr)
1615   {
1616     GNUNET_break(0);
1617     GNUNET_free(plugin);
1618     return GNUNET_SYSERR;
1619   }
1620   optionstr[0] = '\0';
1621   optionstr++;
1622   options = atol (optionstr);
1623   address = strchr (optionstr, '.');
1624   if (NULL == address)
1625   {
1626     GNUNET_break(0);
1627     GNUNET_free(plugin);
1628     return GNUNET_SYSERR;
1629   }
1630   address[0] = '\0';
1631   address++;
1632
1633   if (GNUNET_OK !=
1634       GNUNET_STRINGS_to_address_ip (address,
1635                                     strlen (address),
1636                                     &socket_address))
1637   {
1638     GNUNET_break(0);
1639     GNUNET_free(plugin);
1640     return GNUNET_SYSERR;
1641   }
1642
1643   GNUNET_free(plugin);
1644   switch (socket_address.ss_family)
1645   {
1646   case AF_INET:
1647   {
1648     struct IPv4TcpAddress *t4;
1649     struct sockaddr_in *in4 = (struct sockaddr_in *) &socket_address;
1650     t4 = GNUNET_new (struct IPv4TcpAddress);
1651     t4->options = htonl (options);
1652     t4->ipv4_addr = in4->sin_addr.s_addr;
1653     t4->t4_port = in4->sin_port;
1654     *buf = t4;
1655     *added = sizeof(struct IPv4TcpAddress);
1656     return GNUNET_OK;
1657   }
1658   case AF_INET6:
1659   {
1660     struct IPv6TcpAddress *t6;
1661     struct sockaddr_in6 *in6 = (struct sockaddr_in6 *) &socket_address;
1662     t6 = GNUNET_new (struct IPv6TcpAddress);
1663     t6->options = htonl (options);
1664     t6->ipv6_addr = in6->sin6_addr;
1665     t6->t6_port = in6->sin6_port;
1666     *buf = t6;
1667     *added = sizeof(struct IPv6TcpAddress);
1668     return GNUNET_OK;
1669   }
1670   default:
1671     return GNUNET_SYSERR;
1672   }
1673 }
1674
1675
1676 /**
1677  * Find the session handle for the given client.
1678  * Currently uses both the hashmap and the client
1679  * context, as the client context is new and the
1680  * logic still needs to be tested.
1681  *
1682  * @param plugin the plugin
1683  * @param client which client to find the session handle for
1684  * @return NULL if no matching session exists
1685  */
1686 static struct GNUNET_ATS_Session *
1687 lookup_session_by_client (struct Plugin *plugin,
1688                           struct GNUNET_SERVER_Client *client)
1689 {
1690   return GNUNET_SERVER_client_get_user_context (client,
1691                                                 struct GNUNET_ATS_Session);
1692 }
1693
1694
1695 /**
1696  * Functions with this signature are called whenever we need
1697  * to close a session due to a disconnect or failure to
1698  * establish a connection.
1699  *
1700  * @param cls the `struct Plugin`
1701  * @param session session to close down
1702  * @return #GNUNET_OK on success
1703  */
1704 static int
1705 tcp_plugin_disconnect_session (void *cls,
1706                                struct GNUNET_ATS_Session *session)
1707 {
1708   struct Plugin *plugin = cls;
1709   struct PendingMessage *pm;
1710
1711   LOG (GNUNET_ERROR_TYPE_DEBUG,
1712        "Disconnecting session of peer `%s' address `%s'\n",
1713        GNUNET_i2s (&session->target),
1714        tcp_plugin_address_to_string (session->plugin,
1715                                      session->address->address,
1716                                      session->address->address_length));
1717
1718   if (NULL != session->timeout_task)
1719   {
1720     GNUNET_SCHEDULER_cancel (session->timeout_task);
1721     session->timeout_task = NULL;
1722     session->timeout = GNUNET_TIME_UNIT_ZERO_ABS;
1723   }
1724
1725   if (GNUNET_YES ==
1726       GNUNET_CONTAINER_multipeermap_remove (plugin->sessionmap,
1727                                             &session->target,
1728                                             session))
1729   {
1730     GNUNET_STATISTICS_update (session->plugin->env->stats,
1731                               gettext_noop ("# TCP sessions active"),
1732                               -1,
1733                               GNUNET_NO);
1734   }
1735   else
1736   {
1737     GNUNET_assert (GNUNET_YES ==
1738                    GNUNET_CONTAINER_multipeermap_remove (plugin->nat_wait_conns,
1739                                                          &session->target,
1740                                                          session));
1741   }
1742   if (NULL != session->client)
1743     GNUNET_SERVER_client_set_user_context (session->client,
1744                                            NULL);
1745
1746   /* clean up state */
1747   if (NULL != session->transmit_handle)
1748   {
1749     GNUNET_SERVER_notify_transmit_ready_cancel (session->transmit_handle);
1750     session->transmit_handle = NULL;
1751   }
1752   session->plugin->env->session_end (session->plugin->env->cls,
1753                                      session->address,
1754                                      session);
1755
1756   if (NULL != session->nat_connection_timeout)
1757   {
1758     GNUNET_SCHEDULER_cancel (session->nat_connection_timeout);
1759     session->nat_connection_timeout = NULL;
1760   }
1761
1762   while (NULL != (pm = session->pending_messages_head))
1763   {
1764     LOG (GNUNET_ERROR_TYPE_DEBUG,
1765          (NULL != pm->transmit_cont)
1766          ? "Could not deliver message to `%s' at %s.\n"
1767          : "Could not deliver message to `%s' at %s, notifying.\n",
1768          GNUNET_i2s (&session->target),
1769          tcp_plugin_address_to_string (session->plugin,
1770                                        session->address->address,
1771                                        session->address->address_length));
1772     GNUNET_STATISTICS_update (session->plugin->env->stats,
1773                               gettext_noop ("# bytes currently in TCP buffers"),
1774                               -(int64_t) pm->message_size, GNUNET_NO);
1775     GNUNET_STATISTICS_update (session->plugin->env->stats,
1776                               gettext_noop ("# bytes discarded by TCP (disconnect)"),
1777                               pm->message_size,
1778                               GNUNET_NO);
1779     GNUNET_CONTAINER_DLL_remove (session->pending_messages_head,
1780                                  session->pending_messages_tail,
1781                                  pm);
1782     GNUNET_assert (0 < session->msgs_in_queue);
1783     session->msgs_in_queue--;
1784     GNUNET_assert (pm->message_size <= session->bytes_in_queue);
1785     session->bytes_in_queue -= pm->message_size;
1786     if (NULL != pm->transmit_cont)
1787       pm->transmit_cont (pm->transmit_cont_cls,
1788                          &session->target,
1789                          GNUNET_SYSERR,
1790                          pm->message_size,
1791                          0);
1792     GNUNET_free (pm);
1793   }
1794   GNUNET_assert (0 == session->msgs_in_queue);
1795   GNUNET_assert (0 == session->bytes_in_queue);
1796   notify_session_monitor (session->plugin,
1797                           session,
1798                           GNUNET_TRANSPORT_SS_DONE);
1799
1800   if (NULL != session->receive_delay_task)
1801   {
1802     GNUNET_SCHEDULER_cancel (session->receive_delay_task);
1803     session->receive_delay_task = NULL;
1804   }
1805   if (NULL != session->client)
1806   {
1807     GNUNET_SERVER_client_disconnect (session->client);
1808     session->client = NULL;
1809   }
1810   GNUNET_HELLO_address_free (session->address);
1811   GNUNET_assert (NULL == session->transmit_handle);
1812   GNUNET_free (session);
1813   return GNUNET_OK;
1814 }
1815
1816
1817 /**
1818  * Function that is called to get the keepalive factor.
1819  * #GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT is divided by this number to
1820  * calculate the interval between keepalive packets.
1821  *
1822  * @param cls closure with the `struct Plugin`
1823  * @return keepalive factor
1824  */
1825 static unsigned int
1826 tcp_plugin_query_keepalive_factor (void *cls)
1827 {
1828   return 3;
1829 }
1830
1831
1832 /**
1833  * Session was idle for too long, so disconnect it
1834  *
1835  * @param cls the `struct GNUNET_ATS_Session` of the idle session
1836  */
1837 static void
1838 session_timeout (void *cls)
1839 {
1840   struct GNUNET_ATS_Session *s = cls;
1841   struct GNUNET_TIME_Relative left;
1842
1843   s->timeout_task = NULL;
1844   left = GNUNET_TIME_absolute_get_remaining (s->timeout);
1845   if (0 != left.rel_value_us)
1846   {
1847     /* not actually our turn yet, but let's at least update
1848        the monitor, it may think we're about to die ... */
1849     notify_session_monitor (s->plugin,
1850                             s,
1851                             GNUNET_TRANSPORT_SS_UPDATE);
1852     s->timeout_task = GNUNET_SCHEDULER_add_delayed (left,
1853                                                     &session_timeout,
1854                                                     s);
1855     return;
1856   }
1857   LOG (GNUNET_ERROR_TYPE_DEBUG,
1858        "Session %p was idle for %s, disconnecting\n",
1859        s,
1860        GNUNET_STRINGS_relative_time_to_string (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
1861                                                GNUNET_YES));
1862   /* call session destroy function */
1863   tcp_plugin_disconnect_session (s->plugin,
1864                                  s);
1865 }
1866
1867
1868 /**
1869  * Increment session timeout due to activity.
1870  *
1871  * @param s session to increment timeout for
1872  */
1873 static void
1874 reschedule_session_timeout (struct GNUNET_ATS_Session *s)
1875 {
1876   GNUNET_assert (NULL != s->timeout_task);
1877   s->timeout = GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1878 }
1879
1880
1881 /**
1882  * Create a new session.  Also queues a welcome message.
1883  *
1884  * @param plugin the plugin
1885  * @param address the address to create the session for
1886  * @param scope network scope the address is from
1887  * @param client client to use, reference counter must have already been increased
1888  * @param is_nat this a NAT session, we should wait for a client to
1889  *               connect to us from an address, then assign that to
1890  *               the session
1891  * @return new session object
1892  */
1893 static struct GNUNET_ATS_Session *
1894 create_session (struct Plugin *plugin,
1895                 const struct GNUNET_HELLO_Address *address,
1896                 enum GNUNET_ATS_Network_Type scope,
1897                 struct GNUNET_SERVER_Client *client,
1898                 int is_nat)
1899 {
1900   struct GNUNET_ATS_Session *session;
1901   struct PendingMessage *pm;
1902
1903   if (GNUNET_YES != is_nat)
1904     GNUNET_assert (NULL != client);
1905   else
1906     GNUNET_assert (NULL == client);
1907
1908   LOG (GNUNET_ERROR_TYPE_DEBUG,
1909        "Creating new session for peer `%s' at address %s\n",
1910        GNUNET_i2s (&address->peer),
1911        tcp_plugin_address_to_string (plugin,
1912                                      address->address,
1913                                      address->address_length));
1914   session = GNUNET_new (struct GNUNET_ATS_Session);
1915   session->last_activity = GNUNET_TIME_absolute_get ();
1916   session->plugin = plugin;
1917   session->is_nat = is_nat;
1918   if (NULL != client)
1919   {
1920     session->client = client;
1921     GNUNET_SERVER_client_set_user_context (client,
1922                                            session);
1923   }
1924   session->address = GNUNET_HELLO_address_copy (address);
1925   session->target = address->peer;
1926   session->expecting_welcome = GNUNET_YES;
1927   session->scope = scope;
1928   pm = GNUNET_malloc (sizeof (struct PendingMessage) +
1929                       sizeof (struct WelcomeMessage));
1930   pm->msg = (const char *) &pm[1];
1931   pm->message_size = sizeof(struct WelcomeMessage);
1932   GNUNET_memcpy (&pm[1],
1933           &plugin->my_welcome,
1934           sizeof(struct WelcomeMessage));
1935   pm->timeout = GNUNET_TIME_UNIT_FOREVER_ABS;
1936   GNUNET_STATISTICS_update (plugin->env->stats,
1937                             gettext_noop ("# bytes currently in TCP buffers"),
1938                             pm->message_size,
1939                             GNUNET_NO);
1940   GNUNET_CONTAINER_DLL_insert (session->pending_messages_head,
1941                                session->pending_messages_tail,
1942                                pm);
1943   session->msgs_in_queue++;
1944   session->bytes_in_queue += pm->message_size;
1945   session->timeout = GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1946   session->timeout_task = GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
1947                                                         &session_timeout,
1948                                                         session);
1949   notify_session_monitor (session->plugin,
1950                           session,
1951                           GNUNET_TRANSPORT_SS_INIT);
1952   if (GNUNET_YES != is_nat)
1953   {
1954     GNUNET_STATISTICS_update (plugin->env->stats,
1955                               gettext_noop ("# TCP sessions active"),
1956                               1,
1957                               GNUNET_NO);
1958     notify_session_monitor (session->plugin,
1959                             session,
1960                             GNUNET_TRANSPORT_SS_UP);
1961   }
1962   else
1963   {
1964     notify_session_monitor (session->plugin,
1965                             session,
1966                             GNUNET_TRANSPORT_SS_HANDSHAKE);
1967   }
1968   return session;
1969 }
1970
1971
1972 /**
1973  * If we have pending messages, ask the server to
1974  * transmit them (schedule the respective tasks, etc.)
1975  *
1976  * @param session for which session should we do this
1977  */
1978 static void
1979 process_pending_messages (struct GNUNET_ATS_Session *session);
1980
1981
1982 /**
1983  * Function called to notify a client about the socket
1984  * being ready to queue more data.  "buf" will be
1985  * NULL and "size" zero if the socket was closed for
1986  * writing in the meantime.
1987  *
1988  * @param cls closure
1989  * @param size number of bytes available in @a buf
1990  * @param buf where the callee should write the message
1991  * @return number of bytes written to @a buf
1992  */
1993 static size_t
1994 do_transmit (void *cls,
1995              size_t size,
1996              void *buf)
1997 {
1998   struct GNUNET_ATS_Session *session = cls;
1999   struct GNUNET_PeerIdentity pid;
2000   struct Plugin *plugin;
2001   struct PendingMessage *pos;
2002   struct PendingMessage *hd;
2003   struct PendingMessage *tl;
2004   struct GNUNET_TIME_Absolute now;
2005   char *cbuf;
2006   size_t ret;
2007
2008   session->transmit_handle = NULL;
2009   plugin = session->plugin;
2010   if (NULL == buf)
2011   {
2012     LOG (GNUNET_ERROR_TYPE_DEBUG,
2013          "Timeout trying to transmit to peer `%s', discarding message queue.\n",
2014          GNUNET_i2s (&session->target));
2015     /* timeout; cancel all messages that have already expired */
2016     hd = NULL;
2017     tl = NULL;
2018     ret = 0;
2019     now = GNUNET_TIME_absolute_get ();
2020     while ( (NULL != (pos = session->pending_messages_head)) &&
2021             (pos->timeout.abs_value_us <= now.abs_value_us) )
2022     {
2023       GNUNET_CONTAINER_DLL_remove (session->pending_messages_head,
2024                                    session->pending_messages_tail,
2025                                    pos);
2026       GNUNET_assert (0 < session->msgs_in_queue);
2027       session->msgs_in_queue--;
2028       GNUNET_assert (pos->message_size <= session->bytes_in_queue);
2029       session->bytes_in_queue -= pos->message_size;
2030       LOG (GNUNET_ERROR_TYPE_DEBUG,
2031            "Failed to transmit %u byte message to `%s'.\n",
2032            pos->message_size,
2033            GNUNET_i2s (&session->target));
2034       ret += pos->message_size;
2035       GNUNET_CONTAINER_DLL_insert_after (hd,
2036                                          tl,
2037                                          tl,
2038                                          pos);
2039     }
2040     /* do this call before callbacks (so that if callbacks destroy
2041      * session, they have a chance to cancel actions done by this
2042      * call) */
2043     process_pending_messages (session);
2044     pid = session->target;
2045     /* no do callbacks and do not use session again since
2046      * the callbacks may abort the session */
2047     while (NULL != (pos = hd))
2048     {
2049       GNUNET_CONTAINER_DLL_remove (hd,
2050                                    tl,
2051                                    pos);
2052       if (NULL != pos->transmit_cont)
2053         pos->transmit_cont (pos->transmit_cont_cls,
2054                             &pid,
2055                             GNUNET_SYSERR,
2056                             pos->message_size,
2057                             0);
2058       GNUNET_free (pos);
2059     }
2060     GNUNET_STATISTICS_update (plugin->env->stats,
2061                               gettext_noop ("# bytes currently in TCP buffers"), -(int64_t) ret,
2062                               GNUNET_NO);
2063     GNUNET_STATISTICS_update (plugin->env->stats,
2064                               gettext_noop ("# bytes discarded by TCP (timeout)"),
2065                               ret,
2066                               GNUNET_NO);
2067     if (0 < ret)
2068       notify_session_monitor (session->plugin,
2069                               session,
2070                               GNUNET_TRANSPORT_SS_UPDATE);
2071     return 0;
2072   }
2073   /* copy all pending messages that would fit */
2074   ret = 0;
2075   cbuf = buf;
2076   hd = NULL;
2077   tl = NULL;
2078   while (NULL != (pos = session->pending_messages_head))
2079   {
2080     if (ret + pos->message_size > size)
2081       break;
2082     GNUNET_CONTAINER_DLL_remove (session->pending_messages_head,
2083                                  session->pending_messages_tail,
2084                                  pos);
2085     GNUNET_assert (0 < session->msgs_in_queue);
2086     session->msgs_in_queue--;
2087     GNUNET_assert (pos->message_size <= session->bytes_in_queue);
2088     session->bytes_in_queue -= pos->message_size;
2089     GNUNET_assert(size >= pos->message_size);
2090     LOG (GNUNET_ERROR_TYPE_DEBUG,
2091          "Transmitting message of type %u size %u to peer %s at %s\n",
2092          ntohs (((struct GNUNET_MessageHeader *) pos->msg)->type),
2093          pos->message_size,
2094          GNUNET_i2s (&session->target),
2095          tcp_plugin_address_to_string (session->plugin,
2096                                        session->address->address,
2097                                        session->address->address_length));
2098     /* FIXME: this GNUNET_memcpy can be up to 7% of our total runtime */
2099     GNUNET_memcpy (cbuf,
2100             pos->msg,
2101             pos->message_size);
2102     cbuf += pos->message_size;
2103     ret += pos->message_size;
2104     size -= pos->message_size;
2105     GNUNET_CONTAINER_DLL_insert_tail (hd,
2106                                       tl,
2107                                       pos);
2108   }
2109   notify_session_monitor (session->plugin,
2110                           session,
2111                           GNUNET_TRANSPORT_SS_UPDATE);
2112   /* schedule 'continuation' before callbacks so that callbacks that
2113    * cancel everything don't cause us to use a session that no longer
2114    * exists... */
2115   process_pending_messages (session);
2116   session->last_activity = GNUNET_TIME_absolute_get ();
2117   pid = session->target;
2118   /* we'll now call callbacks that may cancel the session; hence
2119    * we should not use 'session' after this point */
2120   while (NULL != (pos = hd))
2121   {
2122     GNUNET_CONTAINER_DLL_remove (hd, tl, pos);
2123     if (NULL != pos->transmit_cont)
2124       pos->transmit_cont (pos->transmit_cont_cls,
2125                           &pid,
2126                           GNUNET_OK,
2127                           pos->message_size,
2128                           pos->message_size); /* FIXME: include TCP overhead */
2129     GNUNET_free (pos);
2130   }
2131   GNUNET_assert (NULL == hd);
2132   GNUNET_assert (NULL == tl);
2133   GNUNET_STATISTICS_update (plugin->env->stats,
2134                             gettext_noop ("# bytes currently in TCP buffers"),
2135                             - (int64_t) ret,
2136                             GNUNET_NO);
2137   GNUNET_STATISTICS_update (plugin->env->stats,
2138                             gettext_noop ("# bytes transmitted via TCP"),
2139                             ret,
2140                             GNUNET_NO);
2141   return ret;
2142 }
2143
2144
2145 /**
2146  * If we have pending messages, ask the server to
2147  * transmit them (schedule the respective tasks, etc.)
2148  *
2149  * @param session for which session should we do this
2150  */
2151 static void
2152 process_pending_messages (struct GNUNET_ATS_Session *session)
2153 {
2154   struct PendingMessage *pm;
2155
2156   GNUNET_assert (NULL != session->client);
2157   if (NULL != session->transmit_handle)
2158     return;
2159   if (NULL == (pm = session->pending_messages_head))
2160     return;
2161
2162   session->transmit_handle
2163     = GNUNET_SERVER_notify_transmit_ready (session->client,
2164                                            pm->message_size,
2165                                            GNUNET_TIME_absolute_get_remaining (pm->timeout),
2166                                            &do_transmit,
2167                                            session);
2168 }
2169
2170
2171 /**
2172  * Function that can be used by the transport service to transmit
2173  * a message using the plugin.   Note that in the case of a
2174  * peer disconnecting, the continuation MUST be called
2175  * prior to the disconnect notification itself.  This function
2176  * will be called with this peer's HELLO message to initiate
2177  * a fresh connection to another peer.
2178  *
2179  * @param cls closure
2180  * @param session which session must be used
2181  * @param msgbuf the message to transmit
2182  * @param msgbuf_size number of bytes in @a msgbuf
2183  * @param priority how important is the message (most plugins will
2184  *                 ignore message priority and just FIFO)
2185  * @param to how long to wait at most for the transmission (does not
2186  *                require plugins to discard the message after the timeout,
2187  *                just advisory for the desired delay; most plugins will ignore
2188  *                this as well)
2189  * @param cont continuation to call once the message has
2190  *        been transmitted (or if the transport is ready
2191  *        for the next transmission call; or if the
2192  *        peer disconnected...); can be NULL
2193  * @param cont_cls closure for @a cont
2194  * @return number of bytes used (on the physical network, with overheads);
2195  *         -1 on hard errors (i.e. address invalid); 0 is a legal value
2196  *         and does NOT mean that the message was not transmitted (DV)
2197  */
2198 static ssize_t
2199 tcp_plugin_send (void *cls,
2200                  struct GNUNET_ATS_Session *session,
2201                  const char *msgbuf,
2202                  size_t msgbuf_size,
2203                  unsigned int priority,
2204                  struct GNUNET_TIME_Relative to,
2205                  GNUNET_TRANSPORT_TransmitContinuation cont,
2206                  void *cont_cls)
2207 {
2208   struct Plugin * plugin = cls;
2209   struct PendingMessage *pm;
2210
2211   /* create new message entry */
2212   pm = GNUNET_malloc (sizeof (struct PendingMessage) + msgbuf_size);
2213   pm->msg = (const char *) &pm[1];
2214   GNUNET_memcpy (&pm[1], msgbuf, msgbuf_size);
2215   pm->message_size = msgbuf_size;
2216   pm->timeout = GNUNET_TIME_relative_to_absolute (to);
2217   pm->transmit_cont = cont;
2218   pm->transmit_cont_cls = cont_cls;
2219
2220   LOG (GNUNET_ERROR_TYPE_DEBUG,
2221        "Asked to transmit %u bytes to `%s', added message to list.\n",
2222        msgbuf_size,
2223        GNUNET_i2s (&session->target));
2224
2225   if (GNUNET_YES ==
2226       GNUNET_CONTAINER_multipeermap_contains_value (plugin->sessionmap,
2227                                                     &session->target,
2228                                                     session))
2229   {
2230     GNUNET_assert (NULL != session->client);
2231     GNUNET_SERVER_client_set_timeout (session->client,
2232                                       GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2233     GNUNET_STATISTICS_update (plugin->env->stats,
2234                               gettext_noop ("# bytes currently in TCP buffers"),
2235                               msgbuf_size,
2236                               GNUNET_NO);
2237
2238     /* append pm to pending_messages list */
2239     GNUNET_CONTAINER_DLL_insert_tail (session->pending_messages_head,
2240                                       session->pending_messages_tail,
2241                                       pm);
2242     notify_session_monitor (session->plugin,
2243                             session,
2244                             GNUNET_TRANSPORT_SS_UPDATE);
2245     session->msgs_in_queue++;
2246     session->bytes_in_queue += pm->message_size;
2247     process_pending_messages (session);
2248     return msgbuf_size;
2249   }
2250   if (GNUNET_YES ==
2251       GNUNET_CONTAINER_multipeermap_contains_value (plugin->nat_wait_conns,
2252                                                     &session->target,
2253                                                     session))
2254   {
2255     LOG (GNUNET_ERROR_TYPE_DEBUG,
2256          "This NAT WAIT session for peer `%s' is not yet ready!\n",
2257          GNUNET_i2s (&session->target));
2258     GNUNET_STATISTICS_update (plugin->env->stats,
2259                               gettext_noop ("# bytes currently in TCP buffers"), msgbuf_size,
2260                               GNUNET_NO);
2261     /* append pm to pending_messages list */
2262     GNUNET_CONTAINER_DLL_insert_tail (session->pending_messages_head,
2263                                       session->pending_messages_tail,
2264                                       pm);
2265     session->msgs_in_queue++;
2266     session->bytes_in_queue += pm->message_size;
2267     notify_session_monitor (session->plugin,
2268                             session,
2269                             GNUNET_TRANSPORT_SS_HANDSHAKE);
2270     return msgbuf_size;
2271   }
2272   LOG (GNUNET_ERROR_TYPE_ERROR,
2273        "Invalid session %p\n",
2274        session);
2275   if (NULL != cont)
2276     cont (cont_cls,
2277           &session->target,
2278           GNUNET_SYSERR,
2279           pm->message_size,
2280           0);
2281   GNUNET_break (0);
2282   GNUNET_free (pm);
2283   return GNUNET_SYSERR; /* session does not exist here */
2284 }
2285
2286
2287 /**
2288  * Closure for #session_lookup_it().
2289  */
2290 struct GNUNET_ATS_SessionItCtx
2291 {
2292   /**
2293    * Address we are looking for.
2294    */
2295   const struct GNUNET_HELLO_Address *address;
2296
2297   /**
2298    * Where to store the session (if we found it).
2299    */
2300   struct GNUNET_ATS_Session *result;
2301
2302 };
2303
2304
2305 /**
2306  * Look for a session by address.
2307  *
2308  * @param cls the `struct GNUNET_ATS_SessionItCtx`
2309  * @param key unused
2310  * @param value a `struct GNUNET_ATS_Session`
2311  * @return #GNUNET_YES to continue looking, #GNUNET_NO if we found the session
2312  */
2313 static int
2314 session_lookup_it (void *cls,
2315                    const struct GNUNET_PeerIdentity *key,
2316                    void *value)
2317 {
2318   struct GNUNET_ATS_SessionItCtx *si_ctx = cls;
2319   struct GNUNET_ATS_Session *session = value;
2320
2321   if (0 !=
2322       GNUNET_HELLO_address_cmp (si_ctx->address,
2323                                 session->address))
2324     return GNUNET_YES;
2325   si_ctx->result = session;
2326   return GNUNET_NO;
2327 }
2328
2329
2330 /**
2331  * Task cleaning up a NAT connection attempt after timeout
2332  *
2333  * @param cls the `struct GNUNET_ATS_Session`
2334  */
2335 static void
2336 nat_connect_timeout (void *cls)
2337 {
2338   struct GNUNET_ATS_Session *session = cls;
2339
2340   session->nat_connection_timeout = NULL;
2341   LOG (GNUNET_ERROR_TYPE_DEBUG,
2342        "NAT WAIT connection to `%4s' at `%s' could not be established, removing session\n",
2343        GNUNET_i2s (&session->target),
2344        tcp_plugin_address_to_string (session->plugin,
2345                                      session->address->address,
2346                                      session->address->address_length));
2347   tcp_plugin_disconnect_session (session->plugin,
2348                                  session);
2349 }
2350
2351
2352 /**
2353  * Function that will be called whenever the transport service wants to
2354  * notify the plugin that a session is still active and in use and
2355  * therefore the session timeout for this session has to be updated
2356  *
2357  * @param cls closure
2358  * @param peer which peer was the session for
2359  * @param session which session is being updated
2360  */
2361 static void
2362 tcp_plugin_update_session_timeout (void *cls,
2363                                    const struct GNUNET_PeerIdentity *peer,
2364                                    struct GNUNET_ATS_Session *session)
2365 {
2366   reschedule_session_timeout (session);
2367 }
2368
2369
2370 /**
2371  * Task to signal the server that we can continue
2372  * receiving from the TCP client now.
2373  *
2374  * @param cls the `struct GNUNET_ATS_Session *`
2375  */
2376 static void
2377 delayed_done (void *cls)
2378 {
2379   struct GNUNET_ATS_Session *session = cls;
2380
2381   session->receive_delay_task = NULL;
2382   reschedule_session_timeout (session);
2383   GNUNET_SERVER_receive_done (session->client,
2384                               GNUNET_OK);
2385 }
2386
2387
2388 /**
2389  * Function that will be called whenever the transport service wants to
2390  * notify the plugin that the inbound quota changed and that the plugin
2391  * should update it's delay for the next receive value
2392  *
2393  * @param cls closure
2394  * @param peer which peer was the session for
2395  * @param session which session is being updated
2396  * @param delay new delay to use for receiving
2397  */
2398 static void
2399 tcp_plugin_update_inbound_delay (void *cls,
2400                                  const struct GNUNET_PeerIdentity *peer,
2401                                  struct GNUNET_ATS_Session *session,
2402                                  struct GNUNET_TIME_Relative delay)
2403 {
2404   if (NULL == session->receive_delay_task)
2405     return;
2406   LOG (GNUNET_ERROR_TYPE_DEBUG,
2407        "New inbound delay %s\n",
2408        GNUNET_STRINGS_relative_time_to_string (delay,
2409                                                GNUNET_NO));
2410   session->receive_delay = GNUNET_TIME_relative_to_absolute (delay);
2411   GNUNET_SCHEDULER_cancel (session->receive_delay_task);
2412   session->receive_delay_task = GNUNET_SCHEDULER_add_delayed (delay,
2413                                                               &delayed_done,
2414                                                               session);
2415 }
2416
2417
2418 /**
2419  * Create a new session to transmit data to the target
2420  * This session will used to send data to this peer and the plugin will
2421  * notify us by calling the env->session_end function
2422  *
2423  * @param cls closure
2424  * @param address the address to use
2425  * @return the session if the address is valid, NULL otherwise
2426  */
2427 static struct GNUNET_ATS_Session *
2428 tcp_plugin_get_session (void *cls,
2429                         const struct GNUNET_HELLO_Address *address)
2430 {
2431   struct Plugin *plugin = cls;
2432   struct GNUNET_ATS_Session *session = NULL;
2433   int af;
2434   const void *sb;
2435   size_t sbs;
2436   struct GNUNET_CONNECTION_Handle *sa;
2437   struct sockaddr_in a4;
2438   struct sockaddr_in6 a6;
2439   const struct IPv4TcpAddress *t4;
2440   const struct IPv6TcpAddress *t6;
2441   unsigned int options;
2442   enum GNUNET_ATS_Network_Type net_type;
2443   unsigned int is_natd = GNUNET_NO;
2444   size_t addrlen;
2445 #ifdef TCP_STEALTH
2446   struct GNUNET_NETWORK_Handle *s;
2447 #endif
2448
2449   addrlen = address->address_length;
2450   LOG (GNUNET_ERROR_TYPE_DEBUG,
2451        "Trying to get session for `%s' address of peer `%s'\n",
2452        tcp_plugin_address_to_string (plugin,
2453                                      address->address,
2454                                      address->address_length),
2455        GNUNET_i2s (&address->peer));
2456
2457   if (GNUNET_HELLO_address_check_option (address,
2458                                          GNUNET_HELLO_ADDRESS_INFO_INBOUND))
2459   {
2460     GNUNET_break (0);
2461     return NULL;
2462   }
2463
2464   /* look for existing session */
2465   if (GNUNET_YES ==
2466       GNUNET_CONTAINER_multipeermap_contains (plugin->sessionmap,
2467                                               &address->peer))
2468   {
2469     struct GNUNET_ATS_SessionItCtx si_ctx;
2470
2471     si_ctx.address = address;
2472     si_ctx.result = NULL;
2473     GNUNET_CONTAINER_multipeermap_get_multiple (plugin->sessionmap,
2474                                                 &address->peer,
2475                                                 &session_lookup_it,
2476                                                 &si_ctx);
2477     if (NULL != si_ctx.result)
2478     {
2479       session = si_ctx.result;
2480       LOG (GNUNET_ERROR_TYPE_DEBUG,
2481            "Found existing session for `%s' address `%s'\n",
2482            GNUNET_i2s (&address->peer),
2483            tcp_plugin_address_to_string (plugin,
2484                                          address->address,
2485                                          address->address_length));
2486       return session;
2487     }
2488     /* This is a bit of a hack, limiting TCP to never allow more than
2489        one TCP connection to any given peer at the same time.
2490        Without this, peers sometimes disagree about which of the TCP
2491        connections they should use, causing one side to believe that
2492        they transmit successfully, while the other receives nothing. */
2493     return NULL; /* Refuse to have more than one TCP connection per
2494                     peer pair at the same time. */
2495   }
2496
2497   if (addrlen == sizeof(struct IPv6TcpAddress))
2498   {
2499     GNUNET_assert (NULL != address->address); /* make static analysis happy */
2500     t6 = address->address;
2501     options = t6->options;
2502     af = AF_INET6;
2503     memset (&a6, 0, sizeof(a6));
2504 #if HAVE_SOCKADDR_IN_SIN_LEN
2505     a6.sin6_len = sizeof (a6);
2506 #endif
2507     a6.sin6_family = AF_INET6;
2508     a6.sin6_port = t6->t6_port;
2509     if (t6->t6_port == 0)
2510       is_natd = GNUNET_YES;
2511     GNUNET_memcpy (&a6.sin6_addr, &t6->ipv6_addr, sizeof(struct in6_addr));
2512     sb = &a6;
2513     sbs = sizeof(a6);
2514   }
2515   else if (addrlen == sizeof(struct IPv4TcpAddress))
2516   {
2517     GNUNET_assert(NULL != address->address); /* make static analysis happy */
2518     t4 = address->address;
2519     options = t4->options;
2520     af = AF_INET;
2521     memset (&a4, 0, sizeof(a4));
2522 #if HAVE_SOCKADDR_IN_SIN_LEN
2523     a4.sin_len = sizeof (a4);
2524 #endif
2525     a4.sin_family = AF_INET;
2526     a4.sin_port = t4->t4_port;
2527     if (t4->t4_port == 0)
2528       is_natd = GNUNET_YES;
2529     a4.sin_addr.s_addr = t4->ipv4_addr;
2530     sb = &a4;
2531     sbs = sizeof(a4);
2532   }
2533   else
2534   {
2535     GNUNET_STATISTICS_update (plugin->env->stats,
2536                               gettext_noop ("# requests to create session with invalid address"),
2537                               1,
2538                               GNUNET_NO);
2539     return NULL;
2540   }
2541
2542   net_type = plugin->env->get_address_type (plugin->env->cls,
2543                                             sb,
2544                                             sbs);
2545   GNUNET_break (net_type != GNUNET_ATS_NET_UNSPECIFIED);
2546
2547   if ( (is_natd == GNUNET_YES) &&
2548        (addrlen == sizeof(struct IPv6TcpAddress)) )
2549   {
2550     /* NAT client only works with IPv4 addresses */
2551     return NULL;
2552   }
2553
2554   if (plugin->cur_connections >= plugin->max_connections)
2555   {
2556     /* saturated */
2557     return NULL;
2558   }
2559
2560   if ( (is_natd == GNUNET_YES) &&
2561        (GNUNET_YES ==
2562         GNUNET_CONTAINER_multipeermap_contains (plugin->nat_wait_conns,
2563                                                 &address->peer)))
2564   {
2565     /* Only do one NAT punch attempt per peer identity */
2566     return NULL;
2567   }
2568
2569   if ( (is_natd == GNUNET_YES) &&
2570        (NULL != plugin->nat) &&
2571        (GNUNET_NO ==
2572         GNUNET_CONTAINER_multipeermap_contains (plugin->nat_wait_conns,
2573                                                 &address->peer)))
2574   {
2575     struct sockaddr_in local_sa;
2576
2577     LOG (GNUNET_ERROR_TYPE_DEBUG,
2578          "Found valid IPv4 NAT address (creating session)!\n");
2579     session = create_session (plugin,
2580                               address,
2581                               net_type,
2582                               NULL,
2583                               GNUNET_YES);
2584     session->nat_connection_timeout = GNUNET_SCHEDULER_add_delayed (NAT_TIMEOUT,
2585                                                                     &nat_connect_timeout,
2586                                                                     session);
2587     GNUNET_assert (GNUNET_OK ==
2588                    GNUNET_CONTAINER_multipeermap_put (plugin->nat_wait_conns,
2589                                                       &session->target,
2590                                                       session,
2591                                                       GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
2592
2593     LOG (GNUNET_ERROR_TYPE_DEBUG,
2594          "Created NAT WAIT connection to `%s' at `%s'\n",
2595          GNUNET_i2s (&session->target),
2596          GNUNET_a2s (sb, sbs));
2597     memset (&local_sa,
2598             0,
2599             sizeof (local_sa));
2600     local_sa.sin_family = AF_INET;
2601     local_sa.sin_port = htons (plugin->open_port);
2602     /* We leave sin_address at 0, let the kernel figure it out,
2603        even if our bind() is more specific.  (May want to reconsider
2604        later.) */
2605     if (GNUNET_OK ==
2606         GNUNET_NAT_request_reversal (plugin->nat,
2607                                      &local_sa,
2608                                      &a4))
2609       return session;
2610     LOG (GNUNET_ERROR_TYPE_DEBUG,
2611          "Running NAT client for `%s' at `%s' failed\n",
2612          GNUNET_i2s (&session->target),
2613          GNUNET_a2s (sb, sbs));
2614     tcp_plugin_disconnect_session (plugin,
2615                                    session);
2616     return NULL;
2617   }
2618
2619   /* create new outbound session */
2620   if (0 != (options & TCP_OPTIONS_TCP_STEALTH))
2621   {
2622 #ifdef TCP_STEALTH
2623     s = GNUNET_NETWORK_socket_create (af, SOCK_STREAM, 0);
2624     if (NULL == s)
2625     {
2626       GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK,
2627                            "socket");
2628       sa = NULL;
2629     }
2630     else
2631     {
2632       if ( (GNUNET_OK !=
2633             GNUNET_NETWORK_socket_setsockopt (s,
2634                                               IPPROTO_TCP,
2635                                               TCP_STEALTH,
2636                                               &session->target,
2637                                               sizeof (struct GNUNET_PeerIdentity))) ||
2638            (GNUNET_OK !=
2639             GNUNET_NETWORK_socket_setsockopt (s,
2640                                               IPPROTO_TCP,
2641                                               TCP_STEALTH_INTEGRITY,
2642                                               &plugin->my_welcome,
2643                                               sizeof (struct WelcomeMessage))) )
2644       {
2645         /* TCP STEALTH not supported by kernel */
2646         GNUNET_break (GNUNET_OK ==
2647                       GNUNET_NETWORK_socket_close (s));
2648         sa = NULL;
2649       }
2650       else
2651       {
2652         sa = GNUNET_CONNECTION_connect_socket (s, sb, sbs);
2653       }
2654     }
2655 #else
2656     sa = NULL;
2657 #endif
2658   }
2659   else
2660   {
2661     sa = GNUNET_CONNECTION_create_from_sockaddr (af, sb, sbs);
2662   }
2663   if (NULL == sa)
2664   {
2665     LOG (GNUNET_ERROR_TYPE_DEBUG,
2666          "Failed to create connection to `%s' at `%s'\n",
2667          GNUNET_i2s (&address->peer),
2668          GNUNET_a2s (sb, sbs));
2669     return NULL;
2670   }
2671   LOG (GNUNET_ERROR_TYPE_DEBUG,
2672        "Asked to transmit to `%s', creating fresh session using address `%s'.\n",
2673        GNUNET_i2s (&address->peer),
2674        GNUNET_a2s (sb, sbs));
2675
2676   session = create_session (plugin,
2677                             address,
2678                             net_type,
2679                             GNUNET_SERVER_connect_socket (plugin->server,
2680                                                           sa),
2681                             GNUNET_NO);
2682   (void) GNUNET_CONTAINER_multipeermap_put (plugin->sessionmap,
2683                                             &session->target,
2684                                             session,
2685                                             GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
2686   /* Send TCP Welcome */
2687   process_pending_messages (session);
2688
2689   return session;
2690 }
2691
2692
2693 /**
2694  * We have been asked to destroy all connections to a particular peer.
2695  * This function is called on each applicable session and must tear it
2696  * down.
2697  *
2698  * @param cls the `struct Plugin *`
2699  * @param key the peer which the session belongs to (unused)
2700  * @param value the `struct GNUNET_ATS_Session`
2701  * @return #GNUNET_YES (continue to iterate)
2702  */
2703 static int
2704 session_disconnect_it (void *cls,
2705                        const struct GNUNET_PeerIdentity *key,
2706                        void *value)
2707 {
2708   struct Plugin *plugin = cls;
2709   struct GNUNET_ATS_Session *session = value;
2710
2711   GNUNET_STATISTICS_update (session->plugin->env->stats,
2712                             gettext_noop ("# transport-service disconnect requests for TCP"),
2713                             1,
2714                             GNUNET_NO);
2715   tcp_plugin_disconnect_session (plugin,
2716                                  session);
2717   return GNUNET_YES;
2718 }
2719
2720
2721 /**
2722  * Function that can be called to force a disconnect from the
2723  * specified neighbour.  This should also cancel all previously
2724  * scheduled transmissions.  Obviously the transmission may have been
2725  * partially completed already, which is OK.  The plugin is supposed
2726  * to close the connection (if applicable) and no longer call the
2727  * transmit continuation(s).
2728  *
2729  * Finally, plugin MUST NOT call the services's receive function to
2730  * notify the service that the connection to the specified target was
2731  * closed after a getting this call.
2732  *
2733  * @param cls closure
2734  * @param target peer for which the last transmission is
2735  *        to be cancelled
2736  */
2737 static void
2738 tcp_plugin_disconnect (void *cls,
2739                        const struct GNUNET_PeerIdentity *target)
2740 {
2741   struct Plugin *plugin = cls;
2742
2743   LOG (GNUNET_ERROR_TYPE_DEBUG,
2744        "Disconnecting peer `%s'\n",
2745        GNUNET_i2s (target));
2746   GNUNET_CONTAINER_multipeermap_get_multiple (plugin->sessionmap,
2747                                               target,
2748                                               &session_disconnect_it,
2749                                               plugin);
2750   GNUNET_CONTAINER_multipeermap_get_multiple (plugin->nat_wait_conns,
2751                                               target,
2752                                               &session_disconnect_it,
2753                                               plugin);
2754 }
2755
2756
2757 /**
2758  * We are processing an address pretty printing request and finished
2759  * the IP resolution (if applicable).  Append our port and forward the
2760  * result.  If called with @a hostname NULL, we are done and should
2761  * clean up the pretty printer (otherwise, there might be multiple
2762  * hostnames for the IP address and we might receive more).
2763  *
2764  * @param cls the `struct PrettyPrinterContext *`
2765  * @param hostname hostname part of the address
2766  */
2767 static void
2768 append_port (void *cls,
2769              const char *hostname)
2770 {
2771   struct PrettyPrinterContext *ppc = cls;
2772   struct Plugin *plugin = ppc->plugin;
2773   char *ret;
2774
2775   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2776               "append_port called with hostname `%s'\n",
2777               hostname);
2778   if (NULL == hostname)
2779   {
2780     /* Final call, done */
2781     ppc->resolver_handle = NULL;
2782     GNUNET_CONTAINER_DLL_remove (plugin->ppc_dll_head,
2783                                  plugin->ppc_dll_tail,
2784                                  ppc);
2785     ppc->asc (ppc->asc_cls,
2786               NULL,
2787               GNUNET_OK);
2788     GNUNET_free (ppc);
2789     return;
2790   }
2791   if (GNUNET_YES == ppc->ipv6)
2792     GNUNET_asprintf (&ret,
2793                      "%s.%u.[%s]:%d",
2794                      PLUGIN_NAME,
2795                      ppc->options,
2796                      hostname,
2797                      ppc->port);
2798   else
2799     GNUNET_asprintf (&ret,
2800                      "%s.%u.%s:%d",
2801                      PLUGIN_NAME,
2802                      ppc->options,
2803                      hostname,
2804                      ppc->port);
2805   ppc->asc (ppc->asc_cls,
2806             ret,
2807             GNUNET_OK);
2808   GNUNET_free (ret);
2809 }
2810
2811
2812 /**
2813  * Convert the transports address to a nice, human-readable format.
2814  *
2815  * @param cls closure with the `struct Plugin`
2816  * @param type name of the transport that generated the address
2817  * @param addr one of the addresses of the host, NULL for the last address
2818  *        the specific address format depends on the transport
2819  * @param addrlen length of the @a addr
2820  * @param numeric should (IP) addresses be displayed in numeric form?
2821  * @param timeout after how long should we give up?
2822  * @param asc function to call on each string
2823  * @param asc_cls closure for @a asc
2824  */
2825 static void
2826 tcp_plugin_address_pretty_printer (void *cls,
2827                                    const char *type,
2828                                    const void *addr,
2829                                    size_t addrlen,
2830                                    int numeric,
2831                                    struct GNUNET_TIME_Relative timeout,
2832                                    GNUNET_TRANSPORT_AddressStringCallback asc,
2833                                    void *asc_cls)
2834 {
2835   struct Plugin *plugin = cls;
2836   struct PrettyPrinterContext *ppc;
2837   const void *sb;
2838   size_t sbs;
2839   struct sockaddr_in a4;
2840   struct sockaddr_in6 a6;
2841   const struct IPv4TcpAddress *t4;
2842   const struct IPv6TcpAddress *t6;
2843   uint16_t port;
2844   uint32_t options;
2845
2846   if (sizeof(struct IPv6TcpAddress) == addrlen)
2847   {
2848     t6 = addr;
2849     memset (&a6, 0, sizeof(a6));
2850     a6.sin6_family = AF_INET6;
2851     a6.sin6_port = t6->t6_port;
2852     GNUNET_memcpy (&a6.sin6_addr, &t6->ipv6_addr, sizeof(struct in6_addr));
2853     port = ntohs (t6->t6_port);
2854     options = ntohl (t6->options);
2855     sb = &a6;
2856     sbs = sizeof(a6);
2857   }
2858   else if (sizeof(struct IPv4TcpAddress) == addrlen)
2859   {
2860     t4 = addr;
2861     memset (&a4, 0, sizeof(a4));
2862     a4.sin_family = AF_INET;
2863     a4.sin_port = t4->t4_port;
2864     a4.sin_addr.s_addr = t4->ipv4_addr;
2865     port = ntohs (t4->t4_port);
2866     options = ntohl (t4->options);
2867     sb = &a4;
2868     sbs = sizeof(a4);
2869   }
2870   else
2871   {
2872     /* invalid address */
2873     LOG (GNUNET_ERROR_TYPE_WARNING,
2874          _("Unexpected address length: %u bytes\n"),
2875          (unsigned int) addrlen);
2876     asc (asc_cls, NULL, GNUNET_SYSERR);
2877     asc (asc_cls, NULL, GNUNET_OK);
2878     return;
2879   }
2880   ppc = GNUNET_new (struct PrettyPrinterContext);
2881   ppc->plugin = plugin;
2882   if (addrlen == sizeof(struct IPv6TcpAddress))
2883     ppc->ipv6 = GNUNET_YES;
2884   else
2885     ppc->ipv6 = GNUNET_NO;
2886   ppc->asc = asc;
2887   ppc->asc_cls = asc_cls;
2888   ppc->port = port;
2889   ppc->options = options;
2890   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2891               "Starting DNS reverse lookup\n");
2892   ppc->resolver_handle = GNUNET_RESOLVER_hostname_get (sb,
2893                                                        sbs,
2894                                                        ! numeric,
2895                                                        timeout,
2896                                                        &append_port,
2897                                                        ppc);
2898   if (NULL == ppc->resolver_handle)
2899   {
2900     GNUNET_break (0);
2901     GNUNET_free (ppc);
2902     return;
2903   }
2904   GNUNET_CONTAINER_DLL_insert (plugin->ppc_dll_head,
2905                                plugin->ppc_dll_tail,
2906                                ppc);
2907 }
2908
2909
2910 /**
2911  * Function that will be called to check if a binary address for this
2912  * plugin is well-formed and corresponds to an address for THIS peer
2913  * (as per our configuration).  Naturally, if absolutely necessary,
2914  * plugins can be a bit conservative in their answer, but in general
2915  * plugins should make sure that the address does not redirect
2916  * traffic to a 3rd party that might try to man-in-the-middle our
2917  * traffic.
2918  *
2919  * @param cls closure, our `struct Plugin *`
2920  * @param addr pointer to the address
2921  * @param addrlen length of @a addr
2922  * @return #GNUNET_OK if this is a plausible address for this peer
2923  *         and transport, #GNUNET_SYSERR if not
2924  */
2925 static int
2926 tcp_plugin_check_address (void *cls,
2927                           const void *addr,
2928                           size_t addrlen)
2929 {
2930   struct Plugin *plugin = cls;
2931   const struct IPv4TcpAddress *v4;
2932   const struct IPv6TcpAddress *v6;
2933
2934   if ( (addrlen != sizeof(struct IPv4TcpAddress)) &&
2935        (addrlen != sizeof(struct IPv6TcpAddress)) )
2936   {
2937     GNUNET_break_op (0);
2938     return GNUNET_SYSERR;
2939   }
2940
2941   if (addrlen == sizeof(struct IPv4TcpAddress))
2942   {
2943     struct sockaddr_in s4;
2944
2945     v4 = (const struct IPv4TcpAddress *) addr;
2946     if (0 != memcmp (&v4->options,
2947                      &plugin->myoptions,
2948                      sizeof(uint32_t)))
2949     {
2950       GNUNET_break (0);
2951       return GNUNET_SYSERR;
2952     }
2953     memset (&s4, 0, sizeof (s4));
2954     s4.sin_family = AF_INET;
2955 #if HAVE_SOCKADDR_IN_SIN_LEN
2956     s4.sin_len = sizeof (s4);
2957 #endif
2958     s4.sin_port = v4->t4_port;
2959     s4.sin_addr.s_addr = v4->ipv4_addr;
2960
2961     if (GNUNET_OK !=
2962         GNUNET_NAT_test_address (plugin->nat,
2963                                  &s4,
2964                                  sizeof (struct sockaddr_in)))
2965       return GNUNET_SYSERR;
2966   }
2967   else
2968   {
2969     struct sockaddr_in6 s6;
2970
2971     v6 = (const struct IPv6TcpAddress *) addr;
2972     if (IN6_IS_ADDR_LINKLOCAL (&v6->ipv6_addr))
2973     {
2974       GNUNET_break_op (0);
2975       return GNUNET_SYSERR;
2976     }
2977     if (0 != memcmp (&v6->options,
2978                      &plugin->myoptions,
2979                      sizeof (uint32_t)))
2980     {
2981       GNUNET_break (0);
2982       return GNUNET_SYSERR;
2983     }
2984     memset (&s6, 0, sizeof (s6));
2985     s6.sin6_family = AF_INET6;
2986 #if HAVE_SOCKADDR_IN_SIN_LEN
2987     s6.sin6_len = sizeof (s6);
2988 #endif
2989     s6.sin6_port = v6->t6_port;
2990     s6.sin6_addr = v6->ipv6_addr;
2991
2992     if (GNUNET_OK !=
2993         GNUNET_NAT_test_address (plugin->nat,
2994                                  &s6,
2995                                  sizeof(struct sockaddr_in6)))
2996       return GNUNET_SYSERR;
2997   }
2998   return GNUNET_OK;
2999 }
3000
3001
3002 /**
3003  * We've received a nat probe from this peer via TCP.  Finish
3004  * creating the client session and resume sending of queued
3005  * messages.
3006  *
3007  * @param cls closure
3008  * @param client identification of the client
3009  * @param message the actual message
3010  */
3011 static void
3012 handle_tcp_nat_probe (void *cls,
3013                       struct GNUNET_SERVER_Client *client,
3014                       const struct GNUNET_MessageHeader *message)
3015 {
3016   struct Plugin *plugin = cls;
3017   struct GNUNET_ATS_Session *session;
3018   const struct TCP_NAT_ProbeMessage *tcp_nat_probe;
3019   size_t alen;
3020   void *vaddr;
3021   struct IPv4TcpAddress *t4;
3022   struct IPv6TcpAddress *t6;
3023   const struct sockaddr_in *s4;
3024   const struct sockaddr_in6 *s6;
3025
3026   LOG (GNUNET_ERROR_TYPE_DEBUG,
3027        "Received NAT probe\n");
3028   /* We have received a TCP NAT probe, meaning we (hopefully) initiated
3029    * a connection to this peer by running gnunet-nat-client.  This peer
3030    * received the punch message and now wants us to use the new connection
3031    * as the default for that peer.  Do so and then send a WELCOME message
3032    * so we can really be connected!
3033    */
3034   if (ntohs (message->size) != sizeof(struct TCP_NAT_ProbeMessage))
3035   {
3036     GNUNET_break_op(0);
3037     GNUNET_SERVER_receive_done (client,
3038                                 GNUNET_SYSERR);
3039     return;
3040   }
3041
3042   tcp_nat_probe = (const struct TCP_NAT_ProbeMessage *) message;
3043   if (0 == memcmp (&tcp_nat_probe->clientIdentity, plugin->env->my_identity,
3044           sizeof(struct GNUNET_PeerIdentity)))
3045   {
3046     /* refuse connections from ourselves */
3047     GNUNET_SERVER_receive_done (client,
3048                                 GNUNET_SYSERR);
3049     return;
3050   }
3051
3052   session = GNUNET_CONTAINER_multipeermap_get (plugin->nat_wait_conns,
3053                                                &tcp_nat_probe->clientIdentity);
3054   if (NULL == session)
3055   {
3056     LOG (GNUNET_ERROR_TYPE_DEBUG,
3057          "Did NOT find session for NAT probe!\n");
3058     GNUNET_SERVER_receive_done (client,
3059                                 GNUNET_OK);
3060     return;
3061   }
3062   LOG (GNUNET_ERROR_TYPE_DEBUG,
3063        "Found session for NAT probe!\n");
3064
3065   if (NULL != session->nat_connection_timeout)
3066   {
3067     GNUNET_SCHEDULER_cancel (session->nat_connection_timeout);
3068     session->nat_connection_timeout = NULL;
3069   }
3070
3071   if (GNUNET_OK !=
3072       GNUNET_SERVER_client_get_address (client,
3073                                         &vaddr,
3074                                         &alen))
3075   {
3076     GNUNET_break(0);
3077     GNUNET_SERVER_receive_done (client,
3078                                 GNUNET_SYSERR);
3079     tcp_plugin_disconnect_session (plugin,
3080                                    session);
3081     return;
3082   }
3083   GNUNET_assert (GNUNET_YES ==
3084                  GNUNET_CONTAINER_multipeermap_remove (plugin->nat_wait_conns,
3085                                                        &tcp_nat_probe->clientIdentity,
3086                                                        session));
3087   GNUNET_SERVER_client_set_user_context (client,
3088                                          session);
3089   (void) GNUNET_CONTAINER_multipeermap_put (plugin->sessionmap,
3090                                             &session->target,
3091                                             session,
3092                                             GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
3093   session->last_activity = GNUNET_TIME_absolute_get ();
3094   LOG (GNUNET_ERROR_TYPE_DEBUG,
3095        "Found address `%s' for incoming connection\n",
3096        GNUNET_a2s (vaddr, alen));
3097   switch (((const struct sockaddr *) vaddr)->sa_family)
3098   {
3099   case AF_INET:
3100     s4 = vaddr;
3101     t4 = GNUNET_new (struct IPv4TcpAddress);
3102     t4->options = htonl (TCP_OPTIONS_NONE);
3103     t4->t4_port = s4->sin_port;
3104     t4->ipv4_addr = s4->sin_addr.s_addr;
3105     session->address = GNUNET_HELLO_address_allocate (&tcp_nat_probe->clientIdentity,
3106                                                       PLUGIN_NAME,
3107                                                       &t4,
3108                                                       sizeof(struct IPv4TcpAddress),
3109                                                       GNUNET_HELLO_ADDRESS_INFO_NONE);
3110     break;
3111   case AF_INET6:
3112     s6 = vaddr;
3113     t6 = GNUNET_new (struct IPv6TcpAddress);
3114     t6->options = htonl (TCP_OPTIONS_NONE);
3115     t6->t6_port = s6->sin6_port;
3116     GNUNET_memcpy (&t6->ipv6_addr, &s6->sin6_addr, sizeof(struct in6_addr));
3117     session->address = GNUNET_HELLO_address_allocate (&tcp_nat_probe->clientIdentity,
3118                                                       PLUGIN_NAME,
3119                                                       &t6,
3120                                                       sizeof(struct IPv6TcpAddress),
3121                                                       GNUNET_HELLO_ADDRESS_INFO_NONE);
3122     break;
3123   default:
3124     GNUNET_break_op(0);
3125     LOG(GNUNET_ERROR_TYPE_DEBUG,
3126         "Bad address for incoming connection!\n");
3127     GNUNET_free(vaddr);
3128     GNUNET_SERVER_receive_done (client,
3129                                 GNUNET_SYSERR);
3130     tcp_plugin_disconnect_session (plugin,
3131                                    session);
3132     return;
3133   }
3134   GNUNET_free (vaddr);
3135   GNUNET_break (NULL == session->client);
3136   session->client = client;
3137   GNUNET_STATISTICS_update (plugin->env->stats,
3138                             gettext_noop ("# TCP sessions active"),
3139                             1,
3140                             GNUNET_NO);
3141   process_pending_messages (session);
3142   GNUNET_SERVER_receive_done (client,
3143                               GNUNET_OK);
3144 }
3145
3146
3147 /**
3148  * We've received a welcome from this peer via TCP.  Possibly create a
3149  * fresh client record and send back our welcome.
3150  *
3151  * @param cls closure
3152  * @param client identification of the client
3153  * @param message the actual message
3154  */
3155 static void
3156 handle_tcp_welcome (void *cls,
3157                     struct GNUNET_SERVER_Client *client,
3158                     const struct GNUNET_MessageHeader *message)
3159 {
3160   struct Plugin *plugin = cls;
3161   const struct WelcomeMessage *wm = (const struct WelcomeMessage *) message;
3162   struct GNUNET_HELLO_Address *address;
3163   struct GNUNET_ATS_Session *session;
3164   size_t alen;
3165   void *vaddr;
3166   struct IPv4TcpAddress t4;
3167   struct IPv6TcpAddress t6;
3168   const struct sockaddr_in *s4;
3169   const struct sockaddr_in6 *s6;
3170
3171   if (0 == memcmp (&wm->clientIdentity,
3172                    plugin->env->my_identity,
3173                    sizeof(struct GNUNET_PeerIdentity)))
3174   {
3175     /* refuse connections from ourselves */
3176     if (GNUNET_OK ==
3177         GNUNET_SERVER_client_get_address (client,
3178                                           &vaddr,
3179                                           &alen))
3180     {
3181       LOG (GNUNET_ERROR_TYPE_INFO,
3182            "Received WELCOME message from my own identity `%s' on address `%s'\n",
3183            GNUNET_i2s (&wm->clientIdentity),
3184            GNUNET_a2s (vaddr, alen));
3185       GNUNET_free (vaddr);
3186     }
3187     GNUNET_SERVER_receive_done (client,
3188                                 GNUNET_SYSERR);
3189     return;
3190   }
3191
3192   if (GNUNET_OK ==
3193       GNUNET_SERVER_client_get_address (client,
3194                                         &vaddr,
3195                                         &alen))
3196   {
3197     LOG(GNUNET_ERROR_TYPE_DEBUG,
3198         "Received WELCOME message from `%s' on address `%s'\n",
3199         GNUNET_i2s (&wm->clientIdentity),
3200         GNUNET_a2s (vaddr, alen));
3201     GNUNET_free (vaddr);
3202   }
3203   GNUNET_STATISTICS_update (plugin->env->stats,
3204                             gettext_noop ("# TCP WELCOME messages received"),
3205                             1,
3206                             GNUNET_NO);
3207   session = lookup_session_by_client (plugin,
3208                                       client);
3209   if (NULL != session)
3210   {
3211     if (GNUNET_OK ==
3212         GNUNET_SERVER_client_get_address (client,
3213                                           &vaddr,
3214                                           &alen))
3215     {
3216       LOG (GNUNET_ERROR_TYPE_DEBUG,
3217            "Found existing session %p for peer `%s'\n",
3218            session,
3219            GNUNET_a2s (vaddr, alen));
3220       GNUNET_free (vaddr);
3221     }
3222   }
3223   else
3224   {
3225     if (GNUNET_OK ==
3226         GNUNET_SERVER_client_get_address (client, &vaddr, &alen))
3227     {
3228       if (alen == sizeof(struct sockaddr_in))
3229       {
3230         s4 = vaddr;
3231         memset (&t4, '\0', sizeof (t4));
3232         t4.options = htonl (TCP_OPTIONS_NONE);
3233         t4.t4_port = s4->sin_port;
3234         t4.ipv4_addr = s4->sin_addr.s_addr;
3235         address = GNUNET_HELLO_address_allocate (&wm->clientIdentity,
3236                                                  PLUGIN_NAME,
3237                                                  &t4,
3238                                                  sizeof(t4),
3239                                                  GNUNET_HELLO_ADDRESS_INFO_INBOUND);
3240       }
3241       else if (alen == sizeof(struct sockaddr_in6))
3242       {
3243         s6 = vaddr;
3244         memset (&t6, '\0', sizeof (t6));
3245         t6.options = htonl (TCP_OPTIONS_NONE);
3246         t6.t6_port = s6->sin6_port;
3247         GNUNET_memcpy (&t6.ipv6_addr, &s6->sin6_addr, sizeof(struct in6_addr));
3248         address = GNUNET_HELLO_address_allocate (&wm->clientIdentity,
3249                                                  PLUGIN_NAME,
3250                                                  &t6,
3251                                                  sizeof (t6),
3252                                                  GNUNET_HELLO_ADDRESS_INFO_INBOUND);
3253       }
3254       else
3255       {
3256         GNUNET_break (0);
3257         GNUNET_free_non_null (vaddr);
3258         GNUNET_SERVER_receive_done (client,
3259                                     GNUNET_SYSERR);
3260         return;
3261       }
3262       session = create_session (plugin,
3263                                 address,
3264                                 plugin->env->get_address_type (plugin->env->cls,
3265                                                                vaddr,
3266                                                                alen),
3267                                 client,
3268                                 GNUNET_NO);
3269       GNUNET_break (GNUNET_ATS_NET_UNSPECIFIED != session->scope);
3270       GNUNET_HELLO_address_free (address);
3271       LOG (GNUNET_ERROR_TYPE_DEBUG,
3272            "Creating new%s session %p for peer `%s' client %p\n",
3273            GNUNET_HELLO_address_check_option (session->address,
3274                                               GNUNET_HELLO_ADDRESS_INFO_INBOUND)
3275            ? " inbound" : "",
3276            session,
3277            tcp_plugin_address_to_string (plugin,
3278                                          session->address->address,
3279                                          session->address->address_length),
3280            client);
3281       GNUNET_free (vaddr);
3282       (void) GNUNET_CONTAINER_multipeermap_put (plugin->sessionmap,
3283                                                 &session->target,
3284                                                 session,
3285                                                 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
3286       /* Notify transport and ATS about new session */
3287       plugin->env->session_start (plugin->env->cls,
3288                                   session->address,
3289                                   session,
3290                                   session->scope);
3291     }
3292     else
3293     {
3294       LOG(GNUNET_ERROR_TYPE_DEBUG,
3295           "Did not obtain TCP socket address for incoming connection\n");
3296       GNUNET_break(0);
3297       GNUNET_SERVER_receive_done (client,
3298                                   GNUNET_SYSERR);
3299       return;
3300     }
3301   }
3302
3303   if (GNUNET_YES != session->expecting_welcome)
3304   {
3305     GNUNET_break_op (0);
3306     GNUNET_SERVER_receive_done (client,
3307                                 GNUNET_SYSERR);
3308     return;
3309   }
3310   session->last_activity = GNUNET_TIME_absolute_get ();
3311   session->expecting_welcome = GNUNET_NO;
3312
3313   process_pending_messages (session);
3314   GNUNET_SERVER_client_set_timeout (client,
3315                                     GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
3316   GNUNET_SERVER_receive_done (client,
3317                               GNUNET_OK);
3318 }
3319
3320
3321 /**
3322  * We've received data for this peer via TCP.  Unbox,
3323  * compute latency and forward.
3324  *
3325  * @param cls closure
3326  * @param client identification of the client
3327  * @param message the actual message
3328  */
3329 static void
3330 handle_tcp_data (void *cls,
3331                  struct GNUNET_SERVER_Client *client,
3332                  const struct GNUNET_MessageHeader *message)
3333 {
3334   struct Plugin *plugin = cls;
3335   struct GNUNET_ATS_Session *session;
3336   struct GNUNET_TIME_Relative delay;
3337   uint16_t type;
3338
3339   type = ntohs (message->type);
3340   if ( (GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_WELCOME == type) ||
3341        (GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_NAT_PROBE == type) )
3342   {
3343     /* We don't want to propagate WELCOME and NAT Probe messages up! */
3344     GNUNET_SERVER_receive_done (client,
3345                                 GNUNET_OK);
3346     return;
3347   }
3348   session = lookup_session_by_client (plugin, client);
3349   if (NULL == session)
3350   {
3351     /* No inbound session found */
3352     void *vaddr = NULL;
3353     size_t alen;
3354
3355     GNUNET_assert (GNUNET_OK ==
3356                    GNUNET_SERVER_client_get_address (client,
3357                                                      &vaddr,
3358                                                      &alen));
3359     LOG (GNUNET_ERROR_TYPE_ERROR,
3360          "Received unexpected %u bytes of type %u from `%s'\n",
3361          (unsigned int) ntohs (message->size),
3362          (unsigned int) ntohs (message->type),
3363          GNUNET_a2s (vaddr,
3364                      alen));
3365     GNUNET_break_op(0);
3366     GNUNET_SERVER_receive_done (client,
3367                                 GNUNET_SYSERR);
3368     GNUNET_free_non_null (vaddr);
3369     return;
3370   }
3371   if (GNUNET_YES == session->expecting_welcome)
3372   {
3373     /* Session is expecting WELCOME message */
3374     void *vaddr = NULL;
3375     size_t alen;
3376
3377     GNUNET_SERVER_client_get_address (client,
3378                                       &vaddr,
3379                                       &alen);
3380     LOG (GNUNET_ERROR_TYPE_ERROR,
3381          "Received unexpected %u bytes of type %u from `%s'\n",
3382          (unsigned int) ntohs (message->size),
3383          (unsigned int) ntohs (message->type),
3384          GNUNET_a2s (vaddr, alen));
3385     GNUNET_break_op(0);
3386     GNUNET_SERVER_receive_done (client,
3387                                 GNUNET_SYSERR);
3388     GNUNET_free_non_null (vaddr);
3389     return;
3390   }
3391
3392   session->last_activity = GNUNET_TIME_absolute_get ();
3393   {
3394     void *vaddr = NULL;
3395     size_t alen;
3396
3397     GNUNET_SERVER_client_get_address (client,
3398                                       &vaddr,
3399                                       &alen);
3400     LOG (GNUNET_ERROR_TYPE_DEBUG,
3401          "Passing %u bytes of type %u from `%s' at %s to transport service.\n",
3402          (unsigned int) ntohs (message->size),
3403          (unsigned int) ntohs (message->type),
3404          GNUNET_i2s (&session->target),
3405          GNUNET_a2s (vaddr, alen));
3406     GNUNET_free_non_null (vaddr);
3407   }
3408
3409   GNUNET_STATISTICS_update (plugin->env->stats,
3410                             gettext_noop ("# bytes received via TCP"),
3411                             ntohs (message->size),
3412                             GNUNET_NO);
3413
3414   GNUNET_assert (GNUNET_CONTAINER_multipeermap_contains_value (plugin->sessionmap,
3415                                                                &session->target,
3416                                                                session));
3417   delay = plugin->env->receive (plugin->env->cls,
3418                                 session->address,
3419                                 session,
3420                                 message);
3421   reschedule_session_timeout (session);
3422   if (0 == delay.rel_value_us)
3423   {
3424     GNUNET_SERVER_receive_done (client,
3425                                 GNUNET_OK);
3426   }
3427   else
3428   {
3429     LOG (GNUNET_ERROR_TYPE_DEBUG,
3430          "Throttling receiving from `%s' for %s\n",
3431          GNUNET_i2s (&session->target),
3432          GNUNET_STRINGS_relative_time_to_string (delay,
3433                                                  GNUNET_YES));
3434     GNUNET_SERVER_disable_receive_done_warning (client);
3435     GNUNET_assert (NULL == session->receive_delay_task);
3436     session->receive_delay_task = GNUNET_SCHEDULER_add_delayed (delay,
3437                                                                 &delayed_done,
3438                                                                 session);
3439   }
3440 }
3441
3442
3443 /**
3444  * Function called whenever a peer is connected on the "SERVER" level.
3445  * Increments number of active connections and suspends server if we
3446  * have reached the limit.
3447  *
3448  * @param cls closure
3449  * @param client identification of the client
3450  */
3451 static void
3452 connect_notify (void *cls,
3453                 struct GNUNET_SERVER_Client *client)
3454 {
3455   struct Plugin *plugin = cls;
3456
3457   if (NULL == client)
3458     return;
3459   plugin->cur_connections++;
3460   GNUNET_STATISTICS_set (plugin->env->stats,
3461                          gettext_noop ("# TCP server connections active"),
3462                          plugin->cur_connections,
3463                          GNUNET_NO);
3464   GNUNET_STATISTICS_update (plugin->env->stats,
3465                             gettext_noop ("# TCP server connect events"),
3466                             1,
3467                             GNUNET_NO);
3468   if (plugin->cur_connections != plugin->max_connections)
3469     return;
3470   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3471               _("TCP connection limit reached, suspending server\n"));
3472   GNUNET_STATISTICS_update (plugin->env->stats,
3473                             gettext_noop ("# TCP service suspended"),
3474                             1,
3475                             GNUNET_NO);
3476   GNUNET_SERVER_suspend (plugin->server); /* Maximum number of connections rechead */
3477 }
3478
3479
3480 /**
3481  * Function called whenever a peer is disconnected on the "SERVER"
3482  * level.  Cleans up the connection, decrements number of active
3483  * connections and if applicable resumes listening.
3484  *
3485  * @param cls closure
3486  * @param client identification of the client
3487  */
3488 static void
3489 disconnect_notify (void *cls,
3490                    struct GNUNET_SERVER_Client *client)
3491 {
3492   struct Plugin *plugin = cls;
3493   struct GNUNET_ATS_Session *session;
3494
3495   if (NULL == client)
3496     return;
3497   GNUNET_assert (plugin->cur_connections >= 1);
3498   plugin->cur_connections--;
3499   session = lookup_session_by_client (plugin,
3500                                       client);
3501   if (NULL == session)
3502     return; /* unknown, nothing to do */
3503   LOG (GNUNET_ERROR_TYPE_DEBUG,
3504        "Destroying session of `%s' with %s due to network-level disconnect.\n",
3505        GNUNET_i2s (&session->target),
3506        tcp_plugin_address_to_string (session->plugin,
3507                                      session->address->address,
3508                                      session->address->address_length));
3509
3510   if (plugin->cur_connections == plugin->max_connections)
3511   {
3512     GNUNET_STATISTICS_update (session->plugin->env->stats,
3513                               gettext_noop ("# TCP service resumed"),
3514                               1,
3515                               GNUNET_NO);
3516     GNUNET_SERVER_resume (plugin->server); /* Resume server  */
3517   }
3518   GNUNET_STATISTICS_set (plugin->env->stats,
3519                          gettext_noop ("# TCP server connections active"),
3520                          plugin->cur_connections,
3521                          GNUNET_NO);
3522   GNUNET_STATISTICS_update (session->plugin->env->stats,
3523                             gettext_noop ("# network-level TCP disconnect events"),
3524                             1,
3525                             GNUNET_NO);
3526   tcp_plugin_disconnect_session (plugin,
3527                                  session);
3528 }
3529
3530
3531 /**
3532  * We can now send a probe message, copy into buffer to really send.
3533  *
3534  * @param cls closure, a `struct TCPProbeContext`
3535  * @param size max size to copy
3536  * @param buf buffer to copy message to
3537  * @return number of bytes copied into @a buf
3538  */
3539 static size_t
3540 notify_send_probe (void *cls,
3541                    size_t size,
3542                    void *buf)
3543 {
3544   struct TCPProbeContext *tcp_probe_ctx = cls;
3545   struct Plugin *plugin = tcp_probe_ctx->plugin;
3546   size_t ret;
3547
3548   tcp_probe_ctx->transmit_handle = NULL;
3549   GNUNET_CONTAINER_DLL_remove (plugin->probe_head,
3550                                plugin->probe_tail,
3551                                tcp_probe_ctx);
3552   if (NULL == buf)
3553   {
3554     GNUNET_CONNECTION_destroy (tcp_probe_ctx->sock);
3555     GNUNET_free(tcp_probe_ctx);
3556     return 0;
3557   }
3558   GNUNET_assert(size >= sizeof(tcp_probe_ctx->message));
3559   GNUNET_memcpy (buf,
3560           &tcp_probe_ctx->message,
3561           sizeof(tcp_probe_ctx->message));
3562   GNUNET_SERVER_connect_socket (tcp_probe_ctx->plugin->server,
3563                                 tcp_probe_ctx->sock);
3564   ret = sizeof(tcp_probe_ctx->message);
3565   GNUNET_free (tcp_probe_ctx);
3566   return ret;
3567 }
3568
3569
3570 /**
3571  * Function called by the NAT subsystem suggesting another peer wants
3572  * to connect to us via connection reversal.  Try to connect back to the
3573  * given IP.
3574  *
3575  * @param cls closure
3576  * @param addr address to try
3577  * @param addrlen number of bytes in @a addr
3578  */
3579 static void
3580 try_connection_reversal (void *cls,
3581                          const struct sockaddr *addr,
3582                          socklen_t addrlen)
3583 {
3584   struct Plugin *plugin = cls;
3585   struct GNUNET_CONNECTION_Handle *sock;
3586   struct TCPProbeContext *tcp_probe_ctx;
3587
3588   /**
3589    * We have received an ICMP response, ostensibly from a peer
3590    * that wants to connect to us! Send a message to establish a connection.
3591    */
3592   sock = GNUNET_CONNECTION_create_from_sockaddr (AF_INET,
3593                                                  addr,
3594                                                  addrlen);
3595   if (NULL == sock)
3596   {
3597     /* failed for some odd reason (out of sockets?); ignore attempt */
3598     return;
3599   }
3600
3601   tcp_probe_ctx = GNUNET_new (struct TCPProbeContext);
3602   tcp_probe_ctx->message.header.size
3603     = htons (sizeof (struct TCP_NAT_ProbeMessage));
3604   tcp_probe_ctx->message.header.type
3605     = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_NAT_PROBE);
3606   tcp_probe_ctx->message.clientIdentity
3607     = *plugin->env->my_identity;
3608   tcp_probe_ctx->plugin = plugin;
3609   tcp_probe_ctx->sock = sock;
3610   GNUNET_CONTAINER_DLL_insert (plugin->probe_head,
3611                                plugin->probe_tail,
3612                                tcp_probe_ctx);
3613   tcp_probe_ctx->transmit_handle
3614     = GNUNET_CONNECTION_notify_transmit_ready (sock,
3615                                                ntohs (tcp_probe_ctx->message.header.size),
3616                                                GNUNET_TIME_UNIT_FOREVER_REL,
3617                                                &notify_send_probe,
3618                                                tcp_probe_ctx);
3619 }
3620
3621
3622 /**
3623  * Function obtain the network type for a session
3624  *
3625  * @param cls closure (`struct Plugin *`)
3626  * @param session the session
3627  * @return the network type in HBO or #GNUNET_SYSERR
3628  */
3629 static enum GNUNET_ATS_Network_Type
3630 tcp_plugin_get_network (void *cls,
3631                         struct GNUNET_ATS_Session *session)
3632 {
3633   return session->scope;
3634 }
3635
3636
3637 /**
3638  * Function obtain the network type for an address.
3639  *
3640  * @param cls closure (`struct Plugin *`)
3641  * @param address the address
3642  * @return the network type
3643  */
3644 static enum GNUNET_ATS_Network_Type
3645 tcp_plugin_get_network_for_address (void *cls,
3646                                     const struct GNUNET_HELLO_Address *address)
3647 {
3648   struct Plugin *plugin = cls;
3649   size_t addrlen;
3650   struct sockaddr_in a4;
3651   struct sockaddr_in6 a6;
3652   const struct IPv4TcpAddress *t4;
3653   const struct IPv6TcpAddress *t6;
3654   const void *sb;
3655   size_t sbs;
3656
3657   addrlen = address->address_length;
3658   if (addrlen == sizeof(struct IPv6TcpAddress))
3659   {
3660     GNUNET_assert (NULL != address->address); /* make static analysis happy */
3661     t6 = address->address;
3662     memset (&a6, 0, sizeof(a6));
3663 #if HAVE_SOCKADDR_IN_SIN_LEN
3664     a6.sin6_len = sizeof (a6);
3665 #endif
3666     a6.sin6_family = AF_INET6;
3667     a6.sin6_port = t6->t6_port;
3668     GNUNET_memcpy (&a6.sin6_addr, &t6->ipv6_addr, sizeof(struct in6_addr));
3669     sb = &a6;
3670     sbs = sizeof(a6);
3671   }
3672   else if (addrlen == sizeof(struct IPv4TcpAddress))
3673   {
3674     GNUNET_assert (NULL != address->address); /* make static analysis happy */
3675     t4 = address->address;
3676     memset (&a4, 0, sizeof(a4));
3677 #if HAVE_SOCKADDR_IN_SIN_LEN
3678     a4.sin_len = sizeof (a4);
3679 #endif
3680     a4.sin_family = AF_INET;
3681     a4.sin_port = t4->t4_port;
3682     a4.sin_addr.s_addr = t4->ipv4_addr;
3683     sb = &a4;
3684     sbs = sizeof(a4);
3685   }
3686   else
3687   {
3688     GNUNET_break (0);
3689     return GNUNET_ATS_NET_UNSPECIFIED;
3690   }
3691   return plugin->env->get_address_type (plugin->env->cls,
3692                                         sb,
3693                                         sbs);
3694 }
3695
3696
3697 /**
3698  * Return information about the given session to the
3699  * monitor callback.
3700  *
3701  * @param cls the `struct Plugin` with the monitor callback (`sic`)
3702  * @param peer peer we send information about
3703  * @param value our `struct GNUNET_ATS_Session` to send information about
3704  * @return #GNUNET_OK (continue to iterate)
3705  */
3706 static int
3707 send_session_info_iter (void *cls,
3708                         const struct GNUNET_PeerIdentity *peer,
3709                         void *value)
3710 {
3711   struct Plugin *plugin = cls;
3712   struct GNUNET_ATS_Session *session = value;
3713
3714   notify_session_monitor (plugin,
3715                           session,
3716                           GNUNET_TRANSPORT_SS_INIT);
3717   /* FIXME: cannot tell if this is up or not from current
3718      session state... */
3719   notify_session_monitor (plugin,
3720                           session,
3721                           GNUNET_TRANSPORT_SS_UP);
3722   return GNUNET_OK;
3723 }
3724
3725
3726 /**
3727  * Begin monitoring sessions of a plugin.  There can only
3728  * be one active monitor per plugin (i.e. if there are
3729  * multiple monitors, the transport service needs to
3730  * multiplex the generated events over all of them).
3731  *
3732  * @param cls closure of the plugin
3733  * @param sic callback to invoke, NULL to disable monitor;
3734  *            plugin will being by iterating over all active
3735  *            sessions immediately and then enter monitor mode
3736  * @param sic_cls closure for @a sic
3737  */
3738 static void
3739 tcp_plugin_setup_monitor (void *cls,
3740                           GNUNET_TRANSPORT_SessionInfoCallback sic,
3741                           void *sic_cls)
3742 {
3743   struct Plugin *plugin = cls;
3744
3745   plugin->sic = sic;
3746   plugin->sic_cls = sic_cls;
3747   if (NULL != sic)
3748   {
3749     GNUNET_CONTAINER_multipeermap_iterate (plugin->sessionmap,
3750                                            &send_session_info_iter,
3751                                            plugin);
3752     /* signal end of first iteration */
3753     sic (sic_cls, NULL, NULL);
3754   }
3755 }
3756
3757
3758 /**
3759  * Entry point for the plugin.
3760  *
3761  * @param cls closure, the `struct GNUNET_TRANSPORT_PluginEnvironment *`
3762  * @return the `struct GNUNET_TRANSPORT_PluginFunctions *` or NULL on error
3763  */
3764 void *
3765 libgnunet_plugin_transport_xt_init (void *cls)
3766 {
3767   static const struct GNUNET_SERVER_MessageHandler my_handlers[] = {
3768     { &handle_tcp_welcome, NULL,
3769       GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_WELCOME,
3770       sizeof(struct WelcomeMessage) },
3771     { &handle_tcp_nat_probe, NULL,
3772       GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_NAT_PROBE,
3773       sizeof(struct TCP_NAT_ProbeMessage) },
3774     { &handle_tcp_data, NULL,
3775       GNUNET_MESSAGE_TYPE_ALL, 0 },
3776     { NULL, NULL, 0, 0 }
3777   };
3778   struct GNUNET_TRANSPORT_PluginEnvironment *env = cls;
3779   struct GNUNET_TRANSPORT_PluginFunctions *api;
3780   struct Plugin *plugin;
3781   struct LEGACY_SERVICE_Context *service;
3782   unsigned long long aport;
3783   unsigned long long bport;
3784   unsigned long long max_connections;
3785   unsigned int i;
3786   struct GNUNET_TIME_Relative idle_timeout;
3787 #ifdef TCP_STEALTH
3788   struct GNUNET_NETWORK_Handle *const*lsocks;
3789 #endif
3790   int ret;
3791   int ret_s;
3792   struct sockaddr **addrs;
3793   socklen_t *addrlens;
3794
3795   if (NULL == env->receive)
3796   {
3797     /* run in 'stub' mode (i.e. as part of gnunet-peerinfo), don't fully
3798      initialze the plugin or the API */
3799     api = GNUNET_new (struct GNUNET_TRANSPORT_PluginFunctions);
3800     api->cls = NULL;
3801     api->address_pretty_printer = &tcp_plugin_address_pretty_printer;
3802     api->address_to_string = &tcp_plugin_address_to_string;
3803     api->string_to_address = &tcp_plugin_string_to_address;
3804     return api;
3805   }
3806
3807   GNUNET_assert (NULL != env->cfg);
3808   if (GNUNET_OK !=
3809       GNUNET_CONFIGURATION_get_value_number (env->cfg,
3810                                              "transport-xt",
3811                                              "MAX_CONNECTIONS",
3812                                              &max_connections))
3813     max_connections = 128;
3814
3815   aport = 0;
3816   if ((GNUNET_OK !=
3817        GNUNET_CONFIGURATION_get_value_number (env->cfg,
3818                                               "transport-xt",
3819                                               "PORT", &bport)) ||
3820       (bport > 65535) ||
3821       ((GNUNET_OK ==
3822         GNUNET_CONFIGURATION_get_value_number (env->cfg,
3823                                                "transport-xt",
3824                                                "ADVERTISED-PORT", &aport)) &&
3825        (aport > 65535) ))
3826   {
3827     LOG(GNUNET_ERROR_TYPE_ERROR,
3828         _("Require valid port number for service `%s' in configuration!\n"),
3829         "transport-xt");
3830     return NULL ;
3831   }
3832   if (0 == aport)
3833     aport = bport;
3834   if (0 == bport)
3835     aport = 0;
3836   if (0 != bport)
3837   {
3838     service = LEGACY_SERVICE_start ("transport-xt",
3839                                     env->cfg,
3840                                     LEGACY_SERVICE_OPTION_NONE);
3841     if (NULL == service)
3842     {
3843       LOG (GNUNET_ERROR_TYPE_WARNING,
3844            _("Failed to start service.\n"));
3845       return NULL;
3846     }
3847   }
3848   else
3849     service = NULL;
3850
3851   api = NULL;
3852   plugin = GNUNET_new (struct Plugin);
3853   plugin->sessionmap = GNUNET_CONTAINER_multipeermap_create (max_connections,
3854                                                              GNUNET_YES);
3855   plugin->max_connections = max_connections;
3856   plugin->open_port = bport;
3857   plugin->adv_port = aport;
3858   plugin->env = env;
3859   plugin->my_welcome.header.size = htons (sizeof(struct WelcomeMessage));
3860   plugin->my_welcome.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_WELCOME);
3861   plugin->my_welcome.clientIdentity = *plugin->env->my_identity;
3862
3863   if ( (NULL != service) &&
3864        (GNUNET_YES ==
3865         GNUNET_CONFIGURATION_get_value_yesno (env->cfg,
3866                                               "transport-xt",
3867                                               "TCP_STEALTH")) )
3868   {
3869 #ifdef TCP_STEALTH
3870     plugin->myoptions |= TCP_OPTIONS_TCP_STEALTH;
3871     lsocks = LEGACY_SERVICE_get_listen_sockets (service);
3872     if (NULL != lsocks)
3873     {
3874       uint32_t len = sizeof (struct WelcomeMessage);
3875
3876       for (i=0;NULL!=lsocks[i];i++)
3877       {
3878         if ( (GNUNET_OK !=
3879               GNUNET_NETWORK_socket_setsockopt (lsocks[i],
3880                                                 IPPROTO_TCP,
3881                                                 TCP_STEALTH,
3882                                                 env->my_identity,
3883                                                 sizeof (struct GNUNET_PeerIdentity))) ||
3884              (GNUNET_OK !=
3885               GNUNET_NETWORK_socket_setsockopt (lsocks[i],
3886                                                 IPPROTO_TCP,
3887                                                 TCP_STEALTH_INTEGRITY_LEN,
3888                                                 &len,
3889                                                 sizeof (len))) )
3890         {
3891           /* TCP STEALTH not supported by kernel */
3892           GNUNET_assert (0 == i);
3893           GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3894                       _("TCP_STEALTH not supported on this platform.\n"));
3895           goto die;
3896         }
3897       }
3898     }
3899 #else
3900     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3901                 _("TCP_STEALTH not supported on this platform.\n"));
3902     goto die;
3903 #endif
3904   }
3905
3906   if ( (NULL != service) &&
3907        (GNUNET_SYSERR !=
3908         (ret_s =
3909          get_server_addresses ("transport-xt",
3910                                env->cfg,
3911                                &addrs,
3912                                &addrlens))))
3913   {
3914     for (ret = ret_s-1; ret >= 0; ret--)
3915       LOG (GNUNET_ERROR_TYPE_INFO,
3916            "Binding to address `%s'\n",
3917            GNUNET_a2s (addrs[ret], addrlens[ret]));
3918     plugin->nat
3919       = GNUNET_NAT_register (env->cfg,
3920                              "transport-xt",
3921                              IPPROTO_TCP,
3922                              (unsigned int) ret_s,
3923                              (const struct sockaddr **) addrs,
3924                              addrlens,
3925                              &tcp_nat_port_map_callback,
3926                              &try_connection_reversal,
3927                              plugin);
3928     for (ret = ret_s -1; ret >= 0; ret--)
3929       GNUNET_free (addrs[ret]);
3930     GNUNET_free_non_null (addrs);
3931     GNUNET_free_non_null (addrlens);
3932   }
3933   else
3934   {
3935     plugin->nat = GNUNET_NAT_register (plugin->env->cfg,
3936                                        "transport-xt",
3937                                        IPPROTO_TCP,
3938                                        0,
3939                                        NULL,
3940                                        NULL,
3941                                        NULL,
3942                                        &try_connection_reversal,
3943                                        plugin);
3944   }
3945   api = GNUNET_new (struct GNUNET_TRANSPORT_PluginFunctions);
3946   api->cls = plugin;
3947   api->send = &tcp_plugin_send;
3948   api->get_session = &tcp_plugin_get_session;
3949   api->disconnect_session = &tcp_plugin_disconnect_session;
3950   api->query_keepalive_factor = &tcp_plugin_query_keepalive_factor;
3951   api->disconnect_peer = &tcp_plugin_disconnect;
3952   api->address_pretty_printer = &tcp_plugin_address_pretty_printer;
3953   api->check_address = &tcp_plugin_check_address;
3954   api->address_to_string = &tcp_plugin_address_to_string;
3955   api->string_to_address = &tcp_plugin_string_to_address;
3956   api->get_network = &tcp_plugin_get_network;
3957   api->get_network_for_address = &tcp_plugin_get_network_for_address;
3958   api->update_session_timeout = &tcp_plugin_update_session_timeout;
3959   api->update_inbound_delay = &tcp_plugin_update_inbound_delay;
3960   api->setup_monitor = &tcp_plugin_setup_monitor;
3961   plugin->service = service;
3962   if (NULL != service)
3963   {
3964     plugin->server = LEGACY_SERVICE_get_server (service);
3965   }
3966   else
3967   {
3968     if (GNUNET_OK !=
3969         GNUNET_CONFIGURATION_get_value_time (env->cfg,
3970                                              "transport-xt",
3971                                              "TIMEOUT",
3972                                              &idle_timeout))
3973     {
3974       GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
3975                                  "transport-xt",
3976                                  "TIMEOUT");
3977       goto die;
3978     }
3979     plugin->server
3980       = GNUNET_SERVER_create_with_sockets (NULL,
3981                                            plugin,
3982                                            NULL,
3983                                            idle_timeout,
3984                                            GNUNET_YES);
3985   }
3986   plugin->handlers = GNUNET_malloc (sizeof (my_handlers));
3987   GNUNET_memcpy (plugin->handlers,
3988                  my_handlers,
3989                  sizeof(my_handlers));
3990   for (i = 0;i < sizeof(my_handlers) / sizeof(struct GNUNET_SERVER_MessageHandler);i++)
3991     plugin->handlers[i].callback_cls = plugin;
3992
3993   GNUNET_SERVER_add_handlers (plugin->server,
3994                               plugin->handlers);
3995   GNUNET_SERVER_connect_notify (plugin->server,
3996                                 &connect_notify,
3997                                 plugin);
3998   GNUNET_SERVER_disconnect_notify (plugin->server,
3999                                    &disconnect_notify,
4000                                    plugin);
4001   plugin->nat_wait_conns = GNUNET_CONTAINER_multipeermap_create (16,
4002                                                                  GNUNET_YES);
4003   if (0 != bport)
4004     LOG (GNUNET_ERROR_TYPE_INFO,
4005          _("XT transport listening on port %llu\n"),
4006          bport);
4007   else
4008     LOG (GNUNET_ERROR_TYPE_INFO,
4009          _("XT transport not listening on any port (client only)\n"));
4010   if ( (aport != bport) &&
4011        (0 != bport) )
4012     LOG (GNUNET_ERROR_TYPE_INFO,
4013          _("XT transport advertises itself as being on port %llu\n"),
4014          aport);
4015   /* Initially set connections to 0 */
4016   GNUNET_STATISTICS_set (plugin->env->stats,
4017                          gettext_noop ("# XT sessions active"),
4018                          0,
4019                          GNUNET_NO);
4020   return api;
4021
4022  die:
4023   if (NULL != plugin->nat)
4024     GNUNET_NAT_unregister (plugin->nat);
4025   GNUNET_CONTAINER_multipeermap_destroy (plugin->sessionmap);
4026   if (NULL != service)
4027     LEGACY_SERVICE_stop (service);
4028   GNUNET_free (plugin);
4029   GNUNET_free_non_null (api);
4030   return NULL;
4031 }
4032
4033
4034 /**
4035  * Exit point from the plugin.
4036  *
4037  * @param cls the `struct GNUNET_TRANSPORT_PluginFunctions`
4038  * @return NULL
4039  */
4040 void *
4041 libgnunet_plugin_transport_xt_done (void *cls)
4042 {
4043   struct GNUNET_TRANSPORT_PluginFunctions *api = cls;
4044   struct Plugin *plugin = api->cls;
4045   struct TCPProbeContext *tcp_probe;
4046   struct PrettyPrinterContext *cur;
4047   struct PrettyPrinterContext *next;
4048
4049   if (NULL == plugin)
4050   {
4051     GNUNET_free(api);
4052     return NULL ;
4053   }
4054   LOG (GNUNET_ERROR_TYPE_DEBUG,
4055        "Shutting down XT plugin\n");
4056
4057   /* Removing leftover sessions */
4058   GNUNET_CONTAINER_multipeermap_iterate (plugin->sessionmap,
4059                                          &session_disconnect_it,
4060                                          plugin);
4061   /* Removing leftover NAT sessions */
4062   GNUNET_CONTAINER_multipeermap_iterate (plugin->nat_wait_conns,
4063                                          &session_disconnect_it,
4064                                          plugin);
4065
4066   for (cur = plugin->ppc_dll_head; NULL != cur; cur = next)
4067   {
4068     next = cur->next;
4069     GNUNET_CONTAINER_DLL_remove (plugin->ppc_dll_head,
4070                                  plugin->ppc_dll_tail,
4071                                  cur);
4072     GNUNET_RESOLVER_request_cancel (cur->resolver_handle);
4073     cur->asc (cur->asc_cls,
4074               NULL,
4075               GNUNET_OK);
4076     GNUNET_free (cur);
4077   }
4078
4079   if (NULL != plugin->service)
4080     LEGACY_SERVICE_stop (plugin->service);
4081   else
4082     GNUNET_SERVER_destroy (plugin->server);
4083   GNUNET_free (plugin->handlers);
4084   if (NULL != plugin->nat)
4085     GNUNET_NAT_unregister (plugin->nat);
4086   while (NULL != (tcp_probe = plugin->probe_head))
4087   {
4088     GNUNET_CONTAINER_DLL_remove (plugin->probe_head,
4089                                  plugin->probe_tail,
4090                                  tcp_probe);
4091     GNUNET_CONNECTION_destroy (tcp_probe->sock);
4092     GNUNET_free (tcp_probe);
4093   }
4094   GNUNET_CONTAINER_multipeermap_destroy (plugin->nat_wait_conns);
4095   GNUNET_CONTAINER_multipeermap_destroy (plugin->sessionmap);
4096   GNUNET_break (0 == plugin->cur_connections);
4097   GNUNET_free (plugin);
4098   GNUNET_free (api);
4099   return NULL;
4100 }
4101
4102 /* end of plugin_transport_xt.c */