From: Christian Grothoff Date: Wed, 3 Apr 2019 12:41:20 +0000 (+0200) Subject: remove xt/xu plugins, no longer needed for anything X-Git-Tag: v0.11.1~4 X-Git-Url: https://git.librecmc.org/?a=commitdiff_plain;h=9859b3162a9fd7c9cc0c19582b04dd7f1c1f9408;p=oweals%2Fgnunet.git remove xt/xu plugins, no longer needed for anything --- diff --git a/src/transport/Makefile.am b/src/transport/Makefile.am index 9cf16ddb6..cd31f7cd7 100644 --- a/src/transport/Makefile.am +++ b/src/transport/Makefile.am @@ -378,12 +378,6 @@ plugin_LTLIBRARIES = \ $(WLAN_PLUGIN_LA) \ $(BT_PLUGIN_LA) -if HAVE_EXPERIMENTAL -plugin_LTLIBRARIES += \ - libgnunet_plugin_transport_xt.la \ - libgnunet_plugin_transport_xu.la -endif - # Note: real plugins of course need to be added # to the plugin_LTLIBRARIES above noinst_LTLIBRARIES = \ @@ -401,18 +395,6 @@ libgnunet_plugin_transport_tcp_la_LIBADD = \ libgnunet_plugin_transport_tcp_la_LDFLAGS = \ $(GN_PLUGIN_LDFLAGS) -libgnunet_plugin_transport_xt_la_SOURCES = \ - plugin_transport_xt.c -libgnunet_plugin_transport_xt_la_LIBADD = \ - $(top_builddir)/src/hello/libgnunethello.la \ - $(top_builddir)/src/statistics/libgnunetstatistics.la \ - $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \ - $(top_builddir)/src/nat/libgnunetnatnew.la \ - $(top_builddir)/src/util/libgnunetutil.la \ - $(LTLIBINTL) -libgnunet_plugin_transport_xt_la_LDFLAGS = \ - $(GN_PLUGIN_LDFLAGS) - libgnunet_plugin_transport_template_la_SOURCES = \ plugin_transport_template.c libgnunet_plugin_transport_template_la_LIBADD = \ @@ -461,19 +443,6 @@ libgnunet_plugin_transport_udp_la_LIBADD = \ libgnunet_plugin_transport_udp_la_LDFLAGS = \ $(GN_PLUGIN_LDFLAGS) -libgnunet_plugin_transport_xu_la_SOURCES = \ - plugin_transport_xu.c plugin_transport_xu.h -libgnunet_plugin_transport_xu_la_LIBADD = \ - $(top_builddir)/src/hello/libgnunethello.la \ - $(top_builddir)/src/fragmentation/libgnunetfragmentation.la \ - $(top_builddir)/src/statistics/libgnunetstatistics.la \ - $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \ - $(top_builddir)/src/nat/libgnunetnatnew.la \ - $(top_builddir)/src/util/libgnunetutil.la \ - $(LTLIBINTL) -libgnunet_plugin_transport_xu_la_LDFLAGS = \ - $(GN_PLUGIN_LDFLAGS) - libgnunet_plugin_transport_unix_la_SOURCES = \ plugin_transport_unix.c libgnunet_plugin_transport_unix_la_LIBADD = \ diff --git a/src/transport/plugin_transport_xt.c b/src/transport/plugin_transport_xt.c deleted file mode 100644 index df5e8a127..000000000 --- a/src/transport/plugin_transport_xt.c +++ /dev/null @@ -1,4107 +0,0 @@ -/* - This file is part of GNUnet - Copyright (C) 2002--2015 GNUnet e.V. - - GNUnet is free software: you can redistribute it and/or modify it - under the terms of the GNU Affero General Public License as published - by the Free Software Foundation, either version 3 of the License, - or (at your option) any later version. - - GNUnet is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see . - - SPDX-License-Identifier: AGPL3.0-or-later - */ -/** - * @file transport/plugin_transport_xt.c - * @brief Implementation of the TCP transport service - * @author Christian Grothoff - */ -#include "platform.h" -#include "gnunet_hello_lib.h" -#include "gnunet_constants.h" -#include "gnunet_util_lib.h" -#include "gnunet_nat_service.h" -#include "gnunet_protocols.h" -#include "gnunet_resolver_service.h" -#include "gnunet_signatures.h" -#include "gnunet_statistics_service.h" -#include "gnunet_transport_service.h" -#include "gnunet_transport_plugin.h" -#include "transport.h" - -#define LOG(kind,...) GNUNET_log_from (kind, "transport-xt",__VA_ARGS__) - -#define PLUGIN_NAME "xt" - -/** - * How long until we give up on establishing an NAT connection? - * Must be > 4 RTT - */ -#define NAT_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10) - -/** - * Opaque handle that can be used to cancel - * a transmit-ready notification. - */ -struct GNUNET_CONNECTION_TransmitHandle; - -/** - * @brief handle for a server - */ -struct GNUNET_SERVER_Handle; - -/** - * @brief opaque handle for a client of the server - */ -struct GNUNET_SERVER_Client; - -/** - * @brief opaque handle server returns for aborting transmission to a client. - */ -struct GNUNET_SERVER_TransmitHandle; - -/** - * @brief handle for a network connection - */ -struct GNUNET_CONNECTION_Handle; - -/** - * @brief handle for a network service - */ -struct LEGACY_SERVICE_Context; - - -/** - * Stops a service that was started with #GNUNET_SERVICE_start(). - * - * @param srv service to stop - */ -void -LEGACY_SERVICE_stop (struct LEGACY_SERVICE_Context *srv); - - - -/** - * Function called to notify a client about the connection begin ready - * to queue more data. @a buf will be NULL and @a size zero if the - * connection was closed for writing in the meantime. - * - * @param cls closure - * @param size number of bytes available in @a buf - * @param buf where the callee should write the message - * @return number of bytes written to @a buf - */ -typedef size_t -(*GNUNET_CONNECTION_TransmitReadyNotify) (void *cls, - size_t size, - void *buf); - -/** - * Credentials for UNIX domain sockets. - */ -struct GNUNET_CONNECTION_Credentials -{ - /** - * UID of the other end of the connection. - */ - uid_t uid; - - /** - * GID of the other end of the connection. - */ - gid_t gid; -}; - - -/** - * Functions with this signature are called whenever a client - * is disconnected on the network level. - * - * @param cls closure - * @param client identification of the client; NULL - * for the last call when the server is destroyed - */ -typedef void -(*GNUNET_SERVER_DisconnectCallback) (void *cls, - struct GNUNET_SERVER_Client *client); - - -/** - * Functions with this signature are called whenever a client - * is connected on the network level. - * - * @param cls closure - * @param client identification of the client - */ -typedef void -(*GNUNET_SERVER_ConnectCallback) (void *cls, - struct GNUNET_SERVER_Client *client); - - - - -/** - * Function to call for access control checks. - * - * @param cls closure - * @param ucred credentials, if available, otherwise NULL - * @param addr address - * @param addrlen length of address - * @return GNUNET_YES to allow, GNUNET_NO to deny, GNUNET_SYSERR - * for unknown address family (will be denied). - */ -typedef int -(*GNUNET_CONNECTION_AccessCheck) (void *cls, - const struct - GNUNET_CONNECTION_Credentials * - ucred, - const struct sockaddr * addr, - socklen_t addrlen); - -/** - * Callback function for data received from the network. Note that - * both "available" and "err" would be 0 if the read simply timed out. - * - * @param cls closure - * @param buf pointer to received data - * @param available number of bytes availabe in "buf", - * possibly 0 (on errors) - * @param addr address of the sender - * @param addrlen size of addr - * @param errCode value of errno (on errors receiving) - */ -typedef void -(*GNUNET_CONNECTION_Receiver) (void *cls, const void *buf, - size_t available, - const struct sockaddr * addr, - socklen_t addrlen, int errCode); - - - -/** - * Close the connection and free associated resources. There must - * not be any pending requests for reading or writing to the - * connection at this time. - * - * @param connection connection to destroy - */ -void -GNUNET_CONNECTION_destroy (struct GNUNET_CONNECTION_Handle *connection); - - -/** - * Signature of a function to create a custom tokenizer. - * - * @param cls closure from #GNUNET_SERVER_set_callbacks - * @param client handle to client the tokenzier will be used for - * @return handle to custom tokenizer ('mst') - */ -typedef void* -(*GNUNET_SERVER_MstCreateCallback) (void *cls, - struct GNUNET_SERVER_Client *client); - - -/** - * Signature of a function to destroy a custom tokenizer. - * - * @param cls closure from #GNUNET_SERVER_set_callbacks - * @param mst custom tokenizer handle - */ -typedef void -(*GNUNET_SERVER_MstDestroyCallback) (void *cls, - void *mst); - -/** - * Signature of a function to receive data for a custom tokenizer. - * - * @param cls closure from #GNUNET_SERVER_set_callbacks - * @param mst custom tokenizer handle - * @param client_identity ID of client for which this is a buffer, - * can be NULL (will be passed back to 'cb') - * @param buf input data to add - * @param size number of bytes in @a buf - * @param purge should any excess bytes in the buffer be discarded - * (i.e. for packet-based services like UDP) - * @param one_shot only call callback once, keep rest of message in buffer - * @return #GNUNET_OK if we are done processing (need more data) - * #GNUNET_NO if one_shot was set and we have another message ready - * #GNUNET_SYSERR if the data stream is corrupt - */ -typedef int -(*GNUNET_SERVER_MstReceiveCallback) (void *cls, void *mst, - struct GNUNET_SERVER_Client *client, - const char *buf, - size_t size, - int purge, - int one_shot); -/** - * Functions with this signature are called whenever a message is - * received. - * - * @param cls closure - * @param client identification of the client - * @param message the actual message - */ -typedef void -(*GNUNET_SERVER_MessageCallback) (void *cls, - struct GNUNET_SERVER_Client *client, - const struct GNUNET_MessageHeader *message); - -/** - * Message handler. Each struct specifies how to handle on particular - * type of message received. - */ -struct GNUNET_SERVER_MessageHandler -{ - /** - * Function to call for messages of "type". - */ - GNUNET_SERVER_MessageCallback callback; - - /** - * Closure argument for @e callback. - */ - void *callback_cls; - - /** - * Type of the message this handler covers. - */ - uint16_t type; - - /** - * Expected size of messages of this type. Use 0 for - * variable-size. If non-zero, messages of the given - * type will be discarded (and the connection closed) - * if they do not have the right size. - */ - uint16_t expected_size; - -}; - - -/** - * Options for the service (bitmask). - */ -enum LEGACY_SERVICE_Options -{ - /** - * Use defaults. Terminates all client connections and the listen - * sockets immediately upon receiving the shutdown signal. - */ - LEGACY_SERVICE_OPTION_NONE = 0, - - /** - * Do not trigger server shutdown on signal at all; instead, allow - * for the user to terminate the server explicitly when needed - * by calling #LEGACY_SERVICE_shutdown(). - */ - LEGACY_SERVICE_OPTION_MANUAL_SHUTDOWN = 1, - - /** - * Trigger a SOFT server shutdown on signals, allowing active - * non-monitor clients to complete their transactions. - */ - LEGACY_SERVICE_OPTION_SOFT_SHUTDOWN = 2 -}; - - - -/** - * Ask the server to disconnect from the given client. This is the - * same as passing #GNUNET_SYSERR to #GNUNET_SERVER_receive_done, - * except that it allows dropping of a client even when not handling a - * message from that client. - * - * @param client the client to disconnect from - */ -void -GNUNET_SERVER_client_disconnect (struct GNUNET_SERVER_Client *client); - -/** - * Return user context associated with the given client. - * Note: you should probably use the macro (call without the underscore). - * - * @param client client to query - * @param size number of bytes in user context struct (for verification only) - * @return pointer to user context - */ -void * -GNUNET_SERVER_client_get_user_context_ (struct GNUNET_SERVER_Client *client, - size_t size); - - -/** - * Functions with this signature are called whenever a - * complete message is received by the tokenizer. - * - * Do not call #GNUNET_SERVER_mst_destroy from within - * the scope of this callback. - * - * @param cls closure - * @param client identification of the client - * @param message the actual message - * @return #GNUNET_OK on success, #GNUNET_SYSERR to stop further processing - */ -typedef int -(*GNUNET_SERVER_MessageTokenizerCallback) (void *cls, - void *client, - const struct GNUNET_MessageHeader *message); - - -/** - * Create a message stream tokenizer. - * - * @param cb function to call on completed messages - * @param cb_cls closure for @a cb - * @return handle to tokenizer - */ -struct GNUNET_SERVER_MessageStreamTokenizer * -GNUNET_SERVER_mst_create (GNUNET_SERVER_MessageTokenizerCallback cb, - void *cb_cls); - -/** - * Add incoming data to the receive buffer and call the - * callback for all complete messages. - * - * @param mst tokenizer to use - * @param client_identity ID of client for which this is a buffer, - * can be NULL (will be passed back to 'cb') - * @param buf input data to add - * @param size number of bytes in @a buf - * @param purge should any excess bytes in the buffer be discarded - * (i.e. for packet-based services like UDP) - * @param one_shot only call callback once, keep rest of message in buffer - * @return #GNUNET_OK if we are done processing (need more data) - * #GNUNET_NO if one_shot was set and we have another message ready - * #GNUNET_SYSERR if the data stream is corrupt - */ -int -GNUNET_SERVER_mst_receive (struct GNUNET_SERVER_MessageStreamTokenizer *mst, - void *client_identity, - const char *buf, size_t size, - int purge, int one_shot); - - - -/** - * Destroys a tokenizer. - * - * @param mst tokenizer to destroy - */ -void -GNUNET_SERVER_mst_destroy (struct GNUNET_SERVER_MessageStreamTokenizer *mst); - - -/** - * Set user context to be associated with the given client. - * Note: you should probably use the macro (call without the underscore). - * - * @param client client to query - * @param ptr pointer to user context - * @param size number of bytes in user context struct (for verification only) - */ -void -GNUNET_SERVER_client_set_user_context_ (struct GNUNET_SERVER_Client *client, - void *ptr, - size_t size); -/** - * Return user context associated with the given client. - * - * @param client client to query - * @param type expected return type (i.e. 'struct Foo') - * @return pointer to user context of type 'type *'. - */ -#define GNUNET_SERVER_client_get_user_context(client,type) \ - (type *) GNUNET_SERVER_client_get_user_context_ (client, sizeof (type)) - -/** - * Set user context to be associated with the given client. - * - * @param client client to query - * @param value pointer to user context - */ -#define GNUNET_SERVER_client_set_user_context(client,value) \ - GNUNET_SERVER_client_set_user_context_ (client, value, sizeof (*value)) - - - -/** - * Notify us when the server has enough space to transmit - * a message of the given size to the given client. - * - * @param client client to transmit message to - * @param size requested amount of buffer space - * @param timeout after how long should we give up (and call - * notify with buf NULL and size 0)? - * @param callback function to call when space is available - * @param callback_cls closure for @a callback - * @return non-NULL if the notify callback was queued; can be used - * to cancel the request using - * #GNUNET_SERVER_notify_transmit_ready_cancel. - * NULL if we are already going to notify someone else (busy) - */ -struct GNUNET_SERVER_TransmitHandle * -GNUNET_SERVER_notify_transmit_ready (struct GNUNET_SERVER_Client *client, - size_t size, - struct GNUNET_TIME_Relative timeout, - GNUNET_CONNECTION_TransmitReadyNotify callback, - void *callback_cls); - -/** - * Abort transmission request. - * - * @param th request to abort - */ -void -GNUNET_SERVER_notify_transmit_ready_cancel (struct GNUNET_SERVER_TransmitHandle *th); - - - - -/** - * Notify the server that the given client handle should - * be kept (keeps the connection up if possible, increments - * the internal reference counter). - * - * @param client the client to keep - */ -void -GNUNET_SERVER_client_keep (struct GNUNET_SERVER_Client *client); - - -/** - * Notify the server that the given client handle is no - * longer required. Decrements the reference counter. If - * that counter reaches zero an inactive connection maybe - * closed. - * - * @param client the client to drop - */ -void -GNUNET_SERVER_client_drop (struct GNUNET_SERVER_Client *client); - - -/** - * Function called by the service's run - * method to run service-specific setup code. - * - * @param cls closure - * @param server the initialized server - * @param cfg configuration to use - */ -typedef void -(*LEGACY_SERVICE_Main) (void *cls, - struct GNUNET_SERVER_Handle *server, - const struct GNUNET_CONFIGURATION_Handle *cfg); - - - -/** - * Suspend accepting connections from the listen socket temporarily. - * Resume activity using #GNUNET_SERVER_resume. - * - * @param server server to stop accepting connections. - */ -void -GNUNET_SERVER_suspend (struct GNUNET_SERVER_Handle *server); - -/** - * Notify us when the server has enough space to transmit - * a message of the given size to the given client. - * - * @param client client to transmit message to - * @param size requested amount of buffer space - * @param timeout after how long should we give up (and call - * notify with buf NULL and size 0)? - * @param callback function to call when space is available - * @param callback_cls closure for @a callback - * @return non-NULL if the notify callback was queued; can be used - * to cancel the request using - * #GNUNET_SERVER_notify_transmit_ready_cancel. - * NULL if we are already going to notify someone else (busy) - */ -struct GNUNET_SERVER_TransmitHandle * -GNUNET_SERVER_notify_transmit_ready (struct GNUNET_SERVER_Client *client, - size_t size, - struct GNUNET_TIME_Relative timeout, - GNUNET_CONNECTION_TransmitReadyNotify callback, - void *callback_cls); - - -/** - * Add a TCP socket-based connection to the set of handles managed by - * this server. Use this function for outgoing (P2P) connections that - * we initiated (and where this server should process incoming - * messages). - * - * @param server the server to use - * @param connection the connection to manage (client must - * stop using this connection from now on) - * @return the client handle - */ -struct GNUNET_SERVER_Client * -GNUNET_SERVER_connect_socket (struct GNUNET_SERVER_Handle *server, - struct GNUNET_CONNECTION_Handle *connection); - - -/** - * Resume accepting connections from the listen socket. - * - * @param server server to resume accepting connections. - */ -void -GNUNET_SERVER_resume (struct GNUNET_SERVER_Handle *server); - -/** - * Free resources held by this server. - * - * @param server server to destroy - */ -void -GNUNET_SERVER_destroy (struct GNUNET_SERVER_Handle *server); - - - - -#include "tcp_connection_legacy.c" -#include "tcp_server_mst_legacy.c" -#include "tcp_server_legacy.c" -#include "tcp_service_legacy.c" - -GNUNET_NETWORK_STRUCT_BEGIN - -/** - * Initial handshake message for a session. - */ -struct WelcomeMessage -{ - /** - * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_WELCOME. - */ - struct GNUNET_MessageHeader header; - - /** - * Identity of the node connecting (TCP client) - */ - struct GNUNET_PeerIdentity clientIdentity; - -}; - -/** - * Basically a WELCOME message, but with the purpose - * of giving the waiting peer a client handle to use - */ -struct TCP_NAT_ProbeMessage -{ - /** - * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_NAT_PROBE. - */ - struct GNUNET_MessageHeader header; - - /** - * Identity of the sender of the message. - */ - struct GNUNET_PeerIdentity clientIdentity; - -}; -GNUNET_NETWORK_STRUCT_END - -/** - * Context for sending a NAT probe via TCP. - */ -struct TCPProbeContext -{ - - /** - * Active probes are kept in a DLL. - */ - struct TCPProbeContext *next; - - /** - * Active probes are kept in a DLL. - */ - struct TCPProbeContext *prev; - - /** - * Probe connection. - */ - struct GNUNET_CONNECTION_Handle *sock; - - /** - * Message to be sent. - */ - struct TCP_NAT_ProbeMessage message; - - /** - * Handle to the transmission. - */ - struct GNUNET_CONNECTION_TransmitHandle *transmit_handle; - - /** - * Transport plugin handle. - */ - struct Plugin *plugin; -}; - -/** - * Bits in the `options` field of TCP addresses. - */ -enum TcpAddressOptions -{ - - /** - * No bits set. - */ - TCP_OPTIONS_NONE = 0, - - /** - * See #HTTP_OPTIONS_VERIFY_CERTIFICATE. - */ - TCP_OPTIONS_RESERVED = 1, - - /** - * Enable TCP Stealth-style port knocking. - */ - TCP_OPTIONS_TCP_STEALTH = 2 -}; - -GNUNET_NETWORK_STRUCT_BEGIN - -/** - * Network format for IPv4 addresses. - */ -struct IPv4TcpAddress -{ - /** - * Optional options and flags for this address, - * see `enum TcpAddressOptions` - */ - uint32_t options GNUNET_PACKED; - - /** - * IPv4 address, in network byte order. - */ - uint32_t ipv4_addr GNUNET_PACKED; - - /** - * Port number, in network byte order. - */ - uint16_t t4_port GNUNET_PACKED; - -}; - -/** - * Network format for IPv6 addresses. - */ -struct IPv6TcpAddress -{ - /** - * Optional flags for this address - * see `enum TcpAddressOptions` - */ - uint32_t options GNUNET_PACKED; - - /** - * IPv6 address. - */ - struct in6_addr ipv6_addr GNUNET_PACKED; - - /** - * Port number, in network byte order. - */ - uint16_t t6_port GNUNET_PACKED; - -}; -GNUNET_NETWORK_STRUCT_END - -/** - * Encapsulation of all of the state of the plugin. - */ -struct Plugin; - -/** - * Information kept for each message that is yet to - * be transmitted. - */ -struct PendingMessage -{ - - /** - * This is a doubly-linked list. - */ - struct PendingMessage *next; - - /** - * This is a doubly-linked list. - */ - struct PendingMessage *prev; - - /** - * The pending message - */ - const char *msg; - - /** - * Continuation function to call once the message - * has been sent. Can be NULL if there is no - * continuation to call. - */ - GNUNET_TRANSPORT_TransmitContinuation transmit_cont; - - /** - * Closure for @e transmit_cont. - */ - void *transmit_cont_cls; - - /** - * Timeout value for the pending message. - */ - struct GNUNET_TIME_Absolute timeout; - - /** - * So that the gnunet-service-transport can group messages together, - * these pending messages need to accept a message buffer and size - * instead of just a `struct GNUNET_MessageHeader`. - */ - size_t message_size; - -}; - -/** - * Session handle for TCP connections. - */ -struct GNUNET_ATS_Session -{ - /** - * To whom are we talking to (set to our identity - * if we are still waiting for the welcome message) - */ - struct GNUNET_PeerIdentity target; - - /** - * Pointer to the global plugin struct. - */ - struct Plugin *plugin; - - /** - * The client (used to identify this connection) - */ - struct GNUNET_SERVER_Client *client; - - /** - * Task cleaning up a NAT client connection establishment attempt; - */ - struct GNUNET_SCHEDULER_Task *nat_connection_timeout; - - /** - * Messages currently pending for transmission - * to this peer, if any. - */ - struct PendingMessage *pending_messages_head; - - /** - * Messages currently pending for transmission - * to this peer, if any. - */ - struct PendingMessage *pending_messages_tail; - - /** - * Handle for pending transmission request. - */ - struct GNUNET_SERVER_TransmitHandle *transmit_handle; - - /** - * Address of the other peer. - */ - struct GNUNET_HELLO_Address *address; - - /** - * ID of task used to delay receiving more to throttle sender. - */ - struct GNUNET_SCHEDULER_Task *receive_delay_task; - - /** - * Session timeout task - */ - struct GNUNET_SCHEDULER_Task *timeout_task; - - /** - * When will this session time out? - */ - struct GNUNET_TIME_Absolute timeout; - - /** - * When will we continue to read from the socket? - * (used to enforce inbound quota). - */ - struct GNUNET_TIME_Absolute receive_delay; - - /** - * Last activity on this connection. Used to select preferred - * connection. - */ - struct GNUNET_TIME_Absolute last_activity; - - /** - * Number of bytes waiting for transmission to this peer. - */ - unsigned long long bytes_in_queue; - - /** - * Number of messages waiting for transmission to this peer. - */ - unsigned int msgs_in_queue; - - /** - * Network type of the address. - */ - enum GNUNET_NetworkType scope; - - /** - * Are we still expecting the welcome message? (#GNUNET_YES/#GNUNET_NO) - */ - int expecting_welcome; - - /** - * Was this session created using NAT traversal? - */ - int is_nat; - -}; - - -/** - * Context for address to string conversion, closure - * for #append_port(). - */ -struct PrettyPrinterContext -{ - /** - * DLL - */ - struct PrettyPrinterContext *next; - - /** - * DLL - */ - struct PrettyPrinterContext *prev; - - /** - * Our plugin. - */ - struct Plugin *plugin; - - /** - * Timeout task - */ - struct GNUNET_SCHEDULER_Task *timeout_task; - - /** - * Resolver handle - */ - struct GNUNET_RESOLVER_RequestHandle *resolver_handle; - - /** - * Function to call with the result. - */ - GNUNET_TRANSPORT_AddressStringCallback asc; - - /** - * Clsoure for @e asc. - */ - void *asc_cls; - - /** - * IPv6 address - */ - int ipv6; - - /** - * Options - */ - uint32_t options; - - /** - * Port to add after the IP address. - */ - uint16_t port; -}; - - -/** - * Encapsulation of all of the state of the plugin. - */ -struct Plugin -{ - /** - * Our environment. - */ - struct GNUNET_TRANSPORT_PluginEnvironment *env; - - /** - * The listen socket. - */ - struct GNUNET_CONNECTION_Handle *lsock; - - /** - * Our handle to the NAT module. - */ - struct GNUNET_NAT_Handle *nat; - - /** - * Map from peer identities to sessions for the given peer. - */ - struct GNUNET_CONTAINER_MultiPeerMap *sessionmap; - - /** - * Handle to the network service. - */ - struct LEGACY_SERVICE_Context *service; - - /** - * Handle to the server for this service. - */ - struct GNUNET_SERVER_Handle *server; - - /** - * Copy of the handler array where the closures are - * set to this struct's instance. - */ - struct GNUNET_SERVER_MessageHandler *handlers; - - /** - * Map of peers we have tried to contact behind a NAT - */ - struct GNUNET_CONTAINER_MultiPeerMap *nat_wait_conns; - - /** - * List of active TCP probes. - */ - struct TCPProbeContext *probe_head; - - /** - * List of active TCP probes. - */ - struct TCPProbeContext *probe_tail; - - /** - * Function to call about session status changes. - */ - GNUNET_TRANSPORT_SessionInfoCallback sic; - - /** - * Closure for @e sic. - */ - void *sic_cls; - - /** - * ID of task used to update our addresses when one expires. - */ - struct GNUNET_SCHEDULER_Task *address_update_task; - - /** - * Running pretty printers: head - */ - struct PrettyPrinterContext *ppc_dll_head; - - /** - * Running pretty printers: tail - */ - struct PrettyPrinterContext *ppc_dll_tail; - - /** - * Welcome message used by this peer. - */ - struct WelcomeMessage my_welcome; - - /** - * How many more TCP sessions are we allowed to open right now? - */ - unsigned long long max_connections; - - /** - * How many more TCP sessions do we have right now? - */ - unsigned long long cur_connections; - - /** - * Address options - */ - uint32_t myoptions; - - /** - * Port that we are actually listening on. - */ - uint16_t open_port; - - /** - * Port that the user said we would have visible to the - * rest of the world. - */ - uint16_t adv_port; - -}; - - -/** - * Get the list of addresses that a server for the given service - * should bind to. - * - * @param service_name name of the service - * @param cfg configuration (which specifies the addresses) - * @param addrs set (call by reference) to an array of pointers to the - * addresses the server should bind to and listen on; the - * array will be NULL-terminated (on success) - * @param addr_lens set (call by reference) to an array of the lengths - * of the respective `struct sockaddr` struct in the @a addrs - * array (on success) - * @return number of addresses found on success, - * #GNUNET_SYSERR if the configuration - * did not specify reasonable finding information or - * if it specified a hostname that could not be resolved; - * #GNUNET_NO if the number of addresses configured is - * zero (in this case, `*addrs` and `*addr_lens` will be - * set to NULL). - */ -static int -get_server_addresses (const char *service_name, - const struct GNUNET_CONFIGURATION_Handle *cfg, - struct sockaddr ***addrs, - socklen_t ** addr_lens) -{ - int disablev6; - struct GNUNET_NETWORK_Handle *desc; - unsigned long long port; - char *unixpath; - struct addrinfo hints; - struct addrinfo *res; - struct addrinfo *pos; - struct addrinfo *next; - unsigned int i; - int resi; - int ret; - int abstract; - struct sockaddr **saddrs; - socklen_t *saddrlens; - char *hostname; - - *addrs = NULL; - *addr_lens = NULL; - desc = NULL; - if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "DISABLEV6")) - { - if (GNUNET_SYSERR == - (disablev6 = - GNUNET_CONFIGURATION_get_value_yesno (cfg, service_name, "DISABLEV6"))) - return GNUNET_SYSERR; - } - else - disablev6 = GNUNET_NO; - - if (! disablev6) - { - /* probe IPv6 support */ - desc = GNUNET_NETWORK_socket_create (PF_INET6, SOCK_STREAM, 0); - if (NULL == desc) - { - if ((ENOBUFS == errno) || (ENOMEM == errno) || (ENFILE == errno) || - (EACCES == errno)) - { - GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "socket"); - return GNUNET_SYSERR; - } - LOG (GNUNET_ERROR_TYPE_INFO, - _("Disabling IPv6 support for service `%s', failed to create IPv6 socket: %s\n"), - service_name, STRERROR (errno)); - disablev6 = GNUNET_YES; - } - else - { - GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (desc)); - desc = NULL; - } - } - - port = 0; - if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "PORT")) - { - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_number (cfg, service_name, - "PORT", &port)) - { - LOG (GNUNET_ERROR_TYPE_ERROR, - _("Require valid port number for service `%s' in configuration!\n"), - service_name); - } - if (port > 65535) - { - LOG (GNUNET_ERROR_TYPE_ERROR, - _("Require valid port number for service `%s' in configuration!\n"), - service_name); - return GNUNET_SYSERR; - } - } - - if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "BINDTO")) - { - GNUNET_break (GNUNET_OK == - GNUNET_CONFIGURATION_get_value_string (cfg, service_name, - "BINDTO", &hostname)); - } - else - hostname = NULL; - - unixpath = NULL; - abstract = GNUNET_NO; -#ifdef AF_UNIX - if ((GNUNET_YES == - GNUNET_CONFIGURATION_have_value (cfg, service_name, "UNIXPATH")) && - (GNUNET_OK == - GNUNET_CONFIGURATION_get_value_filename (cfg, service_name, "UNIXPATH", - &unixpath)) && - (0 < strlen (unixpath))) - { - /* probe UNIX support */ - struct sockaddr_un s_un; - - if (strlen (unixpath) >= sizeof (s_un.sun_path)) - { - LOG (GNUNET_ERROR_TYPE_WARNING, - _("UNIXPATH `%s' too long, maximum length is %llu\n"), unixpath, - (unsigned long long) sizeof (s_un.sun_path)); - unixpath = GNUNET_NETWORK_shorten_unixpath (unixpath); - LOG (GNUNET_ERROR_TYPE_INFO, - _("Using `%s' instead\n"), - unixpath); - } -#ifdef LINUX - abstract = GNUNET_CONFIGURATION_get_value_yesno (cfg, - "TESTING", - "USE_ABSTRACT_SOCKETS"); - if (GNUNET_SYSERR == abstract) - abstract = GNUNET_NO; -#endif - if ((GNUNET_YES != abstract) - && (GNUNET_OK != - GNUNET_DISK_directory_create_for_file (unixpath))) - GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, - "mkdir", - unixpath); - } - if (NULL != unixpath) - { - desc = GNUNET_NETWORK_socket_create (AF_UNIX, SOCK_STREAM, 0); - if (NULL == desc) - { - if ((ENOBUFS == errno) || (ENOMEM == errno) || (ENFILE == errno) || - (EACCES == errno)) - { - GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "socket"); - GNUNET_free_non_null (hostname); - GNUNET_free (unixpath); - return GNUNET_SYSERR; - } - LOG (GNUNET_ERROR_TYPE_INFO, - _("Disabling UNIX domain socket support for service `%s', failed to create UNIX domain socket: %s\n"), - service_name, - STRERROR (errno)); - GNUNET_free (unixpath); - unixpath = NULL; - } - else - { - GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (desc)); - desc = NULL; - } - } -#endif - - if ((0 == port) && (NULL == unixpath)) - { - LOG (GNUNET_ERROR_TYPE_ERROR, - _("Have neither PORT nor UNIXPATH for service `%s', but one is required\n"), - service_name); - GNUNET_free_non_null (hostname); - return GNUNET_SYSERR; - } - if (0 == port) - { - saddrs = GNUNET_malloc (2 * sizeof (struct sockaddr *)); - saddrlens = GNUNET_malloc (2 * sizeof (socklen_t)); - add_unixpath (saddrs, saddrlens, unixpath, abstract); - GNUNET_free_non_null (unixpath); - GNUNET_free_non_null (hostname); - *addrs = saddrs; - *addr_lens = saddrlens; - return 1; - } - - if (NULL != hostname) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Resolving `%s' since that is where `%s' will bind to.\n", - hostname, - service_name); - memset (&hints, 0, sizeof (struct addrinfo)); - if (disablev6) - hints.ai_family = AF_INET; - hints.ai_protocol = IPPROTO_TCP; - if ((0 != (ret = getaddrinfo (hostname, NULL, &hints, &res))) || - (NULL == res)) - { - LOG (GNUNET_ERROR_TYPE_ERROR, - _("Failed to resolve `%s': %s\n"), - hostname, - gai_strerror (ret)); - GNUNET_free (hostname); - GNUNET_free_non_null (unixpath); - return GNUNET_SYSERR; - } - next = res; - i = 0; - while (NULL != (pos = next)) - { - next = pos->ai_next; - if ((disablev6) && (pos->ai_family == AF_INET6)) - continue; - i++; - } - if (0 == i) - { - LOG (GNUNET_ERROR_TYPE_ERROR, - _("Failed to find %saddress for `%s'.\n"), - disablev6 ? "IPv4 " : "", - hostname); - freeaddrinfo (res); - GNUNET_free (hostname); - GNUNET_free_non_null (unixpath); - return GNUNET_SYSERR; - } - resi = i; - if (NULL != unixpath) - resi++; - saddrs = GNUNET_malloc ((resi + 1) * sizeof (struct sockaddr *)); - saddrlens = GNUNET_malloc ((resi + 1) * sizeof (socklen_t)); - i = 0; - if (NULL != unixpath) - { - add_unixpath (saddrs, saddrlens, unixpath, abstract); - i++; - } - next = res; - while (NULL != (pos = next)) - { - next = pos->ai_next; - if ((disablev6) && (AF_INET6 == pos->ai_family)) - continue; - if ((IPPROTO_TCP != pos->ai_protocol) && (0 != pos->ai_protocol)) - continue; /* not TCP */ - if ((SOCK_STREAM != pos->ai_socktype) && (0 != pos->ai_socktype)) - continue; /* huh? */ - LOG (GNUNET_ERROR_TYPE_DEBUG, "Service `%s' will bind to `%s'\n", - service_name, GNUNET_a2s (pos->ai_addr, pos->ai_addrlen)); - if (AF_INET == pos->ai_family) - { - GNUNET_assert (sizeof (struct sockaddr_in) == pos->ai_addrlen); - saddrlens[i] = pos->ai_addrlen; - saddrs[i] = GNUNET_malloc (saddrlens[i]); - GNUNET_memcpy (saddrs[i], pos->ai_addr, saddrlens[i]); - ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port); - } - else - { - GNUNET_assert (AF_INET6 == pos->ai_family); - GNUNET_assert (sizeof (struct sockaddr_in6) == pos->ai_addrlen); - saddrlens[i] = pos->ai_addrlen; - saddrs[i] = GNUNET_malloc (saddrlens[i]); - GNUNET_memcpy (saddrs[i], pos->ai_addr, saddrlens[i]); - ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port); - } - i++; - } - GNUNET_free (hostname); - freeaddrinfo (res); - resi = i; - } - else - { - /* will bind against everything, just set port */ - if (disablev6) - { - /* V4-only */ - resi = 1; - if (NULL != unixpath) - resi++; - i = 0; - saddrs = GNUNET_malloc ((resi + 1) * sizeof (struct sockaddr *)); - saddrlens = GNUNET_malloc ((resi + 1) * sizeof (socklen_t)); - if (NULL != unixpath) - { - add_unixpath (saddrs, saddrlens, unixpath, abstract); - i++; - } - saddrlens[i] = sizeof (struct sockaddr_in); - saddrs[i] = GNUNET_malloc (saddrlens[i]); -#if HAVE_SOCKADDR_IN_SIN_LEN - ((struct sockaddr_in *) saddrs[i])->sin_len = saddrlens[i]; -#endif - ((struct sockaddr_in *) saddrs[i])->sin_family = AF_INET; - ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port); - } - else - { - /* dual stack */ - resi = 2; - if (NULL != unixpath) - resi++; - saddrs = GNUNET_malloc ((resi + 1) * sizeof (struct sockaddr *)); - saddrlens = GNUNET_malloc ((resi + 1) * sizeof (socklen_t)); - i = 0; - if (NULL != unixpath) - { - add_unixpath (saddrs, saddrlens, unixpath, abstract); - i++; - } - saddrlens[i] = sizeof (struct sockaddr_in6); - saddrs[i] = GNUNET_malloc (saddrlens[i]); -#if HAVE_SOCKADDR_IN_SIN_LEN - ((struct sockaddr_in6 *) saddrs[i])->sin6_len = saddrlens[0]; -#endif - ((struct sockaddr_in6 *) saddrs[i])->sin6_family = AF_INET6; - ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port); - i++; - saddrlens[i] = sizeof (struct sockaddr_in); - saddrs[i] = GNUNET_malloc (saddrlens[i]); -#if HAVE_SOCKADDR_IN_SIN_LEN - ((struct sockaddr_in *) saddrs[i])->sin_len = saddrlens[1]; -#endif - ((struct sockaddr_in *) saddrs[i])->sin_family = AF_INET; - ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port); - } - } - GNUNET_free_non_null (unixpath); - *addrs = saddrs; - *addr_lens = saddrlens; - return resi; -} -/* end ancient copy-and-paste */ - - -/** - * If a session monitor is attached, notify it about the new - * session state. - * - * @param plugin our plugin - * @param session session that changed state - * @param state new state of the session - */ -static void -notify_session_monitor (struct Plugin *plugin, - struct GNUNET_ATS_Session *session, - enum GNUNET_TRANSPORT_SessionState state) -{ - struct GNUNET_TRANSPORT_SessionInfo info; - - if (NULL == plugin->sic) - return; - memset (&info, 0, sizeof (info)); - info.state = state; - info.is_inbound = GNUNET_HELLO_address_check_option (session->address, - GNUNET_HELLO_ADDRESS_INFO_INBOUND); - info.num_msg_pending = session->msgs_in_queue; - info.num_bytes_pending = session->bytes_in_queue; - if (NULL != session->receive_delay_task) - info.receive_delay = session->receive_delay; - info.session_timeout = session->timeout; - info.address = session->address; - plugin->sic (plugin->sic_cls, - session, - &info); -} - - -/** - * Our external IP address/port mapping has changed. - * - * @param cls closure, the `struct Plugin` - * @param add_remove #GNUNET_YES to mean the new public IP address, #GNUNET_NO to mean - * the previous (now invalid) one - * @param ac address class the address belongs to - * @param addr either the previous or the new public IP address - * @param addrlen actual length of @a addr - */ -static void -tcp_nat_port_map_callback (void *cls, - int add_remove, - enum GNUNET_NAT_AddressClass ac, - const struct sockaddr *addr, - socklen_t addrlen) -{ - struct Plugin *plugin = cls; - struct GNUNET_HELLO_Address *address; - struct IPv4TcpAddress t4; - struct IPv6TcpAddress t6; - void *arg; - size_t args; - - if (GNUNET_NAT_AC_LOOPBACK == ac) - return; - if (GNUNET_NAT_AC_LAN == ac) - return; - if (GNUNET_NAT_AC_LAN_PRIVATE == ac) - return; - LOG (GNUNET_ERROR_TYPE_INFO, - "NAT notification to %s address `%s'\n", - (GNUNET_YES == add_remove) ? "add" : "remove", - GNUNET_a2s (addr, addrlen)); - /* convert 'addr' to our internal format */ - switch (addr->sa_family) - { - case AF_INET: - GNUNET_assert(addrlen == sizeof(struct sockaddr_in)); - memset (&t4, 0, sizeof(t4)); - t4.options = htonl (plugin->myoptions); - t4.ipv4_addr = ((struct sockaddr_in *) addr)->sin_addr.s_addr; - t4.t4_port = ((struct sockaddr_in *) addr)->sin_port; - arg = &t4; - args = sizeof (t4); - break; - case AF_INET6: - GNUNET_assert(addrlen == sizeof(struct sockaddr_in6)); - memset (&t6, 0, sizeof(t6)); - GNUNET_memcpy (&t6.ipv6_addr, - &((struct sockaddr_in6 *) addr)->sin6_addr, - sizeof(struct in6_addr)); - t6.options = htonl (plugin->myoptions); - t6.t6_port = ((struct sockaddr_in6 *) addr)->sin6_port; - arg = &t6; - args = sizeof (t6); - break; - default: - GNUNET_break(0); - return; - } - /* modify our published address list */ - GNUNET_assert ((args == sizeof (struct IPv4TcpAddress)) || - (args == sizeof (struct IPv6TcpAddress))); - /* TODO: use 'ac' here in the future... */ - address = GNUNET_HELLO_address_allocate (plugin->env->my_identity, - PLUGIN_NAME, - arg, - args, - GNUNET_HELLO_ADDRESS_INFO_NONE); - plugin->env->notify_address (plugin->env->cls, - add_remove, - address); - GNUNET_HELLO_address_free (address); -} - - -/** - * Function called for a quick conversion of the binary address to - * a numeric address. Note that the caller must not free the - * address and that the next call to this function is allowed - * to override the address again. - * - * @param cls closure (`struct Plugin*`) - * @param addr binary address - * @param addrlen length of @a addr - * @return string representing the same address - */ -static const char * -tcp_plugin_address_to_string (void *cls, - const void *addr, - size_t addrlen) -{ - static char rbuf[INET6_ADDRSTRLEN + 12]; - char buf[INET6_ADDRSTRLEN]; - const void *sb; - struct in_addr a4; - struct in6_addr a6; - const struct IPv4TcpAddress *t4; - const struct IPv6TcpAddress *t6; - int af; - uint16_t port; - uint32_t options; - - switch (addrlen) - { - case sizeof(struct IPv6TcpAddress): - t6 = addr; - af = AF_INET6; - port = ntohs (t6->t6_port); - options = ntohl (t6->options); - GNUNET_memcpy (&a6, &t6->ipv6_addr, sizeof(a6)); - sb = &a6; - break; - case sizeof(struct IPv4TcpAddress): - t4 = addr; - af = AF_INET; - port = ntohs (t4->t4_port); - options = ntohl (t4->options); - GNUNET_memcpy (&a4, &t4->ipv4_addr, sizeof(a4)); - sb = &a4; - break; - default: - LOG (GNUNET_ERROR_TYPE_WARNING, - _("Unexpected address length: %u bytes\n"), - (unsigned int) addrlen); - return NULL ; - } - if (NULL == inet_ntop (af, sb, buf, INET6_ADDRSTRLEN)) - { - GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, - "inet_ntop"); - return NULL ; - } - GNUNET_snprintf (rbuf, sizeof(rbuf), - (af == AF_INET6) ? "%s.%u.[%s]:%u" : "%s.%u.%s:%u", - PLUGIN_NAME, - options, - buf, - port); - return rbuf; -} - - -/** - * Function called to convert a string address to - * a binary address. - * - * @param cls closure (`struct Plugin*`) - * @param addr string address - * @param addrlen length of the address - * @param buf location to store the buffer - * @param added location to store the number of bytes in the buffer. - * If the function returns #GNUNET_SYSERR, its contents are undefined. - * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure - */ -static int -tcp_plugin_string_to_address (void *cls, - const char *addr, - uint16_t addrlen, - void **buf, - size_t *added) -{ - struct sockaddr_storage socket_address; - char *address; - char *plugin; - char *optionstr; - uint32_t options; - - /* Format tcp.options.address:port */ - address = NULL; - plugin = NULL; - optionstr = NULL; - if ((NULL == addr) || (0 == addrlen)) - { - GNUNET_break(0); - return GNUNET_SYSERR; - } - if ('\0' != addr[addrlen - 1]) - { - GNUNET_break(0); - return GNUNET_SYSERR; - } - if (strlen (addr) != addrlen - 1) - { - GNUNET_break(0); - return GNUNET_SYSERR; - } - plugin = GNUNET_strdup (addr); - optionstr = strchr (plugin, '.'); - if (NULL == optionstr) - { - GNUNET_break(0); - GNUNET_free(plugin); - return GNUNET_SYSERR; - } - optionstr[0] = '\0'; - optionstr++; - options = atol (optionstr); - address = strchr (optionstr, '.'); - if (NULL == address) - { - GNUNET_break(0); - GNUNET_free(plugin); - return GNUNET_SYSERR; - } - address[0] = '\0'; - address++; - - if (GNUNET_OK != - GNUNET_STRINGS_to_address_ip (address, - strlen (address), - &socket_address)) - { - GNUNET_break(0); - GNUNET_free(plugin); - return GNUNET_SYSERR; - } - - GNUNET_free(plugin); - switch (socket_address.ss_family) - { - case AF_INET: - { - struct IPv4TcpAddress *t4; - struct sockaddr_in *in4 = (struct sockaddr_in *) &socket_address; - t4 = GNUNET_new (struct IPv4TcpAddress); - t4->options = htonl (options); - t4->ipv4_addr = in4->sin_addr.s_addr; - t4->t4_port = in4->sin_port; - *buf = t4; - *added = sizeof(struct IPv4TcpAddress); - return GNUNET_OK; - } - case AF_INET6: - { - struct IPv6TcpAddress *t6; - struct sockaddr_in6 *in6 = (struct sockaddr_in6 *) &socket_address; - t6 = GNUNET_new (struct IPv6TcpAddress); - t6->options = htonl (options); - t6->ipv6_addr = in6->sin6_addr; - t6->t6_port = in6->sin6_port; - *buf = t6; - *added = sizeof(struct IPv6TcpAddress); - return GNUNET_OK; - } - default: - return GNUNET_SYSERR; - } -} - - -/** - * Find the session handle for the given client. - * Currently uses both the hashmap and the client - * context, as the client context is new and the - * logic still needs to be tested. - * - * @param plugin the plugin - * @param client which client to find the session handle for - * @return NULL if no matching session exists - */ -static struct GNUNET_ATS_Session * -lookup_session_by_client (struct Plugin *plugin, - struct GNUNET_SERVER_Client *client) -{ - return GNUNET_SERVER_client_get_user_context (client, - struct GNUNET_ATS_Session); -} - - -/** - * Functions with this signature are called whenever we need - * to close a session due to a disconnect or failure to - * establish a connection. - * - * @param cls the `struct Plugin` - * @param session session to close down - * @return #GNUNET_OK on success - */ -static int -tcp_plugin_disconnect_session (void *cls, - struct GNUNET_ATS_Session *session) -{ - struct Plugin *plugin = cls; - struct PendingMessage *pm; - - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Disconnecting session of peer `%s' address `%s'\n", - GNUNET_i2s (&session->target), - tcp_plugin_address_to_string (session->plugin, - session->address->address, - session->address->address_length)); - - if (NULL != session->timeout_task) - { - GNUNET_SCHEDULER_cancel (session->timeout_task); - session->timeout_task = NULL; - session->timeout = GNUNET_TIME_UNIT_ZERO_ABS; - } - - if (GNUNET_YES == - GNUNET_CONTAINER_multipeermap_remove (plugin->sessionmap, - &session->target, - session)) - { - GNUNET_STATISTICS_update (session->plugin->env->stats, - gettext_noop ("# TCP sessions active"), - -1, - GNUNET_NO); - } - else - { - GNUNET_assert (GNUNET_YES == - GNUNET_CONTAINER_multipeermap_remove (plugin->nat_wait_conns, - &session->target, - session)); - } - if (NULL != session->client) - GNUNET_SERVER_client_set_user_context (session->client, - NULL); - - /* clean up state */ - if (NULL != session->transmit_handle) - { - GNUNET_SERVER_notify_transmit_ready_cancel (session->transmit_handle); - session->transmit_handle = NULL; - } - session->plugin->env->session_end (session->plugin->env->cls, - session->address, - session); - - if (NULL != session->nat_connection_timeout) - { - GNUNET_SCHEDULER_cancel (session->nat_connection_timeout); - session->nat_connection_timeout = NULL; - } - - while (NULL != (pm = session->pending_messages_head)) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, - (NULL != pm->transmit_cont) - ? "Could not deliver message to `%s' at %s.\n" - : "Could not deliver message to `%s' at %s, notifying.\n", - GNUNET_i2s (&session->target), - tcp_plugin_address_to_string (session->plugin, - session->address->address, - session->address->address_length)); - GNUNET_STATISTICS_update (session->plugin->env->stats, - gettext_noop ("# bytes currently in TCP buffers"), - -(int64_t) pm->message_size, GNUNET_NO); - GNUNET_STATISTICS_update (session->plugin->env->stats, - gettext_noop ("# bytes discarded by TCP (disconnect)"), - pm->message_size, - GNUNET_NO); - GNUNET_CONTAINER_DLL_remove (session->pending_messages_head, - session->pending_messages_tail, - pm); - GNUNET_assert (0 < session->msgs_in_queue); - session->msgs_in_queue--; - GNUNET_assert (pm->message_size <= session->bytes_in_queue); - session->bytes_in_queue -= pm->message_size; - if (NULL != pm->transmit_cont) - pm->transmit_cont (pm->transmit_cont_cls, - &session->target, - GNUNET_SYSERR, - pm->message_size, - 0); - GNUNET_free (pm); - } - GNUNET_assert (0 == session->msgs_in_queue); - GNUNET_assert (0 == session->bytes_in_queue); - notify_session_monitor (session->plugin, - session, - GNUNET_TRANSPORT_SS_DONE); - - if (NULL != session->receive_delay_task) - { - GNUNET_SCHEDULER_cancel (session->receive_delay_task); - session->receive_delay_task = NULL; - } - if (NULL != session->client) - { - GNUNET_SERVER_client_disconnect (session->client); - session->client = NULL; - } - GNUNET_HELLO_address_free (session->address); - GNUNET_assert (NULL == session->transmit_handle); - GNUNET_free (session); - return GNUNET_OK; -} - - -/** - * Function that is called to get the keepalive factor. - * #GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT is divided by this number to - * calculate the interval between keepalive packets. - * - * @param cls closure with the `struct Plugin` - * @return keepalive factor - */ -static unsigned int -tcp_plugin_query_keepalive_factor (void *cls) -{ - return 3; -} - - -/** - * Session was idle for too long, so disconnect it - * - * @param cls the `struct GNUNET_ATS_Session` of the idle session - */ -static void -session_timeout (void *cls) -{ - struct GNUNET_ATS_Session *s = cls; - struct GNUNET_TIME_Relative left; - - s->timeout_task = NULL; - left = GNUNET_TIME_absolute_get_remaining (s->timeout); - if (0 != left.rel_value_us) - { - /* not actually our turn yet, but let's at least update - the monitor, it may think we're about to die ... */ - notify_session_monitor (s->plugin, - s, - GNUNET_TRANSPORT_SS_UPDATE); - s->timeout_task = GNUNET_SCHEDULER_add_delayed (left, - &session_timeout, - s); - return; - } - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Session %p was idle for %s, disconnecting\n", - s, - GNUNET_STRINGS_relative_time_to_string (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT, - GNUNET_YES)); - /* call session destroy function */ - tcp_plugin_disconnect_session (s->plugin, - s); -} - - -/** - * Increment session timeout due to activity. - * - * @param s session to increment timeout for - */ -static void -reschedule_session_timeout (struct GNUNET_ATS_Session *s) -{ - GNUNET_assert (NULL != s->timeout_task); - s->timeout = GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT); -} - - -/** - * Create a new session. Also queues a welcome message. - * - * @param plugin the plugin - * @param address the address to create the session for - * @param scope network scope the address is from - * @param client client to use, reference counter must have already been increased - * @param is_nat this a NAT session, we should wait for a client to - * connect to us from an address, then assign that to - * the session - * @return new session object - */ -static struct GNUNET_ATS_Session * -create_session (struct Plugin *plugin, - const struct GNUNET_HELLO_Address *address, - enum GNUNET_NetworkType scope, - struct GNUNET_SERVER_Client *client, - int is_nat) -{ - struct GNUNET_ATS_Session *session; - struct PendingMessage *pm; - - if (GNUNET_YES != is_nat) - GNUNET_assert (NULL != client); - else - GNUNET_assert (NULL == client); - - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Creating new session for peer `%s' at address %s\n", - GNUNET_i2s (&address->peer), - tcp_plugin_address_to_string (plugin, - address->address, - address->address_length)); - session = GNUNET_new (struct GNUNET_ATS_Session); - session->last_activity = GNUNET_TIME_absolute_get (); - session->plugin = plugin; - session->is_nat = is_nat; - if (NULL != client) - { - session->client = client; - GNUNET_SERVER_client_set_user_context (client, - session); - } - session->address = GNUNET_HELLO_address_copy (address); - session->target = address->peer; - session->expecting_welcome = GNUNET_YES; - session->scope = scope; - pm = GNUNET_malloc (sizeof (struct PendingMessage) + - sizeof (struct WelcomeMessage)); - pm->msg = (const char *) &pm[1]; - pm->message_size = sizeof(struct WelcomeMessage); - GNUNET_memcpy (&pm[1], - &plugin->my_welcome, - sizeof(struct WelcomeMessage)); - pm->timeout = GNUNET_TIME_UNIT_FOREVER_ABS; - GNUNET_STATISTICS_update (plugin->env->stats, - gettext_noop ("# bytes currently in TCP buffers"), - pm->message_size, - GNUNET_NO); - GNUNET_CONTAINER_DLL_insert (session->pending_messages_head, - session->pending_messages_tail, - pm); - session->msgs_in_queue++; - session->bytes_in_queue += pm->message_size; - session->timeout = GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT); - session->timeout_task = GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT, - &session_timeout, - session); - notify_session_monitor (session->plugin, - session, - GNUNET_TRANSPORT_SS_INIT); - if (GNUNET_YES != is_nat) - { - GNUNET_STATISTICS_update (plugin->env->stats, - gettext_noop ("# TCP sessions active"), - 1, - GNUNET_NO); - notify_session_monitor (session->plugin, - session, - GNUNET_TRANSPORT_SS_UP); - } - else - { - notify_session_monitor (session->plugin, - session, - GNUNET_TRANSPORT_SS_HANDSHAKE); - } - return session; -} - - -/** - * If we have pending messages, ask the server to - * transmit them (schedule the respective tasks, etc.) - * - * @param session for which session should we do this - */ -static void -process_pending_messages (struct GNUNET_ATS_Session *session); - - -/** - * Function called to notify a client about the socket - * being ready to queue more data. "buf" will be - * NULL and "size" zero if the socket was closed for - * writing in the meantime. - * - * @param cls closure - * @param size number of bytes available in @a buf - * @param buf where the callee should write the message - * @return number of bytes written to @a buf - */ -static size_t -do_transmit (void *cls, - size_t size, - void *buf) -{ - struct GNUNET_ATS_Session *session = cls; - struct GNUNET_PeerIdentity pid; - struct Plugin *plugin; - struct PendingMessage *pos; - struct PendingMessage *hd; - struct PendingMessage *tl; - struct GNUNET_TIME_Absolute now; - char *cbuf; - size_t ret; - - session->transmit_handle = NULL; - plugin = session->plugin; - if (NULL == buf) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Timeout trying to transmit to peer `%s', discarding message queue.\n", - GNUNET_i2s (&session->target)); - /* timeout; cancel all messages that have already expired */ - hd = NULL; - tl = NULL; - ret = 0; - now = GNUNET_TIME_absolute_get (); - while ( (NULL != (pos = session->pending_messages_head)) && - (pos->timeout.abs_value_us <= now.abs_value_us) ) - { - GNUNET_CONTAINER_DLL_remove (session->pending_messages_head, - session->pending_messages_tail, - pos); - GNUNET_assert (0 < session->msgs_in_queue); - session->msgs_in_queue--; - GNUNET_assert (pos->message_size <= session->bytes_in_queue); - session->bytes_in_queue -= pos->message_size; - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Failed to transmit %u byte message to `%s'.\n", - pos->message_size, - GNUNET_i2s (&session->target)); - ret += pos->message_size; - GNUNET_CONTAINER_DLL_insert_after (hd, - tl, - tl, - pos); - } - /* do this call before callbacks (so that if callbacks destroy - * session, they have a chance to cancel actions done by this - * call) */ - process_pending_messages (session); - pid = session->target; - /* no do callbacks and do not use session again since - * the callbacks may abort the session */ - while (NULL != (pos = hd)) - { - GNUNET_CONTAINER_DLL_remove (hd, - tl, - pos); - if (NULL != pos->transmit_cont) - pos->transmit_cont (pos->transmit_cont_cls, - &pid, - GNUNET_SYSERR, - pos->message_size, - 0); - GNUNET_free (pos); - } - GNUNET_STATISTICS_update (plugin->env->stats, - gettext_noop ("# bytes currently in TCP buffers"), -(int64_t) ret, - GNUNET_NO); - GNUNET_STATISTICS_update (plugin->env->stats, - gettext_noop ("# bytes discarded by TCP (timeout)"), - ret, - GNUNET_NO); - if (0 < ret) - notify_session_monitor (session->plugin, - session, - GNUNET_TRANSPORT_SS_UPDATE); - return 0; - } - /* copy all pending messages that would fit */ - ret = 0; - cbuf = buf; - hd = NULL; - tl = NULL; - while (NULL != (pos = session->pending_messages_head)) - { - if (ret + pos->message_size > size) - break; - GNUNET_CONTAINER_DLL_remove (session->pending_messages_head, - session->pending_messages_tail, - pos); - GNUNET_assert (0 < session->msgs_in_queue); - session->msgs_in_queue--; - GNUNET_assert (pos->message_size <= session->bytes_in_queue); - session->bytes_in_queue -= pos->message_size; - GNUNET_assert(size >= pos->message_size); - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Transmitting message of type %u size %u to peer %s at %s\n", - ntohs (((struct GNUNET_MessageHeader *) pos->msg)->type), - pos->message_size, - GNUNET_i2s (&session->target), - tcp_plugin_address_to_string (session->plugin, - session->address->address, - session->address->address_length)); - /* FIXME: this GNUNET_memcpy can be up to 7% of our total runtime */ - GNUNET_memcpy (cbuf, - pos->msg, - pos->message_size); - cbuf += pos->message_size; - ret += pos->message_size; - size -= pos->message_size; - GNUNET_CONTAINER_DLL_insert_tail (hd, - tl, - pos); - } - notify_session_monitor (session->plugin, - session, - GNUNET_TRANSPORT_SS_UPDATE); - /* schedule 'continuation' before callbacks so that callbacks that - * cancel everything don't cause us to use a session that no longer - * exists... */ - process_pending_messages (session); - session->last_activity = GNUNET_TIME_absolute_get (); - pid = session->target; - /* we'll now call callbacks that may cancel the session; hence - * we should not use 'session' after this point */ - while (NULL != (pos = hd)) - { - GNUNET_CONTAINER_DLL_remove (hd, tl, pos); - if (NULL != pos->transmit_cont) - pos->transmit_cont (pos->transmit_cont_cls, - &pid, - GNUNET_OK, - pos->message_size, - pos->message_size); /* FIXME: include TCP overhead */ - GNUNET_free (pos); - } - GNUNET_assert (NULL == hd); - GNUNET_assert (NULL == tl); - GNUNET_STATISTICS_update (plugin->env->stats, - gettext_noop ("# bytes currently in TCP buffers"), - - (int64_t) ret, - GNUNET_NO); - GNUNET_STATISTICS_update (plugin->env->stats, - gettext_noop ("# bytes transmitted via TCP"), - ret, - GNUNET_NO); - return ret; -} - - -/** - * If we have pending messages, ask the server to - * transmit them (schedule the respective tasks, etc.) - * - * @param session for which session should we do this - */ -static void -process_pending_messages (struct GNUNET_ATS_Session *session) -{ - struct PendingMessage *pm; - - GNUNET_assert (NULL != session->client); - if (NULL != session->transmit_handle) - return; - if (NULL == (pm = session->pending_messages_head)) - return; - - session->transmit_handle - = GNUNET_SERVER_notify_transmit_ready (session->client, - pm->message_size, - GNUNET_TIME_absolute_get_remaining (pm->timeout), - &do_transmit, - session); -} - - -/** - * Function that can be used by the transport service to transmit - * a message using the plugin. Note that in the case of a - * peer disconnecting, the continuation MUST be called - * prior to the disconnect notification itself. This function - * will be called with this peer's HELLO message to initiate - * a fresh connection to another peer. - * - * @param cls closure - * @param session which session must be used - * @param msgbuf the message to transmit - * @param msgbuf_size number of bytes in @a msgbuf - * @param priority how important is the message (most plugins will - * ignore message priority and just FIFO) - * @param to how long to wait at most for the transmission (does not - * require plugins to discard the message after the timeout, - * just advisory for the desired delay; most plugins will ignore - * this as well) - * @param cont continuation to call once the message has - * been transmitted (or if the transport is ready - * for the next transmission call; or if the - * peer disconnected...); can be NULL - * @param cont_cls closure for @a cont - * @return number of bytes used (on the physical network, with overheads); - * -1 on hard errors (i.e. address invalid); 0 is a legal value - * and does NOT mean that the message was not transmitted (DV) - */ -static ssize_t -tcp_plugin_send (void *cls, - struct GNUNET_ATS_Session *session, - const char *msgbuf, - size_t msgbuf_size, - unsigned int priority, - struct GNUNET_TIME_Relative to, - GNUNET_TRANSPORT_TransmitContinuation cont, - void *cont_cls) -{ - struct Plugin * plugin = cls; - struct PendingMessage *pm; - - /* create new message entry */ - pm = GNUNET_malloc (sizeof (struct PendingMessage) + msgbuf_size); - pm->msg = (const char *) &pm[1]; - GNUNET_memcpy (&pm[1], msgbuf, msgbuf_size); - pm->message_size = msgbuf_size; - pm->timeout = GNUNET_TIME_relative_to_absolute (to); - pm->transmit_cont = cont; - pm->transmit_cont_cls = cont_cls; - - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Asked to transmit %u bytes to `%s', added message to list.\n", - msgbuf_size, - GNUNET_i2s (&session->target)); - - if (GNUNET_YES == - GNUNET_CONTAINER_multipeermap_contains_value (plugin->sessionmap, - &session->target, - session)) - { - GNUNET_assert (NULL != session->client); - GNUNET_SERVER_client_set_timeout (session->client, - GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT); - GNUNET_STATISTICS_update (plugin->env->stats, - gettext_noop ("# bytes currently in TCP buffers"), - msgbuf_size, - GNUNET_NO); - - /* append pm to pending_messages list */ - GNUNET_CONTAINER_DLL_insert_tail (session->pending_messages_head, - session->pending_messages_tail, - pm); - notify_session_monitor (session->plugin, - session, - GNUNET_TRANSPORT_SS_UPDATE); - session->msgs_in_queue++; - session->bytes_in_queue += pm->message_size; - process_pending_messages (session); - return msgbuf_size; - } - if (GNUNET_YES == - GNUNET_CONTAINER_multipeermap_contains_value (plugin->nat_wait_conns, - &session->target, - session)) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, - "This NAT WAIT session for peer `%s' is not yet ready!\n", - GNUNET_i2s (&session->target)); - GNUNET_STATISTICS_update (plugin->env->stats, - gettext_noop ("# bytes currently in TCP buffers"), msgbuf_size, - GNUNET_NO); - /* append pm to pending_messages list */ - GNUNET_CONTAINER_DLL_insert_tail (session->pending_messages_head, - session->pending_messages_tail, - pm); - session->msgs_in_queue++; - session->bytes_in_queue += pm->message_size; - notify_session_monitor (session->plugin, - session, - GNUNET_TRANSPORT_SS_HANDSHAKE); - return msgbuf_size; - } - LOG (GNUNET_ERROR_TYPE_ERROR, - "Invalid session %p\n", - session); - if (NULL != cont) - cont (cont_cls, - &session->target, - GNUNET_SYSERR, - pm->message_size, - 0); - GNUNET_break (0); - GNUNET_free (pm); - return GNUNET_SYSERR; /* session does not exist here */ -} - - -/** - * Closure for #session_lookup_it(). - */ -struct GNUNET_ATS_SessionItCtx -{ - /** - * Address we are looking for. - */ - const struct GNUNET_HELLO_Address *address; - - /** - * Where to store the session (if we found it). - */ - struct GNUNET_ATS_Session *result; - -}; - - -/** - * Look for a session by address. - * - * @param cls the `struct GNUNET_ATS_SessionItCtx` - * @param key unused - * @param value a `struct GNUNET_ATS_Session` - * @return #GNUNET_YES to continue looking, #GNUNET_NO if we found the session - */ -static int -session_lookup_it (void *cls, - const struct GNUNET_PeerIdentity *key, - void *value) -{ - struct GNUNET_ATS_SessionItCtx *si_ctx = cls; - struct GNUNET_ATS_Session *session = value; - - if (0 != - GNUNET_HELLO_address_cmp (si_ctx->address, - session->address)) - return GNUNET_YES; - si_ctx->result = session; - return GNUNET_NO; -} - - -/** - * Task cleaning up a NAT connection attempt after timeout - * - * @param cls the `struct GNUNET_ATS_Session` - */ -static void -nat_connect_timeout (void *cls) -{ - struct GNUNET_ATS_Session *session = cls; - - session->nat_connection_timeout = NULL; - LOG (GNUNET_ERROR_TYPE_DEBUG, - "NAT WAIT connection to `%4s' at `%s' could not be established, removing session\n", - GNUNET_i2s (&session->target), - tcp_plugin_address_to_string (session->plugin, - session->address->address, - session->address->address_length)); - tcp_plugin_disconnect_session (session->plugin, - session); -} - - -/** - * Function that will be called whenever the transport service wants to - * notify the plugin that a session is still active and in use and - * therefore the session timeout for this session has to be updated - * - * @param cls closure - * @param peer which peer was the session for - * @param session which session is being updated - */ -static void -tcp_plugin_update_session_timeout (void *cls, - const struct GNUNET_PeerIdentity *peer, - struct GNUNET_ATS_Session *session) -{ - reschedule_session_timeout (session); -} - - -/** - * Task to signal the server that we can continue - * receiving from the TCP client now. - * - * @param cls the `struct GNUNET_ATS_Session *` - */ -static void -delayed_done (void *cls) -{ - struct GNUNET_ATS_Session *session = cls; - - session->receive_delay_task = NULL; - reschedule_session_timeout (session); - GNUNET_SERVER_receive_done (session->client, - GNUNET_OK); -} - - -/** - * Function that will be called whenever the transport service wants to - * notify the plugin that the inbound quota changed and that the plugin - * should update it's delay for the next receive value - * - * @param cls closure - * @param peer which peer was the session for - * @param session which session is being updated - * @param delay new delay to use for receiving - */ -static void -tcp_plugin_update_inbound_delay (void *cls, - const struct GNUNET_PeerIdentity *peer, - struct GNUNET_ATS_Session *session, - struct GNUNET_TIME_Relative delay) -{ - if (NULL == session->receive_delay_task) - return; - LOG (GNUNET_ERROR_TYPE_DEBUG, - "New inbound delay %s\n", - GNUNET_STRINGS_relative_time_to_string (delay, - GNUNET_NO)); - session->receive_delay = GNUNET_TIME_relative_to_absolute (delay); - GNUNET_SCHEDULER_cancel (session->receive_delay_task); - session->receive_delay_task = GNUNET_SCHEDULER_add_delayed (delay, - &delayed_done, - session); -} - - -/** - * Create a new session to transmit data to the target - * This session will used to send data to this peer and the plugin will - * notify us by calling the env->session_end function - * - * @param cls closure - * @param address the address to use - * @return the session if the address is valid, NULL otherwise - */ -static struct GNUNET_ATS_Session * -tcp_plugin_get_session (void *cls, - const struct GNUNET_HELLO_Address *address) -{ - struct Plugin *plugin = cls; - struct GNUNET_ATS_Session *session = NULL; - int af; - const void *sb; - size_t sbs; - struct GNUNET_CONNECTION_Handle *sa; - struct sockaddr_in a4; - struct sockaddr_in6 a6; - const struct IPv4TcpAddress *t4; - const struct IPv6TcpAddress *t6; - unsigned int options; - enum GNUNET_NetworkType net_type; - unsigned int is_natd = GNUNET_NO; - size_t addrlen; -#ifdef TCP_STEALTH - struct GNUNET_NETWORK_Handle *s; -#endif - - addrlen = address->address_length; - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Trying to get session for `%s' address of peer `%s'\n", - tcp_plugin_address_to_string (plugin, - address->address, - address->address_length), - GNUNET_i2s (&address->peer)); - - if (GNUNET_HELLO_address_check_option (address, - GNUNET_HELLO_ADDRESS_INFO_INBOUND)) - { - GNUNET_break (0); - return NULL; - } - - /* look for existing session */ - if (GNUNET_YES == - GNUNET_CONTAINER_multipeermap_contains (plugin->sessionmap, - &address->peer)) - { - struct GNUNET_ATS_SessionItCtx si_ctx; - - si_ctx.address = address; - si_ctx.result = NULL; - GNUNET_CONTAINER_multipeermap_get_multiple (plugin->sessionmap, - &address->peer, - &session_lookup_it, - &si_ctx); - if (NULL != si_ctx.result) - { - session = si_ctx.result; - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Found existing session for `%s' address `%s'\n", - GNUNET_i2s (&address->peer), - tcp_plugin_address_to_string (plugin, - address->address, - address->address_length)); - return session; - } - /* This is a bit of a hack, limiting TCP to never allow more than - one TCP connection to any given peer at the same time. - Without this, peers sometimes disagree about which of the TCP - connections they should use, causing one side to believe that - they transmit successfully, while the other receives nothing. */ - return NULL; /* Refuse to have more than one TCP connection per - peer pair at the same time. */ - } - - if (addrlen == sizeof(struct IPv6TcpAddress)) - { - GNUNET_assert (NULL != address->address); /* make static analysis happy */ - t6 = address->address; - options = t6->options; - af = AF_INET6; - memset (&a6, 0, sizeof(a6)); -#if HAVE_SOCKADDR_IN_SIN_LEN - a6.sin6_len = sizeof (a6); -#endif - a6.sin6_family = AF_INET6; - a6.sin6_port = t6->t6_port; - if (t6->t6_port == 0) - is_natd = GNUNET_YES; - GNUNET_memcpy (&a6.sin6_addr, &t6->ipv6_addr, sizeof(struct in6_addr)); - sb = &a6; - sbs = sizeof(a6); - } - else if (addrlen == sizeof(struct IPv4TcpAddress)) - { - GNUNET_assert(NULL != address->address); /* make static analysis happy */ - t4 = address->address; - options = t4->options; - af = AF_INET; - memset (&a4, 0, sizeof(a4)); -#if HAVE_SOCKADDR_IN_SIN_LEN - a4.sin_len = sizeof (a4); -#endif - a4.sin_family = AF_INET; - a4.sin_port = t4->t4_port; - if (t4->t4_port == 0) - is_natd = GNUNET_YES; - a4.sin_addr.s_addr = t4->ipv4_addr; - sb = &a4; - sbs = sizeof(a4); - } - else - { - GNUNET_STATISTICS_update (plugin->env->stats, - gettext_noop ("# requests to create session with invalid address"), - 1, - GNUNET_NO); - return NULL; - } - - net_type = plugin->env->get_address_type (plugin->env->cls, - sb, - sbs); - GNUNET_break (net_type != GNUNET_NT_UNSPECIFIED); - - if ( (is_natd == GNUNET_YES) && - (addrlen == sizeof(struct IPv6TcpAddress)) ) - { - /* NAT client only works with IPv4 addresses */ - return NULL; - } - - if (plugin->cur_connections >= plugin->max_connections) - { - /* saturated */ - return NULL; - } - - if ( (is_natd == GNUNET_YES) && - (GNUNET_YES == - GNUNET_CONTAINER_multipeermap_contains (plugin->nat_wait_conns, - &address->peer))) - { - /* Only do one NAT punch attempt per peer identity */ - return NULL; - } - - if ( (is_natd == GNUNET_YES) && - (NULL != plugin->nat) && - (GNUNET_NO == - GNUNET_CONTAINER_multipeermap_contains (plugin->nat_wait_conns, - &address->peer))) - { - struct sockaddr_in local_sa; - - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Found valid IPv4 NAT address (creating session)!\n"); - session = create_session (plugin, - address, - net_type, - NULL, - GNUNET_YES); - session->nat_connection_timeout = GNUNET_SCHEDULER_add_delayed (NAT_TIMEOUT, - &nat_connect_timeout, - session); - GNUNET_assert (GNUNET_OK == - GNUNET_CONTAINER_multipeermap_put (plugin->nat_wait_conns, - &session->target, - session, - GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); - - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Created NAT WAIT connection to `%s' at `%s'\n", - GNUNET_i2s (&session->target), - GNUNET_a2s (sb, sbs)); - memset (&local_sa, - 0, - sizeof (local_sa)); - local_sa.sin_family = AF_INET; - local_sa.sin_port = htons (plugin->open_port); - /* We leave sin_address at 0, let the kernel figure it out, - even if our bind() is more specific. (May want to reconsider - later.) */ - if (GNUNET_OK == - GNUNET_NAT_request_reversal (plugin->nat, - &local_sa, - &a4)) - return session; - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Running NAT client for `%s' at `%s' failed\n", - GNUNET_i2s (&session->target), - GNUNET_a2s (sb, sbs)); - tcp_plugin_disconnect_session (plugin, - session); - return NULL; - } - - /* create new outbound session */ - if (0 != (options & TCP_OPTIONS_TCP_STEALTH)) - { -#ifdef TCP_STEALTH - s = GNUNET_NETWORK_socket_create (af, SOCK_STREAM, 0); - if (NULL == s) - { - GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK, - "socket"); - sa = NULL; - } - else - { - if ( (GNUNET_OK != - GNUNET_NETWORK_socket_setsockopt (s, - IPPROTO_TCP, - TCP_STEALTH, - &session->target, - sizeof (struct GNUNET_PeerIdentity))) || - (GNUNET_OK != - GNUNET_NETWORK_socket_setsockopt (s, - IPPROTO_TCP, - TCP_STEALTH_INTEGRITY, - &plugin->my_welcome, - sizeof (struct WelcomeMessage))) ) - { - /* TCP STEALTH not supported by kernel */ - GNUNET_break (GNUNET_OK == - GNUNET_NETWORK_socket_close (s)); - sa = NULL; - } - else - { - sa = GNUNET_CONNECTION_connect_socket (s, sb, sbs); - } - } -#else - sa = NULL; -#endif - } - else - { - sa = GNUNET_CONNECTION_create_from_sockaddr (af, sb, sbs); - } - if (NULL == sa) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Failed to create connection to `%s' at `%s'\n", - GNUNET_i2s (&address->peer), - GNUNET_a2s (sb, sbs)); - return NULL; - } - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Asked to transmit to `%s', creating fresh session using address `%s'.\n", - GNUNET_i2s (&address->peer), - GNUNET_a2s (sb, sbs)); - - session = create_session (plugin, - address, - net_type, - GNUNET_SERVER_connect_socket (plugin->server, - sa), - GNUNET_NO); - (void) GNUNET_CONTAINER_multipeermap_put (plugin->sessionmap, - &session->target, - session, - GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); - /* Send TCP Welcome */ - process_pending_messages (session); - - return session; -} - - -/** - * We have been asked to destroy all connections to a particular peer. - * This function is called on each applicable session and must tear it - * down. - * - * @param cls the `struct Plugin *` - * @param key the peer which the session belongs to (unused) - * @param value the `struct GNUNET_ATS_Session` - * @return #GNUNET_YES (continue to iterate) - */ -static int -session_disconnect_it (void *cls, - const struct GNUNET_PeerIdentity *key, - void *value) -{ - struct Plugin *plugin = cls; - struct GNUNET_ATS_Session *session = value; - - GNUNET_STATISTICS_update (session->plugin->env->stats, - gettext_noop ("# transport-service disconnect requests for TCP"), - 1, - GNUNET_NO); - tcp_plugin_disconnect_session (plugin, - session); - return GNUNET_YES; -} - - -/** - * Function that can be called to force a disconnect from the - * specified neighbour. This should also cancel all previously - * scheduled transmissions. Obviously the transmission may have been - * partially completed already, which is OK. The plugin is supposed - * to close the connection (if applicable) and no longer call the - * transmit continuation(s). - * - * Finally, plugin MUST NOT call the services's receive function to - * notify the service that the connection to the specified target was - * closed after a getting this call. - * - * @param cls closure - * @param target peer for which the last transmission is - * to be cancelled - */ -static void -tcp_plugin_disconnect (void *cls, - const struct GNUNET_PeerIdentity *target) -{ - struct Plugin *plugin = cls; - - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Disconnecting peer `%s'\n", - GNUNET_i2s (target)); - GNUNET_CONTAINER_multipeermap_get_multiple (plugin->sessionmap, - target, - &session_disconnect_it, - plugin); - GNUNET_CONTAINER_multipeermap_get_multiple (plugin->nat_wait_conns, - target, - &session_disconnect_it, - plugin); -} - - -/** - * We are processing an address pretty printing request and finished - * the IP resolution (if applicable). Append our port and forward the - * result. If called with @a hostname NULL, we are done and should - * clean up the pretty printer (otherwise, there might be multiple - * hostnames for the IP address and we might receive more). - * - * @param cls the `struct PrettyPrinterContext *` - * @param hostname hostname part of the address - */ -static void -append_port (void *cls, - const char *hostname) -{ - struct PrettyPrinterContext *ppc = cls; - struct Plugin *plugin = ppc->plugin; - char *ret; - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "append_port called with hostname `%s'\n", - hostname); - if (NULL == hostname) - { - /* Final call, done */ - ppc->resolver_handle = NULL; - GNUNET_CONTAINER_DLL_remove (plugin->ppc_dll_head, - plugin->ppc_dll_tail, - ppc); - ppc->asc (ppc->asc_cls, - NULL, - GNUNET_OK); - GNUNET_free (ppc); - return; - } - if (GNUNET_YES == ppc->ipv6) - GNUNET_asprintf (&ret, - "%s.%u.[%s]:%d", - PLUGIN_NAME, - ppc->options, - hostname, - ppc->port); - else - GNUNET_asprintf (&ret, - "%s.%u.%s:%d", - PLUGIN_NAME, - ppc->options, - hostname, - ppc->port); - ppc->asc (ppc->asc_cls, - ret, - GNUNET_OK); - GNUNET_free (ret); -} - - -/** - * Convert the transports address to a nice, human-readable format. - * - * @param cls closure with the `struct Plugin` - * @param type name of the transport that generated the address - * @param addr one of the addresses of the host, NULL for the last address - * the specific address format depends on the transport - * @param addrlen length of the @a addr - * @param numeric should (IP) addresses be displayed in numeric form? - * @param timeout after how long should we give up? - * @param asc function to call on each string - * @param asc_cls closure for @a asc - */ -static void -tcp_plugin_address_pretty_printer (void *cls, - const char *type, - const void *addr, - size_t addrlen, - int numeric, - struct GNUNET_TIME_Relative timeout, - GNUNET_TRANSPORT_AddressStringCallback asc, - void *asc_cls) -{ - struct Plugin *plugin = cls; - struct PrettyPrinterContext *ppc; - const void *sb; - size_t sbs; - struct sockaddr_in a4; - struct sockaddr_in6 a6; - const struct IPv4TcpAddress *t4; - const struct IPv6TcpAddress *t6; - uint16_t port; - uint32_t options; - - if (sizeof(struct IPv6TcpAddress) == addrlen) - { - t6 = addr; - memset (&a6, 0, sizeof(a6)); - a6.sin6_family = AF_INET6; - a6.sin6_port = t6->t6_port; - GNUNET_memcpy (&a6.sin6_addr, &t6->ipv6_addr, sizeof(struct in6_addr)); - port = ntohs (t6->t6_port); - options = ntohl (t6->options); - sb = &a6; - sbs = sizeof(a6); - } - else if (sizeof(struct IPv4TcpAddress) == addrlen) - { - t4 = addr; - memset (&a4, 0, sizeof(a4)); - a4.sin_family = AF_INET; - a4.sin_port = t4->t4_port; - a4.sin_addr.s_addr = t4->ipv4_addr; - port = ntohs (t4->t4_port); - options = ntohl (t4->options); - sb = &a4; - sbs = sizeof(a4); - } - else - { - /* invalid address */ - LOG (GNUNET_ERROR_TYPE_WARNING, - _("Unexpected address length: %u bytes\n"), - (unsigned int) addrlen); - asc (asc_cls, NULL, GNUNET_SYSERR); - asc (asc_cls, NULL, GNUNET_OK); - return; - } - ppc = GNUNET_new (struct PrettyPrinterContext); - ppc->plugin = plugin; - if (addrlen == sizeof(struct IPv6TcpAddress)) - ppc->ipv6 = GNUNET_YES; - else - ppc->ipv6 = GNUNET_NO; - ppc->asc = asc; - ppc->asc_cls = asc_cls; - ppc->port = port; - ppc->options = options; - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Starting DNS reverse lookup\n"); - ppc->resolver_handle = GNUNET_RESOLVER_hostname_get (sb, - sbs, - ! numeric, - timeout, - &append_port, - ppc); - if (NULL == ppc->resolver_handle) - { - GNUNET_break (0); - GNUNET_free (ppc); - return; - } - GNUNET_CONTAINER_DLL_insert (plugin->ppc_dll_head, - plugin->ppc_dll_tail, - ppc); -} - - -/** - * Function that will be called to check if a binary address for this - * plugin is well-formed and corresponds to an address for THIS peer - * (as per our configuration). Naturally, if absolutely necessary, - * plugins can be a bit conservative in their answer, but in general - * plugins should make sure that the address does not redirect - * traffic to a 3rd party that might try to man-in-the-middle our - * traffic. - * - * @param cls closure, our `struct Plugin *` - * @param addr pointer to the address - * @param addrlen length of @a addr - * @return #GNUNET_OK if this is a plausible address for this peer - * and transport, #GNUNET_SYSERR if not - */ -static int -tcp_plugin_check_address (void *cls, - const void *addr, - size_t addrlen) -{ - struct Plugin *plugin = cls; - const struct IPv4TcpAddress *v4; - const struct IPv6TcpAddress *v6; - - if ( (addrlen != sizeof(struct IPv4TcpAddress)) && - (addrlen != sizeof(struct IPv6TcpAddress)) ) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - - if (addrlen == sizeof(struct IPv4TcpAddress)) - { - struct sockaddr_in s4; - - v4 = (const struct IPv4TcpAddress *) addr; - if (0 != memcmp (&v4->options, - &plugin->myoptions, - sizeof(uint32_t))) - { - GNUNET_break (0); - return GNUNET_SYSERR; - } - memset (&s4, 0, sizeof (s4)); - s4.sin_family = AF_INET; -#if HAVE_SOCKADDR_IN_SIN_LEN - s4.sin_len = sizeof (s4); -#endif - s4.sin_port = v4->t4_port; - s4.sin_addr.s_addr = v4->ipv4_addr; - - if (GNUNET_OK != - GNUNET_NAT_test_address (plugin->nat, - &s4, - sizeof (struct sockaddr_in))) - return GNUNET_SYSERR; - } - else - { - struct sockaddr_in6 s6; - - v6 = (const struct IPv6TcpAddress *) addr; - if (IN6_IS_ADDR_LINKLOCAL (&v6->ipv6_addr)) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - if (0 != memcmp (&v6->options, - &plugin->myoptions, - sizeof (uint32_t))) - { - GNUNET_break (0); - return GNUNET_SYSERR; - } - memset (&s6, 0, sizeof (s6)); - s6.sin6_family = AF_INET6; -#if HAVE_SOCKADDR_IN_SIN_LEN - s6.sin6_len = sizeof (s6); -#endif - s6.sin6_port = v6->t6_port; - s6.sin6_addr = v6->ipv6_addr; - - if (GNUNET_OK != - GNUNET_NAT_test_address (plugin->nat, - &s6, - sizeof(struct sockaddr_in6))) - return GNUNET_SYSERR; - } - return GNUNET_OK; -} - - -/** - * We've received a nat probe from this peer via TCP. Finish - * creating the client session and resume sending of queued - * messages. - * - * @param cls closure - * @param client identification of the client - * @param message the actual message - */ -static void -handle_tcp_nat_probe (void *cls, - struct GNUNET_SERVER_Client *client, - const struct GNUNET_MessageHeader *message) -{ - struct Plugin *plugin = cls; - struct GNUNET_ATS_Session *session; - const struct TCP_NAT_ProbeMessage *tcp_nat_probe; - size_t alen; - void *vaddr; - struct IPv4TcpAddress *t4; - struct IPv6TcpAddress *t6; - const struct sockaddr_in *s4; - const struct sockaddr_in6 *s6; - - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Received NAT probe\n"); - /* We have received a TCP NAT probe, meaning we (hopefully) initiated - * a connection to this peer by running gnunet-nat-client. This peer - * received the punch message and now wants us to use the new connection - * as the default for that peer. Do so and then send a WELCOME message - * so we can really be connected! - */ - if (ntohs (message->size) != sizeof(struct TCP_NAT_ProbeMessage)) - { - GNUNET_break_op(0); - GNUNET_SERVER_receive_done (client, - GNUNET_SYSERR); - return; - } - - tcp_nat_probe = (const struct TCP_NAT_ProbeMessage *) message; - if (0 == memcmp (&tcp_nat_probe->clientIdentity, plugin->env->my_identity, - sizeof(struct GNUNET_PeerIdentity))) - { - /* refuse connections from ourselves */ - GNUNET_SERVER_receive_done (client, - GNUNET_SYSERR); - return; - } - - session = GNUNET_CONTAINER_multipeermap_get (plugin->nat_wait_conns, - &tcp_nat_probe->clientIdentity); - if (NULL == session) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Did NOT find session for NAT probe!\n"); - GNUNET_SERVER_receive_done (client, - GNUNET_OK); - return; - } - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Found session for NAT probe!\n"); - - if (NULL != session->nat_connection_timeout) - { - GNUNET_SCHEDULER_cancel (session->nat_connection_timeout); - session->nat_connection_timeout = NULL; - } - - if (GNUNET_OK != - GNUNET_SERVER_client_get_address (client, - &vaddr, - &alen)) - { - GNUNET_break(0); - GNUNET_SERVER_receive_done (client, - GNUNET_SYSERR); - tcp_plugin_disconnect_session (plugin, - session); - return; - } - GNUNET_assert (GNUNET_YES == - GNUNET_CONTAINER_multipeermap_remove (plugin->nat_wait_conns, - &tcp_nat_probe->clientIdentity, - session)); - GNUNET_SERVER_client_set_user_context (client, - session); - (void) GNUNET_CONTAINER_multipeermap_put (plugin->sessionmap, - &session->target, - session, - GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); - session->last_activity = GNUNET_TIME_absolute_get (); - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Found address `%s' for incoming connection\n", - GNUNET_a2s (vaddr, alen)); - switch (((const struct sockaddr *) vaddr)->sa_family) - { - case AF_INET: - s4 = vaddr; - t4 = GNUNET_new (struct IPv4TcpAddress); - t4->options = htonl (TCP_OPTIONS_NONE); - t4->t4_port = s4->sin_port; - t4->ipv4_addr = s4->sin_addr.s_addr; - session->address = GNUNET_HELLO_address_allocate (&tcp_nat_probe->clientIdentity, - PLUGIN_NAME, - &t4, - sizeof(struct IPv4TcpAddress), - GNUNET_HELLO_ADDRESS_INFO_NONE); - break; - case AF_INET6: - s6 = vaddr; - t6 = GNUNET_new (struct IPv6TcpAddress); - t6->options = htonl (TCP_OPTIONS_NONE); - t6->t6_port = s6->sin6_port; - GNUNET_memcpy (&t6->ipv6_addr, &s6->sin6_addr, sizeof(struct in6_addr)); - session->address = GNUNET_HELLO_address_allocate (&tcp_nat_probe->clientIdentity, - PLUGIN_NAME, - &t6, - sizeof(struct IPv6TcpAddress), - GNUNET_HELLO_ADDRESS_INFO_NONE); - break; - default: - GNUNET_break_op(0); - LOG(GNUNET_ERROR_TYPE_DEBUG, - "Bad address for incoming connection!\n"); - GNUNET_free(vaddr); - GNUNET_SERVER_receive_done (client, - GNUNET_SYSERR); - tcp_plugin_disconnect_session (plugin, - session); - return; - } - GNUNET_free (vaddr); - GNUNET_break (NULL == session->client); - session->client = client; - GNUNET_STATISTICS_update (plugin->env->stats, - gettext_noop ("# TCP sessions active"), - 1, - GNUNET_NO); - process_pending_messages (session); - GNUNET_SERVER_receive_done (client, - GNUNET_OK); -} - - -/** - * We've received a welcome from this peer via TCP. Possibly create a - * fresh client record and send back our welcome. - * - * @param cls closure - * @param client identification of the client - * @param message the actual message - */ -static void -handle_tcp_welcome (void *cls, - struct GNUNET_SERVER_Client *client, - const struct GNUNET_MessageHeader *message) -{ - struct Plugin *plugin = cls; - const struct WelcomeMessage *wm = (const struct WelcomeMessage *) message; - struct GNUNET_HELLO_Address *address; - struct GNUNET_ATS_Session *session; - size_t alen; - void *vaddr; - struct IPv4TcpAddress t4; - struct IPv6TcpAddress t6; - const struct sockaddr_in *s4; - const struct sockaddr_in6 *s6; - - if (0 == memcmp (&wm->clientIdentity, - plugin->env->my_identity, - sizeof(struct GNUNET_PeerIdentity))) - { - /* refuse connections from ourselves */ - if (GNUNET_OK == - GNUNET_SERVER_client_get_address (client, - &vaddr, - &alen)) - { - LOG (GNUNET_ERROR_TYPE_INFO, - "Received WELCOME message from my own identity `%s' on address `%s'\n", - GNUNET_i2s (&wm->clientIdentity), - GNUNET_a2s (vaddr, alen)); - GNUNET_free (vaddr); - } - GNUNET_SERVER_receive_done (client, - GNUNET_SYSERR); - return; - } - - if (GNUNET_OK == - GNUNET_SERVER_client_get_address (client, - &vaddr, - &alen)) - { - LOG(GNUNET_ERROR_TYPE_DEBUG, - "Received WELCOME message from `%s' on address `%s'\n", - GNUNET_i2s (&wm->clientIdentity), - GNUNET_a2s (vaddr, alen)); - GNUNET_free (vaddr); - } - GNUNET_STATISTICS_update (plugin->env->stats, - gettext_noop ("# TCP WELCOME messages received"), - 1, - GNUNET_NO); - session = lookup_session_by_client (plugin, - client); - if (NULL != session) - { - if (GNUNET_OK == - GNUNET_SERVER_client_get_address (client, - &vaddr, - &alen)) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Found existing session %p for peer `%s'\n", - session, - GNUNET_a2s (vaddr, alen)); - GNUNET_free (vaddr); - } - } - else - { - if (GNUNET_OK == - GNUNET_SERVER_client_get_address (client, &vaddr, &alen)) - { - if (alen == sizeof(struct sockaddr_in)) - { - s4 = vaddr; - memset (&t4, '\0', sizeof (t4)); - t4.options = htonl (TCP_OPTIONS_NONE); - t4.t4_port = s4->sin_port; - t4.ipv4_addr = s4->sin_addr.s_addr; - address = GNUNET_HELLO_address_allocate (&wm->clientIdentity, - PLUGIN_NAME, - &t4, - sizeof(t4), - GNUNET_HELLO_ADDRESS_INFO_INBOUND); - } - else if (alen == sizeof(struct sockaddr_in6)) - { - s6 = vaddr; - memset (&t6, '\0', sizeof (t6)); - t6.options = htonl (TCP_OPTIONS_NONE); - t6.t6_port = s6->sin6_port; - GNUNET_memcpy (&t6.ipv6_addr, &s6->sin6_addr, sizeof(struct in6_addr)); - address = GNUNET_HELLO_address_allocate (&wm->clientIdentity, - PLUGIN_NAME, - &t6, - sizeof (t6), - GNUNET_HELLO_ADDRESS_INFO_INBOUND); - } - else - { - GNUNET_break (0); - GNUNET_free_non_null (vaddr); - GNUNET_SERVER_receive_done (client, - GNUNET_SYSERR); - return; - } - session = create_session (plugin, - address, - plugin->env->get_address_type (plugin->env->cls, - vaddr, - alen), - client, - GNUNET_NO); - GNUNET_break (GNUNET_NT_UNSPECIFIED != session->scope); - GNUNET_HELLO_address_free (address); - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Creating new%s session %p for peer `%s' client %p\n", - GNUNET_HELLO_address_check_option (session->address, - GNUNET_HELLO_ADDRESS_INFO_INBOUND) - ? " inbound" : "", - session, - tcp_plugin_address_to_string (plugin, - session->address->address, - session->address->address_length), - client); - GNUNET_free (vaddr); - (void) GNUNET_CONTAINER_multipeermap_put (plugin->sessionmap, - &session->target, - session, - GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); - /* Notify transport and ATS about new session */ - plugin->env->session_start (plugin->env->cls, - session->address, - session, - session->scope); - } - else - { - LOG(GNUNET_ERROR_TYPE_DEBUG, - "Did not obtain TCP socket address for incoming connection\n"); - GNUNET_break(0); - GNUNET_SERVER_receive_done (client, - GNUNET_SYSERR); - return; - } - } - - if (GNUNET_YES != session->expecting_welcome) - { - GNUNET_break_op (0); - GNUNET_SERVER_receive_done (client, - GNUNET_SYSERR); - return; - } - session->last_activity = GNUNET_TIME_absolute_get (); - session->expecting_welcome = GNUNET_NO; - - process_pending_messages (session); - GNUNET_SERVER_client_set_timeout (client, - GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT); - GNUNET_SERVER_receive_done (client, - GNUNET_OK); -} - - -/** - * We've received data for this peer via TCP. Unbox, - * compute latency and forward. - * - * @param cls closure - * @param client identification of the client - * @param message the actual message - */ -static void -handle_tcp_data (void *cls, - struct GNUNET_SERVER_Client *client, - const struct GNUNET_MessageHeader *message) -{ - struct Plugin *plugin = cls; - struct GNUNET_ATS_Session *session; - struct GNUNET_TIME_Relative delay; - uint16_t type; - - type = ntohs (message->type); - if ( (GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_WELCOME == type) || - (GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_NAT_PROBE == type) ) - { - /* We don't want to propagate WELCOME and NAT Probe messages up! */ - GNUNET_SERVER_receive_done (client, - GNUNET_OK); - return; - } - session = lookup_session_by_client (plugin, client); - if (NULL == session) - { - /* No inbound session found */ - void *vaddr = NULL; - size_t alen; - - GNUNET_assert (GNUNET_OK == - GNUNET_SERVER_client_get_address (client, - &vaddr, - &alen)); - LOG (GNUNET_ERROR_TYPE_ERROR, - "Received unexpected %u bytes of type %u from `%s'\n", - (unsigned int) ntohs (message->size), - (unsigned int) ntohs (message->type), - GNUNET_a2s (vaddr, - alen)); - GNUNET_break_op(0); - GNUNET_SERVER_receive_done (client, - GNUNET_SYSERR); - GNUNET_free_non_null (vaddr); - return; - } - if (GNUNET_YES == session->expecting_welcome) - { - /* Session is expecting WELCOME message */ - void *vaddr = NULL; - size_t alen; - - GNUNET_SERVER_client_get_address (client, - &vaddr, - &alen); - LOG (GNUNET_ERROR_TYPE_ERROR, - "Received unexpected %u bytes of type %u from `%s'\n", - (unsigned int) ntohs (message->size), - (unsigned int) ntohs (message->type), - GNUNET_a2s (vaddr, alen)); - GNUNET_break_op(0); - GNUNET_SERVER_receive_done (client, - GNUNET_SYSERR); - GNUNET_free_non_null (vaddr); - return; - } - - session->last_activity = GNUNET_TIME_absolute_get (); - { - void *vaddr = NULL; - size_t alen; - - GNUNET_SERVER_client_get_address (client, - &vaddr, - &alen); - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Passing %u bytes of type %u from `%s' at %s to transport service.\n", - (unsigned int) ntohs (message->size), - (unsigned int) ntohs (message->type), - GNUNET_i2s (&session->target), - GNUNET_a2s (vaddr, alen)); - GNUNET_free_non_null (vaddr); - } - - GNUNET_STATISTICS_update (plugin->env->stats, - gettext_noop ("# bytes received via TCP"), - ntohs (message->size), - GNUNET_NO); - - GNUNET_assert (GNUNET_CONTAINER_multipeermap_contains_value (plugin->sessionmap, - &session->target, - session)); - delay = plugin->env->receive (plugin->env->cls, - session->address, - session, - message); - reschedule_session_timeout (session); - if (0 == delay.rel_value_us) - { - GNUNET_SERVER_receive_done (client, - GNUNET_OK); - } - else - { - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Throttling receiving from `%s' for %s\n", - GNUNET_i2s (&session->target), - GNUNET_STRINGS_relative_time_to_string (delay, - GNUNET_YES)); - GNUNET_SERVER_disable_receive_done_warning (client); - GNUNET_assert (NULL == session->receive_delay_task); - session->receive_delay_task = GNUNET_SCHEDULER_add_delayed (delay, - &delayed_done, - session); - } -} - - -/** - * Function called whenever a peer is connected on the "SERVER" level. - * Increments number of active connections and suspends server if we - * have reached the limit. - * - * @param cls closure - * @param client identification of the client - */ -static void -connect_notify (void *cls, - struct GNUNET_SERVER_Client *client) -{ - struct Plugin *plugin = cls; - - if (NULL == client) - return; - plugin->cur_connections++; - GNUNET_STATISTICS_set (plugin->env->stats, - gettext_noop ("# TCP server connections active"), - plugin->cur_connections, - GNUNET_NO); - GNUNET_STATISTICS_update (plugin->env->stats, - gettext_noop ("# TCP server connect events"), - 1, - GNUNET_NO); - if (plugin->cur_connections != plugin->max_connections) - return; - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - _("TCP connection limit reached, suspending server\n")); - GNUNET_STATISTICS_update (plugin->env->stats, - gettext_noop ("# TCP service suspended"), - 1, - GNUNET_NO); - GNUNET_SERVER_suspend (plugin->server); /* Maximum number of connections rechead */ -} - - -/** - * Function called whenever a peer is disconnected on the "SERVER" - * level. Cleans up the connection, decrements number of active - * connections and if applicable resumes listening. - * - * @param cls closure - * @param client identification of the client - */ -static void -disconnect_notify (void *cls, - struct GNUNET_SERVER_Client *client) -{ - struct Plugin *plugin = cls; - struct GNUNET_ATS_Session *session; - - if (NULL == client) - return; - GNUNET_assert (plugin->cur_connections >= 1); - plugin->cur_connections--; - session = lookup_session_by_client (plugin, - client); - if (NULL == session) - return; /* unknown, nothing to do */ - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Destroying session of `%s' with %s due to network-level disconnect.\n", - GNUNET_i2s (&session->target), - tcp_plugin_address_to_string (session->plugin, - session->address->address, - session->address->address_length)); - - if (plugin->cur_connections == plugin->max_connections) - { - GNUNET_STATISTICS_update (session->plugin->env->stats, - gettext_noop ("# TCP service resumed"), - 1, - GNUNET_NO); - GNUNET_SERVER_resume (plugin->server); /* Resume server */ - } - GNUNET_STATISTICS_set (plugin->env->stats, - gettext_noop ("# TCP server connections active"), - plugin->cur_connections, - GNUNET_NO); - GNUNET_STATISTICS_update (session->plugin->env->stats, - gettext_noop ("# network-level TCP disconnect events"), - 1, - GNUNET_NO); - tcp_plugin_disconnect_session (plugin, - session); -} - - -/** - * We can now send a probe message, copy into buffer to really send. - * - * @param cls closure, a `struct TCPProbeContext` - * @param size max size to copy - * @param buf buffer to copy message to - * @return number of bytes copied into @a buf - */ -static size_t -notify_send_probe (void *cls, - size_t size, - void *buf) -{ - struct TCPProbeContext *tcp_probe_ctx = cls; - struct Plugin *plugin = tcp_probe_ctx->plugin; - size_t ret; - - tcp_probe_ctx->transmit_handle = NULL; - GNUNET_CONTAINER_DLL_remove (plugin->probe_head, - plugin->probe_tail, - tcp_probe_ctx); - if (NULL == buf) - { - GNUNET_CONNECTION_destroy (tcp_probe_ctx->sock); - GNUNET_free(tcp_probe_ctx); - return 0; - } - GNUNET_assert(size >= sizeof(tcp_probe_ctx->message)); - GNUNET_memcpy (buf, - &tcp_probe_ctx->message, - sizeof(tcp_probe_ctx->message)); - GNUNET_SERVER_connect_socket (tcp_probe_ctx->plugin->server, - tcp_probe_ctx->sock); - ret = sizeof(tcp_probe_ctx->message); - GNUNET_free (tcp_probe_ctx); - return ret; -} - - -/** - * Function called by the NAT subsystem suggesting another peer wants - * to connect to us via connection reversal. Try to connect back to the - * given IP. - * - * @param cls closure - * @param addr address to try - * @param addrlen number of bytes in @a addr - */ -static void -try_connection_reversal (void *cls, - const struct sockaddr *addr, - socklen_t addrlen) -{ - struct Plugin *plugin = cls; - struct GNUNET_CONNECTION_Handle *sock; - struct TCPProbeContext *tcp_probe_ctx; - - /** - * We have received an ICMP response, ostensibly from a peer - * that wants to connect to us! Send a message to establish a connection. - */ - sock = GNUNET_CONNECTION_create_from_sockaddr (AF_INET, - addr, - addrlen); - if (NULL == sock) - { - /* failed for some odd reason (out of sockets?); ignore attempt */ - return; - } - - tcp_probe_ctx = GNUNET_new (struct TCPProbeContext); - tcp_probe_ctx->message.header.size - = htons (sizeof (struct TCP_NAT_ProbeMessage)); - tcp_probe_ctx->message.header.type - = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_NAT_PROBE); - tcp_probe_ctx->message.clientIdentity - = *plugin->env->my_identity; - tcp_probe_ctx->plugin = plugin; - tcp_probe_ctx->sock = sock; - GNUNET_CONTAINER_DLL_insert (plugin->probe_head, - plugin->probe_tail, - tcp_probe_ctx); - tcp_probe_ctx->transmit_handle - = GNUNET_CONNECTION_notify_transmit_ready (sock, - ntohs (tcp_probe_ctx->message.header.size), - GNUNET_TIME_UNIT_FOREVER_REL, - ¬ify_send_probe, - tcp_probe_ctx); -} - - -/** - * Function obtain the network type for a session - * - * @param cls closure (`struct Plugin *`) - * @param session the session - * @return the network type in HBO or #GNUNET_SYSERR - */ -static enum GNUNET_NetworkType -tcp_plugin_get_network (void *cls, - struct GNUNET_ATS_Session *session) -{ - return session->scope; -} - - -/** - * Function obtain the network type for an address. - * - * @param cls closure (`struct Plugin *`) - * @param address the address - * @return the network type - */ -static enum GNUNET_NetworkType -tcp_plugin_get_network_for_address (void *cls, - const struct GNUNET_HELLO_Address *address) -{ - struct Plugin *plugin = cls; - size_t addrlen; - struct sockaddr_in a4; - struct sockaddr_in6 a6; - const struct IPv4TcpAddress *t4; - const struct IPv6TcpAddress *t6; - const void *sb; - size_t sbs; - - addrlen = address->address_length; - if (addrlen == sizeof(struct IPv6TcpAddress)) - { - GNUNET_assert (NULL != address->address); /* make static analysis happy */ - t6 = address->address; - memset (&a6, 0, sizeof(a6)); -#if HAVE_SOCKADDR_IN_SIN_LEN - a6.sin6_len = sizeof (a6); -#endif - a6.sin6_family = AF_INET6; - a6.sin6_port = t6->t6_port; - GNUNET_memcpy (&a6.sin6_addr, &t6->ipv6_addr, sizeof(struct in6_addr)); - sb = &a6; - sbs = sizeof(a6); - } - else if (addrlen == sizeof(struct IPv4TcpAddress)) - { - GNUNET_assert (NULL != address->address); /* make static analysis happy */ - t4 = address->address; - memset (&a4, 0, sizeof(a4)); -#if HAVE_SOCKADDR_IN_SIN_LEN - a4.sin_len = sizeof (a4); -#endif - a4.sin_family = AF_INET; - a4.sin_port = t4->t4_port; - a4.sin_addr.s_addr = t4->ipv4_addr; - sb = &a4; - sbs = sizeof(a4); - } - else - { - GNUNET_break (0); - return GNUNET_NT_UNSPECIFIED; - } - return plugin->env->get_address_type (plugin->env->cls, - sb, - sbs); -} - - -/** - * Return information about the given session to the - * monitor callback. - * - * @param cls the `struct Plugin` with the monitor callback (`sic`) - * @param peer peer we send information about - * @param value our `struct GNUNET_ATS_Session` to send information about - * @return #GNUNET_OK (continue to iterate) - */ -static int -send_session_info_iter (void *cls, - const struct GNUNET_PeerIdentity *peer, - void *value) -{ - struct Plugin *plugin = cls; - struct GNUNET_ATS_Session *session = value; - - notify_session_monitor (plugin, - session, - GNUNET_TRANSPORT_SS_INIT); - /* FIXME: cannot tell if this is up or not from current - session state... */ - notify_session_monitor (plugin, - session, - GNUNET_TRANSPORT_SS_UP); - return GNUNET_OK; -} - - -/** - * Begin monitoring sessions of a plugin. There can only - * be one active monitor per plugin (i.e. if there are - * multiple monitors, the transport service needs to - * multiplex the generated events over all of them). - * - * @param cls closure of the plugin - * @param sic callback to invoke, NULL to disable monitor; - * plugin will being by iterating over all active - * sessions immediately and then enter monitor mode - * @param sic_cls closure for @a sic - */ -static void -tcp_plugin_setup_monitor (void *cls, - GNUNET_TRANSPORT_SessionInfoCallback sic, - void *sic_cls) -{ - struct Plugin *plugin = cls; - - plugin->sic = sic; - plugin->sic_cls = sic_cls; - if (NULL != sic) - { - GNUNET_CONTAINER_multipeermap_iterate (plugin->sessionmap, - &send_session_info_iter, - plugin); - /* signal end of first iteration */ - sic (sic_cls, NULL, NULL); - } -} - - -/** - * Entry point for the plugin. - * - * @param cls closure, the `struct GNUNET_TRANSPORT_PluginEnvironment *` - * @return the `struct GNUNET_TRANSPORT_PluginFunctions *` or NULL on error - */ -void * -libgnunet_plugin_transport_xt_init (void *cls) -{ - static const struct GNUNET_SERVER_MessageHandler my_handlers[] = { - { &handle_tcp_welcome, NULL, - GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_WELCOME, - sizeof(struct WelcomeMessage) }, - { &handle_tcp_nat_probe, NULL, - GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_NAT_PROBE, - sizeof(struct TCP_NAT_ProbeMessage) }, - { &handle_tcp_data, NULL, - GNUNET_MESSAGE_TYPE_ALL, 0 }, - { NULL, NULL, 0, 0 } - }; - struct GNUNET_TRANSPORT_PluginEnvironment *env = cls; - struct GNUNET_TRANSPORT_PluginFunctions *api; - struct Plugin *plugin; - struct LEGACY_SERVICE_Context *service; - unsigned long long aport; - unsigned long long bport; - unsigned long long max_connections; - unsigned int i; - struct GNUNET_TIME_Relative idle_timeout; -#ifdef TCP_STEALTH - struct GNUNET_NETWORK_Handle *const*lsocks; -#endif - int ret; - int ret_s; - struct sockaddr **addrs; - socklen_t *addrlens; - - if (NULL == env->receive) - { - /* run in 'stub' mode (i.e. as part of gnunet-peerinfo), don't fully - initialze the plugin or the API */ - api = GNUNET_new (struct GNUNET_TRANSPORT_PluginFunctions); - api->cls = NULL; - api->address_pretty_printer = &tcp_plugin_address_pretty_printer; - api->address_to_string = &tcp_plugin_address_to_string; - api->string_to_address = &tcp_plugin_string_to_address; - return api; - } - - GNUNET_assert (NULL != env->cfg); - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_number (env->cfg, - "transport-xt", - "MAX_CONNECTIONS", - &max_connections)) - max_connections = 128; - - aport = 0; - if ((GNUNET_OK != - GNUNET_CONFIGURATION_get_value_number (env->cfg, - "transport-xt", - "PORT", &bport)) || - (bport > 65535) || - ((GNUNET_OK == - GNUNET_CONFIGURATION_get_value_number (env->cfg, - "transport-xt", - "ADVERTISED-PORT", &aport)) && - (aport > 65535) )) - { - LOG(GNUNET_ERROR_TYPE_ERROR, - _("Require valid port number for service `%s' in configuration!\n"), - "transport-xt"); - return NULL ; - } - if (0 == aport) - aport = bport; - if (0 == bport) - aport = 0; - if (0 != bport) - { - service = LEGACY_SERVICE_start ("transport-xt", - env->cfg, - LEGACY_SERVICE_OPTION_NONE); - if (NULL == service) - { - LOG (GNUNET_ERROR_TYPE_WARNING, - _("Failed to start service.\n")); - return NULL; - } - } - else - service = NULL; - - api = NULL; - plugin = GNUNET_new (struct Plugin); - plugin->sessionmap = GNUNET_CONTAINER_multipeermap_create (max_connections, - GNUNET_YES); - plugin->max_connections = max_connections; - plugin->open_port = bport; - plugin->adv_port = aport; - plugin->env = env; - plugin->my_welcome.header.size = htons (sizeof(struct WelcomeMessage)); - plugin->my_welcome.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_WELCOME); - plugin->my_welcome.clientIdentity = *plugin->env->my_identity; - - if ( (NULL != service) && - (GNUNET_YES == - GNUNET_CONFIGURATION_get_value_yesno (env->cfg, - "transport-xt", - "TCP_STEALTH")) ) - { -#ifdef TCP_STEALTH - plugin->myoptions |= TCP_OPTIONS_TCP_STEALTH; - lsocks = LEGACY_SERVICE_get_listen_sockets (service); - if (NULL != lsocks) - { - uint32_t len = sizeof (struct WelcomeMessage); - - for (i=0;NULL!=lsocks[i];i++) - { - if ( (GNUNET_OK != - GNUNET_NETWORK_socket_setsockopt (lsocks[i], - IPPROTO_TCP, - TCP_STEALTH, - env->my_identity, - sizeof (struct GNUNET_PeerIdentity))) || - (GNUNET_OK != - GNUNET_NETWORK_socket_setsockopt (lsocks[i], - IPPROTO_TCP, - TCP_STEALTH_INTEGRITY_LEN, - &len, - sizeof (len))) ) - { - /* TCP STEALTH not supported by kernel */ - GNUNET_assert (0 == i); - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - _("TCP_STEALTH not supported on this platform.\n")); - goto die; - } - } - } -#else - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - _("TCP_STEALTH not supported on this platform.\n")); - goto die; -#endif - } - - if ( (NULL != service) && - (GNUNET_SYSERR != - (ret_s = - get_server_addresses ("transport-xt", - env->cfg, - &addrs, - &addrlens)))) - { - for (ret = ret_s-1; ret >= 0; ret--) - LOG (GNUNET_ERROR_TYPE_INFO, - "Binding to address `%s'\n", - GNUNET_a2s (addrs[ret], addrlens[ret])); - plugin->nat - = GNUNET_NAT_register (env->cfg, - "transport-xt", - IPPROTO_TCP, - (unsigned int) ret_s, - (const struct sockaddr **) addrs, - addrlens, - &tcp_nat_port_map_callback, - &try_connection_reversal, - plugin); - for (ret = ret_s -1; ret >= 0; ret--) - GNUNET_free (addrs[ret]); - GNUNET_free_non_null (addrs); - GNUNET_free_non_null (addrlens); - } - else - { - plugin->nat = GNUNET_NAT_register (plugin->env->cfg, - "transport-xt", - IPPROTO_TCP, - 0, - NULL, - NULL, - NULL, - &try_connection_reversal, - plugin); - } - api = GNUNET_new (struct GNUNET_TRANSPORT_PluginFunctions); - api->cls = plugin; - api->send = &tcp_plugin_send; - api->get_session = &tcp_plugin_get_session; - api->disconnect_session = &tcp_plugin_disconnect_session; - api->query_keepalive_factor = &tcp_plugin_query_keepalive_factor; - api->disconnect_peer = &tcp_plugin_disconnect; - api->address_pretty_printer = &tcp_plugin_address_pretty_printer; - api->check_address = &tcp_plugin_check_address; - api->address_to_string = &tcp_plugin_address_to_string; - api->string_to_address = &tcp_plugin_string_to_address; - api->get_network = &tcp_plugin_get_network; - api->get_network_for_address = &tcp_plugin_get_network_for_address; - api->update_session_timeout = &tcp_plugin_update_session_timeout; - api->update_inbound_delay = &tcp_plugin_update_inbound_delay; - api->setup_monitor = &tcp_plugin_setup_monitor; - plugin->service = service; - if (NULL != service) - { - plugin->server = LEGACY_SERVICE_get_server (service); - } - else - { - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_time (env->cfg, - "transport-xt", - "TIMEOUT", - &idle_timeout)) - { - GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, - "transport-xt", - "TIMEOUT"); - goto die; - } - plugin->server - = GNUNET_SERVER_create_with_sockets (NULL, - plugin, - NULL, - idle_timeout, - GNUNET_YES); - } - plugin->handlers = GNUNET_malloc (sizeof (my_handlers)); - GNUNET_memcpy (plugin->handlers, - my_handlers, - sizeof(my_handlers)); - for (i = 0;i < sizeof(my_handlers) / sizeof(struct GNUNET_SERVER_MessageHandler);i++) - plugin->handlers[i].callback_cls = plugin; - - GNUNET_SERVER_add_handlers (plugin->server, - plugin->handlers); - GNUNET_SERVER_connect_notify (plugin->server, - &connect_notify, - plugin); - GNUNET_SERVER_disconnect_notify (plugin->server, - &disconnect_notify, - plugin); - plugin->nat_wait_conns = GNUNET_CONTAINER_multipeermap_create (16, - GNUNET_YES); - if (0 != bport) - LOG (GNUNET_ERROR_TYPE_INFO, - _("XT transport listening on port %llu\n"), - bport); - else - LOG (GNUNET_ERROR_TYPE_INFO, - _("XT transport not listening on any port (client only)\n")); - if ( (aport != bport) && - (0 != bport) ) - LOG (GNUNET_ERROR_TYPE_INFO, - _("XT transport advertises itself as being on port %llu\n"), - aport); - /* Initially set connections to 0 */ - GNUNET_STATISTICS_set (plugin->env->stats, - gettext_noop ("# XT sessions active"), - 0, - GNUNET_NO); - return api; - - die: - if (NULL != plugin->nat) - GNUNET_NAT_unregister (plugin->nat); - GNUNET_CONTAINER_multipeermap_destroy (plugin->sessionmap); - if (NULL != service) - LEGACY_SERVICE_stop (service); - GNUNET_free (plugin); - GNUNET_free_non_null (api); - return NULL; -} - - -/** - * Exit point from the plugin. - * - * @param cls the `struct GNUNET_TRANSPORT_PluginFunctions` - * @return NULL - */ -void * -libgnunet_plugin_transport_xt_done (void *cls) -{ - struct GNUNET_TRANSPORT_PluginFunctions *api = cls; - struct Plugin *plugin = api->cls; - struct TCPProbeContext *tcp_probe; - struct PrettyPrinterContext *cur; - struct PrettyPrinterContext *next; - - if (NULL == plugin) - { - GNUNET_free(api); - return NULL ; - } - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Shutting down XT plugin\n"); - - /* Removing leftover sessions */ - GNUNET_CONTAINER_multipeermap_iterate (plugin->sessionmap, - &session_disconnect_it, - plugin); - /* Removing leftover NAT sessions */ - GNUNET_CONTAINER_multipeermap_iterate (plugin->nat_wait_conns, - &session_disconnect_it, - plugin); - - for (cur = plugin->ppc_dll_head; NULL != cur; cur = next) - { - next = cur->next; - GNUNET_CONTAINER_DLL_remove (plugin->ppc_dll_head, - plugin->ppc_dll_tail, - cur); - GNUNET_RESOLVER_request_cancel (cur->resolver_handle); - cur->asc (cur->asc_cls, - NULL, - GNUNET_OK); - GNUNET_free (cur); - } - - if (NULL != plugin->service) - LEGACY_SERVICE_stop (plugin->service); - else - GNUNET_SERVER_destroy (plugin->server); - GNUNET_free (plugin->handlers); - if (NULL != plugin->nat) - GNUNET_NAT_unregister (plugin->nat); - while (NULL != (tcp_probe = plugin->probe_head)) - { - GNUNET_CONTAINER_DLL_remove (plugin->probe_head, - plugin->probe_tail, - tcp_probe); - GNUNET_CONNECTION_destroy (tcp_probe->sock); - GNUNET_free (tcp_probe); - } - GNUNET_CONTAINER_multipeermap_destroy (plugin->nat_wait_conns); - GNUNET_CONTAINER_multipeermap_destroy (plugin->sessionmap); - GNUNET_break (0 == plugin->cur_connections); - GNUNET_free (plugin); - GNUNET_free (api); - return NULL; -} - -/* end of plugin_transport_xt.c */ diff --git a/src/transport/plugin_transport_xu.c b/src/transport/plugin_transport_xu.c deleted file mode 100644 index b716c6878..000000000 --- a/src/transport/plugin_transport_xu.c +++ /dev/null @@ -1,2492 +0,0 @@ -/* - This file is part of GNUnet - Copyright (C) 2010-2017 GNUnet e.V. - - GNUnet is free software: you can redistribute it and/or modify it - under the terms of the GNU Affero General Public License as published - by the Free Software Foundation, either version 3 of the License, - or (at your option) any later version. - - GNUnet is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see . - - SPDX-License-Identifier: AGPL3.0-or-later - */ - -/** - * @file transport/plugin_transport_xu.c - * @brief Implementation of the XU transport protocol - * @author Christian Grothoff - * @author Nathan Evans - * @author Matthias Wachs - */ -#include "platform.h" -#include "plugin_transport_xu.h" -#include "gnunet_hello_lib.h" -#include "gnunet_util_lib.h" -#include "gnunet_fragmentation_lib.h" -#include "gnunet_nat_service.h" -#include "gnunet_protocols.h" -#include "gnunet_resolver_service.h" -#include "gnunet_signatures.h" -#include "gnunet_constants.h" -#include "gnunet_statistics_service.h" -#include "gnunet_transport_service.h" -#include "gnunet_transport_plugin.h" -#include "transport.h" - -#define LOG(kind,...) GNUNET_log_from (kind, "transport-xu", __VA_ARGS__) - -/** - * After how much inactivity should a XU session time out? - */ -#define XU_SESSION_TIME_OUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60) - - -/** - * XU Message-Packet header (after defragmentation). - */ -struct XUMessage -{ - /** - * Message header. - */ - struct GNUNET_MessageHeader header; - - /** - * Always zero for now. - */ - uint32_t reserved; - - /** - * What is the identity of the sender - */ - struct GNUNET_PeerIdentity sender; - -}; - - -/** - * Closure for #append_port(). - */ -struct PrettyPrinterContext -{ - /** - * DLL - */ - struct PrettyPrinterContext *next; - - /** - * DLL - */ - struct PrettyPrinterContext *prev; - - /** - * Our plugin. - */ - struct Plugin *plugin; - - /** - * Resolver handle - */ - struct GNUNET_RESOLVER_RequestHandle *resolver_handle; - - /** - * Function to call with the result. - */ - GNUNET_TRANSPORT_AddressStringCallback asc; - - /** - * Clsoure for @e asc. - */ - void *asc_cls; - - /** - * Timeout task - */ - struct GNUNET_SCHEDULER_Task *timeout_task; - - /** - * Is this an IPv6 address? - */ - int ipv6; - - /** - * Options - */ - uint32_t options; - - /** - * Port to add after the IP address. - */ - uint16_t port; - -}; - - -/** - * Session with another peer. - */ -struct GNUNET_ATS_Session -{ - /** - * Which peer is this session for? - */ - struct GNUNET_PeerIdentity target; - - /** - * Tokenizer for inbound messages. - */ - struct GNUNET_MessageStreamTokenizer *mst; - - /** - * Plugin this session belongs to. - */ - struct Plugin *plugin; - - /** - * Session timeout task - */ - struct GNUNET_SCHEDULER_Task *timeout_task; - - /** - * When does this session time out? - */ - struct GNUNET_TIME_Absolute timeout; - - /** - * What time did we last transmit? - */ - struct GNUNET_TIME_Absolute last_transmit_time; - - /** - * expected delay for ACKs - */ - struct GNUNET_TIME_Relative last_expected_ack_delay; - - /** - * desired delay between XU messages - */ - struct GNUNET_TIME_Relative last_expected_msg_delay; - - /** - */ - struct GNUNET_TIME_Relative flow_delay_for_other_peer; - struct GNUNET_TIME_Relative flow_delay_from_other_peer; - - /** - * Our own address. - */ - struct GNUNET_HELLO_Address *address; - - /** - * Number of bytes waiting for transmission to this peer. - */ - unsigned long long bytes_in_queue; - - /** - * Number of messages waiting for transmission to this peer. - */ - unsigned int msgs_in_queue; - - /** - * Reference counter to indicate that this session is - * currently being used and must not be destroyed; - * setting @e in_destroy will destroy it as soon as - * possible. - */ - unsigned int rc; - - /** - * Network type of the address. - */ - enum GNUNET_NetworkType scope; - - /** - * Is this session about to be destroyed (sometimes we cannot - * destroy a session immediately as below us on the stack - * there might be code that still uses it; in this case, - * @e rc is non-zero). - */ - int in_destroy; -}; - - - -/** - * If a session monitor is attached, notify it about the new - * session state. - * - * @param plugin our plugin - * @param session session that changed state - * @param state new state of the session - */ -static void -notify_session_monitor (struct Plugin *plugin, - struct GNUNET_ATS_Session *session, - enum GNUNET_TRANSPORT_SessionState state) -{ - struct GNUNET_TRANSPORT_SessionInfo info; - - if (NULL == plugin->sic) - return; - if (GNUNET_YES == session->in_destroy) - return; /* already destroyed, just RC>0 left-over actions */ - memset (&info, - 0, - sizeof (info)); - info.state = state; - info.is_inbound = GNUNET_SYSERR; /* hard to say */ - info.num_msg_pending = session->msgs_in_queue; - info.num_bytes_pending = session->bytes_in_queue; - /* info.receive_delay remains zero as this is not supported by XU - (cannot selectively not receive from 'some' peer while continuing - to receive from others) */ - info.session_timeout = session->timeout; - info.address = session->address; - plugin->sic (plugin->sic_cls, - session, - &info); -} - - -/** - * Return information about the given session to the monitor callback. - * - * @param cls the `struct Plugin` with the monitor callback (`sic`) - * @param peer peer we send information about - * @param value our `struct GNUNET_ATS_Session` to send information about - * @return #GNUNET_OK (continue to iterate) - */ -static int -send_session_info_iter (void *cls, - const struct GNUNET_PeerIdentity *peer, - void *value) -{ - struct Plugin *plugin = cls; - struct GNUNET_ATS_Session *session = value; - - (void) peer; - notify_session_monitor (plugin, - session, - GNUNET_TRANSPORT_SS_INIT); - notify_session_monitor (plugin, - session, - GNUNET_TRANSPORT_SS_UP); - return GNUNET_OK; -} - - -/** - * Begin monitoring sessions of a plugin. There can only - * be one active monitor per plugin (i.e. if there are - * multiple monitors, the transport service needs to - * multiplex the generated events over all of them). - * - * @param cls closure of the plugin - * @param sic callback to invoke, NULL to disable monitor; - * plugin will being by iterating over all active - * sessions immediately and then enter monitor mode - * @param sic_cls closure for @a sic - */ -static void -xu_plugin_setup_monitor (void *cls, - GNUNET_TRANSPORT_SessionInfoCallback sic, - void *sic_cls) -{ - struct Plugin *plugin = cls; - - plugin->sic = sic; - plugin->sic_cls = sic_cls; - if (NULL != sic) - { - GNUNET_CONTAINER_multipeermap_iterate (plugin->sessions, - &send_session_info_iter, - plugin); - /* signal end of first iteration */ - sic (sic_cls, - NULL, - NULL); - } -} - - -/* ****************** Little Helpers ****************** */ - - -/** - * Function to free last resources associated with a session. - * - * @param s session to free - */ -static void -free_session (struct GNUNET_ATS_Session *s) -{ - if (NULL != s->address) - { - GNUNET_HELLO_address_free (s->address); - s->address = NULL; - } - if (NULL != s->mst) - { - GNUNET_MST_destroy (s->mst); - s->mst = NULL; - } - GNUNET_free (s); -} - - -/** - * Function that is called to get the keepalive factor. - * #GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT is divided by this number to - * calculate the interval between keepalive packets. - * - * @param cls closure with the `struct Plugin` - * @return keepalive factor - */ -static unsigned int -xu_query_keepalive_factor (void *cls) -{ - (void) cls; - return 15; -} - - -/** - * Function obtain the network type for a session - * - * @param cls closure (`struct Plugin *`) - * @param session the session - * @return the network type - */ -static enum GNUNET_NetworkType -xu_plugin_get_network (void *cls, - struct GNUNET_ATS_Session *session) -{ - (void) cls; - return session->scope; -} - - -/** - * Function obtain the network type for an address. - * - * @param cls closure (`struct Plugin *`) - * @param address the address - * @return the network type - */ -static enum GNUNET_NetworkType -xu_plugin_get_network_for_address (void *cls, - const struct GNUNET_HELLO_Address *address) -{ - struct Plugin *plugin = cls; - size_t addrlen; - struct sockaddr_in a4; - struct sockaddr_in6 a6; - const struct IPv4XuAddress *u4; - const struct IPv6XuAddress *u6; - const void *sb; - size_t sbs; - - addrlen = address->address_length; - if (addrlen == sizeof(struct IPv6XuAddress)) - { - GNUNET_assert (NULL != address->address); /* make static analysis happy */ - u6 = address->address; - memset (&a6, 0, sizeof(a6)); -#if HAVE_SOCKADDR_IN_SIN_LEN - a6.sin6_len = sizeof (a6); -#endif - a6.sin6_family = AF_INET6; - a6.sin6_port = u6->u6_port; - GNUNET_memcpy (&a6.sin6_addr, &u6->ipv6_addr, sizeof(struct in6_addr)); - sb = &a6; - sbs = sizeof(a6); - } - else if (addrlen == sizeof(struct IPv4XuAddress)) - { - GNUNET_assert (NULL != address->address); /* make static analysis happy */ - u4 = address->address; - memset (&a4, 0, sizeof(a4)); -#if HAVE_SOCKADDR_IN_SIN_LEN - a4.sin_len = sizeof (a4); -#endif - a4.sin_family = AF_INET; - a4.sin_port = u4->u4_port; - a4.sin_addr.s_addr = u4->ipv4_addr; - sb = &a4; - sbs = sizeof(a4); - } - else - { - GNUNET_break (0); - return GNUNET_NT_UNSPECIFIED; - } - return plugin->env->get_address_type (plugin->env->cls, - sb, - sbs); -} - - -/* ******************* Event loop ******************** */ - -/** - * We have been notified that our readset has something to read. We don't - * know which socket needs to be read, so we have to check each one - * Then reschedule this function to be called again once more is available. - * - * @param cls the plugin handle - */ -static void -xu_plugin_select_v4 (void *cls); - - -/** - * We have been notified that our readset has something to read. We don't - * know which socket needs to be read, so we have to check each one - * Then reschedule this function to be called again once more is available. - * - * @param cls the plugin handle - */ -static void -xu_plugin_select_v6 (void *cls); - - -/** - * (re)schedule IPv4-select tasks for this plugin. - * - * @param plugin plugin to reschedule - */ -static void -schedule_select_v4 (struct Plugin *plugin) -{ - if ( (GNUNET_YES != plugin->enable_ipv4) || - (NULL == plugin->sockv4) ) - return; - if (NULL != plugin->select_task_v4) - GNUNET_SCHEDULER_cancel (plugin->select_task_v4); - plugin->select_task_v4 - = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, - plugin->sockv4, - &xu_plugin_select_v4, - plugin); -} - - -/** - * (re)schedule IPv6-select tasks for this plugin. - * - * @param plugin plugin to reschedule - */ -static void -schedule_select_v6 (struct Plugin *plugin) -{ - if ( (GNUNET_YES != plugin->enable_ipv6) || - (NULL == plugin->sockv6) ) - return; - if (NULL != plugin->select_task_v6) - GNUNET_SCHEDULER_cancel (plugin->select_task_v6); - plugin->select_task_v6 - = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, - plugin->sockv6, - &xu_plugin_select_v6, - plugin); -} - - -/* ******************* Address to string and back ***************** */ - - -/** - * Function called for a quick conversion of the binary address to - * a numeric address. Note that the caller must not free the - * address and that the next call to this function is allowed - * to override the address again. - * - * @param cls closure - * @param addr binary address (a `union XuAddress`) - * @param addrlen length of the @a addr - * @return string representing the same address - */ -const char * -xu_address_to_string (void *cls, - const void *addr, - size_t addrlen) -{ - static char rbuf[INET6_ADDRSTRLEN + 10]; - char buf[INET6_ADDRSTRLEN]; - const void *sb; - struct in_addr a4; - struct in6_addr a6; - const struct IPv4XuAddress *t4; - const struct IPv6XuAddress *t6; - int af; - uint16_t port; - uint32_t options; - - (void) cls; - if (NULL == addr) - { - GNUNET_break_op (0); - return NULL; - } - - if (addrlen == sizeof(struct IPv6XuAddress)) - { - t6 = addr; - af = AF_INET6; - options = ntohl (t6->options); - port = ntohs (t6->u6_port); - a6 = t6->ipv6_addr; - sb = &a6; - } - else if (addrlen == sizeof(struct IPv4XuAddress)) - { - t4 = addr; - af = AF_INET; - options = ntohl (t4->options); - port = ntohs (t4->u4_port); - a4.s_addr = t4->ipv4_addr; - sb = &a4; - } - else - { - GNUNET_break_op (0); - return NULL; - } - inet_ntop (af, - sb, - buf, - INET6_ADDRSTRLEN); - GNUNET_snprintf (rbuf, - sizeof(rbuf), - (af == AF_INET6) - ? "%s.%u.[%s]:%u" - : "%s.%u.%s:%u", - PLUGIN_NAME, - options, - buf, - port); - return rbuf; -} - - -/** - * Function called to convert a string address to a binary address. - * - * @param cls closure (`struct Plugin *`) - * @param addr string address - * @param addrlen length of the address - * @param buf location to store the buffer - * @param added location to store the number of bytes in the buffer. - * If the function returns #GNUNET_SYSERR, its contents are undefined. - * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure - */ -static int -xu_string_to_address (void *cls, - const char *addr, - uint16_t addrlen, - void **buf, - size_t *added) -{ - struct sockaddr_storage socket_address; - char *address; - char *plugin; - char *optionstr; - uint32_t options; - - (void) cls; - /* Format tcp.options.address:port */ - address = NULL; - plugin = NULL; - optionstr = NULL; - - if ((NULL == addr) || (0 == addrlen)) - { - GNUNET_break (0); - return GNUNET_SYSERR; - } - if ('\0' != addr[addrlen - 1]) - { - GNUNET_break (0); - return GNUNET_SYSERR; - } - if (strlen (addr) + 1 != (size_t) addrlen) - { - GNUNET_break (0); - return GNUNET_SYSERR; - } - plugin = GNUNET_strdup (addr); - optionstr = strchr (plugin, '.'); - if (NULL == optionstr) - { - GNUNET_break (0); - GNUNET_free (plugin); - return GNUNET_SYSERR; - } - optionstr[0] = '\0'; - optionstr++; - options = atol (optionstr); - address = strchr (optionstr, '.'); - if (NULL == address) - { - GNUNET_break (0); - GNUNET_free (plugin); - return GNUNET_SYSERR; - } - address[0] = '\0'; - address++; - - if (GNUNET_OK != - GNUNET_STRINGS_to_address_ip (address, - strlen (address), - &socket_address)) - { - GNUNET_break (0); - GNUNET_free (plugin); - return GNUNET_SYSERR; - } - GNUNET_free(plugin); - - switch (socket_address.ss_family) - { - case AF_INET: - { - struct IPv4XuAddress *u4; - const struct sockaddr_in *in4 = (const struct sockaddr_in *) &socket_address; - - u4 = GNUNET_new (struct IPv4XuAddress); - u4->options = htonl (options); - u4->ipv4_addr = in4->sin_addr.s_addr; - u4->u4_port = in4->sin_port; - *buf = u4; - *added = sizeof (struct IPv4XuAddress); - return GNUNET_OK; - } - case AF_INET6: - { - struct IPv6XuAddress *u6; - const struct sockaddr_in6 *in6 = (const struct sockaddr_in6 *) &socket_address; - - u6 = GNUNET_new (struct IPv6XuAddress); - u6->options = htonl (options); - u6->ipv6_addr = in6->sin6_addr; - u6->u6_port = in6->sin6_port; - *buf = u6; - *added = sizeof (struct IPv6XuAddress); - return GNUNET_OK; - } - default: - GNUNET_break (0); - return GNUNET_SYSERR; - } -} - - -/** - * Append our port and forward the result. - * - * @param cls a `struct PrettyPrinterContext *` - * @param hostname result from DNS resolver - */ -static void -append_port (void *cls, - const char *hostname) -{ - struct PrettyPrinterContext *ppc = cls; - struct Plugin *plugin = ppc->plugin; - char *ret; - - if (NULL == hostname) - { - /* Final call, done */ - GNUNET_CONTAINER_DLL_remove (plugin->ppc_dll_head, - plugin->ppc_dll_tail, - ppc); - ppc->resolver_handle = NULL; - ppc->asc (ppc->asc_cls, - NULL, - GNUNET_OK); - GNUNET_free (ppc); - return; - } - if (GNUNET_YES == ppc->ipv6) - GNUNET_asprintf (&ret, - "%s.%u.[%s]:%d", - PLUGIN_NAME, - ppc->options, - hostname, - ppc->port); - else - GNUNET_asprintf (&ret, - "%s.%u.%s:%d", - PLUGIN_NAME, - ppc->options, - hostname, - ppc->port); - ppc->asc (ppc->asc_cls, - ret, - GNUNET_OK); - GNUNET_free (ret); -} - - -/** - * Convert the transports address to a nice, human-readable format. - * - * @param cls closure with the `struct Plugin *` - * @param type name of the transport that generated the address - * @param addr one of the addresses of the host, NULL for the last address - * the specific address format depends on the transport; - * a `union XuAddress` - * @param addrlen length of the address - * @param numeric should (IP) addresses be displayed in numeric form? - * @param timeout after how long should we give up? - * @param asc function to call on each string - * @param asc_cls closure for @a asc - */ -static void -xu_plugin_address_pretty_printer (void *cls, - const char *type, - const void *addr, - size_t addrlen, - int numeric, - struct GNUNET_TIME_Relative timeout, - GNUNET_TRANSPORT_AddressStringCallback asc, - void *asc_cls) -{ - struct Plugin *plugin = cls; - struct PrettyPrinterContext *ppc; - const struct sockaddr *sb; - size_t sbs; - struct sockaddr_in a4; - struct sockaddr_in6 a6; - const struct IPv4XuAddress *u4; - const struct IPv6XuAddress *u6; - uint16_t port; - uint32_t options; - - (void) type; - if (addrlen == sizeof(struct IPv6XuAddress)) - { - u6 = addr; - memset (&a6, - 0, - sizeof (a6)); - a6.sin6_family = AF_INET6; -#if HAVE_SOCKADDR_IN_SIN_LEN - a6.sin6_len = sizeof (a6); -#endif - a6.sin6_port = u6->u6_port; - a6.sin6_addr = u6->ipv6_addr; - port = ntohs (u6->u6_port); - options = ntohl (u6->options); - sb = (const struct sockaddr *) &a6; - sbs = sizeof (a6); - } - else if (addrlen == sizeof (struct IPv4XuAddress)) - { - u4 = addr; - memset (&a4, - 0, - sizeof(a4)); - a4.sin_family = AF_INET; -#if HAVE_SOCKADDR_IN_SIN_LEN - a4.sin_len = sizeof (a4); -#endif - a4.sin_port = u4->u4_port; - a4.sin_addr.s_addr = u4->ipv4_addr; - port = ntohs (u4->u4_port); - options = ntohl (u4->options); - sb = (const struct sockaddr *) &a4; - sbs = sizeof(a4); - } - else - { - /* invalid address */ - GNUNET_break_op (0); - asc (asc_cls, - NULL, - GNUNET_SYSERR); - asc (asc_cls, - NULL, - GNUNET_OK); - return; - } - ppc = GNUNET_new (struct PrettyPrinterContext); - ppc->plugin = plugin; - ppc->asc = asc; - ppc->asc_cls = asc_cls; - ppc->port = port; - ppc->options = options; - if (addrlen == sizeof (struct IPv6XuAddress)) - ppc->ipv6 = GNUNET_YES; - else - ppc->ipv6 = GNUNET_NO; - GNUNET_CONTAINER_DLL_insert (plugin->ppc_dll_head, - plugin->ppc_dll_tail, - ppc); - ppc->resolver_handle - = GNUNET_RESOLVER_hostname_get (sb, - sbs, - ! numeric, - timeout, - &append_port, - ppc); -} - - -/** - * Check if the given port is plausible (must be either our listen - * port or our advertised port). If it is neither, we return - * #GNUNET_SYSERR. - * - * @param plugin global variables - * @param in_port port number to check - * @return #GNUNET_OK if port is either our open or advertised port - */ -static int -check_port (const struct Plugin *plugin, - uint16_t in_port) -{ - if ( (plugin->port == in_port) || - (plugin->aport == in_port) ) - return GNUNET_OK; - return GNUNET_SYSERR; -} - - -/** - * Function that will be called to check if a binary address for this - * plugin is well-formed and corresponds to an address for THIS peer - * (as per our configuration). Naturally, if absolutely necessary, - * plugins can be a bit conservative in their answer, but in general - * plugins should make sure that the address does not redirect - * traffic to a 3rd party that might try to man-in-the-middle our - * traffic. - * - * @param cls closure, should be our handle to the Plugin - * @param addr pointer to a `union XuAddress` - * @param addrlen length of @a addr - * @return #GNUNET_OK if this is a plausible address for this peer - * and transport, #GNUNET_SYSERR if not - */ -static int -xu_plugin_check_address (void *cls, - const void *addr, - size_t addrlen) -{ - struct Plugin *plugin = cls; - const struct IPv4XuAddress *v4; - const struct IPv6XuAddress *v6; - - if (sizeof(struct IPv4XuAddress) == addrlen) - { - struct sockaddr_in s4; - - v4 = (const struct IPv4XuAddress *) addr; - if (GNUNET_OK != check_port (plugin, - ntohs (v4->u4_port))) - return GNUNET_SYSERR; - memset (&s4, 0, sizeof (s4)); - s4.sin_family = AF_INET; -#if HAVE_SOCKADDR_IN_SIN_LEN - s4.sin_len = sizeof (s4); -#endif - s4.sin_port = v4->u4_port; - s4.sin_addr.s_addr = v4->ipv4_addr; - - if (GNUNET_OK != - GNUNET_NAT_test_address (plugin->nat, - &s4, - sizeof (struct sockaddr_in))) - return GNUNET_SYSERR; - } - else if (sizeof(struct IPv6XuAddress) == addrlen) - { - struct sockaddr_in6 s6; - - v6 = (const struct IPv6XuAddress *) addr; - if (IN6_IS_ADDR_LINKLOCAL (&v6->ipv6_addr)) - return GNUNET_OK; /* plausible, if unlikely... */ - memset (&s6, 0, sizeof (s6)); - s6.sin6_family = AF_INET6; -#if HAVE_SOCKADDR_IN_SIN_LEN - s6.sin6_len = sizeof (s6); -#endif - s6.sin6_port = v6->u6_port; - s6.sin6_addr = v6->ipv6_addr; - - if (GNUNET_OK != - GNUNET_NAT_test_address (plugin->nat, - &s6, - sizeof(struct sockaddr_in6))) - return GNUNET_SYSERR; - } - else - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - return GNUNET_OK; -} - - -/** - * Our external IP address/port mapping has changed. - * - * @param cls closure, the `struct Plugin` - * @param add_remove #GNUNET_YES to mean the new public IP address, - * #GNUNET_NO to mean the previous (now invalid) one - * @param ac address class the address belongs to - * @param addr either the previous or the new public IP address - * @param addrlen actual length of the @a addr - */ -static void -xu_nat_port_map_callback (void *cls, - int add_remove, - enum GNUNET_NAT_AddressClass ac, - const struct sockaddr *addr, - socklen_t addrlen) -{ - struct Plugin *plugin = cls; - struct GNUNET_HELLO_Address *address; - struct IPv4XuAddress u4; - struct IPv6XuAddress u6; - void *arg; - size_t args; - - if (GNUNET_NAT_AC_LOOPBACK == ac) - return; - if (GNUNET_NAT_AC_LAN == ac) - return; - if (GNUNET_NAT_AC_LAN_PRIVATE == ac) - return; - LOG (GNUNET_ERROR_TYPE_DEBUG, - (GNUNET_YES == add_remove) - ? "NAT notification to add address `%s'\n" - : "NAT notification to remove address `%s'\n", - GNUNET_a2s (addr, - addrlen)); - /* convert 'address' to our internal format */ - switch (addr->sa_family) - { - case AF_INET: - { - const struct sockaddr_in *i4; - - GNUNET_assert (sizeof(struct sockaddr_in) == addrlen); - i4 = (const struct sockaddr_in *) addr; - if (0 == ntohs (i4->sin_port)) - return; /* Port = 0 means unmapped, ignore these for XU. */ - memset (&u4, - 0, - sizeof(u4)); - u4.options = htonl (plugin->myoptions); - u4.ipv4_addr = i4->sin_addr.s_addr; - u4.u4_port = i4->sin_port; - arg = &u4; - args = sizeof (struct IPv4XuAddress); - break; - } - case AF_INET6: - { - const struct sockaddr_in6 *i6; - - GNUNET_assert (sizeof(struct sockaddr_in6) == addrlen); - i6 = (const struct sockaddr_in6 *) addr; - if (0 == ntohs (i6->sin6_port)) - return; /* Port = 0 means unmapped, ignore these for XU. */ - memset (&u6, - 0, - sizeof(u6)); - u6.options = htonl (plugin->myoptions); - u6.ipv6_addr = i6->sin6_addr; - u6.u6_port = i6->sin6_port; - arg = &u6; - args = sizeof (struct IPv6XuAddress); - break; - } - default: - GNUNET_break (0); - return; - } - /* modify our published address list */ - /* TODO: use 'ac' here in the future... */ - address = GNUNET_HELLO_address_allocate (plugin->env->my_identity, - PLUGIN_NAME, - arg, - args, - GNUNET_HELLO_ADDRESS_INFO_NONE); - plugin->env->notify_address (plugin->env->cls, - add_remove, - address); - GNUNET_HELLO_address_free (address); -} - - -/* ********************* Finding sessions ******************* */ - - -/** - * Closure for #session_cmp_it(). - */ -struct GNUNET_ATS_SessionCompareContext -{ - /** - * Set to session matching the address. - */ - struct GNUNET_ATS_Session *res; - - /** - * Address we are looking for. - */ - const struct GNUNET_HELLO_Address *address; -}; - - -/** - * Find a session with a matching address. - * - * @param cls the `struct GNUNET_ATS_SessionCompareContext *` - * @param key peer identity (unused) - * @param value the `struct GNUNET_ATS_Session *` - * @return #GNUNET_NO if we found the session, #GNUNET_OK if not - */ -static int -session_cmp_it (void *cls, - const struct GNUNET_PeerIdentity *key, - void *value) -{ - struct GNUNET_ATS_SessionCompareContext *cctx = cls; - struct GNUNET_ATS_Session *s = value; - - (void) key; - if (0 == GNUNET_HELLO_address_cmp (s->address, - cctx->address)) - { - GNUNET_assert (GNUNET_NO == s->in_destroy); - cctx->res = s; - return GNUNET_NO; - } - return GNUNET_OK; -} - - -/** - * Locate an existing session the transport service is using to - * send data to another peer. Performs some basic sanity checks - * on the address and then tries to locate a matching session. - * - * @param cls the plugin - * @param address the address we should locate the session by - * @return the session if it exists, or NULL if it is not found - */ -static struct GNUNET_ATS_Session * -xu_plugin_lookup_session (void *cls, - const struct GNUNET_HELLO_Address *address) -{ - struct Plugin *plugin = cls; - const struct IPv6XuAddress *xu_a6; - const struct IPv4XuAddress *xu_a4; - struct GNUNET_ATS_SessionCompareContext cctx; - - if (NULL == address->address) - { - GNUNET_break (0); - return NULL; - } - if (sizeof(struct IPv4XuAddress) == address->address_length) - { - if (NULL == plugin->sockv4) - return NULL; - xu_a4 = (const struct IPv4XuAddress *) address->address; - if (0 == xu_a4->u4_port) - { - GNUNET_break (0); - return NULL; - } - } - else if (sizeof(struct IPv6XuAddress) == address->address_length) - { - if (NULL == plugin->sockv6) - return NULL; - xu_a6 = (const struct IPv6XuAddress *) address->address; - if (0 == xu_a6->u6_port) - { - GNUNET_break (0); - return NULL; - } - } - else - { - GNUNET_break (0); - return NULL; - } - - /* check if session already exists */ - cctx.address = address; - cctx.res = NULL; - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Looking for existing session for peer `%s' with address `%s'\n", - GNUNET_i2s (&address->peer), - xu_address_to_string (plugin, - address->address, - address->address_length)); - GNUNET_CONTAINER_multipeermap_get_multiple (plugin->sessions, - &address->peer, - &session_cmp_it, - &cctx); - if (NULL == cctx.res) - return NULL; - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Found existing session %p\n", - cctx.res); - return cctx.res; -} - - -/* ********************** Timeout ****************** */ - - -/** - * Increment session timeout due to activity. - * - * @param s session to reschedule timeout activity for - */ -static void -reschedule_session_timeout (struct GNUNET_ATS_Session *s) -{ - if (GNUNET_YES == s->in_destroy) - return; - GNUNET_assert (NULL != s->timeout_task); - s->timeout = GNUNET_TIME_relative_to_absolute (XU_SESSION_TIME_OUT); -} - - - -/** - * Function that will be called whenever the transport service wants to - * notify the plugin that a session is still active and in use and - * therefore the session timeout for this session has to be updated - * - * @param cls closure with the `struct Plugin` - * @param peer which peer was the session for - * @param session which session is being updated - */ -static void -xu_plugin_update_session_timeout (void *cls, - const struct GNUNET_PeerIdentity *peer, - struct GNUNET_ATS_Session *session) -{ - struct Plugin *plugin = cls; - - if (GNUNET_YES != - GNUNET_CONTAINER_multipeermap_contains_value (plugin->sessions, - peer, - session)) - { - GNUNET_break (0); - return; - } - /* Reschedule session timeout */ - reschedule_session_timeout (session); -} - - -/* ************************* Sending ************************ */ - - -/** - * We failed to transmit a message via XU. Generate - * a descriptive error message. - * - * @param plugin our plugin - * @param sa target address we were trying to reach - * @param slen number of bytes in @a sa - * @param error the errno value returned from the sendto() call - */ -static void -analyze_send_error (struct Plugin *plugin, - const struct sockaddr *sa, - socklen_t slen, - int error) -{ - enum GNUNET_NetworkType type; - - type = plugin->env->get_address_type (plugin->env->cls, - sa, - slen); - if ( ( (GNUNET_NT_LAN == type) || - (GNUNET_NT_WAN == type) ) && - ( (ENETUNREACH == errno) || - (ENETDOWN == errno) ) ) - { - if (slen == sizeof (struct sockaddr_in)) - { - /* IPv4: "Network unreachable" or "Network down" - * - * This indicates we do not have connectivity - */ - LOG (GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK, - _("XU could not transmit message to `%s': " - "Network seems down, please check your network configuration\n"), - GNUNET_a2s (sa, - slen)); - } - if (slen == sizeof (struct sockaddr_in6)) - { - /* IPv6: "Network unreachable" or "Network down" - * - * This indicates that this system is IPv6 enabled, but does not - * have a valid global IPv6 address assigned or we do not have - * connectivity - */ - LOG (GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK, - _("XU could not transmit IPv6 message! " - "Please check your network configuration and disable IPv6 if your " - "connection does not have a global IPv6 address\n")); - } - } - else - { - LOG (GNUNET_ERROR_TYPE_WARNING, - "XU could not transmit message to `%s': `%s'\n", - GNUNET_a2s (sa, - slen), - STRERROR (error)); - } -} - - - - -/** - * Function that can be used by the transport service to transmit a - * message using the plugin. Note that in the case of a peer - * disconnecting, the continuation MUST be called prior to the - * disconnect notification itself. This function will be called with - * this peer's HELLO message to initiate a fresh connection to another - * peer. - * - * @param cls closure - * @param s which session must be used - * @param msgbuf the message to transmit - * @param msgbuf_size number of bytes in @a msgbuf - * @param priority how important is the message (most plugins will - * ignore message priority and just FIFO) - * @param to how long to wait at most for the transmission (does not - * require plugins to discard the message after the timeout, - * just advisory for the desired delay; most plugins will ignore - * this as well) - * @param cont continuation to call once the message has - * been transmitted (or if the transport is ready - * for the next transmission call; or if the - * peer disconnected...); can be NULL - * @param cont_cls closure for @a cont - * @return number of bytes used (on the physical network, with overheads); - * -1 on hard errors (i.e. address invalid); 0 is a legal value - * and does NOT mean that the message was not transmitted (DV) - */ -static ssize_t -xu_plugin_send (void *cls, - struct GNUNET_ATS_Session *s, - const char *msgbuf, - size_t msgbuf_size, - unsigned int priority, - struct GNUNET_TIME_Relative to, - GNUNET_TRANSPORT_TransmitContinuation cont, - void *cont_cls) -{ - struct Plugin *plugin = cls; - size_t xumlen = msgbuf_size + sizeof(struct XUMessage); - struct XUMessage *xu; - char mbuf[xumlen] GNUNET_ALIGN; - ssize_t sent; - socklen_t slen; - const struct sockaddr *a; - const struct IPv4XuAddress *u4; - struct sockaddr_in a4; - const struct IPv6XuAddress *u6; - struct sockaddr_in6 a6; - struct GNUNET_NETWORK_Handle *sock; - - (void) priority; - (void) to; - if ( (sizeof(struct IPv6XuAddress) == s->address->address_length) && - (NULL == plugin->sockv6) ) - return GNUNET_SYSERR; - if ( (sizeof(struct IPv4XuAddress) == s->address->address_length) && - (NULL == plugin->sockv4) ) - return GNUNET_SYSERR; - if (xumlen >= GNUNET_MAX_MESSAGE_SIZE) - { - GNUNET_break (0); - return GNUNET_SYSERR; - } - if (GNUNET_YES != - GNUNET_CONTAINER_multipeermap_contains_value (plugin->sessions, - &s->target, - s)) - { - GNUNET_break (0); - return GNUNET_SYSERR; - } - LOG (GNUNET_ERROR_TYPE_DEBUG, - "XU transmits %u-byte message to `%s' using address `%s'\n", - xumlen, - GNUNET_i2s (&s->target), - xu_address_to_string (plugin, - s->address->address, - s->address->address_length)); - xu = (struct XUMessage *) mbuf; - xu->header.size = htons (xumlen); - xu->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_XU_MESSAGE); - xu->reserved = htonl (0); - xu->sender = *plugin->env->my_identity; - GNUNET_memcpy (&xu[1], - msgbuf, - msgbuf_size); - - if (sizeof (struct IPv4XuAddress) == s->address->address_length) - { - u4 = s->address->address; - memset (&a4, - 0, - sizeof(a4)); - a4.sin_family = AF_INET; -#if HAVE_SOCKADDR_IN_SIN_LEN - a4.sin_len = sizeof (a4); -#endif - a4.sin_port = u4->u4_port; - a4.sin_addr.s_addr = u4->ipv4_addr; - a = (const struct sockaddr *) &a4; - slen = sizeof (a4); - sock = plugin->sockv4; - } - else if (sizeof (struct IPv6XuAddress) == s->address->address_length) - { - u6 = s->address->address; - memset (&a6, - 0, - sizeof(a6)); - a6.sin6_family = AF_INET6; -#if HAVE_SOCKADDR_IN_SIN_LEN - a6.sin6_len = sizeof (a6); -#endif - a6.sin6_port = u6->u6_port; - a6.sin6_addr = u6->ipv6_addr; - a = (const struct sockaddr *) &a6; - slen = sizeof (a6); - sock = plugin->sockv6; - } - else - { - GNUNET_break (0); - return GNUNET_SYSERR; - } - - sent = GNUNET_NETWORK_socket_sendto (sock, - mbuf, - xumlen, - a, - slen); - s->last_transmit_time - = GNUNET_TIME_absolute_max (GNUNET_TIME_absolute_get (), - s->last_transmit_time); - - if (GNUNET_SYSERR == sent) - { - /* Failure */ - analyze_send_error (plugin, - a, - slen, - errno); - GNUNET_STATISTICS_update (plugin->env->stats, - "# XU, total, bytes, sent, failure", - sent, - GNUNET_NO); - GNUNET_STATISTICS_update (plugin->env->stats, - "# XU, total, messages, sent, failure", - 1, - GNUNET_NO); - return GNUNET_SYSERR; - } - /* Success */ - LOG (GNUNET_ERROR_TYPE_DEBUG, - "XU transmitted %u-byte message to `%s' `%s' (%d: %s)\n", - (unsigned int) (msgbuf_size), - GNUNET_i2s (&s->target), - GNUNET_a2s (a, - slen), - (int ) sent, - (sent < 0) ? STRERROR (errno) : "ok"); - GNUNET_STATISTICS_update (plugin->env->stats, - "# XU, total, bytes, sent, success", - sent, - GNUNET_NO); - GNUNET_STATISTICS_update (plugin->env->stats, - "# XU, total, messages, sent, success", - 1, - GNUNET_NO); - cont (cont_cls, - &s->target, - GNUNET_OK, - msgbuf_size, - xumlen); - notify_session_monitor (s->plugin, - s, - GNUNET_TRANSPORT_SS_UPDATE); - return xumlen; -} - - -/* ********************** Receiving ********************** */ - - -/** - * Functions with this signature are called whenever we need to close - * a session due to a disconnect or failure to establish a connection. - * - * @param cls closure with the `struct Plugin` - * @param s session to close down - * @return #GNUNET_OK on success - */ -static int -xu_disconnect_session (void *cls, - struct GNUNET_ATS_Session *s) -{ - struct Plugin *plugin = cls; - - GNUNET_assert (GNUNET_YES != s->in_destroy); - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Session %p to peer `%s' at address %s ended\n", - s, - GNUNET_i2s (&s->target), - xu_address_to_string (plugin, - s->address->address, - s->address->address_length)); - if (NULL != s->timeout_task) - { - GNUNET_SCHEDULER_cancel (s->timeout_task); - s->timeout_task = NULL; - } - GNUNET_assert (GNUNET_YES == - GNUNET_CONTAINER_multipeermap_remove (plugin->sessions, - &s->target, - s)); - s->in_destroy = GNUNET_YES; - notify_session_monitor (s->plugin, - s, - GNUNET_TRANSPORT_SS_DONE); - plugin->env->session_end (plugin->env->cls, - s->address, - s); - GNUNET_STATISTICS_set (plugin->env->stats, - "# XU sessions active", - GNUNET_CONTAINER_multipeermap_size (plugin->sessions), - GNUNET_NO); - if (0 == s->rc) - free_session (s); - return GNUNET_OK; -} - - -/** - * Message tokenizer has broken up an incomming message. Pass it on - * to the service. - * - * @param cls the `struct GNUNET_ATS_Session *` - * @param hdr the actual message - * @return #GNUNET_OK (always) - */ -static int -process_inbound_tokenized_messages (void *cls, - const struct GNUNET_MessageHeader *hdr) -{ - struct GNUNET_ATS_Session *session = cls; - struct Plugin *plugin = session->plugin; - - if (GNUNET_YES == session->in_destroy) - return GNUNET_OK; - reschedule_session_timeout (session); - session->flow_delay_for_other_peer - = plugin->env->receive (plugin->env->cls, - session->address, - session, - hdr); - return GNUNET_OK; -} - - -/** - * Destroy a session, plugin is being unloaded. - * - * @param cls the `struct Plugin` - * @param key hash of public key of target peer - * @param value a `struct PeerSession *` to clean up - * @return #GNUNET_OK (continue to iterate) - */ -static int -disconnect_and_free_it (void *cls, - const struct GNUNET_PeerIdentity *key, - void *value) -{ - struct Plugin *plugin = cls; - - (void) key; - xu_disconnect_session (plugin, - value); - return GNUNET_OK; -} - - -/** - * Disconnect from a remote node. Clean up session if we have one for - * this peer. - * - * @param cls closure for this call (should be handle to Plugin) - * @param target the peeridentity of the peer to disconnect - * @return #GNUNET_OK on success, #GNUNET_SYSERR if the operation failed - */ -static void -xu_disconnect (void *cls, - const struct GNUNET_PeerIdentity *target) -{ - struct Plugin *plugin = cls; - - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Disconnecting from peer `%s'\n", - GNUNET_i2s (target)); - GNUNET_CONTAINER_multipeermap_get_multiple (plugin->sessions, - target, - &disconnect_and_free_it, - plugin); -} - - -/** - * Session was idle, so disconnect it. - * - * @param cls the `struct GNUNET_ATS_Session` to time out - */ -static void -session_timeout (void *cls) -{ - struct GNUNET_ATS_Session *s = cls; - struct Plugin *plugin = s->plugin; - struct GNUNET_TIME_Relative left; - - s->timeout_task = NULL; - left = GNUNET_TIME_absolute_get_remaining (s->timeout); - if (left.rel_value_us > 0) - { - /* not actually our turn yet, but let's at least update - the monitor, it may think we're about to die ... */ - notify_session_monitor (s->plugin, - s, - GNUNET_TRANSPORT_SS_UPDATE); - s->timeout_task = GNUNET_SCHEDULER_add_delayed (left, - &session_timeout, - s); - return; - } - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Session %p was idle for %s, disconnecting\n", - s, - GNUNET_STRINGS_relative_time_to_string (XU_SESSION_TIME_OUT, - GNUNET_YES)); - /* call session destroy function */ - xu_disconnect_session (plugin, - s); -} - - -/** - * Allocate a new session for the given endpoint address. - * Note that this function does not inform the service - * of the new session, this is the responsibility of the - * caller (if needed). - * - * @param cls the `struct Plugin` - * @param address address of the other peer to use - * @param network_type network type the address belongs to - * @return NULL on error, otherwise session handle - */ -static struct GNUNET_ATS_Session * -xu_plugin_create_session (void *cls, - const struct GNUNET_HELLO_Address *address, - enum GNUNET_NetworkType network_type) -{ - struct Plugin *plugin = cls; - struct GNUNET_ATS_Session *s; - - s = GNUNET_new (struct GNUNET_ATS_Session); - s->mst = GNUNET_MST_create (&process_inbound_tokenized_messages, - s); - s->plugin = plugin; - s->address = GNUNET_HELLO_address_copy (address); - s->target = address->peer; - s->last_transmit_time = GNUNET_TIME_absolute_get (); - s->last_expected_ack_delay = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, - 250); - s->last_expected_msg_delay = GNUNET_TIME_UNIT_MILLISECONDS; - s->flow_delay_from_other_peer = GNUNET_TIME_UNIT_ZERO; - s->flow_delay_for_other_peer = GNUNET_TIME_UNIT_ZERO; - s->timeout = GNUNET_TIME_relative_to_absolute (XU_SESSION_TIME_OUT); - s->timeout_task = GNUNET_SCHEDULER_add_delayed (XU_SESSION_TIME_OUT, - &session_timeout, - s); - s->scope = network_type; - - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Creating new session %p for peer `%s' address `%s'\n", - s, - GNUNET_i2s (&address->peer), - xu_address_to_string (plugin, - address->address, - address->address_length)); - GNUNET_assert (GNUNET_OK == - GNUNET_CONTAINER_multipeermap_put (plugin->sessions, - &s->target, - s, - GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE)); - GNUNET_STATISTICS_set (plugin->env->stats, - "# XU sessions active", - GNUNET_CONTAINER_multipeermap_size (plugin->sessions), - GNUNET_NO); - notify_session_monitor (plugin, - s, - GNUNET_TRANSPORT_SS_INIT); - return s; -} - - -/** - * Creates a new outbound session the transport service will use to - * send data to the peer. - * - * @param cls the `struct Plugin *` - * @param address the address - * @return the session or NULL of max connections exceeded - */ -static struct GNUNET_ATS_Session * -xu_plugin_get_session (void *cls, - const struct GNUNET_HELLO_Address *address) -{ - struct Plugin *plugin = cls; - struct GNUNET_ATS_Session *s; - enum GNUNET_NetworkType network_type = GNUNET_NT_UNSPECIFIED; - const struct IPv4XuAddress *xu_v4; - const struct IPv6XuAddress *xu_v6; - - if (NULL == address) - { - GNUNET_break (0); - return NULL; - } - if ( (address->address_length != sizeof(struct IPv4XuAddress)) && - (address->address_length != sizeof(struct IPv6XuAddress)) ) - { - GNUNET_break_op (0); - return NULL; - } - if (NULL != (s = xu_plugin_lookup_session (cls, - address))) - return s; - - /* need to create new session */ - if (sizeof (struct IPv4XuAddress) == address->address_length) - { - struct sockaddr_in v4; - - xu_v4 = (const struct IPv4XuAddress *) address->address; - memset (&v4, '\0', sizeof (v4)); - v4.sin_family = AF_INET; -#if HAVE_SOCKADDR_IN_SIN_LEN - v4.sin_len = sizeof (struct sockaddr_in); -#endif - v4.sin_port = xu_v4->u4_port; - v4.sin_addr.s_addr = xu_v4->ipv4_addr; - network_type = plugin->env->get_address_type (plugin->env->cls, - (const struct sockaddr *) &v4, - sizeof (v4)); - } - if (sizeof (struct IPv6XuAddress) == address->address_length) - { - struct sockaddr_in6 v6; - - xu_v6 = (const struct IPv6XuAddress *) address->address; - memset (&v6, '\0', sizeof (v6)); - v6.sin6_family = AF_INET6; -#if HAVE_SOCKADDR_IN_SIN_LEN - v6.sin6_len = sizeof (struct sockaddr_in6); -#endif - v6.sin6_port = xu_v6->u6_port; - v6.sin6_addr = xu_v6->ipv6_addr; - network_type = plugin->env->get_address_type (plugin->env->cls, - (const struct sockaddr *) &v6, - sizeof (v6)); - } - GNUNET_break (GNUNET_NT_UNSPECIFIED != network_type); - return xu_plugin_create_session (cls, - address, - network_type); -} - - -/** - * We've received a XU Message. Process it (pass contents to main service). - * - * @param plugin plugin context - * @param msg the message - * @param xu_addr sender address - * @param xu_addr_len number of bytes in @a xu_addr - * @param network_type network type the address belongs to - */ -static void -process_xu_message (struct Plugin *plugin, - const struct XUMessage *msg, - const union XuAddress *xu_addr, - size_t xu_addr_len, - enum GNUNET_NetworkType network_type) -{ - struct GNUNET_ATS_Session *s; - struct GNUNET_HELLO_Address *address; - - GNUNET_break (GNUNET_NT_UNSPECIFIED != network_type); - if (0 != ntohl (msg->reserved)) - { - GNUNET_break_op(0); - return; - } - if (ntohs (msg->header.size) - < sizeof(struct GNUNET_MessageHeader) + sizeof(struct XUMessage)) - { - GNUNET_break_op(0); - return; - } - - address = GNUNET_HELLO_address_allocate (&msg->sender, - PLUGIN_NAME, - xu_addr, - xu_addr_len, - GNUNET_HELLO_ADDRESS_INFO_NONE); - if (NULL == - (s = xu_plugin_lookup_session (plugin, - address))) - { - s = xu_plugin_create_session (plugin, - address, - network_type); - plugin->env->session_start (plugin->env->cls, - address, - s, - s->scope); - notify_session_monitor (plugin, - s, - GNUNET_TRANSPORT_SS_UP); - } - GNUNET_free (address); - - s->rc++; - GNUNET_MST_from_buffer (s->mst, - (const char *) &msg[1], - ntohs (msg->header.size) - sizeof(struct XUMessage), - GNUNET_YES, - GNUNET_NO); - s->rc--; - if ( (0 == s->rc) && - (GNUNET_YES == s->in_destroy) ) - free_session (s); -} - - -/** - * Read and process a message from the given socket. - * - * @param plugin the overall plugin - * @param rsock socket to read from - */ -static void -xu_select_read (struct Plugin *plugin, - struct GNUNET_NETWORK_Handle *rsock) -{ - socklen_t fromlen; - struct sockaddr_storage addr; - char buf[65536] GNUNET_ALIGN; - ssize_t size; - const struct GNUNET_MessageHeader *msg; - struct IPv4XuAddress v4; - struct IPv6XuAddress v6; - const struct sockaddr *sa; - const struct sockaddr_in *sa4; - const struct sockaddr_in6 *sa6; - const union XuAddress *int_addr; - size_t int_addr_len; - enum GNUNET_NetworkType network_type; - - fromlen = sizeof (addr); - memset (&addr, - 0, - sizeof(addr)); - size = GNUNET_NETWORK_socket_recvfrom (rsock, - buf, - sizeof (buf), - (struct sockaddr *) &addr, - &fromlen); - sa = (const struct sockaddr *) &addr; -#if MINGW - /* On SOCK_DGRAM XU sockets recvfrom might fail with a - * WSAECONNRESET error to indicate that previous sendto() (yes, sendto!) - * on this socket has failed. - * Quote from MSDN: - * WSAECONNRESET - The virtual circuit was reset by the remote side - * executing a hard or abortive close. The application should close - * the socket; it is no longer usable. On a XU-datagram socket this - * error indicates a previous send operation resulted in an ICMP Port - * Unreachable message. - */ - if ( (-1 == size) && - (ECONNRESET == errno) ) - return; -#endif - if (-1 == size) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, - "XU failed to receive data: %s\n", - STRERROR (errno)); - /* Connection failure or something. Not a protocol violation. */ - return; - } - - /* Check if this is a STUN packet */ - if (GNUNET_NO != - GNUNET_NAT_stun_handle_packet (plugin->nat, - (const struct sockaddr *) &addr, - fromlen, - buf, - size)) - return; /* was STUN, do not process further */ - - if (((size_t) size) < sizeof(struct GNUNET_MessageHeader)) - { - LOG (GNUNET_ERROR_TYPE_WARNING, - "XU got %u bytes from %s, which is not enough for a GNUnet message header\n", - (unsigned int ) size, - GNUNET_a2s (sa, - fromlen)); - /* _MAY_ be a connection failure (got partial message) */ - /* But it _MAY_ also be that the other side uses non-GNUnet protocol. */ - GNUNET_break_op (0); - return; - } - - msg = (const struct GNUNET_MessageHeader *) buf; - LOG (GNUNET_ERROR_TYPE_DEBUG, - "XU received %u-byte message from `%s' type %u\n", - (unsigned int) size, - GNUNET_a2s (sa, - fromlen), - ntohs (msg->type)); - if (size != ntohs (msg->size)) - { - LOG (GNUNET_ERROR_TYPE_WARNING, - "XU malformed message (size %u) header from %s\n", - (unsigned int) size, - GNUNET_a2s (sa, - fromlen)); - GNUNET_break_op (0); - return; - } - GNUNET_STATISTICS_update (plugin->env->stats, - "# XU, total bytes received", - size, - GNUNET_NO); - network_type = plugin->env->get_address_type (plugin->env->cls, - sa, - fromlen); - switch (sa->sa_family) - { - case AF_INET: - sa4 = (const struct sockaddr_in *) &addr; - v4.options = 0; - v4.ipv4_addr = sa4->sin_addr.s_addr; - v4.u4_port = sa4->sin_port; - int_addr = (union XuAddress *) &v4; - int_addr_len = sizeof (v4); - break; - case AF_INET6: - sa6 = (const struct sockaddr_in6 *) &addr; - v6.options = 0; - v6.ipv6_addr = sa6->sin6_addr; - v6.u6_port = sa6->sin6_port; - int_addr = (union XuAddress *) &v6; - int_addr_len = sizeof (v6); - break; - default: - GNUNET_break (0); - return; - } - - switch (ntohs (msg->type)) - { - case GNUNET_MESSAGE_TYPE_TRANSPORT_XU_MESSAGE: - if (ntohs (msg->size) < sizeof(struct XUMessage)) - { - GNUNET_break_op(0); - return; - } - process_xu_message (plugin, - (const struct XUMessage *) msg, - int_addr, - int_addr_len, - network_type); - return; - default: - GNUNET_break_op(0); - return; - } -} - - -/* ***************** Event loop (part 2) *************** */ - - -/** - * We have been notified that our readset has something to read. We don't - * know which socket needs to be read, so we have to check each one - * Then reschedule this function to be called again once more is available. - * - * @param cls the plugin handle - */ -static void -xu_plugin_select_v4 (void *cls) -{ - struct Plugin *plugin = cls; - const struct GNUNET_SCHEDULER_TaskContext *tc; - - plugin->select_task_v4 = NULL; - if (NULL == plugin->sockv4) - return; - tc = GNUNET_SCHEDULER_get_task_context (); - if ( (0 != (tc->reason & GNUNET_SCHEDULER_REASON_READ_READY)) && - (GNUNET_NETWORK_fdset_isset (tc->read_ready, - plugin->sockv4)) ) - xu_select_read (plugin, - plugin->sockv4); - schedule_select_v4 (plugin); -} - - -/** - * We have been notified that our readset has something to read. We don't - * know which socket needs to be read, so we have to check each one - * Then reschedule this function to be called again once more is available. - * - * @param cls the plugin handle - */ -static void -xu_plugin_select_v6 (void *cls) -{ - struct Plugin *plugin = cls; - const struct GNUNET_SCHEDULER_TaskContext *tc; - - plugin->select_task_v6 = NULL; - if (NULL == plugin->sockv6) - return; - tc = GNUNET_SCHEDULER_get_task_context (); - if ( (0 != (tc->reason & GNUNET_SCHEDULER_REASON_READ_READY)) && - (GNUNET_NETWORK_fdset_isset (tc->read_ready, - plugin->sockv6)) ) - xu_select_read (plugin, - plugin->sockv6); - schedule_select_v6 (plugin); -} - - -/* ******************* Initialization *************** */ - - -/** - * Setup the XU sockets (for IPv4 and IPv6) for the plugin. - * - * @param plugin the plugin to initialize - * @param bind_v6 IPv6 address to bind to (can be NULL, for 'any') - * @param bind_v4 IPv4 address to bind to (can be NULL, for 'any') - * @return number of sockets that were successfully bound - */ -static unsigned int -setup_sockets (struct Plugin *plugin, - const struct sockaddr_in6 *bind_v6, - const struct sockaddr_in *bind_v4) -{ - int tries; - unsigned int sockets_created = 0; - struct sockaddr_in6 server_addrv6; - struct sockaddr_in server_addrv4; - const struct sockaddr *server_addr; - const struct sockaddr *addrs[2]; - socklen_t addrlens[2]; - socklen_t addrlen; - int eno; - - /* Create IPv6 socket */ - eno = EINVAL; - if (GNUNET_YES == plugin->enable_ipv6) - { - plugin->sockv6 = GNUNET_NETWORK_socket_create (PF_INET6, - SOCK_DGRAM, - 0); - if (NULL == plugin->sockv6) - { - LOG (GNUNET_ERROR_TYPE_INFO, - _("Disabling IPv6 since it is not supported on this system!\n")); - plugin->enable_ipv6 = GNUNET_NO; - } - else - { - memset (&server_addrv6, - 0, - sizeof(struct sockaddr_in6)); -#if HAVE_SOCKADDR_IN_SIN_LEN - server_addrv6.sin6_len = sizeof (struct sockaddr_in6); -#endif - server_addrv6.sin6_family = AF_INET6; - if (NULL != bind_v6) - server_addrv6.sin6_addr = bind_v6->sin6_addr; - else - server_addrv6.sin6_addr = in6addr_any; - - if (0 == plugin->port) /* autodetect */ - server_addrv6.sin6_port - = htons (GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_STRONG, - 33537) - + 32000); - else - server_addrv6.sin6_port = htons (plugin->port); - addrlen = sizeof (struct sockaddr_in6); - server_addr = (const struct sockaddr *) &server_addrv6; - - tries = 0; - while (tries < 10) - { - LOG(GNUNET_ERROR_TYPE_DEBUG, - "Binding to IPv6 `%s'\n", - GNUNET_a2s (server_addr, - addrlen)); - /* binding */ - if (GNUNET_OK == - GNUNET_NETWORK_socket_bind (plugin->sockv6, - server_addr, - addrlen)) - break; - eno = errno; - if (0 != plugin->port) - { - tries = 10; /* fail immediately */ - break; /* bind failed on specific port */ - } - /* autodetect */ - server_addrv6.sin6_port - = htons (GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_STRONG, - 33537) - + 32000); - tries++; - } - if (tries >= 10) - { - GNUNET_NETWORK_socket_close (plugin->sockv6); - plugin->enable_ipv6 = GNUNET_NO; - plugin->sockv6 = NULL; - } - else - { - plugin->port = ntohs (server_addrv6.sin6_port); - } - if (NULL != plugin->sockv6) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, - "IPv6 XU socket created listinging at %s\n", - GNUNET_a2s (server_addr, - addrlen)); - addrs[sockets_created] = server_addr; - addrlens[sockets_created] = addrlen; - sockets_created++; - } - else - { - LOG (GNUNET_ERROR_TYPE_WARNING, - _("Failed to bind XU socket to %s: %s\n"), - GNUNET_a2s (server_addr, - addrlen), - STRERROR (eno)); - } - } - } - - /* Create IPv4 socket */ - eno = EINVAL; - plugin->sockv4 = GNUNET_NETWORK_socket_create (PF_INET, - SOCK_DGRAM, - 0); - if (NULL == plugin->sockv4) - { - GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, - "socket"); - LOG (GNUNET_ERROR_TYPE_INFO, - _("Disabling IPv4 since it is not supported on this system!\n")); - plugin->enable_ipv4 = GNUNET_NO; - } - else - { - memset (&server_addrv4, - 0, - sizeof(struct sockaddr_in)); -#if HAVE_SOCKADDR_IN_SIN_LEN - server_addrv4.sin_len = sizeof (struct sockaddr_in); -#endif - server_addrv4.sin_family = AF_INET; - if (NULL != bind_v4) - server_addrv4.sin_addr = bind_v4->sin_addr; - else - server_addrv4.sin_addr.s_addr = INADDR_ANY; - - if (0 == plugin->port) - /* autodetect */ - server_addrv4.sin_port - = htons (GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_STRONG, - 33537) - + 32000); - else - server_addrv4.sin_port = htons (plugin->port); - - addrlen = sizeof (struct sockaddr_in); - server_addr = (const struct sockaddr *) &server_addrv4; - - tries = 0; - while (tries < 10) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Binding to IPv4 `%s'\n", - GNUNET_a2s (server_addr, - addrlen)); - - /* binding */ - if (GNUNET_OK == - GNUNET_NETWORK_socket_bind (plugin->sockv4, - server_addr, - addrlen)) - break; - eno = errno; - if (0 != plugin->port) - { - tries = 10; /* fail */ - break; /* bind failed on specific port */ - } - - /* autodetect */ - server_addrv4.sin_port - = htons (GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_STRONG, - 33537) - + 32000); - tries++; - } - if (tries >= 10) - { - GNUNET_NETWORK_socket_close (plugin->sockv4); - plugin->enable_ipv4 = GNUNET_NO; - plugin->sockv4 = NULL; - } - else - { - plugin->port = ntohs (server_addrv4.sin_port); - } - - if (NULL != plugin->sockv4) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, - "IPv4 socket created on port %s\n", - GNUNET_a2s (server_addr, - addrlen)); - addrs[sockets_created] = server_addr; - addrlens[sockets_created] = addrlen; - sockets_created++; - } - else - { - LOG (GNUNET_ERROR_TYPE_ERROR, - _("Failed to bind XU socket to %s: %s\n"), - GNUNET_a2s (server_addr, - addrlen), - STRERROR (eno)); - } - } - - if (0 == sockets_created) - { - LOG (GNUNET_ERROR_TYPE_WARNING, - _("Failed to open XU sockets\n")); - return 0; /* No sockets created, return */ - } - schedule_select_v4 (plugin); - schedule_select_v6 (plugin); - plugin->nat = GNUNET_NAT_register (plugin->env->cfg, - "transport-xu", - IPPROTO_UDP, - sockets_created, - addrs, - addrlens, - &xu_nat_port_map_callback, - NULL, - plugin); - return sockets_created; -} - - -/** - * The exported method. Makes the core api available via a global and - * returns the xu transport API. - * - * @param cls our `struct GNUNET_TRANSPORT_PluginEnvironment` - * @return our `struct GNUNET_TRANSPORT_PluginFunctions` - */ -void * -libgnunet_plugin_transport_xu_init (void *cls) -{ - struct GNUNET_TRANSPORT_PluginEnvironment *env = cls; - struct GNUNET_TRANSPORT_PluginFunctions *api; - struct Plugin *p; - unsigned long long port; - unsigned long long aport; - int enable_v6; - char *bind4_address; - char *bind6_address; - struct sockaddr_in server_addrv4; - struct sockaddr_in6 server_addrv6; - unsigned int res; - int have_bind4; - int have_bind6; - - if (NULL == env->receive) - { - /* run in 'stub' mode (i.e. as part of gnunet-peerinfo), don't fully - initialze the plugin or the API */ - api = GNUNET_new (struct GNUNET_TRANSPORT_PluginFunctions); - api->cls = NULL; - api->address_pretty_printer = &xu_plugin_address_pretty_printer; - api->address_to_string = &xu_address_to_string; - api->string_to_address = &xu_string_to_address; - return api; - } - - /* Get port number: port == 0 : autodetect a port, - * > 0 : use this port, not given : 2086 default */ - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_number (env->cfg, - "transport-xu", - "PORT", - &port)) - port = 2086; - if (port > 65535) - { - GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, - "transport-xu", - "PORT", - _("must be in [0,65535]")); - return NULL; - } - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_number (env->cfg, - "transport-xu", - "ADVERTISED_PORT", - &aport)) - aport = port; - if (aport > 65535) - { - GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, - "transport-xu", - "ADVERTISED_PORT", - _("must be in [0,65535]")); - return NULL; - } - - if (GNUNET_YES == - GNUNET_CONFIGURATION_get_value_yesno (env->cfg, - "nat", - "DISABLEV6")) - enable_v6 = GNUNET_NO; - else - enable_v6 = GNUNET_YES; - - have_bind4 = GNUNET_NO; - memset (&server_addrv4, - 0, - sizeof (server_addrv4)); - if (GNUNET_YES == - GNUNET_CONFIGURATION_get_value_string (env->cfg, - "transport-xu", - "BINDTO", - &bind4_address)) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Binding XU plugin to specific address: `%s'\n", - bind4_address); - if (1 != inet_pton (AF_INET, - bind4_address, - &server_addrv4.sin_addr)) - { - GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, - "transport-xu", - "BINDTO", - _("must be valid IPv4 address")); - GNUNET_free (bind4_address); - return NULL; - } - have_bind4 = GNUNET_YES; - } - GNUNET_free_non_null (bind4_address); - have_bind6 = GNUNET_NO; - memset (&server_addrv6, - 0, - sizeof (server_addrv6)); - if (GNUNET_YES == - GNUNET_CONFIGURATION_get_value_string (env->cfg, - "transport-xu", - "BINDTO6", - &bind6_address)) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Binding xu plugin to specific address: `%s'\n", - bind6_address); - if (1 != inet_pton (AF_INET6, - bind6_address, - &server_addrv6.sin6_addr)) - { - GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, - "transport-xu", - "BINDTO6", - _("must be valid IPv6 address")); - GNUNET_free (bind6_address); - return NULL; - } - have_bind6 = GNUNET_YES; - } - GNUNET_free_non_null (bind6_address); - - p = GNUNET_new (struct Plugin); - p->port = port; - p->aport = aport; - p->enable_ipv6 = enable_v6; - p->enable_ipv4 = GNUNET_YES; /* default */ - p->env = env; - p->sessions = GNUNET_CONTAINER_multipeermap_create (16, - GNUNET_NO); - res = setup_sockets (p, - (GNUNET_YES == have_bind6) ? &server_addrv6 : NULL, - (GNUNET_YES == have_bind4) ? &server_addrv4 : NULL); - if ( (0 == res) || - ( (NULL == p->sockv4) && - (NULL == p->sockv6) ) ) - { - LOG (GNUNET_ERROR_TYPE_ERROR, - _("Failed to create XU network sockets\n")); - GNUNET_CONTAINER_multipeermap_destroy (p->sessions); - if (NULL != p->nat) - GNUNET_NAT_unregister (p->nat); - GNUNET_free (p); - return NULL; - } - - api = GNUNET_new (struct GNUNET_TRANSPORT_PluginFunctions); - api->cls = p; - api->disconnect_session = &xu_disconnect_session; - api->query_keepalive_factor = &xu_query_keepalive_factor; - api->disconnect_peer = &xu_disconnect; - api->address_pretty_printer = &xu_plugin_address_pretty_printer; - api->address_to_string = &xu_address_to_string; - api->string_to_address = &xu_string_to_address; - api->check_address = &xu_plugin_check_address; - api->get_session = &xu_plugin_get_session; - api->send = &xu_plugin_send; - api->get_network = &xu_plugin_get_network; - api->get_network_for_address = &xu_plugin_get_network_for_address; - api->update_session_timeout = &xu_plugin_update_session_timeout; - api->setup_monitor = &xu_plugin_setup_monitor; - return api; -} - - -/** - * The exported method. Makes the core api available via a global and - * returns the xu transport API. - * - * @param cls our `struct GNUNET_TRANSPORT_PluginEnvironment` - * @return NULL - */ -void * -libgnunet_plugin_transport_xu_done (void *cls) -{ - struct GNUNET_TRANSPORT_PluginFunctions *api = cls; - struct Plugin *plugin = api->cls; - struct PrettyPrinterContext *cur; - - if (NULL == plugin) - { - GNUNET_free (api); - return NULL; - } - if (NULL != plugin->select_task_v4) - { - GNUNET_SCHEDULER_cancel (plugin->select_task_v4); - plugin->select_task_v4 = NULL; - } - if (NULL != plugin->select_task_v6) - { - GNUNET_SCHEDULER_cancel (plugin->select_task_v6); - plugin->select_task_v6 = NULL; - } - if (NULL != plugin->sockv4) - { - GNUNET_break (GNUNET_OK == - GNUNET_NETWORK_socket_close (plugin->sockv4)); - plugin->sockv4 = NULL; - } - if (NULL != plugin->sockv6) - { - GNUNET_break (GNUNET_OK == - GNUNET_NETWORK_socket_close (plugin->sockv6)); - plugin->sockv6 = NULL; - } - if (NULL != plugin->nat) - { - GNUNET_NAT_unregister (plugin->nat); - plugin->nat = NULL; - } - GNUNET_CONTAINER_multipeermap_destroy (plugin->sessions); - - while (NULL != (cur = plugin->ppc_dll_head)) - { - GNUNET_break (0); - GNUNET_CONTAINER_DLL_remove (plugin->ppc_dll_head, - plugin->ppc_dll_tail, - cur); - GNUNET_RESOLVER_request_cancel (cur->resolver_handle); - if (NULL != cur->timeout_task) - { - GNUNET_SCHEDULER_cancel (cur->timeout_task); - cur->timeout_task = NULL; - } - GNUNET_free (cur); - } - GNUNET_free (plugin); - GNUNET_free (api); - return NULL; -} - -/* end of plugin_transport_xu.c */ diff --git a/src/transport/plugin_transport_xu.h b/src/transport/plugin_transport_xu.h deleted file mode 100644 index dd3dcd738..000000000 --- a/src/transport/plugin_transport_xu.h +++ /dev/null @@ -1,273 +0,0 @@ -/* - This file is part of GNUnet - Copyright (C) 2010-2014 GNUnet e.V. - - GNUnet is free software: you can redistribute it and/or modify it - under the terms of the GNU Affero General Public License as published - by the Free Software Foundation, either version 3 of the License, - or (at your option) any later version. - - GNUnet is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see . - - SPDX-License-Identifier: AGPL3.0-or-later -*/ - -/** - * @file transport/plugin_transport_xu.h - * @brief Implementation of the XU transport protocol - * @author Christian Grothoff - * @author Nathan Evans - * @author Matthias Wachs - */ -#ifndef PLUGIN_TRANSPORT_XU_H -#define PLUGIN_TRANSPORT_XU_H - -#include "platform.h" -#include "gnunet_hello_lib.h" -#include "gnunet_util_lib.h" -#include "gnunet_fragmentation_lib.h" -#include "gnunet_protocols.h" -#include "gnunet_resolver_service.h" -#include "gnunet_signatures.h" -#include "gnunet_constants.h" -#include "gnunet_statistics_service.h" -#include "gnunet_transport_service.h" -#include "gnunet_transport_plugin.h" -#include "transport.h" - -#define LOG(kind,...) GNUNET_log_from (kind, "transport-xu", __VA_ARGS__) - -#define PLUGIN_NAME "xu" - -#define DEBUG_XU GNUNET_NO - -#define DEBUG_XU_BROADCASTING GNUNET_NO - -/** - * MTU for fragmentation subsystem. Should be conservative since - * all communicating peers MUST work with this MTU. - */ -#define XU_MTU 1400 - - -GNUNET_NETWORK_STRUCT_BEGIN -/** - * Network format for IPv4 addresses. - */ -struct IPv4XuAddress -{ - /** - * Optional options and flags for this address - */ - uint32_t options GNUNET_PACKED; - - /** - * IPv4 address, in network byte order. - */ - uint32_t ipv4_addr GNUNET_PACKED; - - /** - * Port number, in network byte order. - */ - uint16_t u4_port GNUNET_PACKED; -}; - - -/** - * Network format for IPv6 addresses. - */ -struct IPv6XuAddress -{ - /** - * Optional options and flags for this address - */ - uint32_t options GNUNET_PACKED; - - /** - * IPv6 address. - */ - struct in6_addr ipv6_addr GNUNET_PACKED; - - /** - * Port number, in network byte order. - */ - uint16_t u6_port GNUNET_PACKED; -}; -GNUNET_NETWORK_STRUCT_END - -/** - * Either an IPv4 or IPv6 XU address. Note that without a "length", - * one cannot tell which one of the two types this address represents. - */ -union XuAddress -{ - /** - * IPv4 case. - */ - struct IPv4XuAddress v4; - - /** - * IPv6 case. - */ - struct IPv6XuAddress v6; -}; - - -/** - * Information we track for each message in the queue. - */ -struct XU_MessageWrapper; - - -/** - * Closure for #append_port(). - */ -struct PrettyPrinterContext; - - -/** - * Encapsulation of all of the state of the plugin. - */ -struct Plugin -{ - - /** - * Our environment. - */ - struct GNUNET_TRANSPORT_PluginEnvironment *env; - - /** - * Session of peers with whom we are currently connected, - * map of peer identity to `struct GNUNET_ATS_Session *`. - */ - struct GNUNET_CONTAINER_MultiPeerMap *sessions; - - /** - * ID of select task for IPv4 - */ - struct GNUNET_SCHEDULER_Task *select_task_v4; - - /** - * ID of select task for IPv6 - */ - struct GNUNET_SCHEDULER_Task *select_task_v6; - - /** - * Address we were told to bind to exclusively (IPv4). - */ - char *bind4_address; - - /** - * Address we were told to bind to exclusively (IPv6). - */ - char *bind6_address; - - /** - * Handle to NAT traversal support. - */ - struct GNUNET_NAT_Handle *nat; - - /** - * Handle to NAT traversal support. - */ - struct GNUNET_NAT_STUN_Handle *stun; - - /** - * The read socket for IPv4 - */ - struct GNUNET_NETWORK_Handle *sockv4; - - /** - * The read socket for IPv6 - */ - struct GNUNET_NETWORK_Handle *sockv6; - - /** - * Running pretty printers: head - */ - struct PrettyPrinterContext *ppc_dll_head; - - /** - * Running pretty printers: tail - */ - struct PrettyPrinterContext *ppc_dll_tail; - - /** - * Function to call about session status changes. - */ - GNUNET_TRANSPORT_SessionInfoCallback sic; - - /** - * Closure for @e sic. - */ - void *sic_cls; - - /** - * IPv6 multicast address - */ - struct sockaddr_in6 ipv6_multicast_address; - - /** - * Broadcast interval - */ - struct GNUNET_TIME_Relative broadcast_interval; - - /** - * Bytes currently in buffer - */ - int64_t bytes_in_buffer; - - /** - * Address options - */ - uint32_t myoptions; - - /** - * Is IPv6 enabled: #GNUNET_YES or #GNUNET_NO - */ - int enable_ipv6; - - /** - * Is IPv4 enabled: #GNUNET_YES or #GNUNET_NO - */ - int enable_ipv4; - - /** - * Port we listen on. - */ - uint16_t port; - - /** - * Port we advertise on. - */ - uint16_t aport; - -}; - - -/** - * Function called for a quick conversion of the binary address to - * a numeric address. Note that the caller must not free the - * address and that the next call to this function is allowed - * to override the address again. - * - * @param cls closure - * @param addr binary address (a `union XuAddress`) - * @param addrlen length of the @a addr - * @return string representing the same address - */ -const char * -xu_address_to_string (void *cls, - const void *addr, - size_t addrlen); - - -/*#ifndef PLUGIN_TRANSPORT_XU_H*/ -#endif -/* end of plugin_transport_xu.h */