2 This file is part of GNUnet
3 Copyright (C) 2002--2015 GNUnet e.V.
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
21 * @file transport/plugin_transport_tcp.c
22 * @brief Implementation of the TCP transport service
23 * @author Christian Grothoff
26 #include "gnunet_hello_lib.h"
27 #include "gnunet_constants.h"
28 #include "gnunet_util_lib.h"
29 #include "gnunet_nat_service.h"
30 #include "gnunet_protocols.h"
31 #include "gnunet_resolver_service.h"
32 #include "gnunet_signatures.h"
33 #include "gnunet_statistics_service.h"
34 #include "gnunet_transport_service.h"
35 #include "gnunet_transport_plugin.h"
36 #include "transport.h"
38 #define LOG(kind,...) GNUNET_log_from (kind, "transport-tcp",__VA_ARGS__)
40 #define PLUGIN_NAME "tcp"
43 * How long until we give up on establishing an NAT connection?
46 #define NAT_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10)
49 * Opaque handle that can be used to cancel
50 * a transmit-ready notification.
52 struct GNUNET_CONNECTION_TransmitHandle;
55 * @brief handle for a server
57 struct GNUNET_SERVER_Handle;
60 * @brief opaque handle for a client of the server
62 struct GNUNET_SERVER_Client;
65 * @brief opaque handle server returns for aborting transmission to a client.
67 struct GNUNET_SERVER_TransmitHandle;
70 * @brief handle for a network connection
72 struct GNUNET_CONNECTION_Handle;
76 * Function called to notify a client about the connection begin ready
77 * to queue more data. @a buf will be NULL and @a size zero if the
78 * connection was closed for writing in the meantime.
81 * @param size number of bytes available in @a buf
82 * @param buf where the callee should write the message
83 * @return number of bytes written to @a buf
86 (*GNUNET_CONNECTION_TransmitReadyNotify) (void *cls,
91 * Credentials for UNIX domain sockets.
93 struct GNUNET_CONNECTION_Credentials
96 * UID of the other end of the connection.
101 * GID of the other end of the connection.
108 * Functions with this signature are called whenever a client
109 * is disconnected on the network level.
112 * @param client identification of the client; NULL
113 * for the last call when the server is destroyed
116 (*GNUNET_SERVER_DisconnectCallback) (void *cls,
117 struct GNUNET_SERVER_Client *client);
121 * Functions with this signature are called whenever a client
122 * is connected on the network level.
125 * @param client identification of the client
128 (*GNUNET_SERVER_ConnectCallback) (void *cls,
129 struct GNUNET_SERVER_Client *client);
135 * Function to call for access control checks.
138 * @param ucred credentials, if available, otherwise NULL
139 * @param addr address
140 * @param addrlen length of address
141 * @return GNUNET_YES to allow, GNUNET_NO to deny, GNUNET_SYSERR
142 * for unknown address family (will be denied).
145 (*GNUNET_CONNECTION_AccessCheck) (void *cls,
147 GNUNET_CONNECTION_Credentials *
149 const struct sockaddr * addr,
153 * Callback function for data received from the network. Note that
154 * both "available" and "err" would be 0 if the read simply timed out.
157 * @param buf pointer to received data
158 * @param available number of bytes availabe in "buf",
159 * possibly 0 (on errors)
160 * @param addr address of the sender
161 * @param addrlen size of addr
162 * @param errCode value of errno (on errors receiving)
165 (*GNUNET_CONNECTION_Receiver) (void *cls, const void *buf,
167 const struct sockaddr * addr,
168 socklen_t addrlen, int errCode);
173 * Close the connection and free associated resources. There must
174 * not be any pending requests for reading or writing to the
175 * connection at this time.
177 * @param connection connection to destroy
180 GNUNET_CONNECTION_destroy (struct GNUNET_CONNECTION_Handle *connection);
184 * Signature of a function to create a custom tokenizer.
186 * @param cls closure from #GNUNET_SERVER_set_callbacks
187 * @param client handle to client the tokenzier will be used for
188 * @return handle to custom tokenizer ('mst')
191 (*GNUNET_SERVER_MstCreateCallback) (void *cls,
192 struct GNUNET_SERVER_Client *client);
196 * Signature of a function to destroy a custom tokenizer.
198 * @param cls closure from #GNUNET_SERVER_set_callbacks
199 * @param mst custom tokenizer handle
202 (*GNUNET_SERVER_MstDestroyCallback) (void *cls,
206 * Signature of a function to receive data for a custom tokenizer.
208 * @param cls closure from #GNUNET_SERVER_set_callbacks
209 * @param mst custom tokenizer handle
210 * @param client_identity ID of client for which this is a buffer,
211 * can be NULL (will be passed back to 'cb')
212 * @param buf input data to add
213 * @param size number of bytes in @a buf
214 * @param purge should any excess bytes in the buffer be discarded
215 * (i.e. for packet-based services like UDP)
216 * @param one_shot only call callback once, keep rest of message in buffer
217 * @return #GNUNET_OK if we are done processing (need more data)
218 * #GNUNET_NO if one_shot was set and we have another message ready
219 * #GNUNET_SYSERR if the data stream is corrupt
222 (*GNUNET_SERVER_MstReceiveCallback) (void *cls, void *mst,
223 struct GNUNET_SERVER_Client *client,
229 * Functions with this signature are called whenever a message is
233 * @param client identification of the client
234 * @param message the actual message
237 (*GNUNET_SERVER_MessageCallback) (void *cls,
238 struct GNUNET_SERVER_Client *client,
239 const struct GNUNET_MessageHeader *message);
242 * Message handler. Each struct specifies how to handle on particular
243 * type of message received.
245 struct GNUNET_SERVER_MessageHandler
248 * Function to call for messages of "type".
250 GNUNET_SERVER_MessageCallback callback;
253 * Closure argument for @e callback.
258 * Type of the message this handler covers.
263 * Expected size of messages of this type. Use 0 for
264 * variable-size. If non-zero, messages of the given
265 * type will be discarded (and the connection closed)
266 * if they do not have the right size.
268 uint16_t expected_size;
273 * Ask the server to disconnect from the given client. This is the
274 * same as passing #GNUNET_SYSERR to #GNUNET_SERVER_receive_done,
275 * except that it allows dropping of a client even when not handling a
276 * message from that client.
278 * @param client the client to disconnect from
281 GNUNET_SERVER_client_disconnect (struct GNUNET_SERVER_Client *client);
284 * Return user context associated with the given client.
285 * Note: you should probably use the macro (call without the underscore).
287 * @param client client to query
288 * @param size number of bytes in user context struct (for verification only)
289 * @return pointer to user context
292 GNUNET_SERVER_client_get_user_context_ (struct GNUNET_SERVER_Client *client,
297 * Functions with this signature are called whenever a
298 * complete message is received by the tokenizer.
300 * Do not call #GNUNET_SERVER_mst_destroy from within
301 * the scope of this callback.
304 * @param client identification of the client
305 * @param message the actual message
306 * @return #GNUNET_OK on success, #GNUNET_SYSERR to stop further processing
309 (*GNUNET_SERVER_MessageTokenizerCallback) (void *cls,
311 const struct GNUNET_MessageHeader *message);
315 * Create a message stream tokenizer.
317 * @param cb function to call on completed messages
318 * @param cb_cls closure for @a cb
319 * @return handle to tokenizer
321 struct GNUNET_SERVER_MessageStreamTokenizer *
322 GNUNET_SERVER_mst_create (GNUNET_SERVER_MessageTokenizerCallback cb,
326 * Add incoming data to the receive buffer and call the
327 * callback for all complete messages.
329 * @param mst tokenizer to use
330 * @param client_identity ID of client for which this is a buffer,
331 * can be NULL (will be passed back to 'cb')
332 * @param buf input data to add
333 * @param size number of bytes in @a buf
334 * @param purge should any excess bytes in the buffer be discarded
335 * (i.e. for packet-based services like UDP)
336 * @param one_shot only call callback once, keep rest of message in buffer
337 * @return #GNUNET_OK if we are done processing (need more data)
338 * #GNUNET_NO if one_shot was set and we have another message ready
339 * #GNUNET_SYSERR if the data stream is corrupt
342 GNUNET_SERVER_mst_receive (struct GNUNET_SERVER_MessageStreamTokenizer *mst,
343 void *client_identity,
344 const char *buf, size_t size,
345 int purge, int one_shot);
350 * Destroys a tokenizer.
352 * @param mst tokenizer to destroy
355 GNUNET_SERVER_mst_destroy (struct GNUNET_SERVER_MessageStreamTokenizer *mst);
359 * Set user context to be associated with the given client.
360 * Note: you should probably use the macro (call without the underscore).
362 * @param client client to query
363 * @param ptr pointer to user context
364 * @param size number of bytes in user context struct (for verification only)
367 GNUNET_SERVER_client_set_user_context_ (struct GNUNET_SERVER_Client *client,
371 * Return user context associated with the given client.
373 * @param client client to query
374 * @param type expected return type (i.e. 'struct Foo')
375 * @return pointer to user context of type 'type *'.
377 #define GNUNET_SERVER_client_get_user_context(client,type) \
378 (type *) GNUNET_SERVER_client_get_user_context_ (client, sizeof (type))
381 * Set user context to be associated with the given client.
383 * @param client client to query
384 * @param value pointer to user context
386 #define GNUNET_SERVER_client_set_user_context(client,value) \
387 GNUNET_SERVER_client_set_user_context_ (client, value, sizeof (*value))
392 * Notify us when the server has enough space to transmit
393 * a message of the given size to the given client.
395 * @param client client to transmit message to
396 * @param size requested amount of buffer space
397 * @param timeout after how long should we give up (and call
398 * notify with buf NULL and size 0)?
399 * @param callback function to call when space is available
400 * @param callback_cls closure for @a callback
401 * @return non-NULL if the notify callback was queued; can be used
402 * to cancel the request using
403 * #GNUNET_SERVER_notify_transmit_ready_cancel.
404 * NULL if we are already going to notify someone else (busy)
406 struct GNUNET_SERVER_TransmitHandle *
407 GNUNET_SERVER_notify_transmit_ready (struct GNUNET_SERVER_Client *client,
409 struct GNUNET_TIME_Relative timeout,
410 GNUNET_CONNECTION_TransmitReadyNotify callback,
414 * Abort transmission request.
416 * @param th request to abort
419 GNUNET_SERVER_notify_transmit_ready_cancel (struct GNUNET_SERVER_TransmitHandle *th);
425 * Notify the server that the given client handle should
426 * be kept (keeps the connection up if possible, increments
427 * the internal reference counter).
429 * @param client the client to keep
432 GNUNET_SERVER_client_keep (struct GNUNET_SERVER_Client *client);
436 * Notify the server that the given client handle is no
437 * longer required. Decrements the reference counter. If
438 * that counter reaches zero an inactive connection maybe
441 * @param client the client to drop
444 GNUNET_SERVER_client_drop (struct GNUNET_SERVER_Client *client);
448 * Function called by the service's run
449 * method to run service-specific setup code.
452 * @param server the initialized server
453 * @param cfg configuration to use
456 (*GNUNET_SERVICE_Main) (void *cls,
457 struct GNUNET_SERVER_Handle *server,
458 const struct GNUNET_CONFIGURATION_Handle *cfg);
463 * Suspend accepting connections from the listen socket temporarily.
464 * Resume activity using #GNUNET_SERVER_resume.
466 * @param server server to stop accepting connections.
469 GNUNET_SERVER_suspend (struct GNUNET_SERVER_Handle *server);
472 * Notify us when the server has enough space to transmit
473 * a message of the given size to the given client.
475 * @param client client to transmit message to
476 * @param size requested amount of buffer space
477 * @param timeout after how long should we give up (and call
478 * notify with buf NULL and size 0)?
479 * @param callback function to call when space is available
480 * @param callback_cls closure for @a callback
481 * @return non-NULL if the notify callback was queued; can be used
482 * to cancel the request using
483 * #GNUNET_SERVER_notify_transmit_ready_cancel.
484 * NULL if we are already going to notify someone else (busy)
486 struct GNUNET_SERVER_TransmitHandle *
487 GNUNET_SERVER_notify_transmit_ready (struct GNUNET_SERVER_Client *client,
489 struct GNUNET_TIME_Relative timeout,
490 GNUNET_CONNECTION_TransmitReadyNotify callback,
495 * Add a TCP socket-based connection to the set of handles managed by
496 * this server. Use this function for outgoing (P2P) connections that
497 * we initiated (and where this server should process incoming
500 * @param server the server to use
501 * @param connection the connection to manage (client must
502 * stop using this connection from now on)
503 * @return the client handle
505 struct GNUNET_SERVER_Client *
506 GNUNET_SERVER_connect_socket (struct GNUNET_SERVER_Handle *server,
507 struct GNUNET_CONNECTION_Handle *connection);
511 * Resume accepting connections from the listen socket.
513 * @param server server to resume accepting connections.
516 GNUNET_SERVER_resume (struct GNUNET_SERVER_Handle *server);
519 * Free resources held by this server.
521 * @param server server to destroy
524 GNUNET_SERVER_destroy (struct GNUNET_SERVER_Handle *server);
529 #include "tcp_connection_legacy.c"
530 #include "tcp_server_mst_legacy.c"
531 #include "tcp_server_legacy.c"
532 #include "tcp_service_legacy.c"
534 GNUNET_NETWORK_STRUCT_BEGIN
537 * Initial handshake message for a session.
539 struct WelcomeMessage
542 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_WELCOME.
544 struct GNUNET_MessageHeader header;
547 * Identity of the node connecting (TCP client)
549 struct GNUNET_PeerIdentity clientIdentity;
554 * Basically a WELCOME message, but with the purpose
555 * of giving the waiting peer a client handle to use
557 struct TCP_NAT_ProbeMessage
560 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_NAT_PROBE.
562 struct GNUNET_MessageHeader header;
565 * Identity of the sender of the message.
567 struct GNUNET_PeerIdentity clientIdentity;
570 GNUNET_NETWORK_STRUCT_END
573 * Context for sending a NAT probe via TCP.
575 struct TCPProbeContext
579 * Active probes are kept in a DLL.
581 struct TCPProbeContext *next;
584 * Active probes are kept in a DLL.
586 struct TCPProbeContext *prev;
591 struct GNUNET_CONNECTION_Handle *sock;
594 * Message to be sent.
596 struct TCP_NAT_ProbeMessage message;
599 * Handle to the transmission.
601 struct GNUNET_CONNECTION_TransmitHandle *transmit_handle;
604 * Transport plugin handle.
606 struct Plugin *plugin;
610 * Bits in the `options` field of TCP addresses.
612 enum TcpAddressOptions
618 TCP_OPTIONS_NONE = 0,
621 * See #HTTP_OPTIONS_VERIFY_CERTIFICATE.
623 TCP_OPTIONS_RESERVED = 1,
626 * Enable TCP Stealth-style port knocking.
628 TCP_OPTIONS_TCP_STEALTH = 2
631 GNUNET_NETWORK_STRUCT_BEGIN
634 * Network format for IPv4 addresses.
636 struct IPv4TcpAddress
639 * Optional options and flags for this address,
640 * see `enum TcpAddressOptions`
642 uint32_t options GNUNET_PACKED;
645 * IPv4 address, in network byte order.
647 uint32_t ipv4_addr GNUNET_PACKED;
650 * Port number, in network byte order.
652 uint16_t t4_port GNUNET_PACKED;
657 * Network format for IPv6 addresses.
659 struct IPv6TcpAddress
662 * Optional flags for this address
663 * see `enum TcpAddressOptions`
665 uint32_t options GNUNET_PACKED;
670 struct in6_addr ipv6_addr GNUNET_PACKED;
673 * Port number, in network byte order.
675 uint16_t t6_port GNUNET_PACKED;
678 GNUNET_NETWORK_STRUCT_END
681 * Encapsulation of all of the state of the plugin.
686 * Information kept for each message that is yet to
689 struct PendingMessage
693 * This is a doubly-linked list.
695 struct PendingMessage *next;
698 * This is a doubly-linked list.
700 struct PendingMessage *prev;
703 * The pending message
708 * Continuation function to call once the message
709 * has been sent. Can be NULL if there is no
710 * continuation to call.
712 GNUNET_TRANSPORT_TransmitContinuation transmit_cont;
715 * Closure for @e transmit_cont.
717 void *transmit_cont_cls;
720 * Timeout value for the pending message.
722 struct GNUNET_TIME_Absolute timeout;
725 * So that the gnunet-service-transport can group messages together,
726 * these pending messages need to accept a message buffer and size
727 * instead of just a `struct GNUNET_MessageHeader`.
734 * Session handle for TCP connections.
736 struct GNUNET_ATS_Session
739 * To whom are we talking to (set to our identity
740 * if we are still waiting for the welcome message)
742 struct GNUNET_PeerIdentity target;
745 * Pointer to the global plugin struct.
747 struct Plugin *plugin;
750 * The client (used to identify this connection)
752 struct GNUNET_SERVER_Client *client;
755 * Task cleaning up a NAT client connection establishment attempt;
757 struct GNUNET_SCHEDULER_Task *nat_connection_timeout;
760 * Messages currently pending for transmission
761 * to this peer, if any.
763 struct PendingMessage *pending_messages_head;
766 * Messages currently pending for transmission
767 * to this peer, if any.
769 struct PendingMessage *pending_messages_tail;
772 * Handle for pending transmission request.
774 struct GNUNET_SERVER_TransmitHandle *transmit_handle;
777 * Address of the other peer.
779 struct GNUNET_HELLO_Address *address;
782 * ID of task used to delay receiving more to throttle sender.
784 struct GNUNET_SCHEDULER_Task *receive_delay_task;
787 * Session timeout task
789 struct GNUNET_SCHEDULER_Task *timeout_task;
792 * When will this session time out?
794 struct GNUNET_TIME_Absolute timeout;
797 * When will we continue to read from the socket?
798 * (used to enforce inbound quota).
800 struct GNUNET_TIME_Absolute receive_delay;
803 * Last activity on this connection. Used to select preferred
806 struct GNUNET_TIME_Absolute last_activity;
809 * Number of bytes waiting for transmission to this peer.
811 unsigned long long bytes_in_queue;
814 * Number of messages waiting for transmission to this peer.
816 unsigned int msgs_in_queue;
819 * Network type of the address.
821 enum GNUNET_ATS_Network_Type scope;
824 * Are we still expecting the welcome message? (#GNUNET_YES/#GNUNET_NO)
826 int expecting_welcome;
829 * Was this session created using NAT traversal?
837 * Context for address to string conversion, closure
838 * for #append_port().
840 struct PrettyPrinterContext
845 struct PrettyPrinterContext *next;
850 struct PrettyPrinterContext *prev;
855 struct Plugin *plugin;
860 struct GNUNET_SCHEDULER_Task *timeout_task;
865 struct GNUNET_RESOLVER_RequestHandle *resolver_handle;
868 * Function to call with the result.
870 GNUNET_TRANSPORT_AddressStringCallback asc;
873 * Clsoure for @e asc.
888 * Port to add after the IP address.
895 * Encapsulation of all of the state of the plugin.
902 struct GNUNET_TRANSPORT_PluginEnvironment *env;
907 struct GNUNET_CONNECTION_Handle *lsock;
910 * Our handle to the NAT module.
912 struct GNUNET_NAT_Handle *nat;
915 * Map from peer identities to sessions for the given peer.
917 struct GNUNET_CONTAINER_MultiPeerMap *sessionmap;
920 * Handle to the network service.
922 struct GNUNET_SERVICE_Context *service;
925 * Handle to the server for this service.
927 struct GNUNET_SERVER_Handle *server;
930 * Copy of the handler array where the closures are
931 * set to this struct's instance.
933 struct GNUNET_SERVER_MessageHandler *handlers;
936 * Map of peers we have tried to contact behind a NAT
938 struct GNUNET_CONTAINER_MultiPeerMap *nat_wait_conns;
941 * List of active TCP probes.
943 struct TCPProbeContext *probe_head;
946 * List of active TCP probes.
948 struct TCPProbeContext *probe_tail;
951 * Function to call about session status changes.
953 GNUNET_TRANSPORT_SessionInfoCallback sic;
956 * Closure for @e sic.
961 * ID of task used to update our addresses when one expires.
963 struct GNUNET_SCHEDULER_Task *address_update_task;
966 * Running pretty printers: head
968 struct PrettyPrinterContext *ppc_dll_head;
971 * Running pretty printers: tail
973 struct PrettyPrinterContext *ppc_dll_tail;
976 * Welcome message used by this peer.
978 struct WelcomeMessage my_welcome;
981 * How many more TCP sessions are we allowed to open right now?
983 unsigned long long max_connections;
986 * How many more TCP sessions do we have right now?
988 unsigned long long cur_connections;
996 * Port that we are actually listening on.
1001 * Port that the user said we would have visible to the
1002 * rest of the world.
1010 * Get the list of addresses that a server for the given service
1013 * @param service_name name of the service
1014 * @param cfg configuration (which specifies the addresses)
1015 * @param addrs set (call by reference) to an array of pointers to the
1016 * addresses the server should bind to and listen on; the
1017 * array will be NULL-terminated (on success)
1018 * @param addr_lens set (call by reference) to an array of the lengths
1019 * of the respective `struct sockaddr` struct in the @a addrs
1020 * array (on success)
1021 * @return number of addresses found on success,
1022 * #GNUNET_SYSERR if the configuration
1023 * did not specify reasonable finding information or
1024 * if it specified a hostname that could not be resolved;
1025 * #GNUNET_NO if the number of addresses configured is
1026 * zero (in this case, `*addrs` and `*addr_lens` will be
1030 get_server_addresses (const char *service_name,
1031 const struct GNUNET_CONFIGURATION_Handle *cfg,
1032 struct sockaddr ***addrs,
1033 socklen_t ** addr_lens)
1036 struct GNUNET_NETWORK_Handle *desc;
1037 unsigned long long port;
1039 struct addrinfo hints;
1040 struct addrinfo *res;
1041 struct addrinfo *pos;
1042 struct addrinfo *next;
1047 struct sockaddr **saddrs;
1048 socklen_t *saddrlens;
1054 if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "DISABLEV6"))
1056 if (GNUNET_SYSERR ==
1058 GNUNET_CONFIGURATION_get_value_yesno (cfg, service_name, "DISABLEV6")))
1059 return GNUNET_SYSERR;
1062 disablev6 = GNUNET_NO;
1066 /* probe IPv6 support */
1067 desc = GNUNET_NETWORK_socket_create (PF_INET6, SOCK_STREAM, 0);
1070 if ((ENOBUFS == errno) || (ENOMEM == errno) || (ENFILE == errno) ||
1073 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "socket");
1074 return GNUNET_SYSERR;
1076 LOG (GNUNET_ERROR_TYPE_INFO,
1077 _("Disabling IPv6 support for service `%s', failed to create IPv6 socket: %s\n"),
1078 service_name, STRERROR (errno));
1079 disablev6 = GNUNET_YES;
1083 GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (desc));
1089 if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "PORT"))
1092 GNUNET_CONFIGURATION_get_value_number (cfg, service_name,
1095 LOG (GNUNET_ERROR_TYPE_ERROR,
1096 _("Require valid port number for service `%s' in configuration!\n"),
1101 LOG (GNUNET_ERROR_TYPE_ERROR,
1102 _("Require valid port number for service `%s' in configuration!\n"),
1104 return GNUNET_SYSERR;
1108 if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "BINDTO"))
1110 GNUNET_break (GNUNET_OK ==
1111 GNUNET_CONFIGURATION_get_value_string (cfg, service_name,
1112 "BINDTO", &hostname));
1118 abstract = GNUNET_NO;
1121 GNUNET_CONFIGURATION_have_value (cfg, service_name, "UNIXPATH")) &&
1123 GNUNET_CONFIGURATION_get_value_filename (cfg, service_name, "UNIXPATH",
1125 (0 < strlen (unixpath)))
1127 /* probe UNIX support */
1128 struct sockaddr_un s_un;
1130 if (strlen (unixpath) >= sizeof (s_un.sun_path))
1132 LOG (GNUNET_ERROR_TYPE_WARNING,
1133 _("UNIXPATH `%s' too long, maximum length is %llu\n"), unixpath,
1134 (unsigned long long) sizeof (s_un.sun_path));
1135 unixpath = GNUNET_NETWORK_shorten_unixpath (unixpath);
1136 LOG (GNUNET_ERROR_TYPE_INFO,
1137 _("Using `%s' instead\n"),
1141 abstract = GNUNET_CONFIGURATION_get_value_yesno (cfg,
1143 "USE_ABSTRACT_SOCKETS");
1144 if (GNUNET_SYSERR == abstract)
1145 abstract = GNUNET_NO;
1147 if ((GNUNET_YES != abstract)
1149 GNUNET_DISK_directory_create_for_file (unixpath)))
1150 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
1154 if (NULL != unixpath)
1156 desc = GNUNET_NETWORK_socket_create (AF_UNIX, SOCK_STREAM, 0);
1159 if ((ENOBUFS == errno) || (ENOMEM == errno) || (ENFILE == errno) ||
1162 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "socket");
1163 GNUNET_free_non_null (hostname);
1164 GNUNET_free (unixpath);
1165 return GNUNET_SYSERR;
1167 LOG (GNUNET_ERROR_TYPE_INFO,
1168 _("Disabling UNIX domain socket support for service `%s', failed to create UNIX domain socket: %s\n"),
1171 GNUNET_free (unixpath);
1176 GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (desc));
1182 if ((0 == port) && (NULL == unixpath))
1184 LOG (GNUNET_ERROR_TYPE_ERROR,
1185 _("Have neither PORT nor UNIXPATH for service `%s', but one is required\n"),
1187 GNUNET_free_non_null (hostname);
1188 return GNUNET_SYSERR;
1192 saddrs = GNUNET_malloc (2 * sizeof (struct sockaddr *));
1193 saddrlens = GNUNET_malloc (2 * sizeof (socklen_t));
1194 add_unixpath (saddrs, saddrlens, unixpath, abstract);
1195 GNUNET_free_non_null (unixpath);
1196 GNUNET_free_non_null (hostname);
1198 *addr_lens = saddrlens;
1202 if (NULL != hostname)
1204 LOG (GNUNET_ERROR_TYPE_DEBUG,
1205 "Resolving `%s' since that is where `%s' will bind to.\n",
1208 memset (&hints, 0, sizeof (struct addrinfo));
1210 hints.ai_family = AF_INET;
1211 hints.ai_protocol = IPPROTO_TCP;
1212 if ((0 != (ret = getaddrinfo (hostname, NULL, &hints, &res))) ||
1215 LOG (GNUNET_ERROR_TYPE_ERROR,
1216 _("Failed to resolve `%s': %s\n"),
1218 gai_strerror (ret));
1219 GNUNET_free (hostname);
1220 GNUNET_free_non_null (unixpath);
1221 return GNUNET_SYSERR;
1225 while (NULL != (pos = next))
1227 next = pos->ai_next;
1228 if ((disablev6) && (pos->ai_family == AF_INET6))
1234 LOG (GNUNET_ERROR_TYPE_ERROR,
1235 _("Failed to find %saddress for `%s'.\n"),
1236 disablev6 ? "IPv4 " : "",
1239 GNUNET_free (hostname);
1240 GNUNET_free_non_null (unixpath);
1241 return GNUNET_SYSERR;
1244 if (NULL != unixpath)
1246 saddrs = GNUNET_malloc ((resi + 1) * sizeof (struct sockaddr *));
1247 saddrlens = GNUNET_malloc ((resi + 1) * sizeof (socklen_t));
1249 if (NULL != unixpath)
1251 add_unixpath (saddrs, saddrlens, unixpath, abstract);
1255 while (NULL != (pos = next))
1257 next = pos->ai_next;
1258 if ((disablev6) && (AF_INET6 == pos->ai_family))
1260 if ((IPPROTO_TCP != pos->ai_protocol) && (0 != pos->ai_protocol))
1261 continue; /* not TCP */
1262 if ((SOCK_STREAM != pos->ai_socktype) && (0 != pos->ai_socktype))
1263 continue; /* huh? */
1264 LOG (GNUNET_ERROR_TYPE_DEBUG, "Service `%s' will bind to `%s'\n",
1265 service_name, GNUNET_a2s (pos->ai_addr, pos->ai_addrlen));
1266 if (AF_INET == pos->ai_family)
1268 GNUNET_assert (sizeof (struct sockaddr_in) == pos->ai_addrlen);
1269 saddrlens[i] = pos->ai_addrlen;
1270 saddrs[i] = GNUNET_malloc (saddrlens[i]);
1271 GNUNET_memcpy (saddrs[i], pos->ai_addr, saddrlens[i]);
1272 ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
1276 GNUNET_assert (AF_INET6 == pos->ai_family);
1277 GNUNET_assert (sizeof (struct sockaddr_in6) == pos->ai_addrlen);
1278 saddrlens[i] = pos->ai_addrlen;
1279 saddrs[i] = GNUNET_malloc (saddrlens[i]);
1280 GNUNET_memcpy (saddrs[i], pos->ai_addr, saddrlens[i]);
1281 ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port);
1285 GNUNET_free (hostname);
1291 /* will bind against everything, just set port */
1296 if (NULL != unixpath)
1299 saddrs = GNUNET_malloc ((resi + 1) * sizeof (struct sockaddr *));
1300 saddrlens = GNUNET_malloc ((resi + 1) * sizeof (socklen_t));
1301 if (NULL != unixpath)
1303 add_unixpath (saddrs, saddrlens, unixpath, abstract);
1306 saddrlens[i] = sizeof (struct sockaddr_in);
1307 saddrs[i] = GNUNET_malloc (saddrlens[i]);
1308 #if HAVE_SOCKADDR_IN_SIN_LEN
1309 ((struct sockaddr_in *) saddrs[i])->sin_len = saddrlens[i];
1311 ((struct sockaddr_in *) saddrs[i])->sin_family = AF_INET;
1312 ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
1318 if (NULL != unixpath)
1320 saddrs = GNUNET_malloc ((resi + 1) * sizeof (struct sockaddr *));
1321 saddrlens = GNUNET_malloc ((resi + 1) * sizeof (socklen_t));
1323 if (NULL != unixpath)
1325 add_unixpath (saddrs, saddrlens, unixpath, abstract);
1328 saddrlens[i] = sizeof (struct sockaddr_in6);
1329 saddrs[i] = GNUNET_malloc (saddrlens[i]);
1330 #if HAVE_SOCKADDR_IN_SIN_LEN
1331 ((struct sockaddr_in6 *) saddrs[i])->sin6_len = saddrlens[0];
1333 ((struct sockaddr_in6 *) saddrs[i])->sin6_family = AF_INET6;
1334 ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port);
1336 saddrlens[i] = sizeof (struct sockaddr_in);
1337 saddrs[i] = GNUNET_malloc (saddrlens[i]);
1338 #if HAVE_SOCKADDR_IN_SIN_LEN
1339 ((struct sockaddr_in *) saddrs[i])->sin_len = saddrlens[1];
1341 ((struct sockaddr_in *) saddrs[i])->sin_family = AF_INET;
1342 ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
1345 GNUNET_free_non_null (unixpath);
1347 *addr_lens = saddrlens;
1350 /* end ancient copy-and-paste */
1354 * If a session monitor is attached, notify it about the new
1357 * @param plugin our plugin
1358 * @param session session that changed state
1359 * @param state new state of the session
1362 notify_session_monitor (struct Plugin *plugin,
1363 struct GNUNET_ATS_Session *session,
1364 enum GNUNET_TRANSPORT_SessionState state)
1366 struct GNUNET_TRANSPORT_SessionInfo info;
1368 if (NULL == plugin->sic)
1370 memset (&info, 0, sizeof (info));
1372 info.is_inbound = GNUNET_HELLO_address_check_option (session->address,
1373 GNUNET_HELLO_ADDRESS_INFO_INBOUND);
1374 info.num_msg_pending = session->msgs_in_queue;
1375 info.num_bytes_pending = session->bytes_in_queue;
1376 if (NULL != session->receive_delay_task)
1377 info.receive_delay = session->receive_delay;
1378 info.session_timeout = session->timeout;
1379 info.address = session->address;
1380 plugin->sic (plugin->sic_cls,
1387 * Our external IP address/port mapping has changed.
1389 * @param cls closure, the `struct Plugin`
1390 * @param add_remove #GNUNET_YES to mean the new public IP address, #GNUNET_NO to mean
1391 * the previous (now invalid) one
1392 * @param ac address class the address belongs to
1393 * @param addr either the previous or the new public IP address
1394 * @param addrlen actual length of @a addr
1397 tcp_nat_port_map_callback (void *cls,
1399 enum GNUNET_NAT_AddressClass ac,
1400 const struct sockaddr *addr,
1403 struct Plugin *plugin = cls;
1404 struct GNUNET_HELLO_Address *address;
1405 struct IPv4TcpAddress t4;
1406 struct IPv6TcpAddress t6;
1410 LOG (GNUNET_ERROR_TYPE_INFO,
1411 "NAT notification to %s address `%s'\n",
1412 (GNUNET_YES == add_remove) ? "add" : "remove",
1413 GNUNET_a2s (addr, addrlen));
1414 /* convert 'addr' to our internal format */
1415 switch (addr->sa_family)
1418 GNUNET_assert(addrlen == sizeof(struct sockaddr_in));
1419 memset (&t4, 0, sizeof(t4));
1420 t4.options = htonl (plugin->myoptions);
1421 t4.ipv4_addr = ((struct sockaddr_in *) addr)->sin_addr.s_addr;
1422 t4.t4_port = ((struct sockaddr_in *) addr)->sin_port;
1427 GNUNET_assert(addrlen == sizeof(struct sockaddr_in6));
1428 memset (&t6, 0, sizeof(t6));
1429 GNUNET_memcpy (&t6.ipv6_addr,
1430 &((struct sockaddr_in6 *) addr)->sin6_addr,
1431 sizeof(struct in6_addr));
1432 t6.options = htonl (plugin->myoptions);
1433 t6.t6_port = ((struct sockaddr_in6 *) addr)->sin6_port;
1441 /* modify our published address list */
1442 GNUNET_assert ((args == sizeof (struct IPv4TcpAddress)) ||
1443 (args == sizeof (struct IPv6TcpAddress)));
1444 /* TODO: use 'ac' here in the future... */
1445 address = GNUNET_HELLO_address_allocate (plugin->env->my_identity,
1449 GNUNET_HELLO_ADDRESS_INFO_NONE);
1450 plugin->env->notify_address (plugin->env->cls,
1453 GNUNET_HELLO_address_free (address);
1458 * Function called for a quick conversion of the binary address to
1459 * a numeric address. Note that the caller must not free the
1460 * address and that the next call to this function is allowed
1461 * to override the address again.
1463 * @param cls closure (`struct Plugin*`)
1464 * @param addr binary address
1465 * @param addrlen length of @a addr
1466 * @return string representing the same address
1469 tcp_plugin_address_to_string (void *cls,
1473 static char rbuf[INET6_ADDRSTRLEN + 12];
1474 char buf[INET6_ADDRSTRLEN];
1478 const struct IPv4TcpAddress *t4;
1479 const struct IPv6TcpAddress *t6;
1486 case sizeof(struct IPv6TcpAddress):
1489 port = ntohs (t6->t6_port);
1490 options = ntohl (t6->options);
1491 GNUNET_memcpy (&a6, &t6->ipv6_addr, sizeof(a6));
1494 case sizeof(struct IPv4TcpAddress):
1497 port = ntohs (t4->t4_port);
1498 options = ntohl (t4->options);
1499 GNUNET_memcpy (&a4, &t4->ipv4_addr, sizeof(a4));
1503 LOG (GNUNET_ERROR_TYPE_WARNING,
1504 _("Unexpected address length: %u bytes\n"),
1505 (unsigned int) addrlen);
1508 if (NULL == inet_ntop (af, sb, buf, INET6_ADDRSTRLEN))
1510 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
1514 GNUNET_snprintf (rbuf, sizeof(rbuf),
1515 (af == AF_INET6) ? "%s.%u.[%s]:%u" : "%s.%u.%s:%u",
1525 * Function called to convert a string address to
1528 * @param cls closure (`struct Plugin*`)
1529 * @param addr string address
1530 * @param addrlen length of the address
1531 * @param buf location to store the buffer
1532 * @param added location to store the number of bytes in the buffer.
1533 * If the function returns #GNUNET_SYSERR, its contents are undefined.
1534 * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure
1537 tcp_plugin_string_to_address (void *cls,
1543 struct sockaddr_storage socket_address;
1549 /* Format tcp.options.address:port */
1553 if ((NULL == addr) || (0 == addrlen))
1556 return GNUNET_SYSERR;
1558 if ('\0' != addr[addrlen - 1])
1561 return GNUNET_SYSERR;
1563 if (strlen (addr) != addrlen - 1)
1566 return GNUNET_SYSERR;
1568 plugin = GNUNET_strdup (addr);
1569 optionstr = strchr (plugin, '.');
1570 if (NULL == optionstr)
1573 GNUNET_free(plugin);
1574 return GNUNET_SYSERR;
1576 optionstr[0] = '\0';
1578 options = atol (optionstr);
1579 address = strchr (optionstr, '.');
1580 if (NULL == address)
1583 GNUNET_free(plugin);
1584 return GNUNET_SYSERR;
1590 GNUNET_STRINGS_to_address_ip (address,
1595 GNUNET_free(plugin);
1596 return GNUNET_SYSERR;
1599 GNUNET_free(plugin);
1600 switch (socket_address.ss_family)
1604 struct IPv4TcpAddress *t4;
1605 struct sockaddr_in *in4 = (struct sockaddr_in *) &socket_address;
1606 t4 = GNUNET_new (struct IPv4TcpAddress);
1607 t4->options = htonl (options);
1608 t4->ipv4_addr = in4->sin_addr.s_addr;
1609 t4->t4_port = in4->sin_port;
1611 *added = sizeof(struct IPv4TcpAddress);
1616 struct IPv6TcpAddress *t6;
1617 struct sockaddr_in6 *in6 = (struct sockaddr_in6 *) &socket_address;
1618 t6 = GNUNET_new (struct IPv6TcpAddress);
1619 t6->options = htonl (options);
1620 t6->ipv6_addr = in6->sin6_addr;
1621 t6->t6_port = in6->sin6_port;
1623 *added = sizeof(struct IPv6TcpAddress);
1627 return GNUNET_SYSERR;
1633 * Find the session handle for the given client.
1634 * Currently uses both the hashmap and the client
1635 * context, as the client context is new and the
1636 * logic still needs to be tested.
1638 * @param plugin the plugin
1639 * @param client which client to find the session handle for
1640 * @return NULL if no matching session exists
1642 static struct GNUNET_ATS_Session *
1643 lookup_session_by_client (struct Plugin *plugin,
1644 struct GNUNET_SERVER_Client *client)
1646 return GNUNET_SERVER_client_get_user_context (client,
1647 struct GNUNET_ATS_Session);
1652 * Functions with this signature are called whenever we need
1653 * to close a session due to a disconnect or failure to
1654 * establish a connection.
1656 * @param cls the `struct Plugin`
1657 * @param session session to close down
1658 * @return #GNUNET_OK on success
1661 tcp_plugin_disconnect_session (void *cls,
1662 struct GNUNET_ATS_Session *session)
1664 struct Plugin *plugin = cls;
1665 struct PendingMessage *pm;
1667 LOG (GNUNET_ERROR_TYPE_DEBUG,
1668 "Disconnecting session of peer `%s' address `%s'\n",
1669 GNUNET_i2s (&session->target),
1670 tcp_plugin_address_to_string (session->plugin,
1671 session->address->address,
1672 session->address->address_length));
1674 if (NULL != session->timeout_task)
1676 GNUNET_SCHEDULER_cancel (session->timeout_task);
1677 session->timeout_task = NULL;
1678 session->timeout = GNUNET_TIME_UNIT_ZERO_ABS;
1682 GNUNET_CONTAINER_multipeermap_remove (plugin->sessionmap,
1686 GNUNET_STATISTICS_update (session->plugin->env->stats,
1687 gettext_noop ("# TCP sessions active"),
1693 GNUNET_assert (GNUNET_YES ==
1694 GNUNET_CONTAINER_multipeermap_remove (plugin->nat_wait_conns,
1698 if (NULL != session->client)
1699 GNUNET_SERVER_client_set_user_context (session->client,
1702 /* clean up state */
1703 if (NULL != session->transmit_handle)
1705 GNUNET_SERVER_notify_transmit_ready_cancel (session->transmit_handle);
1706 session->transmit_handle = NULL;
1708 session->plugin->env->session_end (session->plugin->env->cls,
1712 if (NULL != session->nat_connection_timeout)
1714 GNUNET_SCHEDULER_cancel (session->nat_connection_timeout);
1715 session->nat_connection_timeout = NULL;
1718 while (NULL != (pm = session->pending_messages_head))
1720 LOG (GNUNET_ERROR_TYPE_DEBUG,
1721 (NULL != pm->transmit_cont)
1722 ? "Could not deliver message to `%s' at %s.\n"
1723 : "Could not deliver message to `%s' at %s, notifying.\n",
1724 GNUNET_i2s (&session->target),
1725 tcp_plugin_address_to_string (session->plugin,
1726 session->address->address,
1727 session->address->address_length));
1728 GNUNET_STATISTICS_update (session->plugin->env->stats,
1729 gettext_noop ("# bytes currently in TCP buffers"),
1730 -(int64_t) pm->message_size, GNUNET_NO);
1731 GNUNET_STATISTICS_update (session->plugin->env->stats,
1732 gettext_noop ("# bytes discarded by TCP (disconnect)"),
1735 GNUNET_CONTAINER_DLL_remove (session->pending_messages_head,
1736 session->pending_messages_tail,
1738 GNUNET_assert (0 < session->msgs_in_queue);
1739 session->msgs_in_queue--;
1740 GNUNET_assert (pm->message_size <= session->bytes_in_queue);
1741 session->bytes_in_queue -= pm->message_size;
1742 if (NULL != pm->transmit_cont)
1743 pm->transmit_cont (pm->transmit_cont_cls,
1750 GNUNET_assert (0 == session->msgs_in_queue);
1751 GNUNET_assert (0 == session->bytes_in_queue);
1752 notify_session_monitor (session->plugin,
1754 GNUNET_TRANSPORT_SS_DONE);
1756 if (NULL != session->receive_delay_task)
1758 GNUNET_SCHEDULER_cancel (session->receive_delay_task);
1759 session->receive_delay_task = NULL;
1761 if (NULL != session->client)
1763 GNUNET_SERVER_client_disconnect (session->client);
1764 session->client = NULL;
1766 GNUNET_HELLO_address_free (session->address);
1767 GNUNET_assert (NULL == session->transmit_handle);
1768 GNUNET_free (session);
1774 * Function that is called to get the keepalive factor.
1775 * #GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT is divided by this number to
1776 * calculate the interval between keepalive packets.
1778 * @param cls closure with the `struct Plugin`
1779 * @return keepalive factor
1782 tcp_plugin_query_keepalive_factor (void *cls)
1789 * Session was idle for too long, so disconnect it
1791 * @param cls the `struct GNUNET_ATS_Session` of the idle session
1794 session_timeout (void *cls)
1796 struct GNUNET_ATS_Session *s = cls;
1797 struct GNUNET_TIME_Relative left;
1799 s->timeout_task = NULL;
1800 left = GNUNET_TIME_absolute_get_remaining (s->timeout);
1801 if (0 != left.rel_value_us)
1803 /* not actually our turn yet, but let's at least update
1804 the monitor, it may think we're about to die ... */
1805 notify_session_monitor (s->plugin,
1807 GNUNET_TRANSPORT_SS_UPDATE);
1808 s->timeout_task = GNUNET_SCHEDULER_add_delayed (left,
1813 LOG (GNUNET_ERROR_TYPE_DEBUG,
1814 "Session %p was idle for %s, disconnecting\n",
1816 GNUNET_STRINGS_relative_time_to_string (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
1818 /* call session destroy function */
1819 tcp_plugin_disconnect_session (s->plugin,
1825 * Increment session timeout due to activity.
1827 * @param s session to increment timeout for
1830 reschedule_session_timeout (struct GNUNET_ATS_Session *s)
1832 GNUNET_assert (NULL != s->timeout_task);
1833 s->timeout = GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1838 * Create a new session. Also queues a welcome message.
1840 * @param plugin the plugin
1841 * @param address the address to create the session for
1842 * @param scope network scope the address is from
1843 * @param client client to use, reference counter must have already been increased
1844 * @param is_nat this a NAT session, we should wait for a client to
1845 * connect to us from an address, then assign that to
1847 * @return new session object
1849 static struct GNUNET_ATS_Session *
1850 create_session (struct Plugin *plugin,
1851 const struct GNUNET_HELLO_Address *address,
1852 enum GNUNET_ATS_Network_Type scope,
1853 struct GNUNET_SERVER_Client *client,
1856 struct GNUNET_ATS_Session *session;
1857 struct PendingMessage *pm;
1859 if (GNUNET_YES != is_nat)
1860 GNUNET_assert (NULL != client);
1862 GNUNET_assert (NULL == client);
1864 LOG (GNUNET_ERROR_TYPE_DEBUG,
1865 "Creating new session for peer `%s' at address %s\n",
1866 GNUNET_i2s (&address->peer),
1867 tcp_plugin_address_to_string (plugin,
1869 address->address_length));
1870 session = GNUNET_new (struct GNUNET_ATS_Session);
1871 session->last_activity = GNUNET_TIME_absolute_get ();
1872 session->plugin = plugin;
1873 session->is_nat = is_nat;
1876 session->client = client;
1877 GNUNET_SERVER_client_set_user_context (client,
1880 session->address = GNUNET_HELLO_address_copy (address);
1881 session->target = address->peer;
1882 session->expecting_welcome = GNUNET_YES;
1883 session->scope = scope;
1884 pm = GNUNET_malloc (sizeof (struct PendingMessage) +
1885 sizeof (struct WelcomeMessage));
1886 pm->msg = (const char *) &pm[1];
1887 pm->message_size = sizeof(struct WelcomeMessage);
1888 GNUNET_memcpy (&pm[1],
1889 &plugin->my_welcome,
1890 sizeof(struct WelcomeMessage));
1891 pm->timeout = GNUNET_TIME_UNIT_FOREVER_ABS;
1892 GNUNET_STATISTICS_update (plugin->env->stats,
1893 gettext_noop ("# bytes currently in TCP buffers"),
1896 GNUNET_CONTAINER_DLL_insert (session->pending_messages_head,
1897 session->pending_messages_tail,
1899 session->msgs_in_queue++;
1900 session->bytes_in_queue += pm->message_size;
1901 session->timeout = GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1902 session->timeout_task = GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
1905 notify_session_monitor (session->plugin,
1907 GNUNET_TRANSPORT_SS_INIT);
1908 if (GNUNET_YES != is_nat)
1910 GNUNET_STATISTICS_update (plugin->env->stats,
1911 gettext_noop ("# TCP sessions active"),
1914 notify_session_monitor (session->plugin,
1916 GNUNET_TRANSPORT_SS_UP);
1920 notify_session_monitor (session->plugin,
1922 GNUNET_TRANSPORT_SS_HANDSHAKE);
1929 * If we have pending messages, ask the server to
1930 * transmit them (schedule the respective tasks, etc.)
1932 * @param session for which session should we do this
1935 process_pending_messages (struct GNUNET_ATS_Session *session);
1939 * Function called to notify a client about the socket
1940 * being ready to queue more data. "buf" will be
1941 * NULL and "size" zero if the socket was closed for
1942 * writing in the meantime.
1944 * @param cls closure
1945 * @param size number of bytes available in @a buf
1946 * @param buf where the callee should write the message
1947 * @return number of bytes written to @a buf
1950 do_transmit (void *cls,
1954 struct GNUNET_ATS_Session *session = cls;
1955 struct GNUNET_PeerIdentity pid;
1956 struct Plugin *plugin;
1957 struct PendingMessage *pos;
1958 struct PendingMessage *hd;
1959 struct PendingMessage *tl;
1960 struct GNUNET_TIME_Absolute now;
1964 session->transmit_handle = NULL;
1965 plugin = session->plugin;
1968 LOG (GNUNET_ERROR_TYPE_DEBUG,
1969 "Timeout trying to transmit to peer `%s', discarding message queue.\n",
1970 GNUNET_i2s (&session->target));
1971 /* timeout; cancel all messages that have already expired */
1975 now = GNUNET_TIME_absolute_get ();
1976 while ( (NULL != (pos = session->pending_messages_head)) &&
1977 (pos->timeout.abs_value_us <= now.abs_value_us) )
1979 GNUNET_CONTAINER_DLL_remove (session->pending_messages_head,
1980 session->pending_messages_tail,
1982 GNUNET_assert (0 < session->msgs_in_queue);
1983 session->msgs_in_queue--;
1984 GNUNET_assert (pos->message_size <= session->bytes_in_queue);
1985 session->bytes_in_queue -= pos->message_size;
1986 LOG (GNUNET_ERROR_TYPE_DEBUG,
1987 "Failed to transmit %u byte message to `%s'.\n",
1989 GNUNET_i2s (&session->target));
1990 ret += pos->message_size;
1991 GNUNET_CONTAINER_DLL_insert_after (hd,
1996 /* do this call before callbacks (so that if callbacks destroy
1997 * session, they have a chance to cancel actions done by this
1999 process_pending_messages (session);
2000 pid = session->target;
2001 /* no do callbacks and do not use session again since
2002 * the callbacks may abort the session */
2003 while (NULL != (pos = hd))
2005 GNUNET_CONTAINER_DLL_remove (hd,
2008 if (NULL != pos->transmit_cont)
2009 pos->transmit_cont (pos->transmit_cont_cls,
2016 GNUNET_STATISTICS_update (plugin->env->stats,
2017 gettext_noop ("# bytes currently in TCP buffers"), -(int64_t) ret,
2019 GNUNET_STATISTICS_update (plugin->env->stats,
2020 gettext_noop ("# bytes discarded by TCP (timeout)"),
2024 notify_session_monitor (session->plugin,
2026 GNUNET_TRANSPORT_SS_UPDATE);
2029 /* copy all pending messages that would fit */
2034 while (NULL != (pos = session->pending_messages_head))
2036 if (ret + pos->message_size > size)
2038 GNUNET_CONTAINER_DLL_remove (session->pending_messages_head,
2039 session->pending_messages_tail,
2041 GNUNET_assert (0 < session->msgs_in_queue);
2042 session->msgs_in_queue--;
2043 GNUNET_assert (pos->message_size <= session->bytes_in_queue);
2044 session->bytes_in_queue -= pos->message_size;
2045 GNUNET_assert(size >= pos->message_size);
2046 LOG (GNUNET_ERROR_TYPE_DEBUG,
2047 "Transmitting message of type %u size %u to peer %s at %s\n",
2048 ntohs (((struct GNUNET_MessageHeader *) pos->msg)->type),
2050 GNUNET_i2s (&session->target),
2051 tcp_plugin_address_to_string (session->plugin,
2052 session->address->address,
2053 session->address->address_length));
2054 /* FIXME: this GNUNET_memcpy can be up to 7% of our total runtime */
2055 GNUNET_memcpy (cbuf,
2058 cbuf += pos->message_size;
2059 ret += pos->message_size;
2060 size -= pos->message_size;
2061 GNUNET_CONTAINER_DLL_insert_tail (hd,
2065 notify_session_monitor (session->plugin,
2067 GNUNET_TRANSPORT_SS_UPDATE);
2068 /* schedule 'continuation' before callbacks so that callbacks that
2069 * cancel everything don't cause us to use a session that no longer
2071 process_pending_messages (session);
2072 session->last_activity = GNUNET_TIME_absolute_get ();
2073 pid = session->target;
2074 /* we'll now call callbacks that may cancel the session; hence
2075 * we should not use 'session' after this point */
2076 while (NULL != (pos = hd))
2078 GNUNET_CONTAINER_DLL_remove (hd, tl, pos);
2079 if (NULL != pos->transmit_cont)
2080 pos->transmit_cont (pos->transmit_cont_cls,
2084 pos->message_size); /* FIXME: include TCP overhead */
2087 GNUNET_assert (NULL == hd);
2088 GNUNET_assert (NULL == tl);
2089 GNUNET_STATISTICS_update (plugin->env->stats,
2090 gettext_noop ("# bytes currently in TCP buffers"),
2093 GNUNET_STATISTICS_update (plugin->env->stats,
2094 gettext_noop ("# bytes transmitted via TCP"),
2102 * If we have pending messages, ask the server to
2103 * transmit them (schedule the respective tasks, etc.)
2105 * @param session for which session should we do this
2108 process_pending_messages (struct GNUNET_ATS_Session *session)
2110 struct PendingMessage *pm;
2112 GNUNET_assert (NULL != session->client);
2113 if (NULL != session->transmit_handle)
2115 if (NULL == (pm = session->pending_messages_head))
2118 session->transmit_handle
2119 = GNUNET_SERVER_notify_transmit_ready (session->client,
2121 GNUNET_TIME_absolute_get_remaining (pm->timeout),
2128 * Function that can be used by the transport service to transmit
2129 * a message using the plugin. Note that in the case of a
2130 * peer disconnecting, the continuation MUST be called
2131 * prior to the disconnect notification itself. This function
2132 * will be called with this peer's HELLO message to initiate
2133 * a fresh connection to another peer.
2135 * @param cls closure
2136 * @param session which session must be used
2137 * @param msgbuf the message to transmit
2138 * @param msgbuf_size number of bytes in @a msgbuf
2139 * @param priority how important is the message (most plugins will
2140 * ignore message priority and just FIFO)
2141 * @param to how long to wait at most for the transmission (does not
2142 * require plugins to discard the message after the timeout,
2143 * just advisory for the desired delay; most plugins will ignore
2145 * @param cont continuation to call once the message has
2146 * been transmitted (or if the transport is ready
2147 * for the next transmission call; or if the
2148 * peer disconnected...); can be NULL
2149 * @param cont_cls closure for @a cont
2150 * @return number of bytes used (on the physical network, with overheads);
2151 * -1 on hard errors (i.e. address invalid); 0 is a legal value
2152 * and does NOT mean that the message was not transmitted (DV)
2155 tcp_plugin_send (void *cls,
2156 struct GNUNET_ATS_Session *session,
2159 unsigned int priority,
2160 struct GNUNET_TIME_Relative to,
2161 GNUNET_TRANSPORT_TransmitContinuation cont,
2164 struct Plugin * plugin = cls;
2165 struct PendingMessage *pm;
2167 /* create new message entry */
2168 pm = GNUNET_malloc (sizeof (struct PendingMessage) + msgbuf_size);
2169 pm->msg = (const char *) &pm[1];
2170 GNUNET_memcpy (&pm[1], msgbuf, msgbuf_size);
2171 pm->message_size = msgbuf_size;
2172 pm->timeout = GNUNET_TIME_relative_to_absolute (to);
2173 pm->transmit_cont = cont;
2174 pm->transmit_cont_cls = cont_cls;
2176 LOG (GNUNET_ERROR_TYPE_DEBUG,
2177 "Asked to transmit %u bytes to `%s', added message to list.\n",
2179 GNUNET_i2s (&session->target));
2182 GNUNET_CONTAINER_multipeermap_contains_value (plugin->sessionmap,
2186 GNUNET_assert (NULL != session->client);
2187 GNUNET_SERVER_client_set_timeout (session->client,
2188 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2189 GNUNET_STATISTICS_update (plugin->env->stats,
2190 gettext_noop ("# bytes currently in TCP buffers"),
2194 /* append pm to pending_messages list */
2195 GNUNET_CONTAINER_DLL_insert_tail (session->pending_messages_head,
2196 session->pending_messages_tail,
2198 notify_session_monitor (session->plugin,
2200 GNUNET_TRANSPORT_SS_UPDATE);
2201 session->msgs_in_queue++;
2202 session->bytes_in_queue += pm->message_size;
2203 process_pending_messages (session);
2207 GNUNET_CONTAINER_multipeermap_contains_value (plugin->nat_wait_conns,
2211 LOG (GNUNET_ERROR_TYPE_DEBUG,
2212 "This NAT WAIT session for peer `%s' is not yet ready!\n",
2213 GNUNET_i2s (&session->target));
2214 GNUNET_STATISTICS_update (plugin->env->stats,
2215 gettext_noop ("# bytes currently in TCP buffers"), msgbuf_size,
2217 /* append pm to pending_messages list */
2218 GNUNET_CONTAINER_DLL_insert_tail (session->pending_messages_head,
2219 session->pending_messages_tail,
2221 session->msgs_in_queue++;
2222 session->bytes_in_queue += pm->message_size;
2223 notify_session_monitor (session->plugin,
2225 GNUNET_TRANSPORT_SS_HANDSHAKE);
2228 LOG (GNUNET_ERROR_TYPE_ERROR,
2229 "Invalid session %p\n",
2239 return GNUNET_SYSERR; /* session does not exist here */
2244 * Closure for #session_lookup_it().
2246 struct GNUNET_ATS_SessionItCtx
2249 * Address we are looking for.
2251 const struct GNUNET_HELLO_Address *address;
2254 * Where to store the session (if we found it).
2256 struct GNUNET_ATS_Session *result;
2262 * Look for a session by address.
2264 * @param cls the `struct GNUNET_ATS_SessionItCtx`
2266 * @param value a `struct GNUNET_ATS_Session`
2267 * @return #GNUNET_YES to continue looking, #GNUNET_NO if we found the session
2270 session_lookup_it (void *cls,
2271 const struct GNUNET_PeerIdentity *key,
2274 struct GNUNET_ATS_SessionItCtx *si_ctx = cls;
2275 struct GNUNET_ATS_Session *session = value;
2278 GNUNET_HELLO_address_cmp (si_ctx->address,
2281 si_ctx->result = session;
2287 * Task cleaning up a NAT connection attempt after timeout
2289 * @param cls the `struct GNUNET_ATS_Session`
2292 nat_connect_timeout (void *cls)
2294 struct GNUNET_ATS_Session *session = cls;
2296 session->nat_connection_timeout = NULL;
2297 LOG (GNUNET_ERROR_TYPE_DEBUG,
2298 "NAT WAIT connection to `%4s' at `%s' could not be established, removing session\n",
2299 GNUNET_i2s (&session->target),
2300 tcp_plugin_address_to_string (session->plugin,
2301 session->address->address,
2302 session->address->address_length));
2303 tcp_plugin_disconnect_session (session->plugin,
2309 * Function that will be called whenever the transport service wants to
2310 * notify the plugin that a session is still active and in use and
2311 * therefore the session timeout for this session has to be updated
2313 * @param cls closure
2314 * @param peer which peer was the session for
2315 * @param session which session is being updated
2318 tcp_plugin_update_session_timeout (void *cls,
2319 const struct GNUNET_PeerIdentity *peer,
2320 struct GNUNET_ATS_Session *session)
2322 reschedule_session_timeout (session);
2327 * Task to signal the server that we can continue
2328 * receiving from the TCP client now.
2330 * @param cls the `struct GNUNET_ATS_Session *`
2333 delayed_done (void *cls)
2335 struct GNUNET_ATS_Session *session = cls;
2337 session->receive_delay_task = NULL;
2338 reschedule_session_timeout (session);
2339 GNUNET_SERVER_receive_done (session->client,
2345 * Function that will be called whenever the transport service wants to
2346 * notify the plugin that the inbound quota changed and that the plugin
2347 * should update it's delay for the next receive value
2349 * @param cls closure
2350 * @param peer which peer was the session for
2351 * @param session which session is being updated
2352 * @param delay new delay to use for receiving
2355 tcp_plugin_update_inbound_delay (void *cls,
2356 const struct GNUNET_PeerIdentity *peer,
2357 struct GNUNET_ATS_Session *session,
2358 struct GNUNET_TIME_Relative delay)
2360 if (NULL == session->receive_delay_task)
2362 LOG (GNUNET_ERROR_TYPE_DEBUG,
2363 "New inbound delay %s\n",
2364 GNUNET_STRINGS_relative_time_to_string (delay,
2366 session->receive_delay = GNUNET_TIME_relative_to_absolute (delay);
2367 GNUNET_SCHEDULER_cancel (session->receive_delay_task);
2368 session->receive_delay_task = GNUNET_SCHEDULER_add_delayed (delay,
2375 * Create a new session to transmit data to the target
2376 * This session will used to send data to this peer and the plugin will
2377 * notify us by calling the env->session_end function
2379 * @param cls closure
2380 * @param address the address to use
2381 * @return the session if the address is valid, NULL otherwise
2383 static struct GNUNET_ATS_Session *
2384 tcp_plugin_get_session (void *cls,
2385 const struct GNUNET_HELLO_Address *address)
2387 struct Plugin *plugin = cls;
2388 struct GNUNET_ATS_Session *session = NULL;
2392 struct GNUNET_CONNECTION_Handle *sa;
2393 struct sockaddr_in a4;
2394 struct sockaddr_in6 a6;
2395 const struct IPv4TcpAddress *t4;
2396 const struct IPv6TcpAddress *t6;
2397 unsigned int options;
2398 enum GNUNET_ATS_Network_Type net_type;
2399 unsigned int is_natd = GNUNET_NO;
2402 struct GNUNET_NETWORK_Handle *s;
2405 addrlen = address->address_length;
2406 LOG (GNUNET_ERROR_TYPE_DEBUG,
2407 "Trying to get session for `%s' address of peer `%s'\n",
2408 tcp_plugin_address_to_string (plugin,
2410 address->address_length),
2411 GNUNET_i2s (&address->peer));
2413 if (GNUNET_HELLO_address_check_option (address,
2414 GNUNET_HELLO_ADDRESS_INFO_INBOUND))
2420 /* look for existing session */
2422 GNUNET_CONTAINER_multipeermap_contains (plugin->sessionmap,
2425 struct GNUNET_ATS_SessionItCtx si_ctx;
2427 si_ctx.address = address;
2428 si_ctx.result = NULL;
2429 GNUNET_CONTAINER_multipeermap_get_multiple (plugin->sessionmap,
2433 if (NULL != si_ctx.result)
2435 session = si_ctx.result;
2436 LOG (GNUNET_ERROR_TYPE_DEBUG,
2437 "Found existing session for `%s' address `%s'\n",
2438 GNUNET_i2s (&address->peer),
2439 tcp_plugin_address_to_string (plugin,
2441 address->address_length));
2444 /* This is a bit of a hack, limiting TCP to never allow more than
2445 one TCP connection to any given peer at the same time.
2446 Without this, peers sometimes disagree about which of the TCP
2447 connections they should use, causing one side to believe that
2448 they transmit successfully, while the other receives nothing. */
2449 return NULL; /* Refuse to have more than one TCP connection per
2450 peer pair at the same time. */
2453 if (addrlen == sizeof(struct IPv6TcpAddress))
2455 GNUNET_assert (NULL != address->address); /* make static analysis happy */
2456 t6 = address->address;
2457 options = t6->options;
2459 memset (&a6, 0, sizeof(a6));
2460 #if HAVE_SOCKADDR_IN_SIN_LEN
2461 a6.sin6_len = sizeof (a6);
2463 a6.sin6_family = AF_INET6;
2464 a6.sin6_port = t6->t6_port;
2465 if (t6->t6_port == 0)
2466 is_natd = GNUNET_YES;
2467 GNUNET_memcpy (&a6.sin6_addr, &t6->ipv6_addr, sizeof(struct in6_addr));
2471 else if (addrlen == sizeof(struct IPv4TcpAddress))
2473 GNUNET_assert(NULL != address->address); /* make static analysis happy */
2474 t4 = address->address;
2475 options = t4->options;
2477 memset (&a4, 0, sizeof(a4));
2478 #if HAVE_SOCKADDR_IN_SIN_LEN
2479 a4.sin_len = sizeof (a4);
2481 a4.sin_family = AF_INET;
2482 a4.sin_port = t4->t4_port;
2483 if (t4->t4_port == 0)
2484 is_natd = GNUNET_YES;
2485 a4.sin_addr.s_addr = t4->ipv4_addr;
2491 GNUNET_STATISTICS_update (plugin->env->stats,
2492 gettext_noop ("# requests to create session with invalid address"),
2498 net_type = plugin->env->get_address_type (plugin->env->cls,
2501 GNUNET_break (net_type != GNUNET_ATS_NET_UNSPECIFIED);
2503 if ( (is_natd == GNUNET_YES) &&
2504 (addrlen == sizeof(struct IPv6TcpAddress)) )
2506 /* NAT client only works with IPv4 addresses */
2510 if (plugin->cur_connections >= plugin->max_connections)
2516 if ( (is_natd == GNUNET_YES) &&
2518 GNUNET_CONTAINER_multipeermap_contains (plugin->nat_wait_conns,
2521 /* Only do one NAT punch attempt per peer identity */
2525 if ( (is_natd == GNUNET_YES) &&
2526 (NULL != plugin->nat) &&
2528 GNUNET_CONTAINER_multipeermap_contains (plugin->nat_wait_conns,
2531 struct sockaddr_in local_sa;
2533 LOG (GNUNET_ERROR_TYPE_DEBUG,
2534 "Found valid IPv4 NAT address (creating session)!\n");
2535 session = create_session (plugin,
2540 session->nat_connection_timeout = GNUNET_SCHEDULER_add_delayed (NAT_TIMEOUT,
2541 &nat_connect_timeout,
2543 GNUNET_assert (GNUNET_OK ==
2544 GNUNET_CONTAINER_multipeermap_put (plugin->nat_wait_conns,
2547 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
2549 LOG (GNUNET_ERROR_TYPE_DEBUG,
2550 "Created NAT WAIT connection to `%s' at `%s'\n",
2551 GNUNET_i2s (&session->target),
2552 GNUNET_a2s (sb, sbs));
2556 local_sa.sin_family = AF_INET;
2557 local_sa.sin_port = htons (plugin->open_port);
2558 /* We leave sin_address at 0, let the kernel figure it out,
2559 even if our bind() is more specific. (May want to reconsider
2562 GNUNET_NAT_request_reversal (plugin->nat,
2566 LOG (GNUNET_ERROR_TYPE_DEBUG,
2567 "Running NAT client for `%s' at `%s' failed\n",
2568 GNUNET_i2s (&session->target),
2569 GNUNET_a2s (sb, sbs));
2570 tcp_plugin_disconnect_session (plugin,
2575 /* create new outbound session */
2576 if (0 != (options & TCP_OPTIONS_TCP_STEALTH))
2579 s = GNUNET_NETWORK_socket_create (af, SOCK_STREAM, 0);
2582 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK,
2589 GNUNET_NETWORK_socket_setsockopt (s,
2593 sizeof (struct GNUNET_PeerIdentity))) ||
2595 GNUNET_NETWORK_socket_setsockopt (s,
2597 TCP_STEALTH_INTEGRITY,
2598 &plugin->my_welcome,
2599 sizeof (struct WelcomeMessage))) )
2601 /* TCP STEALTH not supported by kernel */
2602 GNUNET_break (GNUNET_OK ==
2603 GNUNET_NETWORK_socket_close (s));
2608 sa = GNUNET_CONNECTION_connect_socket (s, sb, sbs);
2617 sa = GNUNET_CONNECTION_create_from_sockaddr (af, sb, sbs);
2621 LOG (GNUNET_ERROR_TYPE_DEBUG,
2622 "Failed to create connection to `%s' at `%s'\n",
2623 GNUNET_i2s (&address->peer),
2624 GNUNET_a2s (sb, sbs));
2627 LOG (GNUNET_ERROR_TYPE_DEBUG,
2628 "Asked to transmit to `%s', creating fresh session using address `%s'.\n",
2629 GNUNET_i2s (&address->peer),
2630 GNUNET_a2s (sb, sbs));
2632 session = create_session (plugin,
2635 GNUNET_SERVER_connect_socket (plugin->server,
2638 (void) GNUNET_CONTAINER_multipeermap_put (plugin->sessionmap,
2641 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
2642 /* Send TCP Welcome */
2643 process_pending_messages (session);
2650 * We have been asked to destroy all connections to a particular peer.
2651 * This function is called on each applicable session and must tear it
2654 * @param cls the `struct Plugin *`
2655 * @param key the peer which the session belongs to (unused)
2656 * @param value the `struct GNUNET_ATS_Session`
2657 * @return #GNUNET_YES (continue to iterate)
2660 session_disconnect_it (void *cls,
2661 const struct GNUNET_PeerIdentity *key,
2664 struct Plugin *plugin = cls;
2665 struct GNUNET_ATS_Session *session = value;
2667 GNUNET_STATISTICS_update (session->plugin->env->stats,
2668 gettext_noop ("# transport-service disconnect requests for TCP"),
2671 tcp_plugin_disconnect_session (plugin,
2678 * Function that can be called to force a disconnect from the
2679 * specified neighbour. This should also cancel all previously
2680 * scheduled transmissions. Obviously the transmission may have been
2681 * partially completed already, which is OK. The plugin is supposed
2682 * to close the connection (if applicable) and no longer call the
2683 * transmit continuation(s).
2685 * Finally, plugin MUST NOT call the services's receive function to
2686 * notify the service that the connection to the specified target was
2687 * closed after a getting this call.
2689 * @param cls closure
2690 * @param target peer for which the last transmission is
2694 tcp_plugin_disconnect (void *cls,
2695 const struct GNUNET_PeerIdentity *target)
2697 struct Plugin *plugin = cls;
2699 LOG (GNUNET_ERROR_TYPE_DEBUG,
2700 "Disconnecting peer `%s'\n",
2701 GNUNET_i2s (target));
2702 GNUNET_CONTAINER_multipeermap_get_multiple (plugin->sessionmap,
2704 &session_disconnect_it,
2706 GNUNET_CONTAINER_multipeermap_get_multiple (plugin->nat_wait_conns,
2708 &session_disconnect_it,
2714 * We are processing an address pretty printing request and finished
2715 * the IP resolution (if applicable). Append our port and forward the
2716 * result. If called with @a hostname NULL, we are done and should
2717 * clean up the pretty printer (otherwise, there might be multiple
2718 * hostnames for the IP address and we might receive more).
2720 * @param cls the `struct PrettyPrinterContext *`
2721 * @param hostname hostname part of the address
2724 append_port (void *cls,
2725 const char *hostname)
2727 struct PrettyPrinterContext *ppc = cls;
2728 struct Plugin *plugin = ppc->plugin;
2731 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2732 "append_port called with hostname `%s'\n",
2734 if (NULL == hostname)
2736 /* Final call, done */
2737 ppc->resolver_handle = NULL;
2738 GNUNET_CONTAINER_DLL_remove (plugin->ppc_dll_head,
2739 plugin->ppc_dll_tail,
2741 ppc->asc (ppc->asc_cls,
2747 if (GNUNET_YES == ppc->ipv6)
2748 GNUNET_asprintf (&ret,
2755 GNUNET_asprintf (&ret,
2761 ppc->asc (ppc->asc_cls,
2769 * Convert the transports address to a nice, human-readable format.
2771 * @param cls closure with the `struct Plugin`
2772 * @param type name of the transport that generated the address
2773 * @param addr one of the addresses of the host, NULL for the last address
2774 * the specific address format depends on the transport
2775 * @param addrlen length of the @a addr
2776 * @param numeric should (IP) addresses be displayed in numeric form?
2777 * @param timeout after how long should we give up?
2778 * @param asc function to call on each string
2779 * @param asc_cls closure for @a asc
2782 tcp_plugin_address_pretty_printer (void *cls,
2787 struct GNUNET_TIME_Relative timeout,
2788 GNUNET_TRANSPORT_AddressStringCallback asc,
2791 struct Plugin *plugin = cls;
2792 struct PrettyPrinterContext *ppc;
2795 struct sockaddr_in a4;
2796 struct sockaddr_in6 a6;
2797 const struct IPv4TcpAddress *t4;
2798 const struct IPv6TcpAddress *t6;
2802 if (sizeof(struct IPv6TcpAddress) == addrlen)
2805 memset (&a6, 0, sizeof(a6));
2806 a6.sin6_family = AF_INET6;
2807 a6.sin6_port = t6->t6_port;
2808 GNUNET_memcpy (&a6.sin6_addr, &t6->ipv6_addr, sizeof(struct in6_addr));
2809 port = ntohs (t6->t6_port);
2810 options = ntohl (t6->options);
2814 else if (sizeof(struct IPv4TcpAddress) == addrlen)
2817 memset (&a4, 0, sizeof(a4));
2818 a4.sin_family = AF_INET;
2819 a4.sin_port = t4->t4_port;
2820 a4.sin_addr.s_addr = t4->ipv4_addr;
2821 port = ntohs (t4->t4_port);
2822 options = ntohl (t4->options);
2828 /* invalid address */
2829 LOG (GNUNET_ERROR_TYPE_WARNING,
2830 _("Unexpected address length: %u bytes\n"),
2831 (unsigned int) addrlen);
2832 asc (asc_cls, NULL, GNUNET_SYSERR);
2833 asc (asc_cls, NULL, GNUNET_OK);
2836 ppc = GNUNET_new (struct PrettyPrinterContext);
2837 ppc->plugin = plugin;
2838 if (addrlen == sizeof(struct IPv6TcpAddress))
2839 ppc->ipv6 = GNUNET_YES;
2841 ppc->ipv6 = GNUNET_NO;
2843 ppc->asc_cls = asc_cls;
2845 ppc->options = options;
2846 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2847 "Starting DNS reverse lookup\n");
2848 ppc->resolver_handle = GNUNET_RESOLVER_hostname_get (sb,
2854 if (NULL == ppc->resolver_handle)
2860 GNUNET_CONTAINER_DLL_insert (plugin->ppc_dll_head,
2861 plugin->ppc_dll_tail,
2867 * Function that will be called to check if a binary address for this
2868 * plugin is well-formed and corresponds to an address for THIS peer
2869 * (as per our configuration). Naturally, if absolutely necessary,
2870 * plugins can be a bit conservative in their answer, but in general
2871 * plugins should make sure that the address does not redirect
2872 * traffic to a 3rd party that might try to man-in-the-middle our
2875 * @param cls closure, our `struct Plugin *`
2876 * @param addr pointer to the address
2877 * @param addrlen length of @a addr
2878 * @return #GNUNET_OK if this is a plausible address for this peer
2879 * and transport, #GNUNET_SYSERR if not
2882 tcp_plugin_check_address (void *cls,
2886 struct Plugin *plugin = cls;
2887 const struct IPv4TcpAddress *v4;
2888 const struct IPv6TcpAddress *v6;
2890 if ( (addrlen != sizeof(struct IPv4TcpAddress)) &&
2891 (addrlen != sizeof(struct IPv6TcpAddress)) )
2893 GNUNET_break_op (0);
2894 return GNUNET_SYSERR;
2897 if (addrlen == sizeof(struct IPv4TcpAddress))
2899 struct sockaddr_in s4;
2901 v4 = (const struct IPv4TcpAddress *) addr;
2902 if (0 != memcmp (&v4->options,
2907 return GNUNET_SYSERR;
2909 memset (&s4, 0, sizeof (s4));
2910 s4.sin_family = AF_INET;
2911 #if HAVE_SOCKADDR_IN_SIN_LEN
2912 s4.sin_len = sizeof (s4);
2914 s4.sin_port = v4->t4_port;
2915 s4.sin_addr.s_addr = v4->ipv4_addr;
2918 GNUNET_NAT_test_address (plugin->nat,
2920 sizeof (struct sockaddr_in)))
2921 return GNUNET_SYSERR;
2925 struct sockaddr_in6 s6;
2927 v6 = (const struct IPv6TcpAddress *) addr;
2928 if (IN6_IS_ADDR_LINKLOCAL (&v6->ipv6_addr))
2930 GNUNET_break_op (0);
2931 return GNUNET_SYSERR;
2933 if (0 != memcmp (&v6->options,
2938 return GNUNET_SYSERR;
2940 memset (&s6, 0, sizeof (s6));
2941 s6.sin6_family = AF_INET6;
2942 #if HAVE_SOCKADDR_IN_SIN_LEN
2943 s6.sin6_len = sizeof (s6);
2945 s6.sin6_port = v6->t6_port;
2946 s6.sin6_addr = v6->ipv6_addr;
2949 GNUNET_NAT_test_address (plugin->nat,
2951 sizeof(struct sockaddr_in6)))
2952 return GNUNET_SYSERR;
2959 * We've received a nat probe from this peer via TCP. Finish
2960 * creating the client session and resume sending of queued
2963 * @param cls closure
2964 * @param client identification of the client
2965 * @param message the actual message
2968 handle_tcp_nat_probe (void *cls,
2969 struct GNUNET_SERVER_Client *client,
2970 const struct GNUNET_MessageHeader *message)
2972 struct Plugin *plugin = cls;
2973 struct GNUNET_ATS_Session *session;
2974 const struct TCP_NAT_ProbeMessage *tcp_nat_probe;
2977 struct IPv4TcpAddress *t4;
2978 struct IPv6TcpAddress *t6;
2979 const struct sockaddr_in *s4;
2980 const struct sockaddr_in6 *s6;
2982 LOG (GNUNET_ERROR_TYPE_DEBUG,
2983 "Received NAT probe\n");
2984 /* We have received a TCP NAT probe, meaning we (hopefully) initiated
2985 * a connection to this peer by running gnunet-nat-client. This peer
2986 * received the punch message and now wants us to use the new connection
2987 * as the default for that peer. Do so and then send a WELCOME message
2988 * so we can really be connected!
2990 if (ntohs (message->size) != sizeof(struct TCP_NAT_ProbeMessage))
2993 GNUNET_SERVER_receive_done (client,
2998 tcp_nat_probe = (const struct TCP_NAT_ProbeMessage *) message;
2999 if (0 == memcmp (&tcp_nat_probe->clientIdentity, plugin->env->my_identity,
3000 sizeof(struct GNUNET_PeerIdentity)))
3002 /* refuse connections from ourselves */
3003 GNUNET_SERVER_receive_done (client,
3008 session = GNUNET_CONTAINER_multipeermap_get (plugin->nat_wait_conns,
3009 &tcp_nat_probe->clientIdentity);
3010 if (NULL == session)
3012 LOG (GNUNET_ERROR_TYPE_DEBUG,
3013 "Did NOT find session for NAT probe!\n");
3014 GNUNET_SERVER_receive_done (client,
3018 LOG (GNUNET_ERROR_TYPE_DEBUG,
3019 "Found session for NAT probe!\n");
3021 if (NULL != session->nat_connection_timeout)
3023 GNUNET_SCHEDULER_cancel (session->nat_connection_timeout);
3024 session->nat_connection_timeout = NULL;
3028 GNUNET_SERVER_client_get_address (client,
3033 GNUNET_SERVER_receive_done (client,
3035 tcp_plugin_disconnect_session (plugin,
3039 GNUNET_assert (GNUNET_YES ==
3040 GNUNET_CONTAINER_multipeermap_remove (plugin->nat_wait_conns,
3041 &tcp_nat_probe->clientIdentity,
3043 GNUNET_SERVER_client_set_user_context (client,
3045 (void) GNUNET_CONTAINER_multipeermap_put (plugin->sessionmap,
3048 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
3049 session->last_activity = GNUNET_TIME_absolute_get ();
3050 LOG (GNUNET_ERROR_TYPE_DEBUG,
3051 "Found address `%s' for incoming connection\n",
3052 GNUNET_a2s (vaddr, alen));
3053 switch (((const struct sockaddr *) vaddr)->sa_family)
3057 t4 = GNUNET_new (struct IPv4TcpAddress);
3058 t4->options = htonl (TCP_OPTIONS_NONE);
3059 t4->t4_port = s4->sin_port;
3060 t4->ipv4_addr = s4->sin_addr.s_addr;
3061 session->address = GNUNET_HELLO_address_allocate (&tcp_nat_probe->clientIdentity,
3064 sizeof(struct IPv4TcpAddress),
3065 GNUNET_HELLO_ADDRESS_INFO_NONE);
3069 t6 = GNUNET_new (struct IPv6TcpAddress);
3070 t6->options = htonl (TCP_OPTIONS_NONE);
3071 t6->t6_port = s6->sin6_port;
3072 GNUNET_memcpy (&t6->ipv6_addr, &s6->sin6_addr, sizeof(struct in6_addr));
3073 session->address = GNUNET_HELLO_address_allocate (&tcp_nat_probe->clientIdentity,
3076 sizeof(struct IPv6TcpAddress),
3077 GNUNET_HELLO_ADDRESS_INFO_NONE);
3081 LOG(GNUNET_ERROR_TYPE_DEBUG,
3082 "Bad address for incoming connection!\n");
3084 GNUNET_SERVER_receive_done (client,
3086 tcp_plugin_disconnect_session (plugin,
3090 GNUNET_free (vaddr);
3091 GNUNET_break (NULL == session->client);
3092 session->client = client;
3093 GNUNET_STATISTICS_update (plugin->env->stats,
3094 gettext_noop ("# TCP sessions active"),
3097 process_pending_messages (session);
3098 GNUNET_SERVER_receive_done (client,
3104 * We've received a welcome from this peer via TCP. Possibly create a
3105 * fresh client record and send back our welcome.
3107 * @param cls closure
3108 * @param client identification of the client
3109 * @param message the actual message
3112 handle_tcp_welcome (void *cls,
3113 struct GNUNET_SERVER_Client *client,
3114 const struct GNUNET_MessageHeader *message)
3116 struct Plugin *plugin = cls;
3117 const struct WelcomeMessage *wm = (const struct WelcomeMessage *) message;
3118 struct GNUNET_HELLO_Address *address;
3119 struct GNUNET_ATS_Session *session;
3122 struct IPv4TcpAddress t4;
3123 struct IPv6TcpAddress t6;
3124 const struct sockaddr_in *s4;
3125 const struct sockaddr_in6 *s6;
3127 if (0 == memcmp (&wm->clientIdentity,
3128 plugin->env->my_identity,
3129 sizeof(struct GNUNET_PeerIdentity)))
3131 /* refuse connections from ourselves */
3132 GNUNET_SERVER_receive_done (client,
3135 GNUNET_SERVER_client_get_address (client,
3139 LOG (GNUNET_ERROR_TYPE_INFO,
3140 "Received WELCOME message from my own identity `%s' on address `%s'\n",
3141 GNUNET_i2s (&wm->clientIdentity),
3142 GNUNET_a2s (vaddr, alen));
3143 GNUNET_free (vaddr);
3149 GNUNET_SERVER_client_get_address (client,
3153 LOG(GNUNET_ERROR_TYPE_DEBUG,
3154 "Received WELCOME message from `%s' on address `%s'\n",
3155 GNUNET_i2s (&wm->clientIdentity),
3156 GNUNET_a2s (vaddr, alen));
3157 GNUNET_free (vaddr);
3159 GNUNET_STATISTICS_update (plugin->env->stats,
3160 gettext_noop ("# TCP WELCOME messages received"),
3163 session = lookup_session_by_client (plugin,
3165 if (NULL != session)
3168 GNUNET_SERVER_client_get_address (client,
3172 LOG (GNUNET_ERROR_TYPE_DEBUG,
3173 "Found existing session %p for peer `%s'\n",
3175 GNUNET_a2s (vaddr, alen));
3176 GNUNET_free (vaddr);
3182 GNUNET_SERVER_client_get_address (client, &vaddr, &alen))
3184 if (alen == sizeof(struct sockaddr_in))
3187 memset (&t4, '\0', sizeof (t4));
3188 t4.options = htonl (TCP_OPTIONS_NONE);
3189 t4.t4_port = s4->sin_port;
3190 t4.ipv4_addr = s4->sin_addr.s_addr;
3191 address = GNUNET_HELLO_address_allocate (&wm->clientIdentity,
3195 GNUNET_HELLO_ADDRESS_INFO_INBOUND);
3197 else if (alen == sizeof(struct sockaddr_in6))
3200 memset (&t6, '\0', sizeof (t6));
3201 t6.options = htonl (TCP_OPTIONS_NONE);
3202 t6.t6_port = s6->sin6_port;
3203 GNUNET_memcpy (&t6.ipv6_addr, &s6->sin6_addr, sizeof(struct in6_addr));
3204 address = GNUNET_HELLO_address_allocate (&wm->clientIdentity,
3208 GNUNET_HELLO_ADDRESS_INFO_INBOUND);
3213 GNUNET_free_non_null (vaddr);
3214 GNUNET_SERVER_receive_done (client,
3218 session = create_session (plugin,
3220 plugin->env->get_address_type (plugin->env->cls,
3225 GNUNET_break (GNUNET_ATS_NET_UNSPECIFIED != session->scope);
3226 GNUNET_HELLO_address_free (address);
3227 LOG (GNUNET_ERROR_TYPE_DEBUG,
3228 "Creating new%s session %p for peer `%s' client %p\n",
3229 GNUNET_HELLO_address_check_option (session->address,
3230 GNUNET_HELLO_ADDRESS_INFO_INBOUND)
3233 tcp_plugin_address_to_string (plugin,
3234 session->address->address,
3235 session->address->address_length),
3237 GNUNET_free (vaddr);
3238 (void) GNUNET_CONTAINER_multipeermap_put (plugin->sessionmap,
3241 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
3242 /* Notify transport and ATS about new session */
3243 plugin->env->session_start (plugin->env->cls,
3250 LOG(GNUNET_ERROR_TYPE_DEBUG,
3251 "Did not obtain TCP socket address for incoming connection\n");
3253 GNUNET_SERVER_receive_done (client,
3259 if (GNUNET_YES != session->expecting_welcome)
3261 GNUNET_break_op (0);
3262 GNUNET_SERVER_receive_done (client,
3266 session->last_activity = GNUNET_TIME_absolute_get ();
3267 session->expecting_welcome = GNUNET_NO;
3269 process_pending_messages (session);
3270 GNUNET_SERVER_client_set_timeout (client,
3271 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
3272 GNUNET_SERVER_receive_done (client,
3278 * We've received data for this peer via TCP. Unbox,
3279 * compute latency and forward.
3281 * @param cls closure
3282 * @param client identification of the client
3283 * @param message the actual message
3286 handle_tcp_data (void *cls,
3287 struct GNUNET_SERVER_Client *client,
3288 const struct GNUNET_MessageHeader *message)
3290 struct Plugin *plugin = cls;
3291 struct GNUNET_ATS_Session *session;
3292 struct GNUNET_TIME_Relative delay;
3295 type = ntohs (message->type);
3296 if ( (GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_WELCOME == type) ||
3297 (GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_NAT_PROBE == type) )
3299 /* We don't want to propagate WELCOME and NAT Probe messages up! */
3300 GNUNET_SERVER_receive_done (client,
3304 session = lookup_session_by_client (plugin, client);
3305 if (NULL == session)
3307 /* No inbound session found */
3311 GNUNET_SERVER_client_get_address (client,
3314 LOG (GNUNET_ERROR_TYPE_ERROR,
3315 "Received unexpected %u bytes of type %u from `%s'\n",
3316 (unsigned int) ntohs (message->size),
3317 (unsigned int) ntohs (message->type),
3321 GNUNET_SERVER_receive_done (client,
3323 GNUNET_free_non_null (vaddr);
3326 if (GNUNET_YES == session->expecting_welcome)
3328 /* Session is expecting WELCOME message */
3332 GNUNET_SERVER_client_get_address (client,
3335 LOG (GNUNET_ERROR_TYPE_ERROR,
3336 "Received unexpected %u bytes of type %u from `%s'\n",
3337 (unsigned int) ntohs (message->size),
3338 (unsigned int) ntohs (message->type),
3339 GNUNET_a2s (vaddr, alen));
3341 GNUNET_SERVER_receive_done (client,
3343 GNUNET_free_non_null (vaddr);
3347 session->last_activity = GNUNET_TIME_absolute_get ();
3352 GNUNET_SERVER_client_get_address (client,
3355 LOG (GNUNET_ERROR_TYPE_DEBUG,
3356 "Passing %u bytes of type %u from `%s' at %s to transport service.\n",
3357 (unsigned int) ntohs (message->size),
3358 (unsigned int) ntohs (message->type),
3359 GNUNET_i2s (&session->target),
3360 GNUNET_a2s (vaddr, alen));
3361 GNUNET_free_non_null (vaddr);
3364 GNUNET_STATISTICS_update (plugin->env->stats,
3365 gettext_noop ("# bytes received via TCP"),
3366 ntohs (message->size),
3369 GNUNET_assert (GNUNET_CONTAINER_multipeermap_contains_value (plugin->sessionmap,
3372 delay = plugin->env->receive (plugin->env->cls,
3376 reschedule_session_timeout (session);
3377 if (0 == delay.rel_value_us)
3379 GNUNET_SERVER_receive_done (client,
3384 LOG (GNUNET_ERROR_TYPE_DEBUG,
3385 "Throttling receiving from `%s' for %s\n",
3386 GNUNET_i2s (&session->target),
3387 GNUNET_STRINGS_relative_time_to_string (delay,
3389 GNUNET_SERVER_disable_receive_done_warning (client);
3390 GNUNET_assert (NULL == session->receive_delay_task);
3391 session->receive_delay_task = GNUNET_SCHEDULER_add_delayed (delay,
3399 * Function called whenever a peer is connected on the "SERVER" level.
3400 * Increments number of active connections and suspends server if we
3401 * have reached the limit.
3403 * @param cls closure
3404 * @param client identification of the client
3407 connect_notify (void *cls,
3408 struct GNUNET_SERVER_Client *client)
3410 struct Plugin *plugin = cls;
3414 plugin->cur_connections++;
3415 GNUNET_STATISTICS_set (plugin->env->stats,
3416 gettext_noop ("# TCP server connections active"),
3417 plugin->cur_connections,
3419 GNUNET_STATISTICS_update (plugin->env->stats,
3420 gettext_noop ("# TCP server connect events"),
3423 if (plugin->cur_connections != plugin->max_connections)
3425 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3426 _("TCP connection limit reached, suspending server\n"));
3427 GNUNET_STATISTICS_update (plugin->env->stats,
3428 gettext_noop ("# TCP service suspended"),
3431 GNUNET_SERVER_suspend (plugin->server); /* Maximum number of connections rechead */
3436 * Function called whenever a peer is disconnected on the "SERVER"
3437 * level. Cleans up the connection, decrements number of active
3438 * connections and if applicable resumes listening.
3440 * @param cls closure
3441 * @param client identification of the client
3444 disconnect_notify (void *cls,
3445 struct GNUNET_SERVER_Client *client)
3447 struct Plugin *plugin = cls;
3448 struct GNUNET_ATS_Session *session;
3452 GNUNET_assert (plugin->cur_connections >= 1);
3453 plugin->cur_connections--;
3454 session = lookup_session_by_client (plugin,
3456 if (NULL == session)
3457 return; /* unknown, nothing to do */
3458 LOG (GNUNET_ERROR_TYPE_DEBUG,
3459 "Destroying session of `%s' with %s due to network-level disconnect.\n",
3460 GNUNET_i2s (&session->target),
3461 tcp_plugin_address_to_string (session->plugin,
3462 session->address->address,
3463 session->address->address_length));
3465 if (plugin->cur_connections == plugin->max_connections)
3467 GNUNET_STATISTICS_update (session->plugin->env->stats,
3468 gettext_noop ("# TCP service resumed"),
3471 GNUNET_SERVER_resume (plugin->server); /* Resume server */
3473 GNUNET_STATISTICS_set (plugin->env->stats,
3474 gettext_noop ("# TCP server connections active"),
3475 plugin->cur_connections,
3477 GNUNET_STATISTICS_update (session->plugin->env->stats,
3478 gettext_noop ("# network-level TCP disconnect events"),
3481 tcp_plugin_disconnect_session (plugin,
3487 * We can now send a probe message, copy into buffer to really send.
3489 * @param cls closure, a `struct TCPProbeContext`
3490 * @param size max size to copy
3491 * @param buf buffer to copy message to
3492 * @return number of bytes copied into @a buf
3495 notify_send_probe (void *cls,
3499 struct TCPProbeContext *tcp_probe_ctx = cls;
3500 struct Plugin *plugin = tcp_probe_ctx->plugin;
3503 tcp_probe_ctx->transmit_handle = NULL;
3504 GNUNET_CONTAINER_DLL_remove (plugin->probe_head,
3509 GNUNET_CONNECTION_destroy (tcp_probe_ctx->sock);
3510 GNUNET_free(tcp_probe_ctx);
3513 GNUNET_assert(size >= sizeof(tcp_probe_ctx->message));
3515 &tcp_probe_ctx->message,
3516 sizeof(tcp_probe_ctx->message));
3517 GNUNET_SERVER_connect_socket (tcp_probe_ctx->plugin->server,
3518 tcp_probe_ctx->sock);
3519 ret = sizeof(tcp_probe_ctx->message);
3520 GNUNET_free (tcp_probe_ctx);
3526 * Function called by the NAT subsystem suggesting another peer wants
3527 * to connect to us via connection reversal. Try to connect back to the
3530 * @param cls closure
3531 * @param addr address to try
3532 * @param addrlen number of bytes in @a addr
3535 try_connection_reversal (void *cls,
3536 const struct sockaddr *addr,
3539 struct Plugin *plugin = cls;
3540 struct GNUNET_CONNECTION_Handle *sock;
3541 struct TCPProbeContext *tcp_probe_ctx;
3544 * We have received an ICMP response, ostensibly from a peer
3545 * that wants to connect to us! Send a message to establish a connection.
3547 sock = GNUNET_CONNECTION_create_from_sockaddr (AF_INET,
3552 /* failed for some odd reason (out of sockets?); ignore attempt */
3556 tcp_probe_ctx = GNUNET_new (struct TCPProbeContext);
3557 tcp_probe_ctx->message.header.size
3558 = htons (sizeof (struct TCP_NAT_ProbeMessage));
3559 tcp_probe_ctx->message.header.type
3560 = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_NAT_PROBE);
3561 tcp_probe_ctx->message.clientIdentity
3562 = *plugin->env->my_identity;
3563 tcp_probe_ctx->plugin = plugin;
3564 tcp_probe_ctx->sock = sock;
3565 GNUNET_CONTAINER_DLL_insert (plugin->probe_head,
3568 tcp_probe_ctx->transmit_handle
3569 = GNUNET_CONNECTION_notify_transmit_ready (sock,
3570 ntohs (tcp_probe_ctx->message.header.size),
3571 GNUNET_TIME_UNIT_FOREVER_REL,
3578 * Function obtain the network type for a session
3580 * @param cls closure (`struct Plugin *`)
3581 * @param session the session
3582 * @return the network type in HBO or #GNUNET_SYSERR
3584 static enum GNUNET_ATS_Network_Type
3585 tcp_plugin_get_network (void *cls,
3586 struct GNUNET_ATS_Session *session)
3588 return session->scope;
3593 * Function obtain the network type for an address.
3595 * @param cls closure (`struct Plugin *`)
3596 * @param address the address
3597 * @return the network type
3599 static enum GNUNET_ATS_Network_Type
3600 tcp_plugin_get_network_for_address (void *cls,
3601 const struct GNUNET_HELLO_Address *address)
3603 struct Plugin *plugin = cls;
3605 struct sockaddr_in a4;
3606 struct sockaddr_in6 a6;
3607 const struct IPv4TcpAddress *t4;
3608 const struct IPv6TcpAddress *t6;
3612 addrlen = address->address_length;
3613 if (addrlen == sizeof(struct IPv6TcpAddress))
3615 GNUNET_assert (NULL != address->address); /* make static analysis happy */
3616 t6 = address->address;
3617 memset (&a6, 0, sizeof(a6));
3618 #if HAVE_SOCKADDR_IN_SIN_LEN
3619 a6.sin6_len = sizeof (a6);
3621 a6.sin6_family = AF_INET6;
3622 a6.sin6_port = t6->t6_port;
3623 GNUNET_memcpy (&a6.sin6_addr, &t6->ipv6_addr, sizeof(struct in6_addr));
3627 else if (addrlen == sizeof(struct IPv4TcpAddress))
3629 GNUNET_assert (NULL != address->address); /* make static analysis happy */
3630 t4 = address->address;
3631 memset (&a4, 0, sizeof(a4));
3632 #if HAVE_SOCKADDR_IN_SIN_LEN
3633 a4.sin_len = sizeof (a4);
3635 a4.sin_family = AF_INET;
3636 a4.sin_port = t4->t4_port;
3637 a4.sin_addr.s_addr = t4->ipv4_addr;
3644 return GNUNET_ATS_NET_UNSPECIFIED;
3646 return plugin->env->get_address_type (plugin->env->cls,
3653 * Return information about the given session to the
3656 * @param cls the `struct Plugin` with the monitor callback (`sic`)
3657 * @param peer peer we send information about
3658 * @param value our `struct GNUNET_ATS_Session` to send information about
3659 * @return #GNUNET_OK (continue to iterate)
3662 send_session_info_iter (void *cls,
3663 const struct GNUNET_PeerIdentity *peer,
3666 struct Plugin *plugin = cls;
3667 struct GNUNET_ATS_Session *session = value;
3669 notify_session_monitor (plugin,
3671 GNUNET_TRANSPORT_SS_INIT);
3672 /* FIXME: cannot tell if this is up or not from current
3674 notify_session_monitor (plugin,
3676 GNUNET_TRANSPORT_SS_UP);
3682 * Begin monitoring sessions of a plugin. There can only
3683 * be one active monitor per plugin (i.e. if there are
3684 * multiple monitors, the transport service needs to
3685 * multiplex the generated events over all of them).
3687 * @param cls closure of the plugin
3688 * @param sic callback to invoke, NULL to disable monitor;
3689 * plugin will being by iterating over all active
3690 * sessions immediately and then enter monitor mode
3691 * @param sic_cls closure for @a sic
3694 tcp_plugin_setup_monitor (void *cls,
3695 GNUNET_TRANSPORT_SessionInfoCallback sic,
3698 struct Plugin *plugin = cls;
3701 plugin->sic_cls = sic_cls;
3704 GNUNET_CONTAINER_multipeermap_iterate (plugin->sessionmap,
3705 &send_session_info_iter,
3707 /* signal end of first iteration */
3708 sic (sic_cls, NULL, NULL);
3714 * Entry point for the plugin.
3716 * @param cls closure, the `struct GNUNET_TRANSPORT_PluginEnvironment *`
3717 * @return the `struct GNUNET_TRANSPORT_PluginFunctions *` or NULL on error
3720 libgnunet_plugin_transport_tcp_init (void *cls)
3722 static const struct GNUNET_SERVER_MessageHandler my_handlers[] = {
3723 { &handle_tcp_welcome, NULL,
3724 GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_WELCOME,
3725 sizeof(struct WelcomeMessage) },
3726 { &handle_tcp_nat_probe, NULL,
3727 GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_NAT_PROBE,
3728 sizeof(struct TCP_NAT_ProbeMessage) },
3729 { &handle_tcp_data, NULL,
3730 GNUNET_MESSAGE_TYPE_ALL, 0 },
3731 { NULL, NULL, 0, 0 }
3733 struct GNUNET_TRANSPORT_PluginEnvironment *env = cls;
3734 struct GNUNET_TRANSPORT_PluginFunctions *api;
3735 struct Plugin *plugin;
3736 struct GNUNET_SERVICE_Context *service;
3737 unsigned long long aport;
3738 unsigned long long bport;
3739 unsigned long long max_connections;
3741 struct GNUNET_TIME_Relative idle_timeout;
3743 struct GNUNET_NETWORK_Handle *const*lsocks;
3747 struct sockaddr **addrs;
3748 socklen_t *addrlens;
3750 if (NULL == env->receive)
3752 /* run in 'stub' mode (i.e. as part of gnunet-peerinfo), don't fully
3753 initialze the plugin or the API */
3754 api = GNUNET_new (struct GNUNET_TRANSPORT_PluginFunctions);
3756 api->address_pretty_printer = &tcp_plugin_address_pretty_printer;
3757 api->address_to_string = &tcp_plugin_address_to_string;
3758 api->string_to_address = &tcp_plugin_string_to_address;
3762 GNUNET_assert (NULL != env->cfg);
3764 GNUNET_CONFIGURATION_get_value_number (env->cfg,
3768 max_connections = 128;
3772 GNUNET_CONFIGURATION_get_value_number (env->cfg, "transport-tcp",
3776 GNUNET_CONFIGURATION_get_value_number (env->cfg, "transport-tcp",
3777 "ADVERTISED-PORT", &aport)) &&
3780 LOG(GNUNET_ERROR_TYPE_ERROR,
3781 _("Require valid port number for service `%s' in configuration!\n"),
3791 service = GNUNET_SERVICE_start ("transport-tcp",
3793 GNUNET_SERVICE_OPTION_NONE);
3794 if (NULL == service)
3796 LOG (GNUNET_ERROR_TYPE_WARNING,
3797 _("Failed to start service.\n"));
3805 plugin = GNUNET_new (struct Plugin);
3806 plugin->sessionmap = GNUNET_CONTAINER_multipeermap_create (max_connections,
3808 plugin->max_connections = max_connections;
3809 plugin->open_port = bport;
3810 plugin->adv_port = aport;
3812 plugin->my_welcome.header.size = htons (sizeof(struct WelcomeMessage));
3813 plugin->my_welcome.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_WELCOME);
3814 plugin->my_welcome.clientIdentity = *plugin->env->my_identity;
3816 if ( (NULL != service) &&
3818 GNUNET_CONFIGURATION_get_value_yesno (env->cfg,
3823 plugin->myoptions |= TCP_OPTIONS_TCP_STEALTH;
3824 lsocks = GNUNET_SERVICE_get_listen_sockets (service);
3827 uint32_t len = sizeof (struct WelcomeMessage);
3829 for (i=0;NULL!=lsocks[i];i++)
3832 GNUNET_NETWORK_socket_setsockopt (lsocks[i],
3836 sizeof (struct GNUNET_PeerIdentity))) ||
3838 GNUNET_NETWORK_socket_setsockopt (lsocks[i],
3840 TCP_STEALTH_INTEGRITY_LEN,
3844 /* TCP STEALTH not supported by kernel */
3845 GNUNET_assert (0 == i);
3846 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3847 _("TCP_STEALTH not supported on this platform.\n"));
3853 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3854 _("TCP_STEALTH not supported on this platform.\n"));
3859 if ( (NULL != service) &&
3862 get_server_addresses ("transport-tcp",
3867 for (ret = ret_s-1; ret >= 0; ret--)
3868 LOG (GNUNET_ERROR_TYPE_INFO,
3869 "Binding to address `%s'\n",
3870 GNUNET_a2s (addrs[ret], addrlens[ret]));
3872 = GNUNET_NAT_register (env->cfg,
3875 (unsigned int) ret_s,
3876 (const struct sockaddr **) addrs,
3878 &tcp_nat_port_map_callback,
3879 &try_connection_reversal,
3881 for (ret = ret_s -1; ret >= 0; ret--)
3882 GNUNET_free (addrs[ret]);
3883 GNUNET_free_non_null (addrs);
3884 GNUNET_free_non_null (addrlens);
3888 plugin->nat = GNUNET_NAT_register (plugin->env->cfg,
3895 &try_connection_reversal,
3898 api = GNUNET_new (struct GNUNET_TRANSPORT_PluginFunctions);
3900 api->send = &tcp_plugin_send;
3901 api->get_session = &tcp_plugin_get_session;
3902 api->disconnect_session = &tcp_plugin_disconnect_session;
3903 api->query_keepalive_factor = &tcp_plugin_query_keepalive_factor;
3904 api->disconnect_peer = &tcp_plugin_disconnect;
3905 api->address_pretty_printer = &tcp_plugin_address_pretty_printer;
3906 api->check_address = &tcp_plugin_check_address;
3907 api->address_to_string = &tcp_plugin_address_to_string;
3908 api->string_to_address = &tcp_plugin_string_to_address;
3909 api->get_network = &tcp_plugin_get_network;
3910 api->get_network_for_address = &tcp_plugin_get_network_for_address;
3911 api->update_session_timeout = &tcp_plugin_update_session_timeout;
3912 api->update_inbound_delay = &tcp_plugin_update_inbound_delay;
3913 api->setup_monitor = &tcp_plugin_setup_monitor;
3914 plugin->service = service;
3915 if (NULL != service)
3917 plugin->server = GNUNET_SERVICE_get_server (service);
3922 GNUNET_CONFIGURATION_get_value_time (env->cfg,
3927 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
3933 = GNUNET_SERVER_create_with_sockets (NULL,
3939 plugin->handlers = GNUNET_malloc (sizeof (my_handlers));
3940 GNUNET_memcpy (plugin->handlers,
3942 sizeof(my_handlers));
3943 for (i = 0;i < sizeof(my_handlers) / sizeof(struct GNUNET_SERVER_MessageHandler);i++)
3944 plugin->handlers[i].callback_cls = plugin;
3946 GNUNET_SERVER_add_handlers (plugin->server,
3948 GNUNET_SERVER_connect_notify (plugin->server,
3951 GNUNET_SERVER_disconnect_notify (plugin->server,
3954 plugin->nat_wait_conns = GNUNET_CONTAINER_multipeermap_create (16,
3957 LOG (GNUNET_ERROR_TYPE_INFO,
3958 _("TCP transport listening on port %llu\n"),
3961 LOG (GNUNET_ERROR_TYPE_INFO,
3962 _("TCP transport not listening on any port (client only)\n"));
3963 if ( (aport != bport) &&
3965 LOG (GNUNET_ERROR_TYPE_INFO,
3966 _("TCP transport advertises itself as being on port %llu\n"),
3968 /* Initially set connections to 0 */
3969 GNUNET_STATISTICS_set (plugin->env->stats,
3970 gettext_noop ("# TCP sessions active"),
3976 if (NULL != plugin->nat)
3977 GNUNET_NAT_unregister (plugin->nat);
3978 GNUNET_CONTAINER_multipeermap_destroy (plugin->sessionmap);
3979 if (NULL != service)
3980 GNUNET_SERVICE_stop (service);
3981 GNUNET_free (plugin);
3982 GNUNET_free_non_null (api);
3988 * Exit point from the plugin.
3990 * @param cls the `struct GNUNET_TRANSPORT_PluginFunctions`
3994 libgnunet_plugin_transport_tcp_done (void *cls)
3996 struct GNUNET_TRANSPORT_PluginFunctions *api = cls;
3997 struct Plugin *plugin = api->cls;
3998 struct TCPProbeContext *tcp_probe;
3999 struct PrettyPrinterContext *cur;
4000 struct PrettyPrinterContext *next;
4007 LOG (GNUNET_ERROR_TYPE_DEBUG,
4008 "Shutting down TCP plugin\n");
4010 /* Removing leftover sessions */
4011 GNUNET_CONTAINER_multipeermap_iterate (plugin->sessionmap,
4012 &session_disconnect_it,
4014 /* Removing leftover NAT sessions */
4015 GNUNET_CONTAINER_multipeermap_iterate (plugin->nat_wait_conns,
4016 &session_disconnect_it,
4019 for (cur = plugin->ppc_dll_head; NULL != cur; cur = next)
4022 GNUNET_CONTAINER_DLL_remove (plugin->ppc_dll_head,
4023 plugin->ppc_dll_tail,
4025 GNUNET_RESOLVER_request_cancel (cur->resolver_handle);
4026 cur->asc (cur->asc_cls,
4032 if (NULL != plugin->service)
4033 GNUNET_SERVICE_stop (plugin->service);
4035 GNUNET_SERVER_destroy (plugin->server);
4036 GNUNET_free (plugin->handlers);
4037 if (NULL != plugin->nat)
4038 GNUNET_NAT_unregister (plugin->nat);
4039 while (NULL != (tcp_probe = plugin->probe_head))
4041 GNUNET_CONTAINER_DLL_remove (plugin->probe_head,
4044 GNUNET_CONNECTION_destroy (tcp_probe->sock);
4045 GNUNET_free (tcp_probe);
4047 GNUNET_CONTAINER_multipeermap_destroy (plugin->nat_wait_conns);
4048 GNUNET_CONTAINER_multipeermap_destroy (plugin->sessionmap);
4049 GNUNET_break (0 == plugin->cur_connections);
4050 GNUNET_free (plugin);
4055 /* end of plugin_transport_tcp.c */