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);
91 * Function called to notify a client about the connection begin ready
92 * to queue more data. @a buf will be NULL and @a size zero if the
93 * connection was closed for writing in the meantime.
96 * @param size number of bytes available in @a buf
97 * @param buf where the callee should write the message
98 * @return number of bytes written to @a buf
101 (*GNUNET_CONNECTION_TransmitReadyNotify) (void *cls,
106 * Credentials for UNIX domain sockets.
108 struct GNUNET_CONNECTION_Credentials
111 * UID of the other end of the connection.
116 * GID of the other end of the connection.
123 * Functions with this signature are called whenever a client
124 * is disconnected on the network level.
127 * @param client identification of the client; NULL
128 * for the last call when the server is destroyed
131 (*GNUNET_SERVER_DisconnectCallback) (void *cls,
132 struct GNUNET_SERVER_Client *client);
136 * Functions with this signature are called whenever a client
137 * is connected on the network level.
140 * @param client identification of the client
143 (*GNUNET_SERVER_ConnectCallback) (void *cls,
144 struct GNUNET_SERVER_Client *client);
150 * Function to call for access control checks.
153 * @param ucred credentials, if available, otherwise NULL
154 * @param addr address
155 * @param addrlen length of address
156 * @return GNUNET_YES to allow, GNUNET_NO to deny, GNUNET_SYSERR
157 * for unknown address family (will be denied).
160 (*GNUNET_CONNECTION_AccessCheck) (void *cls,
162 GNUNET_CONNECTION_Credentials *
164 const struct sockaddr * addr,
168 * Callback function for data received from the network. Note that
169 * both "available" and "err" would be 0 if the read simply timed out.
172 * @param buf pointer to received data
173 * @param available number of bytes availabe in "buf",
174 * possibly 0 (on errors)
175 * @param addr address of the sender
176 * @param addrlen size of addr
177 * @param errCode value of errno (on errors receiving)
180 (*GNUNET_CONNECTION_Receiver) (void *cls, const void *buf,
182 const struct sockaddr * addr,
183 socklen_t addrlen, int errCode);
188 * Close the connection and free associated resources. There must
189 * not be any pending requests for reading or writing to the
190 * connection at this time.
192 * @param connection connection to destroy
195 GNUNET_CONNECTION_destroy (struct GNUNET_CONNECTION_Handle *connection);
199 * Signature of a function to create a custom tokenizer.
201 * @param cls closure from #GNUNET_SERVER_set_callbacks
202 * @param client handle to client the tokenzier will be used for
203 * @return handle to custom tokenizer ('mst')
206 (*GNUNET_SERVER_MstCreateCallback) (void *cls,
207 struct GNUNET_SERVER_Client *client);
211 * Signature of a function to destroy a custom tokenizer.
213 * @param cls closure from #GNUNET_SERVER_set_callbacks
214 * @param mst custom tokenizer handle
217 (*GNUNET_SERVER_MstDestroyCallback) (void *cls,
221 * Signature of a function to receive data for a custom tokenizer.
223 * @param cls closure from #GNUNET_SERVER_set_callbacks
224 * @param mst custom tokenizer handle
225 * @param client_identity ID of client for which this is a buffer,
226 * can be NULL (will be passed back to 'cb')
227 * @param buf input data to add
228 * @param size number of bytes in @a buf
229 * @param purge should any excess bytes in the buffer be discarded
230 * (i.e. for packet-based services like UDP)
231 * @param one_shot only call callback once, keep rest of message in buffer
232 * @return #GNUNET_OK if we are done processing (need more data)
233 * #GNUNET_NO if one_shot was set and we have another message ready
234 * #GNUNET_SYSERR if the data stream is corrupt
237 (*GNUNET_SERVER_MstReceiveCallback) (void *cls, void *mst,
238 struct GNUNET_SERVER_Client *client,
244 * Functions with this signature are called whenever a message is
248 * @param client identification of the client
249 * @param message the actual message
252 (*GNUNET_SERVER_MessageCallback) (void *cls,
253 struct GNUNET_SERVER_Client *client,
254 const struct GNUNET_MessageHeader *message);
257 * Message handler. Each struct specifies how to handle on particular
258 * type of message received.
260 struct GNUNET_SERVER_MessageHandler
263 * Function to call for messages of "type".
265 GNUNET_SERVER_MessageCallback callback;
268 * Closure argument for @e callback.
273 * Type of the message this handler covers.
278 * Expected size of messages of this type. Use 0 for
279 * variable-size. If non-zero, messages of the given
280 * type will be discarded (and the connection closed)
281 * if they do not have the right size.
283 uint16_t expected_size;
289 * Options for the service (bitmask).
291 enum LEGACY_SERVICE_Options
294 * Use defaults. Terminates all client connections and the listen
295 * sockets immediately upon receiving the shutdown signal.
297 LEGACY_SERVICE_OPTION_NONE = 0,
300 * Do not trigger server shutdown on signal at all; instead, allow
301 * for the user to terminate the server explicitly when needed
302 * by calling #LEGACY_SERVICE_shutdown().
304 LEGACY_SERVICE_OPTION_MANUAL_SHUTDOWN = 1,
307 * Trigger a SOFT server shutdown on signals, allowing active
308 * non-monitor clients to complete their transactions.
310 LEGACY_SERVICE_OPTION_SOFT_SHUTDOWN = 2
316 * Ask the server to disconnect from the given client. This is the
317 * same as passing #GNUNET_SYSERR to #GNUNET_SERVER_receive_done,
318 * except that it allows dropping of a client even when not handling a
319 * message from that client.
321 * @param client the client to disconnect from
324 GNUNET_SERVER_client_disconnect (struct GNUNET_SERVER_Client *client);
327 * Return user context associated with the given client.
328 * Note: you should probably use the macro (call without the underscore).
330 * @param client client to query
331 * @param size number of bytes in user context struct (for verification only)
332 * @return pointer to user context
335 GNUNET_SERVER_client_get_user_context_ (struct GNUNET_SERVER_Client *client,
340 * Functions with this signature are called whenever a
341 * complete message is received by the tokenizer.
343 * Do not call #GNUNET_SERVER_mst_destroy from within
344 * the scope of this callback.
347 * @param client identification of the client
348 * @param message the actual message
349 * @return #GNUNET_OK on success, #GNUNET_SYSERR to stop further processing
352 (*GNUNET_SERVER_MessageTokenizerCallback) (void *cls,
354 const struct GNUNET_MessageHeader *message);
358 * Create a message stream tokenizer.
360 * @param cb function to call on completed messages
361 * @param cb_cls closure for @a cb
362 * @return handle to tokenizer
364 struct GNUNET_SERVER_MessageStreamTokenizer *
365 GNUNET_SERVER_mst_create (GNUNET_SERVER_MessageTokenizerCallback cb,
369 * Add incoming data to the receive buffer and call the
370 * callback for all complete messages.
372 * @param mst tokenizer to use
373 * @param client_identity ID of client for which this is a buffer,
374 * can be NULL (will be passed back to 'cb')
375 * @param buf input data to add
376 * @param size number of bytes in @a buf
377 * @param purge should any excess bytes in the buffer be discarded
378 * (i.e. for packet-based services like UDP)
379 * @param one_shot only call callback once, keep rest of message in buffer
380 * @return #GNUNET_OK if we are done processing (need more data)
381 * #GNUNET_NO if one_shot was set and we have another message ready
382 * #GNUNET_SYSERR if the data stream is corrupt
385 GNUNET_SERVER_mst_receive (struct GNUNET_SERVER_MessageStreamTokenizer *mst,
386 void *client_identity,
387 const char *buf, size_t size,
388 int purge, int one_shot);
393 * Destroys a tokenizer.
395 * @param mst tokenizer to destroy
398 GNUNET_SERVER_mst_destroy (struct GNUNET_SERVER_MessageStreamTokenizer *mst);
402 * Set user context to be associated with the given client.
403 * Note: you should probably use the macro (call without the underscore).
405 * @param client client to query
406 * @param ptr pointer to user context
407 * @param size number of bytes in user context struct (for verification only)
410 GNUNET_SERVER_client_set_user_context_ (struct GNUNET_SERVER_Client *client,
414 * Return user context associated with the given client.
416 * @param client client to query
417 * @param type expected return type (i.e. 'struct Foo')
418 * @return pointer to user context of type 'type *'.
420 #define GNUNET_SERVER_client_get_user_context(client,type) \
421 (type *) GNUNET_SERVER_client_get_user_context_ (client, sizeof (type))
424 * Set user context to be associated with the given client.
426 * @param client client to query
427 * @param value pointer to user context
429 #define GNUNET_SERVER_client_set_user_context(client,value) \
430 GNUNET_SERVER_client_set_user_context_ (client, value, sizeof (*value))
435 * Notify us when the server has enough space to transmit
436 * a message of the given size to the given client.
438 * @param client client to transmit message to
439 * @param size requested amount of buffer space
440 * @param timeout after how long should we give up (and call
441 * notify with buf NULL and size 0)?
442 * @param callback function to call when space is available
443 * @param callback_cls closure for @a callback
444 * @return non-NULL if the notify callback was queued; can be used
445 * to cancel the request using
446 * #GNUNET_SERVER_notify_transmit_ready_cancel.
447 * NULL if we are already going to notify someone else (busy)
449 struct GNUNET_SERVER_TransmitHandle *
450 GNUNET_SERVER_notify_transmit_ready (struct GNUNET_SERVER_Client *client,
452 struct GNUNET_TIME_Relative timeout,
453 GNUNET_CONNECTION_TransmitReadyNotify callback,
457 * Abort transmission request.
459 * @param th request to abort
462 GNUNET_SERVER_notify_transmit_ready_cancel (struct GNUNET_SERVER_TransmitHandle *th);
468 * Notify the server that the given client handle should
469 * be kept (keeps the connection up if possible, increments
470 * the internal reference counter).
472 * @param client the client to keep
475 GNUNET_SERVER_client_keep (struct GNUNET_SERVER_Client *client);
479 * Notify the server that the given client handle is no
480 * longer required. Decrements the reference counter. If
481 * that counter reaches zero an inactive connection maybe
484 * @param client the client to drop
487 GNUNET_SERVER_client_drop (struct GNUNET_SERVER_Client *client);
491 * Function called by the service's run
492 * method to run service-specific setup code.
495 * @param server the initialized server
496 * @param cfg configuration to use
499 (*LEGACY_SERVICE_Main) (void *cls,
500 struct GNUNET_SERVER_Handle *server,
501 const struct GNUNET_CONFIGURATION_Handle *cfg);
506 * Suspend accepting connections from the listen socket temporarily.
507 * Resume activity using #GNUNET_SERVER_resume.
509 * @param server server to stop accepting connections.
512 GNUNET_SERVER_suspend (struct GNUNET_SERVER_Handle *server);
515 * Notify us when the server has enough space to transmit
516 * a message of the given size to the given client.
518 * @param client client to transmit message to
519 * @param size requested amount of buffer space
520 * @param timeout after how long should we give up (and call
521 * notify with buf NULL and size 0)?
522 * @param callback function to call when space is available
523 * @param callback_cls closure for @a callback
524 * @return non-NULL if the notify callback was queued; can be used
525 * to cancel the request using
526 * #GNUNET_SERVER_notify_transmit_ready_cancel.
527 * NULL if we are already going to notify someone else (busy)
529 struct GNUNET_SERVER_TransmitHandle *
530 GNUNET_SERVER_notify_transmit_ready (struct GNUNET_SERVER_Client *client,
532 struct GNUNET_TIME_Relative timeout,
533 GNUNET_CONNECTION_TransmitReadyNotify callback,
538 * Add a TCP socket-based connection to the set of handles managed by
539 * this server. Use this function for outgoing (P2P) connections that
540 * we initiated (and where this server should process incoming
543 * @param server the server to use
544 * @param connection the connection to manage (client must
545 * stop using this connection from now on)
546 * @return the client handle
548 struct GNUNET_SERVER_Client *
549 GNUNET_SERVER_connect_socket (struct GNUNET_SERVER_Handle *server,
550 struct GNUNET_CONNECTION_Handle *connection);
554 * Resume accepting connections from the listen socket.
556 * @param server server to resume accepting connections.
559 GNUNET_SERVER_resume (struct GNUNET_SERVER_Handle *server);
562 * Free resources held by this server.
564 * @param server server to destroy
567 GNUNET_SERVER_destroy (struct GNUNET_SERVER_Handle *server);
572 #include "tcp_connection_legacy.c"
573 #include "tcp_server_mst_legacy.c"
574 #include "tcp_server_legacy.c"
575 #include "tcp_service_legacy.c"
577 GNUNET_NETWORK_STRUCT_BEGIN
580 * Initial handshake message for a session.
582 struct WelcomeMessage
585 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_WELCOME.
587 struct GNUNET_MessageHeader header;
590 * Identity of the node connecting (TCP client)
592 struct GNUNET_PeerIdentity clientIdentity;
597 * Basically a WELCOME message, but with the purpose
598 * of giving the waiting peer a client handle to use
600 struct TCP_NAT_ProbeMessage
603 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_NAT_PROBE.
605 struct GNUNET_MessageHeader header;
608 * Identity of the sender of the message.
610 struct GNUNET_PeerIdentity clientIdentity;
613 GNUNET_NETWORK_STRUCT_END
616 * Context for sending a NAT probe via TCP.
618 struct TCPProbeContext
622 * Active probes are kept in a DLL.
624 struct TCPProbeContext *next;
627 * Active probes are kept in a DLL.
629 struct TCPProbeContext *prev;
634 struct GNUNET_CONNECTION_Handle *sock;
637 * Message to be sent.
639 struct TCP_NAT_ProbeMessage message;
642 * Handle to the transmission.
644 struct GNUNET_CONNECTION_TransmitHandle *transmit_handle;
647 * Transport plugin handle.
649 struct Plugin *plugin;
653 * Bits in the `options` field of TCP addresses.
655 enum TcpAddressOptions
661 TCP_OPTIONS_NONE = 0,
664 * See #HTTP_OPTIONS_VERIFY_CERTIFICATE.
666 TCP_OPTIONS_RESERVED = 1,
669 * Enable TCP Stealth-style port knocking.
671 TCP_OPTIONS_TCP_STEALTH = 2
674 GNUNET_NETWORK_STRUCT_BEGIN
677 * Network format for IPv4 addresses.
679 struct IPv4TcpAddress
682 * Optional options and flags for this address,
683 * see `enum TcpAddressOptions`
685 uint32_t options GNUNET_PACKED;
688 * IPv4 address, in network byte order.
690 uint32_t ipv4_addr GNUNET_PACKED;
693 * Port number, in network byte order.
695 uint16_t t4_port GNUNET_PACKED;
700 * Network format for IPv6 addresses.
702 struct IPv6TcpAddress
705 * Optional flags for this address
706 * see `enum TcpAddressOptions`
708 uint32_t options GNUNET_PACKED;
713 struct in6_addr ipv6_addr GNUNET_PACKED;
716 * Port number, in network byte order.
718 uint16_t t6_port GNUNET_PACKED;
721 GNUNET_NETWORK_STRUCT_END
724 * Encapsulation of all of the state of the plugin.
729 * Information kept for each message that is yet to
732 struct PendingMessage
736 * This is a doubly-linked list.
738 struct PendingMessage *next;
741 * This is a doubly-linked list.
743 struct PendingMessage *prev;
746 * The pending message
751 * Continuation function to call once the message
752 * has been sent. Can be NULL if there is no
753 * continuation to call.
755 GNUNET_TRANSPORT_TransmitContinuation transmit_cont;
758 * Closure for @e transmit_cont.
760 void *transmit_cont_cls;
763 * Timeout value for the pending message.
765 struct GNUNET_TIME_Absolute timeout;
768 * So that the gnunet-service-transport can group messages together,
769 * these pending messages need to accept a message buffer and size
770 * instead of just a `struct GNUNET_MessageHeader`.
777 * Session handle for TCP connections.
779 struct GNUNET_ATS_Session
782 * To whom are we talking to (set to our identity
783 * if we are still waiting for the welcome message)
785 struct GNUNET_PeerIdentity target;
788 * Pointer to the global plugin struct.
790 struct Plugin *plugin;
793 * The client (used to identify this connection)
795 struct GNUNET_SERVER_Client *client;
798 * Task cleaning up a NAT client connection establishment attempt;
800 struct GNUNET_SCHEDULER_Task *nat_connection_timeout;
803 * Messages currently pending for transmission
804 * to this peer, if any.
806 struct PendingMessage *pending_messages_head;
809 * Messages currently pending for transmission
810 * to this peer, if any.
812 struct PendingMessage *pending_messages_tail;
815 * Handle for pending transmission request.
817 struct GNUNET_SERVER_TransmitHandle *transmit_handle;
820 * Address of the other peer.
822 struct GNUNET_HELLO_Address *address;
825 * ID of task used to delay receiving more to throttle sender.
827 struct GNUNET_SCHEDULER_Task *receive_delay_task;
830 * Session timeout task
832 struct GNUNET_SCHEDULER_Task *timeout_task;
835 * When will this session time out?
837 struct GNUNET_TIME_Absolute timeout;
840 * When will we continue to read from the socket?
841 * (used to enforce inbound quota).
843 struct GNUNET_TIME_Absolute receive_delay;
846 * Last activity on this connection. Used to select preferred
849 struct GNUNET_TIME_Absolute last_activity;
852 * Number of bytes waiting for transmission to this peer.
854 unsigned long long bytes_in_queue;
857 * Number of messages waiting for transmission to this peer.
859 unsigned int msgs_in_queue;
862 * Network type of the address.
864 enum GNUNET_NetworkType scope;
867 * Are we still expecting the welcome message? (#GNUNET_YES/#GNUNET_NO)
869 int expecting_welcome;
872 * Was this session created using NAT traversal?
880 * Context for address to string conversion, closure
881 * for #append_port().
883 struct PrettyPrinterContext
888 struct PrettyPrinterContext *next;
893 struct PrettyPrinterContext *prev;
898 struct Plugin *plugin;
903 struct GNUNET_SCHEDULER_Task *timeout_task;
908 struct GNUNET_RESOLVER_RequestHandle *resolver_handle;
911 * Function to call with the result.
913 GNUNET_TRANSPORT_AddressStringCallback asc;
916 * Clsoure for @e asc.
931 * Port to add after the IP address.
938 * Encapsulation of all of the state of the plugin.
945 struct GNUNET_TRANSPORT_PluginEnvironment *env;
950 struct GNUNET_CONNECTION_Handle *lsock;
953 * Our handle to the NAT module.
955 struct GNUNET_NAT_Handle *nat;
958 * Map from peer identities to sessions for the given peer.
960 struct GNUNET_CONTAINER_MultiPeerMap *sessionmap;
963 * Handle to the network service.
965 struct LEGACY_SERVICE_Context *service;
968 * Handle to the server for this service.
970 struct GNUNET_SERVER_Handle *server;
973 * Copy of the handler array where the closures are
974 * set to this struct's instance.
976 struct GNUNET_SERVER_MessageHandler *handlers;
979 * Map of peers we have tried to contact behind a NAT
981 struct GNUNET_CONTAINER_MultiPeerMap *nat_wait_conns;
984 * List of active TCP probes.
986 struct TCPProbeContext *probe_head;
989 * List of active TCP probes.
991 struct TCPProbeContext *probe_tail;
994 * Function to call about session status changes.
996 GNUNET_TRANSPORT_SessionInfoCallback sic;
999 * Closure for @e sic.
1004 * ID of task used to update our addresses when one expires.
1006 struct GNUNET_SCHEDULER_Task *address_update_task;
1009 * Running pretty printers: head
1011 struct PrettyPrinterContext *ppc_dll_head;
1014 * Running pretty printers: tail
1016 struct PrettyPrinterContext *ppc_dll_tail;
1019 * Welcome message used by this peer.
1021 struct WelcomeMessage my_welcome;
1024 * How many more TCP sessions are we allowed to open right now?
1026 unsigned long long max_connections;
1029 * How many more TCP sessions do we have right now?
1031 unsigned long long cur_connections;
1039 * Port that we are actually listening on.
1044 * Port that the user said we would have visible to the
1045 * rest of the world.
1053 * Get the list of addresses that a server for the given service
1056 * @param service_name name of the service
1057 * @param cfg configuration (which specifies the addresses)
1058 * @param addrs set (call by reference) to an array of pointers to the
1059 * addresses the server should bind to and listen on; the
1060 * array will be NULL-terminated (on success)
1061 * @param addr_lens set (call by reference) to an array of the lengths
1062 * of the respective `struct sockaddr` struct in the @a addrs
1063 * array (on success)
1064 * @return number of addresses found on success,
1065 * #GNUNET_SYSERR if the configuration
1066 * did not specify reasonable finding information or
1067 * if it specified a hostname that could not be resolved;
1068 * #GNUNET_NO if the number of addresses configured is
1069 * zero (in this case, `*addrs` and `*addr_lens` will be
1073 get_server_addresses (const char *service_name,
1074 const struct GNUNET_CONFIGURATION_Handle *cfg,
1075 struct sockaddr ***addrs,
1076 socklen_t ** addr_lens)
1079 struct GNUNET_NETWORK_Handle *desc;
1080 unsigned long long port;
1082 struct addrinfo hints;
1083 struct addrinfo *res;
1084 struct addrinfo *pos;
1085 struct addrinfo *next;
1090 struct sockaddr **saddrs;
1091 socklen_t *saddrlens;
1097 if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "DISABLEV6"))
1099 if (GNUNET_SYSERR ==
1101 GNUNET_CONFIGURATION_get_value_yesno (cfg, service_name, "DISABLEV6")))
1102 return GNUNET_SYSERR;
1105 disablev6 = GNUNET_NO;
1109 /* probe IPv6 support */
1110 desc = GNUNET_NETWORK_socket_create (PF_INET6, SOCK_STREAM, 0);
1113 if ((ENOBUFS == errno) || (ENOMEM == errno) || (ENFILE == errno) ||
1116 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "socket");
1117 return GNUNET_SYSERR;
1119 LOG (GNUNET_ERROR_TYPE_INFO,
1120 _("Disabling IPv6 support for service `%s', failed to create IPv6 socket: %s\n"),
1121 service_name, STRERROR (errno));
1122 disablev6 = GNUNET_YES;
1126 GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (desc));
1132 if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "PORT"))
1135 GNUNET_CONFIGURATION_get_value_number (cfg, service_name,
1138 LOG (GNUNET_ERROR_TYPE_ERROR,
1139 _("Require valid port number for service `%s' in configuration!\n"),
1144 LOG (GNUNET_ERROR_TYPE_ERROR,
1145 _("Require valid port number for service `%s' in configuration!\n"),
1147 return GNUNET_SYSERR;
1151 if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "BINDTO"))
1153 GNUNET_break (GNUNET_OK ==
1154 GNUNET_CONFIGURATION_get_value_string (cfg, service_name,
1155 "BINDTO", &hostname));
1161 abstract = GNUNET_NO;
1164 GNUNET_CONFIGURATION_have_value (cfg, service_name, "UNIXPATH")) &&
1166 GNUNET_CONFIGURATION_get_value_filename (cfg, service_name, "UNIXPATH",
1168 (0 < strlen (unixpath)))
1170 /* probe UNIX support */
1171 struct sockaddr_un s_un;
1173 if (strlen (unixpath) >= sizeof (s_un.sun_path))
1175 LOG (GNUNET_ERROR_TYPE_WARNING,
1176 _("UNIXPATH `%s' too long, maximum length is %llu\n"), unixpath,
1177 (unsigned long long) sizeof (s_un.sun_path));
1178 unixpath = GNUNET_NETWORK_shorten_unixpath (unixpath);
1179 LOG (GNUNET_ERROR_TYPE_INFO,
1180 _("Using `%s' instead\n"),
1184 abstract = GNUNET_CONFIGURATION_get_value_yesno (cfg,
1186 "USE_ABSTRACT_SOCKETS");
1187 if (GNUNET_SYSERR == abstract)
1188 abstract = GNUNET_NO;
1190 if ((GNUNET_YES != abstract)
1192 GNUNET_DISK_directory_create_for_file (unixpath)))
1193 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
1197 if (NULL != unixpath)
1199 desc = GNUNET_NETWORK_socket_create (AF_UNIX, SOCK_STREAM, 0);
1202 if ((ENOBUFS == errno) || (ENOMEM == errno) || (ENFILE == errno) ||
1205 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "socket");
1206 GNUNET_free_non_null (hostname);
1207 GNUNET_free (unixpath);
1208 return GNUNET_SYSERR;
1210 LOG (GNUNET_ERROR_TYPE_INFO,
1211 _("Disabling UNIX domain socket support for service `%s', failed to create UNIX domain socket: %s\n"),
1214 GNUNET_free (unixpath);
1219 GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (desc));
1225 if ((0 == port) && (NULL == unixpath))
1227 LOG (GNUNET_ERROR_TYPE_ERROR,
1228 _("Have neither PORT nor UNIXPATH for service `%s', but one is required\n"),
1230 GNUNET_free_non_null (hostname);
1231 return GNUNET_SYSERR;
1235 saddrs = GNUNET_malloc (2 * sizeof (struct sockaddr *));
1236 saddrlens = GNUNET_malloc (2 * sizeof (socklen_t));
1237 add_unixpath (saddrs, saddrlens, unixpath, abstract);
1238 GNUNET_free_non_null (unixpath);
1239 GNUNET_free_non_null (hostname);
1241 *addr_lens = saddrlens;
1245 if (NULL != hostname)
1247 LOG (GNUNET_ERROR_TYPE_DEBUG,
1248 "Resolving `%s' since that is where `%s' will bind to.\n",
1251 memset (&hints, 0, sizeof (struct addrinfo));
1253 hints.ai_family = AF_INET;
1254 hints.ai_protocol = IPPROTO_TCP;
1255 if ((0 != (ret = getaddrinfo (hostname, NULL, &hints, &res))) ||
1258 LOG (GNUNET_ERROR_TYPE_ERROR,
1259 _("Failed to resolve `%s': %s\n"),
1261 gai_strerror (ret));
1262 GNUNET_free (hostname);
1263 GNUNET_free_non_null (unixpath);
1264 return GNUNET_SYSERR;
1268 while (NULL != (pos = next))
1270 next = pos->ai_next;
1271 if ((disablev6) && (pos->ai_family == AF_INET6))
1277 LOG (GNUNET_ERROR_TYPE_ERROR,
1278 _("Failed to find %saddress for `%s'.\n"),
1279 disablev6 ? "IPv4 " : "",
1282 GNUNET_free (hostname);
1283 GNUNET_free_non_null (unixpath);
1284 return GNUNET_SYSERR;
1287 if (NULL != unixpath)
1289 saddrs = GNUNET_malloc ((resi + 1) * sizeof (struct sockaddr *));
1290 saddrlens = GNUNET_malloc ((resi + 1) * sizeof (socklen_t));
1292 if (NULL != unixpath)
1294 add_unixpath (saddrs, saddrlens, unixpath, abstract);
1298 while (NULL != (pos = next))
1300 next = pos->ai_next;
1301 if ((disablev6) && (AF_INET6 == pos->ai_family))
1303 if ((IPPROTO_TCP != pos->ai_protocol) && (0 != pos->ai_protocol))
1304 continue; /* not TCP */
1305 if ((SOCK_STREAM != pos->ai_socktype) && (0 != pos->ai_socktype))
1306 continue; /* huh? */
1307 LOG (GNUNET_ERROR_TYPE_DEBUG, "Service `%s' will bind to `%s'\n",
1308 service_name, GNUNET_a2s (pos->ai_addr, pos->ai_addrlen));
1309 if (AF_INET == pos->ai_family)
1311 GNUNET_assert (sizeof (struct sockaddr_in) == pos->ai_addrlen);
1312 saddrlens[i] = pos->ai_addrlen;
1313 saddrs[i] = GNUNET_malloc (saddrlens[i]);
1314 GNUNET_memcpy (saddrs[i], pos->ai_addr, saddrlens[i]);
1315 ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
1319 GNUNET_assert (AF_INET6 == pos->ai_family);
1320 GNUNET_assert (sizeof (struct sockaddr_in6) == pos->ai_addrlen);
1321 saddrlens[i] = pos->ai_addrlen;
1322 saddrs[i] = GNUNET_malloc (saddrlens[i]);
1323 GNUNET_memcpy (saddrs[i], pos->ai_addr, saddrlens[i]);
1324 ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port);
1328 GNUNET_free (hostname);
1334 /* will bind against everything, just set port */
1339 if (NULL != unixpath)
1342 saddrs = GNUNET_malloc ((resi + 1) * sizeof (struct sockaddr *));
1343 saddrlens = GNUNET_malloc ((resi + 1) * sizeof (socklen_t));
1344 if (NULL != unixpath)
1346 add_unixpath (saddrs, saddrlens, unixpath, abstract);
1349 saddrlens[i] = sizeof (struct sockaddr_in);
1350 saddrs[i] = GNUNET_malloc (saddrlens[i]);
1351 #if HAVE_SOCKADDR_IN_SIN_LEN
1352 ((struct sockaddr_in *) saddrs[i])->sin_len = saddrlens[i];
1354 ((struct sockaddr_in *) saddrs[i])->sin_family = AF_INET;
1355 ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
1361 if (NULL != unixpath)
1363 saddrs = GNUNET_malloc ((resi + 1) * sizeof (struct sockaddr *));
1364 saddrlens = GNUNET_malloc ((resi + 1) * sizeof (socklen_t));
1366 if (NULL != unixpath)
1368 add_unixpath (saddrs, saddrlens, unixpath, abstract);
1371 saddrlens[i] = sizeof (struct sockaddr_in6);
1372 saddrs[i] = GNUNET_malloc (saddrlens[i]);
1373 #if HAVE_SOCKADDR_IN_SIN_LEN
1374 ((struct sockaddr_in6 *) saddrs[i])->sin6_len = saddrlens[0];
1376 ((struct sockaddr_in6 *) saddrs[i])->sin6_family = AF_INET6;
1377 ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port);
1379 saddrlens[i] = sizeof (struct sockaddr_in);
1380 saddrs[i] = GNUNET_malloc (saddrlens[i]);
1381 #if HAVE_SOCKADDR_IN_SIN_LEN
1382 ((struct sockaddr_in *) saddrs[i])->sin_len = saddrlens[1];
1384 ((struct sockaddr_in *) saddrs[i])->sin_family = AF_INET;
1385 ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
1388 GNUNET_free_non_null (unixpath);
1390 *addr_lens = saddrlens;
1393 /* end ancient copy-and-paste */
1397 * If a session monitor is attached, notify it about the new
1400 * @param plugin our plugin
1401 * @param session session that changed state
1402 * @param state new state of the session
1405 notify_session_monitor (struct Plugin *plugin,
1406 struct GNUNET_ATS_Session *session,
1407 enum GNUNET_TRANSPORT_SessionState state)
1409 struct GNUNET_TRANSPORT_SessionInfo info;
1411 if (NULL == plugin->sic)
1413 memset (&info, 0, sizeof (info));
1415 info.is_inbound = GNUNET_HELLO_address_check_option (session->address,
1416 GNUNET_HELLO_ADDRESS_INFO_INBOUND);
1417 info.num_msg_pending = session->msgs_in_queue;
1418 info.num_bytes_pending = session->bytes_in_queue;
1419 if (NULL != session->receive_delay_task)
1420 info.receive_delay = session->receive_delay;
1421 info.session_timeout = session->timeout;
1422 info.address = session->address;
1423 plugin->sic (plugin->sic_cls,
1430 * Our external IP address/port mapping has changed.
1432 * @param cls closure, the `struct Plugin`
1433 * @param app_ctx[in,out] location where the app can store stuff
1434 * on add and retrieve it on remove
1435 * @param add_remove #GNUNET_YES to mean the new public IP address, #GNUNET_NO to mean
1436 * the previous (now invalid) one
1437 * @param ac address class the address belongs to
1438 * @param addr either the previous or the new public IP address
1439 * @param addrlen actual length of @a addr
1442 tcp_nat_port_map_callback (void *cls,
1445 enum GNUNET_NAT_AddressClass ac,
1446 const struct sockaddr *addr,
1449 struct Plugin *plugin = cls;
1450 struct GNUNET_HELLO_Address *address;
1451 struct IPv4TcpAddress t4;
1452 struct IPv6TcpAddress t6;
1457 LOG (GNUNET_ERROR_TYPE_INFO,
1458 "NAT notification to %s address `%s'\n",
1459 (GNUNET_YES == add_remove) ? "add" : "remove",
1460 GNUNET_a2s (addr, addrlen));
1461 /* convert 'addr' to our internal format */
1462 switch (addr->sa_family)
1465 GNUNET_assert(addrlen == sizeof(struct sockaddr_in));
1466 memset (&t4, 0, sizeof(t4));
1467 t4.options = htonl (plugin->myoptions);
1468 t4.ipv4_addr = ((struct sockaddr_in *) addr)->sin_addr.s_addr;
1469 t4.t4_port = ((struct sockaddr_in *) addr)->sin_port;
1474 if (IN6_IS_ADDR_LINKLOCAL (&((struct sockaddr_in6 *) addr)->sin6_addr))
1476 /* skip link local, we don't allow them in
1477 #tcp_plugin_check_address() */
1480 GNUNET_assert(addrlen == sizeof(struct sockaddr_in6));
1481 memset (&t6, 0, sizeof(t6));
1482 GNUNET_memcpy (&t6.ipv6_addr,
1483 &((struct sockaddr_in6 *) addr)->sin6_addr,
1484 sizeof(struct in6_addr));
1485 t6.options = htonl (plugin->myoptions);
1486 t6.t6_port = ((struct sockaddr_in6 *) addr)->sin6_port;
1494 /* modify our published address list */
1495 GNUNET_assert ((args == sizeof (struct IPv4TcpAddress)) ||
1496 (args == sizeof (struct IPv6TcpAddress)));
1497 /* TODO: use 'ac' here in the future... */
1498 address = GNUNET_HELLO_address_allocate (plugin->env->my_identity,
1502 GNUNET_HELLO_ADDRESS_INFO_NONE);
1503 plugin->env->notify_address (plugin->env->cls,
1506 GNUNET_HELLO_address_free (address);
1511 * Function called for a quick conversion of the binary address to
1512 * a numeric address. Note that the caller must not free the
1513 * address and that the next call to this function is allowed
1514 * to override the address again.
1516 * @param cls closure (`struct Plugin*`)
1517 * @param addr binary address
1518 * @param addrlen length of @a addr
1519 * @return string representing the same address
1522 tcp_plugin_address_to_string (void *cls,
1526 static char rbuf[INET6_ADDRSTRLEN + 12];
1527 char buf[INET6_ADDRSTRLEN];
1531 const struct IPv4TcpAddress *t4;
1532 const struct IPv6TcpAddress *t6;
1539 case sizeof(struct IPv6TcpAddress):
1542 port = ntohs (t6->t6_port);
1543 options = ntohl (t6->options);
1544 GNUNET_memcpy (&a6, &t6->ipv6_addr, sizeof(a6));
1547 case sizeof(struct IPv4TcpAddress):
1550 port = ntohs (t4->t4_port);
1551 options = ntohl (t4->options);
1552 GNUNET_memcpy (&a4, &t4->ipv4_addr, sizeof(a4));
1556 LOG (GNUNET_ERROR_TYPE_WARNING,
1557 _("Unexpected address length: %u bytes\n"),
1558 (unsigned int) addrlen);
1561 if (NULL == inet_ntop (af, sb, buf, INET6_ADDRSTRLEN))
1563 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
1567 GNUNET_snprintf (rbuf, sizeof(rbuf),
1568 (af == AF_INET6) ? "%s.%u.[%s]:%u" : "%s.%u.%s:%u",
1578 * Function called to convert a string address to
1581 * @param cls closure (`struct Plugin*`)
1582 * @param addr string address
1583 * @param addrlen length of the address
1584 * @param buf location to store the buffer
1585 * @param added location to store the number of bytes in the buffer.
1586 * If the function returns #GNUNET_SYSERR, its contents are undefined.
1587 * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure
1590 tcp_plugin_string_to_address (void *cls,
1596 struct sockaddr_storage socket_address;
1602 /* Format tcp.options.address:port */
1606 if ((NULL == addr) || (0 == addrlen))
1609 return GNUNET_SYSERR;
1611 if ('\0' != addr[addrlen - 1])
1614 return GNUNET_SYSERR;
1616 if (strlen (addr) != addrlen - 1)
1619 return GNUNET_SYSERR;
1621 plugin = GNUNET_strdup (addr);
1622 optionstr = strchr (plugin, '.');
1623 if (NULL == optionstr)
1626 GNUNET_free(plugin);
1627 return GNUNET_SYSERR;
1629 optionstr[0] = '\0';
1631 options = atol (optionstr);
1632 address = strchr (optionstr, '.');
1633 if (NULL == address)
1636 GNUNET_free(plugin);
1637 return GNUNET_SYSERR;
1643 GNUNET_STRINGS_to_address_ip (address,
1648 GNUNET_free(plugin);
1649 return GNUNET_SYSERR;
1652 GNUNET_free(plugin);
1653 switch (socket_address.ss_family)
1657 struct IPv4TcpAddress *t4;
1658 struct sockaddr_in *in4 = (struct sockaddr_in *) &socket_address;
1659 t4 = GNUNET_new (struct IPv4TcpAddress);
1660 t4->options = htonl (options);
1661 t4->ipv4_addr = in4->sin_addr.s_addr;
1662 t4->t4_port = in4->sin_port;
1664 *added = sizeof(struct IPv4TcpAddress);
1669 struct IPv6TcpAddress *t6;
1670 struct sockaddr_in6 *in6 = (struct sockaddr_in6 *) &socket_address;
1671 t6 = GNUNET_new (struct IPv6TcpAddress);
1672 t6->options = htonl (options);
1673 t6->ipv6_addr = in6->sin6_addr;
1674 t6->t6_port = in6->sin6_port;
1676 *added = sizeof(struct IPv6TcpAddress);
1680 return GNUNET_SYSERR;
1686 * Find the session handle for the given client.
1687 * Currently uses both the hashmap and the client
1688 * context, as the client context is new and the
1689 * logic still needs to be tested.
1691 * @param plugin the plugin
1692 * @param client which client to find the session handle for
1693 * @return NULL if no matching session exists
1695 static struct GNUNET_ATS_Session *
1696 lookup_session_by_client (struct Plugin *plugin,
1697 struct GNUNET_SERVER_Client *client)
1699 return GNUNET_SERVER_client_get_user_context (client,
1700 struct GNUNET_ATS_Session);
1705 * Functions with this signature are called whenever we need
1706 * to close a session due to a disconnect or failure to
1707 * establish a connection.
1709 * @param cls the `struct Plugin`
1710 * @param session session to close down
1711 * @return #GNUNET_OK on success
1714 tcp_plugin_disconnect_session (void *cls,
1715 struct GNUNET_ATS_Session *session)
1717 struct Plugin *plugin = cls;
1718 struct PendingMessage *pm;
1720 LOG (GNUNET_ERROR_TYPE_DEBUG,
1721 "Disconnecting session of peer `%s' address `%s'\n",
1722 GNUNET_i2s (&session->target),
1723 tcp_plugin_address_to_string (session->plugin,
1724 session->address->address,
1725 session->address->address_length));
1727 if (NULL != session->timeout_task)
1729 GNUNET_SCHEDULER_cancel (session->timeout_task);
1730 session->timeout_task = NULL;
1731 session->timeout = GNUNET_TIME_UNIT_ZERO_ABS;
1735 GNUNET_CONTAINER_multipeermap_remove (plugin->sessionmap,
1739 GNUNET_STATISTICS_update (session->plugin->env->stats,
1740 gettext_noop ("# TCP sessions active"),
1746 GNUNET_assert (GNUNET_YES ==
1747 GNUNET_CONTAINER_multipeermap_remove (plugin->nat_wait_conns,
1751 if (NULL != session->client)
1752 GNUNET_SERVER_client_set_user_context (session->client,
1755 /* clean up state */
1756 if (NULL != session->transmit_handle)
1758 GNUNET_SERVER_notify_transmit_ready_cancel (session->transmit_handle);
1759 session->transmit_handle = NULL;
1761 session->plugin->env->session_end (session->plugin->env->cls,
1765 if (NULL != session->nat_connection_timeout)
1767 GNUNET_SCHEDULER_cancel (session->nat_connection_timeout);
1768 session->nat_connection_timeout = NULL;
1771 while (NULL != (pm = session->pending_messages_head))
1773 LOG (GNUNET_ERROR_TYPE_DEBUG,
1774 (NULL != pm->transmit_cont)
1775 ? "Could not deliver message to `%s' at %s.\n"
1776 : "Could not deliver message to `%s' at %s, notifying.\n",
1777 GNUNET_i2s (&session->target),
1778 tcp_plugin_address_to_string (session->plugin,
1779 session->address->address,
1780 session->address->address_length));
1781 GNUNET_STATISTICS_update (session->plugin->env->stats,
1782 gettext_noop ("# bytes currently in TCP buffers"),
1783 -(int64_t) pm->message_size, GNUNET_NO);
1784 GNUNET_STATISTICS_update (session->plugin->env->stats,
1785 gettext_noop ("# bytes discarded by TCP (disconnect)"),
1788 GNUNET_CONTAINER_DLL_remove (session->pending_messages_head,
1789 session->pending_messages_tail,
1791 GNUNET_assert (0 < session->msgs_in_queue);
1792 session->msgs_in_queue--;
1793 GNUNET_assert (pm->message_size <= session->bytes_in_queue);
1794 session->bytes_in_queue -= pm->message_size;
1795 if (NULL != pm->transmit_cont)
1796 pm->transmit_cont (pm->transmit_cont_cls,
1803 GNUNET_assert (0 == session->msgs_in_queue);
1804 GNUNET_assert (0 == session->bytes_in_queue);
1805 notify_session_monitor (session->plugin,
1807 GNUNET_TRANSPORT_SS_DONE);
1809 if (NULL != session->receive_delay_task)
1811 GNUNET_SCHEDULER_cancel (session->receive_delay_task);
1812 session->receive_delay_task = NULL;
1814 if (NULL != session->client)
1816 GNUNET_SERVER_client_disconnect (session->client);
1817 session->client = NULL;
1819 GNUNET_HELLO_address_free (session->address);
1820 GNUNET_assert (NULL == session->transmit_handle);
1821 GNUNET_free (session);
1827 * Function that is called to get the keepalive factor.
1828 * #GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT is divided by this number to
1829 * calculate the interval between keepalive packets.
1831 * @param cls closure with the `struct Plugin`
1832 * @return keepalive factor
1835 tcp_plugin_query_keepalive_factor (void *cls)
1842 * Session was idle for too long, so disconnect it
1844 * @param cls the `struct GNUNET_ATS_Session` of the idle session
1847 session_timeout (void *cls)
1849 struct GNUNET_ATS_Session *s = cls;
1850 struct GNUNET_TIME_Relative left;
1852 s->timeout_task = NULL;
1853 left = GNUNET_TIME_absolute_get_remaining (s->timeout);
1854 if (0 != left.rel_value_us)
1856 /* not actually our turn yet, but let's at least update
1857 the monitor, it may think we're about to die ... */
1858 notify_session_monitor (s->plugin,
1860 GNUNET_TRANSPORT_SS_UPDATE);
1861 s->timeout_task = GNUNET_SCHEDULER_add_delayed (left,
1866 LOG (GNUNET_ERROR_TYPE_DEBUG,
1867 "Session %p was idle for %s, disconnecting\n",
1869 GNUNET_STRINGS_relative_time_to_string (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
1871 /* call session destroy function */
1872 tcp_plugin_disconnect_session (s->plugin,
1878 * Increment session timeout due to activity.
1880 * @param s session to increment timeout for
1883 reschedule_session_timeout (struct GNUNET_ATS_Session *s)
1885 GNUNET_assert (NULL != s->timeout_task);
1886 s->timeout = GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1891 * Create a new session. Also queues a welcome message.
1893 * @param plugin the plugin
1894 * @param address the address to create the session for
1895 * @param scope network scope the address is from
1896 * @param client client to use, reference counter must have already been increased
1897 * @param is_nat this a NAT session, we should wait for a client to
1898 * connect to us from an address, then assign that to
1900 * @return new session object
1902 static struct GNUNET_ATS_Session *
1903 create_session (struct Plugin *plugin,
1904 const struct GNUNET_HELLO_Address *address,
1905 enum GNUNET_NetworkType scope,
1906 struct GNUNET_SERVER_Client *client,
1909 struct GNUNET_ATS_Session *session;
1910 struct PendingMessage *pm;
1912 if (GNUNET_YES != is_nat)
1913 GNUNET_assert (NULL != client);
1915 GNUNET_assert (NULL == client);
1917 LOG (GNUNET_ERROR_TYPE_DEBUG,
1918 "Creating new session for peer `%s' at address %s\n",
1919 GNUNET_i2s (&address->peer),
1920 tcp_plugin_address_to_string (plugin,
1922 address->address_length));
1923 session = GNUNET_new (struct GNUNET_ATS_Session);
1924 session->last_activity = GNUNET_TIME_absolute_get ();
1925 session->plugin = plugin;
1926 session->is_nat = is_nat;
1929 session->client = client;
1930 GNUNET_SERVER_client_set_user_context (client,
1933 session->address = GNUNET_HELLO_address_copy (address);
1934 session->target = address->peer;
1935 session->expecting_welcome = GNUNET_YES;
1936 session->scope = scope;
1937 pm = GNUNET_malloc (sizeof (struct PendingMessage) +
1938 sizeof (struct WelcomeMessage));
1939 pm->msg = (const char *) &pm[1];
1940 pm->message_size = sizeof(struct WelcomeMessage);
1941 GNUNET_memcpy (&pm[1],
1942 &plugin->my_welcome,
1943 sizeof(struct WelcomeMessage));
1944 pm->timeout = GNUNET_TIME_UNIT_FOREVER_ABS;
1945 GNUNET_STATISTICS_update (plugin->env->stats,
1946 gettext_noop ("# bytes currently in TCP buffers"),
1949 GNUNET_CONTAINER_DLL_insert (session->pending_messages_head,
1950 session->pending_messages_tail,
1952 session->msgs_in_queue++;
1953 session->bytes_in_queue += pm->message_size;
1954 session->timeout = GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1955 session->timeout_task = GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
1958 notify_session_monitor (session->plugin,
1960 GNUNET_TRANSPORT_SS_INIT);
1961 if (GNUNET_YES != is_nat)
1963 GNUNET_STATISTICS_update (plugin->env->stats,
1964 gettext_noop ("# TCP sessions active"),
1967 notify_session_monitor (session->plugin,
1969 GNUNET_TRANSPORT_SS_UP);
1973 notify_session_monitor (session->plugin,
1975 GNUNET_TRANSPORT_SS_HANDSHAKE);
1982 * If we have pending messages, ask the server to
1983 * transmit them (schedule the respective tasks, etc.)
1985 * @param session for which session should we do this
1988 process_pending_messages (struct GNUNET_ATS_Session *session);
1992 * Function called to notify a client about the socket
1993 * being ready to queue more data. "buf" will be
1994 * NULL and "size" zero if the socket was closed for
1995 * writing in the meantime.
1997 * @param cls closure
1998 * @param size number of bytes available in @a buf
1999 * @param buf where the callee should write the message
2000 * @return number of bytes written to @a buf
2003 do_transmit (void *cls,
2007 struct GNUNET_ATS_Session *session = cls;
2008 struct GNUNET_PeerIdentity pid;
2009 struct Plugin *plugin;
2010 struct PendingMessage *pos;
2011 struct PendingMessage *hd;
2012 struct PendingMessage *tl;
2013 struct GNUNET_TIME_Absolute now;
2017 session->transmit_handle = NULL;
2018 plugin = session->plugin;
2021 LOG (GNUNET_ERROR_TYPE_DEBUG,
2022 "Timeout trying to transmit to peer `%s', discarding message queue.\n",
2023 GNUNET_i2s (&session->target));
2024 /* timeout; cancel all messages that have already expired */
2028 now = GNUNET_TIME_absolute_get ();
2029 while ( (NULL != (pos = session->pending_messages_head)) &&
2030 (pos->timeout.abs_value_us <= now.abs_value_us) )
2032 GNUNET_CONTAINER_DLL_remove (session->pending_messages_head,
2033 session->pending_messages_tail,
2035 GNUNET_assert (0 < session->msgs_in_queue);
2036 session->msgs_in_queue--;
2037 GNUNET_assert (pos->message_size <= session->bytes_in_queue);
2038 session->bytes_in_queue -= pos->message_size;
2039 LOG (GNUNET_ERROR_TYPE_DEBUG,
2040 "Failed to transmit %u byte message to `%s'.\n",
2042 GNUNET_i2s (&session->target));
2043 ret += pos->message_size;
2044 GNUNET_CONTAINER_DLL_insert_after (hd,
2049 /* do this call before callbacks (so that if callbacks destroy
2050 * session, they have a chance to cancel actions done by this
2052 process_pending_messages (session);
2053 pid = session->target;
2054 /* no do callbacks and do not use session again since
2055 * the callbacks may abort the session */
2056 while (NULL != (pos = hd))
2058 GNUNET_CONTAINER_DLL_remove (hd,
2061 if (NULL != pos->transmit_cont)
2062 pos->transmit_cont (pos->transmit_cont_cls,
2069 GNUNET_STATISTICS_update (plugin->env->stats,
2070 gettext_noop ("# bytes currently in TCP buffers"), -(int64_t) ret,
2072 GNUNET_STATISTICS_update (plugin->env->stats,
2073 gettext_noop ("# bytes discarded by TCP (timeout)"),
2077 notify_session_monitor (session->plugin,
2079 GNUNET_TRANSPORT_SS_UPDATE);
2082 /* copy all pending messages that would fit */
2087 while (NULL != (pos = session->pending_messages_head))
2089 if (ret + pos->message_size > size)
2091 GNUNET_CONTAINER_DLL_remove (session->pending_messages_head,
2092 session->pending_messages_tail,
2094 GNUNET_assert (0 < session->msgs_in_queue);
2095 session->msgs_in_queue--;
2096 GNUNET_assert (pos->message_size <= session->bytes_in_queue);
2097 session->bytes_in_queue -= pos->message_size;
2098 GNUNET_assert(size >= pos->message_size);
2099 LOG (GNUNET_ERROR_TYPE_DEBUG,
2100 "Transmitting message of type %u size %u to peer %s at %s\n",
2101 ntohs (((struct GNUNET_MessageHeader *) pos->msg)->type),
2103 GNUNET_i2s (&session->target),
2104 tcp_plugin_address_to_string (session->plugin,
2105 session->address->address,
2106 session->address->address_length));
2107 /* FIXME: this GNUNET_memcpy can be up to 7% of our total runtime */
2108 GNUNET_memcpy (cbuf,
2111 cbuf += pos->message_size;
2112 ret += pos->message_size;
2113 size -= pos->message_size;
2114 GNUNET_CONTAINER_DLL_insert_tail (hd,
2118 notify_session_monitor (session->plugin,
2120 GNUNET_TRANSPORT_SS_UPDATE);
2121 /* schedule 'continuation' before callbacks so that callbacks that
2122 * cancel everything don't cause us to use a session that no longer
2124 process_pending_messages (session);
2125 session->last_activity = GNUNET_TIME_absolute_get ();
2126 pid = session->target;
2127 /* we'll now call callbacks that may cancel the session; hence
2128 * we should not use 'session' after this point */
2129 while (NULL != (pos = hd))
2131 GNUNET_CONTAINER_DLL_remove (hd, tl, pos);
2132 if (NULL != pos->transmit_cont)
2133 pos->transmit_cont (pos->transmit_cont_cls,
2137 pos->message_size); /* FIXME: include TCP overhead */
2140 GNUNET_assert (NULL == hd);
2141 GNUNET_assert (NULL == tl);
2142 GNUNET_STATISTICS_update (plugin->env->stats,
2143 gettext_noop ("# bytes currently in TCP buffers"),
2146 GNUNET_STATISTICS_update (plugin->env->stats,
2147 gettext_noop ("# bytes transmitted via TCP"),
2155 * If we have pending messages, ask the server to
2156 * transmit them (schedule the respective tasks, etc.)
2158 * @param session for which session should we do this
2161 process_pending_messages (struct GNUNET_ATS_Session *session)
2163 struct PendingMessage *pm;
2165 GNUNET_assert (NULL != session->client);
2166 if (NULL != session->transmit_handle)
2168 if (NULL == (pm = session->pending_messages_head))
2171 session->transmit_handle
2172 = GNUNET_SERVER_notify_transmit_ready (session->client,
2174 GNUNET_TIME_absolute_get_remaining (pm->timeout),
2181 * Function that can be used by the transport service to transmit
2182 * a message using the plugin. Note that in the case of a
2183 * peer disconnecting, the continuation MUST be called
2184 * prior to the disconnect notification itself. This function
2185 * will be called with this peer's HELLO message to initiate
2186 * a fresh connection to another peer.
2188 * @param cls closure
2189 * @param session which session must be used
2190 * @param msgbuf the message to transmit
2191 * @param msgbuf_size number of bytes in @a msgbuf
2192 * @param priority how important is the message (most plugins will
2193 * ignore message priority and just FIFO)
2194 * @param to how long to wait at most for the transmission (does not
2195 * require plugins to discard the message after the timeout,
2196 * just advisory for the desired delay; most plugins will ignore
2198 * @param cont continuation to call once the message has
2199 * been transmitted (or if the transport is ready
2200 * for the next transmission call; or if the
2201 * peer disconnected...); can be NULL
2202 * @param cont_cls closure for @a cont
2203 * @return number of bytes used (on the physical network, with overheads);
2204 * -1 on hard errors (i.e. address invalid); 0 is a legal value
2205 * and does NOT mean that the message was not transmitted (DV)
2208 tcp_plugin_send (void *cls,
2209 struct GNUNET_ATS_Session *session,
2212 unsigned int priority,
2213 struct GNUNET_TIME_Relative to,
2214 GNUNET_TRANSPORT_TransmitContinuation cont,
2217 struct Plugin * plugin = cls;
2218 struct PendingMessage *pm;
2220 /* create new message entry */
2221 pm = GNUNET_malloc (sizeof (struct PendingMessage) + msgbuf_size);
2222 pm->msg = (const char *) &pm[1];
2223 GNUNET_memcpy (&pm[1], msgbuf, msgbuf_size);
2224 pm->message_size = msgbuf_size;
2225 pm->timeout = GNUNET_TIME_relative_to_absolute (to);
2226 pm->transmit_cont = cont;
2227 pm->transmit_cont_cls = cont_cls;
2229 LOG (GNUNET_ERROR_TYPE_DEBUG,
2230 "Asked to transmit %u bytes to `%s', added message to list.\n",
2232 GNUNET_i2s (&session->target));
2235 GNUNET_CONTAINER_multipeermap_contains_value (plugin->sessionmap,
2239 GNUNET_assert (NULL != session->client);
2240 GNUNET_SERVER_client_set_timeout (session->client,
2241 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2242 GNUNET_STATISTICS_update (plugin->env->stats,
2243 gettext_noop ("# bytes currently in TCP buffers"),
2247 /* append pm to pending_messages list */
2248 GNUNET_CONTAINER_DLL_insert_tail (session->pending_messages_head,
2249 session->pending_messages_tail,
2251 notify_session_monitor (session->plugin,
2253 GNUNET_TRANSPORT_SS_UPDATE);
2254 session->msgs_in_queue++;
2255 session->bytes_in_queue += pm->message_size;
2256 process_pending_messages (session);
2260 GNUNET_CONTAINER_multipeermap_contains_value (plugin->nat_wait_conns,
2264 LOG (GNUNET_ERROR_TYPE_DEBUG,
2265 "This NAT WAIT session for peer `%s' is not yet ready!\n",
2266 GNUNET_i2s (&session->target));
2267 GNUNET_STATISTICS_update (plugin->env->stats,
2268 gettext_noop ("# bytes currently in TCP buffers"), msgbuf_size,
2270 /* append pm to pending_messages list */
2271 GNUNET_CONTAINER_DLL_insert_tail (session->pending_messages_head,
2272 session->pending_messages_tail,
2274 session->msgs_in_queue++;
2275 session->bytes_in_queue += pm->message_size;
2276 notify_session_monitor (session->plugin,
2278 GNUNET_TRANSPORT_SS_HANDSHAKE);
2281 LOG (GNUNET_ERROR_TYPE_ERROR,
2282 "Invalid session %p\n",
2292 return GNUNET_SYSERR; /* session does not exist here */
2297 * Closure for #session_lookup_it().
2299 struct GNUNET_ATS_SessionItCtx
2302 * Address we are looking for.
2304 const struct GNUNET_HELLO_Address *address;
2307 * Where to store the session (if we found it).
2309 struct GNUNET_ATS_Session *result;
2315 * Look for a session by address.
2317 * @param cls the `struct GNUNET_ATS_SessionItCtx`
2319 * @param value a `struct GNUNET_ATS_Session`
2320 * @return #GNUNET_YES to continue looking, #GNUNET_NO if we found the session
2323 session_lookup_it (void *cls,
2324 const struct GNUNET_PeerIdentity *key,
2327 struct GNUNET_ATS_SessionItCtx *si_ctx = cls;
2328 struct GNUNET_ATS_Session *session = value;
2331 GNUNET_HELLO_address_cmp (si_ctx->address,
2334 si_ctx->result = session;
2340 * Task cleaning up a NAT connection attempt after timeout
2342 * @param cls the `struct GNUNET_ATS_Session`
2345 nat_connect_timeout (void *cls)
2347 struct GNUNET_ATS_Session *session = cls;
2349 session->nat_connection_timeout = NULL;
2350 LOG (GNUNET_ERROR_TYPE_DEBUG,
2351 "NAT WAIT connection to `%4s' at `%s' could not be established, removing session\n",
2352 GNUNET_i2s (&session->target),
2353 tcp_plugin_address_to_string (session->plugin,
2354 session->address->address,
2355 session->address->address_length));
2356 tcp_plugin_disconnect_session (session->plugin,
2362 * Function that will be called whenever the transport service wants to
2363 * notify the plugin that a session is still active and in use and
2364 * therefore the session timeout for this session has to be updated
2366 * @param cls closure
2367 * @param peer which peer was the session for
2368 * @param session which session is being updated
2371 tcp_plugin_update_session_timeout (void *cls,
2372 const struct GNUNET_PeerIdentity *peer,
2373 struct GNUNET_ATS_Session *session)
2375 reschedule_session_timeout (session);
2380 * Task to signal the server that we can continue
2381 * receiving from the TCP client now.
2383 * @param cls the `struct GNUNET_ATS_Session *`
2386 delayed_done (void *cls)
2388 struct GNUNET_ATS_Session *session = cls;
2390 session->receive_delay_task = NULL;
2391 reschedule_session_timeout (session);
2392 GNUNET_SERVER_receive_done (session->client,
2398 * Function that will be called whenever the transport service wants to
2399 * notify the plugin that the inbound quota changed and that the plugin
2400 * should update it's delay for the next receive value
2402 * @param cls closure
2403 * @param peer which peer was the session for
2404 * @param session which session is being updated
2405 * @param delay new delay to use for receiving
2408 tcp_plugin_update_inbound_delay (void *cls,
2409 const struct GNUNET_PeerIdentity *peer,
2410 struct GNUNET_ATS_Session *session,
2411 struct GNUNET_TIME_Relative delay)
2413 if (NULL == session->receive_delay_task)
2415 LOG (GNUNET_ERROR_TYPE_DEBUG,
2416 "New inbound delay %s\n",
2417 GNUNET_STRINGS_relative_time_to_string (delay,
2419 session->receive_delay = GNUNET_TIME_relative_to_absolute (delay);
2420 GNUNET_SCHEDULER_cancel (session->receive_delay_task);
2421 session->receive_delay_task = GNUNET_SCHEDULER_add_delayed (delay,
2428 * Create a new session to transmit data to the target
2429 * This session will used to send data to this peer and the plugin will
2430 * notify us by calling the env->session_end function
2432 * @param cls closure
2433 * @param address the address to use
2434 * @return the session if the address is valid, NULL otherwise
2436 static struct GNUNET_ATS_Session *
2437 tcp_plugin_get_session (void *cls,
2438 const struct GNUNET_HELLO_Address *address)
2440 struct Plugin *plugin = cls;
2441 struct GNUNET_ATS_Session *session = NULL;
2445 struct GNUNET_CONNECTION_Handle *sa;
2446 struct sockaddr_in a4;
2447 struct sockaddr_in6 a6;
2448 const struct IPv4TcpAddress *t4;
2449 const struct IPv6TcpAddress *t6;
2450 unsigned int options;
2451 enum GNUNET_NetworkType net_type;
2452 unsigned int is_natd = GNUNET_NO;
2455 struct GNUNET_NETWORK_Handle *s;
2458 addrlen = address->address_length;
2459 LOG (GNUNET_ERROR_TYPE_DEBUG,
2460 "Trying to get session for `%s' address of peer `%s'\n",
2461 tcp_plugin_address_to_string (plugin,
2463 address->address_length),
2464 GNUNET_i2s (&address->peer));
2466 if (GNUNET_HELLO_address_check_option (address,
2467 GNUNET_HELLO_ADDRESS_INFO_INBOUND))
2473 /* look for existing session */
2475 GNUNET_CONTAINER_multipeermap_contains (plugin->sessionmap,
2478 struct GNUNET_ATS_SessionItCtx si_ctx;
2480 si_ctx.address = address;
2481 si_ctx.result = NULL;
2482 GNUNET_CONTAINER_multipeermap_get_multiple (plugin->sessionmap,
2486 if (NULL != si_ctx.result)
2488 session = si_ctx.result;
2489 LOG (GNUNET_ERROR_TYPE_DEBUG,
2490 "Found existing session for `%s' address `%s'\n",
2491 GNUNET_i2s (&address->peer),
2492 tcp_plugin_address_to_string (plugin,
2494 address->address_length));
2497 /* This is a bit of a hack, limiting TCP to never allow more than
2498 one TCP connection to any given peer at the same time.
2499 Without this, peers sometimes disagree about which of the TCP
2500 connections they should use, causing one side to believe that
2501 they transmit successfully, while the other receives nothing. */
2502 return NULL; /* Refuse to have more than one TCP connection per
2503 peer pair at the same time. */
2506 if (addrlen == sizeof(struct IPv6TcpAddress))
2508 GNUNET_assert (NULL != address->address); /* make static analysis happy */
2509 t6 = address->address;
2510 options = t6->options;
2512 memset (&a6, 0, sizeof(a6));
2513 #if HAVE_SOCKADDR_IN_SIN_LEN
2514 a6.sin6_len = sizeof (a6);
2516 a6.sin6_family = AF_INET6;
2517 a6.sin6_port = t6->t6_port;
2518 if (t6->t6_port == 0)
2519 is_natd = GNUNET_YES;
2520 GNUNET_memcpy (&a6.sin6_addr, &t6->ipv6_addr, sizeof(struct in6_addr));
2524 else if (addrlen == sizeof(struct IPv4TcpAddress))
2526 GNUNET_assert(NULL != address->address); /* make static analysis happy */
2527 t4 = address->address;
2528 options = t4->options;
2530 memset (&a4, 0, sizeof(a4));
2531 #if HAVE_SOCKADDR_IN_SIN_LEN
2532 a4.sin_len = sizeof (a4);
2534 a4.sin_family = AF_INET;
2535 a4.sin_port = t4->t4_port;
2536 if (t4->t4_port == 0)
2537 is_natd = GNUNET_YES;
2538 a4.sin_addr.s_addr = t4->ipv4_addr;
2544 GNUNET_STATISTICS_update (plugin->env->stats,
2545 gettext_noop ("# requests to create session with invalid address"),
2551 net_type = plugin->env->get_address_type (plugin->env->cls,
2554 GNUNET_break (net_type != GNUNET_NT_UNSPECIFIED);
2556 if ( (is_natd == GNUNET_YES) &&
2557 (addrlen == sizeof(struct IPv6TcpAddress)) )
2559 /* NAT client only works with IPv4 addresses */
2563 if (plugin->cur_connections >= plugin->max_connections)
2569 if ( (is_natd == GNUNET_YES) &&
2571 GNUNET_CONTAINER_multipeermap_contains (plugin->nat_wait_conns,
2574 /* Only do one NAT punch attempt per peer identity */
2578 if ( (is_natd == GNUNET_YES) &&
2579 (NULL != plugin->nat) &&
2581 GNUNET_CONTAINER_multipeermap_contains (plugin->nat_wait_conns,
2584 struct sockaddr_in local_sa;
2586 LOG (GNUNET_ERROR_TYPE_DEBUG,
2587 "Found valid IPv4 NAT address (creating session)!\n");
2588 session = create_session (plugin,
2593 session->nat_connection_timeout = GNUNET_SCHEDULER_add_delayed (NAT_TIMEOUT,
2594 &nat_connect_timeout,
2596 GNUNET_assert (GNUNET_OK ==
2597 GNUNET_CONTAINER_multipeermap_put (plugin->nat_wait_conns,
2600 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
2602 LOG (GNUNET_ERROR_TYPE_DEBUG,
2603 "Created NAT WAIT connection to `%s' at `%s'\n",
2604 GNUNET_i2s (&session->target),
2605 GNUNET_a2s (sb, sbs));
2609 local_sa.sin_family = AF_INET;
2610 local_sa.sin_port = htons (plugin->open_port);
2611 /* We leave sin_address at 0, let the kernel figure it out,
2612 even if our bind() is more specific. (May want to reconsider
2615 GNUNET_NAT_request_reversal (plugin->nat,
2619 LOG (GNUNET_ERROR_TYPE_DEBUG,
2620 "Running NAT client for `%s' at `%s' failed\n",
2621 GNUNET_i2s (&session->target),
2622 GNUNET_a2s (sb, sbs));
2623 tcp_plugin_disconnect_session (plugin,
2628 /* create new outbound session */
2629 if (0 != (options & TCP_OPTIONS_TCP_STEALTH))
2632 s = GNUNET_NETWORK_socket_create (af, SOCK_STREAM, 0);
2635 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK,
2642 GNUNET_NETWORK_socket_setsockopt (s,
2646 sizeof (struct GNUNET_PeerIdentity))) ||
2648 GNUNET_NETWORK_socket_setsockopt (s,
2650 TCP_STEALTH_INTEGRITY,
2651 &plugin->my_welcome,
2652 sizeof (struct WelcomeMessage))) )
2654 /* TCP STEALTH not supported by kernel */
2655 GNUNET_break (GNUNET_OK ==
2656 GNUNET_NETWORK_socket_close (s));
2661 sa = GNUNET_CONNECTION_connect_socket (s, sb, sbs);
2670 sa = GNUNET_CONNECTION_create_from_sockaddr (af, sb, sbs);
2674 LOG (GNUNET_ERROR_TYPE_DEBUG,
2675 "Failed to create connection to `%s' at `%s'\n",
2676 GNUNET_i2s (&address->peer),
2677 GNUNET_a2s (sb, sbs));
2680 LOG (GNUNET_ERROR_TYPE_DEBUG,
2681 "Asked to transmit to `%s', creating fresh session using address `%s'.\n",
2682 GNUNET_i2s (&address->peer),
2683 GNUNET_a2s (sb, sbs));
2685 session = create_session (plugin,
2688 GNUNET_SERVER_connect_socket (plugin->server,
2691 (void) GNUNET_CONTAINER_multipeermap_put (plugin->sessionmap,
2694 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
2695 /* Send TCP Welcome */
2696 process_pending_messages (session);
2703 * We have been asked to destroy all connections to a particular peer.
2704 * This function is called on each applicable session and must tear it
2707 * @param cls the `struct Plugin *`
2708 * @param key the peer which the session belongs to (unused)
2709 * @param value the `struct GNUNET_ATS_Session`
2710 * @return #GNUNET_YES (continue to iterate)
2713 session_disconnect_it (void *cls,
2714 const struct GNUNET_PeerIdentity *key,
2717 struct Plugin *plugin = cls;
2718 struct GNUNET_ATS_Session *session = value;
2720 GNUNET_STATISTICS_update (session->plugin->env->stats,
2721 gettext_noop ("# transport-service disconnect requests for TCP"),
2724 tcp_plugin_disconnect_session (plugin,
2731 * Function that can be called to force a disconnect from the
2732 * specified neighbour. This should also cancel all previously
2733 * scheduled transmissions. Obviously the transmission may have been
2734 * partially completed already, which is OK. The plugin is supposed
2735 * to close the connection (if applicable) and no longer call the
2736 * transmit continuation(s).
2738 * Finally, plugin MUST NOT call the services's receive function to
2739 * notify the service that the connection to the specified target was
2740 * closed after a getting this call.
2742 * @param cls closure
2743 * @param target peer for which the last transmission is
2747 tcp_plugin_disconnect (void *cls,
2748 const struct GNUNET_PeerIdentity *target)
2750 struct Plugin *plugin = cls;
2752 LOG (GNUNET_ERROR_TYPE_DEBUG,
2753 "Disconnecting peer `%s'\n",
2754 GNUNET_i2s (target));
2755 GNUNET_CONTAINER_multipeermap_get_multiple (plugin->sessionmap,
2757 &session_disconnect_it,
2759 GNUNET_CONTAINER_multipeermap_get_multiple (plugin->nat_wait_conns,
2761 &session_disconnect_it,
2767 * We are processing an address pretty printing request and finished
2768 * the IP resolution (if applicable). Append our port and forward the
2769 * result. If called with @a hostname NULL, we are done and should
2770 * clean up the pretty printer (otherwise, there might be multiple
2771 * hostnames for the IP address and we might receive more).
2773 * @param cls the `struct PrettyPrinterContext *`
2774 * @param hostname hostname part of the address
2777 append_port (void *cls,
2778 const char *hostname)
2780 struct PrettyPrinterContext *ppc = cls;
2781 struct Plugin *plugin = ppc->plugin;
2784 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2785 "append_port called with hostname `%s'\n",
2787 if (NULL == hostname)
2789 /* Final call, done */
2790 ppc->resolver_handle = NULL;
2791 GNUNET_CONTAINER_DLL_remove (plugin->ppc_dll_head,
2792 plugin->ppc_dll_tail,
2794 ppc->asc (ppc->asc_cls,
2800 if (GNUNET_YES == ppc->ipv6)
2801 GNUNET_asprintf (&ret,
2808 GNUNET_asprintf (&ret,
2814 ppc->asc (ppc->asc_cls,
2822 * Convert the transports address to a nice, human-readable format.
2824 * @param cls closure with the `struct Plugin`
2825 * @param type name of the transport that generated the address
2826 * @param addr one of the addresses of the host, NULL for the last address
2827 * the specific address format depends on the transport
2828 * @param addrlen length of the @a addr
2829 * @param numeric should (IP) addresses be displayed in numeric form?
2830 * @param timeout after how long should we give up?
2831 * @param asc function to call on each string
2832 * @param asc_cls closure for @a asc
2835 tcp_plugin_address_pretty_printer (void *cls,
2840 struct GNUNET_TIME_Relative timeout,
2841 GNUNET_TRANSPORT_AddressStringCallback asc,
2844 struct Plugin *plugin = cls;
2845 struct PrettyPrinterContext *ppc;
2848 struct sockaddr_in a4;
2849 struct sockaddr_in6 a6;
2850 const struct IPv4TcpAddress *t4;
2851 const struct IPv6TcpAddress *t6;
2855 if (sizeof(struct IPv6TcpAddress) == addrlen)
2858 memset (&a6, 0, sizeof(a6));
2859 a6.sin6_family = AF_INET6;
2860 a6.sin6_port = t6->t6_port;
2861 GNUNET_memcpy (&a6.sin6_addr, &t6->ipv6_addr, sizeof(struct in6_addr));
2862 port = ntohs (t6->t6_port);
2863 options = ntohl (t6->options);
2867 else if (sizeof(struct IPv4TcpAddress) == addrlen)
2870 memset (&a4, 0, sizeof(a4));
2871 a4.sin_family = AF_INET;
2872 a4.sin_port = t4->t4_port;
2873 a4.sin_addr.s_addr = t4->ipv4_addr;
2874 port = ntohs (t4->t4_port);
2875 options = ntohl (t4->options);
2881 /* invalid address */
2882 LOG (GNUNET_ERROR_TYPE_WARNING,
2883 _("Unexpected address length: %u bytes\n"),
2884 (unsigned int) addrlen);
2885 asc (asc_cls, NULL, GNUNET_SYSERR);
2886 asc (asc_cls, NULL, GNUNET_OK);
2889 ppc = GNUNET_new (struct PrettyPrinterContext);
2890 ppc->plugin = plugin;
2891 if (addrlen == sizeof(struct IPv6TcpAddress))
2892 ppc->ipv6 = GNUNET_YES;
2894 ppc->ipv6 = GNUNET_NO;
2896 ppc->asc_cls = asc_cls;
2898 ppc->options = options;
2899 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2900 "Starting DNS reverse lookup\n");
2901 ppc->resolver_handle = GNUNET_RESOLVER_hostname_get (sb,
2907 if (NULL == ppc->resolver_handle)
2913 GNUNET_CONTAINER_DLL_insert (plugin->ppc_dll_head,
2914 plugin->ppc_dll_tail,
2920 * Function that will be called to check if a binary address for this
2921 * plugin is well-formed and corresponds to an address for THIS peer
2922 * (as per our configuration). Naturally, if absolutely necessary,
2923 * plugins can be a bit conservative in their answer, but in general
2924 * plugins should make sure that the address does not redirect
2925 * traffic to a 3rd party that might try to man-in-the-middle our
2928 * @param cls closure, our `struct Plugin *`
2929 * @param addr pointer to the address
2930 * @param addrlen length of @a addr
2931 * @return #GNUNET_OK if this is a plausible address for this peer
2932 * and transport, #GNUNET_SYSERR if not
2935 tcp_plugin_check_address (void *cls,
2939 struct Plugin *plugin = cls;
2940 const struct IPv4TcpAddress *v4;
2941 const struct IPv6TcpAddress *v6;
2943 if ( (addrlen != sizeof(struct IPv4TcpAddress)) &&
2944 (addrlen != sizeof(struct IPv6TcpAddress)) )
2946 GNUNET_break_op (0);
2947 return GNUNET_SYSERR;
2950 if (addrlen == sizeof(struct IPv4TcpAddress))
2952 struct sockaddr_in s4;
2954 v4 = (const struct IPv4TcpAddress *) addr;
2955 if (0 != memcmp (&v4->options,
2960 return GNUNET_SYSERR;
2962 memset (&s4, 0, sizeof (s4));
2963 s4.sin_family = AF_INET;
2964 #if HAVE_SOCKADDR_IN_SIN_LEN
2965 s4.sin_len = sizeof (s4);
2967 s4.sin_port = v4->t4_port;
2968 s4.sin_addr.s_addr = v4->ipv4_addr;
2971 GNUNET_NAT_test_address (plugin->nat,
2973 sizeof (struct sockaddr_in)))
2974 return GNUNET_SYSERR;
2978 struct sockaddr_in6 s6;
2980 v6 = (const struct IPv6TcpAddress *) addr;
2981 if (IN6_IS_ADDR_LINKLOCAL (&v6->ipv6_addr))
2983 GNUNET_break_op (0);
2984 return GNUNET_SYSERR;
2986 if (0 != memcmp (&v6->options,
2991 return GNUNET_SYSERR;
2993 memset (&s6, 0, sizeof (s6));
2994 s6.sin6_family = AF_INET6;
2995 #if HAVE_SOCKADDR_IN_SIN_LEN
2996 s6.sin6_len = sizeof (s6);
2998 s6.sin6_port = v6->t6_port;
2999 s6.sin6_addr = v6->ipv6_addr;
3002 GNUNET_NAT_test_address (plugin->nat,
3004 sizeof(struct sockaddr_in6)))
3005 return GNUNET_SYSERR;
3012 * We've received a nat probe from this peer via TCP. Finish
3013 * creating the client session and resume sending of queued
3016 * @param cls closure
3017 * @param client identification of the client
3018 * @param message the actual message
3021 handle_tcp_nat_probe (void *cls,
3022 struct GNUNET_SERVER_Client *client,
3023 const struct GNUNET_MessageHeader *message)
3025 struct Plugin *plugin = cls;
3026 struct GNUNET_ATS_Session *session;
3027 const struct TCP_NAT_ProbeMessage *tcp_nat_probe;
3030 struct IPv4TcpAddress *t4;
3031 struct IPv6TcpAddress *t6;
3032 const struct sockaddr_in *s4;
3033 const struct sockaddr_in6 *s6;
3035 LOG (GNUNET_ERROR_TYPE_DEBUG,
3036 "Received NAT probe\n");
3037 /* We have received a TCP NAT probe, meaning we (hopefully) initiated
3038 * a connection to this peer by running gnunet-nat-client. This peer
3039 * received the punch message and now wants us to use the new connection
3040 * as the default for that peer. Do so and then send a WELCOME message
3041 * so we can really be connected!
3043 if (ntohs (message->size) != sizeof(struct TCP_NAT_ProbeMessage))
3046 GNUNET_SERVER_receive_done (client,
3051 tcp_nat_probe = (const struct TCP_NAT_ProbeMessage *) message;
3052 if (0 == memcmp (&tcp_nat_probe->clientIdentity, plugin->env->my_identity,
3053 sizeof(struct GNUNET_PeerIdentity)))
3055 /* refuse connections from ourselves */
3056 GNUNET_SERVER_receive_done (client,
3061 session = GNUNET_CONTAINER_multipeermap_get (plugin->nat_wait_conns,
3062 &tcp_nat_probe->clientIdentity);
3063 if (NULL == session)
3065 LOG (GNUNET_ERROR_TYPE_DEBUG,
3066 "Did NOT find session for NAT probe!\n");
3067 GNUNET_SERVER_receive_done (client,
3071 LOG (GNUNET_ERROR_TYPE_DEBUG,
3072 "Found session for NAT probe!\n");
3074 if (NULL != session->nat_connection_timeout)
3076 GNUNET_SCHEDULER_cancel (session->nat_connection_timeout);
3077 session->nat_connection_timeout = NULL;
3081 GNUNET_SERVER_client_get_address (client,
3086 GNUNET_SERVER_receive_done (client,
3088 tcp_plugin_disconnect_session (plugin,
3092 GNUNET_assert (GNUNET_YES ==
3093 GNUNET_CONTAINER_multipeermap_remove (plugin->nat_wait_conns,
3094 &tcp_nat_probe->clientIdentity,
3096 GNUNET_SERVER_client_set_user_context (client,
3098 (void) GNUNET_CONTAINER_multipeermap_put (plugin->sessionmap,
3101 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
3102 session->last_activity = GNUNET_TIME_absolute_get ();
3103 LOG (GNUNET_ERROR_TYPE_DEBUG,
3104 "Found address `%s' for incoming connection\n",
3105 GNUNET_a2s (vaddr, alen));
3106 switch (((const struct sockaddr *) vaddr)->sa_family)
3110 t4 = GNUNET_new (struct IPv4TcpAddress);
3111 t4->options = htonl (TCP_OPTIONS_NONE);
3112 t4->t4_port = s4->sin_port;
3113 t4->ipv4_addr = s4->sin_addr.s_addr;
3114 session->address = GNUNET_HELLO_address_allocate (&tcp_nat_probe->clientIdentity,
3117 sizeof(struct IPv4TcpAddress),
3118 GNUNET_HELLO_ADDRESS_INFO_NONE);
3122 t6 = GNUNET_new (struct IPv6TcpAddress);
3123 t6->options = htonl (TCP_OPTIONS_NONE);
3124 t6->t6_port = s6->sin6_port;
3125 GNUNET_memcpy (&t6->ipv6_addr, &s6->sin6_addr, sizeof(struct in6_addr));
3126 session->address = GNUNET_HELLO_address_allocate (&tcp_nat_probe->clientIdentity,
3129 sizeof(struct IPv6TcpAddress),
3130 GNUNET_HELLO_ADDRESS_INFO_NONE);
3134 LOG(GNUNET_ERROR_TYPE_DEBUG,
3135 "Bad address for incoming connection!\n");
3137 GNUNET_SERVER_receive_done (client,
3139 tcp_plugin_disconnect_session (plugin,
3143 GNUNET_free (vaddr);
3144 GNUNET_break (NULL == session->client);
3145 session->client = client;
3146 GNUNET_STATISTICS_update (plugin->env->stats,
3147 gettext_noop ("# TCP sessions active"),
3150 process_pending_messages (session);
3151 GNUNET_SERVER_receive_done (client,
3157 * We've received a welcome from this peer via TCP. Possibly create a
3158 * fresh client record and send back our welcome.
3160 * @param cls closure
3161 * @param client identification of the client
3162 * @param message the actual message
3165 handle_tcp_welcome (void *cls,
3166 struct GNUNET_SERVER_Client *client,
3167 const struct GNUNET_MessageHeader *message)
3169 struct Plugin *plugin = cls;
3170 const struct WelcomeMessage *wm = (const struct WelcomeMessage *) message;
3171 struct GNUNET_HELLO_Address *address;
3172 struct GNUNET_ATS_Session *session;
3175 struct IPv4TcpAddress t4;
3176 struct IPv6TcpAddress t6;
3177 const struct sockaddr_in *s4;
3178 const struct sockaddr_in6 *s6;
3180 if (0 == memcmp (&wm->clientIdentity,
3181 plugin->env->my_identity,
3182 sizeof(struct GNUNET_PeerIdentity)))
3184 /* refuse connections from ourselves */
3186 GNUNET_SERVER_client_get_address (client,
3190 LOG (GNUNET_ERROR_TYPE_INFO,
3191 "Received WELCOME message from my own identity `%s' on address `%s'\n",
3192 GNUNET_i2s (&wm->clientIdentity),
3193 GNUNET_a2s (vaddr, alen));
3194 GNUNET_free (vaddr);
3196 GNUNET_SERVER_receive_done (client,
3202 GNUNET_SERVER_client_get_address (client,
3206 LOG(GNUNET_ERROR_TYPE_DEBUG,
3207 "Received WELCOME message from `%s' on address `%s'\n",
3208 GNUNET_i2s (&wm->clientIdentity),
3209 GNUNET_a2s (vaddr, alen));
3210 GNUNET_free (vaddr);
3212 GNUNET_STATISTICS_update (plugin->env->stats,
3213 gettext_noop ("# TCP WELCOME messages received"),
3216 session = lookup_session_by_client (plugin,
3218 if (NULL != session)
3221 GNUNET_SERVER_client_get_address (client,
3225 LOG (GNUNET_ERROR_TYPE_DEBUG,
3226 "Found existing session %p for peer `%s'\n",
3228 GNUNET_a2s (vaddr, alen));
3229 GNUNET_free (vaddr);
3235 GNUNET_SERVER_client_get_address (client, &vaddr, &alen))
3237 if (alen == sizeof(struct sockaddr_in))
3240 memset (&t4, '\0', sizeof (t4));
3241 t4.options = htonl (TCP_OPTIONS_NONE);
3242 t4.t4_port = s4->sin_port;
3243 t4.ipv4_addr = s4->sin_addr.s_addr;
3244 address = GNUNET_HELLO_address_allocate (&wm->clientIdentity,
3248 GNUNET_HELLO_ADDRESS_INFO_INBOUND);
3250 else if (alen == sizeof(struct sockaddr_in6))
3253 memset (&t6, '\0', sizeof (t6));
3254 t6.options = htonl (TCP_OPTIONS_NONE);
3255 t6.t6_port = s6->sin6_port;
3256 GNUNET_memcpy (&t6.ipv6_addr, &s6->sin6_addr, sizeof(struct in6_addr));
3257 address = GNUNET_HELLO_address_allocate (&wm->clientIdentity,
3261 GNUNET_HELLO_ADDRESS_INFO_INBOUND);
3266 GNUNET_free_non_null (vaddr);
3267 GNUNET_SERVER_receive_done (client,
3271 session = create_session (plugin,
3273 plugin->env->get_address_type (plugin->env->cls,
3278 GNUNET_break (GNUNET_NT_UNSPECIFIED != session->scope);
3279 GNUNET_HELLO_address_free (address);
3280 LOG (GNUNET_ERROR_TYPE_DEBUG,
3281 "Creating new%s session %p for peer `%s' client %p\n",
3282 GNUNET_HELLO_address_check_option (session->address,
3283 GNUNET_HELLO_ADDRESS_INFO_INBOUND)
3286 tcp_plugin_address_to_string (plugin,
3287 session->address->address,
3288 session->address->address_length),
3290 GNUNET_free (vaddr);
3291 (void) GNUNET_CONTAINER_multipeermap_put (plugin->sessionmap,
3294 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
3295 /* Notify transport and ATS about new session */
3296 plugin->env->session_start (plugin->env->cls,
3303 LOG(GNUNET_ERROR_TYPE_DEBUG,
3304 "Did not obtain TCP socket address for incoming connection\n");
3306 GNUNET_SERVER_receive_done (client,
3312 if (GNUNET_YES != session->expecting_welcome)
3314 GNUNET_break_op (0);
3315 GNUNET_SERVER_receive_done (client,
3319 session->last_activity = GNUNET_TIME_absolute_get ();
3320 session->expecting_welcome = GNUNET_NO;
3322 process_pending_messages (session);
3323 GNUNET_SERVER_client_set_timeout (client,
3324 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
3325 GNUNET_SERVER_receive_done (client,
3331 * We've received data for this peer via TCP. Unbox,
3332 * compute latency and forward.
3334 * @param cls closure
3335 * @param client identification of the client
3336 * @param message the actual message
3339 handle_tcp_data (void *cls,
3340 struct GNUNET_SERVER_Client *client,
3341 const struct GNUNET_MessageHeader *message)
3343 struct Plugin *plugin = cls;
3344 struct GNUNET_ATS_Session *session;
3345 struct GNUNET_TIME_Relative delay;
3348 type = ntohs (message->type);
3349 if ( (GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_WELCOME == type) ||
3350 (GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_NAT_PROBE == type) )
3352 /* We don't want to propagate WELCOME and NAT Probe messages up! */
3353 GNUNET_SERVER_receive_done (client,
3357 session = lookup_session_by_client (plugin, client);
3358 if (NULL == session)
3360 /* No inbound session found */
3364 GNUNET_assert (GNUNET_OK ==
3365 GNUNET_SERVER_client_get_address (client,
3368 LOG (GNUNET_ERROR_TYPE_ERROR,
3369 "Received unexpected %u bytes of type %u from `%s'\n",
3370 (unsigned int) ntohs (message->size),
3371 (unsigned int) ntohs (message->type),
3375 GNUNET_SERVER_receive_done (client,
3377 GNUNET_free_non_null (vaddr);
3380 if (GNUNET_YES == session->expecting_welcome)
3382 /* Session is expecting WELCOME message */
3386 GNUNET_SERVER_client_get_address (client,
3389 LOG (GNUNET_ERROR_TYPE_ERROR,
3390 "Received unexpected %u bytes of type %u from `%s'\n",
3391 (unsigned int) ntohs (message->size),
3392 (unsigned int) ntohs (message->type),
3393 GNUNET_a2s (vaddr, alen));
3395 GNUNET_SERVER_receive_done (client,
3397 GNUNET_free_non_null (vaddr);
3401 session->last_activity = GNUNET_TIME_absolute_get ();
3406 GNUNET_SERVER_client_get_address (client,
3409 LOG (GNUNET_ERROR_TYPE_DEBUG,
3410 "Passing %u bytes of type %u from `%s' at %s to transport service.\n",
3411 (unsigned int) ntohs (message->size),
3412 (unsigned int) ntohs (message->type),
3413 GNUNET_i2s (&session->target),
3414 GNUNET_a2s (vaddr, alen));
3415 GNUNET_free_non_null (vaddr);
3418 GNUNET_STATISTICS_update (plugin->env->stats,
3419 gettext_noop ("# bytes received via TCP"),
3420 ntohs (message->size),
3423 GNUNET_assert (GNUNET_CONTAINER_multipeermap_contains_value (plugin->sessionmap,
3426 delay = plugin->env->receive (plugin->env->cls,
3430 reschedule_session_timeout (session);
3431 if (0 == delay.rel_value_us)
3433 GNUNET_SERVER_receive_done (client,
3438 LOG (GNUNET_ERROR_TYPE_DEBUG,
3439 "Throttling receiving from `%s' for %s\n",
3440 GNUNET_i2s (&session->target),
3441 GNUNET_STRINGS_relative_time_to_string (delay,
3443 GNUNET_SERVER_disable_receive_done_warning (client);
3444 GNUNET_assert (NULL == session->receive_delay_task);
3445 session->receive_delay_task = GNUNET_SCHEDULER_add_delayed (delay,
3453 * Function called whenever a peer is connected on the "SERVER" level.
3454 * Increments number of active connections and suspends server if we
3455 * have reached the limit.
3457 * @param cls closure
3458 * @param client identification of the client
3461 connect_notify (void *cls,
3462 struct GNUNET_SERVER_Client *client)
3464 struct Plugin *plugin = cls;
3468 plugin->cur_connections++;
3469 GNUNET_STATISTICS_set (plugin->env->stats,
3470 gettext_noop ("# TCP server connections active"),
3471 plugin->cur_connections,
3473 GNUNET_STATISTICS_update (plugin->env->stats,
3474 gettext_noop ("# TCP server connect events"),
3477 if (plugin->cur_connections != plugin->max_connections)
3479 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3480 _("TCP connection limit reached, suspending server\n"));
3481 GNUNET_STATISTICS_update (plugin->env->stats,
3482 gettext_noop ("# TCP service suspended"),
3485 GNUNET_SERVER_suspend (plugin->server); /* Maximum number of connections rechead */
3490 * Function called whenever a peer is disconnected on the "SERVER"
3491 * level. Cleans up the connection, decrements number of active
3492 * connections and if applicable resumes listening.
3494 * @param cls closure
3495 * @param client identification of the client
3498 disconnect_notify (void *cls,
3499 struct GNUNET_SERVER_Client *client)
3501 struct Plugin *plugin = cls;
3502 struct GNUNET_ATS_Session *session;
3506 GNUNET_assert (plugin->cur_connections >= 1);
3507 plugin->cur_connections--;
3508 session = lookup_session_by_client (plugin,
3510 if (NULL == session)
3511 return; /* unknown, nothing to do */
3512 LOG (GNUNET_ERROR_TYPE_DEBUG,
3513 "Destroying session of `%s' with %s due to network-level disconnect.\n",
3514 GNUNET_i2s (&session->target),
3515 tcp_plugin_address_to_string (session->plugin,
3516 session->address->address,
3517 session->address->address_length));
3519 if (plugin->cur_connections == plugin->max_connections)
3521 GNUNET_STATISTICS_update (session->plugin->env->stats,
3522 gettext_noop ("# TCP service resumed"),
3525 GNUNET_SERVER_resume (plugin->server); /* Resume server */
3527 GNUNET_STATISTICS_set (plugin->env->stats,
3528 gettext_noop ("# TCP server connections active"),
3529 plugin->cur_connections,
3531 GNUNET_STATISTICS_update (session->plugin->env->stats,
3532 gettext_noop ("# network-level TCP disconnect events"),
3535 tcp_plugin_disconnect_session (plugin,
3541 * We can now send a probe message, copy into buffer to really send.
3543 * @param cls closure, a `struct TCPProbeContext`
3544 * @param size max size to copy
3545 * @param buf buffer to copy message to
3546 * @return number of bytes copied into @a buf
3549 notify_send_probe (void *cls,
3553 struct TCPProbeContext *tcp_probe_ctx = cls;
3554 struct Plugin *plugin = tcp_probe_ctx->plugin;
3557 tcp_probe_ctx->transmit_handle = NULL;
3558 GNUNET_CONTAINER_DLL_remove (plugin->probe_head,
3563 GNUNET_CONNECTION_destroy (tcp_probe_ctx->sock);
3564 GNUNET_free(tcp_probe_ctx);
3567 GNUNET_assert(size >= sizeof(tcp_probe_ctx->message));
3569 &tcp_probe_ctx->message,
3570 sizeof(tcp_probe_ctx->message));
3571 GNUNET_SERVER_connect_socket (tcp_probe_ctx->plugin->server,
3572 tcp_probe_ctx->sock);
3573 ret = sizeof(tcp_probe_ctx->message);
3574 GNUNET_free (tcp_probe_ctx);
3580 * Function called by the NAT subsystem suggesting another peer wants
3581 * to connect to us via connection reversal. Try to connect back to the
3584 * @param cls closure
3585 * @param addr address to try
3586 * @param addrlen number of bytes in @a addr
3589 try_connection_reversal (void *cls,
3590 const struct sockaddr *addr,
3593 struct Plugin *plugin = cls;
3594 struct GNUNET_CONNECTION_Handle *sock;
3595 struct TCPProbeContext *tcp_probe_ctx;
3598 * We have received an ICMP response, ostensibly from a peer
3599 * that wants to connect to us! Send a message to establish a connection.
3601 sock = GNUNET_CONNECTION_create_from_sockaddr (AF_INET,
3606 /* failed for some odd reason (out of sockets?); ignore attempt */
3610 tcp_probe_ctx = GNUNET_new (struct TCPProbeContext);
3611 tcp_probe_ctx->message.header.size
3612 = htons (sizeof (struct TCP_NAT_ProbeMessage));
3613 tcp_probe_ctx->message.header.type
3614 = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_NAT_PROBE);
3615 tcp_probe_ctx->message.clientIdentity
3616 = *plugin->env->my_identity;
3617 tcp_probe_ctx->plugin = plugin;
3618 tcp_probe_ctx->sock = sock;
3619 GNUNET_CONTAINER_DLL_insert (plugin->probe_head,
3622 tcp_probe_ctx->transmit_handle
3623 = GNUNET_CONNECTION_notify_transmit_ready (sock,
3624 ntohs (tcp_probe_ctx->message.header.size),
3625 GNUNET_TIME_UNIT_FOREVER_REL,
3632 * Function obtain the network type for a session
3634 * @param cls closure (`struct Plugin *`)
3635 * @param session the session
3636 * @return the network type in HBO or #GNUNET_SYSERR
3638 static enum GNUNET_NetworkType
3639 tcp_plugin_get_network (void *cls,
3640 struct GNUNET_ATS_Session *session)
3642 return session->scope;
3647 * Function obtain the network type for an address.
3649 * @param cls closure (`struct Plugin *`)
3650 * @param address the address
3651 * @return the network type
3653 static enum GNUNET_NetworkType
3654 tcp_plugin_get_network_for_address (void *cls,
3655 const struct GNUNET_HELLO_Address *address)
3657 struct Plugin *plugin = cls;
3659 struct sockaddr_in a4;
3660 struct sockaddr_in6 a6;
3661 const struct IPv4TcpAddress *t4;
3662 const struct IPv6TcpAddress *t6;
3666 addrlen = address->address_length;
3667 if (addrlen == sizeof(struct IPv6TcpAddress))
3669 GNUNET_assert (NULL != address->address); /* make static analysis happy */
3670 t6 = address->address;
3671 memset (&a6, 0, sizeof(a6));
3672 #if HAVE_SOCKADDR_IN_SIN_LEN
3673 a6.sin6_len = sizeof (a6);
3675 a6.sin6_family = AF_INET6;
3676 a6.sin6_port = t6->t6_port;
3677 GNUNET_memcpy (&a6.sin6_addr, &t6->ipv6_addr, sizeof(struct in6_addr));
3681 else if (addrlen == sizeof(struct IPv4TcpAddress))
3683 GNUNET_assert (NULL != address->address); /* make static analysis happy */
3684 t4 = address->address;
3685 memset (&a4, 0, sizeof(a4));
3686 #if HAVE_SOCKADDR_IN_SIN_LEN
3687 a4.sin_len = sizeof (a4);
3689 a4.sin_family = AF_INET;
3690 a4.sin_port = t4->t4_port;
3691 a4.sin_addr.s_addr = t4->ipv4_addr;
3698 return GNUNET_NT_UNSPECIFIED;
3700 return plugin->env->get_address_type (plugin->env->cls,
3707 * Return information about the given session to the
3710 * @param cls the `struct Plugin` with the monitor callback (`sic`)
3711 * @param peer peer we send information about
3712 * @param value our `struct GNUNET_ATS_Session` to send information about
3713 * @return #GNUNET_OK (continue to iterate)
3716 send_session_info_iter (void *cls,
3717 const struct GNUNET_PeerIdentity *peer,
3720 struct Plugin *plugin = cls;
3721 struct GNUNET_ATS_Session *session = value;
3723 notify_session_monitor (plugin,
3725 GNUNET_TRANSPORT_SS_INIT);
3726 /* FIXME: cannot tell if this is up or not from current
3728 notify_session_monitor (plugin,
3730 GNUNET_TRANSPORT_SS_UP);
3736 * Begin monitoring sessions of a plugin. There can only
3737 * be one active monitor per plugin (i.e. if there are
3738 * multiple monitors, the transport service needs to
3739 * multiplex the generated events over all of them).
3741 * @param cls closure of the plugin
3742 * @param sic callback to invoke, NULL to disable monitor;
3743 * plugin will being by iterating over all active
3744 * sessions immediately and then enter monitor mode
3745 * @param sic_cls closure for @a sic
3748 tcp_plugin_setup_monitor (void *cls,
3749 GNUNET_TRANSPORT_SessionInfoCallback sic,
3752 struct Plugin *plugin = cls;
3755 plugin->sic_cls = sic_cls;
3758 GNUNET_CONTAINER_multipeermap_iterate (plugin->sessionmap,
3759 &send_session_info_iter,
3761 /* signal end of first iteration */
3762 sic (sic_cls, NULL, NULL);
3768 * Entry point for the plugin.
3770 * @param cls closure, the `struct GNUNET_TRANSPORT_PluginEnvironment *`
3771 * @return the `struct GNUNET_TRANSPORT_PluginFunctions *` or NULL on error
3774 libgnunet_plugin_transport_tcp_init (void *cls)
3776 static const struct GNUNET_SERVER_MessageHandler my_handlers[] = {
3777 { &handle_tcp_welcome, NULL,
3778 GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_WELCOME,
3779 sizeof(struct WelcomeMessage) },
3780 { &handle_tcp_nat_probe, NULL,
3781 GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_NAT_PROBE,
3782 sizeof(struct TCP_NAT_ProbeMessage) },
3783 { &handle_tcp_data, NULL,
3784 GNUNET_MESSAGE_TYPE_ALL, 0 },
3785 { NULL, NULL, 0, 0 }
3787 struct GNUNET_TRANSPORT_PluginEnvironment *env = cls;
3788 struct GNUNET_TRANSPORT_PluginFunctions *api;
3789 struct Plugin *plugin;
3790 struct LEGACY_SERVICE_Context *service;
3791 unsigned long long aport;
3792 unsigned long long bport;
3793 unsigned long long max_connections;
3795 struct GNUNET_TIME_Relative idle_timeout;
3797 struct GNUNET_NETWORK_Handle *const*lsocks;
3801 struct sockaddr **addrs;
3802 socklen_t *addrlens;
3804 if (NULL == env->receive)
3806 /* run in 'stub' mode (i.e. as part of gnunet-peerinfo), don't fully
3807 initialze the plugin or the API */
3808 api = GNUNET_new (struct GNUNET_TRANSPORT_PluginFunctions);
3810 api->address_pretty_printer = &tcp_plugin_address_pretty_printer;
3811 api->address_to_string = &tcp_plugin_address_to_string;
3812 api->string_to_address = &tcp_plugin_string_to_address;
3816 GNUNET_assert (NULL != env->cfg);
3818 GNUNET_CONFIGURATION_get_value_number (env->cfg,
3822 max_connections = 128;
3826 GNUNET_CONFIGURATION_get_value_number (env->cfg, "transport-tcp",
3830 GNUNET_CONFIGURATION_get_value_number (env->cfg, "transport-tcp",
3831 "ADVERTISED-PORT", &aport)) &&
3834 LOG(GNUNET_ERROR_TYPE_ERROR,
3835 _("Require valid port number for service `%s' in configuration!\n"),
3845 service = LEGACY_SERVICE_start ("transport-tcp",
3847 LEGACY_SERVICE_OPTION_NONE);
3848 if (NULL == service)
3850 LOG (GNUNET_ERROR_TYPE_WARNING,
3851 _("Failed to start service.\n"));
3859 plugin = GNUNET_new (struct Plugin);
3860 plugin->sessionmap = GNUNET_CONTAINER_multipeermap_create (max_connections,
3862 plugin->max_connections = max_connections;
3863 plugin->open_port = bport;
3864 plugin->adv_port = aport;
3866 plugin->my_welcome.header.size = htons (sizeof(struct WelcomeMessage));
3867 plugin->my_welcome.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_WELCOME);
3868 plugin->my_welcome.clientIdentity = *plugin->env->my_identity;
3870 if ( (NULL != service) &&
3872 GNUNET_CONFIGURATION_get_value_yesno (env->cfg,
3877 plugin->myoptions |= TCP_OPTIONS_TCP_STEALTH;
3878 lsocks = LEGACY_SERVICE_get_listen_sockets (service);
3881 uint32_t len = sizeof (struct WelcomeMessage);
3883 for (i=0;NULL!=lsocks[i];i++)
3886 GNUNET_NETWORK_socket_setsockopt (lsocks[i],
3890 sizeof (struct GNUNET_PeerIdentity))) ||
3892 GNUNET_NETWORK_socket_setsockopt (lsocks[i],
3894 TCP_STEALTH_INTEGRITY_LEN,
3898 /* TCP STEALTH not supported by kernel */
3899 GNUNET_assert (0 == i);
3900 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3901 _("TCP_STEALTH not supported on this platform.\n"));
3907 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3908 _("TCP_STEALTH not supported on this platform.\n"));
3913 if ( (NULL != service) &&
3916 get_server_addresses ("transport-tcp",
3921 for (ret = ret_s-1; ret >= 0; ret--)
3922 LOG (GNUNET_ERROR_TYPE_INFO,
3923 "Binding to address `%s'\n",
3924 GNUNET_a2s (addrs[ret], addrlens[ret]));
3926 = GNUNET_NAT_register (env->cfg,
3929 (unsigned int) ret_s,
3930 (const struct sockaddr **) addrs,
3932 &tcp_nat_port_map_callback,
3933 &try_connection_reversal,
3935 for (ret = ret_s -1; ret >= 0; ret--)
3936 GNUNET_free (addrs[ret]);
3937 GNUNET_free_non_null (addrs);
3938 GNUNET_free_non_null (addrlens);
3942 plugin->nat = GNUNET_NAT_register (plugin->env->cfg,
3949 &try_connection_reversal,
3952 api = GNUNET_new (struct GNUNET_TRANSPORT_PluginFunctions);
3954 api->send = &tcp_plugin_send;
3955 api->get_session = &tcp_plugin_get_session;
3956 api->disconnect_session = &tcp_plugin_disconnect_session;
3957 api->query_keepalive_factor = &tcp_plugin_query_keepalive_factor;
3958 api->disconnect_peer = &tcp_plugin_disconnect;
3959 api->address_pretty_printer = &tcp_plugin_address_pretty_printer;
3960 api->check_address = &tcp_plugin_check_address;
3961 api->address_to_string = &tcp_plugin_address_to_string;
3962 api->string_to_address = &tcp_plugin_string_to_address;
3963 api->get_network = &tcp_plugin_get_network;
3964 api->get_network_for_address = &tcp_plugin_get_network_for_address;
3965 api->update_session_timeout = &tcp_plugin_update_session_timeout;
3966 api->update_inbound_delay = &tcp_plugin_update_inbound_delay;
3967 api->setup_monitor = &tcp_plugin_setup_monitor;
3968 plugin->service = service;
3969 if (NULL != service)
3971 plugin->server = LEGACY_SERVICE_get_server (service);
3976 GNUNET_CONFIGURATION_get_value_time (env->cfg,
3981 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
3987 = GNUNET_SERVER_create_with_sockets (NULL,
3993 plugin->handlers = GNUNET_malloc (sizeof (my_handlers));
3994 GNUNET_memcpy (plugin->handlers,
3996 sizeof(my_handlers));
3997 for (i = 0;i < sizeof(my_handlers) / sizeof(struct GNUNET_SERVER_MessageHandler);i++)
3998 plugin->handlers[i].callback_cls = plugin;
4000 GNUNET_SERVER_add_handlers (plugin->server,
4002 GNUNET_SERVER_connect_notify (plugin->server,
4005 GNUNET_SERVER_disconnect_notify (plugin->server,
4008 plugin->nat_wait_conns = GNUNET_CONTAINER_multipeermap_create (16,
4011 LOG (GNUNET_ERROR_TYPE_INFO,
4012 _("TCP transport listening on port %llu\n"),
4015 LOG (GNUNET_ERROR_TYPE_INFO,
4016 _("TCP transport not listening on any port (client only)\n"));
4017 if ( (aport != bport) &&
4019 LOG (GNUNET_ERROR_TYPE_INFO,
4020 _("TCP transport advertises itself as being on port %llu\n"),
4022 /* Initially set connections to 0 */
4023 GNUNET_STATISTICS_set (plugin->env->stats,
4024 gettext_noop ("# TCP sessions active"),
4030 if (NULL != plugin->nat)
4031 GNUNET_NAT_unregister (plugin->nat);
4032 GNUNET_CONTAINER_multipeermap_destroy (plugin->sessionmap);
4033 if (NULL != service)
4034 LEGACY_SERVICE_stop (service);
4035 GNUNET_free (plugin);
4036 GNUNET_free_non_null (api);
4042 * Exit point from the plugin.
4044 * @param cls the `struct GNUNET_TRANSPORT_PluginFunctions`
4048 libgnunet_plugin_transport_tcp_done (void *cls)
4050 struct GNUNET_TRANSPORT_PluginFunctions *api = cls;
4051 struct Plugin *plugin = api->cls;
4052 struct TCPProbeContext *tcp_probe;
4053 struct PrettyPrinterContext *cur;
4054 struct PrettyPrinterContext *next;
4061 LOG (GNUNET_ERROR_TYPE_DEBUG,
4062 "Shutting down TCP plugin\n");
4064 /* Removing leftover sessions */
4065 GNUNET_CONTAINER_multipeermap_iterate (plugin->sessionmap,
4066 &session_disconnect_it,
4068 /* Removing leftover NAT sessions */
4069 GNUNET_CONTAINER_multipeermap_iterate (plugin->nat_wait_conns,
4070 &session_disconnect_it,
4073 for (cur = plugin->ppc_dll_head; NULL != cur; cur = next)
4076 GNUNET_CONTAINER_DLL_remove (plugin->ppc_dll_head,
4077 plugin->ppc_dll_tail,
4079 GNUNET_RESOLVER_request_cancel (cur->resolver_handle);
4080 cur->asc (cur->asc_cls,
4086 if (NULL != plugin->service)
4087 LEGACY_SERVICE_stop (plugin->service);
4089 GNUNET_SERVER_destroy (plugin->server);
4090 GNUNET_free (plugin->handlers);
4091 if (NULL != plugin->nat)
4092 GNUNET_NAT_unregister (plugin->nat);
4093 while (NULL != (tcp_probe = plugin->probe_head))
4095 GNUNET_CONTAINER_DLL_remove (plugin->probe_head,
4098 GNUNET_CONNECTION_destroy (tcp_probe->sock);
4099 GNUNET_free (tcp_probe);
4101 GNUNET_CONTAINER_multipeermap_destroy (plugin->nat_wait_conns);
4102 GNUNET_CONTAINER_multipeermap_destroy (plugin->sessionmap);
4103 GNUNET_break (0 == plugin->cur_connections);
4104 GNUNET_free (plugin);
4109 /* end of plugin_transport_tcp.c */