2 This file is part of GNUnet
3 Copyright (C) 2002--2015 GNUnet e.V.
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
19 * @file transport/plugin_transport_xt.c
20 * @brief Implementation of the TCP transport service
21 * @author Christian Grothoff
24 #include "gnunet_hello_lib.h"
25 #include "gnunet_constants.h"
26 #include "gnunet_util_lib.h"
27 #include "gnunet_nat_service.h"
28 #include "gnunet_protocols.h"
29 #include "gnunet_resolver_service.h"
30 #include "gnunet_signatures.h"
31 #include "gnunet_statistics_service.h"
32 #include "gnunet_transport_service.h"
33 #include "gnunet_transport_plugin.h"
34 #include "transport.h"
36 #define LOG(kind,...) GNUNET_log_from (kind, "transport-xt",__VA_ARGS__)
38 #define PLUGIN_NAME "xt"
41 * How long until we give up on establishing an NAT connection?
44 #define NAT_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10)
47 * Opaque handle that can be used to cancel
48 * a transmit-ready notification.
50 struct GNUNET_CONNECTION_TransmitHandle;
53 * @brief handle for a server
55 struct GNUNET_SERVER_Handle;
58 * @brief opaque handle for a client of the server
60 struct GNUNET_SERVER_Client;
63 * @brief opaque handle server returns for aborting transmission to a client.
65 struct GNUNET_SERVER_TransmitHandle;
68 * @brief handle for a network connection
70 struct GNUNET_CONNECTION_Handle;
73 * @brief handle for a network service
75 struct LEGACY_SERVICE_Context;
79 * Stops a service that was started with #GNUNET_SERVICE_start().
81 * @param srv service to stop
84 LEGACY_SERVICE_stop (struct LEGACY_SERVICE_Context *srv);
89 * Function called to notify a client about the connection begin ready
90 * to queue more data. @a buf will be NULL and @a size zero if the
91 * connection was closed for writing in the meantime.
94 * @param size number of bytes available in @a buf
95 * @param buf where the callee should write the message
96 * @return number of bytes written to @a buf
99 (*GNUNET_CONNECTION_TransmitReadyNotify) (void *cls,
104 * Credentials for UNIX domain sockets.
106 struct GNUNET_CONNECTION_Credentials
109 * UID of the other end of the connection.
114 * GID of the other end of the connection.
121 * Functions with this signature are called whenever a client
122 * is disconnected on the network level.
125 * @param client identification of the client; NULL
126 * for the last call when the server is destroyed
129 (*GNUNET_SERVER_DisconnectCallback) (void *cls,
130 struct GNUNET_SERVER_Client *client);
134 * Functions with this signature are called whenever a client
135 * is connected on the network level.
138 * @param client identification of the client
141 (*GNUNET_SERVER_ConnectCallback) (void *cls,
142 struct GNUNET_SERVER_Client *client);
148 * Function to call for access control checks.
151 * @param ucred credentials, if available, otherwise NULL
152 * @param addr address
153 * @param addrlen length of address
154 * @return GNUNET_YES to allow, GNUNET_NO to deny, GNUNET_SYSERR
155 * for unknown address family (will be denied).
158 (*GNUNET_CONNECTION_AccessCheck) (void *cls,
160 GNUNET_CONNECTION_Credentials *
162 const struct sockaddr * addr,
166 * Callback function for data received from the network. Note that
167 * both "available" and "err" would be 0 if the read simply timed out.
170 * @param buf pointer to received data
171 * @param available number of bytes availabe in "buf",
172 * possibly 0 (on errors)
173 * @param addr address of the sender
174 * @param addrlen size of addr
175 * @param errCode value of errno (on errors receiving)
178 (*GNUNET_CONNECTION_Receiver) (void *cls, const void *buf,
180 const struct sockaddr * addr,
181 socklen_t addrlen, int errCode);
186 * Close the connection and free associated resources. There must
187 * not be any pending requests for reading or writing to the
188 * connection at this time.
190 * @param connection connection to destroy
193 GNUNET_CONNECTION_destroy (struct GNUNET_CONNECTION_Handle *connection);
197 * Signature of a function to create a custom tokenizer.
199 * @param cls closure from #GNUNET_SERVER_set_callbacks
200 * @param client handle to client the tokenzier will be used for
201 * @return handle to custom tokenizer ('mst')
204 (*GNUNET_SERVER_MstCreateCallback) (void *cls,
205 struct GNUNET_SERVER_Client *client);
209 * Signature of a function to destroy a custom tokenizer.
211 * @param cls closure from #GNUNET_SERVER_set_callbacks
212 * @param mst custom tokenizer handle
215 (*GNUNET_SERVER_MstDestroyCallback) (void *cls,
219 * Signature of a function to receive data for a custom tokenizer.
221 * @param cls closure from #GNUNET_SERVER_set_callbacks
222 * @param mst custom tokenizer handle
223 * @param client_identity ID of client for which this is a buffer,
224 * can be NULL (will be passed back to 'cb')
225 * @param buf input data to add
226 * @param size number of bytes in @a buf
227 * @param purge should any excess bytes in the buffer be discarded
228 * (i.e. for packet-based services like UDP)
229 * @param one_shot only call callback once, keep rest of message in buffer
230 * @return #GNUNET_OK if we are done processing (need more data)
231 * #GNUNET_NO if one_shot was set and we have another message ready
232 * #GNUNET_SYSERR if the data stream is corrupt
235 (*GNUNET_SERVER_MstReceiveCallback) (void *cls, void *mst,
236 struct GNUNET_SERVER_Client *client,
242 * Functions with this signature are called whenever a message is
246 * @param client identification of the client
247 * @param message the actual message
250 (*GNUNET_SERVER_MessageCallback) (void *cls,
251 struct GNUNET_SERVER_Client *client,
252 const struct GNUNET_MessageHeader *message);
255 * Message handler. Each struct specifies how to handle on particular
256 * type of message received.
258 struct GNUNET_SERVER_MessageHandler
261 * Function to call for messages of "type".
263 GNUNET_SERVER_MessageCallback callback;
266 * Closure argument for @e callback.
271 * Type of the message this handler covers.
276 * Expected size of messages of this type. Use 0 for
277 * variable-size. If non-zero, messages of the given
278 * type will be discarded (and the connection closed)
279 * if they do not have the right size.
281 uint16_t expected_size;
287 * Options for the service (bitmask).
289 enum LEGACY_SERVICE_Options
292 * Use defaults. Terminates all client connections and the listen
293 * sockets immediately upon receiving the shutdown signal.
295 LEGACY_SERVICE_OPTION_NONE = 0,
298 * Do not trigger server shutdown on signal at all; instead, allow
299 * for the user to terminate the server explicitly when needed
300 * by calling #LEGACY_SERVICE_shutdown().
302 LEGACY_SERVICE_OPTION_MANUAL_SHUTDOWN = 1,
305 * Trigger a SOFT server shutdown on signals, allowing active
306 * non-monitor clients to complete their transactions.
308 LEGACY_SERVICE_OPTION_SOFT_SHUTDOWN = 2
314 * Ask the server to disconnect from the given client. This is the
315 * same as passing #GNUNET_SYSERR to #GNUNET_SERVER_receive_done,
316 * except that it allows dropping of a client even when not handling a
317 * message from that client.
319 * @param client the client to disconnect from
322 GNUNET_SERVER_client_disconnect (struct GNUNET_SERVER_Client *client);
325 * Return user context associated with the given client.
326 * Note: you should probably use the macro (call without the underscore).
328 * @param client client to query
329 * @param size number of bytes in user context struct (for verification only)
330 * @return pointer to user context
333 GNUNET_SERVER_client_get_user_context_ (struct GNUNET_SERVER_Client *client,
338 * Functions with this signature are called whenever a
339 * complete message is received by the tokenizer.
341 * Do not call #GNUNET_SERVER_mst_destroy from within
342 * the scope of this callback.
345 * @param client identification of the client
346 * @param message the actual message
347 * @return #GNUNET_OK on success, #GNUNET_SYSERR to stop further processing
350 (*GNUNET_SERVER_MessageTokenizerCallback) (void *cls,
352 const struct GNUNET_MessageHeader *message);
356 * Create a message stream tokenizer.
358 * @param cb function to call on completed messages
359 * @param cb_cls closure for @a cb
360 * @return handle to tokenizer
362 struct GNUNET_SERVER_MessageStreamTokenizer *
363 GNUNET_SERVER_mst_create (GNUNET_SERVER_MessageTokenizerCallback cb,
367 * Add incoming data to the receive buffer and call the
368 * callback for all complete messages.
370 * @param mst tokenizer to use
371 * @param client_identity ID of client for which this is a buffer,
372 * can be NULL (will be passed back to 'cb')
373 * @param buf input data to add
374 * @param size number of bytes in @a buf
375 * @param purge should any excess bytes in the buffer be discarded
376 * (i.e. for packet-based services like UDP)
377 * @param one_shot only call callback once, keep rest of message in buffer
378 * @return #GNUNET_OK if we are done processing (need more data)
379 * #GNUNET_NO if one_shot was set and we have another message ready
380 * #GNUNET_SYSERR if the data stream is corrupt
383 GNUNET_SERVER_mst_receive (struct GNUNET_SERVER_MessageStreamTokenizer *mst,
384 void *client_identity,
385 const char *buf, size_t size,
386 int purge, int one_shot);
391 * Destroys a tokenizer.
393 * @param mst tokenizer to destroy
396 GNUNET_SERVER_mst_destroy (struct GNUNET_SERVER_MessageStreamTokenizer *mst);
400 * Set user context to be associated with the given client.
401 * Note: you should probably use the macro (call without the underscore).
403 * @param client client to query
404 * @param ptr pointer to user context
405 * @param size number of bytes in user context struct (for verification only)
408 GNUNET_SERVER_client_set_user_context_ (struct GNUNET_SERVER_Client *client,
412 * Return user context associated with the given client.
414 * @param client client to query
415 * @param type expected return type (i.e. 'struct Foo')
416 * @return pointer to user context of type 'type *'.
418 #define GNUNET_SERVER_client_get_user_context(client,type) \
419 (type *) GNUNET_SERVER_client_get_user_context_ (client, sizeof (type))
422 * Set user context to be associated with the given client.
424 * @param client client to query
425 * @param value pointer to user context
427 #define GNUNET_SERVER_client_set_user_context(client,value) \
428 GNUNET_SERVER_client_set_user_context_ (client, value, sizeof (*value))
433 * Notify us when the server has enough space to transmit
434 * a message of the given size to the given client.
436 * @param client client to transmit message to
437 * @param size requested amount of buffer space
438 * @param timeout after how long should we give up (and call
439 * notify with buf NULL and size 0)?
440 * @param callback function to call when space is available
441 * @param callback_cls closure for @a callback
442 * @return non-NULL if the notify callback was queued; can be used
443 * to cancel the request using
444 * #GNUNET_SERVER_notify_transmit_ready_cancel.
445 * NULL if we are already going to notify someone else (busy)
447 struct GNUNET_SERVER_TransmitHandle *
448 GNUNET_SERVER_notify_transmit_ready (struct GNUNET_SERVER_Client *client,
450 struct GNUNET_TIME_Relative timeout,
451 GNUNET_CONNECTION_TransmitReadyNotify callback,
455 * Abort transmission request.
457 * @param th request to abort
460 GNUNET_SERVER_notify_transmit_ready_cancel (struct GNUNET_SERVER_TransmitHandle *th);
466 * Notify the server that the given client handle should
467 * be kept (keeps the connection up if possible, increments
468 * the internal reference counter).
470 * @param client the client to keep
473 GNUNET_SERVER_client_keep (struct GNUNET_SERVER_Client *client);
477 * Notify the server that the given client handle is no
478 * longer required. Decrements the reference counter. If
479 * that counter reaches zero an inactive connection maybe
482 * @param client the client to drop
485 GNUNET_SERVER_client_drop (struct GNUNET_SERVER_Client *client);
489 * Function called by the service's run
490 * method to run service-specific setup code.
493 * @param server the initialized server
494 * @param cfg configuration to use
497 (*LEGACY_SERVICE_Main) (void *cls,
498 struct GNUNET_SERVER_Handle *server,
499 const struct GNUNET_CONFIGURATION_Handle *cfg);
504 * Suspend accepting connections from the listen socket temporarily.
505 * Resume activity using #GNUNET_SERVER_resume.
507 * @param server server to stop accepting connections.
510 GNUNET_SERVER_suspend (struct GNUNET_SERVER_Handle *server);
513 * Notify us when the server has enough space to transmit
514 * a message of the given size to the given client.
516 * @param client client to transmit message to
517 * @param size requested amount of buffer space
518 * @param timeout after how long should we give up (and call
519 * notify with buf NULL and size 0)?
520 * @param callback function to call when space is available
521 * @param callback_cls closure for @a callback
522 * @return non-NULL if the notify callback was queued; can be used
523 * to cancel the request using
524 * #GNUNET_SERVER_notify_transmit_ready_cancel.
525 * NULL if we are already going to notify someone else (busy)
527 struct GNUNET_SERVER_TransmitHandle *
528 GNUNET_SERVER_notify_transmit_ready (struct GNUNET_SERVER_Client *client,
530 struct GNUNET_TIME_Relative timeout,
531 GNUNET_CONNECTION_TransmitReadyNotify callback,
536 * Add a TCP socket-based connection to the set of handles managed by
537 * this server. Use this function for outgoing (P2P) connections that
538 * we initiated (and where this server should process incoming
541 * @param server the server to use
542 * @param connection the connection to manage (client must
543 * stop using this connection from now on)
544 * @return the client handle
546 struct GNUNET_SERVER_Client *
547 GNUNET_SERVER_connect_socket (struct GNUNET_SERVER_Handle *server,
548 struct GNUNET_CONNECTION_Handle *connection);
552 * Resume accepting connections from the listen socket.
554 * @param server server to resume accepting connections.
557 GNUNET_SERVER_resume (struct GNUNET_SERVER_Handle *server);
560 * Free resources held by this server.
562 * @param server server to destroy
565 GNUNET_SERVER_destroy (struct GNUNET_SERVER_Handle *server);
570 #include "tcp_connection_legacy.c"
571 #include "tcp_server_mst_legacy.c"
572 #include "tcp_server_legacy.c"
573 #include "tcp_service_legacy.c"
575 GNUNET_NETWORK_STRUCT_BEGIN
578 * Initial handshake message for a session.
580 struct WelcomeMessage
583 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_WELCOME.
585 struct GNUNET_MessageHeader header;
588 * Identity of the node connecting (TCP client)
590 struct GNUNET_PeerIdentity clientIdentity;
595 * Basically a WELCOME message, but with the purpose
596 * of giving the waiting peer a client handle to use
598 struct TCP_NAT_ProbeMessage
601 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_NAT_PROBE.
603 struct GNUNET_MessageHeader header;
606 * Identity of the sender of the message.
608 struct GNUNET_PeerIdentity clientIdentity;
611 GNUNET_NETWORK_STRUCT_END
614 * Context for sending a NAT probe via TCP.
616 struct TCPProbeContext
620 * Active probes are kept in a DLL.
622 struct TCPProbeContext *next;
625 * Active probes are kept in a DLL.
627 struct TCPProbeContext *prev;
632 struct GNUNET_CONNECTION_Handle *sock;
635 * Message to be sent.
637 struct TCP_NAT_ProbeMessage message;
640 * Handle to the transmission.
642 struct GNUNET_CONNECTION_TransmitHandle *transmit_handle;
645 * Transport plugin handle.
647 struct Plugin *plugin;
651 * Bits in the `options` field of TCP addresses.
653 enum TcpAddressOptions
659 TCP_OPTIONS_NONE = 0,
662 * See #HTTP_OPTIONS_VERIFY_CERTIFICATE.
664 TCP_OPTIONS_RESERVED = 1,
667 * Enable TCP Stealth-style port knocking.
669 TCP_OPTIONS_TCP_STEALTH = 2
672 GNUNET_NETWORK_STRUCT_BEGIN
675 * Network format for IPv4 addresses.
677 struct IPv4TcpAddress
680 * Optional options and flags for this address,
681 * see `enum TcpAddressOptions`
683 uint32_t options GNUNET_PACKED;
686 * IPv4 address, in network byte order.
688 uint32_t ipv4_addr GNUNET_PACKED;
691 * Port number, in network byte order.
693 uint16_t t4_port GNUNET_PACKED;
698 * Network format for IPv6 addresses.
700 struct IPv6TcpAddress
703 * Optional flags for this address
704 * see `enum TcpAddressOptions`
706 uint32_t options GNUNET_PACKED;
711 struct in6_addr ipv6_addr GNUNET_PACKED;
714 * Port number, in network byte order.
716 uint16_t t6_port GNUNET_PACKED;
719 GNUNET_NETWORK_STRUCT_END
722 * Encapsulation of all of the state of the plugin.
727 * Information kept for each message that is yet to
730 struct PendingMessage
734 * This is a doubly-linked list.
736 struct PendingMessage *next;
739 * This is a doubly-linked list.
741 struct PendingMessage *prev;
744 * The pending message
749 * Continuation function to call once the message
750 * has been sent. Can be NULL if there is no
751 * continuation to call.
753 GNUNET_TRANSPORT_TransmitContinuation transmit_cont;
756 * Closure for @e transmit_cont.
758 void *transmit_cont_cls;
761 * Timeout value for the pending message.
763 struct GNUNET_TIME_Absolute timeout;
766 * So that the gnunet-service-transport can group messages together,
767 * these pending messages need to accept a message buffer and size
768 * instead of just a `struct GNUNET_MessageHeader`.
775 * Session handle for TCP connections.
777 struct GNUNET_ATS_Session
780 * To whom are we talking to (set to our identity
781 * if we are still waiting for the welcome message)
783 struct GNUNET_PeerIdentity target;
786 * Pointer to the global plugin struct.
788 struct Plugin *plugin;
791 * The client (used to identify this connection)
793 struct GNUNET_SERVER_Client *client;
796 * Task cleaning up a NAT client connection establishment attempt;
798 struct GNUNET_SCHEDULER_Task *nat_connection_timeout;
801 * Messages currently pending for transmission
802 * to this peer, if any.
804 struct PendingMessage *pending_messages_head;
807 * Messages currently pending for transmission
808 * to this peer, if any.
810 struct PendingMessage *pending_messages_tail;
813 * Handle for pending transmission request.
815 struct GNUNET_SERVER_TransmitHandle *transmit_handle;
818 * Address of the other peer.
820 struct GNUNET_HELLO_Address *address;
823 * ID of task used to delay receiving more to throttle sender.
825 struct GNUNET_SCHEDULER_Task *receive_delay_task;
828 * Session timeout task
830 struct GNUNET_SCHEDULER_Task *timeout_task;
833 * When will this session time out?
835 struct GNUNET_TIME_Absolute timeout;
838 * When will we continue to read from the socket?
839 * (used to enforce inbound quota).
841 struct GNUNET_TIME_Absolute receive_delay;
844 * Last activity on this connection. Used to select preferred
847 struct GNUNET_TIME_Absolute last_activity;
850 * Number of bytes waiting for transmission to this peer.
852 unsigned long long bytes_in_queue;
855 * Number of messages waiting for transmission to this peer.
857 unsigned int msgs_in_queue;
860 * Network type of the address.
862 enum GNUNET_ATS_Network_Type scope;
865 * Are we still expecting the welcome message? (#GNUNET_YES/#GNUNET_NO)
867 int expecting_welcome;
870 * Was this session created using NAT traversal?
878 * Context for address to string conversion, closure
879 * for #append_port().
881 struct PrettyPrinterContext
886 struct PrettyPrinterContext *next;
891 struct PrettyPrinterContext *prev;
896 struct Plugin *plugin;
901 struct GNUNET_SCHEDULER_Task *timeout_task;
906 struct GNUNET_RESOLVER_RequestHandle *resolver_handle;
909 * Function to call with the result.
911 GNUNET_TRANSPORT_AddressStringCallback asc;
914 * Clsoure for @e asc.
929 * Port to add after the IP address.
936 * Encapsulation of all of the state of the plugin.
943 struct GNUNET_TRANSPORT_PluginEnvironment *env;
948 struct GNUNET_CONNECTION_Handle *lsock;
951 * Our handle to the NAT module.
953 struct GNUNET_NAT_Handle *nat;
956 * Map from peer identities to sessions for the given peer.
958 struct GNUNET_CONTAINER_MultiPeerMap *sessionmap;
961 * Handle to the network service.
963 struct LEGACY_SERVICE_Context *service;
966 * Handle to the server for this service.
968 struct GNUNET_SERVER_Handle *server;
971 * Copy of the handler array where the closures are
972 * set to this struct's instance.
974 struct GNUNET_SERVER_MessageHandler *handlers;
977 * Map of peers we have tried to contact behind a NAT
979 struct GNUNET_CONTAINER_MultiPeerMap *nat_wait_conns;
982 * List of active TCP probes.
984 struct TCPProbeContext *probe_head;
987 * List of active TCP probes.
989 struct TCPProbeContext *probe_tail;
992 * Function to call about session status changes.
994 GNUNET_TRANSPORT_SessionInfoCallback sic;
997 * Closure for @e sic.
1002 * ID of task used to update our addresses when one expires.
1004 struct GNUNET_SCHEDULER_Task *address_update_task;
1007 * Running pretty printers: head
1009 struct PrettyPrinterContext *ppc_dll_head;
1012 * Running pretty printers: tail
1014 struct PrettyPrinterContext *ppc_dll_tail;
1017 * Welcome message used by this peer.
1019 struct WelcomeMessage my_welcome;
1022 * How many more TCP sessions are we allowed to open right now?
1024 unsigned long long max_connections;
1027 * How many more TCP sessions do we have right now?
1029 unsigned long long cur_connections;
1037 * Port that we are actually listening on.
1042 * Port that the user said we would have visible to the
1043 * rest of the world.
1051 * Get the list of addresses that a server for the given service
1054 * @param service_name name of the service
1055 * @param cfg configuration (which specifies the addresses)
1056 * @param addrs set (call by reference) to an array of pointers to the
1057 * addresses the server should bind to and listen on; the
1058 * array will be NULL-terminated (on success)
1059 * @param addr_lens set (call by reference) to an array of the lengths
1060 * of the respective `struct sockaddr` struct in the @a addrs
1061 * array (on success)
1062 * @return number of addresses found on success,
1063 * #GNUNET_SYSERR if the configuration
1064 * did not specify reasonable finding information or
1065 * if it specified a hostname that could not be resolved;
1066 * #GNUNET_NO if the number of addresses configured is
1067 * zero (in this case, `*addrs` and `*addr_lens` will be
1071 get_server_addresses (const char *service_name,
1072 const struct GNUNET_CONFIGURATION_Handle *cfg,
1073 struct sockaddr ***addrs,
1074 socklen_t ** addr_lens)
1077 struct GNUNET_NETWORK_Handle *desc;
1078 unsigned long long port;
1080 struct addrinfo hints;
1081 struct addrinfo *res;
1082 struct addrinfo *pos;
1083 struct addrinfo *next;
1088 struct sockaddr **saddrs;
1089 socklen_t *saddrlens;
1095 if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "DISABLEV6"))
1097 if (GNUNET_SYSERR ==
1099 GNUNET_CONFIGURATION_get_value_yesno (cfg, service_name, "DISABLEV6")))
1100 return GNUNET_SYSERR;
1103 disablev6 = GNUNET_NO;
1107 /* probe IPv6 support */
1108 desc = GNUNET_NETWORK_socket_create (PF_INET6, SOCK_STREAM, 0);
1111 if ((ENOBUFS == errno) || (ENOMEM == errno) || (ENFILE == errno) ||
1114 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "socket");
1115 return GNUNET_SYSERR;
1117 LOG (GNUNET_ERROR_TYPE_INFO,
1118 _("Disabling IPv6 support for service `%s', failed to create IPv6 socket: %s\n"),
1119 service_name, STRERROR (errno));
1120 disablev6 = GNUNET_YES;
1124 GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (desc));
1130 if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "PORT"))
1133 GNUNET_CONFIGURATION_get_value_number (cfg, service_name,
1136 LOG (GNUNET_ERROR_TYPE_ERROR,
1137 _("Require valid port number for service `%s' in configuration!\n"),
1142 LOG (GNUNET_ERROR_TYPE_ERROR,
1143 _("Require valid port number for service `%s' in configuration!\n"),
1145 return GNUNET_SYSERR;
1149 if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "BINDTO"))
1151 GNUNET_break (GNUNET_OK ==
1152 GNUNET_CONFIGURATION_get_value_string (cfg, service_name,
1153 "BINDTO", &hostname));
1159 abstract = GNUNET_NO;
1162 GNUNET_CONFIGURATION_have_value (cfg, service_name, "UNIXPATH")) &&
1164 GNUNET_CONFIGURATION_get_value_filename (cfg, service_name, "UNIXPATH",
1166 (0 < strlen (unixpath)))
1168 /* probe UNIX support */
1169 struct sockaddr_un s_un;
1171 if (strlen (unixpath) >= sizeof (s_un.sun_path))
1173 LOG (GNUNET_ERROR_TYPE_WARNING,
1174 _("UNIXPATH `%s' too long, maximum length is %llu\n"), unixpath,
1175 (unsigned long long) sizeof (s_un.sun_path));
1176 unixpath = GNUNET_NETWORK_shorten_unixpath (unixpath);
1177 LOG (GNUNET_ERROR_TYPE_INFO,
1178 _("Using `%s' instead\n"),
1182 abstract = GNUNET_CONFIGURATION_get_value_yesno (cfg,
1184 "USE_ABSTRACT_SOCKETS");
1185 if (GNUNET_SYSERR == abstract)
1186 abstract = GNUNET_NO;
1188 if ((GNUNET_YES != abstract)
1190 GNUNET_DISK_directory_create_for_file (unixpath)))
1191 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
1195 if (NULL != unixpath)
1197 desc = GNUNET_NETWORK_socket_create (AF_UNIX, SOCK_STREAM, 0);
1200 if ((ENOBUFS == errno) || (ENOMEM == errno) || (ENFILE == errno) ||
1203 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "socket");
1204 GNUNET_free_non_null (hostname);
1205 GNUNET_free (unixpath);
1206 return GNUNET_SYSERR;
1208 LOG (GNUNET_ERROR_TYPE_INFO,
1209 _("Disabling UNIX domain socket support for service `%s', failed to create UNIX domain socket: %s\n"),
1212 GNUNET_free (unixpath);
1217 GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (desc));
1223 if ((0 == port) && (NULL == unixpath))
1225 LOG (GNUNET_ERROR_TYPE_ERROR,
1226 _("Have neither PORT nor UNIXPATH for service `%s', but one is required\n"),
1228 GNUNET_free_non_null (hostname);
1229 return GNUNET_SYSERR;
1233 saddrs = GNUNET_malloc (2 * sizeof (struct sockaddr *));
1234 saddrlens = GNUNET_malloc (2 * sizeof (socklen_t));
1235 add_unixpath (saddrs, saddrlens, unixpath, abstract);
1236 GNUNET_free_non_null (unixpath);
1237 GNUNET_free_non_null (hostname);
1239 *addr_lens = saddrlens;
1243 if (NULL != hostname)
1245 LOG (GNUNET_ERROR_TYPE_DEBUG,
1246 "Resolving `%s' since that is where `%s' will bind to.\n",
1249 memset (&hints, 0, sizeof (struct addrinfo));
1251 hints.ai_family = AF_INET;
1252 hints.ai_protocol = IPPROTO_TCP;
1253 if ((0 != (ret = getaddrinfo (hostname, NULL, &hints, &res))) ||
1256 LOG (GNUNET_ERROR_TYPE_ERROR,
1257 _("Failed to resolve `%s': %s\n"),
1259 gai_strerror (ret));
1260 GNUNET_free (hostname);
1261 GNUNET_free_non_null (unixpath);
1262 return GNUNET_SYSERR;
1266 while (NULL != (pos = next))
1268 next = pos->ai_next;
1269 if ((disablev6) && (pos->ai_family == AF_INET6))
1275 LOG (GNUNET_ERROR_TYPE_ERROR,
1276 _("Failed to find %saddress for `%s'.\n"),
1277 disablev6 ? "IPv4 " : "",
1280 GNUNET_free (hostname);
1281 GNUNET_free_non_null (unixpath);
1282 return GNUNET_SYSERR;
1285 if (NULL != unixpath)
1287 saddrs = GNUNET_malloc ((resi + 1) * sizeof (struct sockaddr *));
1288 saddrlens = GNUNET_malloc ((resi + 1) * sizeof (socklen_t));
1290 if (NULL != unixpath)
1292 add_unixpath (saddrs, saddrlens, unixpath, abstract);
1296 while (NULL != (pos = next))
1298 next = pos->ai_next;
1299 if ((disablev6) && (AF_INET6 == pos->ai_family))
1301 if ((IPPROTO_TCP != pos->ai_protocol) && (0 != pos->ai_protocol))
1302 continue; /* not TCP */
1303 if ((SOCK_STREAM != pos->ai_socktype) && (0 != pos->ai_socktype))
1304 continue; /* huh? */
1305 LOG (GNUNET_ERROR_TYPE_DEBUG, "Service `%s' will bind to `%s'\n",
1306 service_name, GNUNET_a2s (pos->ai_addr, pos->ai_addrlen));
1307 if (AF_INET == pos->ai_family)
1309 GNUNET_assert (sizeof (struct sockaddr_in) == pos->ai_addrlen);
1310 saddrlens[i] = pos->ai_addrlen;
1311 saddrs[i] = GNUNET_malloc (saddrlens[i]);
1312 GNUNET_memcpy (saddrs[i], pos->ai_addr, saddrlens[i]);
1313 ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
1317 GNUNET_assert (AF_INET6 == pos->ai_family);
1318 GNUNET_assert (sizeof (struct sockaddr_in6) == pos->ai_addrlen);
1319 saddrlens[i] = pos->ai_addrlen;
1320 saddrs[i] = GNUNET_malloc (saddrlens[i]);
1321 GNUNET_memcpy (saddrs[i], pos->ai_addr, saddrlens[i]);
1322 ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port);
1326 GNUNET_free (hostname);
1332 /* will bind against everything, just set port */
1337 if (NULL != unixpath)
1340 saddrs = GNUNET_malloc ((resi + 1) * sizeof (struct sockaddr *));
1341 saddrlens = GNUNET_malloc ((resi + 1) * sizeof (socklen_t));
1342 if (NULL != unixpath)
1344 add_unixpath (saddrs, saddrlens, unixpath, abstract);
1347 saddrlens[i] = sizeof (struct sockaddr_in);
1348 saddrs[i] = GNUNET_malloc (saddrlens[i]);
1349 #if HAVE_SOCKADDR_IN_SIN_LEN
1350 ((struct sockaddr_in *) saddrs[i])->sin_len = saddrlens[i];
1352 ((struct sockaddr_in *) saddrs[i])->sin_family = AF_INET;
1353 ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
1359 if (NULL != unixpath)
1361 saddrs = GNUNET_malloc ((resi + 1) * sizeof (struct sockaddr *));
1362 saddrlens = GNUNET_malloc ((resi + 1) * sizeof (socklen_t));
1364 if (NULL != unixpath)
1366 add_unixpath (saddrs, saddrlens, unixpath, abstract);
1369 saddrlens[i] = sizeof (struct sockaddr_in6);
1370 saddrs[i] = GNUNET_malloc (saddrlens[i]);
1371 #if HAVE_SOCKADDR_IN_SIN_LEN
1372 ((struct sockaddr_in6 *) saddrs[i])->sin6_len = saddrlens[0];
1374 ((struct sockaddr_in6 *) saddrs[i])->sin6_family = AF_INET6;
1375 ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port);
1377 saddrlens[i] = sizeof (struct sockaddr_in);
1378 saddrs[i] = GNUNET_malloc (saddrlens[i]);
1379 #if HAVE_SOCKADDR_IN_SIN_LEN
1380 ((struct sockaddr_in *) saddrs[i])->sin_len = saddrlens[1];
1382 ((struct sockaddr_in *) saddrs[i])->sin_family = AF_INET;
1383 ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
1386 GNUNET_free_non_null (unixpath);
1388 *addr_lens = saddrlens;
1391 /* end ancient copy-and-paste */
1395 * If a session monitor is attached, notify it about the new
1398 * @param plugin our plugin
1399 * @param session session that changed state
1400 * @param state new state of the session
1403 notify_session_monitor (struct Plugin *plugin,
1404 struct GNUNET_ATS_Session *session,
1405 enum GNUNET_TRANSPORT_SessionState state)
1407 struct GNUNET_TRANSPORT_SessionInfo info;
1409 if (NULL == plugin->sic)
1411 memset (&info, 0, sizeof (info));
1413 info.is_inbound = GNUNET_HELLO_address_check_option (session->address,
1414 GNUNET_HELLO_ADDRESS_INFO_INBOUND);
1415 info.num_msg_pending = session->msgs_in_queue;
1416 info.num_bytes_pending = session->bytes_in_queue;
1417 if (NULL != session->receive_delay_task)
1418 info.receive_delay = session->receive_delay;
1419 info.session_timeout = session->timeout;
1420 info.address = session->address;
1421 plugin->sic (plugin->sic_cls,
1428 * Our external IP address/port mapping has changed.
1430 * @param cls closure, the `struct Plugin`
1431 * @param add_remove #GNUNET_YES to mean the new public IP address, #GNUNET_NO to mean
1432 * the previous (now invalid) one
1433 * @param ac address class the address belongs to
1434 * @param addr either the previous or the new public IP address
1435 * @param addrlen actual length of @a addr
1438 tcp_nat_port_map_callback (void *cls,
1440 enum GNUNET_NAT_AddressClass ac,
1441 const struct sockaddr *addr,
1444 struct Plugin *plugin = cls;
1445 struct GNUNET_HELLO_Address *address;
1446 struct IPv4TcpAddress t4;
1447 struct IPv6TcpAddress t6;
1451 if (GNUNET_NAT_AC_LOOPBACK == ac)
1453 if (GNUNET_NAT_AC_LAN == ac)
1455 if (GNUNET_NAT_AC_LAN_PRIVATE == ac)
1457 LOG (GNUNET_ERROR_TYPE_INFO,
1458 "NAT notification to %s address `%s'\n",
1459 (GNUNET_YES == add_remove) ? "add" : "remove",
1460 GNUNET_a2s (addr, addrlen));
1461 /* convert 'addr' to our internal format */
1462 switch (addr->sa_family)
1465 GNUNET_assert(addrlen == sizeof(struct sockaddr_in));
1466 memset (&t4, 0, sizeof(t4));
1467 t4.options = htonl (plugin->myoptions);
1468 t4.ipv4_addr = ((struct sockaddr_in *) addr)->sin_addr.s_addr;
1469 t4.t4_port = ((struct sockaddr_in *) addr)->sin_port;
1474 GNUNET_assert(addrlen == sizeof(struct sockaddr_in6));
1475 memset (&t6, 0, sizeof(t6));
1476 GNUNET_memcpy (&t6.ipv6_addr,
1477 &((struct sockaddr_in6 *) addr)->sin6_addr,
1478 sizeof(struct in6_addr));
1479 t6.options = htonl (plugin->myoptions);
1480 t6.t6_port = ((struct sockaddr_in6 *) addr)->sin6_port;
1488 /* modify our published address list */
1489 GNUNET_assert ((args == sizeof (struct IPv4TcpAddress)) ||
1490 (args == sizeof (struct IPv6TcpAddress)));
1491 /* TODO: use 'ac' here in the future... */
1492 address = GNUNET_HELLO_address_allocate (plugin->env->my_identity,
1496 GNUNET_HELLO_ADDRESS_INFO_NONE);
1497 plugin->env->notify_address (plugin->env->cls,
1500 GNUNET_HELLO_address_free (address);
1505 * Function called for a quick conversion of the binary address to
1506 * a numeric address. Note that the caller must not free the
1507 * address and that the next call to this function is allowed
1508 * to override the address again.
1510 * @param cls closure (`struct Plugin*`)
1511 * @param addr binary address
1512 * @param addrlen length of @a addr
1513 * @return string representing the same address
1516 tcp_plugin_address_to_string (void *cls,
1520 static char rbuf[INET6_ADDRSTRLEN + 12];
1521 char buf[INET6_ADDRSTRLEN];
1525 const struct IPv4TcpAddress *t4;
1526 const struct IPv6TcpAddress *t6;
1533 case sizeof(struct IPv6TcpAddress):
1536 port = ntohs (t6->t6_port);
1537 options = ntohl (t6->options);
1538 GNUNET_memcpy (&a6, &t6->ipv6_addr, sizeof(a6));
1541 case sizeof(struct IPv4TcpAddress):
1544 port = ntohs (t4->t4_port);
1545 options = ntohl (t4->options);
1546 GNUNET_memcpy (&a4, &t4->ipv4_addr, sizeof(a4));
1550 LOG (GNUNET_ERROR_TYPE_WARNING,
1551 _("Unexpected address length: %u bytes\n"),
1552 (unsigned int) addrlen);
1555 if (NULL == inet_ntop (af, sb, buf, INET6_ADDRSTRLEN))
1557 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
1561 GNUNET_snprintf (rbuf, sizeof(rbuf),
1562 (af == AF_INET6) ? "%s.%u.[%s]:%u" : "%s.%u.%s:%u",
1572 * Function called to convert a string address to
1575 * @param cls closure (`struct Plugin*`)
1576 * @param addr string address
1577 * @param addrlen length of the address
1578 * @param buf location to store the buffer
1579 * @param added location to store the number of bytes in the buffer.
1580 * If the function returns #GNUNET_SYSERR, its contents are undefined.
1581 * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure
1584 tcp_plugin_string_to_address (void *cls,
1590 struct sockaddr_storage socket_address;
1596 /* Format tcp.options.address:port */
1600 if ((NULL == addr) || (0 == addrlen))
1603 return GNUNET_SYSERR;
1605 if ('\0' != addr[addrlen - 1])
1608 return GNUNET_SYSERR;
1610 if (strlen (addr) != addrlen - 1)
1613 return GNUNET_SYSERR;
1615 plugin = GNUNET_strdup (addr);
1616 optionstr = strchr (plugin, '.');
1617 if (NULL == optionstr)
1620 GNUNET_free(plugin);
1621 return GNUNET_SYSERR;
1623 optionstr[0] = '\0';
1625 options = atol (optionstr);
1626 address = strchr (optionstr, '.');
1627 if (NULL == address)
1630 GNUNET_free(plugin);
1631 return GNUNET_SYSERR;
1637 GNUNET_STRINGS_to_address_ip (address,
1642 GNUNET_free(plugin);
1643 return GNUNET_SYSERR;
1646 GNUNET_free(plugin);
1647 switch (socket_address.ss_family)
1651 struct IPv4TcpAddress *t4;
1652 struct sockaddr_in *in4 = (struct sockaddr_in *) &socket_address;
1653 t4 = GNUNET_new (struct IPv4TcpAddress);
1654 t4->options = htonl (options);
1655 t4->ipv4_addr = in4->sin_addr.s_addr;
1656 t4->t4_port = in4->sin_port;
1658 *added = sizeof(struct IPv4TcpAddress);
1663 struct IPv6TcpAddress *t6;
1664 struct sockaddr_in6 *in6 = (struct sockaddr_in6 *) &socket_address;
1665 t6 = GNUNET_new (struct IPv6TcpAddress);
1666 t6->options = htonl (options);
1667 t6->ipv6_addr = in6->sin6_addr;
1668 t6->t6_port = in6->sin6_port;
1670 *added = sizeof(struct IPv6TcpAddress);
1674 return GNUNET_SYSERR;
1680 * Find the session handle for the given client.
1681 * Currently uses both the hashmap and the client
1682 * context, as the client context is new and the
1683 * logic still needs to be tested.
1685 * @param plugin the plugin
1686 * @param client which client to find the session handle for
1687 * @return NULL if no matching session exists
1689 static struct GNUNET_ATS_Session *
1690 lookup_session_by_client (struct Plugin *plugin,
1691 struct GNUNET_SERVER_Client *client)
1693 return GNUNET_SERVER_client_get_user_context (client,
1694 struct GNUNET_ATS_Session);
1699 * Functions with this signature are called whenever we need
1700 * to close a session due to a disconnect or failure to
1701 * establish a connection.
1703 * @param cls the `struct Plugin`
1704 * @param session session to close down
1705 * @return #GNUNET_OK on success
1708 tcp_plugin_disconnect_session (void *cls,
1709 struct GNUNET_ATS_Session *session)
1711 struct Plugin *plugin = cls;
1712 struct PendingMessage *pm;
1714 LOG (GNUNET_ERROR_TYPE_DEBUG,
1715 "Disconnecting session of peer `%s' address `%s'\n",
1716 GNUNET_i2s (&session->target),
1717 tcp_plugin_address_to_string (session->plugin,
1718 session->address->address,
1719 session->address->address_length));
1721 if (NULL != session->timeout_task)
1723 GNUNET_SCHEDULER_cancel (session->timeout_task);
1724 session->timeout_task = NULL;
1725 session->timeout = GNUNET_TIME_UNIT_ZERO_ABS;
1729 GNUNET_CONTAINER_multipeermap_remove (plugin->sessionmap,
1733 GNUNET_STATISTICS_update (session->plugin->env->stats,
1734 gettext_noop ("# TCP sessions active"),
1740 GNUNET_assert (GNUNET_YES ==
1741 GNUNET_CONTAINER_multipeermap_remove (plugin->nat_wait_conns,
1745 if (NULL != session->client)
1746 GNUNET_SERVER_client_set_user_context (session->client,
1749 /* clean up state */
1750 if (NULL != session->transmit_handle)
1752 GNUNET_SERVER_notify_transmit_ready_cancel (session->transmit_handle);
1753 session->transmit_handle = NULL;
1755 session->plugin->env->session_end (session->plugin->env->cls,
1759 if (NULL != session->nat_connection_timeout)
1761 GNUNET_SCHEDULER_cancel (session->nat_connection_timeout);
1762 session->nat_connection_timeout = NULL;
1765 while (NULL != (pm = session->pending_messages_head))
1767 LOG (GNUNET_ERROR_TYPE_DEBUG,
1768 (NULL != pm->transmit_cont)
1769 ? "Could not deliver message to `%s' at %s.\n"
1770 : "Could not deliver message to `%s' at %s, notifying.\n",
1771 GNUNET_i2s (&session->target),
1772 tcp_plugin_address_to_string (session->plugin,
1773 session->address->address,
1774 session->address->address_length));
1775 GNUNET_STATISTICS_update (session->plugin->env->stats,
1776 gettext_noop ("# bytes currently in TCP buffers"),
1777 -(int64_t) pm->message_size, GNUNET_NO);
1778 GNUNET_STATISTICS_update (session->plugin->env->stats,
1779 gettext_noop ("# bytes discarded by TCP (disconnect)"),
1782 GNUNET_CONTAINER_DLL_remove (session->pending_messages_head,
1783 session->pending_messages_tail,
1785 GNUNET_assert (0 < session->msgs_in_queue);
1786 session->msgs_in_queue--;
1787 GNUNET_assert (pm->message_size <= session->bytes_in_queue);
1788 session->bytes_in_queue -= pm->message_size;
1789 if (NULL != pm->transmit_cont)
1790 pm->transmit_cont (pm->transmit_cont_cls,
1797 GNUNET_assert (0 == session->msgs_in_queue);
1798 GNUNET_assert (0 == session->bytes_in_queue);
1799 notify_session_monitor (session->plugin,
1801 GNUNET_TRANSPORT_SS_DONE);
1803 if (NULL != session->receive_delay_task)
1805 GNUNET_SCHEDULER_cancel (session->receive_delay_task);
1806 session->receive_delay_task = NULL;
1808 if (NULL != session->client)
1810 GNUNET_SERVER_client_disconnect (session->client);
1811 session->client = NULL;
1813 GNUNET_HELLO_address_free (session->address);
1814 GNUNET_assert (NULL == session->transmit_handle);
1815 GNUNET_free (session);
1821 * Function that is called to get the keepalive factor.
1822 * #GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT is divided by this number to
1823 * calculate the interval between keepalive packets.
1825 * @param cls closure with the `struct Plugin`
1826 * @return keepalive factor
1829 tcp_plugin_query_keepalive_factor (void *cls)
1836 * Session was idle for too long, so disconnect it
1838 * @param cls the `struct GNUNET_ATS_Session` of the idle session
1841 session_timeout (void *cls)
1843 struct GNUNET_ATS_Session *s = cls;
1844 struct GNUNET_TIME_Relative left;
1846 s->timeout_task = NULL;
1847 left = GNUNET_TIME_absolute_get_remaining (s->timeout);
1848 if (0 != left.rel_value_us)
1850 /* not actually our turn yet, but let's at least update
1851 the monitor, it may think we're about to die ... */
1852 notify_session_monitor (s->plugin,
1854 GNUNET_TRANSPORT_SS_UPDATE);
1855 s->timeout_task = GNUNET_SCHEDULER_add_delayed (left,
1860 LOG (GNUNET_ERROR_TYPE_DEBUG,
1861 "Session %p was idle for %s, disconnecting\n",
1863 GNUNET_STRINGS_relative_time_to_string (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
1865 /* call session destroy function */
1866 tcp_plugin_disconnect_session (s->plugin,
1872 * Increment session timeout due to activity.
1874 * @param s session to increment timeout for
1877 reschedule_session_timeout (struct GNUNET_ATS_Session *s)
1879 GNUNET_assert (NULL != s->timeout_task);
1880 s->timeout = GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1885 * Create a new session. Also queues a welcome message.
1887 * @param plugin the plugin
1888 * @param address the address to create the session for
1889 * @param scope network scope the address is from
1890 * @param client client to use, reference counter must have already been increased
1891 * @param is_nat this a NAT session, we should wait for a client to
1892 * connect to us from an address, then assign that to
1894 * @return new session object
1896 static struct GNUNET_ATS_Session *
1897 create_session (struct Plugin *plugin,
1898 const struct GNUNET_HELLO_Address *address,
1899 enum GNUNET_ATS_Network_Type scope,
1900 struct GNUNET_SERVER_Client *client,
1903 struct GNUNET_ATS_Session *session;
1904 struct PendingMessage *pm;
1906 if (GNUNET_YES != is_nat)
1907 GNUNET_assert (NULL != client);
1909 GNUNET_assert (NULL == client);
1911 LOG (GNUNET_ERROR_TYPE_DEBUG,
1912 "Creating new session for peer `%s' at address %s\n",
1913 GNUNET_i2s (&address->peer),
1914 tcp_plugin_address_to_string (plugin,
1916 address->address_length));
1917 session = GNUNET_new (struct GNUNET_ATS_Session);
1918 session->last_activity = GNUNET_TIME_absolute_get ();
1919 session->plugin = plugin;
1920 session->is_nat = is_nat;
1923 session->client = client;
1924 GNUNET_SERVER_client_set_user_context (client,
1927 session->address = GNUNET_HELLO_address_copy (address);
1928 session->target = address->peer;
1929 session->expecting_welcome = GNUNET_YES;
1930 session->scope = scope;
1931 pm = GNUNET_malloc (sizeof (struct PendingMessage) +
1932 sizeof (struct WelcomeMessage));
1933 pm->msg = (const char *) &pm[1];
1934 pm->message_size = sizeof(struct WelcomeMessage);
1935 GNUNET_memcpy (&pm[1],
1936 &plugin->my_welcome,
1937 sizeof(struct WelcomeMessage));
1938 pm->timeout = GNUNET_TIME_UNIT_FOREVER_ABS;
1939 GNUNET_STATISTICS_update (plugin->env->stats,
1940 gettext_noop ("# bytes currently in TCP buffers"),
1943 GNUNET_CONTAINER_DLL_insert (session->pending_messages_head,
1944 session->pending_messages_tail,
1946 session->msgs_in_queue++;
1947 session->bytes_in_queue += pm->message_size;
1948 session->timeout = GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1949 session->timeout_task = GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
1952 notify_session_monitor (session->plugin,
1954 GNUNET_TRANSPORT_SS_INIT);
1955 if (GNUNET_YES != is_nat)
1957 GNUNET_STATISTICS_update (plugin->env->stats,
1958 gettext_noop ("# TCP sessions active"),
1961 notify_session_monitor (session->plugin,
1963 GNUNET_TRANSPORT_SS_UP);
1967 notify_session_monitor (session->plugin,
1969 GNUNET_TRANSPORT_SS_HANDSHAKE);
1976 * If we have pending messages, ask the server to
1977 * transmit them (schedule the respective tasks, etc.)
1979 * @param session for which session should we do this
1982 process_pending_messages (struct GNUNET_ATS_Session *session);
1986 * Function called to notify a client about the socket
1987 * being ready to queue more data. "buf" will be
1988 * NULL and "size" zero if the socket was closed for
1989 * writing in the meantime.
1991 * @param cls closure
1992 * @param size number of bytes available in @a buf
1993 * @param buf where the callee should write the message
1994 * @return number of bytes written to @a buf
1997 do_transmit (void *cls,
2001 struct GNUNET_ATS_Session *session = cls;
2002 struct GNUNET_PeerIdentity pid;
2003 struct Plugin *plugin;
2004 struct PendingMessage *pos;
2005 struct PendingMessage *hd;
2006 struct PendingMessage *tl;
2007 struct GNUNET_TIME_Absolute now;
2011 session->transmit_handle = NULL;
2012 plugin = session->plugin;
2015 LOG (GNUNET_ERROR_TYPE_DEBUG,
2016 "Timeout trying to transmit to peer `%s', discarding message queue.\n",
2017 GNUNET_i2s (&session->target));
2018 /* timeout; cancel all messages that have already expired */
2022 now = GNUNET_TIME_absolute_get ();
2023 while ( (NULL != (pos = session->pending_messages_head)) &&
2024 (pos->timeout.abs_value_us <= now.abs_value_us) )
2026 GNUNET_CONTAINER_DLL_remove (session->pending_messages_head,
2027 session->pending_messages_tail,
2029 GNUNET_assert (0 < session->msgs_in_queue);
2030 session->msgs_in_queue--;
2031 GNUNET_assert (pos->message_size <= session->bytes_in_queue);
2032 session->bytes_in_queue -= pos->message_size;
2033 LOG (GNUNET_ERROR_TYPE_DEBUG,
2034 "Failed to transmit %u byte message to `%s'.\n",
2036 GNUNET_i2s (&session->target));
2037 ret += pos->message_size;
2038 GNUNET_CONTAINER_DLL_insert_after (hd,
2043 /* do this call before callbacks (so that if callbacks destroy
2044 * session, they have a chance to cancel actions done by this
2046 process_pending_messages (session);
2047 pid = session->target;
2048 /* no do callbacks and do not use session again since
2049 * the callbacks may abort the session */
2050 while (NULL != (pos = hd))
2052 GNUNET_CONTAINER_DLL_remove (hd,
2055 if (NULL != pos->transmit_cont)
2056 pos->transmit_cont (pos->transmit_cont_cls,
2063 GNUNET_STATISTICS_update (plugin->env->stats,
2064 gettext_noop ("# bytes currently in TCP buffers"), -(int64_t) ret,
2066 GNUNET_STATISTICS_update (plugin->env->stats,
2067 gettext_noop ("# bytes discarded by TCP (timeout)"),
2071 notify_session_monitor (session->plugin,
2073 GNUNET_TRANSPORT_SS_UPDATE);
2076 /* copy all pending messages that would fit */
2081 while (NULL != (pos = session->pending_messages_head))
2083 if (ret + pos->message_size > size)
2085 GNUNET_CONTAINER_DLL_remove (session->pending_messages_head,
2086 session->pending_messages_tail,
2088 GNUNET_assert (0 < session->msgs_in_queue);
2089 session->msgs_in_queue--;
2090 GNUNET_assert (pos->message_size <= session->bytes_in_queue);
2091 session->bytes_in_queue -= pos->message_size;
2092 GNUNET_assert(size >= pos->message_size);
2093 LOG (GNUNET_ERROR_TYPE_DEBUG,
2094 "Transmitting message of type %u size %u to peer %s at %s\n",
2095 ntohs (((struct GNUNET_MessageHeader *) pos->msg)->type),
2097 GNUNET_i2s (&session->target),
2098 tcp_plugin_address_to_string (session->plugin,
2099 session->address->address,
2100 session->address->address_length));
2101 /* FIXME: this GNUNET_memcpy can be up to 7% of our total runtime */
2102 GNUNET_memcpy (cbuf,
2105 cbuf += pos->message_size;
2106 ret += pos->message_size;
2107 size -= pos->message_size;
2108 GNUNET_CONTAINER_DLL_insert_tail (hd,
2112 notify_session_monitor (session->plugin,
2114 GNUNET_TRANSPORT_SS_UPDATE);
2115 /* schedule 'continuation' before callbacks so that callbacks that
2116 * cancel everything don't cause us to use a session that no longer
2118 process_pending_messages (session);
2119 session->last_activity = GNUNET_TIME_absolute_get ();
2120 pid = session->target;
2121 /* we'll now call callbacks that may cancel the session; hence
2122 * we should not use 'session' after this point */
2123 while (NULL != (pos = hd))
2125 GNUNET_CONTAINER_DLL_remove (hd, tl, pos);
2126 if (NULL != pos->transmit_cont)
2127 pos->transmit_cont (pos->transmit_cont_cls,
2131 pos->message_size); /* FIXME: include TCP overhead */
2134 GNUNET_assert (NULL == hd);
2135 GNUNET_assert (NULL == tl);
2136 GNUNET_STATISTICS_update (plugin->env->stats,
2137 gettext_noop ("# bytes currently in TCP buffers"),
2140 GNUNET_STATISTICS_update (plugin->env->stats,
2141 gettext_noop ("# bytes transmitted via TCP"),
2149 * If we have pending messages, ask the server to
2150 * transmit them (schedule the respective tasks, etc.)
2152 * @param session for which session should we do this
2155 process_pending_messages (struct GNUNET_ATS_Session *session)
2157 struct PendingMessage *pm;
2159 GNUNET_assert (NULL != session->client);
2160 if (NULL != session->transmit_handle)
2162 if (NULL == (pm = session->pending_messages_head))
2165 session->transmit_handle
2166 = GNUNET_SERVER_notify_transmit_ready (session->client,
2168 GNUNET_TIME_absolute_get_remaining (pm->timeout),
2175 * Function that can be used by the transport service to transmit
2176 * a message using the plugin. Note that in the case of a
2177 * peer disconnecting, the continuation MUST be called
2178 * prior to the disconnect notification itself. This function
2179 * will be called with this peer's HELLO message to initiate
2180 * a fresh connection to another peer.
2182 * @param cls closure
2183 * @param session which session must be used
2184 * @param msgbuf the message to transmit
2185 * @param msgbuf_size number of bytes in @a msgbuf
2186 * @param priority how important is the message (most plugins will
2187 * ignore message priority and just FIFO)
2188 * @param to how long to wait at most for the transmission (does not
2189 * require plugins to discard the message after the timeout,
2190 * just advisory for the desired delay; most plugins will ignore
2192 * @param cont continuation to call once the message has
2193 * been transmitted (or if the transport is ready
2194 * for the next transmission call; or if the
2195 * peer disconnected...); can be NULL
2196 * @param cont_cls closure for @a cont
2197 * @return number of bytes used (on the physical network, with overheads);
2198 * -1 on hard errors (i.e. address invalid); 0 is a legal value
2199 * and does NOT mean that the message was not transmitted (DV)
2202 tcp_plugin_send (void *cls,
2203 struct GNUNET_ATS_Session *session,
2206 unsigned int priority,
2207 struct GNUNET_TIME_Relative to,
2208 GNUNET_TRANSPORT_TransmitContinuation cont,
2211 struct Plugin * plugin = cls;
2212 struct PendingMessage *pm;
2214 /* create new message entry */
2215 pm = GNUNET_malloc (sizeof (struct PendingMessage) + msgbuf_size);
2216 pm->msg = (const char *) &pm[1];
2217 GNUNET_memcpy (&pm[1], msgbuf, msgbuf_size);
2218 pm->message_size = msgbuf_size;
2219 pm->timeout = GNUNET_TIME_relative_to_absolute (to);
2220 pm->transmit_cont = cont;
2221 pm->transmit_cont_cls = cont_cls;
2223 LOG (GNUNET_ERROR_TYPE_DEBUG,
2224 "Asked to transmit %u bytes to `%s', added message to list.\n",
2226 GNUNET_i2s (&session->target));
2229 GNUNET_CONTAINER_multipeermap_contains_value (plugin->sessionmap,
2233 GNUNET_assert (NULL != session->client);
2234 GNUNET_SERVER_client_set_timeout (session->client,
2235 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2236 GNUNET_STATISTICS_update (plugin->env->stats,
2237 gettext_noop ("# bytes currently in TCP buffers"),
2241 /* append pm to pending_messages list */
2242 GNUNET_CONTAINER_DLL_insert_tail (session->pending_messages_head,
2243 session->pending_messages_tail,
2245 notify_session_monitor (session->plugin,
2247 GNUNET_TRANSPORT_SS_UPDATE);
2248 session->msgs_in_queue++;
2249 session->bytes_in_queue += pm->message_size;
2250 process_pending_messages (session);
2254 GNUNET_CONTAINER_multipeermap_contains_value (plugin->nat_wait_conns,
2258 LOG (GNUNET_ERROR_TYPE_DEBUG,
2259 "This NAT WAIT session for peer `%s' is not yet ready!\n",
2260 GNUNET_i2s (&session->target));
2261 GNUNET_STATISTICS_update (plugin->env->stats,
2262 gettext_noop ("# bytes currently in TCP buffers"), msgbuf_size,
2264 /* append pm to pending_messages list */
2265 GNUNET_CONTAINER_DLL_insert_tail (session->pending_messages_head,
2266 session->pending_messages_tail,
2268 session->msgs_in_queue++;
2269 session->bytes_in_queue += pm->message_size;
2270 notify_session_monitor (session->plugin,
2272 GNUNET_TRANSPORT_SS_HANDSHAKE);
2275 LOG (GNUNET_ERROR_TYPE_ERROR,
2276 "Invalid session %p\n",
2286 return GNUNET_SYSERR; /* session does not exist here */
2291 * Closure for #session_lookup_it().
2293 struct GNUNET_ATS_SessionItCtx
2296 * Address we are looking for.
2298 const struct GNUNET_HELLO_Address *address;
2301 * Where to store the session (if we found it).
2303 struct GNUNET_ATS_Session *result;
2309 * Look for a session by address.
2311 * @param cls the `struct GNUNET_ATS_SessionItCtx`
2313 * @param value a `struct GNUNET_ATS_Session`
2314 * @return #GNUNET_YES to continue looking, #GNUNET_NO if we found the session
2317 session_lookup_it (void *cls,
2318 const struct GNUNET_PeerIdentity *key,
2321 struct GNUNET_ATS_SessionItCtx *si_ctx = cls;
2322 struct GNUNET_ATS_Session *session = value;
2325 GNUNET_HELLO_address_cmp (si_ctx->address,
2328 si_ctx->result = session;
2334 * Task cleaning up a NAT connection attempt after timeout
2336 * @param cls the `struct GNUNET_ATS_Session`
2339 nat_connect_timeout (void *cls)
2341 struct GNUNET_ATS_Session *session = cls;
2343 session->nat_connection_timeout = NULL;
2344 LOG (GNUNET_ERROR_TYPE_DEBUG,
2345 "NAT WAIT connection to `%4s' at `%s' could not be established, removing session\n",
2346 GNUNET_i2s (&session->target),
2347 tcp_plugin_address_to_string (session->plugin,
2348 session->address->address,
2349 session->address->address_length));
2350 tcp_plugin_disconnect_session (session->plugin,
2356 * Function that will be called whenever the transport service wants to
2357 * notify the plugin that a session is still active and in use and
2358 * therefore the session timeout for this session has to be updated
2360 * @param cls closure
2361 * @param peer which peer was the session for
2362 * @param session which session is being updated
2365 tcp_plugin_update_session_timeout (void *cls,
2366 const struct GNUNET_PeerIdentity *peer,
2367 struct GNUNET_ATS_Session *session)
2369 reschedule_session_timeout (session);
2374 * Task to signal the server that we can continue
2375 * receiving from the TCP client now.
2377 * @param cls the `struct GNUNET_ATS_Session *`
2380 delayed_done (void *cls)
2382 struct GNUNET_ATS_Session *session = cls;
2384 session->receive_delay_task = NULL;
2385 reschedule_session_timeout (session);
2386 GNUNET_SERVER_receive_done (session->client,
2392 * Function that will be called whenever the transport service wants to
2393 * notify the plugin that the inbound quota changed and that the plugin
2394 * should update it's delay for the next receive value
2396 * @param cls closure
2397 * @param peer which peer was the session for
2398 * @param session which session is being updated
2399 * @param delay new delay to use for receiving
2402 tcp_plugin_update_inbound_delay (void *cls,
2403 const struct GNUNET_PeerIdentity *peer,
2404 struct GNUNET_ATS_Session *session,
2405 struct GNUNET_TIME_Relative delay)
2407 if (NULL == session->receive_delay_task)
2409 LOG (GNUNET_ERROR_TYPE_DEBUG,
2410 "New inbound delay %s\n",
2411 GNUNET_STRINGS_relative_time_to_string (delay,
2413 session->receive_delay = GNUNET_TIME_relative_to_absolute (delay);
2414 GNUNET_SCHEDULER_cancel (session->receive_delay_task);
2415 session->receive_delay_task = GNUNET_SCHEDULER_add_delayed (delay,
2422 * Create a new session to transmit data to the target
2423 * This session will used to send data to this peer and the plugin will
2424 * notify us by calling the env->session_end function
2426 * @param cls closure
2427 * @param address the address to use
2428 * @return the session if the address is valid, NULL otherwise
2430 static struct GNUNET_ATS_Session *
2431 tcp_plugin_get_session (void *cls,
2432 const struct GNUNET_HELLO_Address *address)
2434 struct Plugin *plugin = cls;
2435 struct GNUNET_ATS_Session *session = NULL;
2439 struct GNUNET_CONNECTION_Handle *sa;
2440 struct sockaddr_in a4;
2441 struct sockaddr_in6 a6;
2442 const struct IPv4TcpAddress *t4;
2443 const struct IPv6TcpAddress *t6;
2444 unsigned int options;
2445 enum GNUNET_ATS_Network_Type net_type;
2446 unsigned int is_natd = GNUNET_NO;
2449 struct GNUNET_NETWORK_Handle *s;
2452 addrlen = address->address_length;
2453 LOG (GNUNET_ERROR_TYPE_DEBUG,
2454 "Trying to get session for `%s' address of peer `%s'\n",
2455 tcp_plugin_address_to_string (plugin,
2457 address->address_length),
2458 GNUNET_i2s (&address->peer));
2460 if (GNUNET_HELLO_address_check_option (address,
2461 GNUNET_HELLO_ADDRESS_INFO_INBOUND))
2467 /* look for existing session */
2469 GNUNET_CONTAINER_multipeermap_contains (plugin->sessionmap,
2472 struct GNUNET_ATS_SessionItCtx si_ctx;
2474 si_ctx.address = address;
2475 si_ctx.result = NULL;
2476 GNUNET_CONTAINER_multipeermap_get_multiple (plugin->sessionmap,
2480 if (NULL != si_ctx.result)
2482 session = si_ctx.result;
2483 LOG (GNUNET_ERROR_TYPE_DEBUG,
2484 "Found existing session for `%s' address `%s'\n",
2485 GNUNET_i2s (&address->peer),
2486 tcp_plugin_address_to_string (plugin,
2488 address->address_length));
2491 /* This is a bit of a hack, limiting TCP to never allow more than
2492 one TCP connection to any given peer at the same time.
2493 Without this, peers sometimes disagree about which of the TCP
2494 connections they should use, causing one side to believe that
2495 they transmit successfully, while the other receives nothing. */
2496 return NULL; /* Refuse to have more than one TCP connection per
2497 peer pair at the same time. */
2500 if (addrlen == sizeof(struct IPv6TcpAddress))
2502 GNUNET_assert (NULL != address->address); /* make static analysis happy */
2503 t6 = address->address;
2504 options = t6->options;
2506 memset (&a6, 0, sizeof(a6));
2507 #if HAVE_SOCKADDR_IN_SIN_LEN
2508 a6.sin6_len = sizeof (a6);
2510 a6.sin6_family = AF_INET6;
2511 a6.sin6_port = t6->t6_port;
2512 if (t6->t6_port == 0)
2513 is_natd = GNUNET_YES;
2514 GNUNET_memcpy (&a6.sin6_addr, &t6->ipv6_addr, sizeof(struct in6_addr));
2518 else if (addrlen == sizeof(struct IPv4TcpAddress))
2520 GNUNET_assert(NULL != address->address); /* make static analysis happy */
2521 t4 = address->address;
2522 options = t4->options;
2524 memset (&a4, 0, sizeof(a4));
2525 #if HAVE_SOCKADDR_IN_SIN_LEN
2526 a4.sin_len = sizeof (a4);
2528 a4.sin_family = AF_INET;
2529 a4.sin_port = t4->t4_port;
2530 if (t4->t4_port == 0)
2531 is_natd = GNUNET_YES;
2532 a4.sin_addr.s_addr = t4->ipv4_addr;
2538 GNUNET_STATISTICS_update (plugin->env->stats,
2539 gettext_noop ("# requests to create session with invalid address"),
2545 net_type = plugin->env->get_address_type (plugin->env->cls,
2548 GNUNET_break (net_type != GNUNET_ATS_NET_UNSPECIFIED);
2550 if ( (is_natd == GNUNET_YES) &&
2551 (addrlen == sizeof(struct IPv6TcpAddress)) )
2553 /* NAT client only works with IPv4 addresses */
2557 if (plugin->cur_connections >= plugin->max_connections)
2563 if ( (is_natd == GNUNET_YES) &&
2565 GNUNET_CONTAINER_multipeermap_contains (plugin->nat_wait_conns,
2568 /* Only do one NAT punch attempt per peer identity */
2572 if ( (is_natd == GNUNET_YES) &&
2573 (NULL != plugin->nat) &&
2575 GNUNET_CONTAINER_multipeermap_contains (plugin->nat_wait_conns,
2578 struct sockaddr_in local_sa;
2580 LOG (GNUNET_ERROR_TYPE_DEBUG,
2581 "Found valid IPv4 NAT address (creating session)!\n");
2582 session = create_session (plugin,
2587 session->nat_connection_timeout = GNUNET_SCHEDULER_add_delayed (NAT_TIMEOUT,
2588 &nat_connect_timeout,
2590 GNUNET_assert (GNUNET_OK ==
2591 GNUNET_CONTAINER_multipeermap_put (plugin->nat_wait_conns,
2594 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
2596 LOG (GNUNET_ERROR_TYPE_DEBUG,
2597 "Created NAT WAIT connection to `%s' at `%s'\n",
2598 GNUNET_i2s (&session->target),
2599 GNUNET_a2s (sb, sbs));
2603 local_sa.sin_family = AF_INET;
2604 local_sa.sin_port = htons (plugin->open_port);
2605 /* We leave sin_address at 0, let the kernel figure it out,
2606 even if our bind() is more specific. (May want to reconsider
2609 GNUNET_NAT_request_reversal (plugin->nat,
2613 LOG (GNUNET_ERROR_TYPE_DEBUG,
2614 "Running NAT client for `%s' at `%s' failed\n",
2615 GNUNET_i2s (&session->target),
2616 GNUNET_a2s (sb, sbs));
2617 tcp_plugin_disconnect_session (plugin,
2622 /* create new outbound session */
2623 if (0 != (options & TCP_OPTIONS_TCP_STEALTH))
2626 s = GNUNET_NETWORK_socket_create (af, SOCK_STREAM, 0);
2629 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK,
2636 GNUNET_NETWORK_socket_setsockopt (s,
2640 sizeof (struct GNUNET_PeerIdentity))) ||
2642 GNUNET_NETWORK_socket_setsockopt (s,
2644 TCP_STEALTH_INTEGRITY,
2645 &plugin->my_welcome,
2646 sizeof (struct WelcomeMessage))) )
2648 /* TCP STEALTH not supported by kernel */
2649 GNUNET_break (GNUNET_OK ==
2650 GNUNET_NETWORK_socket_close (s));
2655 sa = GNUNET_CONNECTION_connect_socket (s, sb, sbs);
2664 sa = GNUNET_CONNECTION_create_from_sockaddr (af, sb, sbs);
2668 LOG (GNUNET_ERROR_TYPE_DEBUG,
2669 "Failed to create connection to `%s' at `%s'\n",
2670 GNUNET_i2s (&address->peer),
2671 GNUNET_a2s (sb, sbs));
2674 LOG (GNUNET_ERROR_TYPE_DEBUG,
2675 "Asked to transmit to `%s', creating fresh session using address `%s'.\n",
2676 GNUNET_i2s (&address->peer),
2677 GNUNET_a2s (sb, sbs));
2679 session = create_session (plugin,
2682 GNUNET_SERVER_connect_socket (plugin->server,
2685 (void) GNUNET_CONTAINER_multipeermap_put (plugin->sessionmap,
2688 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
2689 /* Send TCP Welcome */
2690 process_pending_messages (session);
2697 * We have been asked to destroy all connections to a particular peer.
2698 * This function is called on each applicable session and must tear it
2701 * @param cls the `struct Plugin *`
2702 * @param key the peer which the session belongs to (unused)
2703 * @param value the `struct GNUNET_ATS_Session`
2704 * @return #GNUNET_YES (continue to iterate)
2707 session_disconnect_it (void *cls,
2708 const struct GNUNET_PeerIdentity *key,
2711 struct Plugin *plugin = cls;
2712 struct GNUNET_ATS_Session *session = value;
2714 GNUNET_STATISTICS_update (session->plugin->env->stats,
2715 gettext_noop ("# transport-service disconnect requests for TCP"),
2718 tcp_plugin_disconnect_session (plugin,
2725 * Function that can be called to force a disconnect from the
2726 * specified neighbour. This should also cancel all previously
2727 * scheduled transmissions. Obviously the transmission may have been
2728 * partially completed already, which is OK. The plugin is supposed
2729 * to close the connection (if applicable) and no longer call the
2730 * transmit continuation(s).
2732 * Finally, plugin MUST NOT call the services's receive function to
2733 * notify the service that the connection to the specified target was
2734 * closed after a getting this call.
2736 * @param cls closure
2737 * @param target peer for which the last transmission is
2741 tcp_plugin_disconnect (void *cls,
2742 const struct GNUNET_PeerIdentity *target)
2744 struct Plugin *plugin = cls;
2746 LOG (GNUNET_ERROR_TYPE_DEBUG,
2747 "Disconnecting peer `%s'\n",
2748 GNUNET_i2s (target));
2749 GNUNET_CONTAINER_multipeermap_get_multiple (plugin->sessionmap,
2751 &session_disconnect_it,
2753 GNUNET_CONTAINER_multipeermap_get_multiple (plugin->nat_wait_conns,
2755 &session_disconnect_it,
2761 * We are processing an address pretty printing request and finished
2762 * the IP resolution (if applicable). Append our port and forward the
2763 * result. If called with @a hostname NULL, we are done and should
2764 * clean up the pretty printer (otherwise, there might be multiple
2765 * hostnames for the IP address and we might receive more).
2767 * @param cls the `struct PrettyPrinterContext *`
2768 * @param hostname hostname part of the address
2771 append_port (void *cls,
2772 const char *hostname)
2774 struct PrettyPrinterContext *ppc = cls;
2775 struct Plugin *plugin = ppc->plugin;
2778 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2779 "append_port called with hostname `%s'\n",
2781 if (NULL == hostname)
2783 /* Final call, done */
2784 ppc->resolver_handle = NULL;
2785 GNUNET_CONTAINER_DLL_remove (plugin->ppc_dll_head,
2786 plugin->ppc_dll_tail,
2788 ppc->asc (ppc->asc_cls,
2794 if (GNUNET_YES == ppc->ipv6)
2795 GNUNET_asprintf (&ret,
2802 GNUNET_asprintf (&ret,
2808 ppc->asc (ppc->asc_cls,
2816 * Convert the transports address to a nice, human-readable format.
2818 * @param cls closure with the `struct Plugin`
2819 * @param type name of the transport that generated the address
2820 * @param addr one of the addresses of the host, NULL for the last address
2821 * the specific address format depends on the transport
2822 * @param addrlen length of the @a addr
2823 * @param numeric should (IP) addresses be displayed in numeric form?
2824 * @param timeout after how long should we give up?
2825 * @param asc function to call on each string
2826 * @param asc_cls closure for @a asc
2829 tcp_plugin_address_pretty_printer (void *cls,
2834 struct GNUNET_TIME_Relative timeout,
2835 GNUNET_TRANSPORT_AddressStringCallback asc,
2838 struct Plugin *plugin = cls;
2839 struct PrettyPrinterContext *ppc;
2842 struct sockaddr_in a4;
2843 struct sockaddr_in6 a6;
2844 const struct IPv4TcpAddress *t4;
2845 const struct IPv6TcpAddress *t6;
2849 if (sizeof(struct IPv6TcpAddress) == addrlen)
2852 memset (&a6, 0, sizeof(a6));
2853 a6.sin6_family = AF_INET6;
2854 a6.sin6_port = t6->t6_port;
2855 GNUNET_memcpy (&a6.sin6_addr, &t6->ipv6_addr, sizeof(struct in6_addr));
2856 port = ntohs (t6->t6_port);
2857 options = ntohl (t6->options);
2861 else if (sizeof(struct IPv4TcpAddress) == addrlen)
2864 memset (&a4, 0, sizeof(a4));
2865 a4.sin_family = AF_INET;
2866 a4.sin_port = t4->t4_port;
2867 a4.sin_addr.s_addr = t4->ipv4_addr;
2868 port = ntohs (t4->t4_port);
2869 options = ntohl (t4->options);
2875 /* invalid address */
2876 LOG (GNUNET_ERROR_TYPE_WARNING,
2877 _("Unexpected address length: %u bytes\n"),
2878 (unsigned int) addrlen);
2879 asc (asc_cls, NULL, GNUNET_SYSERR);
2880 asc (asc_cls, NULL, GNUNET_OK);
2883 ppc = GNUNET_new (struct PrettyPrinterContext);
2884 ppc->plugin = plugin;
2885 if (addrlen == sizeof(struct IPv6TcpAddress))
2886 ppc->ipv6 = GNUNET_YES;
2888 ppc->ipv6 = GNUNET_NO;
2890 ppc->asc_cls = asc_cls;
2892 ppc->options = options;
2893 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2894 "Starting DNS reverse lookup\n");
2895 ppc->resolver_handle = GNUNET_RESOLVER_hostname_get (sb,
2901 if (NULL == ppc->resolver_handle)
2907 GNUNET_CONTAINER_DLL_insert (plugin->ppc_dll_head,
2908 plugin->ppc_dll_tail,
2914 * Function that will be called to check if a binary address for this
2915 * plugin is well-formed and corresponds to an address for THIS peer
2916 * (as per our configuration). Naturally, if absolutely necessary,
2917 * plugins can be a bit conservative in their answer, but in general
2918 * plugins should make sure that the address does not redirect
2919 * traffic to a 3rd party that might try to man-in-the-middle our
2922 * @param cls closure, our `struct Plugin *`
2923 * @param addr pointer to the address
2924 * @param addrlen length of @a addr
2925 * @return #GNUNET_OK if this is a plausible address for this peer
2926 * and transport, #GNUNET_SYSERR if not
2929 tcp_plugin_check_address (void *cls,
2933 struct Plugin *plugin = cls;
2934 const struct IPv4TcpAddress *v4;
2935 const struct IPv6TcpAddress *v6;
2937 if ( (addrlen != sizeof(struct IPv4TcpAddress)) &&
2938 (addrlen != sizeof(struct IPv6TcpAddress)) )
2940 GNUNET_break_op (0);
2941 return GNUNET_SYSERR;
2944 if (addrlen == sizeof(struct IPv4TcpAddress))
2946 struct sockaddr_in s4;
2948 v4 = (const struct IPv4TcpAddress *) addr;
2949 if (0 != memcmp (&v4->options,
2954 return GNUNET_SYSERR;
2956 memset (&s4, 0, sizeof (s4));
2957 s4.sin_family = AF_INET;
2958 #if HAVE_SOCKADDR_IN_SIN_LEN
2959 s4.sin_len = sizeof (s4);
2961 s4.sin_port = v4->t4_port;
2962 s4.sin_addr.s_addr = v4->ipv4_addr;
2965 GNUNET_NAT_test_address (plugin->nat,
2967 sizeof (struct sockaddr_in)))
2968 return GNUNET_SYSERR;
2972 struct sockaddr_in6 s6;
2974 v6 = (const struct IPv6TcpAddress *) addr;
2975 if (IN6_IS_ADDR_LINKLOCAL (&v6->ipv6_addr))
2977 GNUNET_break_op (0);
2978 return GNUNET_SYSERR;
2980 if (0 != memcmp (&v6->options,
2985 return GNUNET_SYSERR;
2987 memset (&s6, 0, sizeof (s6));
2988 s6.sin6_family = AF_INET6;
2989 #if HAVE_SOCKADDR_IN_SIN_LEN
2990 s6.sin6_len = sizeof (s6);
2992 s6.sin6_port = v6->t6_port;
2993 s6.sin6_addr = v6->ipv6_addr;
2996 GNUNET_NAT_test_address (plugin->nat,
2998 sizeof(struct sockaddr_in6)))
2999 return GNUNET_SYSERR;
3006 * We've received a nat probe from this peer via TCP. Finish
3007 * creating the client session and resume sending of queued
3010 * @param cls closure
3011 * @param client identification of the client
3012 * @param message the actual message
3015 handle_tcp_nat_probe (void *cls,
3016 struct GNUNET_SERVER_Client *client,
3017 const struct GNUNET_MessageHeader *message)
3019 struct Plugin *plugin = cls;
3020 struct GNUNET_ATS_Session *session;
3021 const struct TCP_NAT_ProbeMessage *tcp_nat_probe;
3024 struct IPv4TcpAddress *t4;
3025 struct IPv6TcpAddress *t6;
3026 const struct sockaddr_in *s4;
3027 const struct sockaddr_in6 *s6;
3029 LOG (GNUNET_ERROR_TYPE_DEBUG,
3030 "Received NAT probe\n");
3031 /* We have received a TCP NAT probe, meaning we (hopefully) initiated
3032 * a connection to this peer by running gnunet-nat-client. This peer
3033 * received the punch message and now wants us to use the new connection
3034 * as the default for that peer. Do so and then send a WELCOME message
3035 * so we can really be connected!
3037 if (ntohs (message->size) != sizeof(struct TCP_NAT_ProbeMessage))
3040 GNUNET_SERVER_receive_done (client,
3045 tcp_nat_probe = (const struct TCP_NAT_ProbeMessage *) message;
3046 if (0 == memcmp (&tcp_nat_probe->clientIdentity, plugin->env->my_identity,
3047 sizeof(struct GNUNET_PeerIdentity)))
3049 /* refuse connections from ourselves */
3050 GNUNET_SERVER_receive_done (client,
3055 session = GNUNET_CONTAINER_multipeermap_get (plugin->nat_wait_conns,
3056 &tcp_nat_probe->clientIdentity);
3057 if (NULL == session)
3059 LOG (GNUNET_ERROR_TYPE_DEBUG,
3060 "Did NOT find session for NAT probe!\n");
3061 GNUNET_SERVER_receive_done (client,
3065 LOG (GNUNET_ERROR_TYPE_DEBUG,
3066 "Found session for NAT probe!\n");
3068 if (NULL != session->nat_connection_timeout)
3070 GNUNET_SCHEDULER_cancel (session->nat_connection_timeout);
3071 session->nat_connection_timeout = NULL;
3075 GNUNET_SERVER_client_get_address (client,
3080 GNUNET_SERVER_receive_done (client,
3082 tcp_plugin_disconnect_session (plugin,
3086 GNUNET_assert (GNUNET_YES ==
3087 GNUNET_CONTAINER_multipeermap_remove (plugin->nat_wait_conns,
3088 &tcp_nat_probe->clientIdentity,
3090 GNUNET_SERVER_client_set_user_context (client,
3092 (void) GNUNET_CONTAINER_multipeermap_put (plugin->sessionmap,
3095 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
3096 session->last_activity = GNUNET_TIME_absolute_get ();
3097 LOG (GNUNET_ERROR_TYPE_DEBUG,
3098 "Found address `%s' for incoming connection\n",
3099 GNUNET_a2s (vaddr, alen));
3100 switch (((const struct sockaddr *) vaddr)->sa_family)
3104 t4 = GNUNET_new (struct IPv4TcpAddress);
3105 t4->options = htonl (TCP_OPTIONS_NONE);
3106 t4->t4_port = s4->sin_port;
3107 t4->ipv4_addr = s4->sin_addr.s_addr;
3108 session->address = GNUNET_HELLO_address_allocate (&tcp_nat_probe->clientIdentity,
3111 sizeof(struct IPv4TcpAddress),
3112 GNUNET_HELLO_ADDRESS_INFO_NONE);
3116 t6 = GNUNET_new (struct IPv6TcpAddress);
3117 t6->options = htonl (TCP_OPTIONS_NONE);
3118 t6->t6_port = s6->sin6_port;
3119 GNUNET_memcpy (&t6->ipv6_addr, &s6->sin6_addr, sizeof(struct in6_addr));
3120 session->address = GNUNET_HELLO_address_allocate (&tcp_nat_probe->clientIdentity,
3123 sizeof(struct IPv6TcpAddress),
3124 GNUNET_HELLO_ADDRESS_INFO_NONE);
3128 LOG(GNUNET_ERROR_TYPE_DEBUG,
3129 "Bad address for incoming connection!\n");
3131 GNUNET_SERVER_receive_done (client,
3133 tcp_plugin_disconnect_session (plugin,
3137 GNUNET_free (vaddr);
3138 GNUNET_break (NULL == session->client);
3139 session->client = client;
3140 GNUNET_STATISTICS_update (plugin->env->stats,
3141 gettext_noop ("# TCP sessions active"),
3144 process_pending_messages (session);
3145 GNUNET_SERVER_receive_done (client,
3151 * We've received a welcome from this peer via TCP. Possibly create a
3152 * fresh client record and send back our welcome.
3154 * @param cls closure
3155 * @param client identification of the client
3156 * @param message the actual message
3159 handle_tcp_welcome (void *cls,
3160 struct GNUNET_SERVER_Client *client,
3161 const struct GNUNET_MessageHeader *message)
3163 struct Plugin *plugin = cls;
3164 const struct WelcomeMessage *wm = (const struct WelcomeMessage *) message;
3165 struct GNUNET_HELLO_Address *address;
3166 struct GNUNET_ATS_Session *session;
3169 struct IPv4TcpAddress t4;
3170 struct IPv6TcpAddress t6;
3171 const struct sockaddr_in *s4;
3172 const struct sockaddr_in6 *s6;
3174 if (0 == memcmp (&wm->clientIdentity,
3175 plugin->env->my_identity,
3176 sizeof(struct GNUNET_PeerIdentity)))
3178 /* refuse connections from ourselves */
3180 GNUNET_SERVER_client_get_address (client,
3184 LOG (GNUNET_ERROR_TYPE_INFO,
3185 "Received WELCOME message from my own identity `%s' on address `%s'\n",
3186 GNUNET_i2s (&wm->clientIdentity),
3187 GNUNET_a2s (vaddr, alen));
3188 GNUNET_free (vaddr);
3190 GNUNET_SERVER_receive_done (client,
3196 GNUNET_SERVER_client_get_address (client,
3200 LOG(GNUNET_ERROR_TYPE_DEBUG,
3201 "Received WELCOME message from `%s' on address `%s'\n",
3202 GNUNET_i2s (&wm->clientIdentity),
3203 GNUNET_a2s (vaddr, alen));
3204 GNUNET_free (vaddr);
3206 GNUNET_STATISTICS_update (plugin->env->stats,
3207 gettext_noop ("# TCP WELCOME messages received"),
3210 session = lookup_session_by_client (plugin,
3212 if (NULL != session)
3215 GNUNET_SERVER_client_get_address (client,
3219 LOG (GNUNET_ERROR_TYPE_DEBUG,
3220 "Found existing session %p for peer `%s'\n",
3222 GNUNET_a2s (vaddr, alen));
3223 GNUNET_free (vaddr);
3229 GNUNET_SERVER_client_get_address (client, &vaddr, &alen))
3231 if (alen == sizeof(struct sockaddr_in))
3234 memset (&t4, '\0', sizeof (t4));
3235 t4.options = htonl (TCP_OPTIONS_NONE);
3236 t4.t4_port = s4->sin_port;
3237 t4.ipv4_addr = s4->sin_addr.s_addr;
3238 address = GNUNET_HELLO_address_allocate (&wm->clientIdentity,
3242 GNUNET_HELLO_ADDRESS_INFO_INBOUND);
3244 else if (alen == sizeof(struct sockaddr_in6))
3247 memset (&t6, '\0', sizeof (t6));
3248 t6.options = htonl (TCP_OPTIONS_NONE);
3249 t6.t6_port = s6->sin6_port;
3250 GNUNET_memcpy (&t6.ipv6_addr, &s6->sin6_addr, sizeof(struct in6_addr));
3251 address = GNUNET_HELLO_address_allocate (&wm->clientIdentity,
3255 GNUNET_HELLO_ADDRESS_INFO_INBOUND);
3260 GNUNET_free_non_null (vaddr);
3261 GNUNET_SERVER_receive_done (client,
3265 session = create_session (plugin,
3267 plugin->env->get_address_type (plugin->env->cls,
3272 GNUNET_break (GNUNET_ATS_NET_UNSPECIFIED != session->scope);
3273 GNUNET_HELLO_address_free (address);
3274 LOG (GNUNET_ERROR_TYPE_DEBUG,
3275 "Creating new%s session %p for peer `%s' client %p\n",
3276 GNUNET_HELLO_address_check_option (session->address,
3277 GNUNET_HELLO_ADDRESS_INFO_INBOUND)
3280 tcp_plugin_address_to_string (plugin,
3281 session->address->address,
3282 session->address->address_length),
3284 GNUNET_free (vaddr);
3285 (void) GNUNET_CONTAINER_multipeermap_put (plugin->sessionmap,
3288 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
3289 /* Notify transport and ATS about new session */
3290 plugin->env->session_start (plugin->env->cls,
3297 LOG(GNUNET_ERROR_TYPE_DEBUG,
3298 "Did not obtain TCP socket address for incoming connection\n");
3300 GNUNET_SERVER_receive_done (client,
3306 if (GNUNET_YES != session->expecting_welcome)
3308 GNUNET_break_op (0);
3309 GNUNET_SERVER_receive_done (client,
3313 session->last_activity = GNUNET_TIME_absolute_get ();
3314 session->expecting_welcome = GNUNET_NO;
3316 process_pending_messages (session);
3317 GNUNET_SERVER_client_set_timeout (client,
3318 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
3319 GNUNET_SERVER_receive_done (client,
3325 * We've received data for this peer via TCP. Unbox,
3326 * compute latency and forward.
3328 * @param cls closure
3329 * @param client identification of the client
3330 * @param message the actual message
3333 handle_tcp_data (void *cls,
3334 struct GNUNET_SERVER_Client *client,
3335 const struct GNUNET_MessageHeader *message)
3337 struct Plugin *plugin = cls;
3338 struct GNUNET_ATS_Session *session;
3339 struct GNUNET_TIME_Relative delay;
3342 type = ntohs (message->type);
3343 if ( (GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_WELCOME == type) ||
3344 (GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_NAT_PROBE == type) )
3346 /* We don't want to propagate WELCOME and NAT Probe messages up! */
3347 GNUNET_SERVER_receive_done (client,
3351 session = lookup_session_by_client (plugin, client);
3352 if (NULL == session)
3354 /* No inbound session found */
3358 GNUNET_assert (GNUNET_OK ==
3359 GNUNET_SERVER_client_get_address (client,
3362 LOG (GNUNET_ERROR_TYPE_ERROR,
3363 "Received unexpected %u bytes of type %u from `%s'\n",
3364 (unsigned int) ntohs (message->size),
3365 (unsigned int) ntohs (message->type),
3369 GNUNET_SERVER_receive_done (client,
3371 GNUNET_free_non_null (vaddr);
3374 if (GNUNET_YES == session->expecting_welcome)
3376 /* Session is expecting WELCOME message */
3380 GNUNET_SERVER_client_get_address (client,
3383 LOG (GNUNET_ERROR_TYPE_ERROR,
3384 "Received unexpected %u bytes of type %u from `%s'\n",
3385 (unsigned int) ntohs (message->size),
3386 (unsigned int) ntohs (message->type),
3387 GNUNET_a2s (vaddr, alen));
3389 GNUNET_SERVER_receive_done (client,
3391 GNUNET_free_non_null (vaddr);
3395 session->last_activity = GNUNET_TIME_absolute_get ();
3400 GNUNET_SERVER_client_get_address (client,
3403 LOG (GNUNET_ERROR_TYPE_DEBUG,
3404 "Passing %u bytes of type %u from `%s' at %s to transport service.\n",
3405 (unsigned int) ntohs (message->size),
3406 (unsigned int) ntohs (message->type),
3407 GNUNET_i2s (&session->target),
3408 GNUNET_a2s (vaddr, alen));
3409 GNUNET_free_non_null (vaddr);
3412 GNUNET_STATISTICS_update (plugin->env->stats,
3413 gettext_noop ("# bytes received via TCP"),
3414 ntohs (message->size),
3417 GNUNET_assert (GNUNET_CONTAINER_multipeermap_contains_value (plugin->sessionmap,
3420 delay = plugin->env->receive (plugin->env->cls,
3424 reschedule_session_timeout (session);
3425 if (0 == delay.rel_value_us)
3427 GNUNET_SERVER_receive_done (client,
3432 LOG (GNUNET_ERROR_TYPE_DEBUG,
3433 "Throttling receiving from `%s' for %s\n",
3434 GNUNET_i2s (&session->target),
3435 GNUNET_STRINGS_relative_time_to_string (delay,
3437 GNUNET_SERVER_disable_receive_done_warning (client);
3438 GNUNET_assert (NULL == session->receive_delay_task);
3439 session->receive_delay_task = GNUNET_SCHEDULER_add_delayed (delay,
3447 * Function called whenever a peer is connected on the "SERVER" level.
3448 * Increments number of active connections and suspends server if we
3449 * have reached the limit.
3451 * @param cls closure
3452 * @param client identification of the client
3455 connect_notify (void *cls,
3456 struct GNUNET_SERVER_Client *client)
3458 struct Plugin *plugin = cls;
3462 plugin->cur_connections++;
3463 GNUNET_STATISTICS_set (plugin->env->stats,
3464 gettext_noop ("# TCP server connections active"),
3465 plugin->cur_connections,
3467 GNUNET_STATISTICS_update (plugin->env->stats,
3468 gettext_noop ("# TCP server connect events"),
3471 if (plugin->cur_connections != plugin->max_connections)
3473 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3474 _("TCP connection limit reached, suspending server\n"));
3475 GNUNET_STATISTICS_update (plugin->env->stats,
3476 gettext_noop ("# TCP service suspended"),
3479 GNUNET_SERVER_suspend (plugin->server); /* Maximum number of connections rechead */
3484 * Function called whenever a peer is disconnected on the "SERVER"
3485 * level. Cleans up the connection, decrements number of active
3486 * connections and if applicable resumes listening.
3488 * @param cls closure
3489 * @param client identification of the client
3492 disconnect_notify (void *cls,
3493 struct GNUNET_SERVER_Client *client)
3495 struct Plugin *plugin = cls;
3496 struct GNUNET_ATS_Session *session;
3500 GNUNET_assert (plugin->cur_connections >= 1);
3501 plugin->cur_connections--;
3502 session = lookup_session_by_client (plugin,
3504 if (NULL == session)
3505 return; /* unknown, nothing to do */
3506 LOG (GNUNET_ERROR_TYPE_DEBUG,
3507 "Destroying session of `%s' with %s due to network-level disconnect.\n",
3508 GNUNET_i2s (&session->target),
3509 tcp_plugin_address_to_string (session->plugin,
3510 session->address->address,
3511 session->address->address_length));
3513 if (plugin->cur_connections == plugin->max_connections)
3515 GNUNET_STATISTICS_update (session->plugin->env->stats,
3516 gettext_noop ("# TCP service resumed"),
3519 GNUNET_SERVER_resume (plugin->server); /* Resume server */
3521 GNUNET_STATISTICS_set (plugin->env->stats,
3522 gettext_noop ("# TCP server connections active"),
3523 plugin->cur_connections,
3525 GNUNET_STATISTICS_update (session->plugin->env->stats,
3526 gettext_noop ("# network-level TCP disconnect events"),
3529 tcp_plugin_disconnect_session (plugin,
3535 * We can now send a probe message, copy into buffer to really send.
3537 * @param cls closure, a `struct TCPProbeContext`
3538 * @param size max size to copy
3539 * @param buf buffer to copy message to
3540 * @return number of bytes copied into @a buf
3543 notify_send_probe (void *cls,
3547 struct TCPProbeContext *tcp_probe_ctx = cls;
3548 struct Plugin *plugin = tcp_probe_ctx->plugin;
3551 tcp_probe_ctx->transmit_handle = NULL;
3552 GNUNET_CONTAINER_DLL_remove (plugin->probe_head,
3557 GNUNET_CONNECTION_destroy (tcp_probe_ctx->sock);
3558 GNUNET_free(tcp_probe_ctx);
3561 GNUNET_assert(size >= sizeof(tcp_probe_ctx->message));
3563 &tcp_probe_ctx->message,
3564 sizeof(tcp_probe_ctx->message));
3565 GNUNET_SERVER_connect_socket (tcp_probe_ctx->plugin->server,
3566 tcp_probe_ctx->sock);
3567 ret = sizeof(tcp_probe_ctx->message);
3568 GNUNET_free (tcp_probe_ctx);
3574 * Function called by the NAT subsystem suggesting another peer wants
3575 * to connect to us via connection reversal. Try to connect back to the
3578 * @param cls closure
3579 * @param addr address to try
3580 * @param addrlen number of bytes in @a addr
3583 try_connection_reversal (void *cls,
3584 const struct sockaddr *addr,
3587 struct Plugin *plugin = cls;
3588 struct GNUNET_CONNECTION_Handle *sock;
3589 struct TCPProbeContext *tcp_probe_ctx;
3592 * We have received an ICMP response, ostensibly from a peer
3593 * that wants to connect to us! Send a message to establish a connection.
3595 sock = GNUNET_CONNECTION_create_from_sockaddr (AF_INET,
3600 /* failed for some odd reason (out of sockets?); ignore attempt */
3604 tcp_probe_ctx = GNUNET_new (struct TCPProbeContext);
3605 tcp_probe_ctx->message.header.size
3606 = htons (sizeof (struct TCP_NAT_ProbeMessage));
3607 tcp_probe_ctx->message.header.type
3608 = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_NAT_PROBE);
3609 tcp_probe_ctx->message.clientIdentity
3610 = *plugin->env->my_identity;
3611 tcp_probe_ctx->plugin = plugin;
3612 tcp_probe_ctx->sock = sock;
3613 GNUNET_CONTAINER_DLL_insert (plugin->probe_head,
3616 tcp_probe_ctx->transmit_handle
3617 = GNUNET_CONNECTION_notify_transmit_ready (sock,
3618 ntohs (tcp_probe_ctx->message.header.size),
3619 GNUNET_TIME_UNIT_FOREVER_REL,
3626 * Function obtain the network type for a session
3628 * @param cls closure (`struct Plugin *`)
3629 * @param session the session
3630 * @return the network type in HBO or #GNUNET_SYSERR
3632 static enum GNUNET_ATS_Network_Type
3633 tcp_plugin_get_network (void *cls,
3634 struct GNUNET_ATS_Session *session)
3636 return session->scope;
3641 * Function obtain the network type for an address.
3643 * @param cls closure (`struct Plugin *`)
3644 * @param address the address
3645 * @return the network type
3647 static enum GNUNET_ATS_Network_Type
3648 tcp_plugin_get_network_for_address (void *cls,
3649 const struct GNUNET_HELLO_Address *address)
3651 struct Plugin *plugin = cls;
3653 struct sockaddr_in a4;
3654 struct sockaddr_in6 a6;
3655 const struct IPv4TcpAddress *t4;
3656 const struct IPv6TcpAddress *t6;
3660 addrlen = address->address_length;
3661 if (addrlen == sizeof(struct IPv6TcpAddress))
3663 GNUNET_assert (NULL != address->address); /* make static analysis happy */
3664 t6 = address->address;
3665 memset (&a6, 0, sizeof(a6));
3666 #if HAVE_SOCKADDR_IN_SIN_LEN
3667 a6.sin6_len = sizeof (a6);
3669 a6.sin6_family = AF_INET6;
3670 a6.sin6_port = t6->t6_port;
3671 GNUNET_memcpy (&a6.sin6_addr, &t6->ipv6_addr, sizeof(struct in6_addr));
3675 else if (addrlen == sizeof(struct IPv4TcpAddress))
3677 GNUNET_assert (NULL != address->address); /* make static analysis happy */
3678 t4 = address->address;
3679 memset (&a4, 0, sizeof(a4));
3680 #if HAVE_SOCKADDR_IN_SIN_LEN
3681 a4.sin_len = sizeof (a4);
3683 a4.sin_family = AF_INET;
3684 a4.sin_port = t4->t4_port;
3685 a4.sin_addr.s_addr = t4->ipv4_addr;
3692 return GNUNET_ATS_NET_UNSPECIFIED;
3694 return plugin->env->get_address_type (plugin->env->cls,
3701 * Return information about the given session to the
3704 * @param cls the `struct Plugin` with the monitor callback (`sic`)
3705 * @param peer peer we send information about
3706 * @param value our `struct GNUNET_ATS_Session` to send information about
3707 * @return #GNUNET_OK (continue to iterate)
3710 send_session_info_iter (void *cls,
3711 const struct GNUNET_PeerIdentity *peer,
3714 struct Plugin *plugin = cls;
3715 struct GNUNET_ATS_Session *session = value;
3717 notify_session_monitor (plugin,
3719 GNUNET_TRANSPORT_SS_INIT);
3720 /* FIXME: cannot tell if this is up or not from current
3722 notify_session_monitor (plugin,
3724 GNUNET_TRANSPORT_SS_UP);
3730 * Begin monitoring sessions of a plugin. There can only
3731 * be one active monitor per plugin (i.e. if there are
3732 * multiple monitors, the transport service needs to
3733 * multiplex the generated events over all of them).
3735 * @param cls closure of the plugin
3736 * @param sic callback to invoke, NULL to disable monitor;
3737 * plugin will being by iterating over all active
3738 * sessions immediately and then enter monitor mode
3739 * @param sic_cls closure for @a sic
3742 tcp_plugin_setup_monitor (void *cls,
3743 GNUNET_TRANSPORT_SessionInfoCallback sic,
3746 struct Plugin *plugin = cls;
3749 plugin->sic_cls = sic_cls;
3752 GNUNET_CONTAINER_multipeermap_iterate (plugin->sessionmap,
3753 &send_session_info_iter,
3755 /* signal end of first iteration */
3756 sic (sic_cls, NULL, NULL);
3762 * Entry point for the plugin.
3764 * @param cls closure, the `struct GNUNET_TRANSPORT_PluginEnvironment *`
3765 * @return the `struct GNUNET_TRANSPORT_PluginFunctions *` or NULL on error
3768 libgnunet_plugin_transport_xt_init (void *cls)
3770 static const struct GNUNET_SERVER_MessageHandler my_handlers[] = {
3771 { &handle_tcp_welcome, NULL,
3772 GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_WELCOME,
3773 sizeof(struct WelcomeMessage) },
3774 { &handle_tcp_nat_probe, NULL,
3775 GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_NAT_PROBE,
3776 sizeof(struct TCP_NAT_ProbeMessage) },
3777 { &handle_tcp_data, NULL,
3778 GNUNET_MESSAGE_TYPE_ALL, 0 },
3779 { NULL, NULL, 0, 0 }
3781 struct GNUNET_TRANSPORT_PluginEnvironment *env = cls;
3782 struct GNUNET_TRANSPORT_PluginFunctions *api;
3783 struct Plugin *plugin;
3784 struct LEGACY_SERVICE_Context *service;
3785 unsigned long long aport;
3786 unsigned long long bport;
3787 unsigned long long max_connections;
3789 struct GNUNET_TIME_Relative idle_timeout;
3791 struct GNUNET_NETWORK_Handle *const*lsocks;
3795 struct sockaddr **addrs;
3796 socklen_t *addrlens;
3798 if (NULL == env->receive)
3800 /* run in 'stub' mode (i.e. as part of gnunet-peerinfo), don't fully
3801 initialze the plugin or the API */
3802 api = GNUNET_new (struct GNUNET_TRANSPORT_PluginFunctions);
3804 api->address_pretty_printer = &tcp_plugin_address_pretty_printer;
3805 api->address_to_string = &tcp_plugin_address_to_string;
3806 api->string_to_address = &tcp_plugin_string_to_address;
3810 GNUNET_assert (NULL != env->cfg);
3812 GNUNET_CONFIGURATION_get_value_number (env->cfg,
3816 max_connections = 128;
3820 GNUNET_CONFIGURATION_get_value_number (env->cfg,
3825 GNUNET_CONFIGURATION_get_value_number (env->cfg,
3827 "ADVERTISED-PORT", &aport)) &&
3830 LOG(GNUNET_ERROR_TYPE_ERROR,
3831 _("Require valid port number for service `%s' in configuration!\n"),
3841 service = LEGACY_SERVICE_start ("transport-xt",
3843 LEGACY_SERVICE_OPTION_NONE);
3844 if (NULL == service)
3846 LOG (GNUNET_ERROR_TYPE_WARNING,
3847 _("Failed to start service.\n"));
3855 plugin = GNUNET_new (struct Plugin);
3856 plugin->sessionmap = GNUNET_CONTAINER_multipeermap_create (max_connections,
3858 plugin->max_connections = max_connections;
3859 plugin->open_port = bport;
3860 plugin->adv_port = aport;
3862 plugin->my_welcome.header.size = htons (sizeof(struct WelcomeMessage));
3863 plugin->my_welcome.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_WELCOME);
3864 plugin->my_welcome.clientIdentity = *plugin->env->my_identity;
3866 if ( (NULL != service) &&
3868 GNUNET_CONFIGURATION_get_value_yesno (env->cfg,
3873 plugin->myoptions |= TCP_OPTIONS_TCP_STEALTH;
3874 lsocks = LEGACY_SERVICE_get_listen_sockets (service);
3877 uint32_t len = sizeof (struct WelcomeMessage);
3879 for (i=0;NULL!=lsocks[i];i++)
3882 GNUNET_NETWORK_socket_setsockopt (lsocks[i],
3886 sizeof (struct GNUNET_PeerIdentity))) ||
3888 GNUNET_NETWORK_socket_setsockopt (lsocks[i],
3890 TCP_STEALTH_INTEGRITY_LEN,
3894 /* TCP STEALTH not supported by kernel */
3895 GNUNET_assert (0 == i);
3896 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3897 _("TCP_STEALTH not supported on this platform.\n"));
3903 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3904 _("TCP_STEALTH not supported on this platform.\n"));
3909 if ( (NULL != service) &&
3912 get_server_addresses ("transport-xt",
3917 for (ret = ret_s-1; ret >= 0; ret--)
3918 LOG (GNUNET_ERROR_TYPE_INFO,
3919 "Binding to address `%s'\n",
3920 GNUNET_a2s (addrs[ret], addrlens[ret]));
3922 = GNUNET_NAT_register (env->cfg,
3925 (unsigned int) ret_s,
3926 (const struct sockaddr **) addrs,
3928 &tcp_nat_port_map_callback,
3929 &try_connection_reversal,
3931 for (ret = ret_s -1; ret >= 0; ret--)
3932 GNUNET_free (addrs[ret]);
3933 GNUNET_free_non_null (addrs);
3934 GNUNET_free_non_null (addrlens);
3938 plugin->nat = GNUNET_NAT_register (plugin->env->cfg,
3945 &try_connection_reversal,
3948 api = GNUNET_new (struct GNUNET_TRANSPORT_PluginFunctions);
3950 api->send = &tcp_plugin_send;
3951 api->get_session = &tcp_plugin_get_session;
3952 api->disconnect_session = &tcp_plugin_disconnect_session;
3953 api->query_keepalive_factor = &tcp_plugin_query_keepalive_factor;
3954 api->disconnect_peer = &tcp_plugin_disconnect;
3955 api->address_pretty_printer = &tcp_plugin_address_pretty_printer;
3956 api->check_address = &tcp_plugin_check_address;
3957 api->address_to_string = &tcp_plugin_address_to_string;
3958 api->string_to_address = &tcp_plugin_string_to_address;
3959 api->get_network = &tcp_plugin_get_network;
3960 api->get_network_for_address = &tcp_plugin_get_network_for_address;
3961 api->update_session_timeout = &tcp_plugin_update_session_timeout;
3962 api->update_inbound_delay = &tcp_plugin_update_inbound_delay;
3963 api->setup_monitor = &tcp_plugin_setup_monitor;
3964 plugin->service = service;
3965 if (NULL != service)
3967 plugin->server = LEGACY_SERVICE_get_server (service);
3972 GNUNET_CONFIGURATION_get_value_time (env->cfg,
3977 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
3983 = GNUNET_SERVER_create_with_sockets (NULL,
3989 plugin->handlers = GNUNET_malloc (sizeof (my_handlers));
3990 GNUNET_memcpy (plugin->handlers,
3992 sizeof(my_handlers));
3993 for (i = 0;i < sizeof(my_handlers) / sizeof(struct GNUNET_SERVER_MessageHandler);i++)
3994 plugin->handlers[i].callback_cls = plugin;
3996 GNUNET_SERVER_add_handlers (plugin->server,
3998 GNUNET_SERVER_connect_notify (plugin->server,
4001 GNUNET_SERVER_disconnect_notify (plugin->server,
4004 plugin->nat_wait_conns = GNUNET_CONTAINER_multipeermap_create (16,
4007 LOG (GNUNET_ERROR_TYPE_INFO,
4008 _("XT transport listening on port %llu\n"),
4011 LOG (GNUNET_ERROR_TYPE_INFO,
4012 _("XT transport not listening on any port (client only)\n"));
4013 if ( (aport != bport) &&
4015 LOG (GNUNET_ERROR_TYPE_INFO,
4016 _("XT transport advertises itself as being on port %llu\n"),
4018 /* Initially set connections to 0 */
4019 GNUNET_STATISTICS_set (plugin->env->stats,
4020 gettext_noop ("# XT sessions active"),
4026 if (NULL != plugin->nat)
4027 GNUNET_NAT_unregister (plugin->nat);
4028 GNUNET_CONTAINER_multipeermap_destroy (plugin->sessionmap);
4029 if (NULL != service)
4030 LEGACY_SERVICE_stop (service);
4031 GNUNET_free (plugin);
4032 GNUNET_free_non_null (api);
4038 * Exit point from the plugin.
4040 * @param cls the `struct GNUNET_TRANSPORT_PluginFunctions`
4044 libgnunet_plugin_transport_xt_done (void *cls)
4046 struct GNUNET_TRANSPORT_PluginFunctions *api = cls;
4047 struct Plugin *plugin = api->cls;
4048 struct TCPProbeContext *tcp_probe;
4049 struct PrettyPrinterContext *cur;
4050 struct PrettyPrinterContext *next;
4057 LOG (GNUNET_ERROR_TYPE_DEBUG,
4058 "Shutting down XT plugin\n");
4060 /* Removing leftover sessions */
4061 GNUNET_CONTAINER_multipeermap_iterate (plugin->sessionmap,
4062 &session_disconnect_it,
4064 /* Removing leftover NAT sessions */
4065 GNUNET_CONTAINER_multipeermap_iterate (plugin->nat_wait_conns,
4066 &session_disconnect_it,
4069 for (cur = plugin->ppc_dll_head; NULL != cur; cur = next)
4072 GNUNET_CONTAINER_DLL_remove (plugin->ppc_dll_head,
4073 plugin->ppc_dll_tail,
4075 GNUNET_RESOLVER_request_cancel (cur->resolver_handle);
4076 cur->asc (cur->asc_cls,
4082 if (NULL != plugin->service)
4083 LEGACY_SERVICE_stop (plugin->service);
4085 GNUNET_SERVER_destroy (plugin->server);
4086 GNUNET_free (plugin->handlers);
4087 if (NULL != plugin->nat)
4088 GNUNET_NAT_unregister (plugin->nat);
4089 while (NULL != (tcp_probe = plugin->probe_head))
4091 GNUNET_CONTAINER_DLL_remove (plugin->probe_head,
4094 GNUNET_CONNECTION_destroy (tcp_probe->sock);
4095 GNUNET_free (tcp_probe);
4097 GNUNET_CONTAINER_multipeermap_destroy (plugin->nat_wait_conns);
4098 GNUNET_CONTAINER_multipeermap_destroy (plugin->sessionmap);
4099 GNUNET_break (0 == plugin->cur_connections);
4100 GNUNET_free (plugin);
4105 /* end of plugin_transport_xt.c */