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 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.
16 * @file transport/plugin_transport_xt.c
17 * @brief Implementation of the TCP transport service
18 * @author Christian Grothoff
21 #include "gnunet_hello_lib.h"
22 #include "gnunet_constants.h"
23 #include "gnunet_util_lib.h"
24 #include "gnunet_nat_service.h"
25 #include "gnunet_protocols.h"
26 #include "gnunet_resolver_service.h"
27 #include "gnunet_signatures.h"
28 #include "gnunet_statistics_service.h"
29 #include "gnunet_transport_service.h"
30 #include "gnunet_transport_plugin.h"
31 #include "transport.h"
33 #define LOG(kind,...) GNUNET_log_from (kind, "transport-xt",__VA_ARGS__)
35 #define PLUGIN_NAME "xt"
38 * How long until we give up on establishing an NAT connection?
41 #define NAT_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10)
44 * Opaque handle that can be used to cancel
45 * a transmit-ready notification.
47 struct GNUNET_CONNECTION_TransmitHandle;
50 * @brief handle for a server
52 struct GNUNET_SERVER_Handle;
55 * @brief opaque handle for a client of the server
57 struct GNUNET_SERVER_Client;
60 * @brief opaque handle server returns for aborting transmission to a client.
62 struct GNUNET_SERVER_TransmitHandle;
65 * @brief handle for a network connection
67 struct GNUNET_CONNECTION_Handle;
70 * @brief handle for a network service
72 struct LEGACY_SERVICE_Context;
76 * Stops a service that was started with #GNUNET_SERVICE_start().
78 * @param srv service to stop
81 LEGACY_SERVICE_stop (struct LEGACY_SERVICE_Context *srv);
86 * Function called to notify a client about the connection begin ready
87 * to queue more data. @a buf will be NULL and @a size zero if the
88 * connection was closed for writing in the meantime.
91 * @param size number of bytes available in @a buf
92 * @param buf where the callee should write the message
93 * @return number of bytes written to @a buf
96 (*GNUNET_CONNECTION_TransmitReadyNotify) (void *cls,
101 * Credentials for UNIX domain sockets.
103 struct GNUNET_CONNECTION_Credentials
106 * UID of the other end of the connection.
111 * GID of the other end of the connection.
118 * Functions with this signature are called whenever a client
119 * is disconnected on the network level.
122 * @param client identification of the client; NULL
123 * for the last call when the server is destroyed
126 (*GNUNET_SERVER_DisconnectCallback) (void *cls,
127 struct GNUNET_SERVER_Client *client);
131 * Functions with this signature are called whenever a client
132 * is connected on the network level.
135 * @param client identification of the client
138 (*GNUNET_SERVER_ConnectCallback) (void *cls,
139 struct GNUNET_SERVER_Client *client);
145 * Function to call for access control checks.
148 * @param ucred credentials, if available, otherwise NULL
149 * @param addr address
150 * @param addrlen length of address
151 * @return GNUNET_YES to allow, GNUNET_NO to deny, GNUNET_SYSERR
152 * for unknown address family (will be denied).
155 (*GNUNET_CONNECTION_AccessCheck) (void *cls,
157 GNUNET_CONNECTION_Credentials *
159 const struct sockaddr * addr,
163 * Callback function for data received from the network. Note that
164 * both "available" and "err" would be 0 if the read simply timed out.
167 * @param buf pointer to received data
168 * @param available number of bytes availabe in "buf",
169 * possibly 0 (on errors)
170 * @param addr address of the sender
171 * @param addrlen size of addr
172 * @param errCode value of errno (on errors receiving)
175 (*GNUNET_CONNECTION_Receiver) (void *cls, const void *buf,
177 const struct sockaddr * addr,
178 socklen_t addrlen, int errCode);
183 * Close the connection and free associated resources. There must
184 * not be any pending requests for reading or writing to the
185 * connection at this time.
187 * @param connection connection to destroy
190 GNUNET_CONNECTION_destroy (struct GNUNET_CONNECTION_Handle *connection);
194 * Signature of a function to create a custom tokenizer.
196 * @param cls closure from #GNUNET_SERVER_set_callbacks
197 * @param client handle to client the tokenzier will be used for
198 * @return handle to custom tokenizer ('mst')
201 (*GNUNET_SERVER_MstCreateCallback) (void *cls,
202 struct GNUNET_SERVER_Client *client);
206 * Signature of a function to destroy a custom tokenizer.
208 * @param cls closure from #GNUNET_SERVER_set_callbacks
209 * @param mst custom tokenizer handle
212 (*GNUNET_SERVER_MstDestroyCallback) (void *cls,
216 * Signature of a function to receive data for a custom tokenizer.
218 * @param cls closure from #GNUNET_SERVER_set_callbacks
219 * @param mst custom tokenizer handle
220 * @param client_identity ID of client for which this is a buffer,
221 * can be NULL (will be passed back to 'cb')
222 * @param buf input data to add
223 * @param size number of bytes in @a buf
224 * @param purge should any excess bytes in the buffer be discarded
225 * (i.e. for packet-based services like UDP)
226 * @param one_shot only call callback once, keep rest of message in buffer
227 * @return #GNUNET_OK if we are done processing (need more data)
228 * #GNUNET_NO if one_shot was set and we have another message ready
229 * #GNUNET_SYSERR if the data stream is corrupt
232 (*GNUNET_SERVER_MstReceiveCallback) (void *cls, void *mst,
233 struct GNUNET_SERVER_Client *client,
239 * Functions with this signature are called whenever a message is
243 * @param client identification of the client
244 * @param message the actual message
247 (*GNUNET_SERVER_MessageCallback) (void *cls,
248 struct GNUNET_SERVER_Client *client,
249 const struct GNUNET_MessageHeader *message);
252 * Message handler. Each struct specifies how to handle on particular
253 * type of message received.
255 struct GNUNET_SERVER_MessageHandler
258 * Function to call for messages of "type".
260 GNUNET_SERVER_MessageCallback callback;
263 * Closure argument for @e callback.
268 * Type of the message this handler covers.
273 * Expected size of messages of this type. Use 0 for
274 * variable-size. If non-zero, messages of the given
275 * type will be discarded (and the connection closed)
276 * if they do not have the right size.
278 uint16_t expected_size;
284 * Options for the service (bitmask).
286 enum LEGACY_SERVICE_Options
289 * Use defaults. Terminates all client connections and the listen
290 * sockets immediately upon receiving the shutdown signal.
292 LEGACY_SERVICE_OPTION_NONE = 0,
295 * Do not trigger server shutdown on signal at all; instead, allow
296 * for the user to terminate the server explicitly when needed
297 * by calling #LEGACY_SERVICE_shutdown().
299 LEGACY_SERVICE_OPTION_MANUAL_SHUTDOWN = 1,
302 * Trigger a SOFT server shutdown on signals, allowing active
303 * non-monitor clients to complete their transactions.
305 LEGACY_SERVICE_OPTION_SOFT_SHUTDOWN = 2
311 * Ask the server to disconnect from the given client. This is the
312 * same as passing #GNUNET_SYSERR to #GNUNET_SERVER_receive_done,
313 * except that it allows dropping of a client even when not handling a
314 * message from that client.
316 * @param client the client to disconnect from
319 GNUNET_SERVER_client_disconnect (struct GNUNET_SERVER_Client *client);
322 * Return user context associated with the given client.
323 * Note: you should probably use the macro (call without the underscore).
325 * @param client client to query
326 * @param size number of bytes in user context struct (for verification only)
327 * @return pointer to user context
330 GNUNET_SERVER_client_get_user_context_ (struct GNUNET_SERVER_Client *client,
335 * Functions with this signature are called whenever a
336 * complete message is received by the tokenizer.
338 * Do not call #GNUNET_SERVER_mst_destroy from within
339 * the scope of this callback.
342 * @param client identification of the client
343 * @param message the actual message
344 * @return #GNUNET_OK on success, #GNUNET_SYSERR to stop further processing
347 (*GNUNET_SERVER_MessageTokenizerCallback) (void *cls,
349 const struct GNUNET_MessageHeader *message);
353 * Create a message stream tokenizer.
355 * @param cb function to call on completed messages
356 * @param cb_cls closure for @a cb
357 * @return handle to tokenizer
359 struct GNUNET_SERVER_MessageStreamTokenizer *
360 GNUNET_SERVER_mst_create (GNUNET_SERVER_MessageTokenizerCallback cb,
364 * Add incoming data to the receive buffer and call the
365 * callback for all complete messages.
367 * @param mst tokenizer to use
368 * @param client_identity ID of client for which this is a buffer,
369 * can be NULL (will be passed back to 'cb')
370 * @param buf input data to add
371 * @param size number of bytes in @a buf
372 * @param purge should any excess bytes in the buffer be discarded
373 * (i.e. for packet-based services like UDP)
374 * @param one_shot only call callback once, keep rest of message in buffer
375 * @return #GNUNET_OK if we are done processing (need more data)
376 * #GNUNET_NO if one_shot was set and we have another message ready
377 * #GNUNET_SYSERR if the data stream is corrupt
380 GNUNET_SERVER_mst_receive (struct GNUNET_SERVER_MessageStreamTokenizer *mst,
381 void *client_identity,
382 const char *buf, size_t size,
383 int purge, int one_shot);
388 * Destroys a tokenizer.
390 * @param mst tokenizer to destroy
393 GNUNET_SERVER_mst_destroy (struct GNUNET_SERVER_MessageStreamTokenizer *mst);
397 * Set user context to be associated with the given client.
398 * Note: you should probably use the macro (call without the underscore).
400 * @param client client to query
401 * @param ptr pointer to user context
402 * @param size number of bytes in user context struct (for verification only)
405 GNUNET_SERVER_client_set_user_context_ (struct GNUNET_SERVER_Client *client,
409 * Return user context associated with the given client.
411 * @param client client to query
412 * @param type expected return type (i.e. 'struct Foo')
413 * @return pointer to user context of type 'type *'.
415 #define GNUNET_SERVER_client_get_user_context(client,type) \
416 (type *) GNUNET_SERVER_client_get_user_context_ (client, sizeof (type))
419 * Set user context to be associated with the given client.
421 * @param client client to query
422 * @param value pointer to user context
424 #define GNUNET_SERVER_client_set_user_context(client,value) \
425 GNUNET_SERVER_client_set_user_context_ (client, value, sizeof (*value))
430 * Notify us when the server has enough space to transmit
431 * a message of the given size to the given client.
433 * @param client client to transmit message to
434 * @param size requested amount of buffer space
435 * @param timeout after how long should we give up (and call
436 * notify with buf NULL and size 0)?
437 * @param callback function to call when space is available
438 * @param callback_cls closure for @a callback
439 * @return non-NULL if the notify callback was queued; can be used
440 * to cancel the request using
441 * #GNUNET_SERVER_notify_transmit_ready_cancel.
442 * NULL if we are already going to notify someone else (busy)
444 struct GNUNET_SERVER_TransmitHandle *
445 GNUNET_SERVER_notify_transmit_ready (struct GNUNET_SERVER_Client *client,
447 struct GNUNET_TIME_Relative timeout,
448 GNUNET_CONNECTION_TransmitReadyNotify callback,
452 * Abort transmission request.
454 * @param th request to abort
457 GNUNET_SERVER_notify_transmit_ready_cancel (struct GNUNET_SERVER_TransmitHandle *th);
463 * Notify the server that the given client handle should
464 * be kept (keeps the connection up if possible, increments
465 * the internal reference counter).
467 * @param client the client to keep
470 GNUNET_SERVER_client_keep (struct GNUNET_SERVER_Client *client);
474 * Notify the server that the given client handle is no
475 * longer required. Decrements the reference counter. If
476 * that counter reaches zero an inactive connection maybe
479 * @param client the client to drop
482 GNUNET_SERVER_client_drop (struct GNUNET_SERVER_Client *client);
486 * Function called by the service's run
487 * method to run service-specific setup code.
490 * @param server the initialized server
491 * @param cfg configuration to use
494 (*LEGACY_SERVICE_Main) (void *cls,
495 struct GNUNET_SERVER_Handle *server,
496 const struct GNUNET_CONFIGURATION_Handle *cfg);
501 * Suspend accepting connections from the listen socket temporarily.
502 * Resume activity using #GNUNET_SERVER_resume.
504 * @param server server to stop accepting connections.
507 GNUNET_SERVER_suspend (struct GNUNET_SERVER_Handle *server);
510 * Notify us when the server has enough space to transmit
511 * a message of the given size to the given client.
513 * @param client client to transmit message to
514 * @param size requested amount of buffer space
515 * @param timeout after how long should we give up (and call
516 * notify with buf NULL and size 0)?
517 * @param callback function to call when space is available
518 * @param callback_cls closure for @a callback
519 * @return non-NULL if the notify callback was queued; can be used
520 * to cancel the request using
521 * #GNUNET_SERVER_notify_transmit_ready_cancel.
522 * NULL if we are already going to notify someone else (busy)
524 struct GNUNET_SERVER_TransmitHandle *
525 GNUNET_SERVER_notify_transmit_ready (struct GNUNET_SERVER_Client *client,
527 struct GNUNET_TIME_Relative timeout,
528 GNUNET_CONNECTION_TransmitReadyNotify callback,
533 * Add a TCP socket-based connection to the set of handles managed by
534 * this server. Use this function for outgoing (P2P) connections that
535 * we initiated (and where this server should process incoming
538 * @param server the server to use
539 * @param connection the connection to manage (client must
540 * stop using this connection from now on)
541 * @return the client handle
543 struct GNUNET_SERVER_Client *
544 GNUNET_SERVER_connect_socket (struct GNUNET_SERVER_Handle *server,
545 struct GNUNET_CONNECTION_Handle *connection);
549 * Resume accepting connections from the listen socket.
551 * @param server server to resume accepting connections.
554 GNUNET_SERVER_resume (struct GNUNET_SERVER_Handle *server);
557 * Free resources held by this server.
559 * @param server server to destroy
562 GNUNET_SERVER_destroy (struct GNUNET_SERVER_Handle *server);
567 #include "tcp_connection_legacy.c"
568 #include "tcp_server_mst_legacy.c"
569 #include "tcp_server_legacy.c"
570 #include "tcp_service_legacy.c"
572 GNUNET_NETWORK_STRUCT_BEGIN
575 * Initial handshake message for a session.
577 struct WelcomeMessage
580 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_WELCOME.
582 struct GNUNET_MessageHeader header;
585 * Identity of the node connecting (TCP client)
587 struct GNUNET_PeerIdentity clientIdentity;
592 * Basically a WELCOME message, but with the purpose
593 * of giving the waiting peer a client handle to use
595 struct TCP_NAT_ProbeMessage
598 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_NAT_PROBE.
600 struct GNUNET_MessageHeader header;
603 * Identity of the sender of the message.
605 struct GNUNET_PeerIdentity clientIdentity;
608 GNUNET_NETWORK_STRUCT_END
611 * Context for sending a NAT probe via TCP.
613 struct TCPProbeContext
617 * Active probes are kept in a DLL.
619 struct TCPProbeContext *next;
622 * Active probes are kept in a DLL.
624 struct TCPProbeContext *prev;
629 struct GNUNET_CONNECTION_Handle *sock;
632 * Message to be sent.
634 struct TCP_NAT_ProbeMessage message;
637 * Handle to the transmission.
639 struct GNUNET_CONNECTION_TransmitHandle *transmit_handle;
642 * Transport plugin handle.
644 struct Plugin *plugin;
648 * Bits in the `options` field of TCP addresses.
650 enum TcpAddressOptions
656 TCP_OPTIONS_NONE = 0,
659 * See #HTTP_OPTIONS_VERIFY_CERTIFICATE.
661 TCP_OPTIONS_RESERVED = 1,
664 * Enable TCP Stealth-style port knocking.
666 TCP_OPTIONS_TCP_STEALTH = 2
669 GNUNET_NETWORK_STRUCT_BEGIN
672 * Network format for IPv4 addresses.
674 struct IPv4TcpAddress
677 * Optional options and flags for this address,
678 * see `enum TcpAddressOptions`
680 uint32_t options GNUNET_PACKED;
683 * IPv4 address, in network byte order.
685 uint32_t ipv4_addr GNUNET_PACKED;
688 * Port number, in network byte order.
690 uint16_t t4_port GNUNET_PACKED;
695 * Network format for IPv6 addresses.
697 struct IPv6TcpAddress
700 * Optional flags for this address
701 * see `enum TcpAddressOptions`
703 uint32_t options GNUNET_PACKED;
708 struct in6_addr ipv6_addr GNUNET_PACKED;
711 * Port number, in network byte order.
713 uint16_t t6_port GNUNET_PACKED;
716 GNUNET_NETWORK_STRUCT_END
719 * Encapsulation of all of the state of the plugin.
724 * Information kept for each message that is yet to
727 struct PendingMessage
731 * This is a doubly-linked list.
733 struct PendingMessage *next;
736 * This is a doubly-linked list.
738 struct PendingMessage *prev;
741 * The pending message
746 * Continuation function to call once the message
747 * has been sent. Can be NULL if there is no
748 * continuation to call.
750 GNUNET_TRANSPORT_TransmitContinuation transmit_cont;
753 * Closure for @e transmit_cont.
755 void *transmit_cont_cls;
758 * Timeout value for the pending message.
760 struct GNUNET_TIME_Absolute timeout;
763 * So that the gnunet-service-transport can group messages together,
764 * these pending messages need to accept a message buffer and size
765 * instead of just a `struct GNUNET_MessageHeader`.
772 * Session handle for TCP connections.
774 struct GNUNET_ATS_Session
777 * To whom are we talking to (set to our identity
778 * if we are still waiting for the welcome message)
780 struct GNUNET_PeerIdentity target;
783 * Pointer to the global plugin struct.
785 struct Plugin *plugin;
788 * The client (used to identify this connection)
790 struct GNUNET_SERVER_Client *client;
793 * Task cleaning up a NAT client connection establishment attempt;
795 struct GNUNET_SCHEDULER_Task *nat_connection_timeout;
798 * Messages currently pending for transmission
799 * to this peer, if any.
801 struct PendingMessage *pending_messages_head;
804 * Messages currently pending for transmission
805 * to this peer, if any.
807 struct PendingMessage *pending_messages_tail;
810 * Handle for pending transmission request.
812 struct GNUNET_SERVER_TransmitHandle *transmit_handle;
815 * Address of the other peer.
817 struct GNUNET_HELLO_Address *address;
820 * ID of task used to delay receiving more to throttle sender.
822 struct GNUNET_SCHEDULER_Task *receive_delay_task;
825 * Session timeout task
827 struct GNUNET_SCHEDULER_Task *timeout_task;
830 * When will this session time out?
832 struct GNUNET_TIME_Absolute timeout;
835 * When will we continue to read from the socket?
836 * (used to enforce inbound quota).
838 struct GNUNET_TIME_Absolute receive_delay;
841 * Last activity on this connection. Used to select preferred
844 struct GNUNET_TIME_Absolute last_activity;
847 * Number of bytes waiting for transmission to this peer.
849 unsigned long long bytes_in_queue;
852 * Number of messages waiting for transmission to this peer.
854 unsigned int msgs_in_queue;
857 * Network type of the address.
859 enum GNUNET_ATS_Network_Type scope;
862 * Are we still expecting the welcome message? (#GNUNET_YES/#GNUNET_NO)
864 int expecting_welcome;
867 * Was this session created using NAT traversal?
875 * Context for address to string conversion, closure
876 * for #append_port().
878 struct PrettyPrinterContext
883 struct PrettyPrinterContext *next;
888 struct PrettyPrinterContext *prev;
893 struct Plugin *plugin;
898 struct GNUNET_SCHEDULER_Task *timeout_task;
903 struct GNUNET_RESOLVER_RequestHandle *resolver_handle;
906 * Function to call with the result.
908 GNUNET_TRANSPORT_AddressStringCallback asc;
911 * Clsoure for @e asc.
926 * Port to add after the IP address.
933 * Encapsulation of all of the state of the plugin.
940 struct GNUNET_TRANSPORT_PluginEnvironment *env;
945 struct GNUNET_CONNECTION_Handle *lsock;
948 * Our handle to the NAT module.
950 struct GNUNET_NAT_Handle *nat;
953 * Map from peer identities to sessions for the given peer.
955 struct GNUNET_CONTAINER_MultiPeerMap *sessionmap;
958 * Handle to the network service.
960 struct LEGACY_SERVICE_Context *service;
963 * Handle to the server for this service.
965 struct GNUNET_SERVER_Handle *server;
968 * Copy of the handler array where the closures are
969 * set to this struct's instance.
971 struct GNUNET_SERVER_MessageHandler *handlers;
974 * Map of peers we have tried to contact behind a NAT
976 struct GNUNET_CONTAINER_MultiPeerMap *nat_wait_conns;
979 * List of active TCP probes.
981 struct TCPProbeContext *probe_head;
984 * List of active TCP probes.
986 struct TCPProbeContext *probe_tail;
989 * Function to call about session status changes.
991 GNUNET_TRANSPORT_SessionInfoCallback sic;
994 * Closure for @e sic.
999 * ID of task used to update our addresses when one expires.
1001 struct GNUNET_SCHEDULER_Task *address_update_task;
1004 * Running pretty printers: head
1006 struct PrettyPrinterContext *ppc_dll_head;
1009 * Running pretty printers: tail
1011 struct PrettyPrinterContext *ppc_dll_tail;
1014 * Welcome message used by this peer.
1016 struct WelcomeMessage my_welcome;
1019 * How many more TCP sessions are we allowed to open right now?
1021 unsigned long long max_connections;
1024 * How many more TCP sessions do we have right now?
1026 unsigned long long cur_connections;
1034 * Port that we are actually listening on.
1039 * Port that the user said we would have visible to the
1040 * rest of the world.
1048 * Get the list of addresses that a server for the given service
1051 * @param service_name name of the service
1052 * @param cfg configuration (which specifies the addresses)
1053 * @param addrs set (call by reference) to an array of pointers to the
1054 * addresses the server should bind to and listen on; the
1055 * array will be NULL-terminated (on success)
1056 * @param addr_lens set (call by reference) to an array of the lengths
1057 * of the respective `struct sockaddr` struct in the @a addrs
1058 * array (on success)
1059 * @return number of addresses found on success,
1060 * #GNUNET_SYSERR if the configuration
1061 * did not specify reasonable finding information or
1062 * if it specified a hostname that could not be resolved;
1063 * #GNUNET_NO if the number of addresses configured is
1064 * zero (in this case, `*addrs` and `*addr_lens` will be
1068 get_server_addresses (const char *service_name,
1069 const struct GNUNET_CONFIGURATION_Handle *cfg,
1070 struct sockaddr ***addrs,
1071 socklen_t ** addr_lens)
1074 struct GNUNET_NETWORK_Handle *desc;
1075 unsigned long long port;
1077 struct addrinfo hints;
1078 struct addrinfo *res;
1079 struct addrinfo *pos;
1080 struct addrinfo *next;
1085 struct sockaddr **saddrs;
1086 socklen_t *saddrlens;
1092 if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "DISABLEV6"))
1094 if (GNUNET_SYSERR ==
1096 GNUNET_CONFIGURATION_get_value_yesno (cfg, service_name, "DISABLEV6")))
1097 return GNUNET_SYSERR;
1100 disablev6 = GNUNET_NO;
1104 /* probe IPv6 support */
1105 desc = GNUNET_NETWORK_socket_create (PF_INET6, SOCK_STREAM, 0);
1108 if ((ENOBUFS == errno) || (ENOMEM == errno) || (ENFILE == errno) ||
1111 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "socket");
1112 return GNUNET_SYSERR;
1114 LOG (GNUNET_ERROR_TYPE_INFO,
1115 _("Disabling IPv6 support for service `%s', failed to create IPv6 socket: %s\n"),
1116 service_name, STRERROR (errno));
1117 disablev6 = GNUNET_YES;
1121 GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (desc));
1127 if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "PORT"))
1130 GNUNET_CONFIGURATION_get_value_number (cfg, service_name,
1133 LOG (GNUNET_ERROR_TYPE_ERROR,
1134 _("Require valid port number for service `%s' in configuration!\n"),
1139 LOG (GNUNET_ERROR_TYPE_ERROR,
1140 _("Require valid port number for service `%s' in configuration!\n"),
1142 return GNUNET_SYSERR;
1146 if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "BINDTO"))
1148 GNUNET_break (GNUNET_OK ==
1149 GNUNET_CONFIGURATION_get_value_string (cfg, service_name,
1150 "BINDTO", &hostname));
1156 abstract = GNUNET_NO;
1159 GNUNET_CONFIGURATION_have_value (cfg, service_name, "UNIXPATH")) &&
1161 GNUNET_CONFIGURATION_get_value_filename (cfg, service_name, "UNIXPATH",
1163 (0 < strlen (unixpath)))
1165 /* probe UNIX support */
1166 struct sockaddr_un s_un;
1168 if (strlen (unixpath) >= sizeof (s_un.sun_path))
1170 LOG (GNUNET_ERROR_TYPE_WARNING,
1171 _("UNIXPATH `%s' too long, maximum length is %llu\n"), unixpath,
1172 (unsigned long long) sizeof (s_un.sun_path));
1173 unixpath = GNUNET_NETWORK_shorten_unixpath (unixpath);
1174 LOG (GNUNET_ERROR_TYPE_INFO,
1175 _("Using `%s' instead\n"),
1179 abstract = GNUNET_CONFIGURATION_get_value_yesno (cfg,
1181 "USE_ABSTRACT_SOCKETS");
1182 if (GNUNET_SYSERR == abstract)
1183 abstract = GNUNET_NO;
1185 if ((GNUNET_YES != abstract)
1187 GNUNET_DISK_directory_create_for_file (unixpath)))
1188 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
1192 if (NULL != unixpath)
1194 desc = GNUNET_NETWORK_socket_create (AF_UNIX, SOCK_STREAM, 0);
1197 if ((ENOBUFS == errno) || (ENOMEM == errno) || (ENFILE == errno) ||
1200 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "socket");
1201 GNUNET_free_non_null (hostname);
1202 GNUNET_free (unixpath);
1203 return GNUNET_SYSERR;
1205 LOG (GNUNET_ERROR_TYPE_INFO,
1206 _("Disabling UNIX domain socket support for service `%s', failed to create UNIX domain socket: %s\n"),
1209 GNUNET_free (unixpath);
1214 GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (desc));
1220 if ((0 == port) && (NULL == unixpath))
1222 LOG (GNUNET_ERROR_TYPE_ERROR,
1223 _("Have neither PORT nor UNIXPATH for service `%s', but one is required\n"),
1225 GNUNET_free_non_null (hostname);
1226 return GNUNET_SYSERR;
1230 saddrs = GNUNET_malloc (2 * sizeof (struct sockaddr *));
1231 saddrlens = GNUNET_malloc (2 * sizeof (socklen_t));
1232 add_unixpath (saddrs, saddrlens, unixpath, abstract);
1233 GNUNET_free_non_null (unixpath);
1234 GNUNET_free_non_null (hostname);
1236 *addr_lens = saddrlens;
1240 if (NULL != hostname)
1242 LOG (GNUNET_ERROR_TYPE_DEBUG,
1243 "Resolving `%s' since that is where `%s' will bind to.\n",
1246 memset (&hints, 0, sizeof (struct addrinfo));
1248 hints.ai_family = AF_INET;
1249 hints.ai_protocol = IPPROTO_TCP;
1250 if ((0 != (ret = getaddrinfo (hostname, NULL, &hints, &res))) ||
1253 LOG (GNUNET_ERROR_TYPE_ERROR,
1254 _("Failed to resolve `%s': %s\n"),
1256 gai_strerror (ret));
1257 GNUNET_free (hostname);
1258 GNUNET_free_non_null (unixpath);
1259 return GNUNET_SYSERR;
1263 while (NULL != (pos = next))
1265 next = pos->ai_next;
1266 if ((disablev6) && (pos->ai_family == AF_INET6))
1272 LOG (GNUNET_ERROR_TYPE_ERROR,
1273 _("Failed to find %saddress for `%s'.\n"),
1274 disablev6 ? "IPv4 " : "",
1277 GNUNET_free (hostname);
1278 GNUNET_free_non_null (unixpath);
1279 return GNUNET_SYSERR;
1282 if (NULL != unixpath)
1284 saddrs = GNUNET_malloc ((resi + 1) * sizeof (struct sockaddr *));
1285 saddrlens = GNUNET_malloc ((resi + 1) * sizeof (socklen_t));
1287 if (NULL != unixpath)
1289 add_unixpath (saddrs, saddrlens, unixpath, abstract);
1293 while (NULL != (pos = next))
1295 next = pos->ai_next;
1296 if ((disablev6) && (AF_INET6 == pos->ai_family))
1298 if ((IPPROTO_TCP != pos->ai_protocol) && (0 != pos->ai_protocol))
1299 continue; /* not TCP */
1300 if ((SOCK_STREAM != pos->ai_socktype) && (0 != pos->ai_socktype))
1301 continue; /* huh? */
1302 LOG (GNUNET_ERROR_TYPE_DEBUG, "Service `%s' will bind to `%s'\n",
1303 service_name, GNUNET_a2s (pos->ai_addr, pos->ai_addrlen));
1304 if (AF_INET == pos->ai_family)
1306 GNUNET_assert (sizeof (struct sockaddr_in) == pos->ai_addrlen);
1307 saddrlens[i] = pos->ai_addrlen;
1308 saddrs[i] = GNUNET_malloc (saddrlens[i]);
1309 GNUNET_memcpy (saddrs[i], pos->ai_addr, saddrlens[i]);
1310 ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
1314 GNUNET_assert (AF_INET6 == pos->ai_family);
1315 GNUNET_assert (sizeof (struct sockaddr_in6) == pos->ai_addrlen);
1316 saddrlens[i] = pos->ai_addrlen;
1317 saddrs[i] = GNUNET_malloc (saddrlens[i]);
1318 GNUNET_memcpy (saddrs[i], pos->ai_addr, saddrlens[i]);
1319 ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port);
1323 GNUNET_free (hostname);
1329 /* will bind against everything, just set port */
1334 if (NULL != unixpath)
1337 saddrs = GNUNET_malloc ((resi + 1) * sizeof (struct sockaddr *));
1338 saddrlens = GNUNET_malloc ((resi + 1) * sizeof (socklen_t));
1339 if (NULL != unixpath)
1341 add_unixpath (saddrs, saddrlens, unixpath, abstract);
1344 saddrlens[i] = sizeof (struct sockaddr_in);
1345 saddrs[i] = GNUNET_malloc (saddrlens[i]);
1346 #if HAVE_SOCKADDR_IN_SIN_LEN
1347 ((struct sockaddr_in *) saddrs[i])->sin_len = saddrlens[i];
1349 ((struct sockaddr_in *) saddrs[i])->sin_family = AF_INET;
1350 ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
1356 if (NULL != unixpath)
1358 saddrs = GNUNET_malloc ((resi + 1) * sizeof (struct sockaddr *));
1359 saddrlens = GNUNET_malloc ((resi + 1) * sizeof (socklen_t));
1361 if (NULL != unixpath)
1363 add_unixpath (saddrs, saddrlens, unixpath, abstract);
1366 saddrlens[i] = sizeof (struct sockaddr_in6);
1367 saddrs[i] = GNUNET_malloc (saddrlens[i]);
1368 #if HAVE_SOCKADDR_IN_SIN_LEN
1369 ((struct sockaddr_in6 *) saddrs[i])->sin6_len = saddrlens[0];
1371 ((struct sockaddr_in6 *) saddrs[i])->sin6_family = AF_INET6;
1372 ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port);
1374 saddrlens[i] = sizeof (struct sockaddr_in);
1375 saddrs[i] = GNUNET_malloc (saddrlens[i]);
1376 #if HAVE_SOCKADDR_IN_SIN_LEN
1377 ((struct sockaddr_in *) saddrs[i])->sin_len = saddrlens[1];
1379 ((struct sockaddr_in *) saddrs[i])->sin_family = AF_INET;
1380 ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
1383 GNUNET_free_non_null (unixpath);
1385 *addr_lens = saddrlens;
1388 /* end ancient copy-and-paste */
1392 * If a session monitor is attached, notify it about the new
1395 * @param plugin our plugin
1396 * @param session session that changed state
1397 * @param state new state of the session
1400 notify_session_monitor (struct Plugin *plugin,
1401 struct GNUNET_ATS_Session *session,
1402 enum GNUNET_TRANSPORT_SessionState state)
1404 struct GNUNET_TRANSPORT_SessionInfo info;
1406 if (NULL == plugin->sic)
1408 memset (&info, 0, sizeof (info));
1410 info.is_inbound = GNUNET_HELLO_address_check_option (session->address,
1411 GNUNET_HELLO_ADDRESS_INFO_INBOUND);
1412 info.num_msg_pending = session->msgs_in_queue;
1413 info.num_bytes_pending = session->bytes_in_queue;
1414 if (NULL != session->receive_delay_task)
1415 info.receive_delay = session->receive_delay;
1416 info.session_timeout = session->timeout;
1417 info.address = session->address;
1418 plugin->sic (plugin->sic_cls,
1425 * Our external IP address/port mapping has changed.
1427 * @param cls closure, the `struct Plugin`
1428 * @param add_remove #GNUNET_YES to mean the new public IP address, #GNUNET_NO to mean
1429 * the previous (now invalid) one
1430 * @param ac address class the address belongs to
1431 * @param addr either the previous or the new public IP address
1432 * @param addrlen actual length of @a addr
1435 tcp_nat_port_map_callback (void *cls,
1437 enum GNUNET_NAT_AddressClass ac,
1438 const struct sockaddr *addr,
1441 struct Plugin *plugin = cls;
1442 struct GNUNET_HELLO_Address *address;
1443 struct IPv4TcpAddress t4;
1444 struct IPv6TcpAddress t6;
1448 if (GNUNET_NAT_AC_LOOPBACK == ac)
1450 if (GNUNET_NAT_AC_LAN == ac)
1452 if (GNUNET_NAT_AC_LAN_PRIVATE == ac)
1454 LOG (GNUNET_ERROR_TYPE_INFO,
1455 "NAT notification to %s address `%s'\n",
1456 (GNUNET_YES == add_remove) ? "add" : "remove",
1457 GNUNET_a2s (addr, addrlen));
1458 /* convert 'addr' to our internal format */
1459 switch (addr->sa_family)
1462 GNUNET_assert(addrlen == sizeof(struct sockaddr_in));
1463 memset (&t4, 0, sizeof(t4));
1464 t4.options = htonl (plugin->myoptions);
1465 t4.ipv4_addr = ((struct sockaddr_in *) addr)->sin_addr.s_addr;
1466 t4.t4_port = ((struct sockaddr_in *) addr)->sin_port;
1471 GNUNET_assert(addrlen == sizeof(struct sockaddr_in6));
1472 memset (&t6, 0, sizeof(t6));
1473 GNUNET_memcpy (&t6.ipv6_addr,
1474 &((struct sockaddr_in6 *) addr)->sin6_addr,
1475 sizeof(struct in6_addr));
1476 t6.options = htonl (plugin->myoptions);
1477 t6.t6_port = ((struct sockaddr_in6 *) addr)->sin6_port;
1485 /* modify our published address list */
1486 GNUNET_assert ((args == sizeof (struct IPv4TcpAddress)) ||
1487 (args == sizeof (struct IPv6TcpAddress)));
1488 /* TODO: use 'ac' here in the future... */
1489 address = GNUNET_HELLO_address_allocate (plugin->env->my_identity,
1493 GNUNET_HELLO_ADDRESS_INFO_NONE);
1494 plugin->env->notify_address (plugin->env->cls,
1497 GNUNET_HELLO_address_free (address);
1502 * Function called for a quick conversion of the binary address to
1503 * a numeric address. Note that the caller must not free the
1504 * address and that the next call to this function is allowed
1505 * to override the address again.
1507 * @param cls closure (`struct Plugin*`)
1508 * @param addr binary address
1509 * @param addrlen length of @a addr
1510 * @return string representing the same address
1513 tcp_plugin_address_to_string (void *cls,
1517 static char rbuf[INET6_ADDRSTRLEN + 12];
1518 char buf[INET6_ADDRSTRLEN];
1522 const struct IPv4TcpAddress *t4;
1523 const struct IPv6TcpAddress *t6;
1530 case sizeof(struct IPv6TcpAddress):
1533 port = ntohs (t6->t6_port);
1534 options = ntohl (t6->options);
1535 GNUNET_memcpy (&a6, &t6->ipv6_addr, sizeof(a6));
1538 case sizeof(struct IPv4TcpAddress):
1541 port = ntohs (t4->t4_port);
1542 options = ntohl (t4->options);
1543 GNUNET_memcpy (&a4, &t4->ipv4_addr, sizeof(a4));
1547 LOG (GNUNET_ERROR_TYPE_WARNING,
1548 _("Unexpected address length: %u bytes\n"),
1549 (unsigned int) addrlen);
1552 if (NULL == inet_ntop (af, sb, buf, INET6_ADDRSTRLEN))
1554 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
1558 GNUNET_snprintf (rbuf, sizeof(rbuf),
1559 (af == AF_INET6) ? "%s.%u.[%s]:%u" : "%s.%u.%s:%u",
1569 * Function called to convert a string address to
1572 * @param cls closure (`struct Plugin*`)
1573 * @param addr string address
1574 * @param addrlen length of the address
1575 * @param buf location to store the buffer
1576 * @param added location to store the number of bytes in the buffer.
1577 * If the function returns #GNUNET_SYSERR, its contents are undefined.
1578 * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure
1581 tcp_plugin_string_to_address (void *cls,
1587 struct sockaddr_storage socket_address;
1593 /* Format tcp.options.address:port */
1597 if ((NULL == addr) || (0 == addrlen))
1600 return GNUNET_SYSERR;
1602 if ('\0' != addr[addrlen - 1])
1605 return GNUNET_SYSERR;
1607 if (strlen (addr) != addrlen - 1)
1610 return GNUNET_SYSERR;
1612 plugin = GNUNET_strdup (addr);
1613 optionstr = strchr (plugin, '.');
1614 if (NULL == optionstr)
1617 GNUNET_free(plugin);
1618 return GNUNET_SYSERR;
1620 optionstr[0] = '\0';
1622 options = atol (optionstr);
1623 address = strchr (optionstr, '.');
1624 if (NULL == address)
1627 GNUNET_free(plugin);
1628 return GNUNET_SYSERR;
1634 GNUNET_STRINGS_to_address_ip (address,
1639 GNUNET_free(plugin);
1640 return GNUNET_SYSERR;
1643 GNUNET_free(plugin);
1644 switch (socket_address.ss_family)
1648 struct IPv4TcpAddress *t4;
1649 struct sockaddr_in *in4 = (struct sockaddr_in *) &socket_address;
1650 t4 = GNUNET_new (struct IPv4TcpAddress);
1651 t4->options = htonl (options);
1652 t4->ipv4_addr = in4->sin_addr.s_addr;
1653 t4->t4_port = in4->sin_port;
1655 *added = sizeof(struct IPv4TcpAddress);
1660 struct IPv6TcpAddress *t6;
1661 struct sockaddr_in6 *in6 = (struct sockaddr_in6 *) &socket_address;
1662 t6 = GNUNET_new (struct IPv6TcpAddress);
1663 t6->options = htonl (options);
1664 t6->ipv6_addr = in6->sin6_addr;
1665 t6->t6_port = in6->sin6_port;
1667 *added = sizeof(struct IPv6TcpAddress);
1671 return GNUNET_SYSERR;
1677 * Find the session handle for the given client.
1678 * Currently uses both the hashmap and the client
1679 * context, as the client context is new and the
1680 * logic still needs to be tested.
1682 * @param plugin the plugin
1683 * @param client which client to find the session handle for
1684 * @return NULL if no matching session exists
1686 static struct GNUNET_ATS_Session *
1687 lookup_session_by_client (struct Plugin *plugin,
1688 struct GNUNET_SERVER_Client *client)
1690 return GNUNET_SERVER_client_get_user_context (client,
1691 struct GNUNET_ATS_Session);
1696 * Functions with this signature are called whenever we need
1697 * to close a session due to a disconnect or failure to
1698 * establish a connection.
1700 * @param cls the `struct Plugin`
1701 * @param session session to close down
1702 * @return #GNUNET_OK on success
1705 tcp_plugin_disconnect_session (void *cls,
1706 struct GNUNET_ATS_Session *session)
1708 struct Plugin *plugin = cls;
1709 struct PendingMessage *pm;
1711 LOG (GNUNET_ERROR_TYPE_DEBUG,
1712 "Disconnecting session of peer `%s' address `%s'\n",
1713 GNUNET_i2s (&session->target),
1714 tcp_plugin_address_to_string (session->plugin,
1715 session->address->address,
1716 session->address->address_length));
1718 if (NULL != session->timeout_task)
1720 GNUNET_SCHEDULER_cancel (session->timeout_task);
1721 session->timeout_task = NULL;
1722 session->timeout = GNUNET_TIME_UNIT_ZERO_ABS;
1726 GNUNET_CONTAINER_multipeermap_remove (plugin->sessionmap,
1730 GNUNET_STATISTICS_update (session->plugin->env->stats,
1731 gettext_noop ("# TCP sessions active"),
1737 GNUNET_assert (GNUNET_YES ==
1738 GNUNET_CONTAINER_multipeermap_remove (plugin->nat_wait_conns,
1742 if (NULL != session->client)
1743 GNUNET_SERVER_client_set_user_context (session->client,
1746 /* clean up state */
1747 if (NULL != session->transmit_handle)
1749 GNUNET_SERVER_notify_transmit_ready_cancel (session->transmit_handle);
1750 session->transmit_handle = NULL;
1752 session->plugin->env->session_end (session->plugin->env->cls,
1756 if (NULL != session->nat_connection_timeout)
1758 GNUNET_SCHEDULER_cancel (session->nat_connection_timeout);
1759 session->nat_connection_timeout = NULL;
1762 while (NULL != (pm = session->pending_messages_head))
1764 LOG (GNUNET_ERROR_TYPE_DEBUG,
1765 (NULL != pm->transmit_cont)
1766 ? "Could not deliver message to `%s' at %s.\n"
1767 : "Could not deliver message to `%s' at %s, notifying.\n",
1768 GNUNET_i2s (&session->target),
1769 tcp_plugin_address_to_string (session->plugin,
1770 session->address->address,
1771 session->address->address_length));
1772 GNUNET_STATISTICS_update (session->plugin->env->stats,
1773 gettext_noop ("# bytes currently in TCP buffers"),
1774 -(int64_t) pm->message_size, GNUNET_NO);
1775 GNUNET_STATISTICS_update (session->plugin->env->stats,
1776 gettext_noop ("# bytes discarded by TCP (disconnect)"),
1779 GNUNET_CONTAINER_DLL_remove (session->pending_messages_head,
1780 session->pending_messages_tail,
1782 GNUNET_assert (0 < session->msgs_in_queue);
1783 session->msgs_in_queue--;
1784 GNUNET_assert (pm->message_size <= session->bytes_in_queue);
1785 session->bytes_in_queue -= pm->message_size;
1786 if (NULL != pm->transmit_cont)
1787 pm->transmit_cont (pm->transmit_cont_cls,
1794 GNUNET_assert (0 == session->msgs_in_queue);
1795 GNUNET_assert (0 == session->bytes_in_queue);
1796 notify_session_monitor (session->plugin,
1798 GNUNET_TRANSPORT_SS_DONE);
1800 if (NULL != session->receive_delay_task)
1802 GNUNET_SCHEDULER_cancel (session->receive_delay_task);
1803 session->receive_delay_task = NULL;
1805 if (NULL != session->client)
1807 GNUNET_SERVER_client_disconnect (session->client);
1808 session->client = NULL;
1810 GNUNET_HELLO_address_free (session->address);
1811 GNUNET_assert (NULL == session->transmit_handle);
1812 GNUNET_free (session);
1818 * Function that is called to get the keepalive factor.
1819 * #GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT is divided by this number to
1820 * calculate the interval between keepalive packets.
1822 * @param cls closure with the `struct Plugin`
1823 * @return keepalive factor
1826 tcp_plugin_query_keepalive_factor (void *cls)
1833 * Session was idle for too long, so disconnect it
1835 * @param cls the `struct GNUNET_ATS_Session` of the idle session
1838 session_timeout (void *cls)
1840 struct GNUNET_ATS_Session *s = cls;
1841 struct GNUNET_TIME_Relative left;
1843 s->timeout_task = NULL;
1844 left = GNUNET_TIME_absolute_get_remaining (s->timeout);
1845 if (0 != left.rel_value_us)
1847 /* not actually our turn yet, but let's at least update
1848 the monitor, it may think we're about to die ... */
1849 notify_session_monitor (s->plugin,
1851 GNUNET_TRANSPORT_SS_UPDATE);
1852 s->timeout_task = GNUNET_SCHEDULER_add_delayed (left,
1857 LOG (GNUNET_ERROR_TYPE_DEBUG,
1858 "Session %p was idle for %s, disconnecting\n",
1860 GNUNET_STRINGS_relative_time_to_string (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
1862 /* call session destroy function */
1863 tcp_plugin_disconnect_session (s->plugin,
1869 * Increment session timeout due to activity.
1871 * @param s session to increment timeout for
1874 reschedule_session_timeout (struct GNUNET_ATS_Session *s)
1876 GNUNET_assert (NULL != s->timeout_task);
1877 s->timeout = GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1882 * Create a new session. Also queues a welcome message.
1884 * @param plugin the plugin
1885 * @param address the address to create the session for
1886 * @param scope network scope the address is from
1887 * @param client client to use, reference counter must have already been increased
1888 * @param is_nat this a NAT session, we should wait for a client to
1889 * connect to us from an address, then assign that to
1891 * @return new session object
1893 static struct GNUNET_ATS_Session *
1894 create_session (struct Plugin *plugin,
1895 const struct GNUNET_HELLO_Address *address,
1896 enum GNUNET_ATS_Network_Type scope,
1897 struct GNUNET_SERVER_Client *client,
1900 struct GNUNET_ATS_Session *session;
1901 struct PendingMessage *pm;
1903 if (GNUNET_YES != is_nat)
1904 GNUNET_assert (NULL != client);
1906 GNUNET_assert (NULL == client);
1908 LOG (GNUNET_ERROR_TYPE_DEBUG,
1909 "Creating new session for peer `%s' at address %s\n",
1910 GNUNET_i2s (&address->peer),
1911 tcp_plugin_address_to_string (plugin,
1913 address->address_length));
1914 session = GNUNET_new (struct GNUNET_ATS_Session);
1915 session->last_activity = GNUNET_TIME_absolute_get ();
1916 session->plugin = plugin;
1917 session->is_nat = is_nat;
1920 session->client = client;
1921 GNUNET_SERVER_client_set_user_context (client,
1924 session->address = GNUNET_HELLO_address_copy (address);
1925 session->target = address->peer;
1926 session->expecting_welcome = GNUNET_YES;
1927 session->scope = scope;
1928 pm = GNUNET_malloc (sizeof (struct PendingMessage) +
1929 sizeof (struct WelcomeMessage));
1930 pm->msg = (const char *) &pm[1];
1931 pm->message_size = sizeof(struct WelcomeMessage);
1932 GNUNET_memcpy (&pm[1],
1933 &plugin->my_welcome,
1934 sizeof(struct WelcomeMessage));
1935 pm->timeout = GNUNET_TIME_UNIT_FOREVER_ABS;
1936 GNUNET_STATISTICS_update (plugin->env->stats,
1937 gettext_noop ("# bytes currently in TCP buffers"),
1940 GNUNET_CONTAINER_DLL_insert (session->pending_messages_head,
1941 session->pending_messages_tail,
1943 session->msgs_in_queue++;
1944 session->bytes_in_queue += pm->message_size;
1945 session->timeout = GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1946 session->timeout_task = GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
1949 notify_session_monitor (session->plugin,
1951 GNUNET_TRANSPORT_SS_INIT);
1952 if (GNUNET_YES != is_nat)
1954 GNUNET_STATISTICS_update (plugin->env->stats,
1955 gettext_noop ("# TCP sessions active"),
1958 notify_session_monitor (session->plugin,
1960 GNUNET_TRANSPORT_SS_UP);
1964 notify_session_monitor (session->plugin,
1966 GNUNET_TRANSPORT_SS_HANDSHAKE);
1973 * If we have pending messages, ask the server to
1974 * transmit them (schedule the respective tasks, etc.)
1976 * @param session for which session should we do this
1979 process_pending_messages (struct GNUNET_ATS_Session *session);
1983 * Function called to notify a client about the socket
1984 * being ready to queue more data. "buf" will be
1985 * NULL and "size" zero if the socket was closed for
1986 * writing in the meantime.
1988 * @param cls closure
1989 * @param size number of bytes available in @a buf
1990 * @param buf where the callee should write the message
1991 * @return number of bytes written to @a buf
1994 do_transmit (void *cls,
1998 struct GNUNET_ATS_Session *session = cls;
1999 struct GNUNET_PeerIdentity pid;
2000 struct Plugin *plugin;
2001 struct PendingMessage *pos;
2002 struct PendingMessage *hd;
2003 struct PendingMessage *tl;
2004 struct GNUNET_TIME_Absolute now;
2008 session->transmit_handle = NULL;
2009 plugin = session->plugin;
2012 LOG (GNUNET_ERROR_TYPE_DEBUG,
2013 "Timeout trying to transmit to peer `%s', discarding message queue.\n",
2014 GNUNET_i2s (&session->target));
2015 /* timeout; cancel all messages that have already expired */
2019 now = GNUNET_TIME_absolute_get ();
2020 while ( (NULL != (pos = session->pending_messages_head)) &&
2021 (pos->timeout.abs_value_us <= now.abs_value_us) )
2023 GNUNET_CONTAINER_DLL_remove (session->pending_messages_head,
2024 session->pending_messages_tail,
2026 GNUNET_assert (0 < session->msgs_in_queue);
2027 session->msgs_in_queue--;
2028 GNUNET_assert (pos->message_size <= session->bytes_in_queue);
2029 session->bytes_in_queue -= pos->message_size;
2030 LOG (GNUNET_ERROR_TYPE_DEBUG,
2031 "Failed to transmit %u byte message to `%s'.\n",
2033 GNUNET_i2s (&session->target));
2034 ret += pos->message_size;
2035 GNUNET_CONTAINER_DLL_insert_after (hd,
2040 /* do this call before callbacks (so that if callbacks destroy
2041 * session, they have a chance to cancel actions done by this
2043 process_pending_messages (session);
2044 pid = session->target;
2045 /* no do callbacks and do not use session again since
2046 * the callbacks may abort the session */
2047 while (NULL != (pos = hd))
2049 GNUNET_CONTAINER_DLL_remove (hd,
2052 if (NULL != pos->transmit_cont)
2053 pos->transmit_cont (pos->transmit_cont_cls,
2060 GNUNET_STATISTICS_update (plugin->env->stats,
2061 gettext_noop ("# bytes currently in TCP buffers"), -(int64_t) ret,
2063 GNUNET_STATISTICS_update (plugin->env->stats,
2064 gettext_noop ("# bytes discarded by TCP (timeout)"),
2068 notify_session_monitor (session->plugin,
2070 GNUNET_TRANSPORT_SS_UPDATE);
2073 /* copy all pending messages that would fit */
2078 while (NULL != (pos = session->pending_messages_head))
2080 if (ret + pos->message_size > size)
2082 GNUNET_CONTAINER_DLL_remove (session->pending_messages_head,
2083 session->pending_messages_tail,
2085 GNUNET_assert (0 < session->msgs_in_queue);
2086 session->msgs_in_queue--;
2087 GNUNET_assert (pos->message_size <= session->bytes_in_queue);
2088 session->bytes_in_queue -= pos->message_size;
2089 GNUNET_assert(size >= pos->message_size);
2090 LOG (GNUNET_ERROR_TYPE_DEBUG,
2091 "Transmitting message of type %u size %u to peer %s at %s\n",
2092 ntohs (((struct GNUNET_MessageHeader *) pos->msg)->type),
2094 GNUNET_i2s (&session->target),
2095 tcp_plugin_address_to_string (session->plugin,
2096 session->address->address,
2097 session->address->address_length));
2098 /* FIXME: this GNUNET_memcpy can be up to 7% of our total runtime */
2099 GNUNET_memcpy (cbuf,
2102 cbuf += pos->message_size;
2103 ret += pos->message_size;
2104 size -= pos->message_size;
2105 GNUNET_CONTAINER_DLL_insert_tail (hd,
2109 notify_session_monitor (session->plugin,
2111 GNUNET_TRANSPORT_SS_UPDATE);
2112 /* schedule 'continuation' before callbacks so that callbacks that
2113 * cancel everything don't cause us to use a session that no longer
2115 process_pending_messages (session);
2116 session->last_activity = GNUNET_TIME_absolute_get ();
2117 pid = session->target;
2118 /* we'll now call callbacks that may cancel the session; hence
2119 * we should not use 'session' after this point */
2120 while (NULL != (pos = hd))
2122 GNUNET_CONTAINER_DLL_remove (hd, tl, pos);
2123 if (NULL != pos->transmit_cont)
2124 pos->transmit_cont (pos->transmit_cont_cls,
2128 pos->message_size); /* FIXME: include TCP overhead */
2131 GNUNET_assert (NULL == hd);
2132 GNUNET_assert (NULL == tl);
2133 GNUNET_STATISTICS_update (plugin->env->stats,
2134 gettext_noop ("# bytes currently in TCP buffers"),
2137 GNUNET_STATISTICS_update (plugin->env->stats,
2138 gettext_noop ("# bytes transmitted via TCP"),
2146 * If we have pending messages, ask the server to
2147 * transmit them (schedule the respective tasks, etc.)
2149 * @param session for which session should we do this
2152 process_pending_messages (struct GNUNET_ATS_Session *session)
2154 struct PendingMessage *pm;
2156 GNUNET_assert (NULL != session->client);
2157 if (NULL != session->transmit_handle)
2159 if (NULL == (pm = session->pending_messages_head))
2162 session->transmit_handle
2163 = GNUNET_SERVER_notify_transmit_ready (session->client,
2165 GNUNET_TIME_absolute_get_remaining (pm->timeout),
2172 * Function that can be used by the transport service to transmit
2173 * a message using the plugin. Note that in the case of a
2174 * peer disconnecting, the continuation MUST be called
2175 * prior to the disconnect notification itself. This function
2176 * will be called with this peer's HELLO message to initiate
2177 * a fresh connection to another peer.
2179 * @param cls closure
2180 * @param session which session must be used
2181 * @param msgbuf the message to transmit
2182 * @param msgbuf_size number of bytes in @a msgbuf
2183 * @param priority how important is the message (most plugins will
2184 * ignore message priority and just FIFO)
2185 * @param to how long to wait at most for the transmission (does not
2186 * require plugins to discard the message after the timeout,
2187 * just advisory for the desired delay; most plugins will ignore
2189 * @param cont continuation to call once the message has
2190 * been transmitted (or if the transport is ready
2191 * for the next transmission call; or if the
2192 * peer disconnected...); can be NULL
2193 * @param cont_cls closure for @a cont
2194 * @return number of bytes used (on the physical network, with overheads);
2195 * -1 on hard errors (i.e. address invalid); 0 is a legal value
2196 * and does NOT mean that the message was not transmitted (DV)
2199 tcp_plugin_send (void *cls,
2200 struct GNUNET_ATS_Session *session,
2203 unsigned int priority,
2204 struct GNUNET_TIME_Relative to,
2205 GNUNET_TRANSPORT_TransmitContinuation cont,
2208 struct Plugin * plugin = cls;
2209 struct PendingMessage *pm;
2211 /* create new message entry */
2212 pm = GNUNET_malloc (sizeof (struct PendingMessage) + msgbuf_size);
2213 pm->msg = (const char *) &pm[1];
2214 GNUNET_memcpy (&pm[1], msgbuf, msgbuf_size);
2215 pm->message_size = msgbuf_size;
2216 pm->timeout = GNUNET_TIME_relative_to_absolute (to);
2217 pm->transmit_cont = cont;
2218 pm->transmit_cont_cls = cont_cls;
2220 LOG (GNUNET_ERROR_TYPE_DEBUG,
2221 "Asked to transmit %u bytes to `%s', added message to list.\n",
2223 GNUNET_i2s (&session->target));
2226 GNUNET_CONTAINER_multipeermap_contains_value (plugin->sessionmap,
2230 GNUNET_assert (NULL != session->client);
2231 GNUNET_SERVER_client_set_timeout (session->client,
2232 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2233 GNUNET_STATISTICS_update (plugin->env->stats,
2234 gettext_noop ("# bytes currently in TCP buffers"),
2238 /* append pm to pending_messages list */
2239 GNUNET_CONTAINER_DLL_insert_tail (session->pending_messages_head,
2240 session->pending_messages_tail,
2242 notify_session_monitor (session->plugin,
2244 GNUNET_TRANSPORT_SS_UPDATE);
2245 session->msgs_in_queue++;
2246 session->bytes_in_queue += pm->message_size;
2247 process_pending_messages (session);
2251 GNUNET_CONTAINER_multipeermap_contains_value (plugin->nat_wait_conns,
2255 LOG (GNUNET_ERROR_TYPE_DEBUG,
2256 "This NAT WAIT session for peer `%s' is not yet ready!\n",
2257 GNUNET_i2s (&session->target));
2258 GNUNET_STATISTICS_update (plugin->env->stats,
2259 gettext_noop ("# bytes currently in TCP buffers"), msgbuf_size,
2261 /* append pm to pending_messages list */
2262 GNUNET_CONTAINER_DLL_insert_tail (session->pending_messages_head,
2263 session->pending_messages_tail,
2265 session->msgs_in_queue++;
2266 session->bytes_in_queue += pm->message_size;
2267 notify_session_monitor (session->plugin,
2269 GNUNET_TRANSPORT_SS_HANDSHAKE);
2272 LOG (GNUNET_ERROR_TYPE_ERROR,
2273 "Invalid session %p\n",
2283 return GNUNET_SYSERR; /* session does not exist here */
2288 * Closure for #session_lookup_it().
2290 struct GNUNET_ATS_SessionItCtx
2293 * Address we are looking for.
2295 const struct GNUNET_HELLO_Address *address;
2298 * Where to store the session (if we found it).
2300 struct GNUNET_ATS_Session *result;
2306 * Look for a session by address.
2308 * @param cls the `struct GNUNET_ATS_SessionItCtx`
2310 * @param value a `struct GNUNET_ATS_Session`
2311 * @return #GNUNET_YES to continue looking, #GNUNET_NO if we found the session
2314 session_lookup_it (void *cls,
2315 const struct GNUNET_PeerIdentity *key,
2318 struct GNUNET_ATS_SessionItCtx *si_ctx = cls;
2319 struct GNUNET_ATS_Session *session = value;
2322 GNUNET_HELLO_address_cmp (si_ctx->address,
2325 si_ctx->result = session;
2331 * Task cleaning up a NAT connection attempt after timeout
2333 * @param cls the `struct GNUNET_ATS_Session`
2336 nat_connect_timeout (void *cls)
2338 struct GNUNET_ATS_Session *session = cls;
2340 session->nat_connection_timeout = NULL;
2341 LOG (GNUNET_ERROR_TYPE_DEBUG,
2342 "NAT WAIT connection to `%4s' at `%s' could not be established, removing session\n",
2343 GNUNET_i2s (&session->target),
2344 tcp_plugin_address_to_string (session->plugin,
2345 session->address->address,
2346 session->address->address_length));
2347 tcp_plugin_disconnect_session (session->plugin,
2353 * Function that will be called whenever the transport service wants to
2354 * notify the plugin that a session is still active and in use and
2355 * therefore the session timeout for this session has to be updated
2357 * @param cls closure
2358 * @param peer which peer was the session for
2359 * @param session which session is being updated
2362 tcp_plugin_update_session_timeout (void *cls,
2363 const struct GNUNET_PeerIdentity *peer,
2364 struct GNUNET_ATS_Session *session)
2366 reschedule_session_timeout (session);
2371 * Task to signal the server that we can continue
2372 * receiving from the TCP client now.
2374 * @param cls the `struct GNUNET_ATS_Session *`
2377 delayed_done (void *cls)
2379 struct GNUNET_ATS_Session *session = cls;
2381 session->receive_delay_task = NULL;
2382 reschedule_session_timeout (session);
2383 GNUNET_SERVER_receive_done (session->client,
2389 * Function that will be called whenever the transport service wants to
2390 * notify the plugin that the inbound quota changed and that the plugin
2391 * should update it's delay for the next receive value
2393 * @param cls closure
2394 * @param peer which peer was the session for
2395 * @param session which session is being updated
2396 * @param delay new delay to use for receiving
2399 tcp_plugin_update_inbound_delay (void *cls,
2400 const struct GNUNET_PeerIdentity *peer,
2401 struct GNUNET_ATS_Session *session,
2402 struct GNUNET_TIME_Relative delay)
2404 if (NULL == session->receive_delay_task)
2406 LOG (GNUNET_ERROR_TYPE_DEBUG,
2407 "New inbound delay %s\n",
2408 GNUNET_STRINGS_relative_time_to_string (delay,
2410 session->receive_delay = GNUNET_TIME_relative_to_absolute (delay);
2411 GNUNET_SCHEDULER_cancel (session->receive_delay_task);
2412 session->receive_delay_task = GNUNET_SCHEDULER_add_delayed (delay,
2419 * Create a new session to transmit data to the target
2420 * This session will used to send data to this peer and the plugin will
2421 * notify us by calling the env->session_end function
2423 * @param cls closure
2424 * @param address the address to use
2425 * @return the session if the address is valid, NULL otherwise
2427 static struct GNUNET_ATS_Session *
2428 tcp_plugin_get_session (void *cls,
2429 const struct GNUNET_HELLO_Address *address)
2431 struct Plugin *plugin = cls;
2432 struct GNUNET_ATS_Session *session = NULL;
2436 struct GNUNET_CONNECTION_Handle *sa;
2437 struct sockaddr_in a4;
2438 struct sockaddr_in6 a6;
2439 const struct IPv4TcpAddress *t4;
2440 const struct IPv6TcpAddress *t6;
2441 unsigned int options;
2442 enum GNUNET_ATS_Network_Type net_type;
2443 unsigned int is_natd = GNUNET_NO;
2446 struct GNUNET_NETWORK_Handle *s;
2449 addrlen = address->address_length;
2450 LOG (GNUNET_ERROR_TYPE_DEBUG,
2451 "Trying to get session for `%s' address of peer `%s'\n",
2452 tcp_plugin_address_to_string (plugin,
2454 address->address_length),
2455 GNUNET_i2s (&address->peer));
2457 if (GNUNET_HELLO_address_check_option (address,
2458 GNUNET_HELLO_ADDRESS_INFO_INBOUND))
2464 /* look for existing session */
2466 GNUNET_CONTAINER_multipeermap_contains (plugin->sessionmap,
2469 struct GNUNET_ATS_SessionItCtx si_ctx;
2471 si_ctx.address = address;
2472 si_ctx.result = NULL;
2473 GNUNET_CONTAINER_multipeermap_get_multiple (plugin->sessionmap,
2477 if (NULL != si_ctx.result)
2479 session = si_ctx.result;
2480 LOG (GNUNET_ERROR_TYPE_DEBUG,
2481 "Found existing session for `%s' address `%s'\n",
2482 GNUNET_i2s (&address->peer),
2483 tcp_plugin_address_to_string (plugin,
2485 address->address_length));
2488 /* This is a bit of a hack, limiting TCP to never allow more than
2489 one TCP connection to any given peer at the same time.
2490 Without this, peers sometimes disagree about which of the TCP
2491 connections they should use, causing one side to believe that
2492 they transmit successfully, while the other receives nothing. */
2493 return NULL; /* Refuse to have more than one TCP connection per
2494 peer pair at the same time. */
2497 if (addrlen == sizeof(struct IPv6TcpAddress))
2499 GNUNET_assert (NULL != address->address); /* make static analysis happy */
2500 t6 = address->address;
2501 options = t6->options;
2503 memset (&a6, 0, sizeof(a6));
2504 #if HAVE_SOCKADDR_IN_SIN_LEN
2505 a6.sin6_len = sizeof (a6);
2507 a6.sin6_family = AF_INET6;
2508 a6.sin6_port = t6->t6_port;
2509 if (t6->t6_port == 0)
2510 is_natd = GNUNET_YES;
2511 GNUNET_memcpy (&a6.sin6_addr, &t6->ipv6_addr, sizeof(struct in6_addr));
2515 else if (addrlen == sizeof(struct IPv4TcpAddress))
2517 GNUNET_assert(NULL != address->address); /* make static analysis happy */
2518 t4 = address->address;
2519 options = t4->options;
2521 memset (&a4, 0, sizeof(a4));
2522 #if HAVE_SOCKADDR_IN_SIN_LEN
2523 a4.sin_len = sizeof (a4);
2525 a4.sin_family = AF_INET;
2526 a4.sin_port = t4->t4_port;
2527 if (t4->t4_port == 0)
2528 is_natd = GNUNET_YES;
2529 a4.sin_addr.s_addr = t4->ipv4_addr;
2535 GNUNET_STATISTICS_update (plugin->env->stats,
2536 gettext_noop ("# requests to create session with invalid address"),
2542 net_type = plugin->env->get_address_type (plugin->env->cls,
2545 GNUNET_break (net_type != GNUNET_ATS_NET_UNSPECIFIED);
2547 if ( (is_natd == GNUNET_YES) &&
2548 (addrlen == sizeof(struct IPv6TcpAddress)) )
2550 /* NAT client only works with IPv4 addresses */
2554 if (plugin->cur_connections >= plugin->max_connections)
2560 if ( (is_natd == GNUNET_YES) &&
2562 GNUNET_CONTAINER_multipeermap_contains (plugin->nat_wait_conns,
2565 /* Only do one NAT punch attempt per peer identity */
2569 if ( (is_natd == GNUNET_YES) &&
2570 (NULL != plugin->nat) &&
2572 GNUNET_CONTAINER_multipeermap_contains (plugin->nat_wait_conns,
2575 struct sockaddr_in local_sa;
2577 LOG (GNUNET_ERROR_TYPE_DEBUG,
2578 "Found valid IPv4 NAT address (creating session)!\n");
2579 session = create_session (plugin,
2584 session->nat_connection_timeout = GNUNET_SCHEDULER_add_delayed (NAT_TIMEOUT,
2585 &nat_connect_timeout,
2587 GNUNET_assert (GNUNET_OK ==
2588 GNUNET_CONTAINER_multipeermap_put (plugin->nat_wait_conns,
2591 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
2593 LOG (GNUNET_ERROR_TYPE_DEBUG,
2594 "Created NAT WAIT connection to `%s' at `%s'\n",
2595 GNUNET_i2s (&session->target),
2596 GNUNET_a2s (sb, sbs));
2600 local_sa.sin_family = AF_INET;
2601 local_sa.sin_port = htons (plugin->open_port);
2602 /* We leave sin_address at 0, let the kernel figure it out,
2603 even if our bind() is more specific. (May want to reconsider
2606 GNUNET_NAT_request_reversal (plugin->nat,
2610 LOG (GNUNET_ERROR_TYPE_DEBUG,
2611 "Running NAT client for `%s' at `%s' failed\n",
2612 GNUNET_i2s (&session->target),
2613 GNUNET_a2s (sb, sbs));
2614 tcp_plugin_disconnect_session (plugin,
2619 /* create new outbound session */
2620 if (0 != (options & TCP_OPTIONS_TCP_STEALTH))
2623 s = GNUNET_NETWORK_socket_create (af, SOCK_STREAM, 0);
2626 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK,
2633 GNUNET_NETWORK_socket_setsockopt (s,
2637 sizeof (struct GNUNET_PeerIdentity))) ||
2639 GNUNET_NETWORK_socket_setsockopt (s,
2641 TCP_STEALTH_INTEGRITY,
2642 &plugin->my_welcome,
2643 sizeof (struct WelcomeMessage))) )
2645 /* TCP STEALTH not supported by kernel */
2646 GNUNET_break (GNUNET_OK ==
2647 GNUNET_NETWORK_socket_close (s));
2652 sa = GNUNET_CONNECTION_connect_socket (s, sb, sbs);
2661 sa = GNUNET_CONNECTION_create_from_sockaddr (af, sb, sbs);
2665 LOG (GNUNET_ERROR_TYPE_DEBUG,
2666 "Failed to create connection to `%s' at `%s'\n",
2667 GNUNET_i2s (&address->peer),
2668 GNUNET_a2s (sb, sbs));
2671 LOG (GNUNET_ERROR_TYPE_DEBUG,
2672 "Asked to transmit to `%s', creating fresh session using address `%s'.\n",
2673 GNUNET_i2s (&address->peer),
2674 GNUNET_a2s (sb, sbs));
2676 session = create_session (plugin,
2679 GNUNET_SERVER_connect_socket (plugin->server,
2682 (void) GNUNET_CONTAINER_multipeermap_put (plugin->sessionmap,
2685 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
2686 /* Send TCP Welcome */
2687 process_pending_messages (session);
2694 * We have been asked to destroy all connections to a particular peer.
2695 * This function is called on each applicable session and must tear it
2698 * @param cls the `struct Plugin *`
2699 * @param key the peer which the session belongs to (unused)
2700 * @param value the `struct GNUNET_ATS_Session`
2701 * @return #GNUNET_YES (continue to iterate)
2704 session_disconnect_it (void *cls,
2705 const struct GNUNET_PeerIdentity *key,
2708 struct Plugin *plugin = cls;
2709 struct GNUNET_ATS_Session *session = value;
2711 GNUNET_STATISTICS_update (session->plugin->env->stats,
2712 gettext_noop ("# transport-service disconnect requests for TCP"),
2715 tcp_plugin_disconnect_session (plugin,
2722 * Function that can be called to force a disconnect from the
2723 * specified neighbour. This should also cancel all previously
2724 * scheduled transmissions. Obviously the transmission may have been
2725 * partially completed already, which is OK. The plugin is supposed
2726 * to close the connection (if applicable) and no longer call the
2727 * transmit continuation(s).
2729 * Finally, plugin MUST NOT call the services's receive function to
2730 * notify the service that the connection to the specified target was
2731 * closed after a getting this call.
2733 * @param cls closure
2734 * @param target peer for which the last transmission is
2738 tcp_plugin_disconnect (void *cls,
2739 const struct GNUNET_PeerIdentity *target)
2741 struct Plugin *plugin = cls;
2743 LOG (GNUNET_ERROR_TYPE_DEBUG,
2744 "Disconnecting peer `%s'\n",
2745 GNUNET_i2s (target));
2746 GNUNET_CONTAINER_multipeermap_get_multiple (plugin->sessionmap,
2748 &session_disconnect_it,
2750 GNUNET_CONTAINER_multipeermap_get_multiple (plugin->nat_wait_conns,
2752 &session_disconnect_it,
2758 * We are processing an address pretty printing request and finished
2759 * the IP resolution (if applicable). Append our port and forward the
2760 * result. If called with @a hostname NULL, we are done and should
2761 * clean up the pretty printer (otherwise, there might be multiple
2762 * hostnames for the IP address and we might receive more).
2764 * @param cls the `struct PrettyPrinterContext *`
2765 * @param hostname hostname part of the address
2768 append_port (void *cls,
2769 const char *hostname)
2771 struct PrettyPrinterContext *ppc = cls;
2772 struct Plugin *plugin = ppc->plugin;
2775 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2776 "append_port called with hostname `%s'\n",
2778 if (NULL == hostname)
2780 /* Final call, done */
2781 ppc->resolver_handle = NULL;
2782 GNUNET_CONTAINER_DLL_remove (plugin->ppc_dll_head,
2783 plugin->ppc_dll_tail,
2785 ppc->asc (ppc->asc_cls,
2791 if (GNUNET_YES == ppc->ipv6)
2792 GNUNET_asprintf (&ret,
2799 GNUNET_asprintf (&ret,
2805 ppc->asc (ppc->asc_cls,
2813 * Convert the transports address to a nice, human-readable format.
2815 * @param cls closure with the `struct Plugin`
2816 * @param type name of the transport that generated the address
2817 * @param addr one of the addresses of the host, NULL for the last address
2818 * the specific address format depends on the transport
2819 * @param addrlen length of the @a addr
2820 * @param numeric should (IP) addresses be displayed in numeric form?
2821 * @param timeout after how long should we give up?
2822 * @param asc function to call on each string
2823 * @param asc_cls closure for @a asc
2826 tcp_plugin_address_pretty_printer (void *cls,
2831 struct GNUNET_TIME_Relative timeout,
2832 GNUNET_TRANSPORT_AddressStringCallback asc,
2835 struct Plugin *plugin = cls;
2836 struct PrettyPrinterContext *ppc;
2839 struct sockaddr_in a4;
2840 struct sockaddr_in6 a6;
2841 const struct IPv4TcpAddress *t4;
2842 const struct IPv6TcpAddress *t6;
2846 if (sizeof(struct IPv6TcpAddress) == addrlen)
2849 memset (&a6, 0, sizeof(a6));
2850 a6.sin6_family = AF_INET6;
2851 a6.sin6_port = t6->t6_port;
2852 GNUNET_memcpy (&a6.sin6_addr, &t6->ipv6_addr, sizeof(struct in6_addr));
2853 port = ntohs (t6->t6_port);
2854 options = ntohl (t6->options);
2858 else if (sizeof(struct IPv4TcpAddress) == addrlen)
2861 memset (&a4, 0, sizeof(a4));
2862 a4.sin_family = AF_INET;
2863 a4.sin_port = t4->t4_port;
2864 a4.sin_addr.s_addr = t4->ipv4_addr;
2865 port = ntohs (t4->t4_port);
2866 options = ntohl (t4->options);
2872 /* invalid address */
2873 LOG (GNUNET_ERROR_TYPE_WARNING,
2874 _("Unexpected address length: %u bytes\n"),
2875 (unsigned int) addrlen);
2876 asc (asc_cls, NULL, GNUNET_SYSERR);
2877 asc (asc_cls, NULL, GNUNET_OK);
2880 ppc = GNUNET_new (struct PrettyPrinterContext);
2881 ppc->plugin = plugin;
2882 if (addrlen == sizeof(struct IPv6TcpAddress))
2883 ppc->ipv6 = GNUNET_YES;
2885 ppc->ipv6 = GNUNET_NO;
2887 ppc->asc_cls = asc_cls;
2889 ppc->options = options;
2890 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2891 "Starting DNS reverse lookup\n");
2892 ppc->resolver_handle = GNUNET_RESOLVER_hostname_get (sb,
2898 if (NULL == ppc->resolver_handle)
2904 GNUNET_CONTAINER_DLL_insert (plugin->ppc_dll_head,
2905 plugin->ppc_dll_tail,
2911 * Function that will be called to check if a binary address for this
2912 * plugin is well-formed and corresponds to an address for THIS peer
2913 * (as per our configuration). Naturally, if absolutely necessary,
2914 * plugins can be a bit conservative in their answer, but in general
2915 * plugins should make sure that the address does not redirect
2916 * traffic to a 3rd party that might try to man-in-the-middle our
2919 * @param cls closure, our `struct Plugin *`
2920 * @param addr pointer to the address
2921 * @param addrlen length of @a addr
2922 * @return #GNUNET_OK if this is a plausible address for this peer
2923 * and transport, #GNUNET_SYSERR if not
2926 tcp_plugin_check_address (void *cls,
2930 struct Plugin *plugin = cls;
2931 const struct IPv4TcpAddress *v4;
2932 const struct IPv6TcpAddress *v6;
2934 if ( (addrlen != sizeof(struct IPv4TcpAddress)) &&
2935 (addrlen != sizeof(struct IPv6TcpAddress)) )
2937 GNUNET_break_op (0);
2938 return GNUNET_SYSERR;
2941 if (addrlen == sizeof(struct IPv4TcpAddress))
2943 struct sockaddr_in s4;
2945 v4 = (const struct IPv4TcpAddress *) addr;
2946 if (0 != memcmp (&v4->options,
2951 return GNUNET_SYSERR;
2953 memset (&s4, 0, sizeof (s4));
2954 s4.sin_family = AF_INET;
2955 #if HAVE_SOCKADDR_IN_SIN_LEN
2956 s4.sin_len = sizeof (s4);
2958 s4.sin_port = v4->t4_port;
2959 s4.sin_addr.s_addr = v4->ipv4_addr;
2962 GNUNET_NAT_test_address (plugin->nat,
2964 sizeof (struct sockaddr_in)))
2965 return GNUNET_SYSERR;
2969 struct sockaddr_in6 s6;
2971 v6 = (const struct IPv6TcpAddress *) addr;
2972 if (IN6_IS_ADDR_LINKLOCAL (&v6->ipv6_addr))
2974 GNUNET_break_op (0);
2975 return GNUNET_SYSERR;
2977 if (0 != memcmp (&v6->options,
2982 return GNUNET_SYSERR;
2984 memset (&s6, 0, sizeof (s6));
2985 s6.sin6_family = AF_INET6;
2986 #if HAVE_SOCKADDR_IN_SIN_LEN
2987 s6.sin6_len = sizeof (s6);
2989 s6.sin6_port = v6->t6_port;
2990 s6.sin6_addr = v6->ipv6_addr;
2993 GNUNET_NAT_test_address (plugin->nat,
2995 sizeof(struct sockaddr_in6)))
2996 return GNUNET_SYSERR;
3003 * We've received a nat probe from this peer via TCP. Finish
3004 * creating the client session and resume sending of queued
3007 * @param cls closure
3008 * @param client identification of the client
3009 * @param message the actual message
3012 handle_tcp_nat_probe (void *cls,
3013 struct GNUNET_SERVER_Client *client,
3014 const struct GNUNET_MessageHeader *message)
3016 struct Plugin *plugin = cls;
3017 struct GNUNET_ATS_Session *session;
3018 const struct TCP_NAT_ProbeMessage *tcp_nat_probe;
3021 struct IPv4TcpAddress *t4;
3022 struct IPv6TcpAddress *t6;
3023 const struct sockaddr_in *s4;
3024 const struct sockaddr_in6 *s6;
3026 LOG (GNUNET_ERROR_TYPE_DEBUG,
3027 "Received NAT probe\n");
3028 /* We have received a TCP NAT probe, meaning we (hopefully) initiated
3029 * a connection to this peer by running gnunet-nat-client. This peer
3030 * received the punch message and now wants us to use the new connection
3031 * as the default for that peer. Do so and then send a WELCOME message
3032 * so we can really be connected!
3034 if (ntohs (message->size) != sizeof(struct TCP_NAT_ProbeMessage))
3037 GNUNET_SERVER_receive_done (client,
3042 tcp_nat_probe = (const struct TCP_NAT_ProbeMessage *) message;
3043 if (0 == memcmp (&tcp_nat_probe->clientIdentity, plugin->env->my_identity,
3044 sizeof(struct GNUNET_PeerIdentity)))
3046 /* refuse connections from ourselves */
3047 GNUNET_SERVER_receive_done (client,
3052 session = GNUNET_CONTAINER_multipeermap_get (plugin->nat_wait_conns,
3053 &tcp_nat_probe->clientIdentity);
3054 if (NULL == session)
3056 LOG (GNUNET_ERROR_TYPE_DEBUG,
3057 "Did NOT find session for NAT probe!\n");
3058 GNUNET_SERVER_receive_done (client,
3062 LOG (GNUNET_ERROR_TYPE_DEBUG,
3063 "Found session for NAT probe!\n");
3065 if (NULL != session->nat_connection_timeout)
3067 GNUNET_SCHEDULER_cancel (session->nat_connection_timeout);
3068 session->nat_connection_timeout = NULL;
3072 GNUNET_SERVER_client_get_address (client,
3077 GNUNET_SERVER_receive_done (client,
3079 tcp_plugin_disconnect_session (plugin,
3083 GNUNET_assert (GNUNET_YES ==
3084 GNUNET_CONTAINER_multipeermap_remove (plugin->nat_wait_conns,
3085 &tcp_nat_probe->clientIdentity,
3087 GNUNET_SERVER_client_set_user_context (client,
3089 (void) GNUNET_CONTAINER_multipeermap_put (plugin->sessionmap,
3092 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
3093 session->last_activity = GNUNET_TIME_absolute_get ();
3094 LOG (GNUNET_ERROR_TYPE_DEBUG,
3095 "Found address `%s' for incoming connection\n",
3096 GNUNET_a2s (vaddr, alen));
3097 switch (((const struct sockaddr *) vaddr)->sa_family)
3101 t4 = GNUNET_new (struct IPv4TcpAddress);
3102 t4->options = htonl (TCP_OPTIONS_NONE);
3103 t4->t4_port = s4->sin_port;
3104 t4->ipv4_addr = s4->sin_addr.s_addr;
3105 session->address = GNUNET_HELLO_address_allocate (&tcp_nat_probe->clientIdentity,
3108 sizeof(struct IPv4TcpAddress),
3109 GNUNET_HELLO_ADDRESS_INFO_NONE);
3113 t6 = GNUNET_new (struct IPv6TcpAddress);
3114 t6->options = htonl (TCP_OPTIONS_NONE);
3115 t6->t6_port = s6->sin6_port;
3116 GNUNET_memcpy (&t6->ipv6_addr, &s6->sin6_addr, sizeof(struct in6_addr));
3117 session->address = GNUNET_HELLO_address_allocate (&tcp_nat_probe->clientIdentity,
3120 sizeof(struct IPv6TcpAddress),
3121 GNUNET_HELLO_ADDRESS_INFO_NONE);
3125 LOG(GNUNET_ERROR_TYPE_DEBUG,
3126 "Bad address for incoming connection!\n");
3128 GNUNET_SERVER_receive_done (client,
3130 tcp_plugin_disconnect_session (plugin,
3134 GNUNET_free (vaddr);
3135 GNUNET_break (NULL == session->client);
3136 session->client = client;
3137 GNUNET_STATISTICS_update (plugin->env->stats,
3138 gettext_noop ("# TCP sessions active"),
3141 process_pending_messages (session);
3142 GNUNET_SERVER_receive_done (client,
3148 * We've received a welcome from this peer via TCP. Possibly create a
3149 * fresh client record and send back our welcome.
3151 * @param cls closure
3152 * @param client identification of the client
3153 * @param message the actual message
3156 handle_tcp_welcome (void *cls,
3157 struct GNUNET_SERVER_Client *client,
3158 const struct GNUNET_MessageHeader *message)
3160 struct Plugin *plugin = cls;
3161 const struct WelcomeMessage *wm = (const struct WelcomeMessage *) message;
3162 struct GNUNET_HELLO_Address *address;
3163 struct GNUNET_ATS_Session *session;
3166 struct IPv4TcpAddress t4;
3167 struct IPv6TcpAddress t6;
3168 const struct sockaddr_in *s4;
3169 const struct sockaddr_in6 *s6;
3171 if (0 == memcmp (&wm->clientIdentity,
3172 plugin->env->my_identity,
3173 sizeof(struct GNUNET_PeerIdentity)))
3175 /* refuse connections from ourselves */
3177 GNUNET_SERVER_client_get_address (client,
3181 LOG (GNUNET_ERROR_TYPE_INFO,
3182 "Received WELCOME message from my own identity `%s' on address `%s'\n",
3183 GNUNET_i2s (&wm->clientIdentity),
3184 GNUNET_a2s (vaddr, alen));
3185 GNUNET_free (vaddr);
3187 GNUNET_SERVER_receive_done (client,
3193 GNUNET_SERVER_client_get_address (client,
3197 LOG(GNUNET_ERROR_TYPE_DEBUG,
3198 "Received WELCOME message from `%s' on address `%s'\n",
3199 GNUNET_i2s (&wm->clientIdentity),
3200 GNUNET_a2s (vaddr, alen));
3201 GNUNET_free (vaddr);
3203 GNUNET_STATISTICS_update (plugin->env->stats,
3204 gettext_noop ("# TCP WELCOME messages received"),
3207 session = lookup_session_by_client (plugin,
3209 if (NULL != session)
3212 GNUNET_SERVER_client_get_address (client,
3216 LOG (GNUNET_ERROR_TYPE_DEBUG,
3217 "Found existing session %p for peer `%s'\n",
3219 GNUNET_a2s (vaddr, alen));
3220 GNUNET_free (vaddr);
3226 GNUNET_SERVER_client_get_address (client, &vaddr, &alen))
3228 if (alen == sizeof(struct sockaddr_in))
3231 memset (&t4, '\0', sizeof (t4));
3232 t4.options = htonl (TCP_OPTIONS_NONE);
3233 t4.t4_port = s4->sin_port;
3234 t4.ipv4_addr = s4->sin_addr.s_addr;
3235 address = GNUNET_HELLO_address_allocate (&wm->clientIdentity,
3239 GNUNET_HELLO_ADDRESS_INFO_INBOUND);
3241 else if (alen == sizeof(struct sockaddr_in6))
3244 memset (&t6, '\0', sizeof (t6));
3245 t6.options = htonl (TCP_OPTIONS_NONE);
3246 t6.t6_port = s6->sin6_port;
3247 GNUNET_memcpy (&t6.ipv6_addr, &s6->sin6_addr, sizeof(struct in6_addr));
3248 address = GNUNET_HELLO_address_allocate (&wm->clientIdentity,
3252 GNUNET_HELLO_ADDRESS_INFO_INBOUND);
3257 GNUNET_free_non_null (vaddr);
3258 GNUNET_SERVER_receive_done (client,
3262 session = create_session (plugin,
3264 plugin->env->get_address_type (plugin->env->cls,
3269 GNUNET_break (GNUNET_ATS_NET_UNSPECIFIED != session->scope);
3270 GNUNET_HELLO_address_free (address);
3271 LOG (GNUNET_ERROR_TYPE_DEBUG,
3272 "Creating new%s session %p for peer `%s' client %p\n",
3273 GNUNET_HELLO_address_check_option (session->address,
3274 GNUNET_HELLO_ADDRESS_INFO_INBOUND)
3277 tcp_plugin_address_to_string (plugin,
3278 session->address->address,
3279 session->address->address_length),
3281 GNUNET_free (vaddr);
3282 (void) GNUNET_CONTAINER_multipeermap_put (plugin->sessionmap,
3285 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
3286 /* Notify transport and ATS about new session */
3287 plugin->env->session_start (plugin->env->cls,
3294 LOG(GNUNET_ERROR_TYPE_DEBUG,
3295 "Did not obtain TCP socket address for incoming connection\n");
3297 GNUNET_SERVER_receive_done (client,
3303 if (GNUNET_YES != session->expecting_welcome)
3305 GNUNET_break_op (0);
3306 GNUNET_SERVER_receive_done (client,
3310 session->last_activity = GNUNET_TIME_absolute_get ();
3311 session->expecting_welcome = GNUNET_NO;
3313 process_pending_messages (session);
3314 GNUNET_SERVER_client_set_timeout (client,
3315 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
3316 GNUNET_SERVER_receive_done (client,
3322 * We've received data for this peer via TCP. Unbox,
3323 * compute latency and forward.
3325 * @param cls closure
3326 * @param client identification of the client
3327 * @param message the actual message
3330 handle_tcp_data (void *cls,
3331 struct GNUNET_SERVER_Client *client,
3332 const struct GNUNET_MessageHeader *message)
3334 struct Plugin *plugin = cls;
3335 struct GNUNET_ATS_Session *session;
3336 struct GNUNET_TIME_Relative delay;
3339 type = ntohs (message->type);
3340 if ( (GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_WELCOME == type) ||
3341 (GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_NAT_PROBE == type) )
3343 /* We don't want to propagate WELCOME and NAT Probe messages up! */
3344 GNUNET_SERVER_receive_done (client,
3348 session = lookup_session_by_client (plugin, client);
3349 if (NULL == session)
3351 /* No inbound session found */
3355 GNUNET_assert (GNUNET_OK ==
3356 GNUNET_SERVER_client_get_address (client,
3359 LOG (GNUNET_ERROR_TYPE_ERROR,
3360 "Received unexpected %u bytes of type %u from `%s'\n",
3361 (unsigned int) ntohs (message->size),
3362 (unsigned int) ntohs (message->type),
3366 GNUNET_SERVER_receive_done (client,
3368 GNUNET_free_non_null (vaddr);
3371 if (GNUNET_YES == session->expecting_welcome)
3373 /* Session is expecting WELCOME message */
3377 GNUNET_SERVER_client_get_address (client,
3380 LOG (GNUNET_ERROR_TYPE_ERROR,
3381 "Received unexpected %u bytes of type %u from `%s'\n",
3382 (unsigned int) ntohs (message->size),
3383 (unsigned int) ntohs (message->type),
3384 GNUNET_a2s (vaddr, alen));
3386 GNUNET_SERVER_receive_done (client,
3388 GNUNET_free_non_null (vaddr);
3392 session->last_activity = GNUNET_TIME_absolute_get ();
3397 GNUNET_SERVER_client_get_address (client,
3400 LOG (GNUNET_ERROR_TYPE_DEBUG,
3401 "Passing %u bytes of type %u from `%s' at %s to transport service.\n",
3402 (unsigned int) ntohs (message->size),
3403 (unsigned int) ntohs (message->type),
3404 GNUNET_i2s (&session->target),
3405 GNUNET_a2s (vaddr, alen));
3406 GNUNET_free_non_null (vaddr);
3409 GNUNET_STATISTICS_update (plugin->env->stats,
3410 gettext_noop ("# bytes received via TCP"),
3411 ntohs (message->size),
3414 GNUNET_assert (GNUNET_CONTAINER_multipeermap_contains_value (plugin->sessionmap,
3417 delay = plugin->env->receive (plugin->env->cls,
3421 reschedule_session_timeout (session);
3422 if (0 == delay.rel_value_us)
3424 GNUNET_SERVER_receive_done (client,
3429 LOG (GNUNET_ERROR_TYPE_DEBUG,
3430 "Throttling receiving from `%s' for %s\n",
3431 GNUNET_i2s (&session->target),
3432 GNUNET_STRINGS_relative_time_to_string (delay,
3434 GNUNET_SERVER_disable_receive_done_warning (client);
3435 GNUNET_assert (NULL == session->receive_delay_task);
3436 session->receive_delay_task = GNUNET_SCHEDULER_add_delayed (delay,
3444 * Function called whenever a peer is connected on the "SERVER" level.
3445 * Increments number of active connections and suspends server if we
3446 * have reached the limit.
3448 * @param cls closure
3449 * @param client identification of the client
3452 connect_notify (void *cls,
3453 struct GNUNET_SERVER_Client *client)
3455 struct Plugin *plugin = cls;
3459 plugin->cur_connections++;
3460 GNUNET_STATISTICS_set (plugin->env->stats,
3461 gettext_noop ("# TCP server connections active"),
3462 plugin->cur_connections,
3464 GNUNET_STATISTICS_update (plugin->env->stats,
3465 gettext_noop ("# TCP server connect events"),
3468 if (plugin->cur_connections != plugin->max_connections)
3470 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3471 _("TCP connection limit reached, suspending server\n"));
3472 GNUNET_STATISTICS_update (plugin->env->stats,
3473 gettext_noop ("# TCP service suspended"),
3476 GNUNET_SERVER_suspend (plugin->server); /* Maximum number of connections rechead */
3481 * Function called whenever a peer is disconnected on the "SERVER"
3482 * level. Cleans up the connection, decrements number of active
3483 * connections and if applicable resumes listening.
3485 * @param cls closure
3486 * @param client identification of the client
3489 disconnect_notify (void *cls,
3490 struct GNUNET_SERVER_Client *client)
3492 struct Plugin *plugin = cls;
3493 struct GNUNET_ATS_Session *session;
3497 GNUNET_assert (plugin->cur_connections >= 1);
3498 plugin->cur_connections--;
3499 session = lookup_session_by_client (plugin,
3501 if (NULL == session)
3502 return; /* unknown, nothing to do */
3503 LOG (GNUNET_ERROR_TYPE_DEBUG,
3504 "Destroying session of `%s' with %s due to network-level disconnect.\n",
3505 GNUNET_i2s (&session->target),
3506 tcp_plugin_address_to_string (session->plugin,
3507 session->address->address,
3508 session->address->address_length));
3510 if (plugin->cur_connections == plugin->max_connections)
3512 GNUNET_STATISTICS_update (session->plugin->env->stats,
3513 gettext_noop ("# TCP service resumed"),
3516 GNUNET_SERVER_resume (plugin->server); /* Resume server */
3518 GNUNET_STATISTICS_set (plugin->env->stats,
3519 gettext_noop ("# TCP server connections active"),
3520 plugin->cur_connections,
3522 GNUNET_STATISTICS_update (session->plugin->env->stats,
3523 gettext_noop ("# network-level TCP disconnect events"),
3526 tcp_plugin_disconnect_session (plugin,
3532 * We can now send a probe message, copy into buffer to really send.
3534 * @param cls closure, a `struct TCPProbeContext`
3535 * @param size max size to copy
3536 * @param buf buffer to copy message to
3537 * @return number of bytes copied into @a buf
3540 notify_send_probe (void *cls,
3544 struct TCPProbeContext *tcp_probe_ctx = cls;
3545 struct Plugin *plugin = tcp_probe_ctx->plugin;
3548 tcp_probe_ctx->transmit_handle = NULL;
3549 GNUNET_CONTAINER_DLL_remove (plugin->probe_head,
3554 GNUNET_CONNECTION_destroy (tcp_probe_ctx->sock);
3555 GNUNET_free(tcp_probe_ctx);
3558 GNUNET_assert(size >= sizeof(tcp_probe_ctx->message));
3560 &tcp_probe_ctx->message,
3561 sizeof(tcp_probe_ctx->message));
3562 GNUNET_SERVER_connect_socket (tcp_probe_ctx->plugin->server,
3563 tcp_probe_ctx->sock);
3564 ret = sizeof(tcp_probe_ctx->message);
3565 GNUNET_free (tcp_probe_ctx);
3571 * Function called by the NAT subsystem suggesting another peer wants
3572 * to connect to us via connection reversal. Try to connect back to the
3575 * @param cls closure
3576 * @param addr address to try
3577 * @param addrlen number of bytes in @a addr
3580 try_connection_reversal (void *cls,
3581 const struct sockaddr *addr,
3584 struct Plugin *plugin = cls;
3585 struct GNUNET_CONNECTION_Handle *sock;
3586 struct TCPProbeContext *tcp_probe_ctx;
3589 * We have received an ICMP response, ostensibly from a peer
3590 * that wants to connect to us! Send a message to establish a connection.
3592 sock = GNUNET_CONNECTION_create_from_sockaddr (AF_INET,
3597 /* failed for some odd reason (out of sockets?); ignore attempt */
3601 tcp_probe_ctx = GNUNET_new (struct TCPProbeContext);
3602 tcp_probe_ctx->message.header.size
3603 = htons (sizeof (struct TCP_NAT_ProbeMessage));
3604 tcp_probe_ctx->message.header.type
3605 = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_NAT_PROBE);
3606 tcp_probe_ctx->message.clientIdentity
3607 = *plugin->env->my_identity;
3608 tcp_probe_ctx->plugin = plugin;
3609 tcp_probe_ctx->sock = sock;
3610 GNUNET_CONTAINER_DLL_insert (plugin->probe_head,
3613 tcp_probe_ctx->transmit_handle
3614 = GNUNET_CONNECTION_notify_transmit_ready (sock,
3615 ntohs (tcp_probe_ctx->message.header.size),
3616 GNUNET_TIME_UNIT_FOREVER_REL,
3623 * Function obtain the network type for a session
3625 * @param cls closure (`struct Plugin *`)
3626 * @param session the session
3627 * @return the network type in HBO or #GNUNET_SYSERR
3629 static enum GNUNET_ATS_Network_Type
3630 tcp_plugin_get_network (void *cls,
3631 struct GNUNET_ATS_Session *session)
3633 return session->scope;
3638 * Function obtain the network type for an address.
3640 * @param cls closure (`struct Plugin *`)
3641 * @param address the address
3642 * @return the network type
3644 static enum GNUNET_ATS_Network_Type
3645 tcp_plugin_get_network_for_address (void *cls,
3646 const struct GNUNET_HELLO_Address *address)
3648 struct Plugin *plugin = cls;
3650 struct sockaddr_in a4;
3651 struct sockaddr_in6 a6;
3652 const struct IPv4TcpAddress *t4;
3653 const struct IPv6TcpAddress *t6;
3657 addrlen = address->address_length;
3658 if (addrlen == sizeof(struct IPv6TcpAddress))
3660 GNUNET_assert (NULL != address->address); /* make static analysis happy */
3661 t6 = address->address;
3662 memset (&a6, 0, sizeof(a6));
3663 #if HAVE_SOCKADDR_IN_SIN_LEN
3664 a6.sin6_len = sizeof (a6);
3666 a6.sin6_family = AF_INET6;
3667 a6.sin6_port = t6->t6_port;
3668 GNUNET_memcpy (&a6.sin6_addr, &t6->ipv6_addr, sizeof(struct in6_addr));
3672 else if (addrlen == sizeof(struct IPv4TcpAddress))
3674 GNUNET_assert (NULL != address->address); /* make static analysis happy */
3675 t4 = address->address;
3676 memset (&a4, 0, sizeof(a4));
3677 #if HAVE_SOCKADDR_IN_SIN_LEN
3678 a4.sin_len = sizeof (a4);
3680 a4.sin_family = AF_INET;
3681 a4.sin_port = t4->t4_port;
3682 a4.sin_addr.s_addr = t4->ipv4_addr;
3689 return GNUNET_ATS_NET_UNSPECIFIED;
3691 return plugin->env->get_address_type (plugin->env->cls,
3698 * Return information about the given session to the
3701 * @param cls the `struct Plugin` with the monitor callback (`sic`)
3702 * @param peer peer we send information about
3703 * @param value our `struct GNUNET_ATS_Session` to send information about
3704 * @return #GNUNET_OK (continue to iterate)
3707 send_session_info_iter (void *cls,
3708 const struct GNUNET_PeerIdentity *peer,
3711 struct Plugin *plugin = cls;
3712 struct GNUNET_ATS_Session *session = value;
3714 notify_session_monitor (plugin,
3716 GNUNET_TRANSPORT_SS_INIT);
3717 /* FIXME: cannot tell if this is up or not from current
3719 notify_session_monitor (plugin,
3721 GNUNET_TRANSPORT_SS_UP);
3727 * Begin monitoring sessions of a plugin. There can only
3728 * be one active monitor per plugin (i.e. if there are
3729 * multiple monitors, the transport service needs to
3730 * multiplex the generated events over all of them).
3732 * @param cls closure of the plugin
3733 * @param sic callback to invoke, NULL to disable monitor;
3734 * plugin will being by iterating over all active
3735 * sessions immediately and then enter monitor mode
3736 * @param sic_cls closure for @a sic
3739 tcp_plugin_setup_monitor (void *cls,
3740 GNUNET_TRANSPORT_SessionInfoCallback sic,
3743 struct Plugin *plugin = cls;
3746 plugin->sic_cls = sic_cls;
3749 GNUNET_CONTAINER_multipeermap_iterate (plugin->sessionmap,
3750 &send_session_info_iter,
3752 /* signal end of first iteration */
3753 sic (sic_cls, NULL, NULL);
3759 * Entry point for the plugin.
3761 * @param cls closure, the `struct GNUNET_TRANSPORT_PluginEnvironment *`
3762 * @return the `struct GNUNET_TRANSPORT_PluginFunctions *` or NULL on error
3765 libgnunet_plugin_transport_xt_init (void *cls)
3767 static const struct GNUNET_SERVER_MessageHandler my_handlers[] = {
3768 { &handle_tcp_welcome, NULL,
3769 GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_WELCOME,
3770 sizeof(struct WelcomeMessage) },
3771 { &handle_tcp_nat_probe, NULL,
3772 GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_NAT_PROBE,
3773 sizeof(struct TCP_NAT_ProbeMessage) },
3774 { &handle_tcp_data, NULL,
3775 GNUNET_MESSAGE_TYPE_ALL, 0 },
3776 { NULL, NULL, 0, 0 }
3778 struct GNUNET_TRANSPORT_PluginEnvironment *env = cls;
3779 struct GNUNET_TRANSPORT_PluginFunctions *api;
3780 struct Plugin *plugin;
3781 struct LEGACY_SERVICE_Context *service;
3782 unsigned long long aport;
3783 unsigned long long bport;
3784 unsigned long long max_connections;
3786 struct GNUNET_TIME_Relative idle_timeout;
3788 struct GNUNET_NETWORK_Handle *const*lsocks;
3792 struct sockaddr **addrs;
3793 socklen_t *addrlens;
3795 if (NULL == env->receive)
3797 /* run in 'stub' mode (i.e. as part of gnunet-peerinfo), don't fully
3798 initialze the plugin or the API */
3799 api = GNUNET_new (struct GNUNET_TRANSPORT_PluginFunctions);
3801 api->address_pretty_printer = &tcp_plugin_address_pretty_printer;
3802 api->address_to_string = &tcp_plugin_address_to_string;
3803 api->string_to_address = &tcp_plugin_string_to_address;
3807 GNUNET_assert (NULL != env->cfg);
3809 GNUNET_CONFIGURATION_get_value_number (env->cfg,
3813 max_connections = 128;
3817 GNUNET_CONFIGURATION_get_value_number (env->cfg,
3822 GNUNET_CONFIGURATION_get_value_number (env->cfg,
3824 "ADVERTISED-PORT", &aport)) &&
3827 LOG(GNUNET_ERROR_TYPE_ERROR,
3828 _("Require valid port number for service `%s' in configuration!\n"),
3838 service = LEGACY_SERVICE_start ("transport-xt",
3840 LEGACY_SERVICE_OPTION_NONE);
3841 if (NULL == service)
3843 LOG (GNUNET_ERROR_TYPE_WARNING,
3844 _("Failed to start service.\n"));
3852 plugin = GNUNET_new (struct Plugin);
3853 plugin->sessionmap = GNUNET_CONTAINER_multipeermap_create (max_connections,
3855 plugin->max_connections = max_connections;
3856 plugin->open_port = bport;
3857 plugin->adv_port = aport;
3859 plugin->my_welcome.header.size = htons (sizeof(struct WelcomeMessage));
3860 plugin->my_welcome.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_WELCOME);
3861 plugin->my_welcome.clientIdentity = *plugin->env->my_identity;
3863 if ( (NULL != service) &&
3865 GNUNET_CONFIGURATION_get_value_yesno (env->cfg,
3870 plugin->myoptions |= TCP_OPTIONS_TCP_STEALTH;
3871 lsocks = LEGACY_SERVICE_get_listen_sockets (service);
3874 uint32_t len = sizeof (struct WelcomeMessage);
3876 for (i=0;NULL!=lsocks[i];i++)
3879 GNUNET_NETWORK_socket_setsockopt (lsocks[i],
3883 sizeof (struct GNUNET_PeerIdentity))) ||
3885 GNUNET_NETWORK_socket_setsockopt (lsocks[i],
3887 TCP_STEALTH_INTEGRITY_LEN,
3891 /* TCP STEALTH not supported by kernel */
3892 GNUNET_assert (0 == i);
3893 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3894 _("TCP_STEALTH not supported on this platform.\n"));
3900 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3901 _("TCP_STEALTH not supported on this platform.\n"));
3906 if ( (NULL != service) &&
3909 get_server_addresses ("transport-xt",
3914 for (ret = ret_s-1; ret >= 0; ret--)
3915 LOG (GNUNET_ERROR_TYPE_INFO,
3916 "Binding to address `%s'\n",
3917 GNUNET_a2s (addrs[ret], addrlens[ret]));
3919 = GNUNET_NAT_register (env->cfg,
3922 (unsigned int) ret_s,
3923 (const struct sockaddr **) addrs,
3925 &tcp_nat_port_map_callback,
3926 &try_connection_reversal,
3928 for (ret = ret_s -1; ret >= 0; ret--)
3929 GNUNET_free (addrs[ret]);
3930 GNUNET_free_non_null (addrs);
3931 GNUNET_free_non_null (addrlens);
3935 plugin->nat = GNUNET_NAT_register (plugin->env->cfg,
3942 &try_connection_reversal,
3945 api = GNUNET_new (struct GNUNET_TRANSPORT_PluginFunctions);
3947 api->send = &tcp_plugin_send;
3948 api->get_session = &tcp_plugin_get_session;
3949 api->disconnect_session = &tcp_plugin_disconnect_session;
3950 api->query_keepalive_factor = &tcp_plugin_query_keepalive_factor;
3951 api->disconnect_peer = &tcp_plugin_disconnect;
3952 api->address_pretty_printer = &tcp_plugin_address_pretty_printer;
3953 api->check_address = &tcp_plugin_check_address;
3954 api->address_to_string = &tcp_plugin_address_to_string;
3955 api->string_to_address = &tcp_plugin_string_to_address;
3956 api->get_network = &tcp_plugin_get_network;
3957 api->get_network_for_address = &tcp_plugin_get_network_for_address;
3958 api->update_session_timeout = &tcp_plugin_update_session_timeout;
3959 api->update_inbound_delay = &tcp_plugin_update_inbound_delay;
3960 api->setup_monitor = &tcp_plugin_setup_monitor;
3961 plugin->service = service;
3962 if (NULL != service)
3964 plugin->server = LEGACY_SERVICE_get_server (service);
3969 GNUNET_CONFIGURATION_get_value_time (env->cfg,
3974 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
3980 = GNUNET_SERVER_create_with_sockets (NULL,
3986 plugin->handlers = GNUNET_malloc (sizeof (my_handlers));
3987 GNUNET_memcpy (plugin->handlers,
3989 sizeof(my_handlers));
3990 for (i = 0;i < sizeof(my_handlers) / sizeof(struct GNUNET_SERVER_MessageHandler);i++)
3991 plugin->handlers[i].callback_cls = plugin;
3993 GNUNET_SERVER_add_handlers (plugin->server,
3995 GNUNET_SERVER_connect_notify (plugin->server,
3998 GNUNET_SERVER_disconnect_notify (plugin->server,
4001 plugin->nat_wait_conns = GNUNET_CONTAINER_multipeermap_create (16,
4004 LOG (GNUNET_ERROR_TYPE_INFO,
4005 _("XT transport listening on port %llu\n"),
4008 LOG (GNUNET_ERROR_TYPE_INFO,
4009 _("XT transport not listening on any port (client only)\n"));
4010 if ( (aport != bport) &&
4012 LOG (GNUNET_ERROR_TYPE_INFO,
4013 _("XT transport advertises itself as being on port %llu\n"),
4015 /* Initially set connections to 0 */
4016 GNUNET_STATISTICS_set (plugin->env->stats,
4017 gettext_noop ("# XT sessions active"),
4023 if (NULL != plugin->nat)
4024 GNUNET_NAT_unregister (plugin->nat);
4025 GNUNET_CONTAINER_multipeermap_destroy (plugin->sessionmap);
4026 if (NULL != service)
4027 LEGACY_SERVICE_stop (service);
4028 GNUNET_free (plugin);
4029 GNUNET_free_non_null (api);
4035 * Exit point from the plugin.
4037 * @param cls the `struct GNUNET_TRANSPORT_PluginFunctions`
4041 libgnunet_plugin_transport_xt_done (void *cls)
4043 struct GNUNET_TRANSPORT_PluginFunctions *api = cls;
4044 struct Plugin *plugin = api->cls;
4045 struct TCPProbeContext *tcp_probe;
4046 struct PrettyPrinterContext *cur;
4047 struct PrettyPrinterContext *next;
4054 LOG (GNUNET_ERROR_TYPE_DEBUG,
4055 "Shutting down XT plugin\n");
4057 /* Removing leftover sessions */
4058 GNUNET_CONTAINER_multipeermap_iterate (plugin->sessionmap,
4059 &session_disconnect_it,
4061 /* Removing leftover NAT sessions */
4062 GNUNET_CONTAINER_multipeermap_iterate (plugin->nat_wait_conns,
4063 &session_disconnect_it,
4066 for (cur = plugin->ppc_dll_head; NULL != cur; cur = next)
4069 GNUNET_CONTAINER_DLL_remove (plugin->ppc_dll_head,
4070 plugin->ppc_dll_tail,
4072 GNUNET_RESOLVER_request_cancel (cur->resolver_handle);
4073 cur->asc (cur->asc_cls,
4079 if (NULL != plugin->service)
4080 LEGACY_SERVICE_stop (plugin->service);
4082 GNUNET_SERVER_destroy (plugin->server);
4083 GNUNET_free (plugin->handlers);
4084 if (NULL != plugin->nat)
4085 GNUNET_NAT_unregister (plugin->nat);
4086 while (NULL != (tcp_probe = plugin->probe_head))
4088 GNUNET_CONTAINER_DLL_remove (plugin->probe_head,
4091 GNUNET_CONNECTION_destroy (tcp_probe->sock);
4092 GNUNET_free (tcp_probe);
4094 GNUNET_CONTAINER_multipeermap_destroy (plugin->nat_wait_conns);
4095 GNUNET_CONTAINER_multipeermap_destroy (plugin->sessionmap);
4096 GNUNET_break (0 == plugin->cur_connections);
4097 GNUNET_free (plugin);
4102 /* end of plugin_transport_xt.c */