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/>.
18 SPDX-License-Identifier: AGPL3.0-or-later
21 * @file transport/plugin_transport_tcp.c
22 * @brief Implementation of the TCP transport service
23 * @author Christian Grothoff
26 #include "gnunet_hello_lib.h"
27 #include "gnunet_constants.h"
28 #include "gnunet_util_lib.h"
29 #include "gnunet_nat_service.h"
30 #include "gnunet_protocols.h"
31 #include "gnunet_resolver_service.h"
32 #include "gnunet_signatures.h"
33 #include "gnunet_statistics_service.h"
34 #include "gnunet_transport_service.h"
35 #include "gnunet_transport_plugin.h"
36 #include "transport.h"
38 #define LOG(kind, ...) GNUNET_log_from (kind, "transport-tcp", __VA_ARGS__)
40 #define PLUGIN_NAME "tcp"
43 * How long until we give up on establishing an NAT connection?
46 #define NAT_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10)
49 * Opaque handle that can be used to cancel
50 * a transmit-ready notification.
52 struct GNUNET_CONNECTION_TransmitHandle;
55 * @brief handle for a server
57 struct GNUNET_SERVER_Handle;
60 * @brief opaque handle for a client of the server
62 struct GNUNET_SERVER_Client;
65 * @brief opaque handle server returns for aborting transmission to a client.
67 struct GNUNET_SERVER_TransmitHandle;
70 * @brief handle for a network connection
72 struct GNUNET_CONNECTION_Handle;
75 * @brief handle for a network service
77 struct LEGACY_SERVICE_Context;
81 * Stops a service that was started with #GNUNET_SERVICE_start().
83 * @param srv service to stop
86 LEGACY_SERVICE_stop (struct LEGACY_SERVICE_Context *srv);
90 * Function called to notify a client about the connection begin ready
91 * to queue more data. @a buf will be NULL and @a size zero if the
92 * connection was closed for writing in the meantime.
95 * @param size number of bytes available in @a buf
96 * @param buf where the callee should write the message
97 * @return number of bytes written to @a buf
99 typedef size_t (*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
128 typedef void (*GNUNET_SERVER_DisconnectCallback) (
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
140 typedef void (*GNUNET_SERVER_ConnectCallback) (
142 struct GNUNET_SERVER_Client *client);
146 * Function to call for access control checks.
149 * @param ucred credentials, if available, otherwise NULL
150 * @param addr address
151 * @param addrlen length of address
152 * @return GNUNET_YES to allow, GNUNET_NO to deny, GNUNET_SYSERR
153 * for unknown address family (will be denied).
155 typedef int (*GNUNET_CONNECTION_AccessCheck) (
157 const struct GNUNET_CONNECTION_Credentials *ucred,
158 const struct sockaddr *addr,
162 * Callback function for data received from the network. Note that
163 * both "available" and "err" would be 0 if the read simply timed out.
166 * @param buf pointer to received data
167 * @param available number of bytes availabe in "buf",
168 * possibly 0 (on errors)
169 * @param addr address of the sender
170 * @param addrlen size of addr
171 * @param errCode value of errno (on errors receiving)
173 typedef void (*GNUNET_CONNECTION_Receiver) (void *cls,
176 const struct sockaddr *addr,
182 * Close the connection and free associated resources. There must
183 * not be any pending requests for reading or writing to the
184 * connection at this time.
186 * @param connection connection to destroy
189 GNUNET_CONNECTION_destroy (struct GNUNET_CONNECTION_Handle *connection);
193 * Signature of a function to create a custom tokenizer.
195 * @param cls closure from #GNUNET_SERVER_set_callbacks
196 * @param client handle to client the tokenzier will be used for
197 * @return handle to custom tokenizer ('mst')
199 typedef void *(*GNUNET_SERVER_MstCreateCallback) (
201 struct GNUNET_SERVER_Client *client);
205 * Signature of a function to destroy a custom tokenizer.
207 * @param cls closure from #GNUNET_SERVER_set_callbacks
208 * @param mst custom tokenizer handle
210 typedef void (*GNUNET_SERVER_MstDestroyCallback) (void *cls, void *mst);
213 * Signature of a function to receive data for a custom tokenizer.
215 * @param cls closure from #GNUNET_SERVER_set_callbacks
216 * @param mst custom tokenizer handle
217 * @param client_identity ID of client for which this is a buffer,
218 * can be NULL (will be passed back to 'cb')
219 * @param buf input data to add
220 * @param size number of bytes in @a buf
221 * @param purge should any excess bytes in the buffer be discarded
222 * (i.e. for packet-based services like UDP)
223 * @param one_shot only call callback once, keep rest of message in buffer
224 * @return #GNUNET_OK if we are done processing (need more data)
225 * #GNUNET_NO if one_shot was set and we have another message ready
226 * #GNUNET_SYSERR if the data stream is corrupt
228 typedef int (*GNUNET_SERVER_MstReceiveCallback) (
231 struct GNUNET_SERVER_Client *client,
237 * Functions with this signature are called whenever a message is
241 * @param client identification of the client
242 * @param message the actual message
244 typedef void (*GNUNET_SERVER_MessageCallback) (
246 struct GNUNET_SERVER_Client *client,
247 const struct GNUNET_MessageHeader *message);
250 * Message handler. Each struct specifies how to handle on particular
251 * type of message received.
253 struct GNUNET_SERVER_MessageHandler
256 * Function to call for messages of "type".
258 GNUNET_SERVER_MessageCallback callback;
261 * Closure argument for @e callback.
266 * Type of the message this handler covers.
271 * Expected size of messages of this type. Use 0 for
272 * variable-size. If non-zero, messages of the given
273 * type will be discarded (and the connection closed)
274 * if they do not have the right size.
276 uint16_t expected_size;
281 * Options for the service (bitmask).
283 enum LEGACY_SERVICE_Options
286 * Use defaults. Terminates all client connections and the listen
287 * sockets immediately upon receiving the shutdown signal.
289 LEGACY_SERVICE_OPTION_NONE = 0,
292 * Do not trigger server shutdown on signal at all; instead, allow
293 * for the user to terminate the server explicitly when needed
294 * by calling #LEGACY_SERVICE_shutdown().
296 LEGACY_SERVICE_OPTION_MANUAL_SHUTDOWN = 1,
299 * Trigger a SOFT server shutdown on signals, allowing active
300 * non-monitor clients to complete their transactions.
302 LEGACY_SERVICE_OPTION_SOFT_SHUTDOWN = 2
307 * Ask the server to disconnect from the given client. This is the
308 * same as passing #GNUNET_SYSERR to #GNUNET_SERVER_receive_done,
309 * except that it allows dropping of a client even when not handling a
310 * message from that client.
312 * @param client the client to disconnect from
315 GNUNET_SERVER_client_disconnect (struct GNUNET_SERVER_Client *client);
318 * Return user context associated with the given client.
319 * Note: you should probably use the macro (call without the underscore).
321 * @param client client to query
322 * @param size number of bytes in user context struct (for verification only)
323 * @return pointer to user context
326 GNUNET_SERVER_client_get_user_context_ (struct GNUNET_SERVER_Client *client,
331 * Functions with this signature are called whenever a
332 * complete message is received by the tokenizer.
334 * Do not call #GNUNET_SERVER_mst_destroy from within
335 * the scope of this callback.
338 * @param client identification of the client
339 * @param message the actual message
340 * @return #GNUNET_OK on success, #GNUNET_SYSERR to stop further processing
342 typedef int (*GNUNET_SERVER_MessageTokenizerCallback) (
345 const struct GNUNET_MessageHeader *message);
349 * Create a message stream tokenizer.
351 * @param cb function to call on completed messages
352 * @param cb_cls closure for @a cb
353 * @return handle to tokenizer
355 struct GNUNET_SERVER_MessageStreamTokenizer *
356 GNUNET_SERVER_mst_create (GNUNET_SERVER_MessageTokenizerCallback cb,
360 * Add incoming data to the receive buffer and call the
361 * callback for all complete messages.
363 * @param mst tokenizer to use
364 * @param client_identity ID of client for which this is a buffer,
365 * can be NULL (will be passed back to 'cb')
366 * @param buf input data to add
367 * @param size number of bytes in @a buf
368 * @param purge should any excess bytes in the buffer be discarded
369 * (i.e. for packet-based services like UDP)
370 * @param one_shot only call callback once, keep rest of message in buffer
371 * @return #GNUNET_OK if we are done processing (need more data)
372 * #GNUNET_NO if one_shot was set and we have another message ready
373 * #GNUNET_SYSERR if the data stream is corrupt
376 GNUNET_SERVER_mst_receive (struct GNUNET_SERVER_MessageStreamTokenizer *mst,
377 void *client_identity,
385 * Destroys a tokenizer.
387 * @param mst tokenizer to destroy
390 GNUNET_SERVER_mst_destroy (struct GNUNET_SERVER_MessageStreamTokenizer *mst);
394 * Set user context to be associated with the given client.
395 * Note: you should probably use the macro (call without the underscore).
397 * @param client client to query
398 * @param ptr pointer to user context
399 * @param size number of bytes in user context struct (for verification only)
402 GNUNET_SERVER_client_set_user_context_ (struct GNUNET_SERVER_Client *client,
406 * Return user context associated with the given client.
408 * @param client client to query
409 * @param type expected return type (i.e. 'struct Foo')
410 * @return pointer to user context of type 'type *'.
412 #define GNUNET_SERVER_client_get_user_context(client, type) \
413 (type *) GNUNET_SERVER_client_get_user_context_ (client, sizeof(type))
416 * Set user context to be associated with the given client.
418 * @param client client to query
419 * @param value pointer to user context
421 #define GNUNET_SERVER_client_set_user_context(client, value) \
422 GNUNET_SERVER_client_set_user_context_ (client, value, sizeof(*value))
426 * Notify us when the server has enough space to transmit
427 * a message of the given size to the given client.
429 * @param client client to transmit message to
430 * @param size requested amount of buffer space
431 * @param timeout after how long should we give up (and call
432 * notify with buf NULL and size 0)?
433 * @param callback function to call when space is available
434 * @param callback_cls closure for @a callback
435 * @return non-NULL if the notify callback was queued; can be used
436 * to cancel the request using
437 * #GNUNET_SERVER_notify_transmit_ready_cancel.
438 * NULL if we are already going to notify someone else (busy)
440 struct GNUNET_SERVER_TransmitHandle *
441 GNUNET_SERVER_notify_transmit_ready (
442 struct GNUNET_SERVER_Client *client,
444 struct GNUNET_TIME_Relative timeout,
445 GNUNET_CONNECTION_TransmitReadyNotify callback,
449 * Abort transmission request.
451 * @param th request to abort
454 GNUNET_SERVER_notify_transmit_ready_cancel (
455 struct GNUNET_SERVER_TransmitHandle *th);
459 * Notify the server that the given client handle should
460 * be kept (keeps the connection up if possible, increments
461 * the internal reference counter).
463 * @param client the client to keep
466 GNUNET_SERVER_client_keep (struct GNUNET_SERVER_Client *client);
470 * Notify the server that the given client handle is no
471 * longer required. Decrements the reference counter. If
472 * that counter reaches zero an inactive connection maybe
475 * @param client the client to drop
478 GNUNET_SERVER_client_drop (struct GNUNET_SERVER_Client *client);
482 * Function called by the service's run
483 * method to run service-specific setup code.
486 * @param server the initialized server
487 * @param cfg configuration to use
489 typedef void (*LEGACY_SERVICE_Main) (
491 struct GNUNET_SERVER_Handle *server,
492 const struct GNUNET_CONFIGURATION_Handle *cfg);
496 * Suspend accepting connections from the listen socket temporarily.
497 * Resume activity using #GNUNET_SERVER_resume.
499 * @param server server to stop accepting connections.
502 GNUNET_SERVER_suspend (struct GNUNET_SERVER_Handle *server);
505 * Notify us when the server has enough space to transmit
506 * a message of the given size to the given client.
508 * @param client client to transmit message to
509 * @param size requested amount of buffer space
510 * @param timeout after how long should we give up (and call
511 * notify with buf NULL and size 0)?
512 * @param callback function to call when space is available
513 * @param callback_cls closure for @a callback
514 * @return non-NULL if the notify callback was queued; can be used
515 * to cancel the request using
516 * #GNUNET_SERVER_notify_transmit_ready_cancel.
517 * NULL if we are already going to notify someone else (busy)
519 struct GNUNET_SERVER_TransmitHandle *
520 GNUNET_SERVER_notify_transmit_ready (
521 struct GNUNET_SERVER_Client *client,
523 struct GNUNET_TIME_Relative timeout,
524 GNUNET_CONNECTION_TransmitReadyNotify callback,
529 * Add a TCP socket-based connection to the set of handles managed by
530 * this server. Use this function for outgoing (P2P) connections that
531 * we initiated (and where this server should process incoming
534 * @param server the server to use
535 * @param connection the connection to manage (client must
536 * stop using this connection from now on)
537 * @return the client handle
539 struct GNUNET_SERVER_Client *
540 GNUNET_SERVER_connect_socket (struct GNUNET_SERVER_Handle *server,
541 struct GNUNET_CONNECTION_Handle *connection);
545 * Resume accepting connections from the listen socket.
547 * @param server server to resume accepting connections.
550 GNUNET_SERVER_resume (struct GNUNET_SERVER_Handle *server);
553 * Free resources held by this server.
555 * @param server server to destroy
558 GNUNET_SERVER_destroy (struct GNUNET_SERVER_Handle *server);
561 #include "tcp_connection_legacy.c"
562 #include "tcp_server_mst_legacy.c"
563 #include "tcp_server_legacy.c"
564 #include "tcp_service_legacy.c"
566 GNUNET_NETWORK_STRUCT_BEGIN
569 * Initial handshake message for a session.
571 struct WelcomeMessage
574 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_WELCOME.
576 struct GNUNET_MessageHeader header;
579 * Identity of the node connecting (TCP client)
581 struct GNUNET_PeerIdentity clientIdentity;
585 * Basically a WELCOME message, but with the purpose
586 * of giving the waiting peer a client handle to use
588 struct TCP_NAT_ProbeMessage
591 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_NAT_PROBE.
593 struct GNUNET_MessageHeader header;
596 * Identity of the sender of the message.
598 struct GNUNET_PeerIdentity clientIdentity;
600 GNUNET_NETWORK_STRUCT_END
603 * Context for sending a NAT probe via TCP.
605 struct TCPProbeContext
608 * Active probes are kept in a DLL.
610 struct TCPProbeContext *next;
613 * Active probes are kept in a DLL.
615 struct TCPProbeContext *prev;
620 struct GNUNET_CONNECTION_Handle *sock;
623 * Message to be sent.
625 struct TCP_NAT_ProbeMessage message;
628 * Handle to the transmission.
630 struct GNUNET_CONNECTION_TransmitHandle *transmit_handle;
633 * Transport plugin handle.
635 struct Plugin *plugin;
639 * Bits in the `options` field of TCP addresses.
641 enum TcpAddressOptions
646 TCP_OPTIONS_NONE = 0,
649 * See #HTTP_OPTIONS_VERIFY_CERTIFICATE.
651 TCP_OPTIONS_RESERVED = 1,
654 * Enable TCP Stealth-style port knocking.
656 TCP_OPTIONS_TCP_STEALTH = 2
659 GNUNET_NETWORK_STRUCT_BEGIN
662 * Network format for IPv4 addresses.
664 struct IPv4TcpAddress
667 * Optional options and flags for this address,
668 * see `enum TcpAddressOptions`
670 uint32_t options GNUNET_PACKED;
673 * IPv4 address, in network byte order.
675 uint32_t ipv4_addr GNUNET_PACKED;
678 * Port number, in network byte order.
680 uint16_t t4_port GNUNET_PACKED;
684 * Network format for IPv6 addresses.
686 struct IPv6TcpAddress
689 * Optional flags for this address
690 * see `enum TcpAddressOptions`
692 uint32_t options GNUNET_PACKED;
697 struct in6_addr ipv6_addr GNUNET_PACKED;
700 * Port number, in network byte order.
702 uint16_t t6_port GNUNET_PACKED;
704 GNUNET_NETWORK_STRUCT_END
707 * Encapsulation of all of the state of the plugin.
712 * Information kept for each message that is yet to
715 struct PendingMessage
718 * This is a doubly-linked list.
720 struct PendingMessage *next;
723 * This is a doubly-linked list.
725 struct PendingMessage *prev;
728 * The pending message
733 * Continuation function to call once the message
734 * has been sent. Can be NULL if there is no
735 * continuation to call.
737 GNUNET_TRANSPORT_TransmitContinuation transmit_cont;
740 * Closure for @e transmit_cont.
742 void *transmit_cont_cls;
745 * Timeout value for the pending message.
747 struct GNUNET_TIME_Absolute timeout;
750 * So that the gnunet-service-transport can group messages together,
751 * these pending messages need to accept a message buffer and size
752 * instead of just a `struct GNUNET_MessageHeader`.
758 * Session handle for TCP connections.
760 struct GNUNET_ATS_Session
763 * To whom are we talking to (set to our identity
764 * if we are still waiting for the welcome message)
766 struct GNUNET_PeerIdentity target;
769 * Pointer to the global plugin struct.
771 struct Plugin *plugin;
774 * The client (used to identify this connection)
776 struct GNUNET_SERVER_Client *client;
779 * Task cleaning up a NAT client connection establishment attempt;
781 struct GNUNET_SCHEDULER_Task *nat_connection_timeout;
784 * Messages currently pending for transmission
785 * to this peer, if any.
787 struct PendingMessage *pending_messages_head;
790 * Messages currently pending for transmission
791 * to this peer, if any.
793 struct PendingMessage *pending_messages_tail;
796 * Handle for pending transmission request.
798 struct GNUNET_SERVER_TransmitHandle *transmit_handle;
801 * Address of the other peer.
803 struct GNUNET_HELLO_Address *address;
806 * ID of task used to delay receiving more to throttle sender.
808 struct GNUNET_SCHEDULER_Task *receive_delay_task;
811 * Session timeout task
813 struct GNUNET_SCHEDULER_Task *timeout_task;
816 * When will this session time out?
818 struct GNUNET_TIME_Absolute timeout;
821 * When will we continue to read from the socket?
822 * (used to enforce inbound quota).
824 struct GNUNET_TIME_Absolute receive_delay;
827 * Last activity on this connection. Used to select preferred
830 struct GNUNET_TIME_Absolute last_activity;
833 * Number of bytes waiting for transmission to this peer.
835 unsigned long long bytes_in_queue;
838 * Number of messages waiting for transmission to this peer.
840 unsigned int msgs_in_queue;
843 * Network type of the address.
845 enum GNUNET_NetworkType scope;
848 * Are we still expecting the welcome message? (#GNUNET_YES/#GNUNET_NO)
850 int expecting_welcome;
853 * Was this session created using NAT traversal?
860 * Context for address to string conversion, closure
861 * for #append_port().
863 struct PrettyPrinterContext
868 struct PrettyPrinterContext *next;
873 struct PrettyPrinterContext *prev;
878 struct Plugin *plugin;
883 struct GNUNET_SCHEDULER_Task *timeout_task;
888 struct GNUNET_RESOLVER_RequestHandle *resolver_handle;
891 * Function to call with the result.
893 GNUNET_TRANSPORT_AddressStringCallback asc;
896 * Clsoure for @e asc.
911 * Port to add after the IP address.
918 * Encapsulation of all of the state of the plugin.
925 struct GNUNET_TRANSPORT_PluginEnvironment *env;
930 struct GNUNET_CONNECTION_Handle *lsock;
933 * Our handle to the NAT module.
935 struct GNUNET_NAT_Handle *nat;
938 * Map from peer identities to sessions for the given peer.
940 struct GNUNET_CONTAINER_MultiPeerMap *sessionmap;
943 * Handle to the network service.
945 struct LEGACY_SERVICE_Context *service;
948 * Handle to the server for this service.
950 struct GNUNET_SERVER_Handle *server;
953 * Copy of the handler array where the closures are
954 * set to this struct's instance.
956 struct GNUNET_SERVER_MessageHandler *handlers;
959 * Map of peers we have tried to contact behind a NAT
961 struct GNUNET_CONTAINER_MultiPeerMap *nat_wait_conns;
964 * List of active TCP probes.
966 struct TCPProbeContext *probe_head;
969 * List of active TCP probes.
971 struct TCPProbeContext *probe_tail;
974 * Function to call about session status changes.
976 GNUNET_TRANSPORT_SessionInfoCallback sic;
979 * Closure for @e sic.
984 * ID of task used to update our addresses when one expires.
986 struct GNUNET_SCHEDULER_Task *address_update_task;
989 * Running pretty printers: head
991 struct PrettyPrinterContext *ppc_dll_head;
994 * Running pretty printers: tail
996 struct PrettyPrinterContext *ppc_dll_tail;
999 * Welcome message used by this peer.
1001 struct WelcomeMessage my_welcome;
1004 * How many more TCP sessions are we allowed to open right now?
1006 unsigned long long max_connections;
1009 * How many more TCP sessions do we have right now?
1011 unsigned long long cur_connections;
1019 * Port that we are actually listening on.
1024 * Port that the user said we would have visible to the
1025 * rest of the world.
1032 * Get the list of addresses that a server for the given service
1035 * @param service_name name of the service
1036 * @param cfg configuration (which specifies the addresses)
1037 * @param addrs set (call by reference) to an array of pointers to the
1038 * addresses the server should bind to and listen on; the
1039 * array will be NULL-terminated (on success)
1040 * @param addr_lens set (call by reference) to an array of the lengths
1041 * of the respective `struct sockaddr` struct in the @a addrs
1042 * array (on success)
1043 * @return number of addresses found on success,
1044 * #GNUNET_SYSERR if the configuration
1045 * did not specify reasonable finding information or
1046 * if it specified a hostname that could not be resolved;
1047 * #GNUNET_NO if the number of addresses configured is
1048 * zero (in this case, `*addrs` and `*addr_lens` will be
1052 get_server_addresses (const char *service_name,
1053 const struct GNUNET_CONFIGURATION_Handle *cfg,
1054 struct sockaddr ***addrs,
1055 socklen_t **addr_lens)
1058 struct GNUNET_NETWORK_Handle *desc;
1059 unsigned long long port;
1061 struct addrinfo hints;
1062 struct addrinfo *res;
1063 struct addrinfo *pos;
1064 struct addrinfo *next;
1069 struct sockaddr **saddrs;
1070 socklen_t *saddrlens;
1076 if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "DISABLEV6"))
1078 if (GNUNET_SYSERR ==
1079 (disablev6 = GNUNET_CONFIGURATION_get_value_yesno (cfg,
1082 return GNUNET_SYSERR;
1085 disablev6 = GNUNET_NO;
1089 /* probe IPv6 support */
1090 desc = GNUNET_NETWORK_socket_create (PF_INET6, SOCK_STREAM, 0);
1093 if ((ENOBUFS == errno) || (ENOMEM == errno) || (ENFILE == errno) ||
1096 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "socket");
1097 return GNUNET_SYSERR;
1099 LOG (GNUNET_ERROR_TYPE_INFO,
1101 "Disabling IPv6 support for service `%s', failed to create IPv6 socket: %s\n"),
1104 disablev6 = GNUNET_YES;
1108 GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (desc));
1114 if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "PORT"))
1116 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (cfg,
1121 LOG (GNUNET_ERROR_TYPE_ERROR,
1122 _ ("Require valid port number for service `%s' in configuration!\n"),
1127 LOG (GNUNET_ERROR_TYPE_ERROR,
1128 _ ("Require valid port number for service `%s' in configuration!\n"),
1130 return GNUNET_SYSERR;
1134 if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "BINDTO"))
1136 GNUNET_break (GNUNET_OK ==
1137 GNUNET_CONFIGURATION_get_value_string (cfg,
1146 abstract = GNUNET_NO;
1149 GNUNET_CONFIGURATION_have_value (cfg, service_name, "UNIXPATH")) &&
1150 (GNUNET_OK == GNUNET_CONFIGURATION_get_value_filename (cfg,
1154 (0 < strlen (unixpath)))
1156 /* probe UNIX support */
1157 struct sockaddr_un s_un;
1159 if (strlen (unixpath) >= sizeof(s_un.sun_path))
1161 LOG (GNUNET_ERROR_TYPE_WARNING,
1162 _ ("UNIXPATH `%s' too long, maximum length is %llu\n"),
1164 (unsigned long long) sizeof(s_un.sun_path));
1165 unixpath = GNUNET_NETWORK_shorten_unixpath (unixpath);
1166 LOG (GNUNET_ERROR_TYPE_INFO, _ ("Using `%s' instead\n"), unixpath);
1169 abstract = GNUNET_CONFIGURATION_get_value_yesno (cfg,
1171 "USE_ABSTRACT_SOCKETS");
1172 if (GNUNET_SYSERR == abstract)
1173 abstract = GNUNET_NO;
1175 if ((GNUNET_YES != abstract) &&
1176 (GNUNET_OK != GNUNET_DISK_directory_create_for_file (unixpath)))
1177 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "mkdir", unixpath);
1179 if (NULL != unixpath)
1181 desc = GNUNET_NETWORK_socket_create (AF_UNIX, SOCK_STREAM, 0);
1184 if ((ENOBUFS == errno) || (ENOMEM == errno) || (ENFILE == errno) ||
1187 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "socket");
1188 GNUNET_free_non_null (hostname);
1189 GNUNET_free (unixpath);
1190 return GNUNET_SYSERR;
1192 LOG (GNUNET_ERROR_TYPE_INFO,
1194 "Disabling UNIX domain socket support for service `%s', failed to create UNIX domain socket: %s\n"),
1197 GNUNET_free (unixpath);
1202 GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (desc));
1208 if ((0 == port) && (NULL == unixpath))
1210 LOG (GNUNET_ERROR_TYPE_ERROR,
1212 "Have neither PORT nor UNIXPATH for service `%s', but one is required\n"),
1214 GNUNET_free_non_null (hostname);
1215 return GNUNET_SYSERR;
1219 saddrs = GNUNET_malloc (2 * sizeof(struct sockaddr *));
1220 saddrlens = GNUNET_malloc (2 * sizeof(socklen_t));
1221 add_unixpath (saddrs, saddrlens, unixpath, abstract);
1222 GNUNET_free_non_null (unixpath);
1223 GNUNET_free_non_null (hostname);
1225 *addr_lens = saddrlens;
1229 if (NULL != hostname)
1231 LOG (GNUNET_ERROR_TYPE_DEBUG,
1232 "Resolving `%s' since that is where `%s' will bind to.\n",
1235 memset (&hints, 0, sizeof(struct addrinfo));
1237 hints.ai_family = AF_INET;
1238 hints.ai_protocol = IPPROTO_TCP;
1239 if ((0 != (ret = getaddrinfo (hostname, NULL, &hints, &res))) ||
1242 LOG (GNUNET_ERROR_TYPE_ERROR,
1243 _ ("Failed to resolve `%s': %s\n"),
1245 gai_strerror (ret));
1246 GNUNET_free (hostname);
1247 GNUNET_free_non_null (unixpath);
1248 return GNUNET_SYSERR;
1252 while (NULL != (pos = next))
1254 next = pos->ai_next;
1255 if ((disablev6) && (pos->ai_family == AF_INET6))
1261 LOG (GNUNET_ERROR_TYPE_ERROR,
1262 _ ("Failed to find %saddress for `%s'.\n"),
1263 disablev6 ? "IPv4 " : "",
1266 GNUNET_free (hostname);
1267 GNUNET_free_non_null (unixpath);
1268 return GNUNET_SYSERR;
1271 if (NULL != unixpath)
1273 saddrs = GNUNET_malloc ((resi + 1) * sizeof(struct sockaddr *));
1274 saddrlens = GNUNET_malloc ((resi + 1) * sizeof(socklen_t));
1276 if (NULL != unixpath)
1278 add_unixpath (saddrs, saddrlens, unixpath, abstract);
1282 while (NULL != (pos = next))
1284 next = pos->ai_next;
1285 if ((disablev6) && (AF_INET6 == pos->ai_family))
1287 if ((IPPROTO_TCP != pos->ai_protocol) && (0 != pos->ai_protocol))
1288 continue; /* not TCP */
1289 if ((SOCK_STREAM != pos->ai_socktype) && (0 != pos->ai_socktype))
1290 continue; /* huh? */
1291 LOG (GNUNET_ERROR_TYPE_DEBUG,
1292 "Service `%s' will bind to `%s'\n",
1294 GNUNET_a2s (pos->ai_addr, pos->ai_addrlen));
1295 if (AF_INET == pos->ai_family)
1297 GNUNET_assert (sizeof(struct sockaddr_in) == pos->ai_addrlen);
1298 saddrlens[i] = pos->ai_addrlen;
1299 saddrs[i] = GNUNET_malloc (saddrlens[i]);
1300 GNUNET_memcpy (saddrs[i], pos->ai_addr, saddrlens[i]);
1301 ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
1305 GNUNET_assert (AF_INET6 == pos->ai_family);
1306 GNUNET_assert (sizeof(struct sockaddr_in6) == pos->ai_addrlen);
1307 saddrlens[i] = pos->ai_addrlen;
1308 saddrs[i] = GNUNET_malloc (saddrlens[i]);
1309 GNUNET_memcpy (saddrs[i], pos->ai_addr, saddrlens[i]);
1310 ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port);
1314 GNUNET_free (hostname);
1320 /* will bind against everything, just set port */
1325 if (NULL != unixpath)
1328 saddrs = GNUNET_malloc ((resi + 1) * sizeof(struct sockaddr *));
1329 saddrlens = GNUNET_malloc ((resi + 1) * sizeof(socklen_t));
1330 if (NULL != unixpath)
1332 add_unixpath (saddrs, saddrlens, unixpath, abstract);
1335 saddrlens[i] = sizeof(struct sockaddr_in);
1336 saddrs[i] = GNUNET_malloc (saddrlens[i]);
1337 #if HAVE_SOCKADDR_IN_SIN_LEN
1338 ((struct sockaddr_in *) saddrs[i])->sin_len = saddrlens[i];
1340 ((struct sockaddr_in *) saddrs[i])->sin_family = AF_INET;
1341 ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
1347 if (NULL != unixpath)
1349 saddrs = GNUNET_malloc ((resi + 1) * sizeof(struct sockaddr *));
1350 saddrlens = GNUNET_malloc ((resi + 1) * sizeof(socklen_t));
1352 if (NULL != unixpath)
1354 add_unixpath (saddrs, saddrlens, unixpath, abstract);
1357 saddrlens[i] = sizeof(struct sockaddr_in6);
1358 saddrs[i] = GNUNET_malloc (saddrlens[i]);
1359 #if HAVE_SOCKADDR_IN_SIN_LEN
1360 ((struct sockaddr_in6 *) saddrs[i])->sin6_len = saddrlens[0];
1362 ((struct sockaddr_in6 *) saddrs[i])->sin6_family = AF_INET6;
1363 ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port);
1365 saddrlens[i] = sizeof(struct sockaddr_in);
1366 saddrs[i] = GNUNET_malloc (saddrlens[i]);
1367 #if HAVE_SOCKADDR_IN_SIN_LEN
1368 ((struct sockaddr_in *) saddrs[i])->sin_len = saddrlens[1];
1370 ((struct sockaddr_in *) saddrs[i])->sin_family = AF_INET;
1371 ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
1374 GNUNET_free_non_null (unixpath);
1376 *addr_lens = saddrlens;
1379 /* end ancient copy-and-paste */
1383 * If a session monitor is attached, notify it about the new
1386 * @param plugin our plugin
1387 * @param session session that changed state
1388 * @param state new state of the session
1391 notify_session_monitor (struct Plugin *plugin,
1392 struct GNUNET_ATS_Session *session,
1393 enum GNUNET_TRANSPORT_SessionState state)
1395 struct GNUNET_TRANSPORT_SessionInfo info;
1397 if (NULL == plugin->sic)
1399 memset (&info, 0, sizeof(info));
1402 GNUNET_HELLO_address_check_option (session->address,
1403 GNUNET_HELLO_ADDRESS_INFO_INBOUND);
1404 info.num_msg_pending = session->msgs_in_queue;
1405 info.num_bytes_pending = session->bytes_in_queue;
1406 if (NULL != session->receive_delay_task)
1407 info.receive_delay = session->receive_delay;
1408 info.session_timeout = session->timeout;
1409 info.address = session->address;
1410 plugin->sic (plugin->sic_cls, session, &info);
1415 * Our external IP address/port mapping has changed.
1417 * @param cls closure, the `struct Plugin`
1418 * @param app_ctx[in,out] location where the app can store stuff
1419 * on add and retrieve it on remove
1420 * @param add_remove #GNUNET_YES to mean the new public IP address, #GNUNET_NO to mean
1421 * the previous (now invalid) one
1422 * @param ac address class the address belongs to
1423 * @param addr either the previous or the new public IP address
1424 * @param addrlen actual length of @a addr
1427 tcp_nat_port_map_callback (void *cls,
1430 enum GNUNET_NAT_AddressClass ac,
1431 const struct sockaddr *addr,
1434 struct Plugin *plugin = cls;
1435 struct GNUNET_HELLO_Address *address;
1436 struct IPv4TcpAddress t4;
1437 struct IPv6TcpAddress t6;
1442 LOG (GNUNET_ERROR_TYPE_INFO,
1443 "NAT notification to %s address `%s'\n",
1444 (GNUNET_YES == add_remove) ? "add" : "remove",
1445 GNUNET_a2s (addr, addrlen));
1446 /* convert 'addr' to our internal format */
1447 switch (addr->sa_family)
1450 GNUNET_assert (addrlen == sizeof(struct sockaddr_in));
1451 memset (&t4, 0, sizeof(t4));
1452 t4.options = htonl (plugin->myoptions);
1453 t4.ipv4_addr = ((struct sockaddr_in *) addr)->sin_addr.s_addr;
1454 t4.t4_port = ((struct sockaddr_in *) addr)->sin_port;
1460 if (IN6_IS_ADDR_LINKLOCAL (&((struct sockaddr_in6 *) addr)->sin6_addr))
1462 /* skip link local, we don't allow them in
1463 #tcp_plugin_check_address() */
1466 GNUNET_assert (addrlen == sizeof(struct sockaddr_in6));
1467 memset (&t6, 0, sizeof(t6));
1468 GNUNET_memcpy (&t6.ipv6_addr,
1469 &((struct sockaddr_in6 *) addr)->sin6_addr,
1470 sizeof(struct in6_addr));
1471 t6.options = htonl (plugin->myoptions);
1472 t6.t6_port = ((struct sockaddr_in6 *) addr)->sin6_port;
1481 /* modify our published address list */
1482 GNUNET_assert ((args == sizeof(struct IPv4TcpAddress)) ||
1483 (args == sizeof(struct IPv6TcpAddress)));
1484 /* TODO: use 'ac' here in the future... */
1485 address = GNUNET_HELLO_address_allocate (plugin->env->my_identity,
1489 GNUNET_HELLO_ADDRESS_INFO_NONE);
1490 plugin->env->notify_address (plugin->env->cls, add_remove, address);
1491 GNUNET_HELLO_address_free (address);
1496 * Function called for a quick conversion of the binary address to
1497 * a numeric address. Note that the caller must not free the
1498 * address and that the next call to this function is allowed
1499 * to override the address again.
1501 * @param cls closure (`struct Plugin*`)
1502 * @param addr binary address
1503 * @param addrlen length of @a addr
1504 * @return string representing the same address
1507 tcp_plugin_address_to_string (void *cls, const void *addr, size_t addrlen)
1509 static char rbuf[INET6_ADDRSTRLEN + 12];
1510 char buf[INET6_ADDRSTRLEN];
1514 const struct IPv4TcpAddress *t4;
1515 const struct IPv6TcpAddress *t6;
1522 case sizeof(struct IPv6TcpAddress):
1525 port = ntohs (t6->t6_port);
1526 options = ntohl (t6->options);
1527 GNUNET_memcpy (&a6, &t6->ipv6_addr, sizeof(a6));
1531 case sizeof(struct IPv4TcpAddress):
1534 port = ntohs (t4->t4_port);
1535 options = ntohl (t4->options);
1536 GNUNET_memcpy (&a4, &t4->ipv4_addr, sizeof(a4));
1541 LOG (GNUNET_ERROR_TYPE_WARNING,
1542 _ ("Unexpected address length: %u bytes\n"),
1543 (unsigned int) addrlen);
1546 if (NULL == inet_ntop (af, sb, buf, INET6_ADDRSTRLEN))
1548 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "inet_ntop");
1551 GNUNET_snprintf (rbuf,
1553 (af == AF_INET6) ? "%s.%u.[%s]:%u" : "%s.%u.%s:%u",
1563 * Function called to convert a string address to
1566 * @param cls closure (`struct Plugin*`)
1567 * @param addr string address
1568 * @param addrlen length of the address
1569 * @param buf location to store the buffer
1570 * @param added location to store the number of bytes in the buffer.
1571 * If the function returns #GNUNET_SYSERR, its contents are undefined.
1572 * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure
1575 tcp_plugin_string_to_address (void *cls,
1581 struct sockaddr_storage socket_address;
1587 /* Format tcp.options.address:port */
1591 if ((NULL == addr) || (0 == addrlen))
1594 return GNUNET_SYSERR;
1596 if ('\0' != addr[addrlen - 1])
1599 return GNUNET_SYSERR;
1601 if (strlen (addr) != addrlen - 1)
1604 return GNUNET_SYSERR;
1606 plugin = GNUNET_strdup (addr);
1607 optionstr = strchr (plugin, '.');
1608 if (NULL == optionstr)
1611 GNUNET_free (plugin);
1612 return GNUNET_SYSERR;
1614 optionstr[0] = '\0';
1616 options = atol (optionstr);
1617 address = strchr (optionstr, '.');
1618 if (NULL == address)
1621 GNUNET_free (plugin);
1622 return GNUNET_SYSERR;
1628 GNUNET_STRINGS_to_address_ip (address, strlen (address), &socket_address))
1631 GNUNET_free (plugin);
1632 return GNUNET_SYSERR;
1635 GNUNET_free (plugin);
1636 switch (socket_address.ss_family)
1639 struct IPv4TcpAddress *t4;
1640 struct sockaddr_in *in4 = (struct sockaddr_in *) &socket_address;
1641 t4 = GNUNET_new (struct IPv4TcpAddress);
1642 t4->options = htonl (options);
1643 t4->ipv4_addr = in4->sin_addr.s_addr;
1644 t4->t4_port = in4->sin_port;
1646 *added = sizeof(struct IPv4TcpAddress);
1651 struct IPv6TcpAddress *t6;
1652 struct sockaddr_in6 *in6 = (struct sockaddr_in6 *) &socket_address;
1653 t6 = GNUNET_new (struct IPv6TcpAddress);
1654 t6->options = htonl (options);
1655 t6->ipv6_addr = in6->sin6_addr;
1656 t6->t6_port = in6->sin6_port;
1658 *added = sizeof(struct IPv6TcpAddress);
1663 return GNUNET_SYSERR;
1669 * Find the session handle for the given client.
1670 * Currently uses both the hashmap and the client
1671 * context, as the client context is new and the
1672 * logic still needs to be tested.
1674 * @param plugin the plugin
1675 * @param client which client to find the session handle for
1676 * @return NULL if no matching session exists
1678 static struct GNUNET_ATS_Session *
1679 lookup_session_by_client (struct Plugin *plugin,
1680 struct GNUNET_SERVER_Client *client)
1682 return GNUNET_SERVER_client_get_user_context (client,
1683 struct GNUNET_ATS_Session);
1688 * Functions with this signature are called whenever we need
1689 * to close a session due to a disconnect or failure to
1690 * establish a connection.
1692 * @param cls the `struct Plugin`
1693 * @param session session to close down
1694 * @return #GNUNET_OK on success
1697 tcp_plugin_disconnect_session (void *cls, struct GNUNET_ATS_Session *session)
1699 struct Plugin *plugin = cls;
1700 struct PendingMessage *pm;
1702 LOG (GNUNET_ERROR_TYPE_DEBUG,
1703 "Disconnecting session of peer `%s' address `%s'\n",
1704 GNUNET_i2s (&session->target),
1705 tcp_plugin_address_to_string (session->plugin,
1706 session->address->address,
1707 session->address->address_length));
1709 if (NULL != session->timeout_task)
1711 GNUNET_SCHEDULER_cancel (session->timeout_task);
1712 session->timeout_task = NULL;
1713 session->timeout = GNUNET_TIME_UNIT_ZERO_ABS;
1716 if (GNUNET_YES == GNUNET_CONTAINER_multipeermap_remove (plugin->sessionmap,
1720 GNUNET_STATISTICS_update (session->plugin->env->stats,
1721 gettext_noop ("# TCP sessions active"),
1727 GNUNET_assert (GNUNET_YES ==
1728 GNUNET_CONTAINER_multipeermap_remove (plugin->nat_wait_conns,
1732 if (NULL != session->client)
1733 GNUNET_SERVER_client_set_user_context (session->client, NULL);
1735 /* clean up state */
1736 if (NULL != session->transmit_handle)
1738 GNUNET_SERVER_notify_transmit_ready_cancel (session->transmit_handle);
1739 session->transmit_handle = NULL;
1741 session->plugin->env->session_end (session->plugin->env->cls,
1745 if (NULL != session->nat_connection_timeout)
1747 GNUNET_SCHEDULER_cancel (session->nat_connection_timeout);
1748 session->nat_connection_timeout = NULL;
1751 while (NULL != (pm = session->pending_messages_head))
1753 LOG (GNUNET_ERROR_TYPE_DEBUG,
1754 (NULL != pm->transmit_cont)
1755 ? "Could not deliver message to `%s' at %s.\n"
1756 : "Could not deliver message to `%s' at %s, notifying.\n",
1757 GNUNET_i2s (&session->target),
1758 tcp_plugin_address_to_string (session->plugin,
1759 session->address->address,
1760 session->address->address_length));
1761 GNUNET_STATISTICS_update (session->plugin->env->stats,
1762 gettext_noop ("# bytes currently in TCP buffers"),
1763 -(int64_t) pm->message_size,
1765 GNUNET_STATISTICS_update (session->plugin->env->stats,
1767 "# bytes discarded by TCP (disconnect)"),
1770 GNUNET_CONTAINER_DLL_remove (session->pending_messages_head,
1771 session->pending_messages_tail,
1773 GNUNET_assert (0 < session->msgs_in_queue);
1774 session->msgs_in_queue--;
1775 GNUNET_assert (pm->message_size <= session->bytes_in_queue);
1776 session->bytes_in_queue -= pm->message_size;
1777 if (NULL != pm->transmit_cont)
1778 pm->transmit_cont (pm->transmit_cont_cls,
1785 GNUNET_assert (0 == session->msgs_in_queue);
1786 GNUNET_assert (0 == session->bytes_in_queue);
1787 notify_session_monitor (session->plugin, session, GNUNET_TRANSPORT_SS_DONE);
1789 if (NULL != session->receive_delay_task)
1791 GNUNET_SCHEDULER_cancel (session->receive_delay_task);
1792 session->receive_delay_task = NULL;
1794 if (NULL != session->client)
1796 GNUNET_SERVER_client_disconnect (session->client);
1797 session->client = NULL;
1799 GNUNET_HELLO_address_free (session->address);
1800 GNUNET_assert (NULL == session->transmit_handle);
1801 GNUNET_free (session);
1807 * Function that is called to get the keepalive factor.
1808 * #GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT is divided by this number to
1809 * calculate the interval between keepalive packets.
1811 * @param cls closure with the `struct Plugin`
1812 * @return keepalive factor
1815 tcp_plugin_query_keepalive_factor (void *cls)
1822 * Session was idle for too long, so disconnect it
1824 * @param cls the `struct GNUNET_ATS_Session` of the idle session
1827 session_timeout (void *cls)
1829 struct GNUNET_ATS_Session *s = cls;
1830 struct GNUNET_TIME_Relative left;
1832 s->timeout_task = NULL;
1833 left = GNUNET_TIME_absolute_get_remaining (s->timeout);
1834 if (0 != left.rel_value_us)
1836 /* not actually our turn yet, but let's at least update
1837 the monitor, it may think we're about to die ... */
1838 notify_session_monitor (s->plugin, s, GNUNET_TRANSPORT_SS_UPDATE);
1839 s->timeout_task = GNUNET_SCHEDULER_add_delayed (left, &session_timeout, s);
1842 LOG (GNUNET_ERROR_TYPE_DEBUG,
1843 "Session %p was idle for %s, disconnecting\n",
1845 GNUNET_STRINGS_relative_time_to_string (
1846 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
1848 /* call session destroy function */
1849 tcp_plugin_disconnect_session (s->plugin, s);
1854 * Increment session timeout due to activity.
1856 * @param s session to increment timeout for
1859 reschedule_session_timeout (struct GNUNET_ATS_Session *s)
1861 GNUNET_assert (NULL != s->timeout_task);
1863 GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1868 * Create a new session. Also queues a welcome message.
1870 * @param plugin the plugin
1871 * @param address the address to create the session for
1872 * @param scope network scope the address is from
1873 * @param client client to use, reference counter must have already been increased
1874 * @param is_nat this a NAT session, we should wait for a client to
1875 * connect to us from an address, then assign that to
1877 * @return new session object
1879 static struct GNUNET_ATS_Session *
1880 create_session (struct Plugin *plugin,
1881 const struct GNUNET_HELLO_Address *address,
1882 enum GNUNET_NetworkType scope,
1883 struct GNUNET_SERVER_Client *client,
1886 struct GNUNET_ATS_Session *session;
1887 struct PendingMessage *pm;
1889 if (GNUNET_YES != is_nat)
1890 GNUNET_assert (NULL != client);
1892 GNUNET_assert (NULL == client);
1894 LOG (GNUNET_ERROR_TYPE_DEBUG,
1895 "Creating new session for peer `%s' at address %s\n",
1896 GNUNET_i2s (&address->peer),
1897 tcp_plugin_address_to_string (plugin,
1899 address->address_length));
1900 session = GNUNET_new (struct GNUNET_ATS_Session);
1901 session->last_activity = GNUNET_TIME_absolute_get ();
1902 session->plugin = plugin;
1903 session->is_nat = is_nat;
1906 session->client = client;
1907 GNUNET_SERVER_client_set_user_context (client, session);
1909 session->address = GNUNET_HELLO_address_copy (address);
1910 session->target = address->peer;
1911 session->expecting_welcome = GNUNET_YES;
1912 session->scope = scope;
1913 pm = GNUNET_malloc (sizeof(struct PendingMessage)
1914 + sizeof(struct WelcomeMessage));
1915 pm->msg = (const char *) &pm[1];
1916 pm->message_size = sizeof(struct WelcomeMessage);
1917 GNUNET_memcpy (&pm[1], &plugin->my_welcome, sizeof(struct WelcomeMessage));
1918 pm->timeout = GNUNET_TIME_UNIT_FOREVER_ABS;
1919 GNUNET_STATISTICS_update (plugin->env->stats,
1920 gettext_noop ("# bytes currently in TCP buffers"),
1923 GNUNET_CONTAINER_DLL_insert (session->pending_messages_head,
1924 session->pending_messages_tail,
1926 session->msgs_in_queue++;
1927 session->bytes_in_queue += pm->message_size;
1929 GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1930 session->timeout_task =
1931 GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
1934 notify_session_monitor (session->plugin, session, GNUNET_TRANSPORT_SS_INIT);
1935 if (GNUNET_YES != is_nat)
1937 GNUNET_STATISTICS_update (plugin->env->stats,
1938 gettext_noop ("# TCP sessions active"),
1941 notify_session_monitor (session->plugin, session, GNUNET_TRANSPORT_SS_UP);
1945 notify_session_monitor (session->plugin,
1947 GNUNET_TRANSPORT_SS_HANDSHAKE);
1954 * If we have pending messages, ask the server to
1955 * transmit them (schedule the respective tasks, etc.)
1957 * @param session for which session should we do this
1960 process_pending_messages (struct GNUNET_ATS_Session *session);
1964 * Function called to notify a client about the socket
1965 * being ready to queue more data. "buf" will be
1966 * NULL and "size" zero if the socket was closed for
1967 * writing in the meantime.
1969 * @param cls closure
1970 * @param size number of bytes available in @a buf
1971 * @param buf where the callee should write the message
1972 * @return number of bytes written to @a buf
1975 do_transmit (void *cls, size_t size, void *buf)
1977 struct GNUNET_ATS_Session *session = cls;
1978 struct GNUNET_PeerIdentity pid;
1979 struct Plugin *plugin;
1980 struct PendingMessage *pos;
1981 struct PendingMessage *hd;
1982 struct PendingMessage *tl;
1983 struct GNUNET_TIME_Absolute now;
1987 session->transmit_handle = NULL;
1988 plugin = session->plugin;
1991 LOG (GNUNET_ERROR_TYPE_DEBUG,
1992 "Timeout trying to transmit to peer `%s', discarding message queue.\n",
1993 GNUNET_i2s (&session->target));
1994 /* timeout; cancel all messages that have already expired */
1998 now = GNUNET_TIME_absolute_get ();
1999 while ((NULL != (pos = session->pending_messages_head)) &&
2000 (pos->timeout.abs_value_us <= now.abs_value_us))
2002 GNUNET_CONTAINER_DLL_remove (session->pending_messages_head,
2003 session->pending_messages_tail,
2005 GNUNET_assert (0 < session->msgs_in_queue);
2006 session->msgs_in_queue--;
2007 GNUNET_assert (pos->message_size <= session->bytes_in_queue);
2008 session->bytes_in_queue -= pos->message_size;
2009 LOG (GNUNET_ERROR_TYPE_DEBUG,
2010 "Failed to transmit %u byte message to `%s'.\n",
2012 GNUNET_i2s (&session->target));
2013 ret += pos->message_size;
2014 GNUNET_CONTAINER_DLL_insert_after (hd, tl, tl, pos);
2016 /* do this call before callbacks (so that if callbacks destroy
2017 * session, they have a chance to cancel actions done by this
2019 process_pending_messages (session);
2020 pid = session->target;
2021 /* no do callbacks and do not use session again since
2022 * the callbacks may abort the session */
2023 while (NULL != (pos = hd))
2025 GNUNET_CONTAINER_DLL_remove (hd, tl, pos);
2026 if (NULL != pos->transmit_cont)
2027 pos->transmit_cont (pos->transmit_cont_cls,
2034 GNUNET_STATISTICS_update (plugin->env->stats,
2035 gettext_noop ("# bytes currently in TCP buffers"),
2038 GNUNET_STATISTICS_update (plugin->env->stats,
2040 "# bytes discarded by TCP (timeout)"),
2044 notify_session_monitor (session->plugin,
2046 GNUNET_TRANSPORT_SS_UPDATE);
2049 /* copy all pending messages that would fit */
2054 while (NULL != (pos = session->pending_messages_head))
2056 if (ret + pos->message_size > size)
2058 GNUNET_CONTAINER_DLL_remove (session->pending_messages_head,
2059 session->pending_messages_tail,
2061 GNUNET_assert (0 < session->msgs_in_queue);
2062 session->msgs_in_queue--;
2063 GNUNET_assert (pos->message_size <= session->bytes_in_queue);
2064 session->bytes_in_queue -= pos->message_size;
2065 GNUNET_assert (size >= pos->message_size);
2066 LOG (GNUNET_ERROR_TYPE_DEBUG,
2067 "Transmitting message of type %u size %u to peer %s at %s\n",
2068 ntohs (((struct GNUNET_MessageHeader *) pos->msg)->type),
2070 GNUNET_i2s (&session->target),
2071 tcp_plugin_address_to_string (session->plugin,
2072 session->address->address,
2073 session->address->address_length));
2074 /* FIXME: this GNUNET_memcpy can be up to 7% of our total runtime */
2075 GNUNET_memcpy (cbuf, pos->msg, pos->message_size);
2076 cbuf += pos->message_size;
2077 ret += pos->message_size;
2078 size -= pos->message_size;
2079 GNUNET_CONTAINER_DLL_insert_tail (hd, tl, pos);
2081 notify_session_monitor (session->plugin, session, GNUNET_TRANSPORT_SS_UPDATE);
2082 /* schedule 'continuation' before callbacks so that callbacks that
2083 * cancel everything don't cause us to use a session that no longer
2085 process_pending_messages (session);
2086 session->last_activity = GNUNET_TIME_absolute_get ();
2087 pid = session->target;
2088 /* we'll now call callbacks that may cancel the session; hence
2089 * we should not use 'session' after this point */
2090 while (NULL != (pos = hd))
2092 GNUNET_CONTAINER_DLL_remove (hd, tl, pos);
2093 if (NULL != pos->transmit_cont)
2094 pos->transmit_cont (pos->transmit_cont_cls,
2098 pos->message_size); /* FIXME: include TCP overhead */
2101 GNUNET_assert (NULL == hd);
2102 GNUNET_assert (NULL == tl);
2103 GNUNET_STATISTICS_update (plugin->env->stats,
2104 gettext_noop ("# bytes currently in TCP buffers"),
2107 GNUNET_STATISTICS_update (plugin->env->stats,
2108 gettext_noop ("# bytes transmitted via TCP"),
2116 * If we have pending messages, ask the server to
2117 * transmit them (schedule the respective tasks, etc.)
2119 * @param session for which session should we do this
2122 process_pending_messages (struct GNUNET_ATS_Session *session)
2124 struct PendingMessage *pm;
2126 GNUNET_assert (NULL != session->client);
2127 if (NULL != session->transmit_handle)
2129 if (NULL == (pm = session->pending_messages_head))
2132 session->transmit_handle =
2133 GNUNET_SERVER_notify_transmit_ready (session->client,
2135 GNUNET_TIME_absolute_get_remaining (
2143 * Function that can be used by the transport service to transmit
2144 * a message using the plugin. Note that in the case of a
2145 * peer disconnecting, the continuation MUST be called
2146 * prior to the disconnect notification itself. This function
2147 * will be called with this peer's HELLO message to initiate
2148 * a fresh connection to another peer.
2150 * @param cls closure
2151 * @param session which session must be used
2152 * @param msgbuf the message to transmit
2153 * @param msgbuf_size number of bytes in @a msgbuf
2154 * @param priority how important is the message (most plugins will
2155 * ignore message priority and just FIFO)
2156 * @param to how long to wait at most for the transmission (does not
2157 * require plugins to discard the message after the timeout,
2158 * just advisory for the desired delay; most plugins will ignore
2160 * @param cont continuation to call once the message has
2161 * been transmitted (or if the transport is ready
2162 * for the next transmission call; or if the
2163 * peer disconnected...); can be NULL
2164 * @param cont_cls closure for @a cont
2165 * @return number of bytes used (on the physical network, with overheads);
2166 * -1 on hard errors (i.e. address invalid); 0 is a legal value
2167 * and does NOT mean that the message was not transmitted (DV)
2170 tcp_plugin_send (void *cls,
2171 struct GNUNET_ATS_Session *session,
2174 unsigned int priority,
2175 struct GNUNET_TIME_Relative to,
2176 GNUNET_TRANSPORT_TransmitContinuation cont,
2179 struct Plugin *plugin = cls;
2180 struct PendingMessage *pm;
2182 /* create new message entry */
2183 pm = GNUNET_malloc (sizeof(struct PendingMessage) + msgbuf_size);
2184 pm->msg = (const char *) &pm[1];
2185 GNUNET_memcpy (&pm[1], msgbuf, msgbuf_size);
2186 pm->message_size = msgbuf_size;
2187 pm->timeout = GNUNET_TIME_relative_to_absolute (to);
2188 pm->transmit_cont = cont;
2189 pm->transmit_cont_cls = cont_cls;
2191 LOG (GNUNET_ERROR_TYPE_DEBUG,
2192 "Asked to transmit %u bytes to `%s', added message to list.\n",
2194 GNUNET_i2s (&session->target));
2197 GNUNET_CONTAINER_multipeermap_contains_value (plugin->sessionmap,
2201 GNUNET_assert (NULL != session->client);
2202 GNUNET_SERVER_client_set_timeout (session->client,
2203 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2204 GNUNET_STATISTICS_update (plugin->env->stats,
2205 gettext_noop ("# bytes currently in TCP buffers"),
2209 /* append pm to pending_messages list */
2210 GNUNET_CONTAINER_DLL_insert_tail (session->pending_messages_head,
2211 session->pending_messages_tail,
2213 notify_session_monitor (session->plugin,
2215 GNUNET_TRANSPORT_SS_UPDATE);
2216 session->msgs_in_queue++;
2217 session->bytes_in_queue += pm->message_size;
2218 process_pending_messages (session);
2222 GNUNET_CONTAINER_multipeermap_contains_value (plugin->nat_wait_conns,
2226 LOG (GNUNET_ERROR_TYPE_DEBUG,
2227 "This NAT WAIT session for peer `%s' is not yet ready!\n",
2228 GNUNET_i2s (&session->target));
2229 GNUNET_STATISTICS_update (plugin->env->stats,
2230 gettext_noop ("# bytes currently in TCP buffers"),
2233 /* append pm to pending_messages list */
2234 GNUNET_CONTAINER_DLL_insert_tail (session->pending_messages_head,
2235 session->pending_messages_tail,
2237 session->msgs_in_queue++;
2238 session->bytes_in_queue += pm->message_size;
2239 notify_session_monitor (session->plugin,
2241 GNUNET_TRANSPORT_SS_HANDSHAKE);
2244 LOG (GNUNET_ERROR_TYPE_ERROR, "Invalid session %p\n", session);
2246 cont (cont_cls, &session->target, GNUNET_SYSERR, pm->message_size, 0);
2249 return GNUNET_SYSERR; /* session does not exist here */
2254 * Closure for #session_lookup_it().
2256 struct GNUNET_ATS_SessionItCtx
2259 * Address we are looking for.
2261 const struct GNUNET_HELLO_Address *address;
2264 * Where to store the session (if we found it).
2266 struct GNUNET_ATS_Session *result;
2271 * Look for a session by address.
2273 * @param cls the `struct GNUNET_ATS_SessionItCtx`
2275 * @param value a `struct GNUNET_ATS_Session`
2276 * @return #GNUNET_YES to continue looking, #GNUNET_NO if we found the session
2279 session_lookup_it (void *cls,
2280 const struct GNUNET_PeerIdentity *key,
2283 struct GNUNET_ATS_SessionItCtx *si_ctx = cls;
2284 struct GNUNET_ATS_Session *session = value;
2286 if (0 != GNUNET_HELLO_address_cmp (si_ctx->address, session->address))
2288 si_ctx->result = session;
2294 * Task cleaning up a NAT connection attempt after timeout
2296 * @param cls the `struct GNUNET_ATS_Session`
2299 nat_connect_timeout (void *cls)
2301 struct GNUNET_ATS_Session *session = cls;
2303 session->nat_connection_timeout = NULL;
2304 LOG (GNUNET_ERROR_TYPE_DEBUG,
2305 "NAT WAIT connection to `%4s' at `%s' could not be established, removing session\n",
2306 GNUNET_i2s (&session->target),
2307 tcp_plugin_address_to_string (session->plugin,
2308 session->address->address,
2309 session->address->address_length));
2310 tcp_plugin_disconnect_session (session->plugin, session);
2315 * Function that will be called whenever the transport service wants to
2316 * notify the plugin that a session is still active and in use and
2317 * therefore the session timeout for this session has to be updated
2319 * @param cls closure
2320 * @param peer which peer was the session for
2321 * @param session which session is being updated
2324 tcp_plugin_update_session_timeout (void *cls,
2325 const struct GNUNET_PeerIdentity *peer,
2326 struct GNUNET_ATS_Session *session)
2328 reschedule_session_timeout (session);
2333 * Task to signal the server that we can continue
2334 * receiving from the TCP client now.
2336 * @param cls the `struct GNUNET_ATS_Session *`
2339 delayed_done (void *cls)
2341 struct GNUNET_ATS_Session *session = cls;
2343 session->receive_delay_task = NULL;
2344 reschedule_session_timeout (session);
2345 GNUNET_SERVER_receive_done (session->client, GNUNET_OK);
2350 * Function that will be called whenever the transport service wants to
2351 * notify the plugin that the inbound quota changed and that the plugin
2352 * should update it's delay for the next receive value
2354 * @param cls closure
2355 * @param peer which peer was the session for
2356 * @param session which session is being updated
2357 * @param delay new delay to use for receiving
2360 tcp_plugin_update_inbound_delay (void *cls,
2361 const struct GNUNET_PeerIdentity *peer,
2362 struct GNUNET_ATS_Session *session,
2363 struct GNUNET_TIME_Relative delay)
2365 if (NULL == session->receive_delay_task)
2367 LOG (GNUNET_ERROR_TYPE_DEBUG,
2368 "New inbound delay %s\n",
2369 GNUNET_STRINGS_relative_time_to_string (delay, GNUNET_NO));
2370 session->receive_delay = GNUNET_TIME_relative_to_absolute (delay);
2371 GNUNET_SCHEDULER_cancel (session->receive_delay_task);
2372 session->receive_delay_task =
2373 GNUNET_SCHEDULER_add_delayed (delay, &delayed_done, session);
2378 * Create a new session to transmit data to the target
2379 * This session will used to send data to this peer and the plugin will
2380 * notify us by calling the env->session_end function
2382 * @param cls closure
2383 * @param address the address to use
2384 * @return the session if the address is valid, NULL otherwise
2386 static struct GNUNET_ATS_Session *
2387 tcp_plugin_get_session (void *cls, const struct GNUNET_HELLO_Address *address)
2389 struct Plugin *plugin = cls;
2390 struct GNUNET_ATS_Session *session = NULL;
2394 struct GNUNET_CONNECTION_Handle *sa;
2395 struct sockaddr_in a4;
2396 struct sockaddr_in6 a6;
2397 const struct IPv4TcpAddress *t4;
2398 const struct IPv6TcpAddress *t6;
2399 unsigned int options;
2400 enum GNUNET_NetworkType net_type;
2401 unsigned int is_natd = GNUNET_NO;
2405 struct GNUNET_NETWORK_Handle *s;
2408 addrlen = address->address_length;
2409 LOG (GNUNET_ERROR_TYPE_DEBUG,
2410 "Trying to get session for `%s' address of peer `%s'\n",
2411 tcp_plugin_address_to_string (plugin,
2413 address->address_length),
2414 GNUNET_i2s (&address->peer));
2416 if (GNUNET_HELLO_address_check_option (address,
2417 GNUNET_HELLO_ADDRESS_INFO_INBOUND))
2423 /* look for existing session */
2424 if (GNUNET_YES == GNUNET_CONTAINER_multipeermap_contains (plugin->sessionmap,
2427 struct GNUNET_ATS_SessionItCtx si_ctx;
2429 si_ctx.address = address;
2430 si_ctx.result = NULL;
2431 GNUNET_CONTAINER_multipeermap_get_multiple (plugin->sessionmap,
2435 if (NULL != si_ctx.result)
2437 session = si_ctx.result;
2438 LOG (GNUNET_ERROR_TYPE_DEBUG,
2439 "Found existing session for `%s' address `%s'\n",
2440 GNUNET_i2s (&address->peer),
2441 tcp_plugin_address_to_string (plugin,
2443 address->address_length));
2446 /* This is a bit of a hack, limiting TCP to never allow more than
2447 one TCP connection to any given peer at the same time.
2448 Without this, peers sometimes disagree about which of the TCP
2449 connections they should use, causing one side to believe that
2450 they transmit successfully, while the other receives nothing. */
2451 return NULL; /* Refuse to have more than one TCP connection per
2452 peer pair at the same time. */
2455 if (addrlen == sizeof(struct IPv6TcpAddress))
2457 GNUNET_assert (NULL != address->address); /* make static analysis happy */
2458 t6 = address->address;
2459 options = t6->options;
2461 memset (&a6, 0, sizeof(a6));
2462 #if HAVE_SOCKADDR_IN_SIN_LEN
2463 a6.sin6_len = sizeof(a6);
2465 a6.sin6_family = AF_INET6;
2466 a6.sin6_port = t6->t6_port;
2467 if (t6->t6_port == 0)
2468 is_natd = GNUNET_YES;
2469 GNUNET_memcpy (&a6.sin6_addr, &t6->ipv6_addr, sizeof(struct in6_addr));
2473 else if (addrlen == sizeof(struct IPv4TcpAddress))
2475 GNUNET_assert (NULL != address->address); /* make static analysis happy */
2476 t4 = address->address;
2477 options = t4->options;
2479 memset (&a4, 0, sizeof(a4));
2480 #if HAVE_SOCKADDR_IN_SIN_LEN
2481 a4.sin_len = sizeof(a4);
2483 a4.sin_family = AF_INET;
2484 a4.sin_port = t4->t4_port;
2485 if (t4->t4_port == 0)
2486 is_natd = GNUNET_YES;
2487 a4.sin_addr.s_addr = t4->ipv4_addr;
2493 GNUNET_STATISTICS_update (
2495 gettext_noop ("# requests to create session with invalid address"),
2501 net_type = plugin->env->get_address_type (plugin->env->cls, sb, sbs);
2502 GNUNET_break (net_type != GNUNET_NT_UNSPECIFIED);
2504 if ((is_natd == GNUNET_YES) && (addrlen == sizeof(struct IPv6TcpAddress)))
2506 /* NAT client only works with IPv4 addresses */
2510 if (plugin->cur_connections >= plugin->max_connections)
2516 if ((is_natd == GNUNET_YES) &&
2518 GNUNET_CONTAINER_multipeermap_contains (plugin->nat_wait_conns,
2521 /* Only do one NAT punch attempt per peer identity */
2525 if ((is_natd == GNUNET_YES) && (NULL != plugin->nat) &&
2527 GNUNET_CONTAINER_multipeermap_contains (plugin->nat_wait_conns,
2530 struct sockaddr_in local_sa;
2532 LOG (GNUNET_ERROR_TYPE_DEBUG,
2533 "Found valid IPv4 NAT address (creating session)!\n");
2534 session = create_session (plugin, address, net_type, NULL, GNUNET_YES);
2535 session->nat_connection_timeout =
2536 GNUNET_SCHEDULER_add_delayed (NAT_TIMEOUT, &nat_connect_timeout, session);
2537 GNUNET_assert (GNUNET_OK ==
2538 GNUNET_CONTAINER_multipeermap_put (
2539 plugin->nat_wait_conns,
2542 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
2544 LOG (GNUNET_ERROR_TYPE_DEBUG,
2545 "Created NAT WAIT connection to `%s' at `%s'\n",
2546 GNUNET_i2s (&session->target),
2547 GNUNET_a2s (sb, sbs));
2548 memset (&local_sa, 0, sizeof(local_sa));
2549 local_sa.sin_family = AF_INET;
2550 local_sa.sin_port = htons (plugin->open_port);
2551 /* We leave sin_address at 0, let the kernel figure it out,
2552 even if our bind() is more specific. (May want to reconsider
2554 if (GNUNET_OK == GNUNET_NAT_request_reversal (plugin->nat, &local_sa, &a4))
2556 LOG (GNUNET_ERROR_TYPE_DEBUG,
2557 "Running NAT client for `%s' at `%s' failed\n",
2558 GNUNET_i2s (&session->target),
2559 GNUNET_a2s (sb, sbs));
2560 tcp_plugin_disconnect_session (plugin, session);
2564 /* create new outbound session */
2565 if (0 != (options & TCP_OPTIONS_TCP_STEALTH))
2568 s = GNUNET_NETWORK_socket_create (af, SOCK_STREAM, 0);
2571 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK,
2578 GNUNET_NETWORK_socket_setsockopt (s,
2583 struct GNUNET_PeerIdentity))) ||
2585 GNUNET_NETWORK_socket_setsockopt (s,
2587 TCP_STEALTH_INTEGRITY,
2588 &plugin->my_welcome,
2589 sizeof(struct WelcomeMessage))))
2591 /* TCP STEALTH not supported by kernel */
2592 GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (s));
2597 sa = GNUNET_CONNECTION_connect_socket (s, sb, sbs);
2606 sa = GNUNET_CONNECTION_create_from_sockaddr (af, sb, sbs);
2610 LOG (GNUNET_ERROR_TYPE_DEBUG,
2611 "Failed to create connection to `%s' at `%s'\n",
2612 GNUNET_i2s (&address->peer),
2613 GNUNET_a2s (sb, sbs));
2616 LOG (GNUNET_ERROR_TYPE_DEBUG,
2617 "Asked to transmit to `%s', creating fresh session using address `%s'.\n",
2618 GNUNET_i2s (&address->peer),
2619 GNUNET_a2s (sb, sbs));
2621 session = create_session (plugin,
2624 GNUNET_SERVER_connect_socket (plugin->server, sa),
2626 (void) GNUNET_CONTAINER_multipeermap_put (
2630 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
2631 /* Send TCP Welcome */
2632 process_pending_messages (session);
2639 * We have been asked to destroy all connections to a particular peer.
2640 * This function is called on each applicable session and must tear it
2643 * @param cls the `struct Plugin *`
2644 * @param key the peer which the session belongs to (unused)
2645 * @param value the `struct GNUNET_ATS_Session`
2646 * @return #GNUNET_YES (continue to iterate)
2649 session_disconnect_it (void *cls,
2650 const struct GNUNET_PeerIdentity *key,
2653 struct Plugin *plugin = cls;
2654 struct GNUNET_ATS_Session *session = value;
2656 GNUNET_STATISTICS_update (session->plugin->env->stats,
2658 "# transport-service disconnect requests for TCP"),
2661 tcp_plugin_disconnect_session (plugin, session);
2667 * Function that can be called to force a disconnect from the
2668 * specified neighbour. This should also cancel all previously
2669 * scheduled transmissions. Obviously the transmission may have been
2670 * partially completed already, which is OK. The plugin is supposed
2671 * to close the connection (if applicable) and no longer call the
2672 * transmit continuation(s).
2674 * Finally, plugin MUST NOT call the services's receive function to
2675 * notify the service that the connection to the specified target was
2676 * closed after a getting this call.
2678 * @param cls closure
2679 * @param target peer for which the last transmission is
2683 tcp_plugin_disconnect (void *cls, const struct GNUNET_PeerIdentity *target)
2685 struct Plugin *plugin = cls;
2687 LOG (GNUNET_ERROR_TYPE_DEBUG,
2688 "Disconnecting peer `%s'\n",
2689 GNUNET_i2s (target));
2690 GNUNET_CONTAINER_multipeermap_get_multiple (plugin->sessionmap,
2692 &session_disconnect_it,
2694 GNUNET_CONTAINER_multipeermap_get_multiple (plugin->nat_wait_conns,
2696 &session_disconnect_it,
2702 * We are processing an address pretty printing request and finished
2703 * the IP resolution (if applicable). Append our port and forward the
2704 * result. If called with @a hostname NULL, we are done and should
2705 * clean up the pretty printer (otherwise, there might be multiple
2706 * hostnames for the IP address and we might receive more).
2708 * @param cls the `struct PrettyPrinterContext *`
2709 * @param hostname hostname part of the address
2712 append_port (void *cls, const char *hostname)
2714 struct PrettyPrinterContext *ppc = cls;
2715 struct Plugin *plugin = ppc->plugin;
2718 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2719 "append_port called with hostname `%s'\n",
2721 if (NULL == hostname)
2723 /* Final call, done */
2724 ppc->resolver_handle = NULL;
2725 GNUNET_CONTAINER_DLL_remove (plugin->ppc_dll_head,
2726 plugin->ppc_dll_tail,
2728 ppc->asc (ppc->asc_cls, NULL, GNUNET_OK);
2732 if (GNUNET_YES == ppc->ipv6)
2733 GNUNET_asprintf (&ret,
2740 GNUNET_asprintf (&ret,
2746 ppc->asc (ppc->asc_cls, ret, GNUNET_OK);
2752 * Convert the transports address to a nice, human-readable format.
2754 * @param cls closure with the `struct Plugin`
2755 * @param type name of the transport that generated the address
2756 * @param addr one of the addresses of the host, NULL for the last address
2757 * the specific address format depends on the transport
2758 * @param addrlen length of the @a addr
2759 * @param numeric should (IP) addresses be displayed in numeric form?
2760 * @param timeout after how long should we give up?
2761 * @param asc function to call on each string
2762 * @param asc_cls closure for @a asc
2765 tcp_plugin_address_pretty_printer (void *cls,
2770 struct GNUNET_TIME_Relative timeout,
2771 GNUNET_TRANSPORT_AddressStringCallback asc,
2774 struct Plugin *plugin = cls;
2775 struct PrettyPrinterContext *ppc;
2778 struct sockaddr_in a4;
2779 struct sockaddr_in6 a6;
2780 const struct IPv4TcpAddress *t4;
2781 const struct IPv6TcpAddress *t6;
2785 if (sizeof(struct IPv6TcpAddress) == addrlen)
2788 memset (&a6, 0, sizeof(a6));
2789 a6.sin6_family = AF_INET6;
2790 a6.sin6_port = t6->t6_port;
2791 GNUNET_memcpy (&a6.sin6_addr, &t6->ipv6_addr, sizeof(struct in6_addr));
2792 port = ntohs (t6->t6_port);
2793 options = ntohl (t6->options);
2797 else if (sizeof(struct IPv4TcpAddress) == addrlen)
2800 memset (&a4, 0, sizeof(a4));
2801 a4.sin_family = AF_INET;
2802 a4.sin_port = t4->t4_port;
2803 a4.sin_addr.s_addr = t4->ipv4_addr;
2804 port = ntohs (t4->t4_port);
2805 options = ntohl (t4->options);
2811 /* invalid address */
2812 LOG (GNUNET_ERROR_TYPE_WARNING,
2813 _ ("Unexpected address length: %u bytes\n"),
2814 (unsigned int) addrlen);
2815 asc (asc_cls, NULL, GNUNET_SYSERR);
2816 asc (asc_cls, NULL, GNUNET_OK);
2819 ppc = GNUNET_new (struct PrettyPrinterContext);
2820 ppc->plugin = plugin;
2821 if (addrlen == sizeof(struct IPv6TcpAddress))
2822 ppc->ipv6 = GNUNET_YES;
2824 ppc->ipv6 = GNUNET_NO;
2826 ppc->asc_cls = asc_cls;
2828 ppc->options = options;
2829 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting DNS reverse lookup\n");
2830 ppc->resolver_handle = GNUNET_RESOLVER_hostname_get (sb,
2836 if (NULL == ppc->resolver_handle)
2842 GNUNET_CONTAINER_DLL_insert (plugin->ppc_dll_head, plugin->ppc_dll_tail, ppc);
2847 * Function that will be called to check if a binary address for this
2848 * plugin is well-formed and corresponds to an address for THIS peer
2849 * (as per our configuration). Naturally, if absolutely necessary,
2850 * plugins can be a bit conservative in their answer, but in general
2851 * plugins should make sure that the address does not redirect
2852 * traffic to a 3rd party that might try to man-in-the-middle our
2855 * @param cls closure, our `struct Plugin *`
2856 * @param addr pointer to the address
2857 * @param addrlen length of @a addr
2858 * @return #GNUNET_OK if this is a plausible address for this peer
2859 * and transport, #GNUNET_SYSERR if not
2862 tcp_plugin_check_address (void *cls, const void *addr, size_t addrlen)
2864 struct Plugin *plugin = cls;
2865 const struct IPv4TcpAddress *v4;
2866 const struct IPv6TcpAddress *v6;
2868 if ((addrlen != sizeof(struct IPv4TcpAddress)) &&
2869 (addrlen != sizeof(struct IPv6TcpAddress)))
2871 GNUNET_break_op (0);
2872 return GNUNET_SYSERR;
2875 if (addrlen == sizeof(struct IPv4TcpAddress))
2877 struct sockaddr_in s4;
2879 v4 = (const struct IPv4TcpAddress *) addr;
2880 if (0 != memcmp (&v4->options, &plugin->myoptions, sizeof(uint32_t)))
2883 return GNUNET_SYSERR;
2885 memset (&s4, 0, sizeof(s4));
2886 s4.sin_family = AF_INET;
2887 #if HAVE_SOCKADDR_IN_SIN_LEN
2888 s4.sin_len = sizeof(s4);
2890 s4.sin_port = v4->t4_port;
2891 s4.sin_addr.s_addr = v4->ipv4_addr;
2894 GNUNET_NAT_test_address (plugin->nat, &s4, sizeof(struct sockaddr_in)))
2895 return GNUNET_SYSERR;
2899 struct sockaddr_in6 s6;
2901 v6 = (const struct IPv6TcpAddress *) addr;
2902 if (IN6_IS_ADDR_LINKLOCAL (&v6->ipv6_addr))
2904 GNUNET_break_op (0);
2905 return GNUNET_SYSERR;
2907 if (0 != memcmp (&v6->options, &plugin->myoptions, sizeof(uint32_t)))
2910 return GNUNET_SYSERR;
2912 memset (&s6, 0, sizeof(s6));
2913 s6.sin6_family = AF_INET6;
2914 #if HAVE_SOCKADDR_IN_SIN_LEN
2915 s6.sin6_len = sizeof(s6);
2917 s6.sin6_port = v6->t6_port;
2918 s6.sin6_addr = v6->ipv6_addr;
2920 if (GNUNET_OK != GNUNET_NAT_test_address (plugin->nat,
2922 sizeof(struct sockaddr_in6)))
2923 return GNUNET_SYSERR;
2930 * We've received a nat probe from this peer via TCP. Finish
2931 * creating the client session and resume sending of queued
2934 * @param cls closure
2935 * @param client identification of the client
2936 * @param message the actual message
2939 handle_tcp_nat_probe (void *cls,
2940 struct GNUNET_SERVER_Client *client,
2941 const struct GNUNET_MessageHeader *message)
2943 struct Plugin *plugin = cls;
2944 struct GNUNET_ATS_Session *session;
2945 const struct TCP_NAT_ProbeMessage *tcp_nat_probe;
2948 struct IPv4TcpAddress *t4;
2949 struct IPv6TcpAddress *t6;
2950 const struct sockaddr_in *s4;
2951 const struct sockaddr_in6 *s6;
2953 LOG (GNUNET_ERROR_TYPE_DEBUG, "Received NAT probe\n");
2954 /* We have received a TCP NAT probe, meaning we (hopefully) initiated
2955 * a connection to this peer by running gnunet-nat-client. This peer
2956 * received the punch message and now wants us to use the new connection
2957 * as the default for that peer. Do so and then send a WELCOME message
2958 * so we can really be connected!
2960 if (ntohs (message->size) != sizeof(struct TCP_NAT_ProbeMessage))
2962 GNUNET_break_op (0);
2963 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2967 tcp_nat_probe = (const struct TCP_NAT_ProbeMessage *) message;
2968 if (0 == memcmp (&tcp_nat_probe->clientIdentity,
2969 plugin->env->my_identity,
2970 sizeof(struct GNUNET_PeerIdentity)))
2972 /* refuse connections from ourselves */
2973 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2977 session = GNUNET_CONTAINER_multipeermap_get (plugin->nat_wait_conns,
2978 &tcp_nat_probe->clientIdentity);
2979 if (NULL == session)
2981 LOG (GNUNET_ERROR_TYPE_DEBUG, "Did NOT find session for NAT probe!\n");
2982 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2985 LOG (GNUNET_ERROR_TYPE_DEBUG, "Found session for NAT probe!\n");
2987 if (NULL != session->nat_connection_timeout)
2989 GNUNET_SCHEDULER_cancel (session->nat_connection_timeout);
2990 session->nat_connection_timeout = NULL;
2993 if (GNUNET_OK != GNUNET_SERVER_client_get_address (client, &vaddr, &alen))
2996 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2997 tcp_plugin_disconnect_session (plugin, session);
3002 GNUNET_CONTAINER_multipeermap_remove (plugin->nat_wait_conns,
3003 &tcp_nat_probe->clientIdentity,
3005 GNUNET_SERVER_client_set_user_context (client, session);
3006 (void) GNUNET_CONTAINER_multipeermap_put (
3010 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
3011 session->last_activity = GNUNET_TIME_absolute_get ();
3012 LOG (GNUNET_ERROR_TYPE_DEBUG,
3013 "Found address `%s' for incoming connection\n",
3014 GNUNET_a2s (vaddr, alen));
3015 switch (((const struct sockaddr *) vaddr)->sa_family)
3019 t4 = GNUNET_new (struct IPv4TcpAddress);
3020 t4->options = htonl (TCP_OPTIONS_NONE);
3021 t4->t4_port = s4->sin_port;
3022 t4->ipv4_addr = s4->sin_addr.s_addr;
3024 GNUNET_HELLO_address_allocate (&tcp_nat_probe->clientIdentity,
3027 sizeof(struct IPv4TcpAddress),
3028 GNUNET_HELLO_ADDRESS_INFO_NONE);
3033 t6 = GNUNET_new (struct IPv6TcpAddress);
3034 t6->options = htonl (TCP_OPTIONS_NONE);
3035 t6->t6_port = s6->sin6_port;
3036 GNUNET_memcpy (&t6->ipv6_addr, &s6->sin6_addr, sizeof(struct in6_addr));
3038 GNUNET_HELLO_address_allocate (&tcp_nat_probe->clientIdentity,
3041 sizeof(struct IPv6TcpAddress),
3042 GNUNET_HELLO_ADDRESS_INFO_NONE);
3046 GNUNET_break_op (0);
3047 LOG (GNUNET_ERROR_TYPE_DEBUG, "Bad address for incoming connection!\n");
3048 GNUNET_free (vaddr);
3049 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3050 tcp_plugin_disconnect_session (plugin, session);
3053 GNUNET_free (vaddr);
3054 GNUNET_break (NULL == session->client);
3055 session->client = client;
3056 GNUNET_STATISTICS_update (plugin->env->stats,
3057 gettext_noop ("# TCP sessions active"),
3060 process_pending_messages (session);
3061 GNUNET_SERVER_receive_done (client, GNUNET_OK);
3066 * We've received a welcome from this peer via TCP. Possibly create a
3067 * fresh client record and send back our welcome.
3069 * @param cls closure
3070 * @param client identification of the client
3071 * @param message the actual message
3074 handle_tcp_welcome (void *cls,
3075 struct GNUNET_SERVER_Client *client,
3076 const struct GNUNET_MessageHeader *message)
3078 struct Plugin *plugin = cls;
3079 const struct WelcomeMessage *wm = (const struct WelcomeMessage *) message;
3080 struct GNUNET_HELLO_Address *address;
3081 struct GNUNET_ATS_Session *session;
3084 struct IPv4TcpAddress t4;
3085 struct IPv6TcpAddress t6;
3086 const struct sockaddr_in *s4;
3087 const struct sockaddr_in6 *s6;
3089 if (0 == memcmp (&wm->clientIdentity,
3090 plugin->env->my_identity,
3091 sizeof(struct GNUNET_PeerIdentity)))
3093 /* refuse connections from ourselves */
3094 if (GNUNET_OK == GNUNET_SERVER_client_get_address (client, &vaddr, &alen))
3096 LOG (GNUNET_ERROR_TYPE_INFO,
3097 "Received WELCOME message from my own identity `%s' on address `%s'\n",
3098 GNUNET_i2s (&wm->clientIdentity),
3099 GNUNET_a2s (vaddr, alen));
3100 GNUNET_free (vaddr);
3102 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3106 if (GNUNET_OK == GNUNET_SERVER_client_get_address (client, &vaddr, &alen))
3108 LOG (GNUNET_ERROR_TYPE_DEBUG,
3109 "Received WELCOME message from `%s' on address `%s'\n",
3110 GNUNET_i2s (&wm->clientIdentity),
3111 GNUNET_a2s (vaddr, alen));
3112 GNUNET_free (vaddr);
3114 GNUNET_STATISTICS_update (plugin->env->stats,
3115 gettext_noop ("# TCP WELCOME messages received"),
3118 session = lookup_session_by_client (plugin, client);
3119 if (NULL != session)
3121 if (GNUNET_OK == GNUNET_SERVER_client_get_address (client, &vaddr, &alen))
3123 LOG (GNUNET_ERROR_TYPE_DEBUG,
3124 "Found existing session %p for peer `%s'\n",
3126 GNUNET_a2s (vaddr, alen));
3127 GNUNET_free (vaddr);
3132 if (GNUNET_OK == GNUNET_SERVER_client_get_address (client, &vaddr, &alen))
3134 if (alen == sizeof(struct sockaddr_in))
3137 memset (&t4, '\0', sizeof(t4));
3138 t4.options = htonl (TCP_OPTIONS_NONE);
3139 t4.t4_port = s4->sin_port;
3140 t4.ipv4_addr = s4->sin_addr.s_addr;
3142 GNUNET_HELLO_address_allocate (&wm->clientIdentity,
3146 GNUNET_HELLO_ADDRESS_INFO_INBOUND);
3148 else if (alen == sizeof(struct sockaddr_in6))
3151 memset (&t6, '\0', sizeof(t6));
3152 t6.options = htonl (TCP_OPTIONS_NONE);
3153 t6.t6_port = s6->sin6_port;
3154 GNUNET_memcpy (&t6.ipv6_addr, &s6->sin6_addr, sizeof(struct in6_addr));
3156 GNUNET_HELLO_address_allocate (&wm->clientIdentity,
3160 GNUNET_HELLO_ADDRESS_INFO_INBOUND);
3165 GNUNET_free_non_null (vaddr);
3166 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3169 session = create_session (plugin,
3171 plugin->env->get_address_type (plugin->env->cls,
3176 GNUNET_break (GNUNET_NT_UNSPECIFIED != session->scope);
3177 GNUNET_HELLO_address_free (address);
3178 LOG (GNUNET_ERROR_TYPE_DEBUG,
3179 "Creating new%s session %p for peer `%s' client %p\n",
3180 GNUNET_HELLO_address_check_option (session->address,
3181 GNUNET_HELLO_ADDRESS_INFO_INBOUND)
3185 tcp_plugin_address_to_string (plugin,
3186 session->address->address,
3187 session->address->address_length),
3189 GNUNET_free (vaddr);
3190 (void) GNUNET_CONTAINER_multipeermap_put (
3194 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
3195 /* Notify transport and ATS about new session */
3196 plugin->env->session_start (plugin->env->cls,
3203 LOG (GNUNET_ERROR_TYPE_DEBUG,
3204 "Did not obtain TCP socket address for incoming connection\n");
3206 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3211 if (GNUNET_YES != session->expecting_welcome)
3213 GNUNET_break_op (0);
3214 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3217 session->last_activity = GNUNET_TIME_absolute_get ();
3218 session->expecting_welcome = GNUNET_NO;
3220 process_pending_messages (session);
3221 GNUNET_SERVER_client_set_timeout (client,
3222 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
3223 GNUNET_SERVER_receive_done (client, GNUNET_OK);
3228 * We've received data for this peer via TCP. Unbox,
3229 * compute latency and forward.
3231 * @param cls closure
3232 * @param client identification of the client
3233 * @param message the actual message
3236 handle_tcp_data (void *cls,
3237 struct GNUNET_SERVER_Client *client,
3238 const struct GNUNET_MessageHeader *message)
3240 struct Plugin *plugin = cls;
3241 struct GNUNET_ATS_Session *session;
3242 struct GNUNET_TIME_Relative delay;
3245 type = ntohs (message->type);
3246 if ((GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_WELCOME == type) ||
3247 (GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_NAT_PROBE == type))
3249 /* We don't want to propagate WELCOME and NAT Probe messages up! */
3250 GNUNET_SERVER_receive_done (client, GNUNET_OK);
3253 session = lookup_session_by_client (plugin, client);
3254 if (NULL == session)
3256 /* No inbound session found */
3260 GNUNET_assert (GNUNET_OK ==
3261 GNUNET_SERVER_client_get_address (client, &vaddr, &alen));
3262 LOG (GNUNET_ERROR_TYPE_ERROR,
3263 "Received unexpected %u bytes of type %u from `%s'\n",
3264 (unsigned int) ntohs (message->size),
3265 (unsigned int) ntohs (message->type),
3266 GNUNET_a2s (vaddr, alen));
3267 GNUNET_break_op (0);
3268 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3269 GNUNET_free_non_null (vaddr);
3272 if (GNUNET_YES == session->expecting_welcome)
3274 /* Session is expecting WELCOME message */
3278 GNUNET_SERVER_client_get_address (client, &vaddr, &alen);
3279 LOG (GNUNET_ERROR_TYPE_ERROR,
3280 "Received unexpected %u bytes of type %u from `%s'\n",
3281 (unsigned int) ntohs (message->size),
3282 (unsigned int) ntohs (message->type),
3283 GNUNET_a2s (vaddr, alen));
3284 GNUNET_break_op (0);
3285 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3286 GNUNET_free_non_null (vaddr);
3290 session->last_activity = GNUNET_TIME_absolute_get ();
3295 GNUNET_SERVER_client_get_address (client, &vaddr, &alen);
3296 LOG (GNUNET_ERROR_TYPE_DEBUG,
3297 "Passing %u bytes of type %u from `%s' at %s to transport service.\n",
3298 (unsigned int) ntohs (message->size),
3299 (unsigned int) ntohs (message->type),
3300 GNUNET_i2s (&session->target),
3301 GNUNET_a2s (vaddr, alen));
3302 GNUNET_free_non_null (vaddr);
3305 GNUNET_STATISTICS_update (plugin->env->stats,
3306 gettext_noop ("# bytes received via TCP"),
3307 ntohs (message->size),
3311 GNUNET_CONTAINER_multipeermap_contains_value (plugin->sessionmap,
3315 plugin->env->receive (plugin->env->cls, session->address, session, message);
3316 reschedule_session_timeout (session);
3317 if (0 == delay.rel_value_us)
3319 GNUNET_SERVER_receive_done (client, GNUNET_OK);
3323 LOG (GNUNET_ERROR_TYPE_DEBUG,
3324 "Throttling receiving from `%s' for %s\n",
3325 GNUNET_i2s (&session->target),
3326 GNUNET_STRINGS_relative_time_to_string (delay, GNUNET_YES));
3327 GNUNET_SERVER_disable_receive_done_warning (client);
3328 GNUNET_assert (NULL == session->receive_delay_task);
3329 session->receive_delay_task =
3330 GNUNET_SCHEDULER_add_delayed (delay, &delayed_done, session);
3336 * Function called whenever a peer is connected on the "SERVER" level.
3337 * Increments number of active connections and suspends server if we
3338 * have reached the limit.
3340 * @param cls closure
3341 * @param client identification of the client
3344 connect_notify (void *cls, struct GNUNET_SERVER_Client *client)
3346 struct Plugin *plugin = cls;
3350 plugin->cur_connections++;
3351 GNUNET_STATISTICS_set (plugin->env->stats,
3352 gettext_noop ("# TCP server connections active"),
3353 plugin->cur_connections,
3355 GNUNET_STATISTICS_update (plugin->env->stats,
3356 gettext_noop ("# TCP server connect events"),
3359 if (plugin->cur_connections != plugin->max_connections)
3361 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3362 _ ("TCP connection limit reached, suspending server\n"));
3363 GNUNET_STATISTICS_update (plugin->env->stats,
3364 gettext_noop ("# TCP service suspended"),
3367 GNUNET_SERVER_suspend (
3368 plugin->server); /* Maximum number of connections rechead */
3373 * Function called whenever a peer is disconnected on the "SERVER"
3374 * level. Cleans up the connection, decrements number of active
3375 * connections and if applicable resumes listening.
3377 * @param cls closure
3378 * @param client identification of the client
3381 disconnect_notify (void *cls, struct GNUNET_SERVER_Client *client)
3383 struct Plugin *plugin = cls;
3384 struct GNUNET_ATS_Session *session;
3388 GNUNET_assert (plugin->cur_connections >= 1);
3389 plugin->cur_connections--;
3390 session = lookup_session_by_client (plugin, client);
3391 if (NULL == session)
3392 return; /* unknown, nothing to do */
3393 LOG (GNUNET_ERROR_TYPE_DEBUG,
3394 "Destroying session of `%s' with %s due to network-level disconnect.\n",
3395 GNUNET_i2s (&session->target),
3396 tcp_plugin_address_to_string (session->plugin,
3397 session->address->address,
3398 session->address->address_length));
3400 if (plugin->cur_connections == plugin->max_connections)
3402 GNUNET_STATISTICS_update (session->plugin->env->stats,
3403 gettext_noop ("# TCP service resumed"),
3406 GNUNET_SERVER_resume (plugin->server); /* Resume server */
3408 GNUNET_STATISTICS_set (plugin->env->stats,
3409 gettext_noop ("# TCP server connections active"),
3410 plugin->cur_connections,
3412 GNUNET_STATISTICS_update (session->plugin->env->stats,
3414 "# network-level TCP disconnect events"),
3417 tcp_plugin_disconnect_session (plugin, session);
3422 * We can now send a probe message, copy into buffer to really send.
3424 * @param cls closure, a `struct TCPProbeContext`
3425 * @param size max size to copy
3426 * @param buf buffer to copy message to
3427 * @return number of bytes copied into @a buf
3430 notify_send_probe (void *cls, size_t size, void *buf)
3432 struct TCPProbeContext *tcp_probe_ctx = cls;
3433 struct Plugin *plugin = tcp_probe_ctx->plugin;
3436 tcp_probe_ctx->transmit_handle = NULL;
3437 GNUNET_CONTAINER_DLL_remove (plugin->probe_head,
3442 GNUNET_CONNECTION_destroy (tcp_probe_ctx->sock);
3443 GNUNET_free (tcp_probe_ctx);
3446 GNUNET_assert (size >= sizeof(tcp_probe_ctx->message));
3447 GNUNET_memcpy (buf, &tcp_probe_ctx->message, sizeof(tcp_probe_ctx->message));
3448 GNUNET_SERVER_connect_socket (tcp_probe_ctx->plugin->server,
3449 tcp_probe_ctx->sock);
3450 ret = sizeof(tcp_probe_ctx->message);
3451 GNUNET_free (tcp_probe_ctx);
3457 * Function called by the NAT subsystem suggesting another peer wants
3458 * to connect to us via connection reversal. Try to connect back to the
3461 * @param cls closure
3462 * @param addr address to try
3463 * @param addrlen number of bytes in @a addr
3466 try_connection_reversal (void *cls,
3467 const struct sockaddr *addr,
3470 struct Plugin *plugin = cls;
3471 struct GNUNET_CONNECTION_Handle *sock;
3472 struct TCPProbeContext *tcp_probe_ctx;
3475 * We have received an ICMP response, ostensibly from a peer
3476 * that wants to connect to us! Send a message to establish a connection.
3478 sock = GNUNET_CONNECTION_create_from_sockaddr (AF_INET, addr, addrlen);
3481 /* failed for some odd reason (out of sockets?); ignore attempt */
3485 tcp_probe_ctx = GNUNET_new (struct TCPProbeContext);
3486 tcp_probe_ctx->message.header.size =
3487 htons (sizeof(struct TCP_NAT_ProbeMessage));
3488 tcp_probe_ctx->message.header.type =
3489 htons (GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_NAT_PROBE);
3490 tcp_probe_ctx->message.clientIdentity = *plugin->env->my_identity;
3491 tcp_probe_ctx->plugin = plugin;
3492 tcp_probe_ctx->sock = sock;
3493 GNUNET_CONTAINER_DLL_insert (plugin->probe_head,
3496 tcp_probe_ctx->transmit_handle =
3497 GNUNET_CONNECTION_notify_transmit_ready (sock,
3498 ntohs (tcp_probe_ctx->message
3500 GNUNET_TIME_UNIT_FOREVER_REL,
3507 * Function obtain the network type for a session
3509 * @param cls closure (`struct Plugin *`)
3510 * @param session the session
3511 * @return the network type in HBO or #GNUNET_SYSERR
3513 static enum GNUNET_NetworkType
3514 tcp_plugin_get_network (void *cls, struct GNUNET_ATS_Session *session)
3516 return session->scope;
3521 * Function obtain the network type for an address.
3523 * @param cls closure (`struct Plugin *`)
3524 * @param address the address
3525 * @return the network type
3527 static enum GNUNET_NetworkType
3528 tcp_plugin_get_network_for_address (void *cls,
3529 const struct GNUNET_HELLO_Address *address)
3531 struct Plugin *plugin = cls;
3533 struct sockaddr_in a4;
3534 struct sockaddr_in6 a6;
3535 const struct IPv4TcpAddress *t4;
3536 const struct IPv6TcpAddress *t6;
3540 addrlen = address->address_length;
3541 if (addrlen == sizeof(struct IPv6TcpAddress))
3543 GNUNET_assert (NULL != address->address); /* make static analysis happy */
3544 t6 = address->address;
3545 memset (&a6, 0, sizeof(a6));
3546 #if HAVE_SOCKADDR_IN_SIN_LEN
3547 a6.sin6_len = sizeof(a6);
3549 a6.sin6_family = AF_INET6;
3550 a6.sin6_port = t6->t6_port;
3551 GNUNET_memcpy (&a6.sin6_addr, &t6->ipv6_addr, sizeof(struct in6_addr));
3555 else if (addrlen == sizeof(struct IPv4TcpAddress))
3557 GNUNET_assert (NULL != address->address); /* make static analysis happy */
3558 t4 = address->address;
3559 memset (&a4, 0, sizeof(a4));
3560 #if HAVE_SOCKADDR_IN_SIN_LEN
3561 a4.sin_len = sizeof(a4);
3563 a4.sin_family = AF_INET;
3564 a4.sin_port = t4->t4_port;
3565 a4.sin_addr.s_addr = t4->ipv4_addr;
3572 return GNUNET_NT_UNSPECIFIED;
3574 return plugin->env->get_address_type (plugin->env->cls, sb, sbs);
3579 * Return information about the given session to the
3582 * @param cls the `struct Plugin` with the monitor callback (`sic`)
3583 * @param peer peer we send information about
3584 * @param value our `struct GNUNET_ATS_Session` to send information about
3585 * @return #GNUNET_OK (continue to iterate)
3588 send_session_info_iter (void *cls,
3589 const struct GNUNET_PeerIdentity *peer,
3592 struct Plugin *plugin = cls;
3593 struct GNUNET_ATS_Session *session = value;
3595 notify_session_monitor (plugin, session, GNUNET_TRANSPORT_SS_INIT);
3596 /* FIXME: cannot tell if this is up or not from current
3598 notify_session_monitor (plugin, session, GNUNET_TRANSPORT_SS_UP);
3604 * Begin monitoring sessions of a plugin. There can only
3605 * be one active monitor per plugin (i.e. if there are
3606 * multiple monitors, the transport service needs to
3607 * multiplex the generated events over all of them).
3609 * @param cls closure of the plugin
3610 * @param sic callback to invoke, NULL to disable monitor;
3611 * plugin will being by iterating over all active
3612 * sessions immediately and then enter monitor mode
3613 * @param sic_cls closure for @a sic
3616 tcp_plugin_setup_monitor (void *cls,
3617 GNUNET_TRANSPORT_SessionInfoCallback sic,
3620 struct Plugin *plugin = cls;
3623 plugin->sic_cls = sic_cls;
3626 GNUNET_CONTAINER_multipeermap_iterate (plugin->sessionmap,
3627 &send_session_info_iter,
3629 /* signal end of first iteration */
3630 sic (sic_cls, NULL, NULL);
3636 * Entry point for the plugin.
3638 * @param cls closure, the `struct GNUNET_TRANSPORT_PluginEnvironment *`
3639 * @return the `struct GNUNET_TRANSPORT_PluginFunctions *` or NULL on error
3642 libgnunet_plugin_transport_tcp_init (void *cls)
3644 static const struct GNUNET_SERVER_MessageHandler my_handlers[] =
3645 { { &handle_tcp_welcome,
3647 GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_WELCOME,
3648 sizeof(struct WelcomeMessage) },
3649 { &handle_tcp_nat_probe,
3651 GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_NAT_PROBE,
3652 sizeof(struct TCP_NAT_ProbeMessage) },
3653 { &handle_tcp_data, NULL, GNUNET_MESSAGE_TYPE_ALL, 0 },
3654 { NULL, NULL, 0, 0 } };
3655 struct GNUNET_TRANSPORT_PluginEnvironment *env = cls;
3656 struct GNUNET_TRANSPORT_PluginFunctions *api;
3657 struct Plugin *plugin;
3658 struct LEGACY_SERVICE_Context *service;
3659 unsigned long long aport;
3660 unsigned long long bport;
3661 unsigned long long max_connections;
3663 struct GNUNET_TIME_Relative idle_timeout;
3666 struct GNUNET_NETWORK_Handle *const *lsocks;
3670 struct sockaddr **addrs;
3671 socklen_t *addrlens;
3673 if (NULL == env->receive)
3675 /* run in 'stub' mode (i.e. as part of gnunet-peerinfo), don't fully
3676 initialze the plugin or the API */
3677 api = GNUNET_new (struct GNUNET_TRANSPORT_PluginFunctions);
3679 api->address_pretty_printer = &tcp_plugin_address_pretty_printer;
3680 api->address_to_string = &tcp_plugin_address_to_string;
3681 api->string_to_address = &tcp_plugin_string_to_address;
3685 GNUNET_assert (NULL != env->cfg);
3686 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (env->cfg,
3690 max_connections = 128;
3693 if ((GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (env->cfg,
3698 ((GNUNET_OK == GNUNET_CONFIGURATION_get_value_number (env->cfg,
3704 LOG (GNUNET_ERROR_TYPE_ERROR,
3705 _ ("Require valid port number for service `%s' in configuration!\n"),
3715 service = LEGACY_SERVICE_start ("transport-tcp",
3717 LEGACY_SERVICE_OPTION_NONE);
3718 if (NULL == service)
3720 LOG (GNUNET_ERROR_TYPE_WARNING, _ ("Failed to start service.\n"));
3728 plugin = GNUNET_new (struct Plugin);
3729 plugin->sessionmap =
3730 GNUNET_CONTAINER_multipeermap_create (max_connections, GNUNET_YES);
3731 plugin->max_connections = max_connections;
3732 plugin->open_port = bport;
3733 plugin->adv_port = aport;
3735 plugin->my_welcome.header.size = htons (sizeof(struct WelcomeMessage));
3736 plugin->my_welcome.header.type =
3737 htons (GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_WELCOME);
3738 plugin->my_welcome.clientIdentity = *plugin->env->my_identity;
3740 if ((NULL != service) &&
3741 (GNUNET_YES == GNUNET_CONFIGURATION_get_value_yesno (env->cfg,
3746 plugin->myoptions |= TCP_OPTIONS_TCP_STEALTH;
3747 lsocks = LEGACY_SERVICE_get_listen_sockets (service);
3750 uint32_t len = sizeof(struct WelcomeMessage);
3752 for (i = 0; NULL != lsocks[i]; i++)
3756 GNUNET_NETWORK_socket_setsockopt (lsocks[i],
3761 struct GNUNET_PeerIdentity))) ||
3763 GNUNET_NETWORK_socket_setsockopt (lsocks[i],
3765 TCP_STEALTH_INTEGRITY_LEN,
3769 /* TCP STEALTH not supported by kernel */
3770 GNUNET_assert (0 == i);
3771 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3772 _ ("TCP_STEALTH not supported on this platform.\n"));
3778 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3779 _ ("TCP_STEALTH not supported on this platform.\n"));
3784 if ((NULL != service) &&
3787 get_server_addresses ("transport-tcp", env->cfg, &addrs, &addrlens))))
3789 for (ret = ret_s - 1; ret >= 0; ret--)
3790 LOG (GNUNET_ERROR_TYPE_INFO,
3791 "Binding to address `%s'\n",
3792 GNUNET_a2s (addrs[ret], addrlens[ret]));
3793 plugin->nat = GNUNET_NAT_register (env->cfg,
3796 (unsigned int) ret_s,
3797 (const struct sockaddr **) addrs,
3799 &tcp_nat_port_map_callback,
3800 &try_connection_reversal,
3802 for (ret = ret_s - 1; ret >= 0; ret--)
3803 GNUNET_free (addrs[ret]);
3804 GNUNET_free_non_null (addrs);
3805 GNUNET_free_non_null (addrlens);
3809 plugin->nat = GNUNET_NAT_register (plugin->env->cfg,
3816 &try_connection_reversal,
3819 api = GNUNET_new (struct GNUNET_TRANSPORT_PluginFunctions);
3821 api->send = &tcp_plugin_send;
3822 api->get_session = &tcp_plugin_get_session;
3823 api->disconnect_session = &tcp_plugin_disconnect_session;
3824 api->query_keepalive_factor = &tcp_plugin_query_keepalive_factor;
3825 api->disconnect_peer = &tcp_plugin_disconnect;
3826 api->address_pretty_printer = &tcp_plugin_address_pretty_printer;
3827 api->check_address = &tcp_plugin_check_address;
3828 api->address_to_string = &tcp_plugin_address_to_string;
3829 api->string_to_address = &tcp_plugin_string_to_address;
3830 api->get_network = &tcp_plugin_get_network;
3831 api->get_network_for_address = &tcp_plugin_get_network_for_address;
3832 api->update_session_timeout = &tcp_plugin_update_session_timeout;
3833 api->update_inbound_delay = &tcp_plugin_update_inbound_delay;
3834 api->setup_monitor = &tcp_plugin_setup_monitor;
3835 plugin->service = service;
3836 if (NULL != service)
3838 plugin->server = LEGACY_SERVICE_get_server (service);
3842 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_time (env->cfg,
3847 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
3852 plugin->server = GNUNET_SERVER_create_with_sockets (NULL,
3858 plugin->handlers = GNUNET_malloc (sizeof(my_handlers));
3859 GNUNET_memcpy (plugin->handlers, my_handlers, sizeof(my_handlers));
3861 i < sizeof(my_handlers) / sizeof(struct GNUNET_SERVER_MessageHandler);
3863 plugin->handlers[i].callback_cls = plugin;
3865 GNUNET_SERVER_add_handlers (plugin->server, plugin->handlers);
3866 GNUNET_SERVER_connect_notify (plugin->server, &connect_notify, plugin);
3867 GNUNET_SERVER_disconnect_notify (plugin->server, &disconnect_notify, plugin);
3868 plugin->nat_wait_conns =
3869 GNUNET_CONTAINER_multipeermap_create (16, GNUNET_YES);
3871 LOG (GNUNET_ERROR_TYPE_INFO,
3872 _ ("TCP transport listening on port %llu\n"),
3875 LOG (GNUNET_ERROR_TYPE_INFO,
3876 _ ("TCP transport not listening on any port (client only)\n"));
3877 if ((aport != bport) && (0 != bport))
3878 LOG (GNUNET_ERROR_TYPE_INFO,
3879 _ ("TCP transport advertises itself as being on port %llu\n"),
3881 /* Initially set connections to 0 */
3882 GNUNET_STATISTICS_set (plugin->env->stats,
3883 gettext_noop ("# TCP sessions active"),
3889 if (NULL != plugin->nat)
3890 GNUNET_NAT_unregister (plugin->nat);
3891 GNUNET_CONTAINER_multipeermap_destroy (plugin->sessionmap);
3892 if (NULL != service)
3893 LEGACY_SERVICE_stop (service);
3894 GNUNET_free (plugin);
3895 GNUNET_free_non_null (api);
3901 * Exit point from the plugin.
3903 * @param cls the `struct GNUNET_TRANSPORT_PluginFunctions`
3907 libgnunet_plugin_transport_tcp_done (void *cls)
3909 struct GNUNET_TRANSPORT_PluginFunctions *api = cls;
3910 struct Plugin *plugin = api->cls;
3911 struct TCPProbeContext *tcp_probe;
3912 struct PrettyPrinterContext *cur;
3913 struct PrettyPrinterContext *next;
3920 LOG (GNUNET_ERROR_TYPE_DEBUG, "Shutting down TCP plugin\n");
3922 /* Removing leftover sessions */
3923 GNUNET_CONTAINER_multipeermap_iterate (plugin->sessionmap,
3924 &session_disconnect_it,
3926 /* Removing leftover NAT sessions */
3927 GNUNET_CONTAINER_multipeermap_iterate (plugin->nat_wait_conns,
3928 &session_disconnect_it,
3931 for (cur = plugin->ppc_dll_head; NULL != cur; cur = next)
3934 GNUNET_CONTAINER_DLL_remove (plugin->ppc_dll_head,
3935 plugin->ppc_dll_tail,
3937 GNUNET_RESOLVER_request_cancel (cur->resolver_handle);
3938 cur->asc (cur->asc_cls, NULL, GNUNET_OK);
3942 if (NULL != plugin->service)
3943 LEGACY_SERVICE_stop (plugin->service);
3945 GNUNET_SERVER_destroy (plugin->server);
3946 GNUNET_free (plugin->handlers);
3947 if (NULL != plugin->nat)
3948 GNUNET_NAT_unregister (plugin->nat);
3949 while (NULL != (tcp_probe = plugin->probe_head))
3951 GNUNET_CONTAINER_DLL_remove (plugin->probe_head,
3954 GNUNET_CONNECTION_destroy (tcp_probe->sock);
3955 GNUNET_free (tcp_probe);
3957 GNUNET_CONTAINER_multipeermap_destroy (plugin->nat_wait_conns);
3958 GNUNET_CONTAINER_multipeermap_destroy (plugin->sessionmap);
3959 GNUNET_break (0 == plugin->cur_connections);
3960 GNUNET_free (plugin);
3965 /* end of plugin_transport_tcp.c */