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
609 * Active probes are kept in a DLL.
611 struct TCPProbeContext *next;
614 * Active probes are kept in a DLL.
616 struct TCPProbeContext *prev;
621 struct GNUNET_CONNECTION_Handle *sock;
624 * Message to be sent.
626 struct TCP_NAT_ProbeMessage message;
629 * Handle to the transmission.
631 struct GNUNET_CONNECTION_TransmitHandle *transmit_handle;
634 * Transport plugin handle.
636 struct Plugin *plugin;
640 * Bits in the `options` field of TCP addresses.
642 enum TcpAddressOptions
648 TCP_OPTIONS_NONE = 0,
651 * See #HTTP_OPTIONS_VERIFY_CERTIFICATE.
653 TCP_OPTIONS_RESERVED = 1,
656 * Enable TCP Stealth-style port knocking.
658 TCP_OPTIONS_TCP_STEALTH = 2
661 GNUNET_NETWORK_STRUCT_BEGIN
664 * Network format for IPv4 addresses.
666 struct IPv4TcpAddress
669 * Optional options and flags for this address,
670 * see `enum TcpAddressOptions`
672 uint32_t options GNUNET_PACKED;
675 * IPv4 address, in network byte order.
677 uint32_t ipv4_addr GNUNET_PACKED;
680 * Port number, in network byte order.
682 uint16_t t4_port GNUNET_PACKED;
686 * Network format for IPv6 addresses.
688 struct IPv6TcpAddress
691 * Optional flags for this address
692 * see `enum TcpAddressOptions`
694 uint32_t options GNUNET_PACKED;
699 struct in6_addr ipv6_addr GNUNET_PACKED;
702 * Port number, in network byte order.
704 uint16_t t6_port GNUNET_PACKED;
706 GNUNET_NETWORK_STRUCT_END
709 * Encapsulation of all of the state of the plugin.
714 * Information kept for each message that is yet to
717 struct PendingMessage
721 * This is a doubly-linked list.
723 struct PendingMessage *next;
726 * This is a doubly-linked list.
728 struct PendingMessage *prev;
731 * The pending message
736 * Continuation function to call once the message
737 * has been sent. Can be NULL if there is no
738 * continuation to call.
740 GNUNET_TRANSPORT_TransmitContinuation transmit_cont;
743 * Closure for @e transmit_cont.
745 void *transmit_cont_cls;
748 * Timeout value for the pending message.
750 struct GNUNET_TIME_Absolute timeout;
753 * So that the gnunet-service-transport can group messages together,
754 * these pending messages need to accept a message buffer and size
755 * instead of just a `struct GNUNET_MessageHeader`.
761 * Session handle for TCP connections.
763 struct GNUNET_ATS_Session
766 * To whom are we talking to (set to our identity
767 * if we are still waiting for the welcome message)
769 struct GNUNET_PeerIdentity target;
772 * Pointer to the global plugin struct.
774 struct Plugin *plugin;
777 * The client (used to identify this connection)
779 struct GNUNET_SERVER_Client *client;
782 * Task cleaning up a NAT client connection establishment attempt;
784 struct GNUNET_SCHEDULER_Task *nat_connection_timeout;
787 * Messages currently pending for transmission
788 * to this peer, if any.
790 struct PendingMessage *pending_messages_head;
793 * Messages currently pending for transmission
794 * to this peer, if any.
796 struct PendingMessage *pending_messages_tail;
799 * Handle for pending transmission request.
801 struct GNUNET_SERVER_TransmitHandle *transmit_handle;
804 * Address of the other peer.
806 struct GNUNET_HELLO_Address *address;
809 * ID of task used to delay receiving more to throttle sender.
811 struct GNUNET_SCHEDULER_Task *receive_delay_task;
814 * Session timeout task
816 struct GNUNET_SCHEDULER_Task *timeout_task;
819 * When will this session time out?
821 struct GNUNET_TIME_Absolute timeout;
824 * When will we continue to read from the socket?
825 * (used to enforce inbound quota).
827 struct GNUNET_TIME_Absolute receive_delay;
830 * Last activity on this connection. Used to select preferred
833 struct GNUNET_TIME_Absolute last_activity;
836 * Number of bytes waiting for transmission to this peer.
838 unsigned long long bytes_in_queue;
841 * Number of messages waiting for transmission to this peer.
843 unsigned int msgs_in_queue;
846 * Network type of the address.
848 enum GNUNET_NetworkType scope;
851 * Are we still expecting the welcome message? (#GNUNET_YES/#GNUNET_NO)
853 int expecting_welcome;
856 * Was this session created using NAT traversal?
863 * Context for address to string conversion, closure
864 * for #append_port().
866 struct PrettyPrinterContext
871 struct PrettyPrinterContext *next;
876 struct PrettyPrinterContext *prev;
881 struct Plugin *plugin;
886 struct GNUNET_SCHEDULER_Task *timeout_task;
891 struct GNUNET_RESOLVER_RequestHandle *resolver_handle;
894 * Function to call with the result.
896 GNUNET_TRANSPORT_AddressStringCallback asc;
899 * Clsoure for @e asc.
914 * Port to add after the IP address.
921 * Encapsulation of all of the state of the plugin.
928 struct GNUNET_TRANSPORT_PluginEnvironment *env;
933 struct GNUNET_CONNECTION_Handle *lsock;
936 * Our handle to the NAT module.
938 struct GNUNET_NAT_Handle *nat;
941 * Map from peer identities to sessions for the given peer.
943 struct GNUNET_CONTAINER_MultiPeerMap *sessionmap;
946 * Handle to the network service.
948 struct LEGACY_SERVICE_Context *service;
951 * Handle to the server for this service.
953 struct GNUNET_SERVER_Handle *server;
956 * Copy of the handler array where the closures are
957 * set to this struct's instance.
959 struct GNUNET_SERVER_MessageHandler *handlers;
962 * Map of peers we have tried to contact behind a NAT
964 struct GNUNET_CONTAINER_MultiPeerMap *nat_wait_conns;
967 * List of active TCP probes.
969 struct TCPProbeContext *probe_head;
972 * List of active TCP probes.
974 struct TCPProbeContext *probe_tail;
977 * Function to call about session status changes.
979 GNUNET_TRANSPORT_SessionInfoCallback sic;
982 * Closure for @e sic.
987 * ID of task used to update our addresses when one expires.
989 struct GNUNET_SCHEDULER_Task *address_update_task;
992 * Running pretty printers: head
994 struct PrettyPrinterContext *ppc_dll_head;
997 * Running pretty printers: tail
999 struct PrettyPrinterContext *ppc_dll_tail;
1002 * Welcome message used by this peer.
1004 struct WelcomeMessage my_welcome;
1007 * How many more TCP sessions are we allowed to open right now?
1009 unsigned long long max_connections;
1012 * How many more TCP sessions do we have right now?
1014 unsigned long long cur_connections;
1022 * Port that we are actually listening on.
1027 * Port that the user said we would have visible to the
1028 * rest of the world.
1035 * Get the list of addresses that a server for the given service
1038 * @param service_name name of the service
1039 * @param cfg configuration (which specifies the addresses)
1040 * @param addrs set (call by reference) to an array of pointers to the
1041 * addresses the server should bind to and listen on; the
1042 * array will be NULL-terminated (on success)
1043 * @param addr_lens set (call by reference) to an array of the lengths
1044 * of the respective `struct sockaddr` struct in the @a addrs
1045 * array (on success)
1046 * @return number of addresses found on success,
1047 * #GNUNET_SYSERR if the configuration
1048 * did not specify reasonable finding information or
1049 * if it specified a hostname that could not be resolved;
1050 * #GNUNET_NO if the number of addresses configured is
1051 * zero (in this case, `*addrs` and `*addr_lens` will be
1055 get_server_addresses (const char *service_name,
1056 const struct GNUNET_CONFIGURATION_Handle *cfg,
1057 struct sockaddr ***addrs,
1058 socklen_t **addr_lens)
1061 struct GNUNET_NETWORK_Handle *desc;
1062 unsigned long long port;
1064 struct addrinfo hints;
1065 struct addrinfo *res;
1066 struct addrinfo *pos;
1067 struct addrinfo *next;
1072 struct sockaddr **saddrs;
1073 socklen_t *saddrlens;
1079 if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "DISABLEV6"))
1081 if (GNUNET_SYSERR ==
1082 (disablev6 = GNUNET_CONFIGURATION_get_value_yesno (cfg,
1085 return GNUNET_SYSERR;
1088 disablev6 = GNUNET_NO;
1092 /* probe IPv6 support */
1093 desc = GNUNET_NETWORK_socket_create (PF_INET6, SOCK_STREAM, 0);
1096 if ((ENOBUFS == errno) || (ENOMEM == errno) || (ENFILE == errno) ||
1099 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "socket");
1100 return GNUNET_SYSERR;
1102 LOG (GNUNET_ERROR_TYPE_INFO,
1104 "Disabling IPv6 support for service `%s', failed to create IPv6 socket: %s\n"),
1107 disablev6 = GNUNET_YES;
1111 GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (desc));
1117 if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "PORT"))
1119 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (cfg,
1124 LOG (GNUNET_ERROR_TYPE_ERROR,
1125 _ ("Require valid port number for service `%s' in configuration!\n"),
1130 LOG (GNUNET_ERROR_TYPE_ERROR,
1131 _ ("Require valid port number for service `%s' in configuration!\n"),
1133 return GNUNET_SYSERR;
1137 if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "BINDTO"))
1139 GNUNET_break (GNUNET_OK ==
1140 GNUNET_CONFIGURATION_get_value_string (cfg,
1149 abstract = GNUNET_NO;
1152 GNUNET_CONFIGURATION_have_value (cfg, service_name, "UNIXPATH")) &&
1153 (GNUNET_OK == GNUNET_CONFIGURATION_get_value_filename (cfg,
1157 (0 < strlen (unixpath)))
1159 /* probe UNIX support */
1160 struct sockaddr_un s_un;
1162 if (strlen (unixpath) >= sizeof (s_un.sun_path))
1164 LOG (GNUNET_ERROR_TYPE_WARNING,
1165 _ ("UNIXPATH `%s' too long, maximum length is %llu\n"),
1167 (unsigned long long) sizeof (s_un.sun_path));
1168 unixpath = GNUNET_NETWORK_shorten_unixpath (unixpath);
1169 LOG (GNUNET_ERROR_TYPE_INFO, _ ("Using `%s' instead\n"), unixpath);
1172 abstract = GNUNET_CONFIGURATION_get_value_yesno (cfg,
1174 "USE_ABSTRACT_SOCKETS");
1175 if (GNUNET_SYSERR == abstract)
1176 abstract = GNUNET_NO;
1178 if ((GNUNET_YES != abstract) &&
1179 (GNUNET_OK != GNUNET_DISK_directory_create_for_file (unixpath)))
1180 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "mkdir", unixpath);
1182 if (NULL != unixpath)
1184 desc = GNUNET_NETWORK_socket_create (AF_UNIX, SOCK_STREAM, 0);
1187 if ((ENOBUFS == errno) || (ENOMEM == errno) || (ENFILE == errno) ||
1190 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "socket");
1191 GNUNET_free_non_null (hostname);
1192 GNUNET_free (unixpath);
1193 return GNUNET_SYSERR;
1195 LOG (GNUNET_ERROR_TYPE_INFO,
1197 "Disabling UNIX domain socket support for service `%s', failed to create UNIX domain socket: %s\n"),
1200 GNUNET_free (unixpath);
1205 GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (desc));
1211 if ((0 == port) && (NULL == unixpath))
1213 LOG (GNUNET_ERROR_TYPE_ERROR,
1215 "Have neither PORT nor UNIXPATH for service `%s', but one is required\n"),
1217 GNUNET_free_non_null (hostname);
1218 return GNUNET_SYSERR;
1222 saddrs = GNUNET_malloc (2 * sizeof (struct sockaddr *));
1223 saddrlens = GNUNET_malloc (2 * sizeof (socklen_t));
1224 add_unixpath (saddrs, saddrlens, unixpath, abstract);
1225 GNUNET_free_non_null (unixpath);
1226 GNUNET_free_non_null (hostname);
1228 *addr_lens = saddrlens;
1232 if (NULL != hostname)
1234 LOG (GNUNET_ERROR_TYPE_DEBUG,
1235 "Resolving `%s' since that is where `%s' will bind to.\n",
1238 memset (&hints, 0, sizeof (struct addrinfo));
1240 hints.ai_family = AF_INET;
1241 hints.ai_protocol = IPPROTO_TCP;
1242 if ((0 != (ret = getaddrinfo (hostname, NULL, &hints, &res))) ||
1245 LOG (GNUNET_ERROR_TYPE_ERROR,
1246 _ ("Failed to resolve `%s': %s\n"),
1248 gai_strerror (ret));
1249 GNUNET_free (hostname);
1250 GNUNET_free_non_null (unixpath);
1251 return GNUNET_SYSERR;
1255 while (NULL != (pos = next))
1257 next = pos->ai_next;
1258 if ((disablev6) && (pos->ai_family == AF_INET6))
1264 LOG (GNUNET_ERROR_TYPE_ERROR,
1265 _ ("Failed to find %saddress for `%s'.\n"),
1266 disablev6 ? "IPv4 " : "",
1269 GNUNET_free (hostname);
1270 GNUNET_free_non_null (unixpath);
1271 return GNUNET_SYSERR;
1274 if (NULL != unixpath)
1276 saddrs = GNUNET_malloc ((resi + 1) * sizeof (struct sockaddr *));
1277 saddrlens = GNUNET_malloc ((resi + 1) * sizeof (socklen_t));
1279 if (NULL != unixpath)
1281 add_unixpath (saddrs, saddrlens, unixpath, abstract);
1285 while (NULL != (pos = next))
1287 next = pos->ai_next;
1288 if ((disablev6) && (AF_INET6 == pos->ai_family))
1290 if ((IPPROTO_TCP != pos->ai_protocol) && (0 != pos->ai_protocol))
1291 continue; /* not TCP */
1292 if ((SOCK_STREAM != pos->ai_socktype) && (0 != pos->ai_socktype))
1293 continue; /* huh? */
1294 LOG (GNUNET_ERROR_TYPE_DEBUG,
1295 "Service `%s' will bind to `%s'\n",
1297 GNUNET_a2s (pos->ai_addr, pos->ai_addrlen));
1298 if (AF_INET == pos->ai_family)
1300 GNUNET_assert (sizeof (struct sockaddr_in) == pos->ai_addrlen);
1301 saddrlens[i] = pos->ai_addrlen;
1302 saddrs[i] = GNUNET_malloc (saddrlens[i]);
1303 GNUNET_memcpy (saddrs[i], pos->ai_addr, saddrlens[i]);
1304 ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
1308 GNUNET_assert (AF_INET6 == pos->ai_family);
1309 GNUNET_assert (sizeof (struct sockaddr_in6) == pos->ai_addrlen);
1310 saddrlens[i] = pos->ai_addrlen;
1311 saddrs[i] = GNUNET_malloc (saddrlens[i]);
1312 GNUNET_memcpy (saddrs[i], pos->ai_addr, saddrlens[i]);
1313 ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port);
1317 GNUNET_free (hostname);
1323 /* will bind against everything, just set port */
1328 if (NULL != unixpath)
1331 saddrs = GNUNET_malloc ((resi + 1) * sizeof (struct sockaddr *));
1332 saddrlens = GNUNET_malloc ((resi + 1) * sizeof (socklen_t));
1333 if (NULL != unixpath)
1335 add_unixpath (saddrs, saddrlens, unixpath, abstract);
1338 saddrlens[i] = sizeof (struct sockaddr_in);
1339 saddrs[i] = GNUNET_malloc (saddrlens[i]);
1340 #if HAVE_SOCKADDR_IN_SIN_LEN
1341 ((struct sockaddr_in *) saddrs[i])->sin_len = saddrlens[i];
1343 ((struct sockaddr_in *) saddrs[i])->sin_family = AF_INET;
1344 ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
1350 if (NULL != unixpath)
1352 saddrs = GNUNET_malloc ((resi + 1) * sizeof (struct sockaddr *));
1353 saddrlens = GNUNET_malloc ((resi + 1) * sizeof (socklen_t));
1355 if (NULL != unixpath)
1357 add_unixpath (saddrs, saddrlens, unixpath, abstract);
1360 saddrlens[i] = sizeof (struct sockaddr_in6);
1361 saddrs[i] = GNUNET_malloc (saddrlens[i]);
1362 #if HAVE_SOCKADDR_IN_SIN_LEN
1363 ((struct sockaddr_in6 *) saddrs[i])->sin6_len = saddrlens[0];
1365 ((struct sockaddr_in6 *) saddrs[i])->sin6_family = AF_INET6;
1366 ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port);
1368 saddrlens[i] = sizeof (struct sockaddr_in);
1369 saddrs[i] = GNUNET_malloc (saddrlens[i]);
1370 #if HAVE_SOCKADDR_IN_SIN_LEN
1371 ((struct sockaddr_in *) saddrs[i])->sin_len = saddrlens[1];
1373 ((struct sockaddr_in *) saddrs[i])->sin_family = AF_INET;
1374 ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
1377 GNUNET_free_non_null (unixpath);
1379 *addr_lens = saddrlens;
1382 /* end ancient copy-and-paste */
1386 * If a session monitor is attached, notify it about the new
1389 * @param plugin our plugin
1390 * @param session session that changed state
1391 * @param state new state of the session
1394 notify_session_monitor (struct Plugin *plugin,
1395 struct GNUNET_ATS_Session *session,
1396 enum GNUNET_TRANSPORT_SessionState state)
1398 struct GNUNET_TRANSPORT_SessionInfo info;
1400 if (NULL == plugin->sic)
1402 memset (&info, 0, sizeof (info));
1405 GNUNET_HELLO_address_check_option (session->address,
1406 GNUNET_HELLO_ADDRESS_INFO_INBOUND);
1407 info.num_msg_pending = session->msgs_in_queue;
1408 info.num_bytes_pending = session->bytes_in_queue;
1409 if (NULL != session->receive_delay_task)
1410 info.receive_delay = session->receive_delay;
1411 info.session_timeout = session->timeout;
1412 info.address = session->address;
1413 plugin->sic (plugin->sic_cls, session, &info);
1418 * Our external IP address/port mapping has changed.
1420 * @param cls closure, the `struct Plugin`
1421 * @param app_ctx[in,out] location where the app can store stuff
1422 * on add and retrieve it on remove
1423 * @param add_remove #GNUNET_YES to mean the new public IP address, #GNUNET_NO to mean
1424 * the previous (now invalid) one
1425 * @param ac address class the address belongs to
1426 * @param addr either the previous or the new public IP address
1427 * @param addrlen actual length of @a addr
1430 tcp_nat_port_map_callback (void *cls,
1433 enum GNUNET_NAT_AddressClass ac,
1434 const struct sockaddr *addr,
1437 struct Plugin *plugin = cls;
1438 struct GNUNET_HELLO_Address *address;
1439 struct IPv4TcpAddress t4;
1440 struct IPv6TcpAddress t6;
1445 LOG (GNUNET_ERROR_TYPE_INFO,
1446 "NAT notification to %s address `%s'\n",
1447 (GNUNET_YES == add_remove) ? "add" : "remove",
1448 GNUNET_a2s (addr, addrlen));
1449 /* convert 'addr' to our internal format */
1450 switch (addr->sa_family)
1453 GNUNET_assert (addrlen == sizeof (struct sockaddr_in));
1454 memset (&t4, 0, sizeof (t4));
1455 t4.options = htonl (plugin->myoptions);
1456 t4.ipv4_addr = ((struct sockaddr_in *) addr)->sin_addr.s_addr;
1457 t4.t4_port = ((struct sockaddr_in *) addr)->sin_port;
1462 if (IN6_IS_ADDR_LINKLOCAL (&((struct sockaddr_in6 *) addr)->sin6_addr))
1464 /* skip link local, we don't allow them in
1465 #tcp_plugin_check_address() */
1468 GNUNET_assert (addrlen == sizeof (struct sockaddr_in6));
1469 memset (&t6, 0, sizeof (t6));
1470 GNUNET_memcpy (&t6.ipv6_addr,
1471 &((struct sockaddr_in6 *) addr)->sin6_addr,
1472 sizeof (struct in6_addr));
1473 t6.options = htonl (plugin->myoptions);
1474 t6.t6_port = ((struct sockaddr_in6 *) addr)->sin6_port;
1482 /* modify our published address list */
1483 GNUNET_assert ((args == sizeof (struct IPv4TcpAddress)) ||
1484 (args == sizeof (struct IPv6TcpAddress)));
1485 /* TODO: use 'ac' here in the future... */
1486 address = GNUNET_HELLO_address_allocate (plugin->env->my_identity,
1490 GNUNET_HELLO_ADDRESS_INFO_NONE);
1491 plugin->env->notify_address (plugin->env->cls, add_remove, address);
1492 GNUNET_HELLO_address_free (address);
1497 * Function called for a quick conversion of the binary address to
1498 * a numeric address. Note that the caller must not free the
1499 * address and that the next call to this function is allowed
1500 * to override the address again.
1502 * @param cls closure (`struct Plugin*`)
1503 * @param addr binary address
1504 * @param addrlen length of @a addr
1505 * @return string representing the same address
1508 tcp_plugin_address_to_string (void *cls, const void *addr, size_t addrlen)
1510 static char rbuf[INET6_ADDRSTRLEN + 12];
1511 char buf[INET6_ADDRSTRLEN];
1515 const struct IPv4TcpAddress *t4;
1516 const struct IPv6TcpAddress *t6;
1523 case sizeof (struct IPv6TcpAddress):
1526 port = ntohs (t6->t6_port);
1527 options = ntohl (t6->options);
1528 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));
1540 LOG (GNUNET_ERROR_TYPE_WARNING,
1541 _ ("Unexpected address length: %u bytes\n"),
1542 (unsigned int) addrlen);
1545 if (NULL == inet_ntop (af, sb, buf, INET6_ADDRSTRLEN))
1547 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "inet_ntop");
1550 GNUNET_snprintf (rbuf,
1552 (af == AF_INET6) ? "%s.%u.[%s]:%u" : "%s.%u.%s:%u",
1562 * Function called to convert a string address to
1565 * @param cls closure (`struct Plugin*`)
1566 * @param addr string address
1567 * @param addrlen length of the address
1568 * @param buf location to store the buffer
1569 * @param added location to store the number of bytes in the buffer.
1570 * If the function returns #GNUNET_SYSERR, its contents are undefined.
1571 * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure
1574 tcp_plugin_string_to_address (void *cls,
1580 struct sockaddr_storage socket_address;
1586 /* Format tcp.options.address:port */
1590 if ((NULL == addr) || (0 == addrlen))
1593 return GNUNET_SYSERR;
1595 if ('\0' != addr[addrlen - 1])
1598 return GNUNET_SYSERR;
1600 if (strlen (addr) != addrlen - 1)
1603 return GNUNET_SYSERR;
1605 plugin = GNUNET_strdup (addr);
1606 optionstr = strchr (plugin, '.');
1607 if (NULL == optionstr)
1610 GNUNET_free (plugin);
1611 return GNUNET_SYSERR;
1613 optionstr[0] = '\0';
1615 options = atol (optionstr);
1616 address = strchr (optionstr, '.');
1617 if (NULL == address)
1620 GNUNET_free (plugin);
1621 return GNUNET_SYSERR;
1627 GNUNET_STRINGS_to_address_ip (address, strlen (address), &socket_address))
1630 GNUNET_free (plugin);
1631 return GNUNET_SYSERR;
1634 GNUNET_free (plugin);
1635 switch (socket_address.ss_family)
1638 struct IPv4TcpAddress *t4;
1639 struct sockaddr_in *in4 = (struct sockaddr_in *) &socket_address;
1640 t4 = GNUNET_new (struct IPv4TcpAddress);
1641 t4->options = htonl (options);
1642 t4->ipv4_addr = in4->sin_addr.s_addr;
1643 t4->t4_port = in4->sin_port;
1645 *added = sizeof (struct IPv4TcpAddress);
1649 struct IPv6TcpAddress *t6;
1650 struct sockaddr_in6 *in6 = (struct sockaddr_in6 *) &socket_address;
1651 t6 = GNUNET_new (struct IPv6TcpAddress);
1652 t6->options = htonl (options);
1653 t6->ipv6_addr = in6->sin6_addr;
1654 t6->t6_port = in6->sin6_port;
1656 *added = sizeof (struct IPv6TcpAddress);
1660 return GNUNET_SYSERR;
1666 * Find the session handle for the given client.
1667 * Currently uses both the hashmap and the client
1668 * context, as the client context is new and the
1669 * logic still needs to be tested.
1671 * @param plugin the plugin
1672 * @param client which client to find the session handle for
1673 * @return NULL if no matching session exists
1675 static struct GNUNET_ATS_Session *
1676 lookup_session_by_client (struct Plugin *plugin,
1677 struct GNUNET_SERVER_Client *client)
1679 return GNUNET_SERVER_client_get_user_context (client,
1680 struct GNUNET_ATS_Session);
1685 * Functions with this signature are called whenever we need
1686 * to close a session due to a disconnect or failure to
1687 * establish a connection.
1689 * @param cls the `struct Plugin`
1690 * @param session session to close down
1691 * @return #GNUNET_OK on success
1694 tcp_plugin_disconnect_session (void *cls, struct GNUNET_ATS_Session *session)
1696 struct Plugin *plugin = cls;
1697 struct PendingMessage *pm;
1699 LOG (GNUNET_ERROR_TYPE_DEBUG,
1700 "Disconnecting session of peer `%s' address `%s'\n",
1701 GNUNET_i2s (&session->target),
1702 tcp_plugin_address_to_string (session->plugin,
1703 session->address->address,
1704 session->address->address_length));
1706 if (NULL != session->timeout_task)
1708 GNUNET_SCHEDULER_cancel (session->timeout_task);
1709 session->timeout_task = NULL;
1710 session->timeout = GNUNET_TIME_UNIT_ZERO_ABS;
1713 if (GNUNET_YES == GNUNET_CONTAINER_multipeermap_remove (plugin->sessionmap,
1717 GNUNET_STATISTICS_update (session->plugin->env->stats,
1718 gettext_noop ("# TCP sessions active"),
1724 GNUNET_assert (GNUNET_YES ==
1725 GNUNET_CONTAINER_multipeermap_remove (plugin->nat_wait_conns,
1729 if (NULL != session->client)
1730 GNUNET_SERVER_client_set_user_context (session->client, NULL);
1732 /* clean up state */
1733 if (NULL != session->transmit_handle)
1735 GNUNET_SERVER_notify_transmit_ready_cancel (session->transmit_handle);
1736 session->transmit_handle = NULL;
1738 session->plugin->env->session_end (session->plugin->env->cls,
1742 if (NULL != session->nat_connection_timeout)
1744 GNUNET_SCHEDULER_cancel (session->nat_connection_timeout);
1745 session->nat_connection_timeout = NULL;
1748 while (NULL != (pm = session->pending_messages_head))
1750 LOG (GNUNET_ERROR_TYPE_DEBUG,
1751 (NULL != pm->transmit_cont)
1752 ? "Could not deliver message to `%s' at %s.\n"
1753 : "Could not deliver message to `%s' at %s, notifying.\n",
1754 GNUNET_i2s (&session->target),
1755 tcp_plugin_address_to_string (session->plugin,
1756 session->address->address,
1757 session->address->address_length));
1758 GNUNET_STATISTICS_update (session->plugin->env->stats,
1759 gettext_noop ("# bytes currently in TCP buffers"),
1760 -(int64_t) pm->message_size,
1762 GNUNET_STATISTICS_update (session->plugin->env->stats,
1764 "# bytes discarded by TCP (disconnect)"),
1767 GNUNET_CONTAINER_DLL_remove (session->pending_messages_head,
1768 session->pending_messages_tail,
1770 GNUNET_assert (0 < session->msgs_in_queue);
1771 session->msgs_in_queue--;
1772 GNUNET_assert (pm->message_size <= session->bytes_in_queue);
1773 session->bytes_in_queue -= pm->message_size;
1774 if (NULL != pm->transmit_cont)
1775 pm->transmit_cont (pm->transmit_cont_cls,
1782 GNUNET_assert (0 == session->msgs_in_queue);
1783 GNUNET_assert (0 == session->bytes_in_queue);
1784 notify_session_monitor (session->plugin, session, GNUNET_TRANSPORT_SS_DONE);
1786 if (NULL != session->receive_delay_task)
1788 GNUNET_SCHEDULER_cancel (session->receive_delay_task);
1789 session->receive_delay_task = NULL;
1791 if (NULL != session->client)
1793 GNUNET_SERVER_client_disconnect (session->client);
1794 session->client = NULL;
1796 GNUNET_HELLO_address_free (session->address);
1797 GNUNET_assert (NULL == session->transmit_handle);
1798 GNUNET_free (session);
1804 * Function that is called to get the keepalive factor.
1805 * #GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT is divided by this number to
1806 * calculate the interval between keepalive packets.
1808 * @param cls closure with the `struct Plugin`
1809 * @return keepalive factor
1812 tcp_plugin_query_keepalive_factor (void *cls)
1819 * Session was idle for too long, so disconnect it
1821 * @param cls the `struct GNUNET_ATS_Session` of the idle session
1824 session_timeout (void *cls)
1826 struct GNUNET_ATS_Session *s = cls;
1827 struct GNUNET_TIME_Relative left;
1829 s->timeout_task = NULL;
1830 left = GNUNET_TIME_absolute_get_remaining (s->timeout);
1831 if (0 != left.rel_value_us)
1833 /* not actually our turn yet, but let's at least update
1834 the monitor, it may think we're about to die ... */
1835 notify_session_monitor (s->plugin, s, GNUNET_TRANSPORT_SS_UPDATE);
1836 s->timeout_task = GNUNET_SCHEDULER_add_delayed (left, &session_timeout, s);
1839 LOG (GNUNET_ERROR_TYPE_DEBUG,
1840 "Session %p was idle for %s, disconnecting\n",
1842 GNUNET_STRINGS_relative_time_to_string (
1843 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
1845 /* call session destroy function */
1846 tcp_plugin_disconnect_session (s->plugin, s);
1851 * Increment session timeout due to activity.
1853 * @param s session to increment timeout for
1856 reschedule_session_timeout (struct GNUNET_ATS_Session *s)
1858 GNUNET_assert (NULL != s->timeout_task);
1860 GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1865 * Create a new session. Also queues a welcome message.
1867 * @param plugin the plugin
1868 * @param address the address to create the session for
1869 * @param scope network scope the address is from
1870 * @param client client to use, reference counter must have already been increased
1871 * @param is_nat this a NAT session, we should wait for a client to
1872 * connect to us from an address, then assign that to
1874 * @return new session object
1876 static struct GNUNET_ATS_Session *
1877 create_session (struct Plugin *plugin,
1878 const struct GNUNET_HELLO_Address *address,
1879 enum GNUNET_NetworkType scope,
1880 struct GNUNET_SERVER_Client *client,
1883 struct GNUNET_ATS_Session *session;
1884 struct PendingMessage *pm;
1886 if (GNUNET_YES != is_nat)
1887 GNUNET_assert (NULL != client);
1889 GNUNET_assert (NULL == client);
1891 LOG (GNUNET_ERROR_TYPE_DEBUG,
1892 "Creating new session for peer `%s' at address %s\n",
1893 GNUNET_i2s (&address->peer),
1894 tcp_plugin_address_to_string (plugin,
1896 address->address_length));
1897 session = GNUNET_new (struct GNUNET_ATS_Session);
1898 session->last_activity = GNUNET_TIME_absolute_get ();
1899 session->plugin = plugin;
1900 session->is_nat = is_nat;
1903 session->client = client;
1904 GNUNET_SERVER_client_set_user_context (client, session);
1906 session->address = GNUNET_HELLO_address_copy (address);
1907 session->target = address->peer;
1908 session->expecting_welcome = GNUNET_YES;
1909 session->scope = scope;
1910 pm = GNUNET_malloc (sizeof (struct PendingMessage) +
1911 sizeof (struct WelcomeMessage));
1912 pm->msg = (const char *) &pm[1];
1913 pm->message_size = sizeof (struct WelcomeMessage);
1914 GNUNET_memcpy (&pm[1], &plugin->my_welcome, sizeof (struct WelcomeMessage));
1915 pm->timeout = GNUNET_TIME_UNIT_FOREVER_ABS;
1916 GNUNET_STATISTICS_update (plugin->env->stats,
1917 gettext_noop ("# bytes currently in TCP buffers"),
1920 GNUNET_CONTAINER_DLL_insert (session->pending_messages_head,
1921 session->pending_messages_tail,
1923 session->msgs_in_queue++;
1924 session->bytes_in_queue += pm->message_size;
1926 GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1927 session->timeout_task =
1928 GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
1931 notify_session_monitor (session->plugin, session, GNUNET_TRANSPORT_SS_INIT);
1932 if (GNUNET_YES != is_nat)
1934 GNUNET_STATISTICS_update (plugin->env->stats,
1935 gettext_noop ("# TCP sessions active"),
1938 notify_session_monitor (session->plugin, session, GNUNET_TRANSPORT_SS_UP);
1942 notify_session_monitor (session->plugin,
1944 GNUNET_TRANSPORT_SS_HANDSHAKE);
1951 * If we have pending messages, ask the server to
1952 * transmit them (schedule the respective tasks, etc.)
1954 * @param session for which session should we do this
1957 process_pending_messages (struct GNUNET_ATS_Session *session);
1961 * Function called to notify a client about the socket
1962 * being ready to queue more data. "buf" will be
1963 * NULL and "size" zero if the socket was closed for
1964 * writing in the meantime.
1966 * @param cls closure
1967 * @param size number of bytes available in @a buf
1968 * @param buf where the callee should write the message
1969 * @return number of bytes written to @a buf
1972 do_transmit (void *cls, size_t size, void *buf)
1974 struct GNUNET_ATS_Session *session = cls;
1975 struct GNUNET_PeerIdentity pid;
1976 struct Plugin *plugin;
1977 struct PendingMessage *pos;
1978 struct PendingMessage *hd;
1979 struct PendingMessage *tl;
1980 struct GNUNET_TIME_Absolute now;
1984 session->transmit_handle = NULL;
1985 plugin = session->plugin;
1988 LOG (GNUNET_ERROR_TYPE_DEBUG,
1989 "Timeout trying to transmit to peer `%s', discarding message queue.\n",
1990 GNUNET_i2s (&session->target));
1991 /* timeout; cancel all messages that have already expired */
1995 now = GNUNET_TIME_absolute_get ();
1996 while ((NULL != (pos = session->pending_messages_head)) &&
1997 (pos->timeout.abs_value_us <= now.abs_value_us))
1999 GNUNET_CONTAINER_DLL_remove (session->pending_messages_head,
2000 session->pending_messages_tail,
2002 GNUNET_assert (0 < session->msgs_in_queue);
2003 session->msgs_in_queue--;
2004 GNUNET_assert (pos->message_size <= session->bytes_in_queue);
2005 session->bytes_in_queue -= pos->message_size;
2006 LOG (GNUNET_ERROR_TYPE_DEBUG,
2007 "Failed to transmit %u byte message to `%s'.\n",
2009 GNUNET_i2s (&session->target));
2010 ret += pos->message_size;
2011 GNUNET_CONTAINER_DLL_insert_after (hd, tl, tl, pos);
2013 /* do this call before callbacks (so that if callbacks destroy
2014 * session, they have a chance to cancel actions done by this
2016 process_pending_messages (session);
2017 pid = session->target;
2018 /* no do callbacks and do not use session again since
2019 * the callbacks may abort the session */
2020 while (NULL != (pos = hd))
2022 GNUNET_CONTAINER_DLL_remove (hd, tl, pos);
2023 if (NULL != pos->transmit_cont)
2024 pos->transmit_cont (pos->transmit_cont_cls,
2031 GNUNET_STATISTICS_update (plugin->env->stats,
2032 gettext_noop ("# bytes currently in TCP buffers"),
2035 GNUNET_STATISTICS_update (plugin->env->stats,
2037 "# bytes discarded by TCP (timeout)"),
2041 notify_session_monitor (session->plugin,
2043 GNUNET_TRANSPORT_SS_UPDATE);
2046 /* copy all pending messages that would fit */
2051 while (NULL != (pos = session->pending_messages_head))
2053 if (ret + pos->message_size > size)
2055 GNUNET_CONTAINER_DLL_remove (session->pending_messages_head,
2056 session->pending_messages_tail,
2058 GNUNET_assert (0 < session->msgs_in_queue);
2059 session->msgs_in_queue--;
2060 GNUNET_assert (pos->message_size <= session->bytes_in_queue);
2061 session->bytes_in_queue -= pos->message_size;
2062 GNUNET_assert (size >= pos->message_size);
2063 LOG (GNUNET_ERROR_TYPE_DEBUG,
2064 "Transmitting message of type %u size %u to peer %s at %s\n",
2065 ntohs (((struct GNUNET_MessageHeader *) pos->msg)->type),
2067 GNUNET_i2s (&session->target),
2068 tcp_plugin_address_to_string (session->plugin,
2069 session->address->address,
2070 session->address->address_length));
2071 /* FIXME: this GNUNET_memcpy can be up to 7% of our total runtime */
2072 GNUNET_memcpy (cbuf, pos->msg, pos->message_size);
2073 cbuf += pos->message_size;
2074 ret += pos->message_size;
2075 size -= pos->message_size;
2076 GNUNET_CONTAINER_DLL_insert_tail (hd, tl, pos);
2078 notify_session_monitor (session->plugin, session, GNUNET_TRANSPORT_SS_UPDATE);
2079 /* schedule 'continuation' before callbacks so that callbacks that
2080 * cancel everything don't cause us to use a session that no longer
2082 process_pending_messages (session);
2083 session->last_activity = GNUNET_TIME_absolute_get ();
2084 pid = session->target;
2085 /* we'll now call callbacks that may cancel the session; hence
2086 * we should not use 'session' after this point */
2087 while (NULL != (pos = hd))
2089 GNUNET_CONTAINER_DLL_remove (hd, tl, pos);
2090 if (NULL != pos->transmit_cont)
2091 pos->transmit_cont (pos->transmit_cont_cls,
2095 pos->message_size); /* FIXME: include TCP overhead */
2098 GNUNET_assert (NULL == hd);
2099 GNUNET_assert (NULL == tl);
2100 GNUNET_STATISTICS_update (plugin->env->stats,
2101 gettext_noop ("# bytes currently in TCP buffers"),
2104 GNUNET_STATISTICS_update (plugin->env->stats,
2105 gettext_noop ("# bytes transmitted via TCP"),
2113 * If we have pending messages, ask the server to
2114 * transmit them (schedule the respective tasks, etc.)
2116 * @param session for which session should we do this
2119 process_pending_messages (struct GNUNET_ATS_Session *session)
2121 struct PendingMessage *pm;
2123 GNUNET_assert (NULL != session->client);
2124 if (NULL != session->transmit_handle)
2126 if (NULL == (pm = session->pending_messages_head))
2129 session->transmit_handle =
2130 GNUNET_SERVER_notify_transmit_ready (session->client,
2132 GNUNET_TIME_absolute_get_remaining (
2140 * Function that can be used by the transport service to transmit
2141 * a message using the plugin. Note that in the case of a
2142 * peer disconnecting, the continuation MUST be called
2143 * prior to the disconnect notification itself. This function
2144 * will be called with this peer's HELLO message to initiate
2145 * a fresh connection to another peer.
2147 * @param cls closure
2148 * @param session which session must be used
2149 * @param msgbuf the message to transmit
2150 * @param msgbuf_size number of bytes in @a msgbuf
2151 * @param priority how important is the message (most plugins will
2152 * ignore message priority and just FIFO)
2153 * @param to how long to wait at most for the transmission (does not
2154 * require plugins to discard the message after the timeout,
2155 * just advisory for the desired delay; most plugins will ignore
2157 * @param cont continuation to call once the message has
2158 * been transmitted (or if the transport is ready
2159 * for the next transmission call; or if the
2160 * peer disconnected...); can be NULL
2161 * @param cont_cls closure for @a cont
2162 * @return number of bytes used (on the physical network, with overheads);
2163 * -1 on hard errors (i.e. address invalid); 0 is a legal value
2164 * and does NOT mean that the message was not transmitted (DV)
2167 tcp_plugin_send (void *cls,
2168 struct GNUNET_ATS_Session *session,
2171 unsigned int priority,
2172 struct GNUNET_TIME_Relative to,
2173 GNUNET_TRANSPORT_TransmitContinuation cont,
2176 struct Plugin *plugin = cls;
2177 struct PendingMessage *pm;
2179 /* create new message entry */
2180 pm = GNUNET_malloc (sizeof (struct PendingMessage) + msgbuf_size);
2181 pm->msg = (const char *) &pm[1];
2182 GNUNET_memcpy (&pm[1], msgbuf, msgbuf_size);
2183 pm->message_size = msgbuf_size;
2184 pm->timeout = GNUNET_TIME_relative_to_absolute (to);
2185 pm->transmit_cont = cont;
2186 pm->transmit_cont_cls = cont_cls;
2188 LOG (GNUNET_ERROR_TYPE_DEBUG,
2189 "Asked to transmit %u bytes to `%s', added message to list.\n",
2191 GNUNET_i2s (&session->target));
2194 GNUNET_CONTAINER_multipeermap_contains_value (plugin->sessionmap,
2198 GNUNET_assert (NULL != session->client);
2199 GNUNET_SERVER_client_set_timeout (session->client,
2200 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2201 GNUNET_STATISTICS_update (plugin->env->stats,
2202 gettext_noop ("# bytes currently in TCP buffers"),
2206 /* append pm to pending_messages list */
2207 GNUNET_CONTAINER_DLL_insert_tail (session->pending_messages_head,
2208 session->pending_messages_tail,
2210 notify_session_monitor (session->plugin,
2212 GNUNET_TRANSPORT_SS_UPDATE);
2213 session->msgs_in_queue++;
2214 session->bytes_in_queue += pm->message_size;
2215 process_pending_messages (session);
2219 GNUNET_CONTAINER_multipeermap_contains_value (plugin->nat_wait_conns,
2223 LOG (GNUNET_ERROR_TYPE_DEBUG,
2224 "This NAT WAIT session for peer `%s' is not yet ready!\n",
2225 GNUNET_i2s (&session->target));
2226 GNUNET_STATISTICS_update (plugin->env->stats,
2227 gettext_noop ("# bytes currently in TCP buffers"),
2230 /* append pm to pending_messages list */
2231 GNUNET_CONTAINER_DLL_insert_tail (session->pending_messages_head,
2232 session->pending_messages_tail,
2234 session->msgs_in_queue++;
2235 session->bytes_in_queue += pm->message_size;
2236 notify_session_monitor (session->plugin,
2238 GNUNET_TRANSPORT_SS_HANDSHAKE);
2241 LOG (GNUNET_ERROR_TYPE_ERROR, "Invalid session %p\n", session);
2243 cont (cont_cls, &session->target, GNUNET_SYSERR, pm->message_size, 0);
2246 return GNUNET_SYSERR; /* session does not exist here */
2251 * Closure for #session_lookup_it().
2253 struct GNUNET_ATS_SessionItCtx
2256 * Address we are looking for.
2258 const struct GNUNET_HELLO_Address *address;
2261 * Where to store the session (if we found it).
2263 struct GNUNET_ATS_Session *result;
2268 * Look for a session by address.
2270 * @param cls the `struct GNUNET_ATS_SessionItCtx`
2272 * @param value a `struct GNUNET_ATS_Session`
2273 * @return #GNUNET_YES to continue looking, #GNUNET_NO if we found the session
2276 session_lookup_it (void *cls,
2277 const struct GNUNET_PeerIdentity *key,
2280 struct GNUNET_ATS_SessionItCtx *si_ctx = cls;
2281 struct GNUNET_ATS_Session *session = value;
2283 if (0 != GNUNET_HELLO_address_cmp (si_ctx->address, session->address))
2285 si_ctx->result = session;
2291 * Task cleaning up a NAT connection attempt after timeout
2293 * @param cls the `struct GNUNET_ATS_Session`
2296 nat_connect_timeout (void *cls)
2298 struct GNUNET_ATS_Session *session = cls;
2300 session->nat_connection_timeout = NULL;
2301 LOG (GNUNET_ERROR_TYPE_DEBUG,
2302 "NAT WAIT connection to `%4s' at `%s' could not be established, removing session\n",
2303 GNUNET_i2s (&session->target),
2304 tcp_plugin_address_to_string (session->plugin,
2305 session->address->address,
2306 session->address->address_length));
2307 tcp_plugin_disconnect_session (session->plugin, session);
2312 * Function that will be called whenever the transport service wants to
2313 * notify the plugin that a session is still active and in use and
2314 * therefore the session timeout for this session has to be updated
2316 * @param cls closure
2317 * @param peer which peer was the session for
2318 * @param session which session is being updated
2321 tcp_plugin_update_session_timeout (void *cls,
2322 const struct GNUNET_PeerIdentity *peer,
2323 struct GNUNET_ATS_Session *session)
2325 reschedule_session_timeout (session);
2330 * Task to signal the server that we can continue
2331 * receiving from the TCP client now.
2333 * @param cls the `struct GNUNET_ATS_Session *`
2336 delayed_done (void *cls)
2338 struct GNUNET_ATS_Session *session = cls;
2340 session->receive_delay_task = NULL;
2341 reschedule_session_timeout (session);
2342 GNUNET_SERVER_receive_done (session->client, GNUNET_OK);
2347 * Function that will be called whenever the transport service wants to
2348 * notify the plugin that the inbound quota changed and that the plugin
2349 * should update it's delay for the next receive value
2351 * @param cls closure
2352 * @param peer which peer was the session for
2353 * @param session which session is being updated
2354 * @param delay new delay to use for receiving
2357 tcp_plugin_update_inbound_delay (void *cls,
2358 const struct GNUNET_PeerIdentity *peer,
2359 struct GNUNET_ATS_Session *session,
2360 struct GNUNET_TIME_Relative delay)
2362 if (NULL == session->receive_delay_task)
2364 LOG (GNUNET_ERROR_TYPE_DEBUG,
2365 "New inbound delay %s\n",
2366 GNUNET_STRINGS_relative_time_to_string (delay, GNUNET_NO));
2367 session->receive_delay = GNUNET_TIME_relative_to_absolute (delay);
2368 GNUNET_SCHEDULER_cancel (session->receive_delay_task);
2369 session->receive_delay_task =
2370 GNUNET_SCHEDULER_add_delayed (delay, &delayed_done, session);
2375 * Create a new session to transmit data to the target
2376 * This session will used to send data to this peer and the plugin will
2377 * notify us by calling the env->session_end function
2379 * @param cls closure
2380 * @param address the address to use
2381 * @return the session if the address is valid, NULL otherwise
2383 static struct GNUNET_ATS_Session *
2384 tcp_plugin_get_session (void *cls, const struct GNUNET_HELLO_Address *address)
2386 struct Plugin *plugin = cls;
2387 struct GNUNET_ATS_Session *session = NULL;
2391 struct GNUNET_CONNECTION_Handle *sa;
2392 struct sockaddr_in a4;
2393 struct sockaddr_in6 a6;
2394 const struct IPv4TcpAddress *t4;
2395 const struct IPv6TcpAddress *t6;
2396 unsigned int options;
2397 enum GNUNET_NetworkType net_type;
2398 unsigned int is_natd = GNUNET_NO;
2401 struct GNUNET_NETWORK_Handle *s;
2404 addrlen = address->address_length;
2405 LOG (GNUNET_ERROR_TYPE_DEBUG,
2406 "Trying to get session for `%s' address of peer `%s'\n",
2407 tcp_plugin_address_to_string (plugin,
2409 address->address_length),
2410 GNUNET_i2s (&address->peer));
2412 if (GNUNET_HELLO_address_check_option (address,
2413 GNUNET_HELLO_ADDRESS_INFO_INBOUND))
2419 /* look for existing session */
2420 if (GNUNET_YES == GNUNET_CONTAINER_multipeermap_contains (plugin->sessionmap,
2423 struct GNUNET_ATS_SessionItCtx si_ctx;
2425 si_ctx.address = address;
2426 si_ctx.result = NULL;
2427 GNUNET_CONTAINER_multipeermap_get_multiple (plugin->sessionmap,
2431 if (NULL != si_ctx.result)
2433 session = si_ctx.result;
2434 LOG (GNUNET_ERROR_TYPE_DEBUG,
2435 "Found existing session for `%s' address `%s'\n",
2436 GNUNET_i2s (&address->peer),
2437 tcp_plugin_address_to_string (plugin,
2439 address->address_length));
2442 /* This is a bit of a hack, limiting TCP to never allow more than
2443 one TCP connection to any given peer at the same time.
2444 Without this, peers sometimes disagree about which of the TCP
2445 connections they should use, causing one side to believe that
2446 they transmit successfully, while the other receives nothing. */
2447 return NULL; /* Refuse to have more than one TCP connection per
2448 peer pair at the same time. */
2451 if (addrlen == sizeof (struct IPv6TcpAddress))
2453 GNUNET_assert (NULL != address->address); /* make static analysis happy */
2454 t6 = address->address;
2455 options = t6->options;
2457 memset (&a6, 0, sizeof (a6));
2458 #if HAVE_SOCKADDR_IN_SIN_LEN
2459 a6.sin6_len = sizeof (a6);
2461 a6.sin6_family = AF_INET6;
2462 a6.sin6_port = t6->t6_port;
2463 if (t6->t6_port == 0)
2464 is_natd = GNUNET_YES;
2465 GNUNET_memcpy (&a6.sin6_addr, &t6->ipv6_addr, sizeof (struct in6_addr));
2469 else if (addrlen == sizeof (struct IPv4TcpAddress))
2471 GNUNET_assert (NULL != address->address); /* make static analysis happy */
2472 t4 = address->address;
2473 options = t4->options;
2475 memset (&a4, 0, sizeof (a4));
2476 #if HAVE_SOCKADDR_IN_SIN_LEN
2477 a4.sin_len = sizeof (a4);
2479 a4.sin_family = AF_INET;
2480 a4.sin_port = t4->t4_port;
2481 if (t4->t4_port == 0)
2482 is_natd = GNUNET_YES;
2483 a4.sin_addr.s_addr = t4->ipv4_addr;
2489 GNUNET_STATISTICS_update (
2491 gettext_noop ("# requests to create session with invalid address"),
2497 net_type = plugin->env->get_address_type (plugin->env->cls, sb, sbs);
2498 GNUNET_break (net_type != GNUNET_NT_UNSPECIFIED);
2500 if ((is_natd == GNUNET_YES) && (addrlen == sizeof (struct IPv6TcpAddress)))
2502 /* NAT client only works with IPv4 addresses */
2506 if (plugin->cur_connections >= plugin->max_connections)
2512 if ((is_natd == GNUNET_YES) &&
2514 GNUNET_CONTAINER_multipeermap_contains (plugin->nat_wait_conns,
2517 /* Only do one NAT punch attempt per peer identity */
2521 if ((is_natd == GNUNET_YES) && (NULL != plugin->nat) &&
2523 GNUNET_CONTAINER_multipeermap_contains (plugin->nat_wait_conns,
2526 struct sockaddr_in local_sa;
2528 LOG (GNUNET_ERROR_TYPE_DEBUG,
2529 "Found valid IPv4 NAT address (creating session)!\n");
2530 session = create_session (plugin, address, net_type, NULL, GNUNET_YES);
2531 session->nat_connection_timeout =
2532 GNUNET_SCHEDULER_add_delayed (NAT_TIMEOUT, &nat_connect_timeout, session);
2533 GNUNET_assert (GNUNET_OK ==
2534 GNUNET_CONTAINER_multipeermap_put (
2535 plugin->nat_wait_conns,
2538 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
2540 LOG (GNUNET_ERROR_TYPE_DEBUG,
2541 "Created NAT WAIT connection to `%s' at `%s'\n",
2542 GNUNET_i2s (&session->target),
2543 GNUNET_a2s (sb, sbs));
2544 memset (&local_sa, 0, sizeof (local_sa));
2545 local_sa.sin_family = AF_INET;
2546 local_sa.sin_port = htons (plugin->open_port);
2547 /* We leave sin_address at 0, let the kernel figure it out,
2548 even if our bind() is more specific. (May want to reconsider
2550 if (GNUNET_OK == GNUNET_NAT_request_reversal (plugin->nat, &local_sa, &a4))
2552 LOG (GNUNET_ERROR_TYPE_DEBUG,
2553 "Running NAT client for `%s' at `%s' failed\n",
2554 GNUNET_i2s (&session->target),
2555 GNUNET_a2s (sb, sbs));
2556 tcp_plugin_disconnect_session (plugin, session);
2560 /* create new outbound session */
2561 if (0 != (options & TCP_OPTIONS_TCP_STEALTH))
2564 s = GNUNET_NETWORK_socket_create (af, SOCK_STREAM, 0);
2567 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK,
2574 GNUNET_NETWORK_socket_setsockopt (s,
2579 struct GNUNET_PeerIdentity))) ||
2581 GNUNET_NETWORK_socket_setsockopt (s,
2583 TCP_STEALTH_INTEGRITY,
2584 &plugin->my_welcome,
2585 sizeof (struct WelcomeMessage))))
2587 /* TCP STEALTH not supported by kernel */
2588 GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (s));
2593 sa = GNUNET_CONNECTION_connect_socket (s, sb, sbs);
2602 sa = GNUNET_CONNECTION_create_from_sockaddr (af, sb, sbs);
2606 LOG (GNUNET_ERROR_TYPE_DEBUG,
2607 "Failed to create connection to `%s' at `%s'\n",
2608 GNUNET_i2s (&address->peer),
2609 GNUNET_a2s (sb, sbs));
2612 LOG (GNUNET_ERROR_TYPE_DEBUG,
2613 "Asked to transmit to `%s', creating fresh session using address `%s'.\n",
2614 GNUNET_i2s (&address->peer),
2615 GNUNET_a2s (sb, sbs));
2617 session = create_session (plugin,
2620 GNUNET_SERVER_connect_socket (plugin->server, sa),
2622 (void) GNUNET_CONTAINER_multipeermap_put (
2626 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
2627 /* Send TCP Welcome */
2628 process_pending_messages (session);
2635 * We have been asked to destroy all connections to a particular peer.
2636 * This function is called on each applicable session and must tear it
2639 * @param cls the `struct Plugin *`
2640 * @param key the peer which the session belongs to (unused)
2641 * @param value the `struct GNUNET_ATS_Session`
2642 * @return #GNUNET_YES (continue to iterate)
2645 session_disconnect_it (void *cls,
2646 const struct GNUNET_PeerIdentity *key,
2649 struct Plugin *plugin = cls;
2650 struct GNUNET_ATS_Session *session = value;
2652 GNUNET_STATISTICS_update (session->plugin->env->stats,
2654 "# transport-service disconnect requests for TCP"),
2657 tcp_plugin_disconnect_session (plugin, session);
2663 * Function that can be called to force a disconnect from the
2664 * specified neighbour. This should also cancel all previously
2665 * scheduled transmissions. Obviously the transmission may have been
2666 * partially completed already, which is OK. The plugin is supposed
2667 * to close the connection (if applicable) and no longer call the
2668 * transmit continuation(s).
2670 * Finally, plugin MUST NOT call the services's receive function to
2671 * notify the service that the connection to the specified target was
2672 * closed after a getting this call.
2674 * @param cls closure
2675 * @param target peer for which the last transmission is
2679 tcp_plugin_disconnect (void *cls, const struct GNUNET_PeerIdentity *target)
2681 struct Plugin *plugin = cls;
2683 LOG (GNUNET_ERROR_TYPE_DEBUG,
2684 "Disconnecting peer `%s'\n",
2685 GNUNET_i2s (target));
2686 GNUNET_CONTAINER_multipeermap_get_multiple (plugin->sessionmap,
2688 &session_disconnect_it,
2690 GNUNET_CONTAINER_multipeermap_get_multiple (plugin->nat_wait_conns,
2692 &session_disconnect_it,
2698 * We are processing an address pretty printing request and finished
2699 * the IP resolution (if applicable). Append our port and forward the
2700 * result. If called with @a hostname NULL, we are done and should
2701 * clean up the pretty printer (otherwise, there might be multiple
2702 * hostnames for the IP address and we might receive more).
2704 * @param cls the `struct PrettyPrinterContext *`
2705 * @param hostname hostname part of the address
2708 append_port (void *cls, const char *hostname)
2710 struct PrettyPrinterContext *ppc = cls;
2711 struct Plugin *plugin = ppc->plugin;
2714 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2715 "append_port called with hostname `%s'\n",
2717 if (NULL == hostname)
2719 /* Final call, done */
2720 ppc->resolver_handle = NULL;
2721 GNUNET_CONTAINER_DLL_remove (plugin->ppc_dll_head,
2722 plugin->ppc_dll_tail,
2724 ppc->asc (ppc->asc_cls, NULL, GNUNET_OK);
2728 if (GNUNET_YES == ppc->ipv6)
2729 GNUNET_asprintf (&ret,
2736 GNUNET_asprintf (&ret,
2742 ppc->asc (ppc->asc_cls, ret, GNUNET_OK);
2748 * Convert the transports address to a nice, human-readable format.
2750 * @param cls closure with the `struct Plugin`
2751 * @param type name of the transport that generated the address
2752 * @param addr one of the addresses of the host, NULL for the last address
2753 * the specific address format depends on the transport
2754 * @param addrlen length of the @a addr
2755 * @param numeric should (IP) addresses be displayed in numeric form?
2756 * @param timeout after how long should we give up?
2757 * @param asc function to call on each string
2758 * @param asc_cls closure for @a asc
2761 tcp_plugin_address_pretty_printer (void *cls,
2766 struct GNUNET_TIME_Relative timeout,
2767 GNUNET_TRANSPORT_AddressStringCallback asc,
2770 struct Plugin *plugin = cls;
2771 struct PrettyPrinterContext *ppc;
2774 struct sockaddr_in a4;
2775 struct sockaddr_in6 a6;
2776 const struct IPv4TcpAddress *t4;
2777 const struct IPv6TcpAddress *t6;
2781 if (sizeof (struct IPv6TcpAddress) == addrlen)
2784 memset (&a6, 0, sizeof (a6));
2785 a6.sin6_family = AF_INET6;
2786 a6.sin6_port = t6->t6_port;
2787 GNUNET_memcpy (&a6.sin6_addr, &t6->ipv6_addr, sizeof (struct in6_addr));
2788 port = ntohs (t6->t6_port);
2789 options = ntohl (t6->options);
2793 else if (sizeof (struct IPv4TcpAddress) == addrlen)
2796 memset (&a4, 0, sizeof (a4));
2797 a4.sin_family = AF_INET;
2798 a4.sin_port = t4->t4_port;
2799 a4.sin_addr.s_addr = t4->ipv4_addr;
2800 port = ntohs (t4->t4_port);
2801 options = ntohl (t4->options);
2807 /* invalid address */
2808 LOG (GNUNET_ERROR_TYPE_WARNING,
2809 _ ("Unexpected address length: %u bytes\n"),
2810 (unsigned int) addrlen);
2811 asc (asc_cls, NULL, GNUNET_SYSERR);
2812 asc (asc_cls, NULL, GNUNET_OK);
2815 ppc = GNUNET_new (struct PrettyPrinterContext);
2816 ppc->plugin = plugin;
2817 if (addrlen == sizeof (struct IPv6TcpAddress))
2818 ppc->ipv6 = GNUNET_YES;
2820 ppc->ipv6 = GNUNET_NO;
2822 ppc->asc_cls = asc_cls;
2824 ppc->options = options;
2825 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting DNS reverse lookup\n");
2826 ppc->resolver_handle = GNUNET_RESOLVER_hostname_get (sb,
2832 if (NULL == ppc->resolver_handle)
2838 GNUNET_CONTAINER_DLL_insert (plugin->ppc_dll_head, plugin->ppc_dll_tail, ppc);
2843 * Function that will be called to check if a binary address for this
2844 * plugin is well-formed and corresponds to an address for THIS peer
2845 * (as per our configuration). Naturally, if absolutely necessary,
2846 * plugins can be a bit conservative in their answer, but in general
2847 * plugins should make sure that the address does not redirect
2848 * traffic to a 3rd party that might try to man-in-the-middle our
2851 * @param cls closure, our `struct Plugin *`
2852 * @param addr pointer to the address
2853 * @param addrlen length of @a addr
2854 * @return #GNUNET_OK if this is a plausible address for this peer
2855 * and transport, #GNUNET_SYSERR if not
2858 tcp_plugin_check_address (void *cls, const void *addr, size_t addrlen)
2860 struct Plugin *plugin = cls;
2861 const struct IPv4TcpAddress *v4;
2862 const struct IPv6TcpAddress *v6;
2864 if ((addrlen != sizeof (struct IPv4TcpAddress)) &&
2865 (addrlen != sizeof (struct IPv6TcpAddress)))
2867 GNUNET_break_op (0);
2868 return GNUNET_SYSERR;
2871 if (addrlen == sizeof (struct IPv4TcpAddress))
2873 struct sockaddr_in s4;
2875 v4 = (const struct IPv4TcpAddress *) addr;
2876 if (0 != memcmp (&v4->options, &plugin->myoptions, sizeof (uint32_t)))
2879 return GNUNET_SYSERR;
2881 memset (&s4, 0, sizeof (s4));
2882 s4.sin_family = AF_INET;
2883 #if HAVE_SOCKADDR_IN_SIN_LEN
2884 s4.sin_len = sizeof (s4);
2886 s4.sin_port = v4->t4_port;
2887 s4.sin_addr.s_addr = v4->ipv4_addr;
2890 GNUNET_NAT_test_address (plugin->nat, &s4, sizeof (struct sockaddr_in)))
2891 return GNUNET_SYSERR;
2895 struct sockaddr_in6 s6;
2897 v6 = (const struct IPv6TcpAddress *) addr;
2898 if (IN6_IS_ADDR_LINKLOCAL (&v6->ipv6_addr))
2900 GNUNET_break_op (0);
2901 return GNUNET_SYSERR;
2903 if (0 != memcmp (&v6->options, &plugin->myoptions, sizeof (uint32_t)))
2906 return GNUNET_SYSERR;
2908 memset (&s6, 0, sizeof (s6));
2909 s6.sin6_family = AF_INET6;
2910 #if HAVE_SOCKADDR_IN_SIN_LEN
2911 s6.sin6_len = sizeof (s6);
2913 s6.sin6_port = v6->t6_port;
2914 s6.sin6_addr = v6->ipv6_addr;
2916 if (GNUNET_OK != GNUNET_NAT_test_address (plugin->nat,
2918 sizeof (struct sockaddr_in6)))
2919 return GNUNET_SYSERR;
2926 * We've received a nat probe from this peer via TCP. Finish
2927 * creating the client session and resume sending of queued
2930 * @param cls closure
2931 * @param client identification of the client
2932 * @param message the actual message
2935 handle_tcp_nat_probe (void *cls,
2936 struct GNUNET_SERVER_Client *client,
2937 const struct GNUNET_MessageHeader *message)
2939 struct Plugin *plugin = cls;
2940 struct GNUNET_ATS_Session *session;
2941 const struct TCP_NAT_ProbeMessage *tcp_nat_probe;
2944 struct IPv4TcpAddress *t4;
2945 struct IPv6TcpAddress *t6;
2946 const struct sockaddr_in *s4;
2947 const struct sockaddr_in6 *s6;
2949 LOG (GNUNET_ERROR_TYPE_DEBUG, "Received NAT probe\n");
2950 /* We have received a TCP NAT probe, meaning we (hopefully) initiated
2951 * a connection to this peer by running gnunet-nat-client. This peer
2952 * received the punch message and now wants us to use the new connection
2953 * as the default for that peer. Do so and then send a WELCOME message
2954 * so we can really be connected!
2956 if (ntohs (message->size) != sizeof (struct TCP_NAT_ProbeMessage))
2958 GNUNET_break_op (0);
2959 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2963 tcp_nat_probe = (const struct TCP_NAT_ProbeMessage *) message;
2964 if (0 == memcmp (&tcp_nat_probe->clientIdentity,
2965 plugin->env->my_identity,
2966 sizeof (struct GNUNET_PeerIdentity)))
2968 /* refuse connections from ourselves */
2969 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2973 session = GNUNET_CONTAINER_multipeermap_get (plugin->nat_wait_conns,
2974 &tcp_nat_probe->clientIdentity);
2975 if (NULL == session)
2977 LOG (GNUNET_ERROR_TYPE_DEBUG, "Did NOT find session for NAT probe!\n");
2978 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2981 LOG (GNUNET_ERROR_TYPE_DEBUG, "Found session for NAT probe!\n");
2983 if (NULL != session->nat_connection_timeout)
2985 GNUNET_SCHEDULER_cancel (session->nat_connection_timeout);
2986 session->nat_connection_timeout = NULL;
2989 if (GNUNET_OK != GNUNET_SERVER_client_get_address (client, &vaddr, &alen))
2992 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2993 tcp_plugin_disconnect_session (plugin, session);
2998 GNUNET_CONTAINER_multipeermap_remove (plugin->nat_wait_conns,
2999 &tcp_nat_probe->clientIdentity,
3001 GNUNET_SERVER_client_set_user_context (client, session);
3002 (void) GNUNET_CONTAINER_multipeermap_put (
3006 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
3007 session->last_activity = GNUNET_TIME_absolute_get ();
3008 LOG (GNUNET_ERROR_TYPE_DEBUG,
3009 "Found address `%s' for incoming connection\n",
3010 GNUNET_a2s (vaddr, alen));
3011 switch (((const struct sockaddr *) vaddr)->sa_family)
3015 t4 = GNUNET_new (struct IPv4TcpAddress);
3016 t4->options = htonl (TCP_OPTIONS_NONE);
3017 t4->t4_port = s4->sin_port;
3018 t4->ipv4_addr = s4->sin_addr.s_addr;
3020 GNUNET_HELLO_address_allocate (&tcp_nat_probe->clientIdentity,
3023 sizeof (struct IPv4TcpAddress),
3024 GNUNET_HELLO_ADDRESS_INFO_NONE);
3028 t6 = GNUNET_new (struct IPv6TcpAddress);
3029 t6->options = htonl (TCP_OPTIONS_NONE);
3030 t6->t6_port = s6->sin6_port;
3031 GNUNET_memcpy (&t6->ipv6_addr, &s6->sin6_addr, sizeof (struct in6_addr));
3033 GNUNET_HELLO_address_allocate (&tcp_nat_probe->clientIdentity,
3036 sizeof (struct IPv6TcpAddress),
3037 GNUNET_HELLO_ADDRESS_INFO_NONE);
3040 GNUNET_break_op (0);
3041 LOG (GNUNET_ERROR_TYPE_DEBUG, "Bad address for incoming connection!\n");
3042 GNUNET_free (vaddr);
3043 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3044 tcp_plugin_disconnect_session (plugin, session);
3047 GNUNET_free (vaddr);
3048 GNUNET_break (NULL == session->client);
3049 session->client = client;
3050 GNUNET_STATISTICS_update (plugin->env->stats,
3051 gettext_noop ("# TCP sessions active"),
3054 process_pending_messages (session);
3055 GNUNET_SERVER_receive_done (client, GNUNET_OK);
3060 * We've received a welcome from this peer via TCP. Possibly create a
3061 * fresh client record and send back our welcome.
3063 * @param cls closure
3064 * @param client identification of the client
3065 * @param message the actual message
3068 handle_tcp_welcome (void *cls,
3069 struct GNUNET_SERVER_Client *client,
3070 const struct GNUNET_MessageHeader *message)
3072 struct Plugin *plugin = cls;
3073 const struct WelcomeMessage *wm = (const struct WelcomeMessage *) message;
3074 struct GNUNET_HELLO_Address *address;
3075 struct GNUNET_ATS_Session *session;
3078 struct IPv4TcpAddress t4;
3079 struct IPv6TcpAddress t6;
3080 const struct sockaddr_in *s4;
3081 const struct sockaddr_in6 *s6;
3083 if (0 == memcmp (&wm->clientIdentity,
3084 plugin->env->my_identity,
3085 sizeof (struct GNUNET_PeerIdentity)))
3087 /* refuse connections from ourselves */
3088 if (GNUNET_OK == GNUNET_SERVER_client_get_address (client, &vaddr, &alen))
3090 LOG (GNUNET_ERROR_TYPE_INFO,
3091 "Received WELCOME message from my own identity `%s' on address `%s'\n",
3092 GNUNET_i2s (&wm->clientIdentity),
3093 GNUNET_a2s (vaddr, alen));
3094 GNUNET_free (vaddr);
3096 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3100 if (GNUNET_OK == GNUNET_SERVER_client_get_address (client, &vaddr, &alen))
3102 LOG (GNUNET_ERROR_TYPE_DEBUG,
3103 "Received WELCOME message from `%s' on address `%s'\n",
3104 GNUNET_i2s (&wm->clientIdentity),
3105 GNUNET_a2s (vaddr, alen));
3106 GNUNET_free (vaddr);
3108 GNUNET_STATISTICS_update (plugin->env->stats,
3109 gettext_noop ("# TCP WELCOME messages received"),
3112 session = lookup_session_by_client (plugin, client);
3113 if (NULL != session)
3115 if (GNUNET_OK == GNUNET_SERVER_client_get_address (client, &vaddr, &alen))
3117 LOG (GNUNET_ERROR_TYPE_DEBUG,
3118 "Found existing session %p for peer `%s'\n",
3120 GNUNET_a2s (vaddr, alen));
3121 GNUNET_free (vaddr);
3126 if (GNUNET_OK == GNUNET_SERVER_client_get_address (client, &vaddr, &alen))
3128 if (alen == sizeof (struct sockaddr_in))
3131 memset (&t4, '\0', sizeof (t4));
3132 t4.options = htonl (TCP_OPTIONS_NONE);
3133 t4.t4_port = s4->sin_port;
3134 t4.ipv4_addr = s4->sin_addr.s_addr;
3136 GNUNET_HELLO_address_allocate (&wm->clientIdentity,
3140 GNUNET_HELLO_ADDRESS_INFO_INBOUND);
3142 else if (alen == sizeof (struct sockaddr_in6))
3145 memset (&t6, '\0', sizeof (t6));
3146 t6.options = htonl (TCP_OPTIONS_NONE);
3147 t6.t6_port = s6->sin6_port;
3148 GNUNET_memcpy (&t6.ipv6_addr, &s6->sin6_addr, sizeof (struct in6_addr));
3150 GNUNET_HELLO_address_allocate (&wm->clientIdentity,
3154 GNUNET_HELLO_ADDRESS_INFO_INBOUND);
3159 GNUNET_free_non_null (vaddr);
3160 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3163 session = create_session (plugin,
3165 plugin->env->get_address_type (plugin->env->cls,
3170 GNUNET_break (GNUNET_NT_UNSPECIFIED != session->scope);
3171 GNUNET_HELLO_address_free (address);
3172 LOG (GNUNET_ERROR_TYPE_DEBUG,
3173 "Creating new%s session %p for peer `%s' client %p\n",
3174 GNUNET_HELLO_address_check_option (session->address,
3175 GNUNET_HELLO_ADDRESS_INFO_INBOUND)
3179 tcp_plugin_address_to_string (plugin,
3180 session->address->address,
3181 session->address->address_length),
3183 GNUNET_free (vaddr);
3184 (void) GNUNET_CONTAINER_multipeermap_put (
3188 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
3189 /* Notify transport and ATS about new session */
3190 plugin->env->session_start (plugin->env->cls,
3197 LOG (GNUNET_ERROR_TYPE_DEBUG,
3198 "Did not obtain TCP socket address for incoming connection\n");
3200 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3205 if (GNUNET_YES != session->expecting_welcome)
3207 GNUNET_break_op (0);
3208 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3211 session->last_activity = GNUNET_TIME_absolute_get ();
3212 session->expecting_welcome = GNUNET_NO;
3214 process_pending_messages (session);
3215 GNUNET_SERVER_client_set_timeout (client,
3216 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
3217 GNUNET_SERVER_receive_done (client, GNUNET_OK);
3222 * We've received data for this peer via TCP. Unbox,
3223 * compute latency and forward.
3225 * @param cls closure
3226 * @param client identification of the client
3227 * @param message the actual message
3230 handle_tcp_data (void *cls,
3231 struct GNUNET_SERVER_Client *client,
3232 const struct GNUNET_MessageHeader *message)
3234 struct Plugin *plugin = cls;
3235 struct GNUNET_ATS_Session *session;
3236 struct GNUNET_TIME_Relative delay;
3239 type = ntohs (message->type);
3240 if ((GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_WELCOME == type) ||
3241 (GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_NAT_PROBE == type))
3243 /* We don't want to propagate WELCOME and NAT Probe messages up! */
3244 GNUNET_SERVER_receive_done (client, GNUNET_OK);
3247 session = lookup_session_by_client (plugin, client);
3248 if (NULL == session)
3250 /* No inbound session found */
3254 GNUNET_assert (GNUNET_OK ==
3255 GNUNET_SERVER_client_get_address (client, &vaddr, &alen));
3256 LOG (GNUNET_ERROR_TYPE_ERROR,
3257 "Received unexpected %u bytes of type %u from `%s'\n",
3258 (unsigned int) ntohs (message->size),
3259 (unsigned int) ntohs (message->type),
3260 GNUNET_a2s (vaddr, alen));
3261 GNUNET_break_op (0);
3262 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3263 GNUNET_free_non_null (vaddr);
3266 if (GNUNET_YES == session->expecting_welcome)
3268 /* Session is expecting WELCOME message */
3272 GNUNET_SERVER_client_get_address (client, &vaddr, &alen);
3273 LOG (GNUNET_ERROR_TYPE_ERROR,
3274 "Received unexpected %u bytes of type %u from `%s'\n",
3275 (unsigned int) ntohs (message->size),
3276 (unsigned int) ntohs (message->type),
3277 GNUNET_a2s (vaddr, alen));
3278 GNUNET_break_op (0);
3279 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3280 GNUNET_free_non_null (vaddr);
3284 session->last_activity = GNUNET_TIME_absolute_get ();
3289 GNUNET_SERVER_client_get_address (client, &vaddr, &alen);
3290 LOG (GNUNET_ERROR_TYPE_DEBUG,
3291 "Passing %u bytes of type %u from `%s' at %s to transport service.\n",
3292 (unsigned int) ntohs (message->size),
3293 (unsigned int) ntohs (message->type),
3294 GNUNET_i2s (&session->target),
3295 GNUNET_a2s (vaddr, alen));
3296 GNUNET_free_non_null (vaddr);
3299 GNUNET_STATISTICS_update (plugin->env->stats,
3300 gettext_noop ("# bytes received via TCP"),
3301 ntohs (message->size),
3305 GNUNET_CONTAINER_multipeermap_contains_value (plugin->sessionmap,
3309 plugin->env->receive (plugin->env->cls, session->address, session, message);
3310 reschedule_session_timeout (session);
3311 if (0 == delay.rel_value_us)
3313 GNUNET_SERVER_receive_done (client, GNUNET_OK);
3317 LOG (GNUNET_ERROR_TYPE_DEBUG,
3318 "Throttling receiving from `%s' for %s\n",
3319 GNUNET_i2s (&session->target),
3320 GNUNET_STRINGS_relative_time_to_string (delay, GNUNET_YES));
3321 GNUNET_SERVER_disable_receive_done_warning (client);
3322 GNUNET_assert (NULL == session->receive_delay_task);
3323 session->receive_delay_task =
3324 GNUNET_SCHEDULER_add_delayed (delay, &delayed_done, session);
3330 * Function called whenever a peer is connected on the "SERVER" level.
3331 * Increments number of active connections and suspends server if we
3332 * have reached the limit.
3334 * @param cls closure
3335 * @param client identification of the client
3338 connect_notify (void *cls, struct GNUNET_SERVER_Client *client)
3340 struct Plugin *plugin = cls;
3344 plugin->cur_connections++;
3345 GNUNET_STATISTICS_set (plugin->env->stats,
3346 gettext_noop ("# TCP server connections active"),
3347 plugin->cur_connections,
3349 GNUNET_STATISTICS_update (plugin->env->stats,
3350 gettext_noop ("# TCP server connect events"),
3353 if (plugin->cur_connections != plugin->max_connections)
3355 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3356 _ ("TCP connection limit reached, suspending server\n"));
3357 GNUNET_STATISTICS_update (plugin->env->stats,
3358 gettext_noop ("# TCP service suspended"),
3361 GNUNET_SERVER_suspend (
3362 plugin->server); /* Maximum number of connections rechead */
3367 * Function called whenever a peer is disconnected on the "SERVER"
3368 * level. Cleans up the connection, decrements number of active
3369 * connections and if applicable resumes listening.
3371 * @param cls closure
3372 * @param client identification of the client
3375 disconnect_notify (void *cls, struct GNUNET_SERVER_Client *client)
3377 struct Plugin *plugin = cls;
3378 struct GNUNET_ATS_Session *session;
3382 GNUNET_assert (plugin->cur_connections >= 1);
3383 plugin->cur_connections--;
3384 session = lookup_session_by_client (plugin, client);
3385 if (NULL == session)
3386 return; /* unknown, nothing to do */
3387 LOG (GNUNET_ERROR_TYPE_DEBUG,
3388 "Destroying session of `%s' with %s due to network-level disconnect.\n",
3389 GNUNET_i2s (&session->target),
3390 tcp_plugin_address_to_string (session->plugin,
3391 session->address->address,
3392 session->address->address_length));
3394 if (plugin->cur_connections == plugin->max_connections)
3396 GNUNET_STATISTICS_update (session->plugin->env->stats,
3397 gettext_noop ("# TCP service resumed"),
3400 GNUNET_SERVER_resume (plugin->server); /* Resume server */
3402 GNUNET_STATISTICS_set (plugin->env->stats,
3403 gettext_noop ("# TCP server connections active"),
3404 plugin->cur_connections,
3406 GNUNET_STATISTICS_update (session->plugin->env->stats,
3408 "# network-level TCP disconnect events"),
3411 tcp_plugin_disconnect_session (plugin, session);
3416 * We can now send a probe message, copy into buffer to really send.
3418 * @param cls closure, a `struct TCPProbeContext`
3419 * @param size max size to copy
3420 * @param buf buffer to copy message to
3421 * @return number of bytes copied into @a buf
3424 notify_send_probe (void *cls, size_t size, void *buf)
3426 struct TCPProbeContext *tcp_probe_ctx = cls;
3427 struct Plugin *plugin = tcp_probe_ctx->plugin;
3430 tcp_probe_ctx->transmit_handle = NULL;
3431 GNUNET_CONTAINER_DLL_remove (plugin->probe_head,
3436 GNUNET_CONNECTION_destroy (tcp_probe_ctx->sock);
3437 GNUNET_free (tcp_probe_ctx);
3440 GNUNET_assert (size >= sizeof (tcp_probe_ctx->message));
3441 GNUNET_memcpy (buf, &tcp_probe_ctx->message, sizeof (tcp_probe_ctx->message));
3442 GNUNET_SERVER_connect_socket (tcp_probe_ctx->plugin->server,
3443 tcp_probe_ctx->sock);
3444 ret = sizeof (tcp_probe_ctx->message);
3445 GNUNET_free (tcp_probe_ctx);
3451 * Function called by the NAT subsystem suggesting another peer wants
3452 * to connect to us via connection reversal. Try to connect back to the
3455 * @param cls closure
3456 * @param addr address to try
3457 * @param addrlen number of bytes in @a addr
3460 try_connection_reversal (void *cls,
3461 const struct sockaddr *addr,
3464 struct Plugin *plugin = cls;
3465 struct GNUNET_CONNECTION_Handle *sock;
3466 struct TCPProbeContext *tcp_probe_ctx;
3469 * We have received an ICMP response, ostensibly from a peer
3470 * that wants to connect to us! Send a message to establish a connection.
3472 sock = GNUNET_CONNECTION_create_from_sockaddr (AF_INET, addr, addrlen);
3475 /* failed for some odd reason (out of sockets?); ignore attempt */
3479 tcp_probe_ctx = GNUNET_new (struct TCPProbeContext);
3480 tcp_probe_ctx->message.header.size =
3481 htons (sizeof (struct TCP_NAT_ProbeMessage));
3482 tcp_probe_ctx->message.header.type =
3483 htons (GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_NAT_PROBE);
3484 tcp_probe_ctx->message.clientIdentity = *plugin->env->my_identity;
3485 tcp_probe_ctx->plugin = plugin;
3486 tcp_probe_ctx->sock = sock;
3487 GNUNET_CONTAINER_DLL_insert (plugin->probe_head,
3490 tcp_probe_ctx->transmit_handle =
3491 GNUNET_CONNECTION_notify_transmit_ready (sock,
3492 ntohs (tcp_probe_ctx->message
3494 GNUNET_TIME_UNIT_FOREVER_REL,
3501 * Function obtain the network type for a session
3503 * @param cls closure (`struct Plugin *`)
3504 * @param session the session
3505 * @return the network type in HBO or #GNUNET_SYSERR
3507 static enum GNUNET_NetworkType
3508 tcp_plugin_get_network (void *cls, struct GNUNET_ATS_Session *session)
3510 return session->scope;
3515 * Function obtain the network type for an address.
3517 * @param cls closure (`struct Plugin *`)
3518 * @param address the address
3519 * @return the network type
3521 static enum GNUNET_NetworkType
3522 tcp_plugin_get_network_for_address (void *cls,
3523 const struct GNUNET_HELLO_Address *address)
3525 struct Plugin *plugin = cls;
3527 struct sockaddr_in a4;
3528 struct sockaddr_in6 a6;
3529 const struct IPv4TcpAddress *t4;
3530 const struct IPv6TcpAddress *t6;
3534 addrlen = address->address_length;
3535 if (addrlen == sizeof (struct IPv6TcpAddress))
3537 GNUNET_assert (NULL != address->address); /* make static analysis happy */
3538 t6 = address->address;
3539 memset (&a6, 0, sizeof (a6));
3540 #if HAVE_SOCKADDR_IN_SIN_LEN
3541 a6.sin6_len = sizeof (a6);
3543 a6.sin6_family = AF_INET6;
3544 a6.sin6_port = t6->t6_port;
3545 GNUNET_memcpy (&a6.sin6_addr, &t6->ipv6_addr, sizeof (struct in6_addr));
3549 else if (addrlen == sizeof (struct IPv4TcpAddress))
3551 GNUNET_assert (NULL != address->address); /* make static analysis happy */
3552 t4 = address->address;
3553 memset (&a4, 0, sizeof (a4));
3554 #if HAVE_SOCKADDR_IN_SIN_LEN
3555 a4.sin_len = sizeof (a4);
3557 a4.sin_family = AF_INET;
3558 a4.sin_port = t4->t4_port;
3559 a4.sin_addr.s_addr = t4->ipv4_addr;
3566 return GNUNET_NT_UNSPECIFIED;
3568 return plugin->env->get_address_type (plugin->env->cls, sb, sbs);
3573 * Return information about the given session to the
3576 * @param cls the `struct Plugin` with the monitor callback (`sic`)
3577 * @param peer peer we send information about
3578 * @param value our `struct GNUNET_ATS_Session` to send information about
3579 * @return #GNUNET_OK (continue to iterate)
3582 send_session_info_iter (void *cls,
3583 const struct GNUNET_PeerIdentity *peer,
3586 struct Plugin *plugin = cls;
3587 struct GNUNET_ATS_Session *session = value;
3589 notify_session_monitor (plugin, session, GNUNET_TRANSPORT_SS_INIT);
3590 /* FIXME: cannot tell if this is up or not from current
3592 notify_session_monitor (plugin, session, GNUNET_TRANSPORT_SS_UP);
3598 * Begin monitoring sessions of a plugin. There can only
3599 * be one active monitor per plugin (i.e. if there are
3600 * multiple monitors, the transport service needs to
3601 * multiplex the generated events over all of them).
3603 * @param cls closure of the plugin
3604 * @param sic callback to invoke, NULL to disable monitor;
3605 * plugin will being by iterating over all active
3606 * sessions immediately and then enter monitor mode
3607 * @param sic_cls closure for @a sic
3610 tcp_plugin_setup_monitor (void *cls,
3611 GNUNET_TRANSPORT_SessionInfoCallback sic,
3614 struct Plugin *plugin = cls;
3617 plugin->sic_cls = sic_cls;
3620 GNUNET_CONTAINER_multipeermap_iterate (plugin->sessionmap,
3621 &send_session_info_iter,
3623 /* signal end of first iteration */
3624 sic (sic_cls, NULL, NULL);
3630 * Entry point for the plugin.
3632 * @param cls closure, the `struct GNUNET_TRANSPORT_PluginEnvironment *`
3633 * @return the `struct GNUNET_TRANSPORT_PluginFunctions *` or NULL on error
3636 libgnunet_plugin_transport_tcp_init (void *cls)
3638 static const struct GNUNET_SERVER_MessageHandler my_handlers[] =
3639 {{&handle_tcp_welcome,
3641 GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_WELCOME,
3642 sizeof (struct WelcomeMessage)},
3643 {&handle_tcp_nat_probe,
3645 GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_NAT_PROBE,
3646 sizeof (struct TCP_NAT_ProbeMessage)},
3647 {&handle_tcp_data, NULL, GNUNET_MESSAGE_TYPE_ALL, 0},
3648 {NULL, NULL, 0, 0}};
3649 struct GNUNET_TRANSPORT_PluginEnvironment *env = cls;
3650 struct GNUNET_TRANSPORT_PluginFunctions *api;
3651 struct Plugin *plugin;
3652 struct LEGACY_SERVICE_Context *service;
3653 unsigned long long aport;
3654 unsigned long long bport;
3655 unsigned long long max_connections;
3657 struct GNUNET_TIME_Relative idle_timeout;
3659 struct GNUNET_NETWORK_Handle *const *lsocks;
3663 struct sockaddr **addrs;
3664 socklen_t *addrlens;
3666 if (NULL == env->receive)
3668 /* run in 'stub' mode (i.e. as part of gnunet-peerinfo), don't fully
3669 initialze the plugin or the API */
3670 api = GNUNET_new (struct GNUNET_TRANSPORT_PluginFunctions);
3672 api->address_pretty_printer = &tcp_plugin_address_pretty_printer;
3673 api->address_to_string = &tcp_plugin_address_to_string;
3674 api->string_to_address = &tcp_plugin_string_to_address;
3678 GNUNET_assert (NULL != env->cfg);
3679 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (env->cfg,
3683 max_connections = 128;
3686 if ((GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (env->cfg,
3691 ((GNUNET_OK == GNUNET_CONFIGURATION_get_value_number (env->cfg,
3697 LOG (GNUNET_ERROR_TYPE_ERROR,
3698 _ ("Require valid port number for service `%s' in configuration!\n"),
3708 service = LEGACY_SERVICE_start ("transport-tcp",
3710 LEGACY_SERVICE_OPTION_NONE);
3711 if (NULL == service)
3713 LOG (GNUNET_ERROR_TYPE_WARNING, _ ("Failed to start service.\n"));
3721 plugin = GNUNET_new (struct Plugin);
3722 plugin->sessionmap =
3723 GNUNET_CONTAINER_multipeermap_create (max_connections, GNUNET_YES);
3724 plugin->max_connections = max_connections;
3725 plugin->open_port = bport;
3726 plugin->adv_port = aport;
3728 plugin->my_welcome.header.size = htons (sizeof (struct WelcomeMessage));
3729 plugin->my_welcome.header.type =
3730 htons (GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_WELCOME);
3731 plugin->my_welcome.clientIdentity = *plugin->env->my_identity;
3733 if ((NULL != service) &&
3734 (GNUNET_YES == GNUNET_CONFIGURATION_get_value_yesno (env->cfg,
3739 plugin->myoptions |= TCP_OPTIONS_TCP_STEALTH;
3740 lsocks = LEGACY_SERVICE_get_listen_sockets (service);
3743 uint32_t len = sizeof (struct WelcomeMessage);
3745 for (i = 0; NULL != lsocks[i]; i++)
3749 GNUNET_NETWORK_socket_setsockopt (lsocks[i],
3754 struct GNUNET_PeerIdentity))) ||
3756 GNUNET_NETWORK_socket_setsockopt (lsocks[i],
3758 TCP_STEALTH_INTEGRITY_LEN,
3762 /* TCP STEALTH not supported by kernel */
3763 GNUNET_assert (0 == i);
3764 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3765 _ ("TCP_STEALTH not supported on this platform.\n"));
3771 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3772 _ ("TCP_STEALTH not supported on this platform.\n"));
3777 if ((NULL != service) &&
3780 get_server_addresses ("transport-tcp", env->cfg, &addrs, &addrlens))))
3782 for (ret = ret_s - 1; ret >= 0; ret--)
3783 LOG (GNUNET_ERROR_TYPE_INFO,
3784 "Binding to address `%s'\n",
3785 GNUNET_a2s (addrs[ret], addrlens[ret]));
3786 plugin->nat = GNUNET_NAT_register (env->cfg,
3789 (unsigned int) ret_s,
3790 (const struct sockaddr **) addrs,
3792 &tcp_nat_port_map_callback,
3793 &try_connection_reversal,
3795 for (ret = ret_s - 1; ret >= 0; ret--)
3796 GNUNET_free (addrs[ret]);
3797 GNUNET_free_non_null (addrs);
3798 GNUNET_free_non_null (addrlens);
3802 plugin->nat = GNUNET_NAT_register (plugin->env->cfg,
3809 &try_connection_reversal,
3812 api = GNUNET_new (struct GNUNET_TRANSPORT_PluginFunctions);
3814 api->send = &tcp_plugin_send;
3815 api->get_session = &tcp_plugin_get_session;
3816 api->disconnect_session = &tcp_plugin_disconnect_session;
3817 api->query_keepalive_factor = &tcp_plugin_query_keepalive_factor;
3818 api->disconnect_peer = &tcp_plugin_disconnect;
3819 api->address_pretty_printer = &tcp_plugin_address_pretty_printer;
3820 api->check_address = &tcp_plugin_check_address;
3821 api->address_to_string = &tcp_plugin_address_to_string;
3822 api->string_to_address = &tcp_plugin_string_to_address;
3823 api->get_network = &tcp_plugin_get_network;
3824 api->get_network_for_address = &tcp_plugin_get_network_for_address;
3825 api->update_session_timeout = &tcp_plugin_update_session_timeout;
3826 api->update_inbound_delay = &tcp_plugin_update_inbound_delay;
3827 api->setup_monitor = &tcp_plugin_setup_monitor;
3828 plugin->service = service;
3829 if (NULL != service)
3831 plugin->server = LEGACY_SERVICE_get_server (service);
3835 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_time (env->cfg,
3840 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
3845 plugin->server = GNUNET_SERVER_create_with_sockets (NULL,
3851 plugin->handlers = GNUNET_malloc (sizeof (my_handlers));
3852 GNUNET_memcpy (plugin->handlers, my_handlers, sizeof (my_handlers));
3854 i < sizeof (my_handlers) / sizeof (struct GNUNET_SERVER_MessageHandler);
3856 plugin->handlers[i].callback_cls = plugin;
3858 GNUNET_SERVER_add_handlers (plugin->server, plugin->handlers);
3859 GNUNET_SERVER_connect_notify (plugin->server, &connect_notify, plugin);
3860 GNUNET_SERVER_disconnect_notify (plugin->server, &disconnect_notify, plugin);
3861 plugin->nat_wait_conns =
3862 GNUNET_CONTAINER_multipeermap_create (16, GNUNET_YES);
3864 LOG (GNUNET_ERROR_TYPE_INFO,
3865 _ ("TCP transport listening on port %llu\n"),
3868 LOG (GNUNET_ERROR_TYPE_INFO,
3869 _ ("TCP transport not listening on any port (client only)\n"));
3870 if ((aport != bport) && (0 != bport))
3871 LOG (GNUNET_ERROR_TYPE_INFO,
3872 _ ("TCP transport advertises itself as being on port %llu\n"),
3874 /* Initially set connections to 0 */
3875 GNUNET_STATISTICS_set (plugin->env->stats,
3876 gettext_noop ("# TCP sessions active"),
3882 if (NULL != plugin->nat)
3883 GNUNET_NAT_unregister (plugin->nat);
3884 GNUNET_CONTAINER_multipeermap_destroy (plugin->sessionmap);
3885 if (NULL != service)
3886 LEGACY_SERVICE_stop (service);
3887 GNUNET_free (plugin);
3888 GNUNET_free_non_null (api);
3894 * Exit point from the plugin.
3896 * @param cls the `struct GNUNET_TRANSPORT_PluginFunctions`
3900 libgnunet_plugin_transport_tcp_done (void *cls)
3902 struct GNUNET_TRANSPORT_PluginFunctions *api = cls;
3903 struct Plugin *plugin = api->cls;
3904 struct TCPProbeContext *tcp_probe;
3905 struct PrettyPrinterContext *cur;
3906 struct PrettyPrinterContext *next;
3913 LOG (GNUNET_ERROR_TYPE_DEBUG, "Shutting down TCP plugin\n");
3915 /* Removing leftover sessions */
3916 GNUNET_CONTAINER_multipeermap_iterate (plugin->sessionmap,
3917 &session_disconnect_it,
3919 /* Removing leftover NAT sessions */
3920 GNUNET_CONTAINER_multipeermap_iterate (plugin->nat_wait_conns,
3921 &session_disconnect_it,
3924 for (cur = plugin->ppc_dll_head; NULL != cur; cur = next)
3927 GNUNET_CONTAINER_DLL_remove (plugin->ppc_dll_head,
3928 plugin->ppc_dll_tail,
3930 GNUNET_RESOLVER_request_cancel (cur->resolver_handle);
3931 cur->asc (cur->asc_cls, NULL, GNUNET_OK);
3935 if (NULL != plugin->service)
3936 LEGACY_SERVICE_stop (plugin->service);
3938 GNUNET_SERVER_destroy (plugin->server);
3939 GNUNET_free (plugin->handlers);
3940 if (NULL != plugin->nat)
3941 GNUNET_NAT_unregister (plugin->nat);
3942 while (NULL != (tcp_probe = plugin->probe_head))
3944 GNUNET_CONTAINER_DLL_remove (plugin->probe_head,
3947 GNUNET_CONNECTION_destroy (tcp_probe->sock);
3948 GNUNET_free (tcp_probe);
3950 GNUNET_CONTAINER_multipeermap_destroy (plugin->nat_wait_conns);
3951 GNUNET_CONTAINER_multipeermap_destroy (plugin->sessionmap);
3952 GNUNET_break (0 == plugin->cur_connections);
3953 GNUNET_free (plugin);
3958 /* end of plugin_transport_tcp.c */