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,
407 * Return user context associated with the given client.
409 * @param client client to query
410 * @param type expected return type (i.e. 'struct Foo')
411 * @return pointer to user context of type 'type *'.
413 #define GNUNET_SERVER_client_get_user_context(client, type) \
414 (type *) GNUNET_SERVER_client_get_user_context_ (client, sizeof(type))
417 * Set user context to be associated with the given client.
419 * @param client client to query
420 * @param value pointer to user context
422 #define GNUNET_SERVER_client_set_user_context(client, value) \
423 GNUNET_SERVER_client_set_user_context_ (client, value, sizeof(*value))
427 * Notify us when the server has enough space to transmit
428 * a message of the given size to the given client.
430 * @param client client to transmit message to
431 * @param size requested amount of buffer space
432 * @param timeout after how long should we give up (and call
433 * notify with buf NULL and size 0)?
434 * @param callback function to call when space is available
435 * @param callback_cls closure for @a callback
436 * @return non-NULL if the notify callback was queued; can be used
437 * to cancel the request using
438 * #GNUNET_SERVER_notify_transmit_ready_cancel.
439 * NULL if we are already going to notify someone else (busy)
441 struct GNUNET_SERVER_TransmitHandle *
442 GNUNET_SERVER_notify_transmit_ready (
443 struct GNUNET_SERVER_Client *client,
445 struct GNUNET_TIME_Relative timeout,
446 GNUNET_CONNECTION_TransmitReadyNotify callback,
450 * Abort transmission request.
452 * @param th request to abort
455 GNUNET_SERVER_notify_transmit_ready_cancel (
456 struct GNUNET_SERVER_TransmitHandle *th);
460 * Notify the server that the given client handle should
461 * be kept (keeps the connection up if possible, increments
462 * the internal reference counter).
464 * @param client the client to keep
467 GNUNET_SERVER_client_keep (struct GNUNET_SERVER_Client *client);
471 * Notify the server that the given client handle is no
472 * longer required. Decrements the reference counter. If
473 * that counter reaches zero an inactive connection maybe
476 * @param client the client to drop
479 GNUNET_SERVER_client_drop (struct GNUNET_SERVER_Client *client);
483 * Function called by the service's run
484 * method to run service-specific setup code.
487 * @param server the initialized server
488 * @param cfg configuration to use
490 typedef void (*LEGACY_SERVICE_Main) (
492 struct GNUNET_SERVER_Handle *server,
493 const struct GNUNET_CONFIGURATION_Handle *cfg);
497 * Suspend accepting connections from the listen socket temporarily.
498 * Resume activity using #GNUNET_SERVER_resume.
500 * @param server server to stop accepting connections.
503 GNUNET_SERVER_suspend (struct GNUNET_SERVER_Handle *server);
506 * Notify us when the server has enough space to transmit
507 * a message of the given size to the given client.
509 * @param client client to transmit message to
510 * @param size requested amount of buffer space
511 * @param timeout after how long should we give up (and call
512 * notify with buf NULL and size 0)?
513 * @param callback function to call when space is available
514 * @param callback_cls closure for @a callback
515 * @return non-NULL if the notify callback was queued; can be used
516 * to cancel the request using
517 * #GNUNET_SERVER_notify_transmit_ready_cancel.
518 * NULL if we are already going to notify someone else (busy)
520 struct GNUNET_SERVER_TransmitHandle *
521 GNUNET_SERVER_notify_transmit_ready (
522 struct GNUNET_SERVER_Client *client,
524 struct GNUNET_TIME_Relative timeout,
525 GNUNET_CONNECTION_TransmitReadyNotify callback,
530 * Add a TCP socket-based connection to the set of handles managed by
531 * this server. Use this function for outgoing (P2P) connections that
532 * we initiated (and where this server should process incoming
535 * @param server the server to use
536 * @param connection the connection to manage (client must
537 * stop using this connection from now on)
538 * @return the client handle
540 struct GNUNET_SERVER_Client *
541 GNUNET_SERVER_connect_socket (struct GNUNET_SERVER_Handle *server,
542 struct GNUNET_CONNECTION_Handle *connection);
546 * Resume accepting connections from the listen socket.
548 * @param server server to resume accepting connections.
551 GNUNET_SERVER_resume (struct GNUNET_SERVER_Handle *server);
554 * Free resources held by this server.
556 * @param server server to destroy
559 GNUNET_SERVER_destroy (struct GNUNET_SERVER_Handle *server);
562 #include "tcp_connection_legacy.c"
563 #include "tcp_server_mst_legacy.c"
564 #include "tcp_server_legacy.c"
565 #include "tcp_service_legacy.c"
567 GNUNET_NETWORK_STRUCT_BEGIN
570 * Initial handshake message for a session.
572 struct WelcomeMessage
575 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_WELCOME.
577 struct GNUNET_MessageHeader header;
580 * Identity of the node connecting (TCP client)
582 struct GNUNET_PeerIdentity clientIdentity;
586 * Basically a WELCOME message, but with the purpose
587 * of giving the waiting peer a client handle to use
589 struct TCP_NAT_ProbeMessage
592 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_NAT_PROBE.
594 struct GNUNET_MessageHeader header;
597 * Identity of the sender of the message.
599 struct GNUNET_PeerIdentity clientIdentity;
601 GNUNET_NETWORK_STRUCT_END
604 * Context for sending a NAT probe via TCP.
606 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
647 TCP_OPTIONS_NONE = 0,
650 * See #HTTP_OPTIONS_VERIFY_CERTIFICATE.
652 TCP_OPTIONS_RESERVED = 1,
655 * Enable TCP Stealth-style port knocking.
657 TCP_OPTIONS_TCP_STEALTH = 2
660 GNUNET_NETWORK_STRUCT_BEGIN
663 * Network format for IPv4 addresses.
665 struct IPv4TcpAddress
668 * Optional options and flags for this address,
669 * see `enum TcpAddressOptions`
671 uint32_t options GNUNET_PACKED;
674 * IPv4 address, in network byte order.
676 uint32_t ipv4_addr GNUNET_PACKED;
679 * Port number, in network byte order.
681 uint16_t t4_port GNUNET_PACKED;
685 * Network format for IPv6 addresses.
687 struct IPv6TcpAddress
690 * Optional flags for this address
691 * see `enum TcpAddressOptions`
693 uint32_t options GNUNET_PACKED;
698 struct in6_addr ipv6_addr GNUNET_PACKED;
701 * Port number, in network byte order.
703 uint16_t t6_port GNUNET_PACKED;
705 GNUNET_NETWORK_STRUCT_END
708 * Encapsulation of all of the state of the plugin.
713 * Information kept for each message that is yet to
716 struct PendingMessage
719 * This is a doubly-linked list.
721 struct PendingMessage *next;
724 * This is a doubly-linked list.
726 struct PendingMessage *prev;
729 * The pending message
734 * Continuation function to call once the message
735 * has been sent. Can be NULL if there is no
736 * continuation to call.
738 GNUNET_TRANSPORT_TransmitContinuation transmit_cont;
741 * Closure for @e transmit_cont.
743 void *transmit_cont_cls;
746 * Timeout value for the pending message.
748 struct GNUNET_TIME_Absolute timeout;
751 * So that the gnunet-service-transport can group messages together,
752 * these pending messages need to accept a message buffer and size
753 * instead of just a `struct GNUNET_MessageHeader`.
759 * Session handle for TCP connections.
761 struct GNUNET_ATS_Session
764 * To whom are we talking to (set to our identity
765 * if we are still waiting for the welcome message)
767 struct GNUNET_PeerIdentity target;
770 * Pointer to the global plugin struct.
772 struct Plugin *plugin;
775 * The client (used to identify this connection)
777 struct GNUNET_SERVER_Client *client;
780 * Task cleaning up a NAT client connection establishment attempt;
782 struct GNUNET_SCHEDULER_Task *nat_connection_timeout;
785 * Messages currently pending for transmission
786 * to this peer, if any.
788 struct PendingMessage *pending_messages_head;
791 * Messages currently pending for transmission
792 * to this peer, if any.
794 struct PendingMessage *pending_messages_tail;
797 * Handle for pending transmission request.
799 struct GNUNET_SERVER_TransmitHandle *transmit_handle;
802 * Address of the other peer.
804 struct GNUNET_HELLO_Address *address;
807 * ID of task used to delay receiving more to throttle sender.
809 struct GNUNET_SCHEDULER_Task *receive_delay_task;
812 * Session timeout task
814 struct GNUNET_SCHEDULER_Task *timeout_task;
817 * When will this session time out?
819 struct GNUNET_TIME_Absolute timeout;
822 * When will we continue to read from the socket?
823 * (used to enforce inbound quota).
825 struct GNUNET_TIME_Absolute receive_delay;
828 * Last activity on this connection. Used to select preferred
831 struct GNUNET_TIME_Absolute last_activity;
834 * Number of bytes waiting for transmission to this peer.
836 unsigned long long bytes_in_queue;
839 * Number of messages waiting for transmission to this peer.
841 unsigned int msgs_in_queue;
844 * Network type of the address.
846 enum GNUNET_NetworkType scope;
849 * Are we still expecting the welcome message? (#GNUNET_YES/#GNUNET_NO)
851 int expecting_welcome;
854 * Was this session created using NAT traversal?
861 * Context for address to string conversion, closure
862 * for #append_port().
864 struct PrettyPrinterContext
869 struct PrettyPrinterContext *next;
874 struct PrettyPrinterContext *prev;
879 struct Plugin *plugin;
884 struct GNUNET_SCHEDULER_Task *timeout_task;
889 struct GNUNET_RESOLVER_RequestHandle *resolver_handle;
892 * Function to call with the result.
894 GNUNET_TRANSPORT_AddressStringCallback asc;
897 * Clsoure for @e asc.
912 * Port to add after the IP address.
919 * Encapsulation of all of the state of the plugin.
926 struct GNUNET_TRANSPORT_PluginEnvironment *env;
931 struct GNUNET_CONNECTION_Handle *lsock;
934 * Our handle to the NAT module.
936 struct GNUNET_NAT_Handle *nat;
939 * Map from peer identities to sessions for the given peer.
941 struct GNUNET_CONTAINER_MultiPeerMap *sessionmap;
944 * Handle to the network service.
946 struct LEGACY_SERVICE_Context *service;
949 * Handle to the server for this service.
951 struct GNUNET_SERVER_Handle *server;
954 * Copy of the handler array where the closures are
955 * set to this struct's instance.
957 struct GNUNET_SERVER_MessageHandler *handlers;
960 * Map of peers we have tried to contact behind a NAT
962 struct GNUNET_CONTAINER_MultiPeerMap *nat_wait_conns;
965 * List of active TCP probes.
967 struct TCPProbeContext *probe_head;
970 * List of active TCP probes.
972 struct TCPProbeContext *probe_tail;
975 * Function to call about session status changes.
977 GNUNET_TRANSPORT_SessionInfoCallback sic;
980 * Closure for @e sic.
985 * ID of task used to update our addresses when one expires.
987 struct GNUNET_SCHEDULER_Task *address_update_task;
990 * Running pretty printers: head
992 struct PrettyPrinterContext *ppc_dll_head;
995 * Running pretty printers: tail
997 struct PrettyPrinterContext *ppc_dll_tail;
1000 * Welcome message used by this peer.
1002 struct WelcomeMessage my_welcome;
1005 * How many more TCP sessions are we allowed to open right now?
1007 unsigned long long max_connections;
1010 * How many more TCP sessions do we have right now?
1012 unsigned long long cur_connections;
1020 * Port that we are actually listening on.
1025 * Port that the user said we would have visible to the
1026 * rest of the world.
1033 * Get the list of addresses that a server for the given service
1036 * @param service_name name of the service
1037 * @param cfg configuration (which specifies the addresses)
1038 * @param addrs set (call by reference) to an array of pointers to the
1039 * addresses the server should bind to and listen on; the
1040 * array will be NULL-terminated (on success)
1041 * @param addr_lens set (call by reference) to an array of the lengths
1042 * of the respective `struct sockaddr` struct in the @a addrs
1043 * array (on success)
1044 * @return number of addresses found on success,
1045 * #GNUNET_SYSERR if the configuration
1046 * did not specify reasonable finding information or
1047 * if it specified a hostname that could not be resolved;
1048 * #GNUNET_NO if the number of addresses configured is
1049 * zero (in this case, `*addrs` and `*addr_lens` will be
1053 get_server_addresses (const char *service_name,
1054 const struct GNUNET_CONFIGURATION_Handle *cfg,
1055 struct sockaddr ***addrs,
1056 socklen_t **addr_lens)
1059 struct GNUNET_NETWORK_Handle *desc;
1060 unsigned long long port;
1062 struct addrinfo hints;
1063 struct addrinfo *res;
1064 struct addrinfo *pos;
1065 struct addrinfo *next;
1070 struct sockaddr **saddrs;
1071 socklen_t *saddrlens;
1077 if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "DISABLEV6"))
1079 if (GNUNET_SYSERR ==
1080 (disablev6 = GNUNET_CONFIGURATION_get_value_yesno (cfg,
1083 return GNUNET_SYSERR;
1086 disablev6 = GNUNET_NO;
1090 /* probe IPv6 support */
1091 desc = GNUNET_NETWORK_socket_create (PF_INET6, SOCK_STREAM, 0);
1094 if ((ENOBUFS == errno) || (ENOMEM == errno) || (ENFILE == errno) ||
1097 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "socket");
1098 return GNUNET_SYSERR;
1100 LOG (GNUNET_ERROR_TYPE_INFO,
1102 "Disabling IPv6 support for service `%s', failed to create IPv6 socket: %s\n"),
1105 disablev6 = GNUNET_YES;
1109 GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (desc));
1115 if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "PORT"))
1117 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (cfg,
1122 LOG (GNUNET_ERROR_TYPE_ERROR,
1123 _ ("Require valid port number for service `%s' in configuration!\n"),
1128 LOG (GNUNET_ERROR_TYPE_ERROR,
1129 _ ("Require valid port number for service `%s' in configuration!\n"),
1131 return GNUNET_SYSERR;
1135 if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "BINDTO"))
1137 GNUNET_break (GNUNET_OK ==
1138 GNUNET_CONFIGURATION_get_value_string (cfg,
1147 abstract = GNUNET_NO;
1150 GNUNET_CONFIGURATION_have_value (cfg, service_name, "UNIXPATH")) &&
1151 (GNUNET_OK == GNUNET_CONFIGURATION_get_value_filename (cfg,
1155 (0 < strlen (unixpath)))
1157 /* probe UNIX support */
1158 struct sockaddr_un s_un;
1160 if (strlen (unixpath) >= sizeof(s_un.sun_path))
1162 LOG (GNUNET_ERROR_TYPE_WARNING,
1163 _ ("UNIXPATH `%s' too long, maximum length is %llu\n"),
1165 (unsigned long long) sizeof(s_un.sun_path));
1166 unixpath = GNUNET_NETWORK_shorten_unixpath (unixpath);
1167 LOG (GNUNET_ERROR_TYPE_INFO, _ ("Using `%s' instead\n"), unixpath);
1170 abstract = GNUNET_CONFIGURATION_get_value_yesno (cfg,
1172 "USE_ABSTRACT_SOCKETS");
1173 if (GNUNET_SYSERR == abstract)
1174 abstract = GNUNET_NO;
1176 if ((GNUNET_YES != abstract) &&
1177 (GNUNET_OK != GNUNET_DISK_directory_create_for_file (unixpath)))
1178 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "mkdir", unixpath);
1180 if (NULL != unixpath)
1182 desc = GNUNET_NETWORK_socket_create (AF_UNIX, SOCK_STREAM, 0);
1185 if ((ENOBUFS == errno) || (ENOMEM == errno) || (ENFILE == errno) ||
1188 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "socket");
1189 GNUNET_free_non_null (hostname);
1190 GNUNET_free (unixpath);
1191 return GNUNET_SYSERR;
1193 LOG (GNUNET_ERROR_TYPE_INFO,
1195 "Disabling UNIX domain socket support for service `%s', failed to create UNIX domain socket: %s\n"),
1198 GNUNET_free (unixpath);
1203 GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (desc));
1209 if ((0 == port) && (NULL == unixpath))
1211 LOG (GNUNET_ERROR_TYPE_ERROR,
1213 "Have neither PORT nor UNIXPATH for service `%s', but one is required\n"),
1215 GNUNET_free_non_null (hostname);
1216 return GNUNET_SYSERR;
1220 saddrs = GNUNET_malloc (2 * sizeof(struct sockaddr *));
1221 saddrlens = GNUNET_malloc (2 * sizeof(socklen_t));
1222 add_unixpath (saddrs, saddrlens, unixpath, abstract);
1223 GNUNET_free_non_null (unixpath);
1224 GNUNET_free_non_null (hostname);
1226 *addr_lens = saddrlens;
1230 if (NULL != hostname)
1232 LOG (GNUNET_ERROR_TYPE_DEBUG,
1233 "Resolving `%s' since that is where `%s' will bind to.\n",
1236 memset (&hints, 0, sizeof(struct addrinfo));
1238 hints.ai_family = AF_INET;
1239 hints.ai_protocol = IPPROTO_TCP;
1240 if ((0 != (ret = getaddrinfo (hostname, NULL, &hints, &res))) ||
1243 LOG (GNUNET_ERROR_TYPE_ERROR,
1244 _ ("Failed to resolve `%s': %s\n"),
1246 gai_strerror (ret));
1247 GNUNET_free (hostname);
1248 GNUNET_free_non_null (unixpath);
1249 return GNUNET_SYSERR;
1253 while (NULL != (pos = next))
1255 next = pos->ai_next;
1256 if ((disablev6) && (pos->ai_family == AF_INET6))
1262 LOG (GNUNET_ERROR_TYPE_ERROR,
1263 _ ("Failed to find %saddress for `%s'.\n"),
1264 disablev6 ? "IPv4 " : "",
1267 GNUNET_free (hostname);
1268 GNUNET_free_non_null (unixpath);
1269 return GNUNET_SYSERR;
1272 if (NULL != unixpath)
1274 saddrs = GNUNET_malloc ((resi + 1) * sizeof(struct sockaddr *));
1275 saddrlens = GNUNET_malloc ((resi + 1) * sizeof(socklen_t));
1277 if (NULL != unixpath)
1279 add_unixpath (saddrs, saddrlens, unixpath, abstract);
1283 while (NULL != (pos = next))
1285 next = pos->ai_next;
1286 if ((disablev6) && (AF_INET6 == pos->ai_family))
1288 if ((IPPROTO_TCP != pos->ai_protocol) && (0 != pos->ai_protocol))
1289 continue; /* not TCP */
1290 if ((SOCK_STREAM != pos->ai_socktype) && (0 != pos->ai_socktype))
1291 continue; /* huh? */
1292 LOG (GNUNET_ERROR_TYPE_DEBUG,
1293 "Service `%s' will bind to `%s'\n",
1295 GNUNET_a2s (pos->ai_addr, pos->ai_addrlen));
1296 if (AF_INET == pos->ai_family)
1298 GNUNET_assert (sizeof(struct sockaddr_in) == pos->ai_addrlen);
1299 saddrlens[i] = pos->ai_addrlen;
1300 saddrs[i] = GNUNET_malloc (saddrlens[i]);
1301 GNUNET_memcpy (saddrs[i], pos->ai_addr, saddrlens[i]);
1302 ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
1306 GNUNET_assert (AF_INET6 == pos->ai_family);
1307 GNUNET_assert (sizeof(struct sockaddr_in6) == pos->ai_addrlen);
1308 saddrlens[i] = pos->ai_addrlen;
1309 saddrs[i] = GNUNET_malloc (saddrlens[i]);
1310 GNUNET_memcpy (saddrs[i], pos->ai_addr, saddrlens[i]);
1311 ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port);
1315 GNUNET_free (hostname);
1321 /* will bind against everything, just set port */
1326 if (NULL != unixpath)
1329 saddrs = GNUNET_malloc ((resi + 1) * sizeof(struct sockaddr *));
1330 saddrlens = GNUNET_malloc ((resi + 1) * sizeof(socklen_t));
1331 if (NULL != unixpath)
1333 add_unixpath (saddrs, saddrlens, unixpath, abstract);
1336 saddrlens[i] = sizeof(struct sockaddr_in);
1337 saddrs[i] = GNUNET_malloc (saddrlens[i]);
1338 #if HAVE_SOCKADDR_IN_SIN_LEN
1339 ((struct sockaddr_in *) saddrs[i])->sin_len = saddrlens[i];
1341 ((struct sockaddr_in *) saddrs[i])->sin_family = AF_INET;
1342 ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
1348 if (NULL != unixpath)
1350 saddrs = GNUNET_malloc ((resi + 1) * sizeof(struct sockaddr *));
1351 saddrlens = GNUNET_malloc ((resi + 1) * sizeof(socklen_t));
1353 if (NULL != unixpath)
1355 add_unixpath (saddrs, saddrlens, unixpath, abstract);
1358 saddrlens[i] = sizeof(struct sockaddr_in6);
1359 saddrs[i] = GNUNET_malloc (saddrlens[i]);
1360 #if HAVE_SOCKADDR_IN_SIN_LEN
1361 ((struct sockaddr_in6 *) saddrs[i])->sin6_len = saddrlens[0];
1363 ((struct sockaddr_in6 *) saddrs[i])->sin6_family = AF_INET6;
1364 ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port);
1366 saddrlens[i] = sizeof(struct sockaddr_in);
1367 saddrs[i] = GNUNET_malloc (saddrlens[i]);
1368 #if HAVE_SOCKADDR_IN_SIN_LEN
1369 ((struct sockaddr_in *) saddrs[i])->sin_len = saddrlens[1];
1371 ((struct sockaddr_in *) saddrs[i])->sin_family = AF_INET;
1372 ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
1375 GNUNET_free_non_null (unixpath);
1377 *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;
1463 if (IN6_IS_ADDR_LINKLOCAL (&((struct sockaddr_in6 *) addr)->sin6_addr))
1465 /* skip link local, we don't allow them in
1466 #tcp_plugin_check_address() */
1469 GNUNET_assert (addrlen == sizeof(struct sockaddr_in6));
1470 memset (&t6, 0, sizeof(t6));
1471 GNUNET_memcpy (&t6.ipv6_addr,
1472 &((struct sockaddr_in6 *) addr)->sin6_addr,
1473 sizeof(struct in6_addr));
1474 t6.options = htonl (plugin->myoptions);
1475 t6.t6_port = ((struct sockaddr_in6 *) addr)->sin6_port;
1484 /* modify our published address list */
1485 GNUNET_assert ((args == sizeof(struct IPv4TcpAddress)) ||
1486 (args == sizeof(struct IPv6TcpAddress)));
1487 /* TODO: use 'ac' here in the future... */
1488 address = GNUNET_HELLO_address_allocate (plugin->env->my_identity,
1492 GNUNET_HELLO_ADDRESS_INFO_NONE);
1493 plugin->env->notify_address (plugin->env->cls, add_remove, address);
1494 GNUNET_HELLO_address_free (address);
1499 * Function called for a quick conversion of the binary address to
1500 * a numeric address. Note that the caller must not free the
1501 * address and that the next call to this function is allowed
1502 * to override the address again.
1504 * @param cls closure (`struct Plugin*`)
1505 * @param addr binary address
1506 * @param addrlen length of @a addr
1507 * @return string representing the same address
1510 tcp_plugin_address_to_string (void *cls, const void *addr, size_t addrlen)
1512 static char rbuf[INET6_ADDRSTRLEN + 12];
1513 char buf[INET6_ADDRSTRLEN];
1517 const struct IPv4TcpAddress *t4;
1518 const struct IPv6TcpAddress *t6;
1525 case sizeof(struct IPv6TcpAddress):
1528 port = ntohs (t6->t6_port);
1529 options = ntohl (t6->options);
1530 GNUNET_memcpy (&a6, &t6->ipv6_addr, sizeof(a6));
1534 case sizeof(struct IPv4TcpAddress):
1537 port = ntohs (t4->t4_port);
1538 options = ntohl (t4->options);
1539 GNUNET_memcpy (&a4, &t4->ipv4_addr, sizeof(a4));
1544 LOG (GNUNET_ERROR_TYPE_WARNING,
1545 _ ("Unexpected address length: %u bytes\n"),
1546 (unsigned int) addrlen);
1549 if (NULL == inet_ntop (af, sb, buf, INET6_ADDRSTRLEN))
1551 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "inet_ntop");
1554 GNUNET_snprintf (rbuf,
1556 (af == AF_INET6) ? "%s.%u.[%s]:%u" : "%s.%u.%s:%u",
1566 * Function called to convert a string address to
1569 * @param cls closure (`struct Plugin*`)
1570 * @param addr string address
1571 * @param addrlen length of the address
1572 * @param buf location to store the buffer
1573 * @param added location to store the number of bytes in the buffer.
1574 * If the function returns #GNUNET_SYSERR, its contents are undefined.
1575 * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure
1578 tcp_plugin_string_to_address (void *cls,
1584 struct sockaddr_storage socket_address;
1590 /* Format tcp.options.address:port */
1594 if ((NULL == addr) || (0 == addrlen))
1597 return GNUNET_SYSERR;
1599 if ('\0' != addr[addrlen - 1])
1602 return GNUNET_SYSERR;
1604 if (strlen (addr) != addrlen - 1)
1607 return GNUNET_SYSERR;
1609 plugin = GNUNET_strdup (addr);
1610 optionstr = strchr (plugin, '.');
1611 if (NULL == optionstr)
1614 GNUNET_free (plugin);
1615 return GNUNET_SYSERR;
1617 optionstr[0] = '\0';
1619 options = atol (optionstr);
1620 address = strchr (optionstr, '.');
1621 if (NULL == address)
1624 GNUNET_free (plugin);
1625 return GNUNET_SYSERR;
1631 GNUNET_STRINGS_to_address_ip (address, strlen (address), &socket_address))
1634 GNUNET_free (plugin);
1635 return GNUNET_SYSERR;
1638 GNUNET_free (plugin);
1639 switch (socket_address.ss_family)
1642 struct IPv4TcpAddress *t4;
1643 struct sockaddr_in *in4 = (struct sockaddr_in *) &socket_address;
1644 t4 = GNUNET_new (struct IPv4TcpAddress);
1645 t4->options = htonl (options);
1646 t4->ipv4_addr = in4->sin_addr.s_addr;
1647 t4->t4_port = in4->sin_port;
1649 *added = sizeof(struct IPv4TcpAddress);
1654 struct IPv6TcpAddress *t6;
1655 struct sockaddr_in6 *in6 = (struct sockaddr_in6 *) &socket_address;
1656 t6 = GNUNET_new (struct IPv6TcpAddress);
1657 t6->options = htonl (options);
1658 t6->ipv6_addr = in6->sin6_addr;
1659 t6->t6_port = in6->sin6_port;
1661 *added = sizeof(struct IPv6TcpAddress);
1666 return GNUNET_SYSERR;
1672 * Find the session handle for the given client.
1673 * Currently uses both the hashmap and the client
1674 * context, as the client context is new and the
1675 * logic still needs to be tested.
1677 * @param plugin the plugin
1678 * @param client which client to find the session handle for
1679 * @return NULL if no matching session exists
1681 static struct GNUNET_ATS_Session *
1682 lookup_session_by_client (struct Plugin *plugin,
1683 struct GNUNET_SERVER_Client *client)
1685 return GNUNET_SERVER_client_get_user_context (client,
1686 struct GNUNET_ATS_Session);
1691 * Functions with this signature are called whenever we need
1692 * to close a session due to a disconnect or failure to
1693 * establish a connection.
1695 * @param cls the `struct Plugin`
1696 * @param session session to close down
1697 * @return #GNUNET_OK on success
1700 tcp_plugin_disconnect_session (void *cls, struct GNUNET_ATS_Session *session)
1702 struct Plugin *plugin = cls;
1703 struct PendingMessage *pm;
1705 LOG (GNUNET_ERROR_TYPE_DEBUG,
1706 "Disconnecting session of peer `%s' address `%s'\n",
1707 GNUNET_i2s (&session->target),
1708 tcp_plugin_address_to_string (session->plugin,
1709 session->address->address,
1710 session->address->address_length));
1712 if (NULL != session->timeout_task)
1714 GNUNET_SCHEDULER_cancel (session->timeout_task);
1715 session->timeout_task = NULL;
1716 session->timeout = GNUNET_TIME_UNIT_ZERO_ABS;
1719 if (GNUNET_YES == GNUNET_CONTAINER_multipeermap_remove (plugin->sessionmap,
1723 GNUNET_STATISTICS_update (session->plugin->env->stats,
1724 gettext_noop ("# TCP sessions active"),
1730 GNUNET_assert (GNUNET_YES ==
1731 GNUNET_CONTAINER_multipeermap_remove (plugin->nat_wait_conns,
1735 if (NULL != session->client)
1736 GNUNET_SERVER_client_set_user_context (session->client, NULL);
1738 /* clean up state */
1739 if (NULL != session->transmit_handle)
1741 GNUNET_SERVER_notify_transmit_ready_cancel (session->transmit_handle);
1742 session->transmit_handle = NULL;
1744 session->plugin->env->session_end (session->plugin->env->cls,
1748 if (NULL != session->nat_connection_timeout)
1750 GNUNET_SCHEDULER_cancel (session->nat_connection_timeout);
1751 session->nat_connection_timeout = NULL;
1754 while (NULL != (pm = session->pending_messages_head))
1756 LOG (GNUNET_ERROR_TYPE_DEBUG,
1757 (NULL != pm->transmit_cont)
1758 ? "Could not deliver message to `%s' at %s.\n"
1759 : "Could not deliver message to `%s' at %s, notifying.\n",
1760 GNUNET_i2s (&session->target),
1761 tcp_plugin_address_to_string (session->plugin,
1762 session->address->address,
1763 session->address->address_length));
1764 GNUNET_STATISTICS_update (session->plugin->env->stats,
1765 gettext_noop ("# bytes currently in TCP buffers"),
1766 -(int64_t) pm->message_size,
1768 GNUNET_STATISTICS_update (session->plugin->env->stats,
1770 "# bytes discarded by TCP (disconnect)"),
1773 GNUNET_CONTAINER_DLL_remove (session->pending_messages_head,
1774 session->pending_messages_tail,
1776 GNUNET_assert (0 < session->msgs_in_queue);
1777 session->msgs_in_queue--;
1778 GNUNET_assert (pm->message_size <= session->bytes_in_queue);
1779 session->bytes_in_queue -= pm->message_size;
1780 if (NULL != pm->transmit_cont)
1781 pm->transmit_cont (pm->transmit_cont_cls,
1788 GNUNET_assert (0 == session->msgs_in_queue);
1789 GNUNET_assert (0 == session->bytes_in_queue);
1790 notify_session_monitor (session->plugin, session, GNUNET_TRANSPORT_SS_DONE);
1792 if (NULL != session->receive_delay_task)
1794 GNUNET_SCHEDULER_cancel (session->receive_delay_task);
1795 session->receive_delay_task = NULL;
1797 if (NULL != session->client)
1799 GNUNET_SERVER_client_disconnect (session->client);
1800 session->client = NULL;
1802 GNUNET_HELLO_address_free (session->address);
1803 GNUNET_assert (NULL == session->transmit_handle);
1804 GNUNET_free (session);
1810 * Function that is called to get the keepalive factor.
1811 * #GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT is divided by this number to
1812 * calculate the interval between keepalive packets.
1814 * @param cls closure with the `struct Plugin`
1815 * @return keepalive factor
1818 tcp_plugin_query_keepalive_factor (void *cls)
1825 * Session was idle for too long, so disconnect it
1827 * @param cls the `struct GNUNET_ATS_Session` of the idle session
1830 session_timeout (void *cls)
1832 struct GNUNET_ATS_Session *s = cls;
1833 struct GNUNET_TIME_Relative left;
1835 s->timeout_task = NULL;
1836 left = GNUNET_TIME_absolute_get_remaining (s->timeout);
1837 if (0 != left.rel_value_us)
1839 /* not actually our turn yet, but let's at least update
1840 the monitor, it may think we're about to die ... */
1841 notify_session_monitor (s->plugin, s, GNUNET_TRANSPORT_SS_UPDATE);
1842 s->timeout_task = GNUNET_SCHEDULER_add_delayed (left, &session_timeout, s);
1845 LOG (GNUNET_ERROR_TYPE_DEBUG,
1846 "Session %p was idle for %s, disconnecting\n",
1848 GNUNET_STRINGS_relative_time_to_string (
1849 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
1851 /* call session destroy function */
1852 tcp_plugin_disconnect_session (s->plugin, s);
1857 * Increment session timeout due to activity.
1859 * @param s session to increment timeout for
1862 reschedule_session_timeout (struct GNUNET_ATS_Session *s)
1864 GNUNET_assert (NULL != s->timeout_task);
1866 GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1871 * Create a new session. Also queues a welcome message.
1873 * @param plugin the plugin
1874 * @param address the address to create the session for
1875 * @param scope network scope the address is from
1876 * @param client client to use, reference counter must have already been increased
1877 * @param is_nat this a NAT session, we should wait for a client to
1878 * connect to us from an address, then assign that to
1880 * @return new session object
1882 static struct GNUNET_ATS_Session *
1883 create_session (struct Plugin *plugin,
1884 const struct GNUNET_HELLO_Address *address,
1885 enum GNUNET_NetworkType scope,
1886 struct GNUNET_SERVER_Client *client,
1889 struct GNUNET_ATS_Session *session;
1890 struct PendingMessage *pm;
1892 if (GNUNET_YES != is_nat)
1893 GNUNET_assert (NULL != client);
1895 GNUNET_assert (NULL == client);
1897 LOG (GNUNET_ERROR_TYPE_DEBUG,
1898 "Creating new session for peer `%s' at address %s\n",
1899 GNUNET_i2s (&address->peer),
1900 tcp_plugin_address_to_string (plugin,
1902 address->address_length));
1903 session = GNUNET_new (struct GNUNET_ATS_Session);
1904 session->last_activity = GNUNET_TIME_absolute_get ();
1905 session->plugin = plugin;
1906 session->is_nat = is_nat;
1909 session->client = client;
1910 GNUNET_SERVER_client_set_user_context (client, session);
1912 session->address = GNUNET_HELLO_address_copy (address);
1913 session->target = address->peer;
1914 session->expecting_welcome = GNUNET_YES;
1915 session->scope = scope;
1916 pm = GNUNET_malloc (sizeof(struct PendingMessage)
1917 + sizeof(struct WelcomeMessage));
1918 pm->msg = (const char *) &pm[1];
1919 pm->message_size = sizeof(struct WelcomeMessage);
1920 GNUNET_memcpy (&pm[1], &plugin->my_welcome, sizeof(struct WelcomeMessage));
1921 pm->timeout = GNUNET_TIME_UNIT_FOREVER_ABS;
1922 GNUNET_STATISTICS_update (plugin->env->stats,
1923 gettext_noop ("# bytes currently in TCP buffers"),
1926 GNUNET_CONTAINER_DLL_insert (session->pending_messages_head,
1927 session->pending_messages_tail,
1929 session->msgs_in_queue++;
1930 session->bytes_in_queue += pm->message_size;
1932 GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1933 session->timeout_task =
1934 GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
1937 notify_session_monitor (session->plugin, session, GNUNET_TRANSPORT_SS_INIT);
1938 if (GNUNET_YES != is_nat)
1940 GNUNET_STATISTICS_update (plugin->env->stats,
1941 gettext_noop ("# TCP sessions active"),
1944 notify_session_monitor (session->plugin, session, GNUNET_TRANSPORT_SS_UP);
1948 notify_session_monitor (session->plugin,
1950 GNUNET_TRANSPORT_SS_HANDSHAKE);
1957 * If we have pending messages, ask the server to
1958 * transmit them (schedule the respective tasks, etc.)
1960 * @param session for which session should we do this
1963 process_pending_messages (struct GNUNET_ATS_Session *session);
1967 * Function called to notify a client about the socket
1968 * being ready to queue more data. "buf" will be
1969 * NULL and "size" zero if the socket was closed for
1970 * writing in the meantime.
1972 * @param cls closure
1973 * @param size number of bytes available in @a buf
1974 * @param buf where the callee should write the message
1975 * @return number of bytes written to @a buf
1978 do_transmit (void *cls, size_t size, void *buf)
1980 struct GNUNET_ATS_Session *session = cls;
1981 struct GNUNET_PeerIdentity pid;
1982 struct Plugin *plugin;
1983 struct PendingMessage *pos;
1984 struct PendingMessage *hd;
1985 struct PendingMessage *tl;
1986 struct GNUNET_TIME_Absolute now;
1990 session->transmit_handle = NULL;
1991 plugin = session->plugin;
1994 LOG (GNUNET_ERROR_TYPE_DEBUG,
1995 "Timeout trying to transmit to peer `%s', discarding message queue.\n",
1996 GNUNET_i2s (&session->target));
1997 /* timeout; cancel all messages that have already expired */
2001 now = GNUNET_TIME_absolute_get ();
2002 while ((NULL != (pos = session->pending_messages_head)) &&
2003 (pos->timeout.abs_value_us <= now.abs_value_us))
2005 GNUNET_CONTAINER_DLL_remove (session->pending_messages_head,
2006 session->pending_messages_tail,
2008 GNUNET_assert (0 < session->msgs_in_queue);
2009 session->msgs_in_queue--;
2010 GNUNET_assert (pos->message_size <= session->bytes_in_queue);
2011 session->bytes_in_queue -= pos->message_size;
2012 LOG (GNUNET_ERROR_TYPE_DEBUG,
2013 "Failed to transmit %u byte message to `%s'.\n",
2015 GNUNET_i2s (&session->target));
2016 ret += pos->message_size;
2017 GNUNET_CONTAINER_DLL_insert_after (hd, tl, tl, pos);
2019 /* do this call before callbacks (so that if callbacks destroy
2020 * session, they have a chance to cancel actions done by this
2022 process_pending_messages (session);
2023 pid = session->target;
2024 /* no do callbacks and do not use session again since
2025 * the callbacks may abort the session */
2026 while (NULL != (pos = hd))
2028 GNUNET_CONTAINER_DLL_remove (hd, tl, pos);
2029 if (NULL != pos->transmit_cont)
2030 pos->transmit_cont (pos->transmit_cont_cls,
2037 GNUNET_STATISTICS_update (plugin->env->stats,
2038 gettext_noop ("# bytes currently in TCP buffers"),
2041 GNUNET_STATISTICS_update (plugin->env->stats,
2043 "# bytes discarded by TCP (timeout)"),
2047 notify_session_monitor (session->plugin,
2049 GNUNET_TRANSPORT_SS_UPDATE);
2052 /* copy all pending messages that would fit */
2057 while (NULL != (pos = session->pending_messages_head))
2059 if (ret + pos->message_size > size)
2061 GNUNET_CONTAINER_DLL_remove (session->pending_messages_head,
2062 session->pending_messages_tail,
2064 GNUNET_assert (0 < session->msgs_in_queue);
2065 session->msgs_in_queue--;
2066 GNUNET_assert (pos->message_size <= session->bytes_in_queue);
2067 session->bytes_in_queue -= pos->message_size;
2068 GNUNET_assert (size >= pos->message_size);
2069 LOG (GNUNET_ERROR_TYPE_DEBUG,
2070 "Transmitting message of type %u size %u to peer %s at %s\n",
2071 ntohs (((struct GNUNET_MessageHeader *) pos->msg)->type),
2073 GNUNET_i2s (&session->target),
2074 tcp_plugin_address_to_string (session->plugin,
2075 session->address->address,
2076 session->address->address_length));
2077 /* FIXME: this GNUNET_memcpy can be up to 7% of our total runtime */
2078 GNUNET_memcpy (cbuf, pos->msg, pos->message_size);
2079 cbuf += pos->message_size;
2080 ret += pos->message_size;
2081 size -= pos->message_size;
2082 GNUNET_CONTAINER_DLL_insert_tail (hd, tl, pos);
2084 notify_session_monitor (session->plugin, session, GNUNET_TRANSPORT_SS_UPDATE);
2085 /* schedule 'continuation' before callbacks so that callbacks that
2086 * cancel everything don't cause us to use a session that no longer
2088 process_pending_messages (session);
2089 session->last_activity = GNUNET_TIME_absolute_get ();
2090 pid = session->target;
2091 /* we'll now call callbacks that may cancel the session; hence
2092 * we should not use 'session' after this point */
2093 while (NULL != (pos = hd))
2095 GNUNET_CONTAINER_DLL_remove (hd, tl, pos);
2096 if (NULL != pos->transmit_cont)
2097 pos->transmit_cont (pos->transmit_cont_cls,
2101 pos->message_size); /* FIXME: include TCP overhead */
2104 GNUNET_assert (NULL == hd);
2105 GNUNET_assert (NULL == tl);
2106 GNUNET_STATISTICS_update (plugin->env->stats,
2107 gettext_noop ("# bytes currently in TCP buffers"),
2110 GNUNET_STATISTICS_update (plugin->env->stats,
2111 gettext_noop ("# bytes transmitted via TCP"),
2119 * If we have pending messages, ask the server to
2120 * transmit them (schedule the respective tasks, etc.)
2122 * @param session for which session should we do this
2125 process_pending_messages (struct GNUNET_ATS_Session *session)
2127 struct PendingMessage *pm;
2129 GNUNET_assert (NULL != session->client);
2130 if (NULL != session->transmit_handle)
2132 if (NULL == (pm = session->pending_messages_head))
2135 session->transmit_handle =
2136 GNUNET_SERVER_notify_transmit_ready (session->client,
2138 GNUNET_TIME_absolute_get_remaining (
2146 * Function that can be used by the transport service to transmit
2147 * a message using the plugin. Note that in the case of a
2148 * peer disconnecting, the continuation MUST be called
2149 * prior to the disconnect notification itself. This function
2150 * will be called with this peer's HELLO message to initiate
2151 * a fresh connection to another peer.
2153 * @param cls closure
2154 * @param session which session must be used
2155 * @param msgbuf the message to transmit
2156 * @param msgbuf_size number of bytes in @a msgbuf
2157 * @param priority how important is the message (most plugins will
2158 * ignore message priority and just FIFO)
2159 * @param to how long to wait at most for the transmission (does not
2160 * require plugins to discard the message after the timeout,
2161 * just advisory for the desired delay; most plugins will ignore
2163 * @param cont continuation to call once the message has
2164 * been transmitted (or if the transport is ready
2165 * for the next transmission call; or if the
2166 * peer disconnected...); can be NULL
2167 * @param cont_cls closure for @a cont
2168 * @return number of bytes used (on the physical network, with overheads);
2169 * -1 on hard errors (i.e. address invalid); 0 is a legal value
2170 * and does NOT mean that the message was not transmitted (DV)
2173 tcp_plugin_send (void *cls,
2174 struct GNUNET_ATS_Session *session,
2177 unsigned int priority,
2178 struct GNUNET_TIME_Relative to,
2179 GNUNET_TRANSPORT_TransmitContinuation cont,
2182 struct Plugin *plugin = cls;
2183 struct PendingMessage *pm;
2185 /* create new message entry */
2186 pm = GNUNET_malloc (sizeof(struct PendingMessage) + msgbuf_size);
2187 pm->msg = (const char *) &pm[1];
2188 GNUNET_memcpy (&pm[1], msgbuf, msgbuf_size);
2189 pm->message_size = msgbuf_size;
2190 pm->timeout = GNUNET_TIME_relative_to_absolute (to);
2191 pm->transmit_cont = cont;
2192 pm->transmit_cont_cls = cont_cls;
2194 LOG (GNUNET_ERROR_TYPE_DEBUG,
2195 "Asked to transmit %u bytes to `%s', added message to list.\n",
2197 GNUNET_i2s (&session->target));
2200 GNUNET_CONTAINER_multipeermap_contains_value (plugin->sessionmap,
2204 GNUNET_assert (NULL != session->client);
2205 GNUNET_SERVER_client_set_timeout (session->client,
2206 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2207 GNUNET_STATISTICS_update (plugin->env->stats,
2208 gettext_noop ("# bytes currently in TCP buffers"),
2212 /* append pm to pending_messages list */
2213 GNUNET_CONTAINER_DLL_insert_tail (session->pending_messages_head,
2214 session->pending_messages_tail,
2216 notify_session_monitor (session->plugin,
2218 GNUNET_TRANSPORT_SS_UPDATE);
2219 session->msgs_in_queue++;
2220 session->bytes_in_queue += pm->message_size;
2221 process_pending_messages (session);
2225 GNUNET_CONTAINER_multipeermap_contains_value (plugin->nat_wait_conns,
2229 LOG (GNUNET_ERROR_TYPE_DEBUG,
2230 "This NAT WAIT session for peer `%s' is not yet ready!\n",
2231 GNUNET_i2s (&session->target));
2232 GNUNET_STATISTICS_update (plugin->env->stats,
2233 gettext_noop ("# bytes currently in TCP buffers"),
2236 /* append pm to pending_messages list */
2237 GNUNET_CONTAINER_DLL_insert_tail (session->pending_messages_head,
2238 session->pending_messages_tail,
2240 session->msgs_in_queue++;
2241 session->bytes_in_queue += pm->message_size;
2242 notify_session_monitor (session->plugin,
2244 GNUNET_TRANSPORT_SS_HANDSHAKE);
2247 LOG (GNUNET_ERROR_TYPE_ERROR, "Invalid session %p\n", session);
2249 cont (cont_cls, &session->target, GNUNET_SYSERR, pm->message_size, 0);
2252 return GNUNET_SYSERR; /* session does not exist here */
2257 * Closure for #session_lookup_it().
2259 struct GNUNET_ATS_SessionItCtx
2262 * Address we are looking for.
2264 const struct GNUNET_HELLO_Address *address;
2267 * Where to store the session (if we found it).
2269 struct GNUNET_ATS_Session *result;
2274 * Look for a session by address.
2276 * @param cls the `struct GNUNET_ATS_SessionItCtx`
2278 * @param value a `struct GNUNET_ATS_Session`
2279 * @return #GNUNET_YES to continue looking, #GNUNET_NO if we found the session
2282 session_lookup_it (void *cls,
2283 const struct GNUNET_PeerIdentity *key,
2286 struct GNUNET_ATS_SessionItCtx *si_ctx = cls;
2287 struct GNUNET_ATS_Session *session = value;
2289 if (0 != GNUNET_HELLO_address_cmp (si_ctx->address, session->address))
2291 si_ctx->result = session;
2297 * Task cleaning up a NAT connection attempt after timeout
2299 * @param cls the `struct GNUNET_ATS_Session`
2302 nat_connect_timeout (void *cls)
2304 struct GNUNET_ATS_Session *session = cls;
2306 session->nat_connection_timeout = NULL;
2307 LOG (GNUNET_ERROR_TYPE_DEBUG,
2308 "NAT WAIT connection to `%4s' at `%s' could not be established, removing session\n",
2309 GNUNET_i2s (&session->target),
2310 tcp_plugin_address_to_string (session->plugin,
2311 session->address->address,
2312 session->address->address_length));
2313 tcp_plugin_disconnect_session (session->plugin, session);
2318 * Function that will be called whenever the transport service wants to
2319 * notify the plugin that a session is still active and in use and
2320 * therefore the session timeout for this session has to be updated
2322 * @param cls closure
2323 * @param peer which peer was the session for
2324 * @param session which session is being updated
2327 tcp_plugin_update_session_timeout (void *cls,
2328 const struct GNUNET_PeerIdentity *peer,
2329 struct GNUNET_ATS_Session *session)
2331 reschedule_session_timeout (session);
2336 * Task to signal the server that we can continue
2337 * receiving from the TCP client now.
2339 * @param cls the `struct GNUNET_ATS_Session *`
2342 delayed_done (void *cls)
2344 struct GNUNET_ATS_Session *session = cls;
2346 session->receive_delay_task = NULL;
2347 reschedule_session_timeout (session);
2348 GNUNET_SERVER_receive_done (session->client, GNUNET_OK);
2353 * Function that will be called whenever the transport service wants to
2354 * notify the plugin that the inbound quota changed and that the plugin
2355 * should update it's delay for the next receive value
2357 * @param cls closure
2358 * @param peer which peer was the session for
2359 * @param session which session is being updated
2360 * @param delay new delay to use for receiving
2363 tcp_plugin_update_inbound_delay (void *cls,
2364 const struct GNUNET_PeerIdentity *peer,
2365 struct GNUNET_ATS_Session *session,
2366 struct GNUNET_TIME_Relative delay)
2368 if (NULL == session->receive_delay_task)
2370 LOG (GNUNET_ERROR_TYPE_DEBUG,
2371 "New inbound delay %s\n",
2372 GNUNET_STRINGS_relative_time_to_string (delay, GNUNET_NO));
2373 session->receive_delay = GNUNET_TIME_relative_to_absolute (delay);
2374 GNUNET_SCHEDULER_cancel (session->receive_delay_task);
2375 session->receive_delay_task =
2376 GNUNET_SCHEDULER_add_delayed (delay, &delayed_done, session);
2381 * Create a new session to transmit data to the target
2382 * This session will used to send data to this peer and the plugin will
2383 * notify us by calling the env->session_end function
2385 * @param cls closure
2386 * @param address the address to use
2387 * @return the session if the address is valid, NULL otherwise
2389 static struct GNUNET_ATS_Session *
2390 tcp_plugin_get_session (void *cls, const struct GNUNET_HELLO_Address *address)
2392 struct Plugin *plugin = cls;
2393 struct GNUNET_ATS_Session *session = NULL;
2397 struct GNUNET_CONNECTION_Handle *sa;
2398 struct sockaddr_in a4;
2399 struct sockaddr_in6 a6;
2400 const struct IPv4TcpAddress *t4;
2401 const struct IPv6TcpAddress *t6;
2402 unsigned int options;
2403 enum GNUNET_NetworkType net_type;
2404 unsigned int is_natd = GNUNET_NO;
2408 struct GNUNET_NETWORK_Handle *s;
2411 addrlen = address->address_length;
2412 LOG (GNUNET_ERROR_TYPE_DEBUG,
2413 "Trying to get session for `%s' address of peer `%s'\n",
2414 tcp_plugin_address_to_string (plugin,
2416 address->address_length),
2417 GNUNET_i2s (&address->peer));
2419 if (GNUNET_HELLO_address_check_option (address,
2420 GNUNET_HELLO_ADDRESS_INFO_INBOUND))
2426 /* look for existing session */
2427 if (GNUNET_YES == GNUNET_CONTAINER_multipeermap_contains (plugin->sessionmap,
2430 struct GNUNET_ATS_SessionItCtx si_ctx;
2432 si_ctx.address = address;
2433 si_ctx.result = NULL;
2434 GNUNET_CONTAINER_multipeermap_get_multiple (plugin->sessionmap,
2438 if (NULL != si_ctx.result)
2440 session = si_ctx.result;
2441 LOG (GNUNET_ERROR_TYPE_DEBUG,
2442 "Found existing session for `%s' address `%s'\n",
2443 GNUNET_i2s (&address->peer),
2444 tcp_plugin_address_to_string (plugin,
2446 address->address_length));
2449 /* This is a bit of a hack, limiting TCP to never allow more than
2450 one TCP connection to any given peer at the same time.
2451 Without this, peers sometimes disagree about which of the TCP
2452 connections they should use, causing one side to believe that
2453 they transmit successfully, while the other receives nothing. */return NULL; /* Refuse to have more than one TCP connection per
2454 peer pair at the same time. */
2457 if (addrlen == sizeof(struct IPv6TcpAddress))
2459 GNUNET_assert (NULL != address->address); /* make static analysis happy */
2460 t6 = address->address;
2461 options = t6->options;
2463 memset (&a6, 0, sizeof(a6));
2464 #if HAVE_SOCKADDR_IN_SIN_LEN
2465 a6.sin6_len = sizeof(a6);
2467 a6.sin6_family = AF_INET6;
2468 a6.sin6_port = t6->t6_port;
2469 if (t6->t6_port == 0)
2470 is_natd = GNUNET_YES;
2471 GNUNET_memcpy (&a6.sin6_addr, &t6->ipv6_addr, sizeof(struct in6_addr));
2475 else if (addrlen == sizeof(struct IPv4TcpAddress))
2477 GNUNET_assert (NULL != address->address); /* make static analysis happy */
2478 t4 = address->address;
2479 options = t4->options;
2481 memset (&a4, 0, sizeof(a4));
2482 #if HAVE_SOCKADDR_IN_SIN_LEN
2483 a4.sin_len = sizeof(a4);
2485 a4.sin_family = AF_INET;
2486 a4.sin_port = t4->t4_port;
2487 if (t4->t4_port == 0)
2488 is_natd = GNUNET_YES;
2489 a4.sin_addr.s_addr = t4->ipv4_addr;
2495 GNUNET_STATISTICS_update (
2497 gettext_noop ("# requests to create session with invalid address"),
2503 net_type = plugin->env->get_address_type (plugin->env->cls, sb, sbs);
2504 GNUNET_break (net_type != GNUNET_NT_UNSPECIFIED);
2506 if ((is_natd == GNUNET_YES) && (addrlen == sizeof(struct IPv6TcpAddress)))
2508 /* NAT client only works with IPv4 addresses */
2512 if (plugin->cur_connections >= plugin->max_connections)
2518 if ((is_natd == GNUNET_YES) &&
2520 GNUNET_CONTAINER_multipeermap_contains (plugin->nat_wait_conns,
2523 /* Only do one NAT punch attempt per peer identity */
2527 if ((is_natd == GNUNET_YES) && (NULL != plugin->nat) &&
2529 GNUNET_CONTAINER_multipeermap_contains (plugin->nat_wait_conns,
2532 struct sockaddr_in local_sa;
2534 LOG (GNUNET_ERROR_TYPE_DEBUG,
2535 "Found valid IPv4 NAT address (creating session)!\n");
2536 session = create_session (plugin, address, net_type, NULL, GNUNET_YES);
2537 session->nat_connection_timeout =
2538 GNUNET_SCHEDULER_add_delayed (NAT_TIMEOUT, &nat_connect_timeout, session);
2539 GNUNET_assert (GNUNET_OK ==
2540 GNUNET_CONTAINER_multipeermap_put (
2541 plugin->nat_wait_conns,
2544 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
2546 LOG (GNUNET_ERROR_TYPE_DEBUG,
2547 "Created NAT WAIT connection to `%s' at `%s'\n",
2548 GNUNET_i2s (&session->target),
2549 GNUNET_a2s (sb, sbs));
2550 memset (&local_sa, 0, sizeof(local_sa));
2551 local_sa.sin_family = AF_INET;
2552 local_sa.sin_port = htons (plugin->open_port);
2553 /* We leave sin_address at 0, let the kernel figure it out,
2554 even if our bind() is more specific. (May want to reconsider
2556 if (GNUNET_OK == GNUNET_NAT_request_reversal (plugin->nat, &local_sa, &a4))
2558 LOG (GNUNET_ERROR_TYPE_DEBUG,
2559 "Running NAT client for `%s' at `%s' failed\n",
2560 GNUNET_i2s (&session->target),
2561 GNUNET_a2s (sb, sbs));
2562 tcp_plugin_disconnect_session (plugin, session);
2566 /* create new outbound session */
2567 if (0 != (options & TCP_OPTIONS_TCP_STEALTH))
2570 s = GNUNET_NETWORK_socket_create (af, SOCK_STREAM, 0);
2573 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK,
2580 GNUNET_NETWORK_socket_setsockopt (s,
2585 struct GNUNET_PeerIdentity))) ||
2587 GNUNET_NETWORK_socket_setsockopt (s,
2589 TCP_STEALTH_INTEGRITY,
2590 &plugin->my_welcome,
2591 sizeof(struct WelcomeMessage))))
2593 /* TCP STEALTH not supported by kernel */
2594 GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (s));
2599 sa = GNUNET_CONNECTION_connect_socket (s, sb, sbs);
2608 sa = GNUNET_CONNECTION_create_from_sockaddr (af, sb, sbs);
2612 LOG (GNUNET_ERROR_TYPE_DEBUG,
2613 "Failed to create connection to `%s' at `%s'\n",
2614 GNUNET_i2s (&address->peer),
2615 GNUNET_a2s (sb, sbs));
2618 LOG (GNUNET_ERROR_TYPE_DEBUG,
2619 "Asked to transmit to `%s', creating fresh session using address `%s'.\n",
2620 GNUNET_i2s (&address->peer),
2621 GNUNET_a2s (sb, sbs));
2623 session = create_session (plugin,
2626 GNUNET_SERVER_connect_socket (plugin->server, sa),
2628 (void) GNUNET_CONTAINER_multipeermap_put (
2632 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
2633 /* Send TCP Welcome */
2634 process_pending_messages (session);
2641 * We have been asked to destroy all connections to a particular peer.
2642 * This function is called on each applicable session and must tear it
2645 * @param cls the `struct Plugin *`
2646 * @param key the peer which the session belongs to (unused)
2647 * @param value the `struct GNUNET_ATS_Session`
2648 * @return #GNUNET_YES (continue to iterate)
2651 session_disconnect_it (void *cls,
2652 const struct GNUNET_PeerIdentity *key,
2655 struct Plugin *plugin = cls;
2656 struct GNUNET_ATS_Session *session = value;
2658 GNUNET_STATISTICS_update (session->plugin->env->stats,
2660 "# transport-service disconnect requests for TCP"),
2663 tcp_plugin_disconnect_session (plugin, session);
2669 * Function that can be called to force a disconnect from the
2670 * specified neighbour. This should also cancel all previously
2671 * scheduled transmissions. Obviously the transmission may have been
2672 * partially completed already, which is OK. The plugin is supposed
2673 * to close the connection (if applicable) and no longer call the
2674 * transmit continuation(s).
2676 * Finally, plugin MUST NOT call the services's receive function to
2677 * notify the service that the connection to the specified target was
2678 * closed after a getting this call.
2680 * @param cls closure
2681 * @param target peer for which the last transmission is
2685 tcp_plugin_disconnect (void *cls, const struct GNUNET_PeerIdentity *target)
2687 struct Plugin *plugin = cls;
2689 LOG (GNUNET_ERROR_TYPE_DEBUG,
2690 "Disconnecting peer `%s'\n",
2691 GNUNET_i2s (target));
2692 GNUNET_CONTAINER_multipeermap_get_multiple (plugin->sessionmap,
2694 &session_disconnect_it,
2696 GNUNET_CONTAINER_multipeermap_get_multiple (plugin->nat_wait_conns,
2698 &session_disconnect_it,
2704 * We are processing an address pretty printing request and finished
2705 * the IP resolution (if applicable). Append our port and forward the
2706 * result. If called with @a hostname NULL, we are done and should
2707 * clean up the pretty printer (otherwise, there might be multiple
2708 * hostnames for the IP address and we might receive more).
2710 * @param cls the `struct PrettyPrinterContext *`
2711 * @param hostname hostname part of the address
2714 append_port (void *cls, const char *hostname)
2716 struct PrettyPrinterContext *ppc = cls;
2717 struct Plugin *plugin = ppc->plugin;
2720 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2721 "append_port called with hostname `%s'\n",
2723 if (NULL == hostname)
2725 /* Final call, done */
2726 ppc->resolver_handle = NULL;
2727 GNUNET_CONTAINER_DLL_remove (plugin->ppc_dll_head,
2728 plugin->ppc_dll_tail,
2730 ppc->asc (ppc->asc_cls, NULL, GNUNET_OK);
2734 if (GNUNET_YES == ppc->ipv6)
2735 GNUNET_asprintf (&ret,
2742 GNUNET_asprintf (&ret,
2748 ppc->asc (ppc->asc_cls, ret, GNUNET_OK);
2754 * Convert the transports address to a nice, human-readable format.
2756 * @param cls closure with the `struct Plugin`
2757 * @param type name of the transport that generated the address
2758 * @param addr one of the addresses of the host, NULL for the last address
2759 * the specific address format depends on the transport
2760 * @param addrlen length of the @a addr
2761 * @param numeric should (IP) addresses be displayed in numeric form?
2762 * @param timeout after how long should we give up?
2763 * @param asc function to call on each string
2764 * @param asc_cls closure for @a asc
2767 tcp_plugin_address_pretty_printer (void *cls,
2772 struct GNUNET_TIME_Relative timeout,
2773 GNUNET_TRANSPORT_AddressStringCallback asc,
2776 struct Plugin *plugin = cls;
2777 struct PrettyPrinterContext *ppc;
2780 struct sockaddr_in a4;
2781 struct sockaddr_in6 a6;
2782 const struct IPv4TcpAddress *t4;
2783 const struct IPv6TcpAddress *t6;
2787 if (sizeof(struct IPv6TcpAddress) == addrlen)
2790 memset (&a6, 0, sizeof(a6));
2791 a6.sin6_family = AF_INET6;
2792 a6.sin6_port = t6->t6_port;
2793 GNUNET_memcpy (&a6.sin6_addr, &t6->ipv6_addr, sizeof(struct in6_addr));
2794 port = ntohs (t6->t6_port);
2795 options = ntohl (t6->options);
2799 else if (sizeof(struct IPv4TcpAddress) == addrlen)
2802 memset (&a4, 0, sizeof(a4));
2803 a4.sin_family = AF_INET;
2804 a4.sin_port = t4->t4_port;
2805 a4.sin_addr.s_addr = t4->ipv4_addr;
2806 port = ntohs (t4->t4_port);
2807 options = ntohl (t4->options);
2813 /* invalid address */
2814 LOG (GNUNET_ERROR_TYPE_WARNING,
2815 _ ("Unexpected address length: %u bytes\n"),
2816 (unsigned int) addrlen);
2817 asc (asc_cls, NULL, GNUNET_SYSERR);
2818 asc (asc_cls, NULL, GNUNET_OK);
2821 ppc = GNUNET_new (struct PrettyPrinterContext);
2822 ppc->plugin = plugin;
2823 if (addrlen == sizeof(struct IPv6TcpAddress))
2824 ppc->ipv6 = GNUNET_YES;
2826 ppc->ipv6 = GNUNET_NO;
2828 ppc->asc_cls = asc_cls;
2830 ppc->options = options;
2831 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting DNS reverse lookup\n");
2832 ppc->resolver_handle = GNUNET_RESOLVER_hostname_get (sb,
2838 if (NULL == ppc->resolver_handle)
2844 GNUNET_CONTAINER_DLL_insert (plugin->ppc_dll_head, plugin->ppc_dll_tail, ppc);
2849 * Function that will be called to check if a binary address for this
2850 * plugin is well-formed and corresponds to an address for THIS peer
2851 * (as per our configuration). Naturally, if absolutely necessary,
2852 * plugins can be a bit conservative in their answer, but in general
2853 * plugins should make sure that the address does not redirect
2854 * traffic to a 3rd party that might try to man-in-the-middle our
2857 * @param cls closure, our `struct Plugin *`
2858 * @param addr pointer to the address
2859 * @param addrlen length of @a addr
2860 * @return #GNUNET_OK if this is a plausible address for this peer
2861 * and transport, #GNUNET_SYSERR if not
2864 tcp_plugin_check_address (void *cls, const void *addr, size_t addrlen)
2866 struct Plugin *plugin = cls;
2867 const struct IPv4TcpAddress *v4;
2868 const struct IPv6TcpAddress *v6;
2870 if ((addrlen != sizeof(struct IPv4TcpAddress)) &&
2871 (addrlen != sizeof(struct IPv6TcpAddress)))
2873 GNUNET_break_op (0);
2874 return GNUNET_SYSERR;
2877 if (addrlen == sizeof(struct IPv4TcpAddress))
2879 struct sockaddr_in s4;
2881 v4 = (const struct IPv4TcpAddress *) addr;
2882 if (0 != memcmp (&v4->options, &plugin->myoptions, sizeof(uint32_t)))
2885 return GNUNET_SYSERR;
2887 memset (&s4, 0, sizeof(s4));
2888 s4.sin_family = AF_INET;
2889 #if HAVE_SOCKADDR_IN_SIN_LEN
2890 s4.sin_len = sizeof(s4);
2892 s4.sin_port = v4->t4_port;
2893 s4.sin_addr.s_addr = v4->ipv4_addr;
2896 GNUNET_NAT_test_address (plugin->nat, &s4, sizeof(struct sockaddr_in)))
2897 return GNUNET_SYSERR;
2901 struct sockaddr_in6 s6;
2903 v6 = (const struct IPv6TcpAddress *) addr;
2904 if (IN6_IS_ADDR_LINKLOCAL (&v6->ipv6_addr))
2906 GNUNET_break_op (0);
2907 return GNUNET_SYSERR;
2909 if (0 != memcmp (&v6->options, &plugin->myoptions, sizeof(uint32_t)))
2912 return GNUNET_SYSERR;
2914 memset (&s6, 0, sizeof(s6));
2915 s6.sin6_family = AF_INET6;
2916 #if HAVE_SOCKADDR_IN_SIN_LEN
2917 s6.sin6_len = sizeof(s6);
2919 s6.sin6_port = v6->t6_port;
2920 s6.sin6_addr = v6->ipv6_addr;
2922 if (GNUNET_OK != GNUNET_NAT_test_address (plugin->nat,
2924 sizeof(struct sockaddr_in6)))
2925 return GNUNET_SYSERR;
2932 * We've received a nat probe from this peer via TCP. Finish
2933 * creating the client session and resume sending of queued
2936 * @param cls closure
2937 * @param client identification of the client
2938 * @param message the actual message
2941 handle_tcp_nat_probe (void *cls,
2942 struct GNUNET_SERVER_Client *client,
2943 const struct GNUNET_MessageHeader *message)
2945 struct Plugin *plugin = cls;
2946 struct GNUNET_ATS_Session *session;
2947 const struct TCP_NAT_ProbeMessage *tcp_nat_probe;
2950 struct IPv4TcpAddress *t4;
2951 struct IPv6TcpAddress *t6;
2952 const struct sockaddr_in *s4;
2953 const struct sockaddr_in6 *s6;
2955 LOG (GNUNET_ERROR_TYPE_DEBUG, "Received NAT probe\n");
2956 /* We have received a TCP NAT probe, meaning we (hopefully) initiated
2957 * a connection to this peer by running gnunet-nat-client. This peer
2958 * received the punch message and now wants us to use the new connection
2959 * as the default for that peer. Do so and then send a WELCOME message
2960 * so we can really be connected!
2961 */if (ntohs (message->size) != sizeof(struct TCP_NAT_ProbeMessage))
2963 GNUNET_break_op (0);
2964 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2968 tcp_nat_probe = (const struct TCP_NAT_ProbeMessage *) message;
2969 if (0 == memcmp (&tcp_nat_probe->clientIdentity,
2970 plugin->env->my_identity,
2971 sizeof(struct GNUNET_PeerIdentity)))
2973 /* refuse connections from ourselves */
2974 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2978 session = GNUNET_CONTAINER_multipeermap_get (plugin->nat_wait_conns,
2979 &tcp_nat_probe->clientIdentity);
2980 if (NULL == session)
2982 LOG (GNUNET_ERROR_TYPE_DEBUG, "Did NOT find session for NAT probe!\n");
2983 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2986 LOG (GNUNET_ERROR_TYPE_DEBUG, "Found session for NAT probe!\n");
2988 if (NULL != session->nat_connection_timeout)
2990 GNUNET_SCHEDULER_cancel (session->nat_connection_timeout);
2991 session->nat_connection_timeout = NULL;
2994 if (GNUNET_OK != GNUNET_SERVER_client_get_address (client, &vaddr, &alen))
2997 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2998 tcp_plugin_disconnect_session (plugin, session);
3003 GNUNET_CONTAINER_multipeermap_remove (plugin->nat_wait_conns,
3004 &tcp_nat_probe->clientIdentity,
3006 GNUNET_SERVER_client_set_user_context (client, session);
3007 (void) GNUNET_CONTAINER_multipeermap_put (
3011 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
3012 session->last_activity = GNUNET_TIME_absolute_get ();
3013 LOG (GNUNET_ERROR_TYPE_DEBUG,
3014 "Found address `%s' for incoming connection\n",
3015 GNUNET_a2s (vaddr, alen));
3016 switch (((const struct sockaddr *) vaddr)->sa_family)
3020 t4 = GNUNET_new (struct IPv4TcpAddress);
3021 t4->options = htonl (TCP_OPTIONS_NONE);
3022 t4->t4_port = s4->sin_port;
3023 t4->ipv4_addr = s4->sin_addr.s_addr;
3025 GNUNET_HELLO_address_allocate (&tcp_nat_probe->clientIdentity,
3028 sizeof(struct IPv4TcpAddress),
3029 GNUNET_HELLO_ADDRESS_INFO_NONE);
3034 t6 = GNUNET_new (struct IPv6TcpAddress);
3035 t6->options = htonl (TCP_OPTIONS_NONE);
3036 t6->t6_port = s6->sin6_port;
3037 GNUNET_memcpy (&t6->ipv6_addr, &s6->sin6_addr, sizeof(struct in6_addr));
3039 GNUNET_HELLO_address_allocate (&tcp_nat_probe->clientIdentity,
3042 sizeof(struct IPv6TcpAddress),
3043 GNUNET_HELLO_ADDRESS_INFO_NONE);
3047 GNUNET_break_op (0);
3048 LOG (GNUNET_ERROR_TYPE_DEBUG, "Bad address for incoming connection!\n");
3049 GNUNET_free (vaddr);
3050 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3051 tcp_plugin_disconnect_session (plugin, session);
3054 GNUNET_free (vaddr);
3055 GNUNET_break (NULL == session->client);
3056 session->client = client;
3057 GNUNET_STATISTICS_update (plugin->env->stats,
3058 gettext_noop ("# TCP sessions active"),
3061 process_pending_messages (session);
3062 GNUNET_SERVER_receive_done (client, GNUNET_OK);
3067 * We've received a welcome from this peer via TCP. Possibly create a
3068 * fresh client record and send back our welcome.
3070 * @param cls closure
3071 * @param client identification of the client
3072 * @param message the actual message
3075 handle_tcp_welcome (void *cls,
3076 struct GNUNET_SERVER_Client *client,
3077 const struct GNUNET_MessageHeader *message)
3079 struct Plugin *plugin = cls;
3080 const struct WelcomeMessage *wm = (const struct WelcomeMessage *) message;
3081 struct GNUNET_HELLO_Address *address;
3082 struct GNUNET_ATS_Session *session;
3085 struct IPv4TcpAddress t4;
3086 struct IPv6TcpAddress t6;
3087 const struct sockaddr_in *s4;
3088 const struct sockaddr_in6 *s6;
3090 if (0 == memcmp (&wm->clientIdentity,
3091 plugin->env->my_identity,
3092 sizeof(struct GNUNET_PeerIdentity)))
3094 /* refuse connections from ourselves */
3095 if (GNUNET_OK == GNUNET_SERVER_client_get_address (client, &vaddr, &alen))
3097 LOG (GNUNET_ERROR_TYPE_INFO,
3098 "Received WELCOME message from my own identity `%s' on address `%s'\n",
3099 GNUNET_i2s (&wm->clientIdentity),
3100 GNUNET_a2s (vaddr, alen));
3101 GNUNET_free (vaddr);
3103 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3107 if (GNUNET_OK == GNUNET_SERVER_client_get_address (client, &vaddr, &alen))
3109 LOG (GNUNET_ERROR_TYPE_DEBUG,
3110 "Received WELCOME message from `%s' on address `%s'\n",
3111 GNUNET_i2s (&wm->clientIdentity),
3112 GNUNET_a2s (vaddr, alen));
3113 GNUNET_free (vaddr);
3115 GNUNET_STATISTICS_update (plugin->env->stats,
3116 gettext_noop ("# TCP WELCOME messages received"),
3119 session = lookup_session_by_client (plugin, client);
3120 if (NULL != session)
3122 if (GNUNET_OK == GNUNET_SERVER_client_get_address (client, &vaddr, &alen))
3124 LOG (GNUNET_ERROR_TYPE_DEBUG,
3125 "Found existing session %p for peer `%s'\n",
3127 GNUNET_a2s (vaddr, alen));
3128 GNUNET_free (vaddr);
3133 if (GNUNET_OK == GNUNET_SERVER_client_get_address (client, &vaddr, &alen))
3135 if (alen == sizeof(struct sockaddr_in))
3138 memset (&t4, '\0', sizeof(t4));
3139 t4.options = htonl (TCP_OPTIONS_NONE);
3140 t4.t4_port = s4->sin_port;
3141 t4.ipv4_addr = s4->sin_addr.s_addr;
3143 GNUNET_HELLO_address_allocate (&wm->clientIdentity,
3147 GNUNET_HELLO_ADDRESS_INFO_INBOUND);
3149 else if (alen == sizeof(struct sockaddr_in6))
3152 memset (&t6, '\0', sizeof(t6));
3153 t6.options = htonl (TCP_OPTIONS_NONE);
3154 t6.t6_port = s6->sin6_port;
3155 GNUNET_memcpy (&t6.ipv6_addr, &s6->sin6_addr, sizeof(struct in6_addr));
3157 GNUNET_HELLO_address_allocate (&wm->clientIdentity,
3161 GNUNET_HELLO_ADDRESS_INFO_INBOUND);
3166 GNUNET_free_non_null (vaddr);
3167 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3170 session = create_session (plugin,
3172 plugin->env->get_address_type (plugin->env->cls,
3177 GNUNET_break (GNUNET_NT_UNSPECIFIED != session->scope);
3178 GNUNET_HELLO_address_free (address);
3179 LOG (GNUNET_ERROR_TYPE_DEBUG,
3180 "Creating new%s session %p for peer `%s' client %p\n",
3181 GNUNET_HELLO_address_check_option (session->address,
3182 GNUNET_HELLO_ADDRESS_INFO_INBOUND)
3186 tcp_plugin_address_to_string (plugin,
3187 session->address->address,
3188 session->address->address_length),
3190 GNUNET_free (vaddr);
3191 (void) GNUNET_CONTAINER_multipeermap_put (
3195 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
3196 /* Notify transport and ATS about new session */
3197 plugin->env->session_start (plugin->env->cls,
3204 LOG (GNUNET_ERROR_TYPE_DEBUG,
3205 "Did not obtain TCP socket address for incoming connection\n");
3207 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3212 if (GNUNET_YES != session->expecting_welcome)
3214 GNUNET_break_op (0);
3215 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3218 session->last_activity = GNUNET_TIME_absolute_get ();
3219 session->expecting_welcome = GNUNET_NO;
3221 process_pending_messages (session);
3222 GNUNET_SERVER_client_set_timeout (client,
3223 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
3224 GNUNET_SERVER_receive_done (client, GNUNET_OK);
3229 * We've received data for this peer via TCP. Unbox,
3230 * compute latency and forward.
3232 * @param cls closure
3233 * @param client identification of the client
3234 * @param message the actual message
3237 handle_tcp_data (void *cls,
3238 struct GNUNET_SERVER_Client *client,
3239 const struct GNUNET_MessageHeader *message)
3241 struct Plugin *plugin = cls;
3242 struct GNUNET_ATS_Session *session;
3243 struct GNUNET_TIME_Relative delay;
3246 type = ntohs (message->type);
3247 if ((GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_WELCOME == type) ||
3248 (GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_NAT_PROBE == type))
3250 /* We don't want to propagate WELCOME and NAT Probe messages up! */
3251 GNUNET_SERVER_receive_done (client, GNUNET_OK);
3254 session = lookup_session_by_client (plugin, client);
3255 if (NULL == session)
3257 /* No inbound session found */
3261 GNUNET_assert (GNUNET_OK ==
3262 GNUNET_SERVER_client_get_address (client, &vaddr, &alen));
3263 LOG (GNUNET_ERROR_TYPE_ERROR,
3264 "Received unexpected %u bytes of type %u from `%s'\n",
3265 (unsigned int) ntohs (message->size),
3266 (unsigned int) ntohs (message->type),
3267 GNUNET_a2s (vaddr, alen));
3268 GNUNET_break_op (0);
3269 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3270 GNUNET_free_non_null (vaddr);
3273 if (GNUNET_YES == session->expecting_welcome)
3275 /* Session is expecting WELCOME message */
3279 GNUNET_SERVER_client_get_address (client, &vaddr, &alen);
3280 LOG (GNUNET_ERROR_TYPE_ERROR,
3281 "Received unexpected %u bytes of type %u from `%s'\n",
3282 (unsigned int) ntohs (message->size),
3283 (unsigned int) ntohs (message->type),
3284 GNUNET_a2s (vaddr, alen));
3285 GNUNET_break_op (0);
3286 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3287 GNUNET_free_non_null (vaddr);
3291 session->last_activity = GNUNET_TIME_absolute_get ();
3296 GNUNET_SERVER_client_get_address (client, &vaddr, &alen);
3297 LOG (GNUNET_ERROR_TYPE_DEBUG,
3298 "Passing %u bytes of type %u from `%s' at %s to transport service.\n",
3299 (unsigned int) ntohs (message->size),
3300 (unsigned int) ntohs (message->type),
3301 GNUNET_i2s (&session->target),
3302 GNUNET_a2s (vaddr, alen));
3303 GNUNET_free_non_null (vaddr);
3306 GNUNET_STATISTICS_update (plugin->env->stats,
3307 gettext_noop ("# bytes received via TCP"),
3308 ntohs (message->size),
3312 GNUNET_CONTAINER_multipeermap_contains_value (plugin->sessionmap,
3316 plugin->env->receive (plugin->env->cls, session->address, session, message);
3317 reschedule_session_timeout (session);
3318 if (0 == delay.rel_value_us)
3320 GNUNET_SERVER_receive_done (client, GNUNET_OK);
3324 LOG (GNUNET_ERROR_TYPE_DEBUG,
3325 "Throttling receiving from `%s' for %s\n",
3326 GNUNET_i2s (&session->target),
3327 GNUNET_STRINGS_relative_time_to_string (delay, GNUNET_YES));
3328 GNUNET_SERVER_disable_receive_done_warning (client);
3329 GNUNET_assert (NULL == session->receive_delay_task);
3330 session->receive_delay_task =
3331 GNUNET_SCHEDULER_add_delayed (delay, &delayed_done, session);
3337 * Function called whenever a peer is connected on the "SERVER" level.
3338 * Increments number of active connections and suspends server if we
3339 * have reached the limit.
3341 * @param cls closure
3342 * @param client identification of the client
3345 connect_notify (void *cls, struct GNUNET_SERVER_Client *client)
3347 struct Plugin *plugin = cls;
3351 plugin->cur_connections++;
3352 GNUNET_STATISTICS_set (plugin->env->stats,
3353 gettext_noop ("# TCP server connections active"),
3354 plugin->cur_connections,
3356 GNUNET_STATISTICS_update (plugin->env->stats,
3357 gettext_noop ("# TCP server connect events"),
3360 if (plugin->cur_connections != plugin->max_connections)
3362 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3363 _ ("TCP connection limit reached, suspending server\n"));
3364 GNUNET_STATISTICS_update (plugin->env->stats,
3365 gettext_noop ("# TCP service suspended"),
3368 GNUNET_SERVER_suspend (
3369 plugin->server); /* Maximum number of connections rechead */
3374 * Function called whenever a peer is disconnected on the "SERVER"
3375 * level. Cleans up the connection, decrements number of active
3376 * connections and if applicable resumes listening.
3378 * @param cls closure
3379 * @param client identification of the client
3382 disconnect_notify (void *cls, struct GNUNET_SERVER_Client *client)
3384 struct Plugin *plugin = cls;
3385 struct GNUNET_ATS_Session *session;
3389 GNUNET_assert (plugin->cur_connections >= 1);
3390 plugin->cur_connections--;
3391 session = lookup_session_by_client (plugin, client);
3392 if (NULL == session)
3393 return; /* unknown, nothing to do */
3394 LOG (GNUNET_ERROR_TYPE_DEBUG,
3395 "Destroying session of `%s' with %s due to network-level disconnect.\n",
3396 GNUNET_i2s (&session->target),
3397 tcp_plugin_address_to_string (session->plugin,
3398 session->address->address,
3399 session->address->address_length));
3401 if (plugin->cur_connections == plugin->max_connections)
3403 GNUNET_STATISTICS_update (session->plugin->env->stats,
3404 gettext_noop ("# TCP service resumed"),
3407 GNUNET_SERVER_resume (plugin->server); /* Resume server */
3409 GNUNET_STATISTICS_set (plugin->env->stats,
3410 gettext_noop ("# TCP server connections active"),
3411 plugin->cur_connections,
3413 GNUNET_STATISTICS_update (session->plugin->env->stats,
3415 "# network-level TCP disconnect events"),
3418 tcp_plugin_disconnect_session (plugin, session);
3423 * We can now send a probe message, copy into buffer to really send.
3425 * @param cls closure, a `struct TCPProbeContext`
3426 * @param size max size to copy
3427 * @param buf buffer to copy message to
3428 * @return number of bytes copied into @a buf
3431 notify_send_probe (void *cls, size_t size, void *buf)
3433 struct TCPProbeContext *tcp_probe_ctx = cls;
3434 struct Plugin *plugin = tcp_probe_ctx->plugin;
3437 tcp_probe_ctx->transmit_handle = NULL;
3438 GNUNET_CONTAINER_DLL_remove (plugin->probe_head,
3443 GNUNET_CONNECTION_destroy (tcp_probe_ctx->sock);
3444 GNUNET_free (tcp_probe_ctx);
3447 GNUNET_assert (size >= sizeof(tcp_probe_ctx->message));
3448 GNUNET_memcpy (buf, &tcp_probe_ctx->message, sizeof(tcp_probe_ctx->message));
3449 GNUNET_SERVER_connect_socket (tcp_probe_ctx->plugin->server,
3450 tcp_probe_ctx->sock);
3451 ret = sizeof(tcp_probe_ctx->message);
3452 GNUNET_free (tcp_probe_ctx);
3458 * Function called by the NAT subsystem suggesting another peer wants
3459 * to connect to us via connection reversal. Try to connect back to the
3462 * @param cls closure
3463 * @param addr address to try
3464 * @param addrlen number of bytes in @a addr
3467 try_connection_reversal (void *cls,
3468 const struct sockaddr *addr,
3471 struct Plugin *plugin = cls;
3472 struct GNUNET_CONNECTION_Handle *sock;
3473 struct TCPProbeContext *tcp_probe_ctx;
3476 * We have received an ICMP response, ostensibly from a peer
3477 * that wants to connect to us! Send a message to establish a connection.
3479 sock = GNUNET_CONNECTION_create_from_sockaddr (AF_INET, addr, addrlen);
3482 /* failed for some odd reason (out of sockets?); ignore attempt */
3486 tcp_probe_ctx = GNUNET_new (struct TCPProbeContext);
3487 tcp_probe_ctx->message.header.size =
3488 htons (sizeof(struct TCP_NAT_ProbeMessage));
3489 tcp_probe_ctx->message.header.type =
3490 htons (GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_NAT_PROBE);
3491 tcp_probe_ctx->message.clientIdentity = *plugin->env->my_identity;
3492 tcp_probe_ctx->plugin = plugin;
3493 tcp_probe_ctx->sock = sock;
3494 GNUNET_CONTAINER_DLL_insert (plugin->probe_head,
3497 tcp_probe_ctx->transmit_handle =
3498 GNUNET_CONNECTION_notify_transmit_ready (sock,
3499 ntohs (tcp_probe_ctx->message
3501 GNUNET_TIME_UNIT_FOREVER_REL,
3508 * Function obtain the network type for a session
3510 * @param cls closure (`struct Plugin *`)
3511 * @param session the session
3512 * @return the network type in HBO or #GNUNET_SYSERR
3514 static enum GNUNET_NetworkType
3515 tcp_plugin_get_network (void *cls, struct GNUNET_ATS_Session *session)
3517 return session->scope;
3522 * Function obtain the network type for an address.
3524 * @param cls closure (`struct Plugin *`)
3525 * @param address the address
3526 * @return the network type
3528 static enum GNUNET_NetworkType
3529 tcp_plugin_get_network_for_address (void *cls,
3530 const struct GNUNET_HELLO_Address *address)
3532 struct Plugin *plugin = cls;
3534 struct sockaddr_in a4;
3535 struct sockaddr_in6 a6;
3536 const struct IPv4TcpAddress *t4;
3537 const struct IPv6TcpAddress *t6;
3541 addrlen = address->address_length;
3542 if (addrlen == sizeof(struct IPv6TcpAddress))
3544 GNUNET_assert (NULL != address->address); /* make static analysis happy */
3545 t6 = address->address;
3546 memset (&a6, 0, sizeof(a6));
3547 #if HAVE_SOCKADDR_IN_SIN_LEN
3548 a6.sin6_len = sizeof(a6);
3550 a6.sin6_family = AF_INET6;
3551 a6.sin6_port = t6->t6_port;
3552 GNUNET_memcpy (&a6.sin6_addr, &t6->ipv6_addr, sizeof(struct in6_addr));
3556 else if (addrlen == sizeof(struct IPv4TcpAddress))
3558 GNUNET_assert (NULL != address->address); /* make static analysis happy */
3559 t4 = address->address;
3560 memset (&a4, 0, sizeof(a4));
3561 #if HAVE_SOCKADDR_IN_SIN_LEN
3562 a4.sin_len = sizeof(a4);
3564 a4.sin_family = AF_INET;
3565 a4.sin_port = t4->t4_port;
3566 a4.sin_addr.s_addr = t4->ipv4_addr;
3573 return GNUNET_NT_UNSPECIFIED;
3575 return plugin->env->get_address_type (plugin->env->cls, sb, sbs);
3580 * Return information about the given session to the
3583 * @param cls the `struct Plugin` with the monitor callback (`sic`)
3584 * @param peer peer we send information about
3585 * @param value our `struct GNUNET_ATS_Session` to send information about
3586 * @return #GNUNET_OK (continue to iterate)
3589 send_session_info_iter (void *cls,
3590 const struct GNUNET_PeerIdentity *peer,
3593 struct Plugin *plugin = cls;
3594 struct GNUNET_ATS_Session *session = value;
3596 notify_session_monitor (plugin, session, GNUNET_TRANSPORT_SS_INIT);
3597 /* FIXME: cannot tell if this is up or not from current
3599 notify_session_monitor (plugin, session, GNUNET_TRANSPORT_SS_UP);
3605 * Begin monitoring sessions of a plugin. There can only
3606 * be one active monitor per plugin (i.e. if there are
3607 * multiple monitors, the transport service needs to
3608 * multiplex the generated events over all of them).
3610 * @param cls closure of the plugin
3611 * @param sic callback to invoke, NULL to disable monitor;
3612 * plugin will being by iterating over all active
3613 * sessions immediately and then enter monitor mode
3614 * @param sic_cls closure for @a sic
3617 tcp_plugin_setup_monitor (void *cls,
3618 GNUNET_TRANSPORT_SessionInfoCallback sic,
3621 struct Plugin *plugin = cls;
3624 plugin->sic_cls = sic_cls;
3627 GNUNET_CONTAINER_multipeermap_iterate (plugin->sessionmap,
3628 &send_session_info_iter,
3630 /* signal end of first iteration */
3631 sic (sic_cls, NULL, NULL);
3637 * Entry point for the plugin.
3639 * @param cls closure, the `struct GNUNET_TRANSPORT_PluginEnvironment *`
3640 * @return the `struct GNUNET_TRANSPORT_PluginFunctions *` or NULL on error
3643 libgnunet_plugin_transport_tcp_init (void *cls)
3645 static const struct GNUNET_SERVER_MessageHandler my_handlers[] =
3646 { { &handle_tcp_welcome,
3648 GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_WELCOME,
3649 sizeof(struct WelcomeMessage) },
3650 { &handle_tcp_nat_probe,
3652 GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_NAT_PROBE,
3653 sizeof(struct TCP_NAT_ProbeMessage) },
3654 { &handle_tcp_data, NULL, GNUNET_MESSAGE_TYPE_ALL, 0 },
3655 { NULL, NULL, 0, 0 } };
3656 struct GNUNET_TRANSPORT_PluginEnvironment *env = cls;
3657 struct GNUNET_TRANSPORT_PluginFunctions *api;
3658 struct Plugin *plugin;
3659 struct LEGACY_SERVICE_Context *service;
3660 unsigned long long aport;
3661 unsigned long long bport;
3662 unsigned long long max_connections;
3664 struct GNUNET_TIME_Relative idle_timeout;
3667 struct GNUNET_NETWORK_Handle *const *lsocks;
3671 struct sockaddr **addrs;
3672 socklen_t *addrlens;
3674 if (NULL == env->receive)
3676 /* run in 'stub' mode (i.e. as part of gnunet-peerinfo), don't fully
3677 initialze the plugin or the API */
3678 api = GNUNET_new (struct GNUNET_TRANSPORT_PluginFunctions);
3680 api->address_pretty_printer = &tcp_plugin_address_pretty_printer;
3681 api->address_to_string = &tcp_plugin_address_to_string;
3682 api->string_to_address = &tcp_plugin_string_to_address;
3686 GNUNET_assert (NULL != env->cfg);
3687 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (env->cfg,
3691 max_connections = 128;
3694 if ((GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (env->cfg,
3699 ((GNUNET_OK == GNUNET_CONFIGURATION_get_value_number (env->cfg,
3705 LOG (GNUNET_ERROR_TYPE_ERROR,
3706 _ ("Require valid port number for service `%s' in configuration!\n"),
3716 service = LEGACY_SERVICE_start ("transport-tcp",
3718 LEGACY_SERVICE_OPTION_NONE);
3719 if (NULL == service)
3721 LOG (GNUNET_ERROR_TYPE_WARNING, _ ("Failed to start service.\n"));
3729 plugin = GNUNET_new (struct Plugin);
3730 plugin->sessionmap =
3731 GNUNET_CONTAINER_multipeermap_create (max_connections, GNUNET_YES);
3732 plugin->max_connections = max_connections;
3733 plugin->open_port = bport;
3734 plugin->adv_port = aport;
3736 plugin->my_welcome.header.size = htons (sizeof(struct WelcomeMessage));
3737 plugin->my_welcome.header.type =
3738 htons (GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_WELCOME);
3739 plugin->my_welcome.clientIdentity = *plugin->env->my_identity;
3741 if ((NULL != service) &&
3742 (GNUNET_YES == GNUNET_CONFIGURATION_get_value_yesno (env->cfg,
3747 plugin->myoptions |= TCP_OPTIONS_TCP_STEALTH;
3748 lsocks = LEGACY_SERVICE_get_listen_sockets (service);
3751 uint32_t len = sizeof(struct WelcomeMessage);
3753 for (i = 0; NULL != lsocks[i]; i++)
3757 GNUNET_NETWORK_socket_setsockopt (lsocks[i],
3762 struct GNUNET_PeerIdentity))) ||
3764 GNUNET_NETWORK_socket_setsockopt (lsocks[i],
3766 TCP_STEALTH_INTEGRITY_LEN,
3770 /* TCP STEALTH not supported by kernel */
3771 GNUNET_assert (0 == i);
3772 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3773 _ ("TCP_STEALTH not supported on this platform.\n"));
3779 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3780 _ ("TCP_STEALTH not supported on this platform.\n"));
3785 if ((NULL != service) &&
3788 get_server_addresses ("transport-tcp", env->cfg, &addrs, &addrlens))))
3790 for (ret = ret_s - 1; ret >= 0; ret--)
3791 LOG (GNUNET_ERROR_TYPE_INFO,
3792 "Binding to address `%s'\n",
3793 GNUNET_a2s (addrs[ret], addrlens[ret]));
3794 plugin->nat = GNUNET_NAT_register (env->cfg,
3797 (unsigned int) ret_s,
3798 (const struct sockaddr **) addrs,
3800 &tcp_nat_port_map_callback,
3801 &try_connection_reversal,
3803 for (ret = ret_s - 1; ret >= 0; ret--)
3804 GNUNET_free (addrs[ret]);
3805 GNUNET_free_non_null (addrs);
3806 GNUNET_free_non_null (addrlens);
3810 plugin->nat = GNUNET_NAT_register (plugin->env->cfg,
3817 &try_connection_reversal,
3820 api = GNUNET_new (struct GNUNET_TRANSPORT_PluginFunctions);
3822 api->send = &tcp_plugin_send;
3823 api->get_session = &tcp_plugin_get_session;
3824 api->disconnect_session = &tcp_plugin_disconnect_session;
3825 api->query_keepalive_factor = &tcp_plugin_query_keepalive_factor;
3826 api->disconnect_peer = &tcp_plugin_disconnect;
3827 api->address_pretty_printer = &tcp_plugin_address_pretty_printer;
3828 api->check_address = &tcp_plugin_check_address;
3829 api->address_to_string = &tcp_plugin_address_to_string;
3830 api->string_to_address = &tcp_plugin_string_to_address;
3831 api->get_network = &tcp_plugin_get_network;
3832 api->get_network_for_address = &tcp_plugin_get_network_for_address;
3833 api->update_session_timeout = &tcp_plugin_update_session_timeout;
3834 api->update_inbound_delay = &tcp_plugin_update_inbound_delay;
3835 api->setup_monitor = &tcp_plugin_setup_monitor;
3836 plugin->service = service;
3837 if (NULL != service)
3839 plugin->server = LEGACY_SERVICE_get_server (service);
3843 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_time (env->cfg,
3848 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
3853 plugin->server = GNUNET_SERVER_create_with_sockets (NULL,
3859 plugin->handlers = GNUNET_malloc (sizeof(my_handlers));
3860 GNUNET_memcpy (plugin->handlers, my_handlers, sizeof(my_handlers));
3862 i < sizeof(my_handlers) / sizeof(struct GNUNET_SERVER_MessageHandler);
3864 plugin->handlers[i].callback_cls = plugin;
3866 GNUNET_SERVER_add_handlers (plugin->server, plugin->handlers);
3867 GNUNET_SERVER_connect_notify (plugin->server, &connect_notify, plugin);
3868 GNUNET_SERVER_disconnect_notify (plugin->server, &disconnect_notify, plugin);
3869 plugin->nat_wait_conns =
3870 GNUNET_CONTAINER_multipeermap_create (16, GNUNET_YES);
3872 LOG (GNUNET_ERROR_TYPE_INFO,
3873 _ ("TCP transport listening on port %llu\n"),
3876 LOG (GNUNET_ERROR_TYPE_INFO,
3877 _ ("TCP transport not listening on any port (client only)\n"));
3878 if ((aport != bport) && (0 != bport))
3879 LOG (GNUNET_ERROR_TYPE_INFO,
3880 _ ("TCP transport advertises itself as being on port %llu\n"),
3882 /* Initially set connections to 0 */
3883 GNUNET_STATISTICS_set (plugin->env->stats,
3884 gettext_noop ("# TCP sessions active"),
3890 if (NULL != plugin->nat)
3891 GNUNET_NAT_unregister (plugin->nat);
3892 GNUNET_CONTAINER_multipeermap_destroy (plugin->sessionmap);
3893 if (NULL != service)
3894 LEGACY_SERVICE_stop (service);
3895 GNUNET_free (plugin);
3896 GNUNET_free_non_null (api);
3902 * Exit point from the plugin.
3904 * @param cls the `struct GNUNET_TRANSPORT_PluginFunctions`
3908 libgnunet_plugin_transport_tcp_done (void *cls)
3910 struct GNUNET_TRANSPORT_PluginFunctions *api = cls;
3911 struct Plugin *plugin = api->cls;
3912 struct TCPProbeContext *tcp_probe;
3913 struct PrettyPrinterContext *cur;
3914 struct PrettyPrinterContext *next;
3921 LOG (GNUNET_ERROR_TYPE_DEBUG, "Shutting down TCP plugin\n");
3923 /* Removing leftover sessions */
3924 GNUNET_CONTAINER_multipeermap_iterate (plugin->sessionmap,
3925 &session_disconnect_it,
3927 /* Removing leftover NAT sessions */
3928 GNUNET_CONTAINER_multipeermap_iterate (plugin->nat_wait_conns,
3929 &session_disconnect_it,
3932 for (cur = plugin->ppc_dll_head; NULL != cur; cur = next)
3935 GNUNET_CONTAINER_DLL_remove (plugin->ppc_dll_head,
3936 plugin->ppc_dll_tail,
3938 GNUNET_RESOLVER_request_cancel (cur->resolver_handle);
3939 cur->asc (cur->asc_cls, NULL, GNUNET_OK);
3943 if (NULL != plugin->service)
3944 LEGACY_SERVICE_stop (plugin->service);
3946 GNUNET_SERVER_destroy (plugin->server);
3947 GNUNET_free (plugin->handlers);
3948 if (NULL != plugin->nat)
3949 GNUNET_NAT_unregister (plugin->nat);
3950 while (NULL != (tcp_probe = plugin->probe_head))
3952 GNUNET_CONTAINER_DLL_remove (plugin->probe_head,
3955 GNUNET_CONNECTION_destroy (tcp_probe->sock);
3956 GNUNET_free (tcp_probe);
3958 GNUNET_CONTAINER_multipeermap_destroy (plugin->nat_wait_conns);
3959 GNUNET_CONTAINER_multipeermap_destroy (plugin->sessionmap);
3960 GNUNET_break (0 == plugin->cur_connections);
3961 GNUNET_free (plugin);
3967 /* end of plugin_transport_tcp.c */