2 This file is part of GNUnet
3 Copyright (C) 2002--2015 GNUnet e.V.
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
19 * @file transport/plugin_transport_tcp.c
20 * @brief Implementation of the TCP transport service
21 * @author Christian Grothoff
24 #include "gnunet_hello_lib.h"
25 #include "gnunet_constants.h"
26 #include "gnunet_util_lib.h"
27 #include "gnunet_nat_service.h"
28 #include "gnunet_protocols.h"
29 #include "gnunet_resolver_service.h"
30 #include "gnunet_signatures.h"
31 #include "gnunet_statistics_service.h"
32 #include "gnunet_transport_service.h"
33 #include "gnunet_transport_plugin.h"
34 #include "transport.h"
36 #define LOG(kind,...) GNUNET_log_from (kind, "transport-tcp",__VA_ARGS__)
38 #define PLUGIN_NAME "tcp"
41 * How long until we give up on establishing an NAT connection?
44 #define NAT_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10)
47 * Opaque handle that can be used to cancel
48 * a transmit-ready notification.
50 struct GNUNET_CONNECTION_TransmitHandle;
53 * @brief handle for a server
55 struct GNUNET_SERVER_Handle;
58 * @brief opaque handle for a client of the server
60 struct GNUNET_SERVER_Client;
63 * @brief opaque handle server returns for aborting transmission to a client.
65 struct GNUNET_SERVER_TransmitHandle;
68 * @brief handle for a network connection
70 struct GNUNET_CONNECTION_Handle;
73 * @brief handle for a network service
75 struct LEGACY_SERVICE_Context;
79 * Stops a service that was started with #GNUNET_SERVICE_start().
81 * @param srv service to stop
84 LEGACY_SERVICE_stop (struct LEGACY_SERVICE_Context *srv);
89 * Function called to notify a client about the connection begin ready
90 * to queue more data. @a buf will be NULL and @a size zero if the
91 * connection was closed for writing in the meantime.
94 * @param size number of bytes available in @a buf
95 * @param buf where the callee should write the message
96 * @return number of bytes written to @a buf
99 (*GNUNET_CONNECTION_TransmitReadyNotify) (void *cls,
104 * Credentials for UNIX domain sockets.
106 struct GNUNET_CONNECTION_Credentials
109 * UID of the other end of the connection.
114 * GID of the other end of the connection.
121 * Functions with this signature are called whenever a client
122 * is disconnected on the network level.
125 * @param client identification of the client; NULL
126 * for the last call when the server is destroyed
129 (*GNUNET_SERVER_DisconnectCallback) (void *cls,
130 struct GNUNET_SERVER_Client *client);
134 * Functions with this signature are called whenever a client
135 * is connected on the network level.
138 * @param client identification of the client
141 (*GNUNET_SERVER_ConnectCallback) (void *cls,
142 struct GNUNET_SERVER_Client *client);
148 * Function to call for access control checks.
151 * @param ucred credentials, if available, otherwise NULL
152 * @param addr address
153 * @param addrlen length of address
154 * @return GNUNET_YES to allow, GNUNET_NO to deny, GNUNET_SYSERR
155 * for unknown address family (will be denied).
158 (*GNUNET_CONNECTION_AccessCheck) (void *cls,
160 GNUNET_CONNECTION_Credentials *
162 const struct sockaddr * addr,
166 * Callback function for data received from the network. Note that
167 * both "available" and "err" would be 0 if the read simply timed out.
170 * @param buf pointer to received data
171 * @param available number of bytes availabe in "buf",
172 * possibly 0 (on errors)
173 * @param addr address of the sender
174 * @param addrlen size of addr
175 * @param errCode value of errno (on errors receiving)
178 (*GNUNET_CONNECTION_Receiver) (void *cls, const void *buf,
180 const struct sockaddr * addr,
181 socklen_t addrlen, int errCode);
186 * Close the connection and free associated resources. There must
187 * not be any pending requests for reading or writing to the
188 * connection at this time.
190 * @param connection connection to destroy
193 GNUNET_CONNECTION_destroy (struct GNUNET_CONNECTION_Handle *connection);
197 * Signature of a function to create a custom tokenizer.
199 * @param cls closure from #GNUNET_SERVER_set_callbacks
200 * @param client handle to client the tokenzier will be used for
201 * @return handle to custom tokenizer ('mst')
204 (*GNUNET_SERVER_MstCreateCallback) (void *cls,
205 struct GNUNET_SERVER_Client *client);
209 * Signature of a function to destroy a custom tokenizer.
211 * @param cls closure from #GNUNET_SERVER_set_callbacks
212 * @param mst custom tokenizer handle
215 (*GNUNET_SERVER_MstDestroyCallback) (void *cls,
219 * Signature of a function to receive data for a custom tokenizer.
221 * @param cls closure from #GNUNET_SERVER_set_callbacks
222 * @param mst custom tokenizer handle
223 * @param client_identity ID of client for which this is a buffer,
224 * can be NULL (will be passed back to 'cb')
225 * @param buf input data to add
226 * @param size number of bytes in @a buf
227 * @param purge should any excess bytes in the buffer be discarded
228 * (i.e. for packet-based services like UDP)
229 * @param one_shot only call callback once, keep rest of message in buffer
230 * @return #GNUNET_OK if we are done processing (need more data)
231 * #GNUNET_NO if one_shot was set and we have another message ready
232 * #GNUNET_SYSERR if the data stream is corrupt
235 (*GNUNET_SERVER_MstReceiveCallback) (void *cls, void *mst,
236 struct GNUNET_SERVER_Client *client,
242 * Functions with this signature are called whenever a message is
246 * @param client identification of the client
247 * @param message the actual message
250 (*GNUNET_SERVER_MessageCallback) (void *cls,
251 struct GNUNET_SERVER_Client *client,
252 const struct GNUNET_MessageHeader *message);
255 * Message handler. Each struct specifies how to handle on particular
256 * type of message received.
258 struct GNUNET_SERVER_MessageHandler
261 * Function to call for messages of "type".
263 GNUNET_SERVER_MessageCallback callback;
266 * Closure argument for @e callback.
271 * Type of the message this handler covers.
276 * Expected size of messages of this type. Use 0 for
277 * variable-size. If non-zero, messages of the given
278 * type will be discarded (and the connection closed)
279 * if they do not have the right size.
281 uint16_t expected_size;
287 * Options for the service (bitmask).
289 enum LEGACY_SERVICE_Options
292 * Use defaults. Terminates all client connections and the listen
293 * sockets immediately upon receiving the shutdown signal.
295 LEGACY_SERVICE_OPTION_NONE = 0,
298 * Do not trigger server shutdown on signal at all; instead, allow
299 * for the user to terminate the server explicitly when needed
300 * by calling #LEGACY_SERVICE_shutdown().
302 LEGACY_SERVICE_OPTION_MANUAL_SHUTDOWN = 1,
305 * Trigger a SOFT server shutdown on signals, allowing active
306 * non-monitor clients to complete their transactions.
308 LEGACY_SERVICE_OPTION_SOFT_SHUTDOWN = 2
314 * Ask the server to disconnect from the given client. This is the
315 * same as passing #GNUNET_SYSERR to #GNUNET_SERVER_receive_done,
316 * except that it allows dropping of a client even when not handling a
317 * message from that client.
319 * @param client the client to disconnect from
322 GNUNET_SERVER_client_disconnect (struct GNUNET_SERVER_Client *client);
325 * Return user context associated with the given client.
326 * Note: you should probably use the macro (call without the underscore).
328 * @param client client to query
329 * @param size number of bytes in user context struct (for verification only)
330 * @return pointer to user context
333 GNUNET_SERVER_client_get_user_context_ (struct GNUNET_SERVER_Client *client,
338 * Functions with this signature are called whenever a
339 * complete message is received by the tokenizer.
341 * Do not call #GNUNET_SERVER_mst_destroy from within
342 * the scope of this callback.
345 * @param client identification of the client
346 * @param message the actual message
347 * @return #GNUNET_OK on success, #GNUNET_SYSERR to stop further processing
350 (*GNUNET_SERVER_MessageTokenizerCallback) (void *cls,
352 const struct GNUNET_MessageHeader *message);
356 * Create a message stream tokenizer.
358 * @param cb function to call on completed messages
359 * @param cb_cls closure for @a cb
360 * @return handle to tokenizer
362 struct GNUNET_SERVER_MessageStreamTokenizer *
363 GNUNET_SERVER_mst_create (GNUNET_SERVER_MessageTokenizerCallback cb,
367 * Add incoming data to the receive buffer and call the
368 * callback for all complete messages.
370 * @param mst tokenizer to use
371 * @param client_identity ID of client for which this is a buffer,
372 * can be NULL (will be passed back to 'cb')
373 * @param buf input data to add
374 * @param size number of bytes in @a buf
375 * @param purge should any excess bytes in the buffer be discarded
376 * (i.e. for packet-based services like UDP)
377 * @param one_shot only call callback once, keep rest of message in buffer
378 * @return #GNUNET_OK if we are done processing (need more data)
379 * #GNUNET_NO if one_shot was set and we have another message ready
380 * #GNUNET_SYSERR if the data stream is corrupt
383 GNUNET_SERVER_mst_receive (struct GNUNET_SERVER_MessageStreamTokenizer *mst,
384 void *client_identity,
385 const char *buf, size_t size,
386 int purge, int one_shot);
391 * Destroys a tokenizer.
393 * @param mst tokenizer to destroy
396 GNUNET_SERVER_mst_destroy (struct GNUNET_SERVER_MessageStreamTokenizer *mst);
400 * Set user context to be associated with the given client.
401 * Note: you should probably use the macro (call without the underscore).
403 * @param client client to query
404 * @param ptr pointer to user context
405 * @param size number of bytes in user context struct (for verification only)
408 GNUNET_SERVER_client_set_user_context_ (struct GNUNET_SERVER_Client *client,
412 * Return user context associated with the given client.
414 * @param client client to query
415 * @param type expected return type (i.e. 'struct Foo')
416 * @return pointer to user context of type 'type *'.
418 #define GNUNET_SERVER_client_get_user_context(client,type) \
419 (type *) GNUNET_SERVER_client_get_user_context_ (client, sizeof (type))
422 * Set user context to be associated with the given client.
424 * @param client client to query
425 * @param value pointer to user context
427 #define GNUNET_SERVER_client_set_user_context(client,value) \
428 GNUNET_SERVER_client_set_user_context_ (client, value, sizeof (*value))
433 * Notify us when the server has enough space to transmit
434 * a message of the given size to the given client.
436 * @param client client to transmit message to
437 * @param size requested amount of buffer space
438 * @param timeout after how long should we give up (and call
439 * notify with buf NULL and size 0)?
440 * @param callback function to call when space is available
441 * @param callback_cls closure for @a callback
442 * @return non-NULL if the notify callback was queued; can be used
443 * to cancel the request using
444 * #GNUNET_SERVER_notify_transmit_ready_cancel.
445 * NULL if we are already going to notify someone else (busy)
447 struct GNUNET_SERVER_TransmitHandle *
448 GNUNET_SERVER_notify_transmit_ready (struct GNUNET_SERVER_Client *client,
450 struct GNUNET_TIME_Relative timeout,
451 GNUNET_CONNECTION_TransmitReadyNotify callback,
455 * Abort transmission request.
457 * @param th request to abort
460 GNUNET_SERVER_notify_transmit_ready_cancel (struct GNUNET_SERVER_TransmitHandle *th);
466 * Notify the server that the given client handle should
467 * be kept (keeps the connection up if possible, increments
468 * the internal reference counter).
470 * @param client the client to keep
473 GNUNET_SERVER_client_keep (struct GNUNET_SERVER_Client *client);
477 * Notify the server that the given client handle is no
478 * longer required. Decrements the reference counter. If
479 * that counter reaches zero an inactive connection maybe
482 * @param client the client to drop
485 GNUNET_SERVER_client_drop (struct GNUNET_SERVER_Client *client);
489 * Function called by the service's run
490 * method to run service-specific setup code.
493 * @param server the initialized server
494 * @param cfg configuration to use
497 (*LEGACY_SERVICE_Main) (void *cls,
498 struct GNUNET_SERVER_Handle *server,
499 const struct GNUNET_CONFIGURATION_Handle *cfg);
504 * Suspend accepting connections from the listen socket temporarily.
505 * Resume activity using #GNUNET_SERVER_resume.
507 * @param server server to stop accepting connections.
510 GNUNET_SERVER_suspend (struct GNUNET_SERVER_Handle *server);
513 * Notify us when the server has enough space to transmit
514 * a message of the given size to the given client.
516 * @param client client to transmit message to
517 * @param size requested amount of buffer space
518 * @param timeout after how long should we give up (and call
519 * notify with buf NULL and size 0)?
520 * @param callback function to call when space is available
521 * @param callback_cls closure for @a callback
522 * @return non-NULL if the notify callback was queued; can be used
523 * to cancel the request using
524 * #GNUNET_SERVER_notify_transmit_ready_cancel.
525 * NULL if we are already going to notify someone else (busy)
527 struct GNUNET_SERVER_TransmitHandle *
528 GNUNET_SERVER_notify_transmit_ready (struct GNUNET_SERVER_Client *client,
530 struct GNUNET_TIME_Relative timeout,
531 GNUNET_CONNECTION_TransmitReadyNotify callback,
536 * Add a TCP socket-based connection to the set of handles managed by
537 * this server. Use this function for outgoing (P2P) connections that
538 * we initiated (and where this server should process incoming
541 * @param server the server to use
542 * @param connection the connection to manage (client must
543 * stop using this connection from now on)
544 * @return the client handle
546 struct GNUNET_SERVER_Client *
547 GNUNET_SERVER_connect_socket (struct GNUNET_SERVER_Handle *server,
548 struct GNUNET_CONNECTION_Handle *connection);
552 * Resume accepting connections from the listen socket.
554 * @param server server to resume accepting connections.
557 GNUNET_SERVER_resume (struct GNUNET_SERVER_Handle *server);
560 * Free resources held by this server.
562 * @param server server to destroy
565 GNUNET_SERVER_destroy (struct GNUNET_SERVER_Handle *server);
570 #include "tcp_connection_legacy.c"
571 #include "tcp_server_mst_legacy.c"
572 #include "tcp_server_legacy.c"
573 #include "tcp_service_legacy.c"
575 GNUNET_NETWORK_STRUCT_BEGIN
578 * Initial handshake message for a session.
580 struct WelcomeMessage
583 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_WELCOME.
585 struct GNUNET_MessageHeader header;
588 * Identity of the node connecting (TCP client)
590 struct GNUNET_PeerIdentity clientIdentity;
595 * Basically a WELCOME message, but with the purpose
596 * of giving the waiting peer a client handle to use
598 struct TCP_NAT_ProbeMessage
601 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_NAT_PROBE.
603 struct GNUNET_MessageHeader header;
606 * Identity of the sender of the message.
608 struct GNUNET_PeerIdentity clientIdentity;
611 GNUNET_NETWORK_STRUCT_END
614 * Context for sending a NAT probe via TCP.
616 struct TCPProbeContext
620 * Active probes are kept in a DLL.
622 struct TCPProbeContext *next;
625 * Active probes are kept in a DLL.
627 struct TCPProbeContext *prev;
632 struct GNUNET_CONNECTION_Handle *sock;
635 * Message to be sent.
637 struct TCP_NAT_ProbeMessage message;
640 * Handle to the transmission.
642 struct GNUNET_CONNECTION_TransmitHandle *transmit_handle;
645 * Transport plugin handle.
647 struct Plugin *plugin;
651 * Bits in the `options` field of TCP addresses.
653 enum TcpAddressOptions
659 TCP_OPTIONS_NONE = 0,
662 * See #HTTP_OPTIONS_VERIFY_CERTIFICATE.
664 TCP_OPTIONS_RESERVED = 1,
667 * Enable TCP Stealth-style port knocking.
669 TCP_OPTIONS_TCP_STEALTH = 2
672 GNUNET_NETWORK_STRUCT_BEGIN
675 * Network format for IPv4 addresses.
677 struct IPv4TcpAddress
680 * Optional options and flags for this address,
681 * see `enum TcpAddressOptions`
683 uint32_t options GNUNET_PACKED;
686 * IPv4 address, in network byte order.
688 uint32_t ipv4_addr GNUNET_PACKED;
691 * Port number, in network byte order.
693 uint16_t t4_port GNUNET_PACKED;
698 * Network format for IPv6 addresses.
700 struct IPv6TcpAddress
703 * Optional flags for this address
704 * see `enum TcpAddressOptions`
706 uint32_t options GNUNET_PACKED;
711 struct in6_addr ipv6_addr GNUNET_PACKED;
714 * Port number, in network byte order.
716 uint16_t t6_port GNUNET_PACKED;
719 GNUNET_NETWORK_STRUCT_END
722 * Encapsulation of all of the state of the plugin.
727 * Information kept for each message that is yet to
730 struct PendingMessage
734 * This is a doubly-linked list.
736 struct PendingMessage *next;
739 * This is a doubly-linked list.
741 struct PendingMessage *prev;
744 * The pending message
749 * Continuation function to call once the message
750 * has been sent. Can be NULL if there is no
751 * continuation to call.
753 GNUNET_TRANSPORT_TransmitContinuation transmit_cont;
756 * Closure for @e transmit_cont.
758 void *transmit_cont_cls;
761 * Timeout value for the pending message.
763 struct GNUNET_TIME_Absolute timeout;
766 * So that the gnunet-service-transport can group messages together,
767 * these pending messages need to accept a message buffer and size
768 * instead of just a `struct GNUNET_MessageHeader`.
775 * Session handle for TCP connections.
777 struct GNUNET_ATS_Session
780 * To whom are we talking to (set to our identity
781 * if we are still waiting for the welcome message)
783 struct GNUNET_PeerIdentity target;
786 * Pointer to the global plugin struct.
788 struct Plugin *plugin;
791 * The client (used to identify this connection)
793 struct GNUNET_SERVER_Client *client;
796 * Task cleaning up a NAT client connection establishment attempt;
798 struct GNUNET_SCHEDULER_Task *nat_connection_timeout;
801 * Messages currently pending for transmission
802 * to this peer, if any.
804 struct PendingMessage *pending_messages_head;
807 * Messages currently pending for transmission
808 * to this peer, if any.
810 struct PendingMessage *pending_messages_tail;
813 * Handle for pending transmission request.
815 struct GNUNET_SERVER_TransmitHandle *transmit_handle;
818 * Address of the other peer.
820 struct GNUNET_HELLO_Address *address;
823 * ID of task used to delay receiving more to throttle sender.
825 struct GNUNET_SCHEDULER_Task *receive_delay_task;
828 * Session timeout task
830 struct GNUNET_SCHEDULER_Task *timeout_task;
833 * When will this session time out?
835 struct GNUNET_TIME_Absolute timeout;
838 * When will we continue to read from the socket?
839 * (used to enforce inbound quota).
841 struct GNUNET_TIME_Absolute receive_delay;
844 * Last activity on this connection. Used to select preferred
847 struct GNUNET_TIME_Absolute last_activity;
850 * Number of bytes waiting for transmission to this peer.
852 unsigned long long bytes_in_queue;
855 * Number of messages waiting for transmission to this peer.
857 unsigned int msgs_in_queue;
860 * Network type of the address.
862 enum GNUNET_ATS_Network_Type scope;
865 * Are we still expecting the welcome message? (#GNUNET_YES/#GNUNET_NO)
867 int expecting_welcome;
870 * Was this session created using NAT traversal?
878 * Context for address to string conversion, closure
879 * for #append_port().
881 struct PrettyPrinterContext
886 struct PrettyPrinterContext *next;
891 struct PrettyPrinterContext *prev;
896 struct Plugin *plugin;
901 struct GNUNET_SCHEDULER_Task *timeout_task;
906 struct GNUNET_RESOLVER_RequestHandle *resolver_handle;
909 * Function to call with the result.
911 GNUNET_TRANSPORT_AddressStringCallback asc;
914 * Clsoure for @e asc.
929 * Port to add after the IP address.
936 * Encapsulation of all of the state of the plugin.
943 struct GNUNET_TRANSPORT_PluginEnvironment *env;
948 struct GNUNET_CONNECTION_Handle *lsock;
951 * Our handle to the NAT module.
953 struct GNUNET_NAT_Handle *nat;
956 * Map from peer identities to sessions for the given peer.
958 struct GNUNET_CONTAINER_MultiPeerMap *sessionmap;
961 * Handle to the network service.
963 struct LEGACY_SERVICE_Context *service;
966 * Handle to the server for this service.
968 struct GNUNET_SERVER_Handle *server;
971 * Copy of the handler array where the closures are
972 * set to this struct's instance.
974 struct GNUNET_SERVER_MessageHandler *handlers;
977 * Map of peers we have tried to contact behind a NAT
979 struct GNUNET_CONTAINER_MultiPeerMap *nat_wait_conns;
982 * List of active TCP probes.
984 struct TCPProbeContext *probe_head;
987 * List of active TCP probes.
989 struct TCPProbeContext *probe_tail;
992 * Function to call about session status changes.
994 GNUNET_TRANSPORT_SessionInfoCallback sic;
997 * Closure for @e sic.
1002 * ID of task used to update our addresses when one expires.
1004 struct GNUNET_SCHEDULER_Task *address_update_task;
1007 * Running pretty printers: head
1009 struct PrettyPrinterContext *ppc_dll_head;
1012 * Running pretty printers: tail
1014 struct PrettyPrinterContext *ppc_dll_tail;
1017 * Welcome message used by this peer.
1019 struct WelcomeMessage my_welcome;
1022 * How many more TCP sessions are we allowed to open right now?
1024 unsigned long long max_connections;
1027 * How many more TCP sessions do we have right now?
1029 unsigned long long cur_connections;
1037 * Port that we are actually listening on.
1042 * Port that the user said we would have visible to the
1043 * rest of the world.
1051 * Get the list of addresses that a server for the given service
1054 * @param service_name name of the service
1055 * @param cfg configuration (which specifies the addresses)
1056 * @param addrs set (call by reference) to an array of pointers to the
1057 * addresses the server should bind to and listen on; the
1058 * array will be NULL-terminated (on success)
1059 * @param addr_lens set (call by reference) to an array of the lengths
1060 * of the respective `struct sockaddr` struct in the @a addrs
1061 * array (on success)
1062 * @return number of addresses found on success,
1063 * #GNUNET_SYSERR if the configuration
1064 * did not specify reasonable finding information or
1065 * if it specified a hostname that could not be resolved;
1066 * #GNUNET_NO if the number of addresses configured is
1067 * zero (in this case, `*addrs` and `*addr_lens` will be
1071 get_server_addresses (const char *service_name,
1072 const struct GNUNET_CONFIGURATION_Handle *cfg,
1073 struct sockaddr ***addrs,
1074 socklen_t ** addr_lens)
1077 struct GNUNET_NETWORK_Handle *desc;
1078 unsigned long long port;
1080 struct addrinfo hints;
1081 struct addrinfo *res;
1082 struct addrinfo *pos;
1083 struct addrinfo *next;
1088 struct sockaddr **saddrs;
1089 socklen_t *saddrlens;
1095 if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "DISABLEV6"))
1097 if (GNUNET_SYSERR ==
1099 GNUNET_CONFIGURATION_get_value_yesno (cfg, service_name, "DISABLEV6")))
1100 return GNUNET_SYSERR;
1103 disablev6 = GNUNET_NO;
1107 /* probe IPv6 support */
1108 desc = GNUNET_NETWORK_socket_create (PF_INET6, SOCK_STREAM, 0);
1111 if ((ENOBUFS == errno) || (ENOMEM == errno) || (ENFILE == errno) ||
1114 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "socket");
1115 return GNUNET_SYSERR;
1117 LOG (GNUNET_ERROR_TYPE_INFO,
1118 _("Disabling IPv6 support for service `%s', failed to create IPv6 socket: %s\n"),
1119 service_name, STRERROR (errno));
1120 disablev6 = GNUNET_YES;
1124 GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (desc));
1130 if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "PORT"))
1133 GNUNET_CONFIGURATION_get_value_number (cfg, service_name,
1136 LOG (GNUNET_ERROR_TYPE_ERROR,
1137 _("Require valid port number for service `%s' in configuration!\n"),
1142 LOG (GNUNET_ERROR_TYPE_ERROR,
1143 _("Require valid port number for service `%s' in configuration!\n"),
1145 return GNUNET_SYSERR;
1149 if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "BINDTO"))
1151 GNUNET_break (GNUNET_OK ==
1152 GNUNET_CONFIGURATION_get_value_string (cfg, service_name,
1153 "BINDTO", &hostname));
1159 abstract = GNUNET_NO;
1162 GNUNET_CONFIGURATION_have_value (cfg, service_name, "UNIXPATH")) &&
1164 GNUNET_CONFIGURATION_get_value_filename (cfg, service_name, "UNIXPATH",
1166 (0 < strlen (unixpath)))
1168 /* probe UNIX support */
1169 struct sockaddr_un s_un;
1171 if (strlen (unixpath) >= sizeof (s_un.sun_path))
1173 LOG (GNUNET_ERROR_TYPE_WARNING,
1174 _("UNIXPATH `%s' too long, maximum length is %llu\n"), unixpath,
1175 (unsigned long long) sizeof (s_un.sun_path));
1176 unixpath = GNUNET_NETWORK_shorten_unixpath (unixpath);
1177 LOG (GNUNET_ERROR_TYPE_INFO,
1178 _("Using `%s' instead\n"),
1182 abstract = GNUNET_CONFIGURATION_get_value_yesno (cfg,
1184 "USE_ABSTRACT_SOCKETS");
1185 if (GNUNET_SYSERR == abstract)
1186 abstract = GNUNET_NO;
1188 if ((GNUNET_YES != abstract)
1190 GNUNET_DISK_directory_create_for_file (unixpath)))
1191 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
1195 if (NULL != unixpath)
1197 desc = GNUNET_NETWORK_socket_create (AF_UNIX, SOCK_STREAM, 0);
1200 if ((ENOBUFS == errno) || (ENOMEM == errno) || (ENFILE == errno) ||
1203 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "socket");
1204 GNUNET_free_non_null (hostname);
1205 GNUNET_free (unixpath);
1206 return GNUNET_SYSERR;
1208 LOG (GNUNET_ERROR_TYPE_INFO,
1209 _("Disabling UNIX domain socket support for service `%s', failed to create UNIX domain socket: %s\n"),
1212 GNUNET_free (unixpath);
1217 GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (desc));
1223 if ((0 == port) && (NULL == unixpath))
1225 LOG (GNUNET_ERROR_TYPE_ERROR,
1226 _("Have neither PORT nor UNIXPATH for service `%s', but one is required\n"),
1228 GNUNET_free_non_null (hostname);
1229 return GNUNET_SYSERR;
1233 saddrs = GNUNET_malloc (2 * sizeof (struct sockaddr *));
1234 saddrlens = GNUNET_malloc (2 * sizeof (socklen_t));
1235 add_unixpath (saddrs, saddrlens, unixpath, abstract);
1236 GNUNET_free_non_null (unixpath);
1237 GNUNET_free_non_null (hostname);
1239 *addr_lens = saddrlens;
1243 if (NULL != hostname)
1245 LOG (GNUNET_ERROR_TYPE_DEBUG,
1246 "Resolving `%s' since that is where `%s' will bind to.\n",
1249 memset (&hints, 0, sizeof (struct addrinfo));
1251 hints.ai_family = AF_INET;
1252 hints.ai_protocol = IPPROTO_TCP;
1253 if ((0 != (ret = getaddrinfo (hostname, NULL, &hints, &res))) ||
1256 LOG (GNUNET_ERROR_TYPE_ERROR,
1257 _("Failed to resolve `%s': %s\n"),
1259 gai_strerror (ret));
1260 GNUNET_free (hostname);
1261 GNUNET_free_non_null (unixpath);
1262 return GNUNET_SYSERR;
1266 while (NULL != (pos = next))
1268 next = pos->ai_next;
1269 if ((disablev6) && (pos->ai_family == AF_INET6))
1275 LOG (GNUNET_ERROR_TYPE_ERROR,
1276 _("Failed to find %saddress for `%s'.\n"),
1277 disablev6 ? "IPv4 " : "",
1280 GNUNET_free (hostname);
1281 GNUNET_free_non_null (unixpath);
1282 return GNUNET_SYSERR;
1285 if (NULL != unixpath)
1287 saddrs = GNUNET_malloc ((resi + 1) * sizeof (struct sockaddr *));
1288 saddrlens = GNUNET_malloc ((resi + 1) * sizeof (socklen_t));
1290 if (NULL != unixpath)
1292 add_unixpath (saddrs, saddrlens, unixpath, abstract);
1296 while (NULL != (pos = next))
1298 next = pos->ai_next;
1299 if ((disablev6) && (AF_INET6 == pos->ai_family))
1301 if ((IPPROTO_TCP != pos->ai_protocol) && (0 != pos->ai_protocol))
1302 continue; /* not TCP */
1303 if ((SOCK_STREAM != pos->ai_socktype) && (0 != pos->ai_socktype))
1304 continue; /* huh? */
1305 LOG (GNUNET_ERROR_TYPE_DEBUG, "Service `%s' will bind to `%s'\n",
1306 service_name, GNUNET_a2s (pos->ai_addr, pos->ai_addrlen));
1307 if (AF_INET == pos->ai_family)
1309 GNUNET_assert (sizeof (struct sockaddr_in) == pos->ai_addrlen);
1310 saddrlens[i] = pos->ai_addrlen;
1311 saddrs[i] = GNUNET_malloc (saddrlens[i]);
1312 GNUNET_memcpy (saddrs[i], pos->ai_addr, saddrlens[i]);
1313 ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
1317 GNUNET_assert (AF_INET6 == pos->ai_family);
1318 GNUNET_assert (sizeof (struct sockaddr_in6) == pos->ai_addrlen);
1319 saddrlens[i] = pos->ai_addrlen;
1320 saddrs[i] = GNUNET_malloc (saddrlens[i]);
1321 GNUNET_memcpy (saddrs[i], pos->ai_addr, saddrlens[i]);
1322 ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port);
1326 GNUNET_free (hostname);
1332 /* will bind against everything, just set port */
1337 if (NULL != unixpath)
1340 saddrs = GNUNET_malloc ((resi + 1) * sizeof (struct sockaddr *));
1341 saddrlens = GNUNET_malloc ((resi + 1) * sizeof (socklen_t));
1342 if (NULL != unixpath)
1344 add_unixpath (saddrs, saddrlens, unixpath, abstract);
1347 saddrlens[i] = sizeof (struct sockaddr_in);
1348 saddrs[i] = GNUNET_malloc (saddrlens[i]);
1349 #if HAVE_SOCKADDR_IN_SIN_LEN
1350 ((struct sockaddr_in *) saddrs[i])->sin_len = saddrlens[i];
1352 ((struct sockaddr_in *) saddrs[i])->sin_family = AF_INET;
1353 ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
1359 if (NULL != unixpath)
1361 saddrs = GNUNET_malloc ((resi + 1) * sizeof (struct sockaddr *));
1362 saddrlens = GNUNET_malloc ((resi + 1) * sizeof (socklen_t));
1364 if (NULL != unixpath)
1366 add_unixpath (saddrs, saddrlens, unixpath, abstract);
1369 saddrlens[i] = sizeof (struct sockaddr_in6);
1370 saddrs[i] = GNUNET_malloc (saddrlens[i]);
1371 #if HAVE_SOCKADDR_IN_SIN_LEN
1372 ((struct sockaddr_in6 *) saddrs[i])->sin6_len = saddrlens[0];
1374 ((struct sockaddr_in6 *) saddrs[i])->sin6_family = AF_INET6;
1375 ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port);
1377 saddrlens[i] = sizeof (struct sockaddr_in);
1378 saddrs[i] = GNUNET_malloc (saddrlens[i]);
1379 #if HAVE_SOCKADDR_IN_SIN_LEN
1380 ((struct sockaddr_in *) saddrs[i])->sin_len = saddrlens[1];
1382 ((struct sockaddr_in *) saddrs[i])->sin_family = AF_INET;
1383 ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
1386 GNUNET_free_non_null (unixpath);
1388 *addr_lens = saddrlens;
1391 /* end ancient copy-and-paste */
1395 * If a session monitor is attached, notify it about the new
1398 * @param plugin our plugin
1399 * @param session session that changed state
1400 * @param state new state of the session
1403 notify_session_monitor (struct Plugin *plugin,
1404 struct GNUNET_ATS_Session *session,
1405 enum GNUNET_TRANSPORT_SessionState state)
1407 struct GNUNET_TRANSPORT_SessionInfo info;
1409 if (NULL == plugin->sic)
1411 memset (&info, 0, sizeof (info));
1413 info.is_inbound = GNUNET_HELLO_address_check_option (session->address,
1414 GNUNET_HELLO_ADDRESS_INFO_INBOUND);
1415 info.num_msg_pending = session->msgs_in_queue;
1416 info.num_bytes_pending = session->bytes_in_queue;
1417 if (NULL != session->receive_delay_task)
1418 info.receive_delay = session->receive_delay;
1419 info.session_timeout = session->timeout;
1420 info.address = session->address;
1421 plugin->sic (plugin->sic_cls,
1428 * Our external IP address/port mapping has changed.
1430 * @param cls closure, the `struct Plugin`
1431 * @param add_remove #GNUNET_YES to mean the new public IP address, #GNUNET_NO to mean
1432 * the previous (now invalid) one
1433 * @param ac address class the address belongs to
1434 * @param addr either the previous or the new public IP address
1435 * @param addrlen actual length of @a addr
1438 tcp_nat_port_map_callback (void *cls,
1440 enum GNUNET_NAT_AddressClass ac,
1441 const struct sockaddr *addr,
1444 struct Plugin *plugin = cls;
1445 struct GNUNET_HELLO_Address *address;
1446 struct IPv4TcpAddress t4;
1447 struct IPv6TcpAddress t6;
1451 LOG (GNUNET_ERROR_TYPE_INFO,
1452 "NAT notification to %s address `%s'\n",
1453 (GNUNET_YES == add_remove) ? "add" : "remove",
1454 GNUNET_a2s (addr, addrlen));
1455 /* convert 'addr' to our internal format */
1456 switch (addr->sa_family)
1459 GNUNET_assert(addrlen == sizeof(struct sockaddr_in));
1460 memset (&t4, 0, sizeof(t4));
1461 t4.options = htonl (plugin->myoptions);
1462 t4.ipv4_addr = ((struct sockaddr_in *) addr)->sin_addr.s_addr;
1463 t4.t4_port = ((struct sockaddr_in *) addr)->sin_port;
1468 GNUNET_assert(addrlen == sizeof(struct sockaddr_in6));
1469 memset (&t6, 0, sizeof(t6));
1470 GNUNET_memcpy (&t6.ipv6_addr,
1471 &((struct sockaddr_in6 *) addr)->sin6_addr,
1472 sizeof(struct in6_addr));
1473 t6.options = htonl (plugin->myoptions);
1474 t6.t6_port = ((struct sockaddr_in6 *) addr)->sin6_port;
1482 /* modify our published address list */
1483 GNUNET_assert ((args == sizeof (struct IPv4TcpAddress)) ||
1484 (args == sizeof (struct IPv6TcpAddress)));
1485 /* TODO: use 'ac' here in the future... */
1486 address = GNUNET_HELLO_address_allocate (plugin->env->my_identity,
1490 GNUNET_HELLO_ADDRESS_INFO_NONE);
1491 plugin->env->notify_address (plugin->env->cls,
1494 GNUNET_HELLO_address_free (address);
1499 * Function called for a quick conversion of the binary address to
1500 * a numeric address. Note that the caller must not free the
1501 * address and that the next call to this function is allowed
1502 * to override the address again.
1504 * @param cls closure (`struct Plugin*`)
1505 * @param addr binary address
1506 * @param addrlen length of @a addr
1507 * @return string representing the same address
1510 tcp_plugin_address_to_string (void *cls,
1514 static char rbuf[INET6_ADDRSTRLEN + 12];
1515 char buf[INET6_ADDRSTRLEN];
1519 const struct IPv4TcpAddress *t4;
1520 const struct IPv6TcpAddress *t6;
1527 case sizeof(struct IPv6TcpAddress):
1530 port = ntohs (t6->t6_port);
1531 options = ntohl (t6->options);
1532 GNUNET_memcpy (&a6, &t6->ipv6_addr, sizeof(a6));
1535 case sizeof(struct IPv4TcpAddress):
1538 port = ntohs (t4->t4_port);
1539 options = ntohl (t4->options);
1540 GNUNET_memcpy (&a4, &t4->ipv4_addr, sizeof(a4));
1544 LOG (GNUNET_ERROR_TYPE_WARNING,
1545 _("Unexpected address length: %u bytes\n"),
1546 (unsigned int) addrlen);
1549 if (NULL == inet_ntop (af, sb, buf, INET6_ADDRSTRLEN))
1551 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
1555 GNUNET_snprintf (rbuf, sizeof(rbuf),
1556 (af == AF_INET6) ? "%s.%u.[%s]:%u" : "%s.%u.%s:%u",
1566 * Function called to convert a string address to
1569 * @param cls closure (`struct Plugin*`)
1570 * @param addr string address
1571 * @param addrlen length of the address
1572 * @param buf location to store the buffer
1573 * @param added location to store the number of bytes in the buffer.
1574 * If the function returns #GNUNET_SYSERR, its contents are undefined.
1575 * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure
1578 tcp_plugin_string_to_address (void *cls,
1584 struct sockaddr_storage socket_address;
1590 /* Format tcp.options.address:port */
1594 if ((NULL == addr) || (0 == addrlen))
1597 return GNUNET_SYSERR;
1599 if ('\0' != addr[addrlen - 1])
1602 return GNUNET_SYSERR;
1604 if (strlen (addr) != addrlen - 1)
1607 return GNUNET_SYSERR;
1609 plugin = GNUNET_strdup (addr);
1610 optionstr = strchr (plugin, '.');
1611 if (NULL == optionstr)
1614 GNUNET_free(plugin);
1615 return GNUNET_SYSERR;
1617 optionstr[0] = '\0';
1619 options = atol (optionstr);
1620 address = strchr (optionstr, '.');
1621 if (NULL == address)
1624 GNUNET_free(plugin);
1625 return GNUNET_SYSERR;
1631 GNUNET_STRINGS_to_address_ip (address,
1636 GNUNET_free(plugin);
1637 return GNUNET_SYSERR;
1640 GNUNET_free(plugin);
1641 switch (socket_address.ss_family)
1645 struct IPv4TcpAddress *t4;
1646 struct sockaddr_in *in4 = (struct sockaddr_in *) &socket_address;
1647 t4 = GNUNET_new (struct IPv4TcpAddress);
1648 t4->options = htonl (options);
1649 t4->ipv4_addr = in4->sin_addr.s_addr;
1650 t4->t4_port = in4->sin_port;
1652 *added = sizeof(struct IPv4TcpAddress);
1657 struct IPv6TcpAddress *t6;
1658 struct sockaddr_in6 *in6 = (struct sockaddr_in6 *) &socket_address;
1659 t6 = GNUNET_new (struct IPv6TcpAddress);
1660 t6->options = htonl (options);
1661 t6->ipv6_addr = in6->sin6_addr;
1662 t6->t6_port = in6->sin6_port;
1664 *added = sizeof(struct IPv6TcpAddress);
1668 return GNUNET_SYSERR;
1674 * Find the session handle for the given client.
1675 * Currently uses both the hashmap and the client
1676 * context, as the client context is new and the
1677 * logic still needs to be tested.
1679 * @param plugin the plugin
1680 * @param client which client to find the session handle for
1681 * @return NULL if no matching session exists
1683 static struct GNUNET_ATS_Session *
1684 lookup_session_by_client (struct Plugin *plugin,
1685 struct GNUNET_SERVER_Client *client)
1687 return GNUNET_SERVER_client_get_user_context (client,
1688 struct GNUNET_ATS_Session);
1693 * Functions with this signature are called whenever we need
1694 * to close a session due to a disconnect or failure to
1695 * establish a connection.
1697 * @param cls the `struct Plugin`
1698 * @param session session to close down
1699 * @return #GNUNET_OK on success
1702 tcp_plugin_disconnect_session (void *cls,
1703 struct GNUNET_ATS_Session *session)
1705 struct Plugin *plugin = cls;
1706 struct PendingMessage *pm;
1708 LOG (GNUNET_ERROR_TYPE_DEBUG,
1709 "Disconnecting session of peer `%s' address `%s'\n",
1710 GNUNET_i2s (&session->target),
1711 tcp_plugin_address_to_string (session->plugin,
1712 session->address->address,
1713 session->address->address_length));
1715 if (NULL != session->timeout_task)
1717 GNUNET_SCHEDULER_cancel (session->timeout_task);
1718 session->timeout_task = NULL;
1719 session->timeout = GNUNET_TIME_UNIT_ZERO_ABS;
1723 GNUNET_CONTAINER_multipeermap_remove (plugin->sessionmap,
1727 GNUNET_STATISTICS_update (session->plugin->env->stats,
1728 gettext_noop ("# TCP sessions active"),
1734 GNUNET_assert (GNUNET_YES ==
1735 GNUNET_CONTAINER_multipeermap_remove (plugin->nat_wait_conns,
1739 if (NULL != session->client)
1740 GNUNET_SERVER_client_set_user_context (session->client,
1743 /* clean up state */
1744 if (NULL != session->transmit_handle)
1746 GNUNET_SERVER_notify_transmit_ready_cancel (session->transmit_handle);
1747 session->transmit_handle = NULL;
1749 session->plugin->env->session_end (session->plugin->env->cls,
1753 if (NULL != session->nat_connection_timeout)
1755 GNUNET_SCHEDULER_cancel (session->nat_connection_timeout);
1756 session->nat_connection_timeout = NULL;
1759 while (NULL != (pm = session->pending_messages_head))
1761 LOG (GNUNET_ERROR_TYPE_DEBUG,
1762 (NULL != pm->transmit_cont)
1763 ? "Could not deliver message to `%s' at %s.\n"
1764 : "Could not deliver message to `%s' at %s, notifying.\n",
1765 GNUNET_i2s (&session->target),
1766 tcp_plugin_address_to_string (session->plugin,
1767 session->address->address,
1768 session->address->address_length));
1769 GNUNET_STATISTICS_update (session->plugin->env->stats,
1770 gettext_noop ("# bytes currently in TCP buffers"),
1771 -(int64_t) pm->message_size, GNUNET_NO);
1772 GNUNET_STATISTICS_update (session->plugin->env->stats,
1773 gettext_noop ("# bytes discarded by TCP (disconnect)"),
1776 GNUNET_CONTAINER_DLL_remove (session->pending_messages_head,
1777 session->pending_messages_tail,
1779 GNUNET_assert (0 < session->msgs_in_queue);
1780 session->msgs_in_queue--;
1781 GNUNET_assert (pm->message_size <= session->bytes_in_queue);
1782 session->bytes_in_queue -= pm->message_size;
1783 if (NULL != pm->transmit_cont)
1784 pm->transmit_cont (pm->transmit_cont_cls,
1791 GNUNET_assert (0 == session->msgs_in_queue);
1792 GNUNET_assert (0 == session->bytes_in_queue);
1793 notify_session_monitor (session->plugin,
1795 GNUNET_TRANSPORT_SS_DONE);
1797 if (NULL != session->receive_delay_task)
1799 GNUNET_SCHEDULER_cancel (session->receive_delay_task);
1800 session->receive_delay_task = NULL;
1802 if (NULL != session->client)
1804 GNUNET_SERVER_client_disconnect (session->client);
1805 session->client = NULL;
1807 GNUNET_HELLO_address_free (session->address);
1808 GNUNET_assert (NULL == session->transmit_handle);
1809 GNUNET_free (session);
1815 * Function that is called to get the keepalive factor.
1816 * #GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT is divided by this number to
1817 * calculate the interval between keepalive packets.
1819 * @param cls closure with the `struct Plugin`
1820 * @return keepalive factor
1823 tcp_plugin_query_keepalive_factor (void *cls)
1830 * Session was idle for too long, so disconnect it
1832 * @param cls the `struct GNUNET_ATS_Session` of the idle session
1835 session_timeout (void *cls)
1837 struct GNUNET_ATS_Session *s = cls;
1838 struct GNUNET_TIME_Relative left;
1840 s->timeout_task = NULL;
1841 left = GNUNET_TIME_absolute_get_remaining (s->timeout);
1842 if (0 != left.rel_value_us)
1844 /* not actually our turn yet, but let's at least update
1845 the monitor, it may think we're about to die ... */
1846 notify_session_monitor (s->plugin,
1848 GNUNET_TRANSPORT_SS_UPDATE);
1849 s->timeout_task = GNUNET_SCHEDULER_add_delayed (left,
1854 LOG (GNUNET_ERROR_TYPE_DEBUG,
1855 "Session %p was idle for %s, disconnecting\n",
1857 GNUNET_STRINGS_relative_time_to_string (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
1859 /* call session destroy function */
1860 tcp_plugin_disconnect_session (s->plugin,
1866 * Increment session timeout due to activity.
1868 * @param s session to increment timeout for
1871 reschedule_session_timeout (struct GNUNET_ATS_Session *s)
1873 GNUNET_assert (NULL != s->timeout_task);
1874 s->timeout = GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1879 * Create a new session. Also queues a welcome message.
1881 * @param plugin the plugin
1882 * @param address the address to create the session for
1883 * @param scope network scope the address is from
1884 * @param client client to use, reference counter must have already been increased
1885 * @param is_nat this a NAT session, we should wait for a client to
1886 * connect to us from an address, then assign that to
1888 * @return new session object
1890 static struct GNUNET_ATS_Session *
1891 create_session (struct Plugin *plugin,
1892 const struct GNUNET_HELLO_Address *address,
1893 enum GNUNET_ATS_Network_Type scope,
1894 struct GNUNET_SERVER_Client *client,
1897 struct GNUNET_ATS_Session *session;
1898 struct PendingMessage *pm;
1900 if (GNUNET_YES != is_nat)
1901 GNUNET_assert (NULL != client);
1903 GNUNET_assert (NULL == client);
1905 LOG (GNUNET_ERROR_TYPE_DEBUG,
1906 "Creating new session for peer `%s' at address %s\n",
1907 GNUNET_i2s (&address->peer),
1908 tcp_plugin_address_to_string (plugin,
1910 address->address_length));
1911 session = GNUNET_new (struct GNUNET_ATS_Session);
1912 session->last_activity = GNUNET_TIME_absolute_get ();
1913 session->plugin = plugin;
1914 session->is_nat = is_nat;
1917 session->client = client;
1918 GNUNET_SERVER_client_set_user_context (client,
1921 session->address = GNUNET_HELLO_address_copy (address);
1922 session->target = address->peer;
1923 session->expecting_welcome = GNUNET_YES;
1924 session->scope = scope;
1925 pm = GNUNET_malloc (sizeof (struct PendingMessage) +
1926 sizeof (struct WelcomeMessage));
1927 pm->msg = (const char *) &pm[1];
1928 pm->message_size = sizeof(struct WelcomeMessage);
1929 GNUNET_memcpy (&pm[1],
1930 &plugin->my_welcome,
1931 sizeof(struct WelcomeMessage));
1932 pm->timeout = GNUNET_TIME_UNIT_FOREVER_ABS;
1933 GNUNET_STATISTICS_update (plugin->env->stats,
1934 gettext_noop ("# bytes currently in TCP buffers"),
1937 GNUNET_CONTAINER_DLL_insert (session->pending_messages_head,
1938 session->pending_messages_tail,
1940 session->msgs_in_queue++;
1941 session->bytes_in_queue += pm->message_size;
1942 session->timeout = GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1943 session->timeout_task = GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
1946 notify_session_monitor (session->plugin,
1948 GNUNET_TRANSPORT_SS_INIT);
1949 if (GNUNET_YES != is_nat)
1951 GNUNET_STATISTICS_update (plugin->env->stats,
1952 gettext_noop ("# TCP sessions active"),
1955 notify_session_monitor (session->plugin,
1957 GNUNET_TRANSPORT_SS_UP);
1961 notify_session_monitor (session->plugin,
1963 GNUNET_TRANSPORT_SS_HANDSHAKE);
1970 * If we have pending messages, ask the server to
1971 * transmit them (schedule the respective tasks, etc.)
1973 * @param session for which session should we do this
1976 process_pending_messages (struct GNUNET_ATS_Session *session);
1980 * Function called to notify a client about the socket
1981 * being ready to queue more data. "buf" will be
1982 * NULL and "size" zero if the socket was closed for
1983 * writing in the meantime.
1985 * @param cls closure
1986 * @param size number of bytes available in @a buf
1987 * @param buf where the callee should write the message
1988 * @return number of bytes written to @a buf
1991 do_transmit (void *cls,
1995 struct GNUNET_ATS_Session *session = cls;
1996 struct GNUNET_PeerIdentity pid;
1997 struct Plugin *plugin;
1998 struct PendingMessage *pos;
1999 struct PendingMessage *hd;
2000 struct PendingMessage *tl;
2001 struct GNUNET_TIME_Absolute now;
2005 session->transmit_handle = NULL;
2006 plugin = session->plugin;
2009 LOG (GNUNET_ERROR_TYPE_DEBUG,
2010 "Timeout trying to transmit to peer `%s', discarding message queue.\n",
2011 GNUNET_i2s (&session->target));
2012 /* timeout; cancel all messages that have already expired */
2016 now = GNUNET_TIME_absolute_get ();
2017 while ( (NULL != (pos = session->pending_messages_head)) &&
2018 (pos->timeout.abs_value_us <= now.abs_value_us) )
2020 GNUNET_CONTAINER_DLL_remove (session->pending_messages_head,
2021 session->pending_messages_tail,
2023 GNUNET_assert (0 < session->msgs_in_queue);
2024 session->msgs_in_queue--;
2025 GNUNET_assert (pos->message_size <= session->bytes_in_queue);
2026 session->bytes_in_queue -= pos->message_size;
2027 LOG (GNUNET_ERROR_TYPE_DEBUG,
2028 "Failed to transmit %u byte message to `%s'.\n",
2030 GNUNET_i2s (&session->target));
2031 ret += pos->message_size;
2032 GNUNET_CONTAINER_DLL_insert_after (hd,
2037 /* do this call before callbacks (so that if callbacks destroy
2038 * session, they have a chance to cancel actions done by this
2040 process_pending_messages (session);
2041 pid = session->target;
2042 /* no do callbacks and do not use session again since
2043 * the callbacks may abort the session */
2044 while (NULL != (pos = hd))
2046 GNUNET_CONTAINER_DLL_remove (hd,
2049 if (NULL != pos->transmit_cont)
2050 pos->transmit_cont (pos->transmit_cont_cls,
2057 GNUNET_STATISTICS_update (plugin->env->stats,
2058 gettext_noop ("# bytes currently in TCP buffers"), -(int64_t) ret,
2060 GNUNET_STATISTICS_update (plugin->env->stats,
2061 gettext_noop ("# bytes discarded by TCP (timeout)"),
2065 notify_session_monitor (session->plugin,
2067 GNUNET_TRANSPORT_SS_UPDATE);
2070 /* copy all pending messages that would fit */
2075 while (NULL != (pos = session->pending_messages_head))
2077 if (ret + pos->message_size > size)
2079 GNUNET_CONTAINER_DLL_remove (session->pending_messages_head,
2080 session->pending_messages_tail,
2082 GNUNET_assert (0 < session->msgs_in_queue);
2083 session->msgs_in_queue--;
2084 GNUNET_assert (pos->message_size <= session->bytes_in_queue);
2085 session->bytes_in_queue -= pos->message_size;
2086 GNUNET_assert(size >= pos->message_size);
2087 LOG (GNUNET_ERROR_TYPE_DEBUG,
2088 "Transmitting message of type %u size %u to peer %s at %s\n",
2089 ntohs (((struct GNUNET_MessageHeader *) pos->msg)->type),
2091 GNUNET_i2s (&session->target),
2092 tcp_plugin_address_to_string (session->plugin,
2093 session->address->address,
2094 session->address->address_length));
2095 /* FIXME: this GNUNET_memcpy can be up to 7% of our total runtime */
2096 GNUNET_memcpy (cbuf,
2099 cbuf += pos->message_size;
2100 ret += pos->message_size;
2101 size -= pos->message_size;
2102 GNUNET_CONTAINER_DLL_insert_tail (hd,
2106 notify_session_monitor (session->plugin,
2108 GNUNET_TRANSPORT_SS_UPDATE);
2109 /* schedule 'continuation' before callbacks so that callbacks that
2110 * cancel everything don't cause us to use a session that no longer
2112 process_pending_messages (session);
2113 session->last_activity = GNUNET_TIME_absolute_get ();
2114 pid = session->target;
2115 /* we'll now call callbacks that may cancel the session; hence
2116 * we should not use 'session' after this point */
2117 while (NULL != (pos = hd))
2119 GNUNET_CONTAINER_DLL_remove (hd, tl, pos);
2120 if (NULL != pos->transmit_cont)
2121 pos->transmit_cont (pos->transmit_cont_cls,
2125 pos->message_size); /* FIXME: include TCP overhead */
2128 GNUNET_assert (NULL == hd);
2129 GNUNET_assert (NULL == tl);
2130 GNUNET_STATISTICS_update (plugin->env->stats,
2131 gettext_noop ("# bytes currently in TCP buffers"),
2134 GNUNET_STATISTICS_update (plugin->env->stats,
2135 gettext_noop ("# bytes transmitted via TCP"),
2143 * If we have pending messages, ask the server to
2144 * transmit them (schedule the respective tasks, etc.)
2146 * @param session for which session should we do this
2149 process_pending_messages (struct GNUNET_ATS_Session *session)
2151 struct PendingMessage *pm;
2153 GNUNET_assert (NULL != session->client);
2154 if (NULL != session->transmit_handle)
2156 if (NULL == (pm = session->pending_messages_head))
2159 session->transmit_handle
2160 = GNUNET_SERVER_notify_transmit_ready (session->client,
2162 GNUNET_TIME_absolute_get_remaining (pm->timeout),
2169 * Function that can be used by the transport service to transmit
2170 * a message using the plugin. Note that in the case of a
2171 * peer disconnecting, the continuation MUST be called
2172 * prior to the disconnect notification itself. This function
2173 * will be called with this peer's HELLO message to initiate
2174 * a fresh connection to another peer.
2176 * @param cls closure
2177 * @param session which session must be used
2178 * @param msgbuf the message to transmit
2179 * @param msgbuf_size number of bytes in @a msgbuf
2180 * @param priority how important is the message (most plugins will
2181 * ignore message priority and just FIFO)
2182 * @param to how long to wait at most for the transmission (does not
2183 * require plugins to discard the message after the timeout,
2184 * just advisory for the desired delay; most plugins will ignore
2186 * @param cont continuation to call once the message has
2187 * been transmitted (or if the transport is ready
2188 * for the next transmission call; or if the
2189 * peer disconnected...); can be NULL
2190 * @param cont_cls closure for @a cont
2191 * @return number of bytes used (on the physical network, with overheads);
2192 * -1 on hard errors (i.e. address invalid); 0 is a legal value
2193 * and does NOT mean that the message was not transmitted (DV)
2196 tcp_plugin_send (void *cls,
2197 struct GNUNET_ATS_Session *session,
2200 unsigned int priority,
2201 struct GNUNET_TIME_Relative to,
2202 GNUNET_TRANSPORT_TransmitContinuation cont,
2205 struct Plugin * plugin = cls;
2206 struct PendingMessage *pm;
2208 /* create new message entry */
2209 pm = GNUNET_malloc (sizeof (struct PendingMessage) + msgbuf_size);
2210 pm->msg = (const char *) &pm[1];
2211 GNUNET_memcpy (&pm[1], msgbuf, msgbuf_size);
2212 pm->message_size = msgbuf_size;
2213 pm->timeout = GNUNET_TIME_relative_to_absolute (to);
2214 pm->transmit_cont = cont;
2215 pm->transmit_cont_cls = cont_cls;
2217 LOG (GNUNET_ERROR_TYPE_DEBUG,
2218 "Asked to transmit %u bytes to `%s', added message to list.\n",
2220 GNUNET_i2s (&session->target));
2223 GNUNET_CONTAINER_multipeermap_contains_value (plugin->sessionmap,
2227 GNUNET_assert (NULL != session->client);
2228 GNUNET_SERVER_client_set_timeout (session->client,
2229 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2230 GNUNET_STATISTICS_update (plugin->env->stats,
2231 gettext_noop ("# bytes currently in TCP buffers"),
2235 /* append pm to pending_messages list */
2236 GNUNET_CONTAINER_DLL_insert_tail (session->pending_messages_head,
2237 session->pending_messages_tail,
2239 notify_session_monitor (session->plugin,
2241 GNUNET_TRANSPORT_SS_UPDATE);
2242 session->msgs_in_queue++;
2243 session->bytes_in_queue += pm->message_size;
2244 process_pending_messages (session);
2248 GNUNET_CONTAINER_multipeermap_contains_value (plugin->nat_wait_conns,
2252 LOG (GNUNET_ERROR_TYPE_DEBUG,
2253 "This NAT WAIT session for peer `%s' is not yet ready!\n",
2254 GNUNET_i2s (&session->target));
2255 GNUNET_STATISTICS_update (plugin->env->stats,
2256 gettext_noop ("# bytes currently in TCP buffers"), msgbuf_size,
2258 /* append pm to pending_messages list */
2259 GNUNET_CONTAINER_DLL_insert_tail (session->pending_messages_head,
2260 session->pending_messages_tail,
2262 session->msgs_in_queue++;
2263 session->bytes_in_queue += pm->message_size;
2264 notify_session_monitor (session->plugin,
2266 GNUNET_TRANSPORT_SS_HANDSHAKE);
2269 LOG (GNUNET_ERROR_TYPE_ERROR,
2270 "Invalid session %p\n",
2280 return GNUNET_SYSERR; /* session does not exist here */
2285 * Closure for #session_lookup_it().
2287 struct GNUNET_ATS_SessionItCtx
2290 * Address we are looking for.
2292 const struct GNUNET_HELLO_Address *address;
2295 * Where to store the session (if we found it).
2297 struct GNUNET_ATS_Session *result;
2303 * Look for a session by address.
2305 * @param cls the `struct GNUNET_ATS_SessionItCtx`
2307 * @param value a `struct GNUNET_ATS_Session`
2308 * @return #GNUNET_YES to continue looking, #GNUNET_NO if we found the session
2311 session_lookup_it (void *cls,
2312 const struct GNUNET_PeerIdentity *key,
2315 struct GNUNET_ATS_SessionItCtx *si_ctx = cls;
2316 struct GNUNET_ATS_Session *session = value;
2319 GNUNET_HELLO_address_cmp (si_ctx->address,
2322 si_ctx->result = session;
2328 * Task cleaning up a NAT connection attempt after timeout
2330 * @param cls the `struct GNUNET_ATS_Session`
2333 nat_connect_timeout (void *cls)
2335 struct GNUNET_ATS_Session *session = cls;
2337 session->nat_connection_timeout = NULL;
2338 LOG (GNUNET_ERROR_TYPE_DEBUG,
2339 "NAT WAIT connection to `%4s' at `%s' could not be established, removing session\n",
2340 GNUNET_i2s (&session->target),
2341 tcp_plugin_address_to_string (session->plugin,
2342 session->address->address,
2343 session->address->address_length));
2344 tcp_plugin_disconnect_session (session->plugin,
2350 * Function that will be called whenever the transport service wants to
2351 * notify the plugin that a session is still active and in use and
2352 * therefore the session timeout for this session has to be updated
2354 * @param cls closure
2355 * @param peer which peer was the session for
2356 * @param session which session is being updated
2359 tcp_plugin_update_session_timeout (void *cls,
2360 const struct GNUNET_PeerIdentity *peer,
2361 struct GNUNET_ATS_Session *session)
2363 reschedule_session_timeout (session);
2368 * Task to signal the server that we can continue
2369 * receiving from the TCP client now.
2371 * @param cls the `struct GNUNET_ATS_Session *`
2374 delayed_done (void *cls)
2376 struct GNUNET_ATS_Session *session = cls;
2378 session->receive_delay_task = NULL;
2379 reschedule_session_timeout (session);
2380 GNUNET_SERVER_receive_done (session->client,
2386 * Function that will be called whenever the transport service wants to
2387 * notify the plugin that the inbound quota changed and that the plugin
2388 * should update it's delay for the next receive value
2390 * @param cls closure
2391 * @param peer which peer was the session for
2392 * @param session which session is being updated
2393 * @param delay new delay to use for receiving
2396 tcp_plugin_update_inbound_delay (void *cls,
2397 const struct GNUNET_PeerIdentity *peer,
2398 struct GNUNET_ATS_Session *session,
2399 struct GNUNET_TIME_Relative delay)
2401 if (NULL == session->receive_delay_task)
2403 LOG (GNUNET_ERROR_TYPE_DEBUG,
2404 "New inbound delay %s\n",
2405 GNUNET_STRINGS_relative_time_to_string (delay,
2407 session->receive_delay = GNUNET_TIME_relative_to_absolute (delay);
2408 GNUNET_SCHEDULER_cancel (session->receive_delay_task);
2409 session->receive_delay_task = GNUNET_SCHEDULER_add_delayed (delay,
2416 * Create a new session to transmit data to the target
2417 * This session will used to send data to this peer and the plugin will
2418 * notify us by calling the env->session_end function
2420 * @param cls closure
2421 * @param address the address to use
2422 * @return the session if the address is valid, NULL otherwise
2424 static struct GNUNET_ATS_Session *
2425 tcp_plugin_get_session (void *cls,
2426 const struct GNUNET_HELLO_Address *address)
2428 struct Plugin *plugin = cls;
2429 struct GNUNET_ATS_Session *session = NULL;
2433 struct GNUNET_CONNECTION_Handle *sa;
2434 struct sockaddr_in a4;
2435 struct sockaddr_in6 a6;
2436 const struct IPv4TcpAddress *t4;
2437 const struct IPv6TcpAddress *t6;
2438 unsigned int options;
2439 enum GNUNET_ATS_Network_Type net_type;
2440 unsigned int is_natd = GNUNET_NO;
2443 struct GNUNET_NETWORK_Handle *s;
2446 addrlen = address->address_length;
2447 LOG (GNUNET_ERROR_TYPE_DEBUG,
2448 "Trying to get session for `%s' address of peer `%s'\n",
2449 tcp_plugin_address_to_string (plugin,
2451 address->address_length),
2452 GNUNET_i2s (&address->peer));
2454 if (GNUNET_HELLO_address_check_option (address,
2455 GNUNET_HELLO_ADDRESS_INFO_INBOUND))
2461 /* look for existing session */
2463 GNUNET_CONTAINER_multipeermap_contains (plugin->sessionmap,
2466 struct GNUNET_ATS_SessionItCtx si_ctx;
2468 si_ctx.address = address;
2469 si_ctx.result = NULL;
2470 GNUNET_CONTAINER_multipeermap_get_multiple (plugin->sessionmap,
2474 if (NULL != si_ctx.result)
2476 session = si_ctx.result;
2477 LOG (GNUNET_ERROR_TYPE_DEBUG,
2478 "Found existing session for `%s' address `%s'\n",
2479 GNUNET_i2s (&address->peer),
2480 tcp_plugin_address_to_string (plugin,
2482 address->address_length));
2485 /* This is a bit of a hack, limiting TCP to never allow more than
2486 one TCP connection to any given peer at the same time.
2487 Without this, peers sometimes disagree about which of the TCP
2488 connections they should use, causing one side to believe that
2489 they transmit successfully, while the other receives nothing. */
2490 return NULL; /* Refuse to have more than one TCP connection per
2491 peer pair at the same time. */
2494 if (addrlen == sizeof(struct IPv6TcpAddress))
2496 GNUNET_assert (NULL != address->address); /* make static analysis happy */
2497 t6 = address->address;
2498 options = t6->options;
2500 memset (&a6, 0, sizeof(a6));
2501 #if HAVE_SOCKADDR_IN_SIN_LEN
2502 a6.sin6_len = sizeof (a6);
2504 a6.sin6_family = AF_INET6;
2505 a6.sin6_port = t6->t6_port;
2506 if (t6->t6_port == 0)
2507 is_natd = GNUNET_YES;
2508 GNUNET_memcpy (&a6.sin6_addr, &t6->ipv6_addr, sizeof(struct in6_addr));
2512 else if (addrlen == sizeof(struct IPv4TcpAddress))
2514 GNUNET_assert(NULL != address->address); /* make static analysis happy */
2515 t4 = address->address;
2516 options = t4->options;
2518 memset (&a4, 0, sizeof(a4));
2519 #if HAVE_SOCKADDR_IN_SIN_LEN
2520 a4.sin_len = sizeof (a4);
2522 a4.sin_family = AF_INET;
2523 a4.sin_port = t4->t4_port;
2524 if (t4->t4_port == 0)
2525 is_natd = GNUNET_YES;
2526 a4.sin_addr.s_addr = t4->ipv4_addr;
2532 GNUNET_STATISTICS_update (plugin->env->stats,
2533 gettext_noop ("# requests to create session with invalid address"),
2539 net_type = plugin->env->get_address_type (plugin->env->cls,
2542 GNUNET_break (net_type != GNUNET_ATS_NET_UNSPECIFIED);
2544 if ( (is_natd == GNUNET_YES) &&
2545 (addrlen == sizeof(struct IPv6TcpAddress)) )
2547 /* NAT client only works with IPv4 addresses */
2551 if (plugin->cur_connections >= plugin->max_connections)
2557 if ( (is_natd == GNUNET_YES) &&
2559 GNUNET_CONTAINER_multipeermap_contains (plugin->nat_wait_conns,
2562 /* Only do one NAT punch attempt per peer identity */
2566 if ( (is_natd == GNUNET_YES) &&
2567 (NULL != plugin->nat) &&
2569 GNUNET_CONTAINER_multipeermap_contains (plugin->nat_wait_conns,
2572 struct sockaddr_in local_sa;
2574 LOG (GNUNET_ERROR_TYPE_DEBUG,
2575 "Found valid IPv4 NAT address (creating session)!\n");
2576 session = create_session (plugin,
2581 session->nat_connection_timeout = GNUNET_SCHEDULER_add_delayed (NAT_TIMEOUT,
2582 &nat_connect_timeout,
2584 GNUNET_assert (GNUNET_OK ==
2585 GNUNET_CONTAINER_multipeermap_put (plugin->nat_wait_conns,
2588 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
2590 LOG (GNUNET_ERROR_TYPE_DEBUG,
2591 "Created NAT WAIT connection to `%s' at `%s'\n",
2592 GNUNET_i2s (&session->target),
2593 GNUNET_a2s (sb, sbs));
2597 local_sa.sin_family = AF_INET;
2598 local_sa.sin_port = htons (plugin->open_port);
2599 /* We leave sin_address at 0, let the kernel figure it out,
2600 even if our bind() is more specific. (May want to reconsider
2603 GNUNET_NAT_request_reversal (plugin->nat,
2607 LOG (GNUNET_ERROR_TYPE_DEBUG,
2608 "Running NAT client for `%s' at `%s' failed\n",
2609 GNUNET_i2s (&session->target),
2610 GNUNET_a2s (sb, sbs));
2611 tcp_plugin_disconnect_session (plugin,
2616 /* create new outbound session */
2617 if (0 != (options & TCP_OPTIONS_TCP_STEALTH))
2620 s = GNUNET_NETWORK_socket_create (af, SOCK_STREAM, 0);
2623 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK,
2630 GNUNET_NETWORK_socket_setsockopt (s,
2634 sizeof (struct GNUNET_PeerIdentity))) ||
2636 GNUNET_NETWORK_socket_setsockopt (s,
2638 TCP_STEALTH_INTEGRITY,
2639 &plugin->my_welcome,
2640 sizeof (struct WelcomeMessage))) )
2642 /* TCP STEALTH not supported by kernel */
2643 GNUNET_break (GNUNET_OK ==
2644 GNUNET_NETWORK_socket_close (s));
2649 sa = GNUNET_CONNECTION_connect_socket (s, sb, sbs);
2658 sa = GNUNET_CONNECTION_create_from_sockaddr (af, sb, sbs);
2662 LOG (GNUNET_ERROR_TYPE_DEBUG,
2663 "Failed to create connection to `%s' at `%s'\n",
2664 GNUNET_i2s (&address->peer),
2665 GNUNET_a2s (sb, sbs));
2668 LOG (GNUNET_ERROR_TYPE_DEBUG,
2669 "Asked to transmit to `%s', creating fresh session using address `%s'.\n",
2670 GNUNET_i2s (&address->peer),
2671 GNUNET_a2s (sb, sbs));
2673 session = create_session (plugin,
2676 GNUNET_SERVER_connect_socket (plugin->server,
2679 (void) GNUNET_CONTAINER_multipeermap_put (plugin->sessionmap,
2682 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
2683 /* Send TCP Welcome */
2684 process_pending_messages (session);
2691 * We have been asked to destroy all connections to a particular peer.
2692 * This function is called on each applicable session and must tear it
2695 * @param cls the `struct Plugin *`
2696 * @param key the peer which the session belongs to (unused)
2697 * @param value the `struct GNUNET_ATS_Session`
2698 * @return #GNUNET_YES (continue to iterate)
2701 session_disconnect_it (void *cls,
2702 const struct GNUNET_PeerIdentity *key,
2705 struct Plugin *plugin = cls;
2706 struct GNUNET_ATS_Session *session = value;
2708 GNUNET_STATISTICS_update (session->plugin->env->stats,
2709 gettext_noop ("# transport-service disconnect requests for TCP"),
2712 tcp_plugin_disconnect_session (plugin,
2719 * Function that can be called to force a disconnect from the
2720 * specified neighbour. This should also cancel all previously
2721 * scheduled transmissions. Obviously the transmission may have been
2722 * partially completed already, which is OK. The plugin is supposed
2723 * to close the connection (if applicable) and no longer call the
2724 * transmit continuation(s).
2726 * Finally, plugin MUST NOT call the services's receive function to
2727 * notify the service that the connection to the specified target was
2728 * closed after a getting this call.
2730 * @param cls closure
2731 * @param target peer for which the last transmission is
2735 tcp_plugin_disconnect (void *cls,
2736 const struct GNUNET_PeerIdentity *target)
2738 struct Plugin *plugin = cls;
2740 LOG (GNUNET_ERROR_TYPE_DEBUG,
2741 "Disconnecting peer `%s'\n",
2742 GNUNET_i2s (target));
2743 GNUNET_CONTAINER_multipeermap_get_multiple (plugin->sessionmap,
2745 &session_disconnect_it,
2747 GNUNET_CONTAINER_multipeermap_get_multiple (plugin->nat_wait_conns,
2749 &session_disconnect_it,
2755 * We are processing an address pretty printing request and finished
2756 * the IP resolution (if applicable). Append our port and forward the
2757 * result. If called with @a hostname NULL, we are done and should
2758 * clean up the pretty printer (otherwise, there might be multiple
2759 * hostnames for the IP address and we might receive more).
2761 * @param cls the `struct PrettyPrinterContext *`
2762 * @param hostname hostname part of the address
2765 append_port (void *cls,
2766 const char *hostname)
2768 struct PrettyPrinterContext *ppc = cls;
2769 struct Plugin *plugin = ppc->plugin;
2772 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2773 "append_port called with hostname `%s'\n",
2775 if (NULL == hostname)
2777 /* Final call, done */
2778 ppc->resolver_handle = NULL;
2779 GNUNET_CONTAINER_DLL_remove (plugin->ppc_dll_head,
2780 plugin->ppc_dll_tail,
2782 ppc->asc (ppc->asc_cls,
2788 if (GNUNET_YES == ppc->ipv6)
2789 GNUNET_asprintf (&ret,
2796 GNUNET_asprintf (&ret,
2802 ppc->asc (ppc->asc_cls,
2810 * Convert the transports address to a nice, human-readable format.
2812 * @param cls closure with the `struct Plugin`
2813 * @param type name of the transport that generated the address
2814 * @param addr one of the addresses of the host, NULL for the last address
2815 * the specific address format depends on the transport
2816 * @param addrlen length of the @a addr
2817 * @param numeric should (IP) addresses be displayed in numeric form?
2818 * @param timeout after how long should we give up?
2819 * @param asc function to call on each string
2820 * @param asc_cls closure for @a asc
2823 tcp_plugin_address_pretty_printer (void *cls,
2828 struct GNUNET_TIME_Relative timeout,
2829 GNUNET_TRANSPORT_AddressStringCallback asc,
2832 struct Plugin *plugin = cls;
2833 struct PrettyPrinterContext *ppc;
2836 struct sockaddr_in a4;
2837 struct sockaddr_in6 a6;
2838 const struct IPv4TcpAddress *t4;
2839 const struct IPv6TcpAddress *t6;
2843 if (sizeof(struct IPv6TcpAddress) == addrlen)
2846 memset (&a6, 0, sizeof(a6));
2847 a6.sin6_family = AF_INET6;
2848 a6.sin6_port = t6->t6_port;
2849 GNUNET_memcpy (&a6.sin6_addr, &t6->ipv6_addr, sizeof(struct in6_addr));
2850 port = ntohs (t6->t6_port);
2851 options = ntohl (t6->options);
2855 else if (sizeof(struct IPv4TcpAddress) == addrlen)
2858 memset (&a4, 0, sizeof(a4));
2859 a4.sin_family = AF_INET;
2860 a4.sin_port = t4->t4_port;
2861 a4.sin_addr.s_addr = t4->ipv4_addr;
2862 port = ntohs (t4->t4_port);
2863 options = ntohl (t4->options);
2869 /* invalid address */
2870 LOG (GNUNET_ERROR_TYPE_WARNING,
2871 _("Unexpected address length: %u bytes\n"),
2872 (unsigned int) addrlen);
2873 asc (asc_cls, NULL, GNUNET_SYSERR);
2874 asc (asc_cls, NULL, GNUNET_OK);
2877 ppc = GNUNET_new (struct PrettyPrinterContext);
2878 ppc->plugin = plugin;
2879 if (addrlen == sizeof(struct IPv6TcpAddress))
2880 ppc->ipv6 = GNUNET_YES;
2882 ppc->ipv6 = GNUNET_NO;
2884 ppc->asc_cls = asc_cls;
2886 ppc->options = options;
2887 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2888 "Starting DNS reverse lookup\n");
2889 ppc->resolver_handle = GNUNET_RESOLVER_hostname_get (sb,
2895 if (NULL == ppc->resolver_handle)
2901 GNUNET_CONTAINER_DLL_insert (plugin->ppc_dll_head,
2902 plugin->ppc_dll_tail,
2908 * Function that will be called to check if a binary address for this
2909 * plugin is well-formed and corresponds to an address for THIS peer
2910 * (as per our configuration). Naturally, if absolutely necessary,
2911 * plugins can be a bit conservative in their answer, but in general
2912 * plugins should make sure that the address does not redirect
2913 * traffic to a 3rd party that might try to man-in-the-middle our
2916 * @param cls closure, our `struct Plugin *`
2917 * @param addr pointer to the address
2918 * @param addrlen length of @a addr
2919 * @return #GNUNET_OK if this is a plausible address for this peer
2920 * and transport, #GNUNET_SYSERR if not
2923 tcp_plugin_check_address (void *cls,
2927 struct Plugin *plugin = cls;
2928 const struct IPv4TcpAddress *v4;
2929 const struct IPv6TcpAddress *v6;
2931 if ( (addrlen != sizeof(struct IPv4TcpAddress)) &&
2932 (addrlen != sizeof(struct IPv6TcpAddress)) )
2934 GNUNET_break_op (0);
2935 return GNUNET_SYSERR;
2938 if (addrlen == sizeof(struct IPv4TcpAddress))
2940 struct sockaddr_in s4;
2942 v4 = (const struct IPv4TcpAddress *) addr;
2943 if (0 != memcmp (&v4->options,
2948 return GNUNET_SYSERR;
2950 memset (&s4, 0, sizeof (s4));
2951 s4.sin_family = AF_INET;
2952 #if HAVE_SOCKADDR_IN_SIN_LEN
2953 s4.sin_len = sizeof (s4);
2955 s4.sin_port = v4->t4_port;
2956 s4.sin_addr.s_addr = v4->ipv4_addr;
2959 GNUNET_NAT_test_address (plugin->nat,
2961 sizeof (struct sockaddr_in)))
2962 return GNUNET_SYSERR;
2966 struct sockaddr_in6 s6;
2968 v6 = (const struct IPv6TcpAddress *) addr;
2969 if (IN6_IS_ADDR_LINKLOCAL (&v6->ipv6_addr))
2971 GNUNET_break_op (0);
2972 return GNUNET_SYSERR;
2974 if (0 != memcmp (&v6->options,
2979 return GNUNET_SYSERR;
2981 memset (&s6, 0, sizeof (s6));
2982 s6.sin6_family = AF_INET6;
2983 #if HAVE_SOCKADDR_IN_SIN_LEN
2984 s6.sin6_len = sizeof (s6);
2986 s6.sin6_port = v6->t6_port;
2987 s6.sin6_addr = v6->ipv6_addr;
2990 GNUNET_NAT_test_address (plugin->nat,
2992 sizeof(struct sockaddr_in6)))
2993 return GNUNET_SYSERR;
3000 * We've received a nat probe from this peer via TCP. Finish
3001 * creating the client session and resume sending of queued
3004 * @param cls closure
3005 * @param client identification of the client
3006 * @param message the actual message
3009 handle_tcp_nat_probe (void *cls,
3010 struct GNUNET_SERVER_Client *client,
3011 const struct GNUNET_MessageHeader *message)
3013 struct Plugin *plugin = cls;
3014 struct GNUNET_ATS_Session *session;
3015 const struct TCP_NAT_ProbeMessage *tcp_nat_probe;
3018 struct IPv4TcpAddress *t4;
3019 struct IPv6TcpAddress *t6;
3020 const struct sockaddr_in *s4;
3021 const struct sockaddr_in6 *s6;
3023 LOG (GNUNET_ERROR_TYPE_DEBUG,
3024 "Received NAT probe\n");
3025 /* We have received a TCP NAT probe, meaning we (hopefully) initiated
3026 * a connection to this peer by running gnunet-nat-client. This peer
3027 * received the punch message and now wants us to use the new connection
3028 * as the default for that peer. Do so and then send a WELCOME message
3029 * so we can really be connected!
3031 if (ntohs (message->size) != sizeof(struct TCP_NAT_ProbeMessage))
3034 GNUNET_SERVER_receive_done (client,
3039 tcp_nat_probe = (const struct TCP_NAT_ProbeMessage *) message;
3040 if (0 == memcmp (&tcp_nat_probe->clientIdentity, plugin->env->my_identity,
3041 sizeof(struct GNUNET_PeerIdentity)))
3043 /* refuse connections from ourselves */
3044 GNUNET_SERVER_receive_done (client,
3049 session = GNUNET_CONTAINER_multipeermap_get (plugin->nat_wait_conns,
3050 &tcp_nat_probe->clientIdentity);
3051 if (NULL == session)
3053 LOG (GNUNET_ERROR_TYPE_DEBUG,
3054 "Did NOT find session for NAT probe!\n");
3055 GNUNET_SERVER_receive_done (client,
3059 LOG (GNUNET_ERROR_TYPE_DEBUG,
3060 "Found session for NAT probe!\n");
3062 if (NULL != session->nat_connection_timeout)
3064 GNUNET_SCHEDULER_cancel (session->nat_connection_timeout);
3065 session->nat_connection_timeout = NULL;
3069 GNUNET_SERVER_client_get_address (client,
3074 GNUNET_SERVER_receive_done (client,
3076 tcp_plugin_disconnect_session (plugin,
3080 GNUNET_assert (GNUNET_YES ==
3081 GNUNET_CONTAINER_multipeermap_remove (plugin->nat_wait_conns,
3082 &tcp_nat_probe->clientIdentity,
3084 GNUNET_SERVER_client_set_user_context (client,
3086 (void) GNUNET_CONTAINER_multipeermap_put (plugin->sessionmap,
3089 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
3090 session->last_activity = GNUNET_TIME_absolute_get ();
3091 LOG (GNUNET_ERROR_TYPE_DEBUG,
3092 "Found address `%s' for incoming connection\n",
3093 GNUNET_a2s (vaddr, alen));
3094 switch (((const struct sockaddr *) vaddr)->sa_family)
3098 t4 = GNUNET_new (struct IPv4TcpAddress);
3099 t4->options = htonl (TCP_OPTIONS_NONE);
3100 t4->t4_port = s4->sin_port;
3101 t4->ipv4_addr = s4->sin_addr.s_addr;
3102 session->address = GNUNET_HELLO_address_allocate (&tcp_nat_probe->clientIdentity,
3105 sizeof(struct IPv4TcpAddress),
3106 GNUNET_HELLO_ADDRESS_INFO_NONE);
3110 t6 = GNUNET_new (struct IPv6TcpAddress);
3111 t6->options = htonl (TCP_OPTIONS_NONE);
3112 t6->t6_port = s6->sin6_port;
3113 GNUNET_memcpy (&t6->ipv6_addr, &s6->sin6_addr, sizeof(struct in6_addr));
3114 session->address = GNUNET_HELLO_address_allocate (&tcp_nat_probe->clientIdentity,
3117 sizeof(struct IPv6TcpAddress),
3118 GNUNET_HELLO_ADDRESS_INFO_NONE);
3122 LOG(GNUNET_ERROR_TYPE_DEBUG,
3123 "Bad address for incoming connection!\n");
3125 GNUNET_SERVER_receive_done (client,
3127 tcp_plugin_disconnect_session (plugin,
3131 GNUNET_free (vaddr);
3132 GNUNET_break (NULL == session->client);
3133 session->client = client;
3134 GNUNET_STATISTICS_update (plugin->env->stats,
3135 gettext_noop ("# TCP sessions active"),
3138 process_pending_messages (session);
3139 GNUNET_SERVER_receive_done (client,
3145 * We've received a welcome from this peer via TCP. Possibly create a
3146 * fresh client record and send back our welcome.
3148 * @param cls closure
3149 * @param client identification of the client
3150 * @param message the actual message
3153 handle_tcp_welcome (void *cls,
3154 struct GNUNET_SERVER_Client *client,
3155 const struct GNUNET_MessageHeader *message)
3157 struct Plugin *plugin = cls;
3158 const struct WelcomeMessage *wm = (const struct WelcomeMessage *) message;
3159 struct GNUNET_HELLO_Address *address;
3160 struct GNUNET_ATS_Session *session;
3163 struct IPv4TcpAddress t4;
3164 struct IPv6TcpAddress t6;
3165 const struct sockaddr_in *s4;
3166 const struct sockaddr_in6 *s6;
3168 if (0 == memcmp (&wm->clientIdentity,
3169 plugin->env->my_identity,
3170 sizeof(struct GNUNET_PeerIdentity)))
3172 /* refuse connections from ourselves */
3174 GNUNET_SERVER_client_get_address (client,
3178 LOG (GNUNET_ERROR_TYPE_INFO,
3179 "Received WELCOME message from my own identity `%s' on address `%s'\n",
3180 GNUNET_i2s (&wm->clientIdentity),
3181 GNUNET_a2s (vaddr, alen));
3182 GNUNET_free (vaddr);
3184 GNUNET_SERVER_receive_done (client,
3190 GNUNET_SERVER_client_get_address (client,
3194 LOG(GNUNET_ERROR_TYPE_DEBUG,
3195 "Received WELCOME message from `%s' on address `%s'\n",
3196 GNUNET_i2s (&wm->clientIdentity),
3197 GNUNET_a2s (vaddr, alen));
3198 GNUNET_free (vaddr);
3200 GNUNET_STATISTICS_update (plugin->env->stats,
3201 gettext_noop ("# TCP WELCOME messages received"),
3204 session = lookup_session_by_client (plugin,
3206 if (NULL != session)
3209 GNUNET_SERVER_client_get_address (client,
3213 LOG (GNUNET_ERROR_TYPE_DEBUG,
3214 "Found existing session %p for peer `%s'\n",
3216 GNUNET_a2s (vaddr, alen));
3217 GNUNET_free (vaddr);
3223 GNUNET_SERVER_client_get_address (client, &vaddr, &alen))
3225 if (alen == sizeof(struct sockaddr_in))
3228 memset (&t4, '\0', sizeof (t4));
3229 t4.options = htonl (TCP_OPTIONS_NONE);
3230 t4.t4_port = s4->sin_port;
3231 t4.ipv4_addr = s4->sin_addr.s_addr;
3232 address = GNUNET_HELLO_address_allocate (&wm->clientIdentity,
3236 GNUNET_HELLO_ADDRESS_INFO_INBOUND);
3238 else if (alen == sizeof(struct sockaddr_in6))
3241 memset (&t6, '\0', sizeof (t6));
3242 t6.options = htonl (TCP_OPTIONS_NONE);
3243 t6.t6_port = s6->sin6_port;
3244 GNUNET_memcpy (&t6.ipv6_addr, &s6->sin6_addr, sizeof(struct in6_addr));
3245 address = GNUNET_HELLO_address_allocate (&wm->clientIdentity,
3249 GNUNET_HELLO_ADDRESS_INFO_INBOUND);
3254 GNUNET_free_non_null (vaddr);
3255 GNUNET_SERVER_receive_done (client,
3259 session = create_session (plugin,
3261 plugin->env->get_address_type (plugin->env->cls,
3266 GNUNET_break (GNUNET_ATS_NET_UNSPECIFIED != session->scope);
3267 GNUNET_HELLO_address_free (address);
3268 LOG (GNUNET_ERROR_TYPE_DEBUG,
3269 "Creating new%s session %p for peer `%s' client %p\n",
3270 GNUNET_HELLO_address_check_option (session->address,
3271 GNUNET_HELLO_ADDRESS_INFO_INBOUND)
3274 tcp_plugin_address_to_string (plugin,
3275 session->address->address,
3276 session->address->address_length),
3278 GNUNET_free (vaddr);
3279 (void) GNUNET_CONTAINER_multipeermap_put (plugin->sessionmap,
3282 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
3283 /* Notify transport and ATS about new session */
3284 plugin->env->session_start (plugin->env->cls,
3291 LOG(GNUNET_ERROR_TYPE_DEBUG,
3292 "Did not obtain TCP socket address for incoming connection\n");
3294 GNUNET_SERVER_receive_done (client,
3300 if (GNUNET_YES != session->expecting_welcome)
3302 GNUNET_break_op (0);
3303 GNUNET_SERVER_receive_done (client,
3307 session->last_activity = GNUNET_TIME_absolute_get ();
3308 session->expecting_welcome = GNUNET_NO;
3310 process_pending_messages (session);
3311 GNUNET_SERVER_client_set_timeout (client,
3312 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
3313 GNUNET_SERVER_receive_done (client,
3319 * We've received data for this peer via TCP. Unbox,
3320 * compute latency and forward.
3322 * @param cls closure
3323 * @param client identification of the client
3324 * @param message the actual message
3327 handle_tcp_data (void *cls,
3328 struct GNUNET_SERVER_Client *client,
3329 const struct GNUNET_MessageHeader *message)
3331 struct Plugin *plugin = cls;
3332 struct GNUNET_ATS_Session *session;
3333 struct GNUNET_TIME_Relative delay;
3336 type = ntohs (message->type);
3337 if ( (GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_WELCOME == type) ||
3338 (GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_NAT_PROBE == type) )
3340 /* We don't want to propagate WELCOME and NAT Probe messages up! */
3341 GNUNET_SERVER_receive_done (client,
3345 session = lookup_session_by_client (plugin, client);
3346 if (NULL == session)
3348 /* No inbound session found */
3352 GNUNET_assert (GNUNET_OK ==
3353 GNUNET_SERVER_client_get_address (client,
3356 LOG (GNUNET_ERROR_TYPE_ERROR,
3357 "Received unexpected %u bytes of type %u from `%s'\n",
3358 (unsigned int) ntohs (message->size),
3359 (unsigned int) ntohs (message->type),
3363 GNUNET_SERVER_receive_done (client,
3365 GNUNET_free_non_null (vaddr);
3368 if (GNUNET_YES == session->expecting_welcome)
3370 /* Session is expecting WELCOME message */
3374 GNUNET_SERVER_client_get_address (client,
3377 LOG (GNUNET_ERROR_TYPE_ERROR,
3378 "Received unexpected %u bytes of type %u from `%s'\n",
3379 (unsigned int) ntohs (message->size),
3380 (unsigned int) ntohs (message->type),
3381 GNUNET_a2s (vaddr, alen));
3383 GNUNET_SERVER_receive_done (client,
3385 GNUNET_free_non_null (vaddr);
3389 session->last_activity = GNUNET_TIME_absolute_get ();
3394 GNUNET_SERVER_client_get_address (client,
3397 LOG (GNUNET_ERROR_TYPE_DEBUG,
3398 "Passing %u bytes of type %u from `%s' at %s to transport service.\n",
3399 (unsigned int) ntohs (message->size),
3400 (unsigned int) ntohs (message->type),
3401 GNUNET_i2s (&session->target),
3402 GNUNET_a2s (vaddr, alen));
3403 GNUNET_free_non_null (vaddr);
3406 GNUNET_STATISTICS_update (plugin->env->stats,
3407 gettext_noop ("# bytes received via TCP"),
3408 ntohs (message->size),
3411 GNUNET_assert (GNUNET_CONTAINER_multipeermap_contains_value (plugin->sessionmap,
3414 delay = plugin->env->receive (plugin->env->cls,
3418 reschedule_session_timeout (session);
3419 if (0 == delay.rel_value_us)
3421 GNUNET_SERVER_receive_done (client,
3426 LOG (GNUNET_ERROR_TYPE_DEBUG,
3427 "Throttling receiving from `%s' for %s\n",
3428 GNUNET_i2s (&session->target),
3429 GNUNET_STRINGS_relative_time_to_string (delay,
3431 GNUNET_SERVER_disable_receive_done_warning (client);
3432 GNUNET_assert (NULL == session->receive_delay_task);
3433 session->receive_delay_task = GNUNET_SCHEDULER_add_delayed (delay,
3441 * Function called whenever a peer is connected on the "SERVER" level.
3442 * Increments number of active connections and suspends server if we
3443 * have reached the limit.
3445 * @param cls closure
3446 * @param client identification of the client
3449 connect_notify (void *cls,
3450 struct GNUNET_SERVER_Client *client)
3452 struct Plugin *plugin = cls;
3456 plugin->cur_connections++;
3457 GNUNET_STATISTICS_set (plugin->env->stats,
3458 gettext_noop ("# TCP server connections active"),
3459 plugin->cur_connections,
3461 GNUNET_STATISTICS_update (plugin->env->stats,
3462 gettext_noop ("# TCP server connect events"),
3465 if (plugin->cur_connections != plugin->max_connections)
3467 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3468 _("TCP connection limit reached, suspending server\n"));
3469 GNUNET_STATISTICS_update (plugin->env->stats,
3470 gettext_noop ("# TCP service suspended"),
3473 GNUNET_SERVER_suspend (plugin->server); /* Maximum number of connections rechead */
3478 * Function called whenever a peer is disconnected on the "SERVER"
3479 * level. Cleans up the connection, decrements number of active
3480 * connections and if applicable resumes listening.
3482 * @param cls closure
3483 * @param client identification of the client
3486 disconnect_notify (void *cls,
3487 struct GNUNET_SERVER_Client *client)
3489 struct Plugin *plugin = cls;
3490 struct GNUNET_ATS_Session *session;
3494 GNUNET_assert (plugin->cur_connections >= 1);
3495 plugin->cur_connections--;
3496 session = lookup_session_by_client (plugin,
3498 if (NULL == session)
3499 return; /* unknown, nothing to do */
3500 LOG (GNUNET_ERROR_TYPE_DEBUG,
3501 "Destroying session of `%s' with %s due to network-level disconnect.\n",
3502 GNUNET_i2s (&session->target),
3503 tcp_plugin_address_to_string (session->plugin,
3504 session->address->address,
3505 session->address->address_length));
3507 if (plugin->cur_connections == plugin->max_connections)
3509 GNUNET_STATISTICS_update (session->plugin->env->stats,
3510 gettext_noop ("# TCP service resumed"),
3513 GNUNET_SERVER_resume (plugin->server); /* Resume server */
3515 GNUNET_STATISTICS_set (plugin->env->stats,
3516 gettext_noop ("# TCP server connections active"),
3517 plugin->cur_connections,
3519 GNUNET_STATISTICS_update (session->plugin->env->stats,
3520 gettext_noop ("# network-level TCP disconnect events"),
3523 tcp_plugin_disconnect_session (plugin,
3529 * We can now send a probe message, copy into buffer to really send.
3531 * @param cls closure, a `struct TCPProbeContext`
3532 * @param size max size to copy
3533 * @param buf buffer to copy message to
3534 * @return number of bytes copied into @a buf
3537 notify_send_probe (void *cls,
3541 struct TCPProbeContext *tcp_probe_ctx = cls;
3542 struct Plugin *plugin = tcp_probe_ctx->plugin;
3545 tcp_probe_ctx->transmit_handle = NULL;
3546 GNUNET_CONTAINER_DLL_remove (plugin->probe_head,
3551 GNUNET_CONNECTION_destroy (tcp_probe_ctx->sock);
3552 GNUNET_free(tcp_probe_ctx);
3555 GNUNET_assert(size >= sizeof(tcp_probe_ctx->message));
3557 &tcp_probe_ctx->message,
3558 sizeof(tcp_probe_ctx->message));
3559 GNUNET_SERVER_connect_socket (tcp_probe_ctx->plugin->server,
3560 tcp_probe_ctx->sock);
3561 ret = sizeof(tcp_probe_ctx->message);
3562 GNUNET_free (tcp_probe_ctx);
3568 * Function called by the NAT subsystem suggesting another peer wants
3569 * to connect to us via connection reversal. Try to connect back to the
3572 * @param cls closure
3573 * @param addr address to try
3574 * @param addrlen number of bytes in @a addr
3577 try_connection_reversal (void *cls,
3578 const struct sockaddr *addr,
3581 struct Plugin *plugin = cls;
3582 struct GNUNET_CONNECTION_Handle *sock;
3583 struct TCPProbeContext *tcp_probe_ctx;
3586 * We have received an ICMP response, ostensibly from a peer
3587 * that wants to connect to us! Send a message to establish a connection.
3589 sock = GNUNET_CONNECTION_create_from_sockaddr (AF_INET,
3594 /* failed for some odd reason (out of sockets?); ignore attempt */
3598 tcp_probe_ctx = GNUNET_new (struct TCPProbeContext);
3599 tcp_probe_ctx->message.header.size
3600 = htons (sizeof (struct TCP_NAT_ProbeMessage));
3601 tcp_probe_ctx->message.header.type
3602 = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_NAT_PROBE);
3603 tcp_probe_ctx->message.clientIdentity
3604 = *plugin->env->my_identity;
3605 tcp_probe_ctx->plugin = plugin;
3606 tcp_probe_ctx->sock = sock;
3607 GNUNET_CONTAINER_DLL_insert (plugin->probe_head,
3610 tcp_probe_ctx->transmit_handle
3611 = GNUNET_CONNECTION_notify_transmit_ready (sock,
3612 ntohs (tcp_probe_ctx->message.header.size),
3613 GNUNET_TIME_UNIT_FOREVER_REL,
3620 * Function obtain the network type for a session
3622 * @param cls closure (`struct Plugin *`)
3623 * @param session the session
3624 * @return the network type in HBO or #GNUNET_SYSERR
3626 static enum GNUNET_ATS_Network_Type
3627 tcp_plugin_get_network (void *cls,
3628 struct GNUNET_ATS_Session *session)
3630 return session->scope;
3635 * Function obtain the network type for an address.
3637 * @param cls closure (`struct Plugin *`)
3638 * @param address the address
3639 * @return the network type
3641 static enum GNUNET_ATS_Network_Type
3642 tcp_plugin_get_network_for_address (void *cls,
3643 const struct GNUNET_HELLO_Address *address)
3645 struct Plugin *plugin = cls;
3647 struct sockaddr_in a4;
3648 struct sockaddr_in6 a6;
3649 const struct IPv4TcpAddress *t4;
3650 const struct IPv6TcpAddress *t6;
3654 addrlen = address->address_length;
3655 if (addrlen == sizeof(struct IPv6TcpAddress))
3657 GNUNET_assert (NULL != address->address); /* make static analysis happy */
3658 t6 = address->address;
3659 memset (&a6, 0, sizeof(a6));
3660 #if HAVE_SOCKADDR_IN_SIN_LEN
3661 a6.sin6_len = sizeof (a6);
3663 a6.sin6_family = AF_INET6;
3664 a6.sin6_port = t6->t6_port;
3665 GNUNET_memcpy (&a6.sin6_addr, &t6->ipv6_addr, sizeof(struct in6_addr));
3669 else if (addrlen == sizeof(struct IPv4TcpAddress))
3671 GNUNET_assert (NULL != address->address); /* make static analysis happy */
3672 t4 = address->address;
3673 memset (&a4, 0, sizeof(a4));
3674 #if HAVE_SOCKADDR_IN_SIN_LEN
3675 a4.sin_len = sizeof (a4);
3677 a4.sin_family = AF_INET;
3678 a4.sin_port = t4->t4_port;
3679 a4.sin_addr.s_addr = t4->ipv4_addr;
3686 return GNUNET_ATS_NET_UNSPECIFIED;
3688 return plugin->env->get_address_type (plugin->env->cls,
3695 * Return information about the given session to the
3698 * @param cls the `struct Plugin` with the monitor callback (`sic`)
3699 * @param peer peer we send information about
3700 * @param value our `struct GNUNET_ATS_Session` to send information about
3701 * @return #GNUNET_OK (continue to iterate)
3704 send_session_info_iter (void *cls,
3705 const struct GNUNET_PeerIdentity *peer,
3708 struct Plugin *plugin = cls;
3709 struct GNUNET_ATS_Session *session = value;
3711 notify_session_monitor (plugin,
3713 GNUNET_TRANSPORT_SS_INIT);
3714 /* FIXME: cannot tell if this is up or not from current
3716 notify_session_monitor (plugin,
3718 GNUNET_TRANSPORT_SS_UP);
3724 * Begin monitoring sessions of a plugin. There can only
3725 * be one active monitor per plugin (i.e. if there are
3726 * multiple monitors, the transport service needs to
3727 * multiplex the generated events over all of them).
3729 * @param cls closure of the plugin
3730 * @param sic callback to invoke, NULL to disable monitor;
3731 * plugin will being by iterating over all active
3732 * sessions immediately and then enter monitor mode
3733 * @param sic_cls closure for @a sic
3736 tcp_plugin_setup_monitor (void *cls,
3737 GNUNET_TRANSPORT_SessionInfoCallback sic,
3740 struct Plugin *plugin = cls;
3743 plugin->sic_cls = sic_cls;
3746 GNUNET_CONTAINER_multipeermap_iterate (plugin->sessionmap,
3747 &send_session_info_iter,
3749 /* signal end of first iteration */
3750 sic (sic_cls, NULL, NULL);
3756 * Entry point for the plugin.
3758 * @param cls closure, the `struct GNUNET_TRANSPORT_PluginEnvironment *`
3759 * @return the `struct GNUNET_TRANSPORT_PluginFunctions *` or NULL on error
3762 libgnunet_plugin_transport_tcp_init (void *cls)
3764 static const struct GNUNET_SERVER_MessageHandler my_handlers[] = {
3765 { &handle_tcp_welcome, NULL,
3766 GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_WELCOME,
3767 sizeof(struct WelcomeMessage) },
3768 { &handle_tcp_nat_probe, NULL,
3769 GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_NAT_PROBE,
3770 sizeof(struct TCP_NAT_ProbeMessage) },
3771 { &handle_tcp_data, NULL,
3772 GNUNET_MESSAGE_TYPE_ALL, 0 },
3773 { NULL, NULL, 0, 0 }
3775 struct GNUNET_TRANSPORT_PluginEnvironment *env = cls;
3776 struct GNUNET_TRANSPORT_PluginFunctions *api;
3777 struct Plugin *plugin;
3778 struct LEGACY_SERVICE_Context *service;
3779 unsigned long long aport;
3780 unsigned long long bport;
3781 unsigned long long max_connections;
3783 struct GNUNET_TIME_Relative idle_timeout;
3785 struct GNUNET_NETWORK_Handle *const*lsocks;
3789 struct sockaddr **addrs;
3790 socklen_t *addrlens;
3792 if (NULL == env->receive)
3794 /* run in 'stub' mode (i.e. as part of gnunet-peerinfo), don't fully
3795 initialze the plugin or the API */
3796 api = GNUNET_new (struct GNUNET_TRANSPORT_PluginFunctions);
3798 api->address_pretty_printer = &tcp_plugin_address_pretty_printer;
3799 api->address_to_string = &tcp_plugin_address_to_string;
3800 api->string_to_address = &tcp_plugin_string_to_address;
3804 GNUNET_assert (NULL != env->cfg);
3806 GNUNET_CONFIGURATION_get_value_number (env->cfg,
3810 max_connections = 128;
3814 GNUNET_CONFIGURATION_get_value_number (env->cfg, "transport-tcp",
3818 GNUNET_CONFIGURATION_get_value_number (env->cfg, "transport-tcp",
3819 "ADVERTISED-PORT", &aport)) &&
3822 LOG(GNUNET_ERROR_TYPE_ERROR,
3823 _("Require valid port number for service `%s' in configuration!\n"),
3833 service = LEGACY_SERVICE_start ("transport-tcp",
3835 LEGACY_SERVICE_OPTION_NONE);
3836 if (NULL == service)
3838 LOG (GNUNET_ERROR_TYPE_WARNING,
3839 _("Failed to start service.\n"));
3847 plugin = GNUNET_new (struct Plugin);
3848 plugin->sessionmap = GNUNET_CONTAINER_multipeermap_create (max_connections,
3850 plugin->max_connections = max_connections;
3851 plugin->open_port = bport;
3852 plugin->adv_port = aport;
3854 plugin->my_welcome.header.size = htons (sizeof(struct WelcomeMessage));
3855 plugin->my_welcome.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_WELCOME);
3856 plugin->my_welcome.clientIdentity = *plugin->env->my_identity;
3858 if ( (NULL != service) &&
3860 GNUNET_CONFIGURATION_get_value_yesno (env->cfg,
3865 plugin->myoptions |= TCP_OPTIONS_TCP_STEALTH;
3866 lsocks = LEGACY_SERVICE_get_listen_sockets (service);
3869 uint32_t len = sizeof (struct WelcomeMessage);
3871 for (i=0;NULL!=lsocks[i];i++)
3874 GNUNET_NETWORK_socket_setsockopt (lsocks[i],
3878 sizeof (struct GNUNET_PeerIdentity))) ||
3880 GNUNET_NETWORK_socket_setsockopt (lsocks[i],
3882 TCP_STEALTH_INTEGRITY_LEN,
3886 /* TCP STEALTH not supported by kernel */
3887 GNUNET_assert (0 == i);
3888 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3889 _("TCP_STEALTH not supported on this platform.\n"));
3895 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3896 _("TCP_STEALTH not supported on this platform.\n"));
3901 if ( (NULL != service) &&
3904 get_server_addresses ("transport-tcp",
3909 for (ret = ret_s-1; ret >= 0; ret--)
3910 LOG (GNUNET_ERROR_TYPE_INFO,
3911 "Binding to address `%s'\n",
3912 GNUNET_a2s (addrs[ret], addrlens[ret]));
3914 = GNUNET_NAT_register (env->cfg,
3917 (unsigned int) ret_s,
3918 (const struct sockaddr **) addrs,
3920 &tcp_nat_port_map_callback,
3921 &try_connection_reversal,
3923 for (ret = ret_s -1; ret >= 0; ret--)
3924 GNUNET_free (addrs[ret]);
3925 GNUNET_free_non_null (addrs);
3926 GNUNET_free_non_null (addrlens);
3930 plugin->nat = GNUNET_NAT_register (plugin->env->cfg,
3937 &try_connection_reversal,
3940 api = GNUNET_new (struct GNUNET_TRANSPORT_PluginFunctions);
3942 api->send = &tcp_plugin_send;
3943 api->get_session = &tcp_plugin_get_session;
3944 api->disconnect_session = &tcp_plugin_disconnect_session;
3945 api->query_keepalive_factor = &tcp_plugin_query_keepalive_factor;
3946 api->disconnect_peer = &tcp_plugin_disconnect;
3947 api->address_pretty_printer = &tcp_plugin_address_pretty_printer;
3948 api->check_address = &tcp_plugin_check_address;
3949 api->address_to_string = &tcp_plugin_address_to_string;
3950 api->string_to_address = &tcp_plugin_string_to_address;
3951 api->get_network = &tcp_plugin_get_network;
3952 api->get_network_for_address = &tcp_plugin_get_network_for_address;
3953 api->update_session_timeout = &tcp_plugin_update_session_timeout;
3954 api->update_inbound_delay = &tcp_plugin_update_inbound_delay;
3955 api->setup_monitor = &tcp_plugin_setup_monitor;
3956 plugin->service = service;
3957 if (NULL != service)
3959 plugin->server = LEGACY_SERVICE_get_server (service);
3964 GNUNET_CONFIGURATION_get_value_time (env->cfg,
3969 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
3975 = GNUNET_SERVER_create_with_sockets (NULL,
3981 plugin->handlers = GNUNET_malloc (sizeof (my_handlers));
3982 GNUNET_memcpy (plugin->handlers,
3984 sizeof(my_handlers));
3985 for (i = 0;i < sizeof(my_handlers) / sizeof(struct GNUNET_SERVER_MessageHandler);i++)
3986 plugin->handlers[i].callback_cls = plugin;
3988 GNUNET_SERVER_add_handlers (plugin->server,
3990 GNUNET_SERVER_connect_notify (plugin->server,
3993 GNUNET_SERVER_disconnect_notify (plugin->server,
3996 plugin->nat_wait_conns = GNUNET_CONTAINER_multipeermap_create (16,
3999 LOG (GNUNET_ERROR_TYPE_INFO,
4000 _("TCP transport listening on port %llu\n"),
4003 LOG (GNUNET_ERROR_TYPE_INFO,
4004 _("TCP transport not listening on any port (client only)\n"));
4005 if ( (aport != bport) &&
4007 LOG (GNUNET_ERROR_TYPE_INFO,
4008 _("TCP transport advertises itself as being on port %llu\n"),
4010 /* Initially set connections to 0 */
4011 GNUNET_STATISTICS_set (plugin->env->stats,
4012 gettext_noop ("# TCP sessions active"),
4018 if (NULL != plugin->nat)
4019 GNUNET_NAT_unregister (plugin->nat);
4020 GNUNET_CONTAINER_multipeermap_destroy (plugin->sessionmap);
4021 if (NULL != service)
4022 LEGACY_SERVICE_stop (service);
4023 GNUNET_free (plugin);
4024 GNUNET_free_non_null (api);
4030 * Exit point from the plugin.
4032 * @param cls the `struct GNUNET_TRANSPORT_PluginFunctions`
4036 libgnunet_plugin_transport_tcp_done (void *cls)
4038 struct GNUNET_TRANSPORT_PluginFunctions *api = cls;
4039 struct Plugin *plugin = api->cls;
4040 struct TCPProbeContext *tcp_probe;
4041 struct PrettyPrinterContext *cur;
4042 struct PrettyPrinterContext *next;
4049 LOG (GNUNET_ERROR_TYPE_DEBUG,
4050 "Shutting down TCP plugin\n");
4052 /* Removing leftover sessions */
4053 GNUNET_CONTAINER_multipeermap_iterate (plugin->sessionmap,
4054 &session_disconnect_it,
4056 /* Removing leftover NAT sessions */
4057 GNUNET_CONTAINER_multipeermap_iterate (plugin->nat_wait_conns,
4058 &session_disconnect_it,
4061 for (cur = plugin->ppc_dll_head; NULL != cur; cur = next)
4064 GNUNET_CONTAINER_DLL_remove (plugin->ppc_dll_head,
4065 plugin->ppc_dll_tail,
4067 GNUNET_RESOLVER_request_cancel (cur->resolver_handle);
4068 cur->asc (cur->asc_cls,
4074 if (NULL != plugin->service)
4075 LEGACY_SERVICE_stop (plugin->service);
4077 GNUNET_SERVER_destroy (plugin->server);
4078 GNUNET_free (plugin->handlers);
4079 if (NULL != plugin->nat)
4080 GNUNET_NAT_unregister (plugin->nat);
4081 while (NULL != (tcp_probe = plugin->probe_head))
4083 GNUNET_CONTAINER_DLL_remove (plugin->probe_head,
4086 GNUNET_CONNECTION_destroy (tcp_probe->sock);
4087 GNUNET_free (tcp_probe);
4089 GNUNET_CONTAINER_multipeermap_destroy (plugin->nat_wait_conns);
4090 GNUNET_CONTAINER_multipeermap_destroy (plugin->sessionmap);
4091 GNUNET_break (0 == plugin->cur_connections);
4092 GNUNET_free (plugin);
4097 /* end of plugin_transport_tcp.c */