aboutsummaryrefslogtreecommitdiff
path: root/src/transport/plugin_transport_tcp.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/transport/plugin_transport_tcp.c')
-rw-r--r--src/transport/plugin_transport_tcp.c3967
1 files changed, 0 insertions, 3967 deletions
diff --git a/src/transport/plugin_transport_tcp.c b/src/transport/plugin_transport_tcp.c
deleted file mode 100644
index ac4cc672f..000000000
--- a/src/transport/plugin_transport_tcp.c
+++ /dev/null
@@ -1,3967 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2002--2015 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
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.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @file transport/plugin_transport_tcp.c
22 * @brief Implementation of the TCP transport service
23 * @author Christian Grothoff
24 */
25#include "platform.h"
26#include "gnunet_hello_lib.h"
27#include "gnunet_constants.h"
28#include "gnunet_util_lib.h"
29#include "gnunet_nat_service.h"
30#include "gnunet_protocols.h"
31#include "gnunet_resolver_service.h"
32#include "gnunet_signatures.h"
33#include "gnunet_statistics_service.h"
34#include "gnunet_transport_service.h"
35#include "gnunet_transport_plugin.h"
36#include "transport.h"
37
38#define LOG(kind, ...) GNUNET_log_from (kind, "transport-tcp", __VA_ARGS__)
39
40#define PLUGIN_NAME "tcp"
41
42/**
43 * How long until we give up on establishing an NAT connection?
44 * Must be > 4 RTT
45 */
46#define NAT_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10)
47
48/**
49 * Opaque handle that can be used to cancel
50 * a transmit-ready notification.
51 */
52struct GNUNET_CONNECTION_TransmitHandle;
53
54/**
55 * @brief handle for a server
56 */
57struct GNUNET_SERVER_Handle;
58
59/**
60 * @brief opaque handle for a client of the server
61 */
62struct GNUNET_SERVER_Client;
63
64/**
65 * @brief opaque handle server returns for aborting transmission to a client.
66 */
67struct GNUNET_SERVER_TransmitHandle;
68
69/**
70 * @brief handle for a network connection
71 */
72struct GNUNET_CONNECTION_Handle;
73
74/**
75 * @brief handle for a network service
76 */
77struct LEGACY_SERVICE_Context;
78
79
80/**
81 * Stops a service that was started with #GNUNET_SERVICE_start().
82 *
83 * @param srv service to stop
84 */
85void
86LEGACY_SERVICE_stop (struct LEGACY_SERVICE_Context *srv);
87
88
89/**
90 * Function called to notify a client about the connection begin ready
91 * to queue more data. @a buf will be NULL and @a size zero if the
92 * connection was closed for writing in the meantime.
93 *
94 * @param cls closure
95 * @param size number of bytes available in @a buf
96 * @param buf where the callee should write the message
97 * @return number of bytes written to @a buf
98 */
99typedef size_t (*GNUNET_CONNECTION_TransmitReadyNotify) (void *cls,
100 size_t size,
101 void *buf);
102
103/**
104 * Credentials for UNIX domain sockets.
105 */
106struct GNUNET_CONNECTION_Credentials
107{
108 /**
109 * UID of the other end of the connection.
110 */
111 uid_t uid;
112
113 /**
114 * GID of the other end of the connection.
115 */
116 gid_t gid;
117};
118
119
120/**
121 * Functions with this signature are called whenever a client
122 * is disconnected on the network level.
123 *
124 * @param cls closure
125 * @param client identification of the client; NULL
126 * for the last call when the server is destroyed
127 */
128typedef void (*GNUNET_SERVER_DisconnectCallback) (
129 void *cls,
130 struct GNUNET_SERVER_Client *client);
131
132
133/**
134 * Functions with this signature are called whenever a client
135 * is connected on the network level.
136 *
137 * @param cls closure
138 * @param client identification of the client
139 */
140typedef void (*GNUNET_SERVER_ConnectCallback) (
141 void *cls,
142 struct GNUNET_SERVER_Client *client);
143
144
145/**
146 * Function to call for access control checks.
147 *
148 * @param cls closure
149 * @param ucred credentials, if available, otherwise NULL
150 * @param addr address
151 * @param addrlen length of address
152 * @return GNUNET_YES to allow, GNUNET_NO to deny, GNUNET_SYSERR
153 * for unknown address family (will be denied).
154 */
155typedef int (*GNUNET_CONNECTION_AccessCheck) (
156 void *cls,
157 const struct GNUNET_CONNECTION_Credentials *ucred,
158 const struct sockaddr *addr,
159 socklen_t addrlen);
160
161/**
162 * Callback function for data received from the network. Note that
163 * both "available" and "err" would be 0 if the read simply timed out.
164 *
165 * @param cls closure
166 * @param buf pointer to received data
167 * @param available number of bytes available in "buf",
168 * possibly 0 (on errors)
169 * @param addr address of the sender
170 * @param addrlen size of addr
171 * @param errCode value of errno (on errors receiving)
172 */
173typedef void (*GNUNET_CONNECTION_Receiver) (void *cls,
174 const void *buf,
175 size_t available,
176 const struct sockaddr *addr,
177 socklen_t addrlen,
178 int errCode);
179
180
181/**
182 * Close the connection and free associated resources. There must
183 * not be any pending requests for reading or writing to the
184 * connection at this time.
185 *
186 * @param connection connection to destroy
187 */
188void
189GNUNET_CONNECTION_destroy (struct GNUNET_CONNECTION_Handle *connection);
190
191
192/**
193 * Signature of a function to create a custom tokenizer.
194 *
195 * @param cls closure from #GNUNET_SERVER_set_callbacks
196 * @param client handle to client the tokenzier will be used for
197 * @return handle to custom tokenizer ('mst')
198 */
199typedef void *(*GNUNET_SERVER_MstCreateCallback) (
200 void *cls,
201 struct GNUNET_SERVER_Client *client);
202
203
204/**
205 * Signature of a function to destroy a custom tokenizer.
206 *
207 * @param cls closure from #GNUNET_SERVER_set_callbacks
208 * @param mst custom tokenizer handle
209 */
210typedef void (*GNUNET_SERVER_MstDestroyCallback) (void *cls, void *mst);
211
212/**
213 * Signature of a function to receive data for a custom tokenizer.
214 *
215 * @param cls closure from #GNUNET_SERVER_set_callbacks
216 * @param mst custom tokenizer handle
217 * @param client_identity ID of client for which this is a buffer,
218 * can be NULL (will be passed back to 'cb')
219 * @param buf input data to add
220 * @param size number of bytes in @a buf
221 * @param purge should any excess bytes in the buffer be discarded
222 * (i.e. for packet-based services like UDP)
223 * @param one_shot only call callback once, keep rest of message in buffer
224 * @return #GNUNET_OK if we are done processing (need more data)
225 * #GNUNET_NO if one_shot was set and we have another message ready
226 * #GNUNET_SYSERR if the data stream is corrupt
227 */
228typedef int (*GNUNET_SERVER_MstReceiveCallback) (
229 void *cls,
230 void *mst,
231 struct GNUNET_SERVER_Client *client,
232 const char *buf,
233 size_t size,
234 int purge,
235 int one_shot);
236/**
237 * Functions with this signature are called whenever a message is
238 * received.
239 *
240 * @param cls closure
241 * @param client identification of the client
242 * @param message the actual message
243 */
244typedef void (*GNUNET_SERVER_MessageCallback) (
245 void *cls,
246 struct GNUNET_SERVER_Client *client,
247 const struct GNUNET_MessageHeader *message);
248
249/**
250 * Message handler. Each struct specifies how to handle on particular
251 * type of message received.
252 */
253struct GNUNET_SERVER_MessageHandler
254{
255 /**
256 * Function to call for messages of "type".
257 */
258 GNUNET_SERVER_MessageCallback callback;
259
260 /**
261 * Closure argument for @e callback.
262 */
263 void *callback_cls;
264
265 /**
266 * Type of the message this handler covers.
267 */
268 uint16_t type;
269
270 /**
271 * Expected size of messages of this type. Use 0 for
272 * variable-size. If non-zero, messages of the given
273 * type will be discarded (and the connection closed)
274 * if they do not have the right size.
275 */
276 uint16_t expected_size;
277};
278
279
280/**
281 * Options for the service (bitmask).
282 */
283enum LEGACY_SERVICE_Options
284{
285 /**
286 * Use defaults. Terminates all client connections and the listen
287 * sockets immediately upon receiving the shutdown signal.
288 */
289 LEGACY_SERVICE_OPTION_NONE = 0,
290
291 /**
292 * Do not trigger server shutdown on signal at all; instead, allow
293 * for the user to terminate the server explicitly when needed
294 * by calling #LEGACY_SERVICE_shutdown().
295 */
296 LEGACY_SERVICE_OPTION_MANUAL_SHUTDOWN = 1,
297
298 /**
299 * Trigger a SOFT server shutdown on signals, allowing active
300 * non-monitor clients to complete their transactions.
301 */
302 LEGACY_SERVICE_OPTION_SOFT_SHUTDOWN = 2
303};
304
305
306/**
307 * Ask the server to disconnect from the given client. This is the
308 * same as passing #GNUNET_SYSERR to #GNUNET_SERVER_receive_done,
309 * except that it allows dropping of a client even when not handling a
310 * message from that client.
311 *
312 * @param client the client to disconnect from
313 */
314void
315GNUNET_SERVER_client_disconnect (struct GNUNET_SERVER_Client *client);
316
317/**
318 * Return user context associated with the given client.
319 * Note: you should probably use the macro (call without the underscore).
320 *
321 * @param client client to query
322 * @param size number of bytes in user context struct (for verification only)
323 * @return pointer to user context
324 */
325void *
326GNUNET_SERVER_client_get_user_context_ (struct GNUNET_SERVER_Client *client,
327 size_t size);
328
329
330/**
331 * Functions with this signature are called whenever a
332 * complete message is received by the tokenizer.
333 *
334 * Do not call #GNUNET_SERVER_mst_destroy from within
335 * the scope of this callback.
336 *
337 * @param cls closure
338 * @param client identification of the client
339 * @param message the actual message
340 * @return #GNUNET_OK on success, #GNUNET_SYSERR to stop further processing
341 */
342typedef int (*GNUNET_SERVER_MessageTokenizerCallback) (
343 void *cls,
344 void *client,
345 const struct GNUNET_MessageHeader *message);
346
347
348/**
349 * Create a message stream tokenizer.
350 *
351 * @param cb function to call on completed messages
352 * @param cb_cls closure for @a cb
353 * @return handle to tokenizer
354 */
355struct GNUNET_SERVER_MessageStreamTokenizer *
356GNUNET_SERVER_mst_create (GNUNET_SERVER_MessageTokenizerCallback cb,
357 void *cb_cls);
358
359/**
360 * Add incoming data to the receive buffer and call the
361 * callback for all complete messages.
362 *
363 * @param mst tokenizer to use
364 * @param client_identity ID of client for which this is a buffer,
365 * can be NULL (will be passed back to 'cb')
366 * @param buf input data to add
367 * @param size number of bytes in @a buf
368 * @param purge should any excess bytes in the buffer be discarded
369 * (i.e. for packet-based services like UDP)
370 * @param one_shot only call callback once, keep rest of message in buffer
371 * @return #GNUNET_OK if we are done processing (need more data)
372 * #GNUNET_NO if one_shot was set and we have another message ready
373 * #GNUNET_SYSERR if the data stream is corrupt
374 */
375int
376GNUNET_SERVER_mst_receive (struct GNUNET_SERVER_MessageStreamTokenizer *mst,
377 void *client_identity,
378 const char *buf,
379 size_t size,
380 int purge,
381 int one_shot);
382
383
384/**
385 * Destroys a tokenizer.
386 *
387 * @param mst tokenizer to destroy
388 */
389void
390GNUNET_SERVER_mst_destroy (struct GNUNET_SERVER_MessageStreamTokenizer *mst);
391
392
393/**
394 * Set user context to be associated with the given client.
395 * Note: you should probably use the macro (call without the underscore).
396 *
397 * @param client client to query
398 * @param ptr pointer to user context
399 * @param size number of bytes in user context struct (for verification only)
400 */
401void
402GNUNET_SERVER_client_set_user_context_ (struct GNUNET_SERVER_Client *client,
403 void *ptr,
404 size_t size);
405
406/**
407 * Return user context associated with the given client.
408 *
409 * @param client client to query
410 * @param type expected return type (i.e. 'struct Foo')
411 * @return pointer to user context of type 'type *'.
412 */
413#define GNUNET_SERVER_client_get_user_context(client, type) \
414 (type *) GNUNET_SERVER_client_get_user_context_ (client, sizeof(type))
415
416/**
417 * Set user context to be associated with the given client.
418 *
419 * @param client client to query
420 * @param value pointer to user context
421 */
422#define GNUNET_SERVER_client_set_user_context(client, value) \
423 GNUNET_SERVER_client_set_user_context_ (client, value, sizeof(*value))
424
425
426/**
427 * Notify us when the server has enough space to transmit
428 * a message of the given size to the given client.
429 *
430 * @param client client to transmit message to
431 * @param size requested amount of buffer space
432 * @param timeout after how long should we give up (and call
433 * notify with buf NULL and size 0)?
434 * @param callback function to call when space is available
435 * @param callback_cls closure for @a callback
436 * @return non-NULL if the notify callback was queued; can be used
437 * to cancel the request using
438 * #GNUNET_SERVER_notify_transmit_ready_cancel.
439 * NULL if we are already going to notify someone else (busy)
440 */
441struct GNUNET_SERVER_TransmitHandle *
442GNUNET_SERVER_notify_transmit_ready (
443 struct GNUNET_SERVER_Client *client,
444 size_t size,
445 struct GNUNET_TIME_Relative timeout,
446 GNUNET_CONNECTION_TransmitReadyNotify callback,
447 void *callback_cls);
448
449/**
450 * Abort transmission request.
451 *
452 * @param th request to abort
453 */
454void
455GNUNET_SERVER_notify_transmit_ready_cancel (
456 struct GNUNET_SERVER_TransmitHandle *th);
457
458
459/**
460 * Notify the server that the given client handle should
461 * be kept (keeps the connection up if possible, increments
462 * the internal reference counter).
463 *
464 * @param client the client to keep
465 */
466void
467GNUNET_SERVER_client_keep (struct GNUNET_SERVER_Client *client);
468
469
470/**
471 * Notify the server that the given client handle is no
472 * longer required. Decrements the reference counter. If
473 * that counter reaches zero an inactive connection maybe
474 * closed.
475 *
476 * @param client the client to drop
477 */
478void
479GNUNET_SERVER_client_drop (struct GNUNET_SERVER_Client *client);
480
481
482/**
483 * Function called by the service's run
484 * method to run service-specific setup code.
485 *
486 * @param cls closure
487 * @param server the initialized server
488 * @param cfg configuration to use
489 */
490typedef void (*LEGACY_SERVICE_Main) (
491 void *cls,
492 struct GNUNET_SERVER_Handle *server,
493 const struct GNUNET_CONFIGURATION_Handle *cfg);
494
495
496/**
497 * Suspend accepting connections from the listen socket temporarily.
498 * Resume activity using #GNUNET_SERVER_resume.
499 *
500 * @param server server to stop accepting connections.
501 */
502void
503GNUNET_SERVER_suspend (struct GNUNET_SERVER_Handle *server);
504
505/**
506 * Notify us when the server has enough space to transmit
507 * a message of the given size to the given client.
508 *
509 * @param client client to transmit message to
510 * @param size requested amount of buffer space
511 * @param timeout after how long should we give up (and call
512 * notify with buf NULL and size 0)?
513 * @param callback function to call when space is available
514 * @param callback_cls closure for @a callback
515 * @return non-NULL if the notify callback was queued; can be used
516 * to cancel the request using
517 * #GNUNET_SERVER_notify_transmit_ready_cancel.
518 * NULL if we are already going to notify someone else (busy)
519 */
520struct GNUNET_SERVER_TransmitHandle *
521GNUNET_SERVER_notify_transmit_ready (
522 struct GNUNET_SERVER_Client *client,
523 size_t size,
524 struct GNUNET_TIME_Relative timeout,
525 GNUNET_CONNECTION_TransmitReadyNotify callback,
526 void *callback_cls);
527
528
529/**
530 * Add a TCP socket-based connection to the set of handles managed by
531 * this server. Use this function for outgoing (P2P) connections that
532 * we initiated (and where this server should process incoming
533 * messages).
534 *
535 * @param server the server to use
536 * @param connection the connection to manage (client must
537 * stop using this connection from now on)
538 * @return the client handle
539 */
540struct GNUNET_SERVER_Client *
541GNUNET_SERVER_connect_socket (struct GNUNET_SERVER_Handle *server,
542 struct GNUNET_CONNECTION_Handle *connection);
543
544
545/**
546 * Resume accepting connections from the listen socket.
547 *
548 * @param server server to resume accepting connections.
549 */
550void
551GNUNET_SERVER_resume (struct GNUNET_SERVER_Handle *server);
552
553/**
554 * Free resources held by this server.
555 *
556 * @param server server to destroy
557 */
558void
559GNUNET_SERVER_destroy (struct GNUNET_SERVER_Handle *server);
560
561
562#include "tcp_connection_legacy.c"
563#include "tcp_server_mst_legacy.c"
564#include "tcp_server_legacy.c"
565#include "tcp_service_legacy.c"
566
567GNUNET_NETWORK_STRUCT_BEGIN
568
569/**
570 * Initial handshake message for a session.
571 */
572struct WelcomeMessage
573{
574 /**
575 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_WELCOME.
576 */
577 struct GNUNET_MessageHeader header;
578
579 /**
580 * Identity of the node connecting (TCP client)
581 */
582 struct GNUNET_PeerIdentity clientIdentity;
583};
584
585/**
586 * Basically a WELCOME message, but with the purpose
587 * of giving the waiting peer a client handle to use
588 */
589struct TCP_NAT_ProbeMessage
590{
591 /**
592 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_NAT_PROBE.
593 */
594 struct GNUNET_MessageHeader header;
595
596 /**
597 * Identity of the sender of the message.
598 */
599 struct GNUNET_PeerIdentity clientIdentity;
600};
601GNUNET_NETWORK_STRUCT_END
602
603/**
604 * Context for sending a NAT probe via TCP.
605 */
606struct TCPProbeContext
607{
608 /**
609 * Active probes are kept in a DLL.
610 */
611 struct TCPProbeContext *next;
612
613 /**
614 * Active probes are kept in a DLL.
615 */
616 struct TCPProbeContext *prev;
617
618 /**
619 * Probe connection.
620 */
621 struct GNUNET_CONNECTION_Handle *sock;
622
623 /**
624 * Message to be sent.
625 */
626 struct TCP_NAT_ProbeMessage message;
627
628 /**
629 * Handle to the transmission.
630 */
631 struct GNUNET_CONNECTION_TransmitHandle *transmit_handle;
632
633 /**
634 * Transport plugin handle.
635 */
636 struct Plugin *plugin;
637};
638
639/**
640 * Bits in the `options` field of TCP addresses.
641 */
642enum TcpAddressOptions
643{
644 /**
645 * No bits set.
646 */
647 TCP_OPTIONS_NONE = 0,
648
649 /**
650 * See #HTTP_OPTIONS_VERIFY_CERTIFICATE.
651 */
652 TCP_OPTIONS_RESERVED = 1,
653
654 /**
655 * Enable TCP Stealth-style port knocking.
656 */
657 TCP_OPTIONS_TCP_STEALTH = 2
658};
659
660GNUNET_NETWORK_STRUCT_BEGIN
661
662/**
663 * Network format for IPv4 addresses.
664 */
665struct IPv4TcpAddress
666{
667 /**
668 * Optional options and flags for this address,
669 * see `enum TcpAddressOptions`
670 */
671 uint32_t options GNUNET_PACKED;
672
673 /**
674 * IPv4 address, in network byte order.
675 */
676 uint32_t ipv4_addr GNUNET_PACKED;
677
678 /**
679 * Port number, in network byte order.
680 */
681 uint16_t t4_port GNUNET_PACKED;
682};
683
684/**
685 * Network format for IPv6 addresses.
686 */
687struct IPv6TcpAddress
688{
689 /**
690 * Optional flags for this address
691 * see `enum TcpAddressOptions`
692 */
693 uint32_t options GNUNET_PACKED;
694
695 /**
696 * IPv6 address.
697 */
698 struct in6_addr ipv6_addr GNUNET_PACKED;
699
700 /**
701 * Port number, in network byte order.
702 */
703 uint16_t t6_port GNUNET_PACKED;
704};
705GNUNET_NETWORK_STRUCT_END
706
707/**
708 * Encapsulation of all of the state of the plugin.
709 */
710struct Plugin;
711
712/**
713 * Information kept for each message that is yet to
714 * be transmitted.
715 */
716struct PendingMessage
717{
718 /**
719 * This is a doubly-linked list.
720 */
721 struct PendingMessage *next;
722
723 /**
724 * This is a doubly-linked list.
725 */
726 struct PendingMessage *prev;
727
728 /**
729 * The pending message
730 */
731 const char *msg;
732
733 /**
734 * Continuation function to call once the message
735 * has been sent. Can be NULL if there is no
736 * continuation to call.
737 */
738 GNUNET_TRANSPORT_TransmitContinuation transmit_cont;
739
740 /**
741 * Closure for @e transmit_cont.
742 */
743 void *transmit_cont_cls;
744
745 /**
746 * Timeout value for the pending message.
747 */
748 struct GNUNET_TIME_Absolute timeout;
749
750 /**
751 * So that the gnunet-service-transport can group messages together,
752 * these pending messages need to accept a message buffer and size
753 * instead of just a `struct GNUNET_MessageHeader`.
754 */
755 size_t message_size;
756};
757
758/**
759 * Session handle for TCP connections.
760 */
761struct GNUNET_ATS_Session
762{
763 /**
764 * To whom are we talking to (set to our identity
765 * if we are still waiting for the welcome message)
766 */
767 struct GNUNET_PeerIdentity target;
768
769 /**
770 * Pointer to the global plugin struct.
771 */
772 struct Plugin *plugin;
773
774 /**
775 * The client (used to identify this connection)
776 */
777 struct GNUNET_SERVER_Client *client;
778
779 /**
780 * Task cleaning up a NAT client connection establishment attempt;
781 */
782 struct GNUNET_SCHEDULER_Task *nat_connection_timeout;
783
784 /**
785 * Messages currently pending for transmission
786 * to this peer, if any.
787 */
788 struct PendingMessage *pending_messages_head;
789
790 /**
791 * Messages currently pending for transmission
792 * to this peer, if any.
793 */
794 struct PendingMessage *pending_messages_tail;
795
796 /**
797 * Handle for pending transmission request.
798 */
799 struct GNUNET_SERVER_TransmitHandle *transmit_handle;
800
801 /**
802 * Address of the other peer.
803 */
804 struct GNUNET_HELLO_Address *address;
805
806 /**
807 * ID of task used to delay receiving more to throttle sender.
808 */
809 struct GNUNET_SCHEDULER_Task *receive_delay_task;
810
811 /**
812 * Session timeout task
813 */
814 struct GNUNET_SCHEDULER_Task *timeout_task;
815
816 /**
817 * When will this session time out?
818 */
819 struct GNUNET_TIME_Absolute timeout;
820
821 /**
822 * When will we continue to read from the socket?
823 * (used to enforce inbound quota).
824 */
825 struct GNUNET_TIME_Absolute receive_delay;
826
827 /**
828 * Last activity on this connection. Used to select preferred
829 * connection.
830 */
831 struct GNUNET_TIME_Absolute last_activity;
832
833 /**
834 * Number of bytes waiting for transmission to this peer.
835 */
836 unsigned long long bytes_in_queue;
837
838 /**
839 * Number of messages waiting for transmission to this peer.
840 */
841 unsigned int msgs_in_queue;
842
843 /**
844 * Network type of the address.
845 */
846 enum GNUNET_NetworkType scope;
847
848 /**
849 * Are we still expecting the welcome message? (#GNUNET_YES/#GNUNET_NO)
850 */
851 int expecting_welcome;
852
853 /**
854 * Was this session created using NAT traversal?
855 */
856 int is_nat;
857};
858
859
860/**
861 * Context for address to string conversion, closure
862 * for #append_port().
863 */
864struct PrettyPrinterContext
865{
866 /**
867 * DLL
868 */
869 struct PrettyPrinterContext *next;
870
871 /**
872 * DLL
873 */
874 struct PrettyPrinterContext *prev;
875
876 /**
877 * Our plugin.
878 */
879 struct Plugin *plugin;
880
881 /**
882 * Timeout task
883 */
884 struct GNUNET_SCHEDULER_Task *timeout_task;
885
886 /**
887 * Resolver handle
888 */
889 struct GNUNET_RESOLVER_RequestHandle *resolver_handle;
890
891 /**
892 * Function to call with the result.
893 */
894 GNUNET_TRANSPORT_AddressStringCallback asc;
895
896 /**
897 * Clsoure for @e asc.
898 */
899 void *asc_cls;
900
901 /**
902 * IPv6 address
903 */
904 int ipv6;
905
906 /**
907 * Options
908 */
909 uint32_t options;
910
911 /**
912 * Port to add after the IP address.
913 */
914 uint16_t port;
915};
916
917
918/**
919 * Encapsulation of all of the state of the plugin.
920 */
921struct Plugin
922{
923 /**
924 * Our environment.
925 */
926 struct GNUNET_TRANSPORT_PluginEnvironment *env;
927
928 /**
929 * The listen socket.
930 */
931 struct GNUNET_CONNECTION_Handle *lsock;
932
933 /**
934 * Our handle to the NAT module.
935 */
936 struct GNUNET_NAT_Handle *nat;
937
938 /**
939 * Map from peer identities to sessions for the given peer.
940 */
941 struct GNUNET_CONTAINER_MultiPeerMap *sessionmap;
942
943 /**
944 * Handle to the network service.
945 */
946 struct LEGACY_SERVICE_Context *service;
947
948 /**
949 * Handle to the server for this service.
950 */
951 struct GNUNET_SERVER_Handle *server;
952
953 /**
954 * Copy of the handler array where the closures are
955 * set to this struct's instance.
956 */
957 struct GNUNET_SERVER_MessageHandler *handlers;
958
959 /**
960 * Map of peers we have tried to contact behind a NAT
961 */
962 struct GNUNET_CONTAINER_MultiPeerMap *nat_wait_conns;
963
964 /**
965 * List of active TCP probes.
966 */
967 struct TCPProbeContext *probe_head;
968
969 /**
970 * List of active TCP probes.
971 */
972 struct TCPProbeContext *probe_tail;
973
974 /**
975 * Function to call about session status changes.
976 */
977 GNUNET_TRANSPORT_SessionInfoCallback sic;
978
979 /**
980 * Closure for @e sic.
981 */
982 void *sic_cls;
983
984 /**
985 * ID of task used to update our addresses when one expires.
986 */
987 struct GNUNET_SCHEDULER_Task *address_update_task;
988
989 /**
990 * Running pretty printers: head
991 */
992 struct PrettyPrinterContext *ppc_dll_head;
993
994 /**
995 * Running pretty printers: tail
996 */
997 struct PrettyPrinterContext *ppc_dll_tail;
998
999 /**
1000 * Welcome message used by this peer.
1001 */
1002 struct WelcomeMessage my_welcome;
1003
1004 /**
1005 * How many more TCP sessions are we allowed to open right now?
1006 */
1007 unsigned long long max_connections;
1008
1009 /**
1010 * How many more TCP sessions do we have right now?
1011 */
1012 unsigned long long cur_connections;
1013
1014 /**
1015 * Address options
1016 */
1017 uint32_t myoptions;
1018
1019 /**
1020 * Port that we are actually listening on.
1021 */
1022 uint16_t open_port;
1023
1024 /**
1025 * Port that the user said we would have visible to the
1026 * rest of the world.
1027 */
1028 uint16_t adv_port;
1029};
1030
1031
1032/**
1033 * Get the list of addresses that a server for the given service
1034 * should bind to.
1035 *
1036 * @param service_name name of the service
1037 * @param cfg configuration (which specifies the addresses)
1038 * @param addrs set (call by reference) to an array of pointers to the
1039 * addresses the server should bind to and listen on; the
1040 * array will be NULL-terminated (on success)
1041 * @param addr_lens set (call by reference) to an array of the lengths
1042 * of the respective `struct sockaddr` struct in the @a addrs
1043 * array (on success)
1044 * @return number of addresses found on success,
1045 * #GNUNET_SYSERR if the configuration
1046 * did not specify reasonable finding information or
1047 * if it specified a hostname that could not be resolved;
1048 * #GNUNET_NO if the number of addresses configured is
1049 * zero (in this case, `*addrs` and `*addr_lens` will be
1050 * set to NULL).
1051 */
1052static int
1053get_server_addresses (const char *service_name,
1054 const struct GNUNET_CONFIGURATION_Handle *cfg,
1055 struct sockaddr ***addrs,
1056 socklen_t **addr_lens)
1057{
1058 int disablev6;
1059 struct GNUNET_NETWORK_Handle *desc;
1060 unsigned long long port;
1061 char *unixpath;
1062 struct addrinfo hints;
1063 struct addrinfo *res;
1064 struct addrinfo *pos;
1065 struct addrinfo *next;
1066 unsigned int i;
1067 int resi;
1068 int ret;
1069 int abstract;
1070 struct sockaddr **saddrs;
1071 socklen_t *saddrlens;
1072 char *hostname;
1073
1074 *addrs = NULL;
1075 *addr_lens = NULL;
1076 desc = NULL;
1077 if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "DISABLEV6"))
1078 {
1079 if (GNUNET_SYSERR ==
1080 (disablev6 = GNUNET_CONFIGURATION_get_value_yesno (cfg,
1081 service_name,
1082 "DISABLEV6")))
1083 return GNUNET_SYSERR;
1084 }
1085 else
1086 disablev6 = GNUNET_NO;
1087
1088 if (! disablev6)
1089 {
1090 /* probe IPv6 support */
1091 desc = GNUNET_NETWORK_socket_create (PF_INET6, SOCK_STREAM, 0);
1092 if (NULL == desc)
1093 {
1094 if ((ENOBUFS == errno) || (ENOMEM == errno) || (ENFILE == errno) ||
1095 (EACCES == errno))
1096 {
1097 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "socket");
1098 return GNUNET_SYSERR;
1099 }
1100 LOG (GNUNET_ERROR_TYPE_INFO,
1101 _ (
1102 "Disabling IPv6 support for service `%s', failed to create IPv6 socket: %s\n"),
1103 service_name,
1104 strerror (errno));
1105 disablev6 = GNUNET_YES;
1106 }
1107 else
1108 {
1109 GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (desc));
1110 desc = NULL;
1111 }
1112 }
1113
1114 port = 0;
1115 if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "PORT"))
1116 {
1117 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (cfg,
1118 service_name,
1119 "PORT",
1120 &port))
1121 {
1122 LOG (GNUNET_ERROR_TYPE_ERROR,
1123 _ ("Require valid port number for service `%s' in configuration!\n"),
1124 service_name);
1125 }
1126 if (port > 65535)
1127 {
1128 LOG (GNUNET_ERROR_TYPE_ERROR,
1129 _ ("Require valid port number for service `%s' in configuration!\n"),
1130 service_name);
1131 return GNUNET_SYSERR;
1132 }
1133 }
1134
1135 if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "BINDTO"))
1136 {
1137 GNUNET_break (GNUNET_OK ==
1138 GNUNET_CONFIGURATION_get_value_string (cfg,
1139 service_name,
1140 "BINDTO",
1141 &hostname));
1142 }
1143 else
1144 hostname = NULL;
1145
1146 unixpath = NULL;
1147 abstract = GNUNET_NO;
1148#ifdef AF_UNIX
1149 if ((GNUNET_YES ==
1150 GNUNET_CONFIGURATION_have_value (cfg, service_name, "UNIXPATH")) &&
1151 (GNUNET_OK == GNUNET_CONFIGURATION_get_value_filename (cfg,
1152 service_name,
1153 "UNIXPATH",
1154 &unixpath)) &&
1155 (0 < strlen (unixpath)))
1156 {
1157 /* probe UNIX support */
1158 struct sockaddr_un s_un;
1159
1160 if (strlen (unixpath) >= sizeof(s_un.sun_path))
1161 {
1162 LOG (GNUNET_ERROR_TYPE_WARNING,
1163 _ ("UNIXPATH `%s' too long, maximum length is %llu\n"),
1164 unixpath,
1165 (unsigned long long) sizeof(s_un.sun_path));
1166 unixpath = GNUNET_NETWORK_shorten_unixpath (unixpath);
1167 LOG (GNUNET_ERROR_TYPE_INFO, _ ("Using `%s' instead\n"), unixpath);
1168 }
1169#ifdef __linux__
1170 abstract = GNUNET_CONFIGURATION_get_value_yesno (cfg,
1171 "TESTING",
1172 "USE_ABSTRACT_SOCKETS");
1173 if (GNUNET_SYSERR == abstract)
1174 abstract = GNUNET_NO;
1175#endif
1176 if ((GNUNET_YES != abstract) &&
1177 (GNUNET_OK != GNUNET_DISK_directory_create_for_file (unixpath)))
1178 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "mkdir", unixpath);
1179 }
1180 if (NULL != unixpath)
1181 {
1182 desc = GNUNET_NETWORK_socket_create (AF_UNIX, SOCK_STREAM, 0);
1183 if (NULL == desc)
1184 {
1185 if ((ENOBUFS == errno) || (ENOMEM == errno) || (ENFILE == errno) ||
1186 (EACCES == errno))
1187 {
1188 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "socket");
1189 GNUNET_free (hostname);
1190 GNUNET_free (unixpath);
1191 return GNUNET_SYSERR;
1192 }
1193 LOG (GNUNET_ERROR_TYPE_INFO,
1194 _ (
1195 "Disabling UNIX domain socket support for service `%s', failed to create UNIX domain socket: %s\n"),
1196 service_name,
1197 strerror (errno));
1198 GNUNET_free (unixpath);
1199 unixpath = NULL;
1200 }
1201 else
1202 {
1203 GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (desc));
1204 desc = NULL;
1205 }
1206 }
1207#endif
1208
1209 if ((0 == port) && (NULL == unixpath))
1210 {
1211 LOG (GNUNET_ERROR_TYPE_ERROR,
1212 _ (
1213 "Have neither PORT nor UNIXPATH for service `%s', but one is required\n"),
1214 service_name);
1215 GNUNET_free (hostname);
1216 return GNUNET_SYSERR;
1217 }
1218 if (0 == port)
1219 {
1220 saddrs = GNUNET_malloc (2 * sizeof(struct sockaddr *));
1221 saddrlens = GNUNET_malloc (2 * sizeof(socklen_t));
1222 add_unixpath (saddrs, saddrlens, unixpath, abstract);
1223 GNUNET_free (unixpath);
1224 GNUNET_free (hostname);
1225 *addrs = saddrs;
1226 *addr_lens = saddrlens;
1227 return 1;
1228 }
1229
1230 if (NULL != hostname)
1231 {
1232 LOG (GNUNET_ERROR_TYPE_DEBUG,
1233 "Resolving `%s' since that is where `%s' will bind to.\n",
1234 hostname,
1235 service_name);
1236 memset (&hints, 0, sizeof(struct addrinfo));
1237 if (disablev6)
1238 hints.ai_family = AF_INET;
1239 hints.ai_protocol = IPPROTO_TCP;
1240 if ((0 != (ret = getaddrinfo (hostname, NULL, &hints, &res))) ||
1241 (NULL == res))
1242 {
1243 LOG (GNUNET_ERROR_TYPE_ERROR,
1244 _ ("Failed to resolve `%s': %s\n"),
1245 hostname,
1246 gai_strerror (ret));
1247 GNUNET_free (hostname);
1248 GNUNET_free (unixpath);
1249 return GNUNET_SYSERR;
1250 }
1251 next = res;
1252 i = 0;
1253 while (NULL != (pos = next))
1254 {
1255 next = pos->ai_next;
1256 if ((disablev6) && (pos->ai_family == AF_INET6))
1257 continue;
1258 i++;
1259 }
1260 if (0 == i)
1261 {
1262 LOG (GNUNET_ERROR_TYPE_ERROR,
1263 _ ("Failed to find %saddress for `%s'.\n"),
1264 disablev6 ? "IPv4 " : "",
1265 hostname);
1266 freeaddrinfo (res);
1267 GNUNET_free (hostname);
1268 GNUNET_free (unixpath);
1269 return GNUNET_SYSERR;
1270 }
1271 resi = i;
1272 if (NULL != unixpath)
1273 resi++;
1274 saddrs = GNUNET_malloc ((resi + 1) * sizeof(struct sockaddr *));
1275 saddrlens = GNUNET_malloc ((resi + 1) * sizeof(socklen_t));
1276 i = 0;
1277 if (NULL != unixpath)
1278 {
1279 add_unixpath (saddrs, saddrlens, unixpath, abstract);
1280 i++;
1281 }
1282 next = res;
1283 while (NULL != (pos = next))
1284 {
1285 next = pos->ai_next;
1286 if ((disablev6) && (AF_INET6 == pos->ai_family))
1287 continue;
1288 if ((IPPROTO_TCP != pos->ai_protocol) && (0 != pos->ai_protocol))
1289 continue; /* not TCP */
1290 if ((SOCK_STREAM != pos->ai_socktype) && (0 != pos->ai_socktype))
1291 continue; /* huh? */
1292 LOG (GNUNET_ERROR_TYPE_DEBUG,
1293 "Service `%s' will bind to `%s'\n",
1294 service_name,
1295 GNUNET_a2s (pos->ai_addr, pos->ai_addrlen));
1296 if (AF_INET == pos->ai_family)
1297 {
1298 GNUNET_assert (sizeof(struct sockaddr_in) == pos->ai_addrlen);
1299 saddrlens[i] = pos->ai_addrlen;
1300 saddrs[i] = GNUNET_malloc (saddrlens[i]);
1301 GNUNET_memcpy (saddrs[i], pos->ai_addr, saddrlens[i]);
1302 ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
1303 }
1304 else
1305 {
1306 GNUNET_assert (AF_INET6 == pos->ai_family);
1307 GNUNET_assert (sizeof(struct sockaddr_in6) == pos->ai_addrlen);
1308 saddrlens[i] = pos->ai_addrlen;
1309 saddrs[i] = GNUNET_malloc (saddrlens[i]);
1310 GNUNET_memcpy (saddrs[i], pos->ai_addr, saddrlens[i]);
1311 ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port);
1312 }
1313 i++;
1314 }
1315 GNUNET_free (hostname);
1316 freeaddrinfo (res);
1317 resi = i;
1318 }
1319 else
1320 {
1321 /* will bind against everything, just set port */
1322 if (disablev6)
1323 {
1324 /* V4-only */
1325 resi = 1;
1326 if (NULL != unixpath)
1327 resi++;
1328 i = 0;
1329 saddrs = GNUNET_malloc ((resi + 1) * sizeof(struct sockaddr *));
1330 saddrlens = GNUNET_malloc ((resi + 1) * sizeof(socklen_t));
1331 if (NULL != unixpath)
1332 {
1333 add_unixpath (saddrs, saddrlens, unixpath, abstract);
1334 i++;
1335 }
1336 saddrlens[i] = sizeof(struct sockaddr_in);
1337 saddrs[i] = GNUNET_malloc (saddrlens[i]);
1338#if HAVE_SOCKADDR_IN_SIN_LEN
1339 ((struct sockaddr_in *) saddrs[i])->sin_len = saddrlens[i];
1340#endif
1341 ((struct sockaddr_in *) saddrs[i])->sin_family = AF_INET;
1342 ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
1343 }
1344 else
1345 {
1346 /* dual stack */
1347 resi = 2;
1348 if (NULL != unixpath)
1349 resi++;
1350 saddrs = GNUNET_malloc ((resi + 1) * sizeof(struct sockaddr *));
1351 saddrlens = GNUNET_malloc ((resi + 1) * sizeof(socklen_t));
1352 i = 0;
1353 if (NULL != unixpath)
1354 {
1355 add_unixpath (saddrs, saddrlens, unixpath, abstract);
1356 i++;
1357 }
1358 saddrlens[i] = sizeof(struct sockaddr_in6);
1359 saddrs[i] = GNUNET_malloc (saddrlens[i]);
1360#if HAVE_SOCKADDR_IN_SIN_LEN
1361 ((struct sockaddr_in6 *) saddrs[i])->sin6_len = saddrlens[0];
1362#endif
1363 ((struct sockaddr_in6 *) saddrs[i])->sin6_family = AF_INET6;
1364 ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port);
1365 i++;
1366 saddrlens[i] = sizeof(struct sockaddr_in);
1367 saddrs[i] = GNUNET_malloc (saddrlens[i]);
1368#if HAVE_SOCKADDR_IN_SIN_LEN
1369 ((struct sockaddr_in *) saddrs[i])->sin_len = saddrlens[1];
1370#endif
1371 ((struct sockaddr_in *) saddrs[i])->sin_family = AF_INET;
1372 ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
1373 }
1374 }
1375 GNUNET_free (unixpath);
1376 *addrs = saddrs;
1377 *addr_lens = saddrlens;
1378 return resi;
1379}
1380
1381
1382/* end ancient copy-and-paste */
1383
1384
1385/**
1386 * If a session monitor is attached, notify it about the new
1387 * session state.
1388 *
1389 * @param plugin our plugin
1390 * @param session session that changed state
1391 * @param state new state of the session
1392 */
1393static void
1394notify_session_monitor (struct Plugin *plugin,
1395 struct GNUNET_ATS_Session *session,
1396 enum GNUNET_TRANSPORT_SessionState state)
1397{
1398 struct GNUNET_TRANSPORT_SessionInfo info;
1399
1400 if (NULL == plugin->sic)
1401 return;
1402 memset (&info, 0, sizeof(info));
1403 info.state = state;
1404 info.is_inbound =
1405 GNUNET_HELLO_address_check_option (session->address,
1406 GNUNET_HELLO_ADDRESS_INFO_INBOUND);
1407 info.num_msg_pending = session->msgs_in_queue;
1408 info.num_bytes_pending = session->bytes_in_queue;
1409 if (NULL != session->receive_delay_task)
1410 info.receive_delay = session->receive_delay;
1411 info.session_timeout = session->timeout;
1412 info.address = session->address;
1413 plugin->sic (plugin->sic_cls, session, &info);
1414}
1415
1416
1417/**
1418 * Our external IP address/port mapping has changed.
1419 *
1420 * @param cls closure, the `struct Plugin`
1421 * @param app_ctx[in,out] location where the app can store stuff
1422 * on add and retrieve it on remove
1423 * @param add_remove #GNUNET_YES to mean the new public IP address, #GNUNET_NO to mean
1424 * the previous (now invalid) one
1425 * @param ac address class the address belongs to
1426 * @param addr either the previous or the new public IP address
1427 * @param addrlen actual length of @a addr
1428 */
1429static void
1430tcp_nat_port_map_callback (void *cls,
1431 void **app_ctx,
1432 int add_remove,
1433 enum GNUNET_NAT_AddressClass ac,
1434 const struct sockaddr *addr,
1435 socklen_t addrlen)
1436{
1437 struct Plugin *plugin = cls;
1438 struct GNUNET_HELLO_Address *address;
1439 struct IPv4TcpAddress t4;
1440 struct IPv6TcpAddress t6;
1441 void *arg;
1442 size_t args;
1443
1444 (void) app_ctx;
1445 LOG (GNUNET_ERROR_TYPE_INFO,
1446 "NAT notification to %s address `%s'\n",
1447 (GNUNET_YES == add_remove) ? "add" : "remove",
1448 GNUNET_a2s (addr, addrlen));
1449 /* convert 'addr' to our internal format */
1450 switch (addr->sa_family)
1451 {
1452 case AF_INET:
1453 GNUNET_assert (addrlen == sizeof(struct sockaddr_in));
1454 memset (&t4, 0, sizeof(t4));
1455 t4.options = htonl (plugin->myoptions);
1456 t4.ipv4_addr = ((struct sockaddr_in *) addr)->sin_addr.s_addr;
1457 t4.t4_port = ((struct sockaddr_in *) addr)->sin_port;
1458 arg = &t4;
1459 args = sizeof(t4);
1460 break;
1461
1462 case AF_INET6:
1463 if (IN6_IS_ADDR_LINKLOCAL (&((struct sockaddr_in6 *) addr)->sin6_addr))
1464 {
1465 /* skip link local, we don't allow them in
1466 #tcp_plugin_check_address() */
1467 return;
1468 }
1469 GNUNET_assert (addrlen == sizeof(struct sockaddr_in6));
1470 memset (&t6, 0, sizeof(t6));
1471 GNUNET_memcpy (&t6.ipv6_addr,
1472 &((struct sockaddr_in6 *) addr)->sin6_addr,
1473 sizeof(struct in6_addr));
1474 t6.options = htonl (plugin->myoptions);
1475 t6.t6_port = ((struct sockaddr_in6 *) addr)->sin6_port;
1476 arg = &t6;
1477 args = sizeof(t6);
1478 break;
1479
1480 default:
1481 GNUNET_break (0);
1482 return;
1483 }
1484 /* modify our published address list */
1485 GNUNET_assert ((args == sizeof(struct IPv4TcpAddress)) ||
1486 (args == sizeof(struct IPv6TcpAddress)));
1487 /* TODO: use 'ac' here in the future... */
1488 address = GNUNET_HELLO_address_allocate (plugin->env->my_identity,
1489 PLUGIN_NAME,
1490 arg,
1491 args,
1492 GNUNET_HELLO_ADDRESS_INFO_NONE);
1493 plugin->env->notify_address (plugin->env->cls, add_remove, address);
1494 GNUNET_HELLO_address_free (address);
1495}
1496
1497
1498/**
1499 * Function called for a quick conversion of the binary address to
1500 * a numeric address. Note that the caller must not free the
1501 * address and that the next call to this function is allowed
1502 * to override the address again.
1503 *
1504 * @param cls closure (`struct Plugin*`)
1505 * @param addr binary address
1506 * @param addrlen length of @a addr
1507 * @return string representing the same address
1508 */
1509static const char *
1510tcp_plugin_address_to_string (void *cls, const void *addr, size_t addrlen)
1511{
1512 static char rbuf[INET6_ADDRSTRLEN + 12];
1513 char buf[INET6_ADDRSTRLEN];
1514 const void *sb;
1515 struct in_addr a4;
1516 struct in6_addr a6;
1517 const struct IPv4TcpAddress *t4;
1518 const struct IPv6TcpAddress *t6;
1519 int af;
1520 uint16_t port;
1521 uint32_t options;
1522
1523 switch (addrlen)
1524 {
1525 case sizeof(struct IPv6TcpAddress):
1526 t6 = addr;
1527 af = AF_INET6;
1528 port = ntohs (t6->t6_port);
1529 options = ntohl (t6->options);
1530 GNUNET_memcpy (&a6, &t6->ipv6_addr, sizeof(a6));
1531 sb = &a6;
1532 break;
1533
1534 case sizeof(struct IPv4TcpAddress):
1535 t4 = addr;
1536 af = AF_INET;
1537 port = ntohs (t4->t4_port);
1538 options = ntohl (t4->options);
1539 GNUNET_memcpy (&a4, &t4->ipv4_addr, sizeof(a4));
1540 sb = &a4;
1541 break;
1542
1543 default:
1544 LOG (GNUNET_ERROR_TYPE_WARNING,
1545 _ ("Unexpected address length: %u bytes\n"),
1546 (unsigned int) addrlen);
1547 return NULL;
1548 }
1549 if (NULL == inet_ntop (af, sb, buf, INET6_ADDRSTRLEN))
1550 {
1551 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "inet_ntop");
1552 return NULL;
1553 }
1554 GNUNET_snprintf (rbuf,
1555 sizeof(rbuf),
1556 (af == AF_INET6) ? "%s.%u.[%s]:%u" : "%s.%u.%s:%u",
1557 PLUGIN_NAME,
1558 options,
1559 buf,
1560 port);
1561 return rbuf;
1562}
1563
1564
1565/**
1566 * Function called to convert a string address to
1567 * a binary address.
1568 *
1569 * @param cls closure (`struct Plugin*`)
1570 * @param addr string address
1571 * @param addrlen length of the address
1572 * @param buf location to store the buffer
1573 * @param added location to store the number of bytes in the buffer.
1574 * If the function returns #GNUNET_SYSERR, its contents are undefined.
1575 * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure
1576 */
1577static int
1578tcp_plugin_string_to_address (void *cls,
1579 const char *addr,
1580 uint16_t addrlen,
1581 void **buf,
1582 size_t *added)
1583{
1584 struct sockaddr_storage socket_address;
1585 char *address;
1586 char *plugin;
1587 char *optionstr;
1588 uint32_t options;
1589
1590 /* Format tcp.options.address:port */
1591 address = NULL;
1592 plugin = NULL;
1593 optionstr = NULL;
1594 if ((NULL == addr) || (0 == addrlen))
1595 {
1596 GNUNET_break (0);
1597 return GNUNET_SYSERR;
1598 }
1599 if ('\0' != addr[addrlen - 1])
1600 {
1601 GNUNET_break (0);
1602 return GNUNET_SYSERR;
1603 }
1604 if (strlen (addr) != addrlen - 1)
1605 {
1606 GNUNET_break (0);
1607 return GNUNET_SYSERR;
1608 }
1609 plugin = GNUNET_strdup (addr);
1610 optionstr = strchr (plugin, '.');
1611 if (NULL == optionstr)
1612 {
1613 GNUNET_break (0);
1614 GNUNET_free (plugin);
1615 return GNUNET_SYSERR;
1616 }
1617 optionstr[0] = '\0';
1618 optionstr++;
1619 options = atol (optionstr);
1620 address = strchr (optionstr, '.');
1621 if (NULL == address)
1622 {
1623 GNUNET_break (0);
1624 GNUNET_free (plugin);
1625 return GNUNET_SYSERR;
1626 }
1627 address[0] = '\0';
1628 address++;
1629
1630 if (GNUNET_OK !=
1631 GNUNET_STRINGS_to_address_ip (address, strlen (address), &socket_address))
1632 {
1633 GNUNET_break (0);
1634 GNUNET_free (plugin);
1635 return GNUNET_SYSERR;
1636 }
1637
1638 GNUNET_free (plugin);
1639 switch (socket_address.ss_family)
1640 {
1641 case AF_INET: {
1642 struct IPv4TcpAddress *t4;
1643 struct sockaddr_in *in4 = (struct sockaddr_in *) &socket_address;
1644 t4 = GNUNET_new (struct IPv4TcpAddress);
1645 t4->options = htonl (options);
1646 t4->ipv4_addr = in4->sin_addr.s_addr;
1647 t4->t4_port = in4->sin_port;
1648 *buf = t4;
1649 *added = sizeof(struct IPv4TcpAddress);
1650 return GNUNET_OK;
1651 }
1652
1653 case AF_INET6: {
1654 struct IPv6TcpAddress *t6;
1655 struct sockaddr_in6 *in6 = (struct sockaddr_in6 *) &socket_address;
1656 t6 = GNUNET_new (struct IPv6TcpAddress);
1657 t6->options = htonl (options);
1658 t6->ipv6_addr = in6->sin6_addr;
1659 t6->t6_port = in6->sin6_port;
1660 *buf = t6;
1661 *added = sizeof(struct IPv6TcpAddress);
1662 return GNUNET_OK;
1663 }
1664
1665 default:
1666 return GNUNET_SYSERR;
1667 }
1668}
1669
1670
1671/**
1672 * Find the session handle for the given client.
1673 * Currently uses both the hashmap and the client
1674 * context, as the client context is new and the
1675 * logic still needs to be tested.
1676 *
1677 * @param plugin the plugin
1678 * @param client which client to find the session handle for
1679 * @return NULL if no matching session exists
1680 */
1681static struct GNUNET_ATS_Session *
1682lookup_session_by_client (struct Plugin *plugin,
1683 struct GNUNET_SERVER_Client *client)
1684{
1685 return GNUNET_SERVER_client_get_user_context (client,
1686 struct GNUNET_ATS_Session);
1687}
1688
1689
1690/**
1691 * Functions with this signature are called whenever we need
1692 * to close a session due to a disconnect or failure to
1693 * establish a connection.
1694 *
1695 * @param cls the `struct Plugin`
1696 * @param session session to close down
1697 * @return #GNUNET_OK on success
1698 */
1699static int
1700tcp_plugin_disconnect_session (void *cls, struct GNUNET_ATS_Session *session)
1701{
1702 struct Plugin *plugin = cls;
1703 struct PendingMessage *pm;
1704
1705 LOG (GNUNET_ERROR_TYPE_DEBUG,
1706 "Disconnecting session of peer `%s' address `%s'\n",
1707 GNUNET_i2s (&session->target),
1708 tcp_plugin_address_to_string (session->plugin,
1709 session->address->address,
1710 session->address->address_length));
1711
1712 if (NULL != session->timeout_task)
1713 {
1714 GNUNET_SCHEDULER_cancel (session->timeout_task);
1715 session->timeout_task = NULL;
1716 session->timeout = GNUNET_TIME_UNIT_ZERO_ABS;
1717 }
1718
1719 if (GNUNET_YES == GNUNET_CONTAINER_multipeermap_remove (plugin->sessionmap,
1720 &session->target,
1721 session))
1722 {
1723 GNUNET_STATISTICS_update (session->plugin->env->stats,
1724 gettext_noop ("# TCP sessions active"),
1725 -1,
1726 GNUNET_NO);
1727 }
1728 else
1729 {
1730 GNUNET_assert (GNUNET_YES ==
1731 GNUNET_CONTAINER_multipeermap_remove (plugin->nat_wait_conns,
1732 &session->target,
1733 session));
1734 }
1735 if (NULL != session->client)
1736 GNUNET_SERVER_client_set_user_context (session->client, NULL);
1737
1738 /* clean up state */
1739 if (NULL != session->transmit_handle)
1740 {
1741 GNUNET_SERVER_notify_transmit_ready_cancel (session->transmit_handle);
1742 session->transmit_handle = NULL;
1743 }
1744 session->plugin->env->session_end (session->plugin->env->cls,
1745 session->address,
1746 session);
1747
1748 if (NULL != session->nat_connection_timeout)
1749 {
1750 GNUNET_SCHEDULER_cancel (session->nat_connection_timeout);
1751 session->nat_connection_timeout = NULL;
1752 }
1753
1754 while (NULL != (pm = session->pending_messages_head))
1755 {
1756 LOG (GNUNET_ERROR_TYPE_DEBUG,
1757 (NULL != pm->transmit_cont)
1758 ? "Could not deliver message to `%s' at %s.\n"
1759 : "Could not deliver message to `%s' at %s, notifying.\n",
1760 GNUNET_i2s (&session->target),
1761 tcp_plugin_address_to_string (session->plugin,
1762 session->address->address,
1763 session->address->address_length));
1764 GNUNET_STATISTICS_update (session->plugin->env->stats,
1765 gettext_noop ("# bytes currently in TCP buffers"),
1766 -(int64_t) pm->message_size,
1767 GNUNET_NO);
1768 GNUNET_STATISTICS_update (session->plugin->env->stats,
1769 gettext_noop (
1770 "# bytes discarded by TCP (disconnect)"),
1771 pm->message_size,
1772 GNUNET_NO);
1773 GNUNET_CONTAINER_DLL_remove (session->pending_messages_head,
1774 session->pending_messages_tail,
1775 pm);
1776 GNUNET_assert (0 < session->msgs_in_queue);
1777 session->msgs_in_queue--;
1778 GNUNET_assert (pm->message_size <= session->bytes_in_queue);
1779 session->bytes_in_queue -= pm->message_size;
1780 if (NULL != pm->transmit_cont)
1781 pm->transmit_cont (pm->transmit_cont_cls,
1782 &session->target,
1783 GNUNET_SYSERR,
1784 pm->message_size,
1785 0);
1786 GNUNET_free (pm);
1787 }
1788 GNUNET_assert (0 == session->msgs_in_queue);
1789 GNUNET_assert (0 == session->bytes_in_queue);
1790 notify_session_monitor (session->plugin, session, GNUNET_TRANSPORT_SS_DONE);
1791
1792 if (NULL != session->receive_delay_task)
1793 {
1794 GNUNET_SCHEDULER_cancel (session->receive_delay_task);
1795 session->receive_delay_task = NULL;
1796 }
1797 if (NULL != session->client)
1798 {
1799 GNUNET_SERVER_client_disconnect (session->client);
1800 session->client = NULL;
1801 }
1802 GNUNET_HELLO_address_free (session->address);
1803 GNUNET_assert (NULL == session->transmit_handle);
1804 GNUNET_free (session);
1805 return GNUNET_OK;
1806}
1807
1808
1809/**
1810 * Function that is called to get the keepalive factor.
1811 * #GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT is divided by this number to
1812 * calculate the interval between keepalive packets.
1813 *
1814 * @param cls closure with the `struct Plugin`
1815 * @return keepalive factor
1816 */
1817static unsigned int
1818tcp_plugin_query_keepalive_factor (void *cls)
1819{
1820 return 3;
1821}
1822
1823
1824/**
1825 * Session was idle for too long, so disconnect it
1826 *
1827 * @param cls the `struct GNUNET_ATS_Session` of the idle session
1828 */
1829static void
1830session_timeout (void *cls)
1831{
1832 struct GNUNET_ATS_Session *s = cls;
1833 struct GNUNET_TIME_Relative left;
1834
1835 s->timeout_task = NULL;
1836 left = GNUNET_TIME_absolute_get_remaining (s->timeout);
1837 if (0 != left.rel_value_us)
1838 {
1839 /* not actually our turn yet, but let's at least update
1840 the monitor, it may think we're about to die ... */
1841 notify_session_monitor (s->plugin, s, GNUNET_TRANSPORT_SS_UPDATE);
1842 s->timeout_task = GNUNET_SCHEDULER_add_delayed (left, &session_timeout, s);
1843 return;
1844 }
1845 LOG (GNUNET_ERROR_TYPE_DEBUG,
1846 "Session %p was idle for %s, disconnecting\n",
1847 s,
1848 GNUNET_STRINGS_relative_time_to_string (
1849 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
1850 GNUNET_YES));
1851 /* call session destroy function */
1852 tcp_plugin_disconnect_session (s->plugin, s);
1853}
1854
1855
1856/**
1857 * Increment session timeout due to activity.
1858 *
1859 * @param s session to increment timeout for
1860 */
1861static void
1862reschedule_session_timeout (struct GNUNET_ATS_Session *s)
1863{
1864 GNUNET_assert (NULL != s->timeout_task);
1865 s->timeout =
1866 GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1867}
1868
1869
1870/**
1871 * Create a new session. Also queues a welcome message.
1872 *
1873 * @param plugin the plugin
1874 * @param address the address to create the session for
1875 * @param scope network scope the address is from
1876 * @param client client to use, reference counter must have already been increased
1877 * @param is_nat this a NAT session, we should wait for a client to
1878 * connect to us from an address, then assign that to
1879 * the session
1880 * @return new session object
1881 */
1882static struct GNUNET_ATS_Session *
1883create_session (struct Plugin *plugin,
1884 const struct GNUNET_HELLO_Address *address,
1885 enum GNUNET_NetworkType scope,
1886 struct GNUNET_SERVER_Client *client,
1887 int is_nat)
1888{
1889 struct GNUNET_ATS_Session *session;
1890 struct PendingMessage *pm;
1891
1892 if (GNUNET_YES != is_nat)
1893 GNUNET_assert (NULL != client);
1894 else
1895 GNUNET_assert (NULL == client);
1896
1897 LOG (GNUNET_ERROR_TYPE_DEBUG,
1898 "Creating new session for peer `%s' at address %s\n",
1899 GNUNET_i2s (&address->peer),
1900 tcp_plugin_address_to_string (plugin,
1901 address->address,
1902 address->address_length));
1903 session = GNUNET_new (struct GNUNET_ATS_Session);
1904 session->last_activity = GNUNET_TIME_absolute_get ();
1905 session->plugin = plugin;
1906 session->is_nat = is_nat;
1907 if (NULL != client)
1908 {
1909 session->client = client;
1910 GNUNET_SERVER_client_set_user_context (client, session);
1911 }
1912 session->address = GNUNET_HELLO_address_copy (address);
1913 session->target = address->peer;
1914 session->expecting_welcome = GNUNET_YES;
1915 session->scope = scope;
1916 pm = GNUNET_malloc (sizeof(struct PendingMessage)
1917 + sizeof(struct WelcomeMessage));
1918 pm->msg = (const char *) &pm[1];
1919 pm->message_size = sizeof(struct WelcomeMessage);
1920 GNUNET_memcpy (&pm[1], &plugin->my_welcome, sizeof(struct WelcomeMessage));
1921 pm->timeout = GNUNET_TIME_UNIT_FOREVER_ABS;
1922 GNUNET_STATISTICS_update (plugin->env->stats,
1923 gettext_noop ("# bytes currently in TCP buffers"),
1924 pm->message_size,
1925 GNUNET_NO);
1926 GNUNET_CONTAINER_DLL_insert (session->pending_messages_head,
1927 session->pending_messages_tail,
1928 pm);
1929 session->msgs_in_queue++;
1930 session->bytes_in_queue += pm->message_size;
1931 session->timeout =
1932 GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1933 session->timeout_task =
1934 GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
1935 &session_timeout,
1936 session);
1937 notify_session_monitor (session->plugin, session, GNUNET_TRANSPORT_SS_INIT);
1938 if (GNUNET_YES != is_nat)
1939 {
1940 GNUNET_STATISTICS_update (plugin->env->stats,
1941 gettext_noop ("# TCP sessions active"),
1942 1,
1943 GNUNET_NO);
1944 notify_session_monitor (session->plugin, session, GNUNET_TRANSPORT_SS_UP);
1945 }
1946 else
1947 {
1948 notify_session_monitor (session->plugin,
1949 session,
1950 GNUNET_TRANSPORT_SS_HANDSHAKE);
1951 }
1952 return session;
1953}
1954
1955
1956/**
1957 * If we have pending messages, ask the server to
1958 * transmit them (schedule the respective tasks, etc.)
1959 *
1960 * @param session for which session should we do this
1961 */
1962static void
1963process_pending_messages (struct GNUNET_ATS_Session *session);
1964
1965
1966/**
1967 * Function called to notify a client about the socket
1968 * being ready to queue more data. "buf" will be
1969 * NULL and "size" zero if the socket was closed for
1970 * writing in the meantime.
1971 *
1972 * @param cls closure
1973 * @param size number of bytes available in @a buf
1974 * @param buf where the callee should write the message
1975 * @return number of bytes written to @a buf
1976 */
1977static size_t
1978do_transmit (void *cls, size_t size, void *buf)
1979{
1980 struct GNUNET_ATS_Session *session = cls;
1981 struct GNUNET_PeerIdentity pid;
1982 struct Plugin *plugin;
1983 struct PendingMessage *pos;
1984 struct PendingMessage *hd;
1985 struct PendingMessage *tl;
1986 struct GNUNET_TIME_Absolute now;
1987 char *cbuf;
1988 size_t ret;
1989
1990 session->transmit_handle = NULL;
1991 plugin = session->plugin;
1992 if (NULL == buf)
1993 {
1994 LOG (GNUNET_ERROR_TYPE_DEBUG,
1995 "Timeout trying to transmit to peer `%s', discarding message queue.\n",
1996 GNUNET_i2s (&session->target));
1997 /* timeout; cancel all messages that have already expired */
1998 hd = NULL;
1999 tl = NULL;
2000 ret = 0;
2001 now = GNUNET_TIME_absolute_get ();
2002 while ((NULL != (pos = session->pending_messages_head)) &&
2003 (pos->timeout.abs_value_us <= now.abs_value_us))
2004 {
2005 GNUNET_CONTAINER_DLL_remove (session->pending_messages_head,
2006 session->pending_messages_tail,
2007 pos);
2008 GNUNET_assert (0 < session->msgs_in_queue);
2009 session->msgs_in_queue--;
2010 GNUNET_assert (pos->message_size <= session->bytes_in_queue);
2011 session->bytes_in_queue -= pos->message_size;
2012 LOG (GNUNET_ERROR_TYPE_DEBUG,
2013 "Failed to transmit %lu byte message to `%s'.\n",
2014 (unsigned long) pos->message_size,
2015 GNUNET_i2s (&session->target));
2016 ret += pos->message_size;
2017 GNUNET_CONTAINER_DLL_insert_after (hd, tl, tl, pos);
2018 }
2019 /* do this call before callbacks (so that if callbacks destroy
2020 * session, they have a chance to cancel actions done by this
2021 * call) */
2022 process_pending_messages (session);
2023 pid = session->target;
2024 /* no do callbacks and do not use session again since
2025 * the callbacks may abort the session */
2026 while (NULL != (pos = hd))
2027 {
2028 GNUNET_CONTAINER_DLL_remove (hd, tl, pos);
2029 if (NULL != pos->transmit_cont)
2030 pos->transmit_cont (pos->transmit_cont_cls,
2031 &pid,
2032 GNUNET_SYSERR,
2033 pos->message_size,
2034 0);
2035 GNUNET_free (pos);
2036 }
2037 GNUNET_STATISTICS_update (plugin->env->stats,
2038 gettext_noop ("# bytes currently in TCP buffers"),
2039 -(int64_t) ret,
2040 GNUNET_NO);
2041 GNUNET_STATISTICS_update (plugin->env->stats,
2042 gettext_noop (
2043 "# bytes discarded by TCP (timeout)"),
2044 ret,
2045 GNUNET_NO);
2046 if (0 < ret)
2047 notify_session_monitor (session->plugin,
2048 session,
2049 GNUNET_TRANSPORT_SS_UPDATE);
2050 return 0;
2051 }
2052 /* copy all pending messages that would fit */
2053 ret = 0;
2054 cbuf = buf;
2055 hd = NULL;
2056 tl = NULL;
2057 while (NULL != (pos = session->pending_messages_head))
2058 {
2059 if (ret + pos->message_size > size)
2060 break;
2061 GNUNET_CONTAINER_DLL_remove (session->pending_messages_head,
2062 session->pending_messages_tail,
2063 pos);
2064 GNUNET_assert (0 < session->msgs_in_queue);
2065 session->msgs_in_queue--;
2066 GNUNET_assert (pos->message_size <= session->bytes_in_queue);
2067 session->bytes_in_queue -= pos->message_size;
2068 GNUNET_assert (size >= pos->message_size);
2069 LOG (GNUNET_ERROR_TYPE_DEBUG,
2070 "Transmitting message of type %u size %lu to peer %s at %s\n",
2071 ntohs (((struct GNUNET_MessageHeader *) pos->msg)->type),
2072 (unsigned long) pos->message_size,
2073 GNUNET_i2s (&session->target),
2074 tcp_plugin_address_to_string (session->plugin,
2075 session->address->address,
2076 session->address->address_length));
2077 /* FIXME: this GNUNET_memcpy can be up to 7% of our total runtime */
2078 GNUNET_memcpy (cbuf, pos->msg, pos->message_size);
2079 cbuf += pos->message_size;
2080 ret += pos->message_size;
2081 size -= pos->message_size;
2082 GNUNET_CONTAINER_DLL_insert_tail (hd, tl, pos);
2083 }
2084 notify_session_monitor (session->plugin, session, GNUNET_TRANSPORT_SS_UPDATE);
2085 /* schedule 'continuation' before callbacks so that callbacks that
2086 * cancel everything don't cause us to use a session that no longer
2087 * exists... */
2088 process_pending_messages (session);
2089 session->last_activity = GNUNET_TIME_absolute_get ();
2090 pid = session->target;
2091 /* we'll now call callbacks that may cancel the session; hence
2092 * we should not use 'session' after this point */
2093 while (NULL != (pos = hd))
2094 {
2095 GNUNET_CONTAINER_DLL_remove (hd, tl, pos);
2096 if (NULL != pos->transmit_cont)
2097 pos->transmit_cont (pos->transmit_cont_cls,
2098 &pid,
2099 GNUNET_OK,
2100 pos->message_size,
2101 pos->message_size); /* FIXME: include TCP overhead */
2102 GNUNET_free (pos);
2103 }
2104 GNUNET_assert (NULL == hd);
2105 GNUNET_assert (NULL == tl);
2106 GNUNET_STATISTICS_update (plugin->env->stats,
2107 gettext_noop ("# bytes currently in TCP buffers"),
2108 -(int64_t) ret,
2109 GNUNET_NO);
2110 GNUNET_STATISTICS_update (plugin->env->stats,
2111 gettext_noop ("# bytes transmitted via TCP"),
2112 ret,
2113 GNUNET_NO);
2114 return ret;
2115}
2116
2117
2118/**
2119 * If we have pending messages, ask the server to
2120 * transmit them (schedule the respective tasks, etc.)
2121 *
2122 * @param session for which session should we do this
2123 */
2124static void
2125process_pending_messages (struct GNUNET_ATS_Session *session)
2126{
2127 struct PendingMessage *pm;
2128
2129 GNUNET_assert (NULL != session->client);
2130 if (NULL != session->transmit_handle)
2131 return;
2132 if (NULL == (pm = session->pending_messages_head))
2133 return;
2134
2135 session->transmit_handle =
2136 GNUNET_SERVER_notify_transmit_ready (session->client,
2137 pm->message_size,
2138 GNUNET_TIME_absolute_get_remaining (
2139 pm->timeout),
2140 &do_transmit,
2141 session);
2142}
2143
2144
2145/**
2146 * Function that can be used by the transport service to transmit
2147 * a message using the plugin. Note that in the case of a
2148 * peer disconnecting, the continuation MUST be called
2149 * prior to the disconnect notification itself. This function
2150 * will be called with this peer's HELLO message to initiate
2151 * a fresh connection to another peer.
2152 *
2153 * @param cls closure
2154 * @param session which session must be used
2155 * @param msgbuf the message to transmit
2156 * @param msgbuf_size number of bytes in @a msgbuf
2157 * @param priority how important is the message (most plugins will
2158 * ignore message priority and just FIFO)
2159 * @param to how long to wait at most for the transmission (does not
2160 * require plugins to discard the message after the timeout,
2161 * just advisory for the desired delay; most plugins will ignore
2162 * this as well)
2163 * @param cont continuation to call once the message has
2164 * been transmitted (or if the transport is ready
2165 * for the next transmission call; or if the
2166 * peer disconnected...); can be NULL
2167 * @param cont_cls closure for @a cont
2168 * @return number of bytes used (on the physical network, with overheads);
2169 * -1 on hard errors (i.e. address invalid); 0 is a legal value
2170 * and does NOT mean that the message was not transmitted (DV)
2171 */
2172static ssize_t
2173tcp_plugin_send (void *cls,
2174 struct GNUNET_ATS_Session *session,
2175 const char *msgbuf,
2176 size_t msgbuf_size,
2177 unsigned int priority,
2178 struct GNUNET_TIME_Relative to,
2179 GNUNET_TRANSPORT_TransmitContinuation cont,
2180 void *cont_cls)
2181{
2182 struct Plugin *plugin = cls;
2183 struct PendingMessage *pm;
2184
2185 /* create new message entry */
2186 pm = GNUNET_malloc (sizeof(struct PendingMessage) + msgbuf_size);
2187 pm->msg = (const char *) &pm[1];
2188 GNUNET_memcpy (&pm[1], msgbuf, msgbuf_size);
2189 pm->message_size = msgbuf_size;
2190 pm->timeout = GNUNET_TIME_relative_to_absolute (to);
2191 pm->transmit_cont = cont;
2192 pm->transmit_cont_cls = cont_cls;
2193
2194 LOG (GNUNET_ERROR_TYPE_DEBUG,
2195 "Asked to transmit %lu bytes to `%s', added message to list.\n",
2196 (unsigned long) msgbuf_size,
2197 GNUNET_i2s (&session->target));
2198
2199 if (GNUNET_YES ==
2200 GNUNET_CONTAINER_multipeermap_contains_value (plugin->sessionmap,
2201 &session->target,
2202 session))
2203 {
2204 GNUNET_assert (NULL != session->client);
2205 GNUNET_SERVER_client_set_timeout (session->client,
2206 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2207 GNUNET_STATISTICS_update (plugin->env->stats,
2208 gettext_noop ("# bytes currently in TCP buffers"),
2209 msgbuf_size,
2210 GNUNET_NO);
2211
2212 /* append pm to pending_messages list */
2213 GNUNET_CONTAINER_DLL_insert_tail (session->pending_messages_head,
2214 session->pending_messages_tail,
2215 pm);
2216 notify_session_monitor (session->plugin,
2217 session,
2218 GNUNET_TRANSPORT_SS_UPDATE);
2219 session->msgs_in_queue++;
2220 session->bytes_in_queue += pm->message_size;
2221 process_pending_messages (session);
2222 return msgbuf_size;
2223 }
2224 if (GNUNET_YES ==
2225 GNUNET_CONTAINER_multipeermap_contains_value (plugin->nat_wait_conns,
2226 &session->target,
2227 session))
2228 {
2229 LOG (GNUNET_ERROR_TYPE_DEBUG,
2230 "This NAT WAIT session for peer `%s' is not yet ready!\n",
2231 GNUNET_i2s (&session->target));
2232 GNUNET_STATISTICS_update (plugin->env->stats,
2233 gettext_noop ("# bytes currently in TCP buffers"),
2234 msgbuf_size,
2235 GNUNET_NO);
2236 /* append pm to pending_messages list */
2237 GNUNET_CONTAINER_DLL_insert_tail (session->pending_messages_head,
2238 session->pending_messages_tail,
2239 pm);
2240 session->msgs_in_queue++;
2241 session->bytes_in_queue += pm->message_size;
2242 notify_session_monitor (session->plugin,
2243 session,
2244 GNUNET_TRANSPORT_SS_HANDSHAKE);
2245 return msgbuf_size;
2246 }
2247 LOG (GNUNET_ERROR_TYPE_ERROR, "Invalid session %p\n", session);
2248 if (NULL != cont)
2249 cont (cont_cls, &session->target, GNUNET_SYSERR, pm->message_size, 0);
2250 GNUNET_break (0);
2251 GNUNET_free (pm);
2252 return GNUNET_SYSERR; /* session does not exist here */
2253}
2254
2255
2256/**
2257 * Closure for #session_lookup_it().
2258 */
2259struct GNUNET_ATS_SessionItCtx
2260{
2261 /**
2262 * Address we are looking for.
2263 */
2264 const struct GNUNET_HELLO_Address *address;
2265
2266 /**
2267 * Where to store the session (if we found it).
2268 */
2269 struct GNUNET_ATS_Session *result;
2270};
2271
2272
2273/**
2274 * Look for a session by address.
2275 *
2276 * @param cls the `struct GNUNET_ATS_SessionItCtx`
2277 * @param key unused
2278 * @param value a `struct GNUNET_ATS_Session`
2279 * @return #GNUNET_YES to continue looking, #GNUNET_NO if we found the session
2280 */
2281static int
2282session_lookup_it (void *cls,
2283 const struct GNUNET_PeerIdentity *key,
2284 void *value)
2285{
2286 struct GNUNET_ATS_SessionItCtx *si_ctx = cls;
2287 struct GNUNET_ATS_Session *session = value;
2288
2289 if (0 != GNUNET_HELLO_address_cmp (si_ctx->address, session->address))
2290 return GNUNET_YES;
2291 si_ctx->result = session;
2292 return GNUNET_NO;
2293}
2294
2295
2296/**
2297 * Task cleaning up a NAT connection attempt after timeout
2298 *
2299 * @param cls the `struct GNUNET_ATS_Session`
2300 */
2301static void
2302nat_connect_timeout (void *cls)
2303{
2304 struct GNUNET_ATS_Session *session = cls;
2305
2306 session->nat_connection_timeout = NULL;
2307 LOG (GNUNET_ERROR_TYPE_DEBUG,
2308 "NAT WAIT connection to `%4s' at `%s' could not be established, removing session\n",
2309 GNUNET_i2s (&session->target),
2310 tcp_plugin_address_to_string (session->plugin,
2311 session->address->address,
2312 session->address->address_length));
2313 tcp_plugin_disconnect_session (session->plugin, session);
2314}
2315
2316
2317/**
2318 * Function that will be called whenever the transport service wants to
2319 * notify the plugin that a session is still active and in use and
2320 * therefore the session timeout for this session has to be updated
2321 *
2322 * @param cls closure
2323 * @param peer which peer was the session for
2324 * @param session which session is being updated
2325 */
2326static void
2327tcp_plugin_update_session_timeout (void *cls,
2328 const struct GNUNET_PeerIdentity *peer,
2329 struct GNUNET_ATS_Session *session)
2330{
2331 reschedule_session_timeout (session);
2332}
2333
2334
2335/**
2336 * Task to signal the server that we can continue
2337 * receiving from the TCP client now.
2338 *
2339 * @param cls the `struct GNUNET_ATS_Session *`
2340 */
2341static void
2342delayed_done (void *cls)
2343{
2344 struct GNUNET_ATS_Session *session = cls;
2345
2346 session->receive_delay_task = NULL;
2347 reschedule_session_timeout (session);
2348 GNUNET_SERVER_receive_done (session->client, GNUNET_OK);
2349}
2350
2351
2352/**
2353 * Function that will be called whenever the transport service wants to
2354 * notify the plugin that the inbound quota changed and that the plugin
2355 * should update it's delay for the next receive value
2356 *
2357 * @param cls closure
2358 * @param peer which peer was the session for
2359 * @param session which session is being updated
2360 * @param delay new delay to use for receiving
2361 */
2362static void
2363tcp_plugin_update_inbound_delay (void *cls,
2364 const struct GNUNET_PeerIdentity *peer,
2365 struct GNUNET_ATS_Session *session,
2366 struct GNUNET_TIME_Relative delay)
2367{
2368 if (NULL == session->receive_delay_task)
2369 return;
2370 LOG (GNUNET_ERROR_TYPE_DEBUG,
2371 "New inbound delay %s\n",
2372 GNUNET_STRINGS_relative_time_to_string (delay, GNUNET_NO));
2373 session->receive_delay = GNUNET_TIME_relative_to_absolute (delay);
2374 GNUNET_SCHEDULER_cancel (session->receive_delay_task);
2375 session->receive_delay_task =
2376 GNUNET_SCHEDULER_add_delayed (delay, &delayed_done, session);
2377}
2378
2379
2380/**
2381 * Create a new session to transmit data to the target
2382 * This session will used to send data to this peer and the plugin will
2383 * notify us by calling the env->session_end function
2384 *
2385 * @param cls closure
2386 * @param address the address to use
2387 * @return the session if the address is valid, NULL otherwise
2388 */
2389static struct GNUNET_ATS_Session *
2390tcp_plugin_get_session (void *cls, const struct GNUNET_HELLO_Address *address)
2391{
2392 struct Plugin *plugin = cls;
2393 struct GNUNET_ATS_Session *session = NULL;
2394 int af;
2395 const void *sb;
2396 size_t sbs;
2397 struct GNUNET_CONNECTION_Handle *sa;
2398 struct sockaddr_in a4;
2399 struct sockaddr_in6 a6;
2400 const struct IPv4TcpAddress *t4;
2401 const struct IPv6TcpAddress *t6;
2402 unsigned int options;
2403 enum GNUNET_NetworkType net_type;
2404 unsigned int is_natd = GNUNET_NO;
2405 size_t addrlen;
2406
2407#ifdef TCP_STEALTH
2408 struct GNUNET_NETWORK_Handle *s;
2409#endif
2410
2411 addrlen = address->address_length;
2412 LOG (GNUNET_ERROR_TYPE_DEBUG,
2413 "Trying to get session for `%s' address of peer `%s'\n",
2414 tcp_plugin_address_to_string (plugin,
2415 address->address,
2416 address->address_length),
2417 GNUNET_i2s (&address->peer));
2418
2419 if (GNUNET_HELLO_address_check_option (address,
2420 GNUNET_HELLO_ADDRESS_INFO_INBOUND))
2421 {
2422 GNUNET_break (0);
2423 return NULL;
2424 }
2425
2426 /* look for existing session */
2427 if (GNUNET_YES == GNUNET_CONTAINER_multipeermap_contains (plugin->sessionmap,
2428 &address->peer))
2429 {
2430 struct GNUNET_ATS_SessionItCtx si_ctx;
2431
2432 si_ctx.address = address;
2433 si_ctx.result = NULL;
2434 GNUNET_CONTAINER_multipeermap_get_multiple (plugin->sessionmap,
2435 &address->peer,
2436 &session_lookup_it,
2437 &si_ctx);
2438 if (NULL != si_ctx.result)
2439 {
2440 session = si_ctx.result;
2441 LOG (GNUNET_ERROR_TYPE_DEBUG,
2442 "Found existing session for `%s' address `%s'\n",
2443 GNUNET_i2s (&address->peer),
2444 tcp_plugin_address_to_string (plugin,
2445 address->address,
2446 address->address_length));
2447 return session;
2448 }
2449 /* This is a bit of a hack, limiting TCP to never allow more than
2450 one TCP connection to any given peer at the same time.
2451 Without this, peers sometimes disagree about which of the TCP
2452 connections they should use, causing one side to believe that
2453 they transmit successfully, while the other receives nothing. */return NULL; /* Refuse to have more than one TCP connection per
2454 peer pair at the same time. */
2455 }
2456
2457 if (addrlen == sizeof(struct IPv6TcpAddress))
2458 {
2459 GNUNET_assert (NULL != address->address); /* make static analysis happy */
2460 t6 = address->address;
2461 options = t6->options;
2462 af = AF_INET6;
2463 memset (&a6, 0, sizeof(a6));
2464#if HAVE_SOCKADDR_IN_SIN_LEN
2465 a6.sin6_len = sizeof(a6);
2466#endif
2467 a6.sin6_family = AF_INET6;
2468 a6.sin6_port = t6->t6_port;
2469 if (t6->t6_port == 0)
2470 is_natd = GNUNET_YES;
2471 GNUNET_memcpy (&a6.sin6_addr, &t6->ipv6_addr, sizeof(struct in6_addr));
2472 sb = &a6;
2473 sbs = sizeof(a6);
2474 }
2475 else if (addrlen == sizeof(struct IPv4TcpAddress))
2476 {
2477 GNUNET_assert (NULL != address->address); /* make static analysis happy */
2478 t4 = address->address;
2479 options = t4->options;
2480 af = AF_INET;
2481 memset (&a4, 0, sizeof(a4));
2482#if HAVE_SOCKADDR_IN_SIN_LEN
2483 a4.sin_len = sizeof(a4);
2484#endif
2485 a4.sin_family = AF_INET;
2486 a4.sin_port = t4->t4_port;
2487 if (t4->t4_port == 0)
2488 is_natd = GNUNET_YES;
2489 a4.sin_addr.s_addr = t4->ipv4_addr;
2490 sb = &a4;
2491 sbs = sizeof(a4);
2492 }
2493 else
2494 {
2495 GNUNET_STATISTICS_update (
2496 plugin->env->stats,
2497 gettext_noop ("# requests to create session with invalid address"),
2498 1,
2499 GNUNET_NO);
2500 return NULL;
2501 }
2502
2503 net_type = plugin->env->get_address_type (plugin->env->cls, sb, sbs);
2504 GNUNET_break (net_type != GNUNET_NT_UNSPECIFIED);
2505
2506 if ((is_natd == GNUNET_YES) && (addrlen == sizeof(struct IPv6TcpAddress)))
2507 {
2508 /* NAT client only works with IPv4 addresses */
2509 return NULL;
2510 }
2511
2512 if (plugin->cur_connections >= plugin->max_connections)
2513 {
2514 /* saturated */
2515 return NULL;
2516 }
2517
2518 if ((is_natd == GNUNET_YES) &&
2519 (GNUNET_YES ==
2520 GNUNET_CONTAINER_multipeermap_contains (plugin->nat_wait_conns,
2521 &address->peer)))
2522 {
2523 /* Only do one NAT punch attempt per peer identity */
2524 return NULL;
2525 }
2526
2527 if ((is_natd == GNUNET_YES) && (NULL != plugin->nat) &&
2528 (GNUNET_NO ==
2529 GNUNET_CONTAINER_multipeermap_contains (plugin->nat_wait_conns,
2530 &address->peer)))
2531 {
2532 struct sockaddr_in local_sa;
2533
2534 LOG (GNUNET_ERROR_TYPE_DEBUG,
2535 "Found valid IPv4 NAT address (creating session)!\n");
2536 session = create_session (plugin, address, net_type, NULL, GNUNET_YES);
2537 session->nat_connection_timeout =
2538 GNUNET_SCHEDULER_add_delayed (NAT_TIMEOUT, &nat_connect_timeout, session);
2539 GNUNET_assert (GNUNET_OK ==
2540 GNUNET_CONTAINER_multipeermap_put (
2541 plugin->nat_wait_conns,
2542 &session->target,
2543 session,
2544 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
2545
2546 LOG (GNUNET_ERROR_TYPE_DEBUG,
2547 "Created NAT WAIT connection to `%s' at `%s'\n",
2548 GNUNET_i2s (&session->target),
2549 GNUNET_a2s (sb, sbs));
2550 memset (&local_sa, 0, sizeof(local_sa));
2551 local_sa.sin_family = AF_INET;
2552 local_sa.sin_port = htons (plugin->open_port);
2553 /* We leave sin_address at 0, let the kernel figure it out,
2554 even if our bind() is more specific. (May want to reconsider
2555 later.) */
2556 if (GNUNET_OK == GNUNET_NAT_request_reversal (plugin->nat, &local_sa, &a4))
2557 return session;
2558 LOG (GNUNET_ERROR_TYPE_DEBUG,
2559 "Running NAT client for `%s' at `%s' failed\n",
2560 GNUNET_i2s (&session->target),
2561 GNUNET_a2s (sb, sbs));
2562 tcp_plugin_disconnect_session (plugin, session);
2563 return NULL;
2564 }
2565
2566 /* create new outbound session */
2567 if (0 != (options & TCP_OPTIONS_TCP_STEALTH))
2568 {
2569#ifdef TCP_STEALTH
2570 s = GNUNET_NETWORK_socket_create (af, SOCK_STREAM, 0);
2571 if (NULL == s)
2572 {
2573 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK,
2574 "socket");
2575 sa = NULL;
2576 }
2577 else
2578 {
2579 if ((GNUNET_OK !=
2580 GNUNET_NETWORK_socket_setsockopt (s,
2581 IPPROTO_TCP,
2582 TCP_STEALTH,
2583 &session->target,
2584 sizeof(
2585 struct GNUNET_PeerIdentity))) ||
2586 (GNUNET_OK !=
2587 GNUNET_NETWORK_socket_setsockopt (s,
2588 IPPROTO_TCP,
2589 TCP_STEALTH_INTEGRITY,
2590 &plugin->my_welcome,
2591 sizeof(struct WelcomeMessage))))
2592 {
2593 /* TCP STEALTH not supported by kernel */
2594 GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (s));
2595 sa = NULL;
2596 }
2597 else
2598 {
2599 sa = GNUNET_CONNECTION_connect_socket (s, sb, sbs);
2600 }
2601 }
2602#else
2603 sa = NULL;
2604#endif
2605 }
2606 else
2607 {
2608 sa = GNUNET_CONNECTION_create_from_sockaddr (af, sb, sbs);
2609 }
2610 if (NULL == sa)
2611 {
2612 LOG (GNUNET_ERROR_TYPE_DEBUG,
2613 "Failed to create connection to `%s' at `%s'\n",
2614 GNUNET_i2s (&address->peer),
2615 GNUNET_a2s (sb, sbs));
2616 return NULL;
2617 }
2618 LOG (GNUNET_ERROR_TYPE_DEBUG,
2619 "Asked to transmit to `%s', creating fresh session using address `%s'.\n",
2620 GNUNET_i2s (&address->peer),
2621 GNUNET_a2s (sb, sbs));
2622
2623 session = create_session (plugin,
2624 address,
2625 net_type,
2626 GNUNET_SERVER_connect_socket (plugin->server, sa),
2627 GNUNET_NO);
2628 (void) GNUNET_CONTAINER_multipeermap_put (
2629 plugin->sessionmap,
2630 &session->target,
2631 session,
2632 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
2633 /* Send TCP Welcome */
2634 process_pending_messages (session);
2635
2636 return session;
2637}
2638
2639
2640/**
2641 * We have been asked to destroy all connections to a particular peer.
2642 * This function is called on each applicable session and must tear it
2643 * down.
2644 *
2645 * @param cls the `struct Plugin *`
2646 * @param key the peer which the session belongs to (unused)
2647 * @param value the `struct GNUNET_ATS_Session`
2648 * @return #GNUNET_YES (continue to iterate)
2649 */
2650static int
2651session_disconnect_it (void *cls,
2652 const struct GNUNET_PeerIdentity *key,
2653 void *value)
2654{
2655 struct Plugin *plugin = cls;
2656 struct GNUNET_ATS_Session *session = value;
2657
2658 GNUNET_STATISTICS_update (session->plugin->env->stats,
2659 gettext_noop (
2660 "# transport-service disconnect requests for TCP"),
2661 1,
2662 GNUNET_NO);
2663 tcp_plugin_disconnect_session (plugin, session);
2664 return GNUNET_YES;
2665}
2666
2667
2668/**
2669 * Function that can be called to force a disconnect from the
2670 * specified neighbour. This should also cancel all previously
2671 * scheduled transmissions. Obviously the transmission may have been
2672 * partially completed already, which is OK. The plugin is supposed
2673 * to close the connection (if applicable) and no longer call the
2674 * transmit continuation(s).
2675 *
2676 * Finally, plugin MUST NOT call the services's receive function to
2677 * notify the service that the connection to the specified target was
2678 * closed after a getting this call.
2679 *
2680 * @param cls closure
2681 * @param target peer for which the last transmission is
2682 * to be cancelled
2683 */
2684static void
2685tcp_plugin_disconnect (void *cls, const struct GNUNET_PeerIdentity *target)
2686{
2687 struct Plugin *plugin = cls;
2688
2689 LOG (GNUNET_ERROR_TYPE_DEBUG,
2690 "Disconnecting peer `%s'\n",
2691 GNUNET_i2s (target));
2692 GNUNET_CONTAINER_multipeermap_get_multiple (plugin->sessionmap,
2693 target,
2694 &session_disconnect_it,
2695 plugin);
2696 GNUNET_CONTAINER_multipeermap_get_multiple (plugin->nat_wait_conns,
2697 target,
2698 &session_disconnect_it,
2699 plugin);
2700}
2701
2702
2703/**
2704 * We are processing an address pretty printing request and finished
2705 * the IP resolution (if applicable). Append our port and forward the
2706 * result. If called with @a hostname NULL, we are done and should
2707 * clean up the pretty printer (otherwise, there might be multiple
2708 * hostnames for the IP address and we might receive more).
2709 *
2710 * @param cls the `struct PrettyPrinterContext *`
2711 * @param hostname hostname part of the address
2712 */
2713static void
2714append_port (void *cls, const char *hostname)
2715{
2716 struct PrettyPrinterContext *ppc = cls;
2717 struct Plugin *plugin = ppc->plugin;
2718 char *ret;
2719
2720 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2721 "append_port called with hostname `%s'\n",
2722 hostname);
2723 if (NULL == hostname)
2724 {
2725 /* Final call, done */
2726 ppc->resolver_handle = NULL;
2727 GNUNET_CONTAINER_DLL_remove (plugin->ppc_dll_head,
2728 plugin->ppc_dll_tail,
2729 ppc);
2730 ppc->asc (ppc->asc_cls, NULL, GNUNET_OK);
2731 GNUNET_free (ppc);
2732 return;
2733 }
2734 if (GNUNET_YES == ppc->ipv6)
2735 GNUNET_asprintf (&ret,
2736 "%s.%u.[%s]:%d",
2737 PLUGIN_NAME,
2738 ppc->options,
2739 hostname,
2740 ppc->port);
2741 else
2742 GNUNET_asprintf (&ret,
2743 "%s.%u.%s:%d",
2744 PLUGIN_NAME,
2745 ppc->options,
2746 hostname,
2747 ppc->port);
2748 ppc->asc (ppc->asc_cls, ret, GNUNET_OK);
2749 GNUNET_free (ret);
2750}
2751
2752
2753/**
2754 * Convert the transports address to a nice, human-readable format.
2755 *
2756 * @param cls closure with the `struct Plugin`
2757 * @param type name of the transport that generated the address
2758 * @param addr one of the addresses of the host, NULL for the last address
2759 * the specific address format depends on the transport
2760 * @param addrlen length of the @a addr
2761 * @param numeric should (IP) addresses be displayed in numeric form?
2762 * @param timeout after how long should we give up?
2763 * @param asc function to call on each string
2764 * @param asc_cls closure for @a asc
2765 */
2766static void
2767tcp_plugin_address_pretty_printer (void *cls,
2768 const char *type,
2769 const void *addr,
2770 size_t addrlen,
2771 int numeric,
2772 struct GNUNET_TIME_Relative timeout,
2773 GNUNET_TRANSPORT_AddressStringCallback asc,
2774 void *asc_cls)
2775{
2776 struct Plugin *plugin = cls;
2777 struct PrettyPrinterContext *ppc;
2778 const void *sb;
2779 size_t sbs;
2780 struct sockaddr_in a4;
2781 struct sockaddr_in6 a6;
2782 const struct IPv4TcpAddress *t4;
2783 const struct IPv6TcpAddress *t6;
2784 uint16_t port;
2785 uint32_t options;
2786
2787 if (sizeof(struct IPv6TcpAddress) == addrlen)
2788 {
2789 t6 = addr;
2790 memset (&a6, 0, sizeof(a6));
2791 a6.sin6_family = AF_INET6;
2792 a6.sin6_port = t6->t6_port;
2793 GNUNET_memcpy (&a6.sin6_addr, &t6->ipv6_addr, sizeof(struct in6_addr));
2794 port = ntohs (t6->t6_port);
2795 options = ntohl (t6->options);
2796 sb = &a6;
2797 sbs = sizeof(a6);
2798 }
2799 else if (sizeof(struct IPv4TcpAddress) == addrlen)
2800 {
2801 t4 = addr;
2802 memset (&a4, 0, sizeof(a4));
2803 a4.sin_family = AF_INET;
2804 a4.sin_port = t4->t4_port;
2805 a4.sin_addr.s_addr = t4->ipv4_addr;
2806 port = ntohs (t4->t4_port);
2807 options = ntohl (t4->options);
2808 sb = &a4;
2809 sbs = sizeof(a4);
2810 }
2811 else
2812 {
2813 /* invalid address */
2814 LOG (GNUNET_ERROR_TYPE_WARNING,
2815 _ ("Unexpected address length: %u bytes\n"),
2816 (unsigned int) addrlen);
2817 asc (asc_cls, NULL, GNUNET_SYSERR);
2818 asc (asc_cls, NULL, GNUNET_OK);
2819 return;
2820 }
2821 ppc = GNUNET_new (struct PrettyPrinterContext);
2822 ppc->plugin = plugin;
2823 if (addrlen == sizeof(struct IPv6TcpAddress))
2824 ppc->ipv6 = GNUNET_YES;
2825 else
2826 ppc->ipv6 = GNUNET_NO;
2827 ppc->asc = asc;
2828 ppc->asc_cls = asc_cls;
2829 ppc->port = port;
2830 ppc->options = options;
2831 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting DNS reverse lookup\n");
2832 ppc->resolver_handle = GNUNET_RESOLVER_hostname_get (sb,
2833 sbs,
2834 ! numeric,
2835 timeout,
2836 &append_port,
2837 ppc);
2838 if (NULL == ppc->resolver_handle)
2839 {
2840 GNUNET_break (0);
2841 GNUNET_free (ppc);
2842 return;
2843 }
2844 GNUNET_CONTAINER_DLL_insert (plugin->ppc_dll_head, plugin->ppc_dll_tail, ppc);
2845}
2846
2847
2848/**
2849 * Function that will be called to check if a binary address for this
2850 * plugin is well-formed and corresponds to an address for THIS peer
2851 * (as per our configuration). Naturally, if absolutely necessary,
2852 * plugins can be a bit conservative in their answer, but in general
2853 * plugins should make sure that the address does not redirect
2854 * traffic to a 3rd party that might try to man-in-the-middle our
2855 * traffic.
2856 *
2857 * @param cls closure, our `struct Plugin *`
2858 * @param addr pointer to the address
2859 * @param addrlen length of @a addr
2860 * @return #GNUNET_OK if this is a plausible address for this peer
2861 * and transport, #GNUNET_SYSERR if not
2862 */
2863static int
2864tcp_plugin_check_address (void *cls, const void *addr, size_t addrlen)
2865{
2866 struct Plugin *plugin = cls;
2867 const struct IPv4TcpAddress *v4;
2868 const struct IPv6TcpAddress *v6;
2869
2870 if ((addrlen != sizeof(struct IPv4TcpAddress)) &&
2871 (addrlen != sizeof(struct IPv6TcpAddress)))
2872 {
2873 GNUNET_break_op (0);
2874 return GNUNET_SYSERR;
2875 }
2876
2877 if (addrlen == sizeof(struct IPv4TcpAddress))
2878 {
2879 struct sockaddr_in s4;
2880
2881 v4 = (const struct IPv4TcpAddress *) addr;
2882 if (0 != memcmp (&v4->options, &plugin->myoptions, sizeof(uint32_t)))
2883 {
2884 GNUNET_break (0);
2885 return GNUNET_SYSERR;
2886 }
2887 memset (&s4, 0, sizeof(s4));
2888 s4.sin_family = AF_INET;
2889#if HAVE_SOCKADDR_IN_SIN_LEN
2890 s4.sin_len = sizeof(s4);
2891#endif
2892 s4.sin_port = v4->t4_port;
2893 s4.sin_addr.s_addr = v4->ipv4_addr;
2894
2895 if (GNUNET_OK !=
2896 GNUNET_NAT_test_address (plugin->nat, &s4, sizeof(struct sockaddr_in)))
2897 return GNUNET_SYSERR;
2898 }
2899 else
2900 {
2901 struct sockaddr_in6 s6;
2902
2903 v6 = (const struct IPv6TcpAddress *) addr;
2904 if (IN6_IS_ADDR_LINKLOCAL (&v6->ipv6_addr))
2905 {
2906 GNUNET_break_op (0);
2907 return GNUNET_SYSERR;
2908 }
2909 if (0 != memcmp (&v6->options, &plugin->myoptions, sizeof(uint32_t)))
2910 {
2911 GNUNET_break (0);
2912 return GNUNET_SYSERR;
2913 }
2914 memset (&s6, 0, sizeof(s6));
2915 s6.sin6_family = AF_INET6;
2916#if HAVE_SOCKADDR_IN_SIN_LEN
2917 s6.sin6_len = sizeof(s6);
2918#endif
2919 s6.sin6_port = v6->t6_port;
2920 s6.sin6_addr = v6->ipv6_addr;
2921
2922 if (GNUNET_OK != GNUNET_NAT_test_address (plugin->nat,
2923 &s6,
2924 sizeof(struct sockaddr_in6)))
2925 return GNUNET_SYSERR;
2926 }
2927 return GNUNET_OK;
2928}
2929
2930
2931/**
2932 * We've received a nat probe from this peer via TCP. Finish
2933 * creating the client session and resume sending of queued
2934 * messages.
2935 *
2936 * @param cls closure
2937 * @param client identification of the client
2938 * @param message the actual message
2939 */
2940static void
2941handle_tcp_nat_probe (void *cls,
2942 struct GNUNET_SERVER_Client *client,
2943 const struct GNUNET_MessageHeader *message)
2944{
2945 struct Plugin *plugin = cls;
2946 struct GNUNET_ATS_Session *session;
2947 const struct TCP_NAT_ProbeMessage *tcp_nat_probe;
2948 size_t alen;
2949 void *vaddr;
2950 struct IPv4TcpAddress *t4;
2951 struct IPv6TcpAddress *t6;
2952 const struct sockaddr_in *s4;
2953 const struct sockaddr_in6 *s6;
2954
2955 LOG (GNUNET_ERROR_TYPE_DEBUG, "Received NAT probe\n");
2956 /* We have received a TCP NAT probe, meaning we (hopefully) initiated
2957 * a connection to this peer by running gnunet-nat-client. This peer
2958 * received the punch message and now wants us to use the new connection
2959 * as the default for that peer. Do so and then send a WELCOME message
2960 * so we can really be connected!
2961 */if (ntohs (message->size) != sizeof(struct TCP_NAT_ProbeMessage))
2962 {
2963 GNUNET_break_op (0);
2964 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2965 return;
2966 }
2967
2968 tcp_nat_probe = (const struct TCP_NAT_ProbeMessage *) message;
2969 if (0 == memcmp (&tcp_nat_probe->clientIdentity,
2970 plugin->env->my_identity,
2971 sizeof(struct GNUNET_PeerIdentity)))
2972 {
2973 /* refuse connections from ourselves */
2974 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2975 return;
2976 }
2977
2978 session = GNUNET_CONTAINER_multipeermap_get (plugin->nat_wait_conns,
2979 &tcp_nat_probe->clientIdentity);
2980 if (NULL == session)
2981 {
2982 LOG (GNUNET_ERROR_TYPE_DEBUG, "Did NOT find session for NAT probe!\n");
2983 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2984 return;
2985 }
2986 LOG (GNUNET_ERROR_TYPE_DEBUG, "Found session for NAT probe!\n");
2987
2988 if (NULL != session->nat_connection_timeout)
2989 {
2990 GNUNET_SCHEDULER_cancel (session->nat_connection_timeout);
2991 session->nat_connection_timeout = NULL;
2992 }
2993
2994 if (GNUNET_OK != GNUNET_SERVER_client_get_address (client, &vaddr, &alen))
2995 {
2996 GNUNET_break (0);
2997 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2998 tcp_plugin_disconnect_session (plugin, session);
2999 return;
3000 }
3001 GNUNET_assert (
3002 GNUNET_YES ==
3003 GNUNET_CONTAINER_multipeermap_remove (plugin->nat_wait_conns,
3004 &tcp_nat_probe->clientIdentity,
3005 session));
3006 GNUNET_SERVER_client_set_user_context (client, session);
3007 (void) GNUNET_CONTAINER_multipeermap_put (
3008 plugin->sessionmap,
3009 &session->target,
3010 session,
3011 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
3012 session->last_activity = GNUNET_TIME_absolute_get ();
3013 LOG (GNUNET_ERROR_TYPE_DEBUG,
3014 "Found address `%s' for incoming connection\n",
3015 GNUNET_a2s (vaddr, alen));
3016 switch (((const struct sockaddr *) vaddr)->sa_family)
3017 {
3018 case AF_INET:
3019 s4 = vaddr;
3020 t4 = GNUNET_new (struct IPv4TcpAddress);
3021 t4->options = htonl (TCP_OPTIONS_NONE);
3022 t4->t4_port = s4->sin_port;
3023 t4->ipv4_addr = s4->sin_addr.s_addr;
3024 session->address =
3025 GNUNET_HELLO_address_allocate (&tcp_nat_probe->clientIdentity,
3026 PLUGIN_NAME,
3027 &t4,
3028 sizeof(struct IPv4TcpAddress),
3029 GNUNET_HELLO_ADDRESS_INFO_NONE);
3030 break;
3031
3032 case AF_INET6:
3033 s6 = vaddr;
3034 t6 = GNUNET_new (struct IPv6TcpAddress);
3035 t6->options = htonl (TCP_OPTIONS_NONE);
3036 t6->t6_port = s6->sin6_port;
3037 GNUNET_memcpy (&t6->ipv6_addr, &s6->sin6_addr, sizeof(struct in6_addr));
3038 session->address =
3039 GNUNET_HELLO_address_allocate (&tcp_nat_probe->clientIdentity,
3040 PLUGIN_NAME,
3041 &t6,
3042 sizeof(struct IPv6TcpAddress),
3043 GNUNET_HELLO_ADDRESS_INFO_NONE);
3044 break;
3045
3046 default:
3047 GNUNET_break_op (0);
3048 LOG (GNUNET_ERROR_TYPE_DEBUG, "Bad address for incoming connection!\n");
3049 GNUNET_free (vaddr);
3050 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3051 tcp_plugin_disconnect_session (plugin, session);
3052 return;
3053 }
3054 GNUNET_free (vaddr);
3055 GNUNET_break (NULL == session->client);
3056 session->client = client;
3057 GNUNET_STATISTICS_update (plugin->env->stats,
3058 gettext_noop ("# TCP sessions active"),
3059 1,
3060 GNUNET_NO);
3061 process_pending_messages (session);
3062 GNUNET_SERVER_receive_done (client, GNUNET_OK);
3063}
3064
3065
3066/**
3067 * We've received a welcome from this peer via TCP. Possibly create a
3068 * fresh client record and send back our welcome.
3069 *
3070 * @param cls closure
3071 * @param client identification of the client
3072 * @param message the actual message
3073 */
3074static void
3075handle_tcp_welcome (void *cls,
3076 struct GNUNET_SERVER_Client *client,
3077 const struct GNUNET_MessageHeader *message)
3078{
3079 struct Plugin *plugin = cls;
3080 const struct WelcomeMessage *wm = (const struct WelcomeMessage *) message;
3081 struct GNUNET_HELLO_Address *address;
3082 struct GNUNET_ATS_Session *session;
3083 size_t alen;
3084 void *vaddr;
3085 struct IPv4TcpAddress t4;
3086 struct IPv6TcpAddress t6;
3087 const struct sockaddr_in *s4;
3088 const struct sockaddr_in6 *s6;
3089
3090 if (0 == memcmp (&wm->clientIdentity,
3091 plugin->env->my_identity,
3092 sizeof(struct GNUNET_PeerIdentity)))
3093 {
3094 /* refuse connections from ourselves */
3095 if (GNUNET_OK == GNUNET_SERVER_client_get_address (client, &vaddr, &alen))
3096 {
3097 LOG (GNUNET_ERROR_TYPE_INFO,
3098 "Received WELCOME message from my own identity `%s' on address `%s'\n",
3099 GNUNET_i2s (&wm->clientIdentity),
3100 GNUNET_a2s (vaddr, alen));
3101 GNUNET_free (vaddr);
3102 }
3103 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3104 return;
3105 }
3106
3107 if (GNUNET_OK == GNUNET_SERVER_client_get_address (client, &vaddr, &alen))
3108 {
3109 LOG (GNUNET_ERROR_TYPE_DEBUG,
3110 "Received WELCOME message from `%s' on address `%s'\n",
3111 GNUNET_i2s (&wm->clientIdentity),
3112 GNUNET_a2s (vaddr, alen));
3113 GNUNET_free (vaddr);
3114 }
3115 GNUNET_STATISTICS_update (plugin->env->stats,
3116 gettext_noop ("# TCP WELCOME messages received"),
3117 1,
3118 GNUNET_NO);
3119 session = lookup_session_by_client (plugin, client);
3120 if (NULL != session)
3121 {
3122 if (GNUNET_OK == GNUNET_SERVER_client_get_address (client, &vaddr, &alen))
3123 {
3124 LOG (GNUNET_ERROR_TYPE_DEBUG,
3125 "Found existing session %p for peer `%s'\n",
3126 session,
3127 GNUNET_a2s (vaddr, alen));
3128 GNUNET_free (vaddr);
3129 }
3130 }
3131 else
3132 {
3133 if (GNUNET_OK == GNUNET_SERVER_client_get_address (client, &vaddr, &alen))
3134 {
3135 if (alen == sizeof(struct sockaddr_in))
3136 {
3137 s4 = vaddr;
3138 memset (&t4, '\0', sizeof(t4));
3139 t4.options = htonl (TCP_OPTIONS_NONE);
3140 t4.t4_port = s4->sin_port;
3141 t4.ipv4_addr = s4->sin_addr.s_addr;
3142 address =
3143 GNUNET_HELLO_address_allocate (&wm->clientIdentity,
3144 PLUGIN_NAME,
3145 &t4,
3146 sizeof(t4),
3147 GNUNET_HELLO_ADDRESS_INFO_INBOUND);
3148 }
3149 else if (alen == sizeof(struct sockaddr_in6))
3150 {
3151 s6 = vaddr;
3152 memset (&t6, '\0', sizeof(t6));
3153 t6.options = htonl (TCP_OPTIONS_NONE);
3154 t6.t6_port = s6->sin6_port;
3155 GNUNET_memcpy (&t6.ipv6_addr, &s6->sin6_addr, sizeof(struct in6_addr));
3156 address =
3157 GNUNET_HELLO_address_allocate (&wm->clientIdentity,
3158 PLUGIN_NAME,
3159 &t6,
3160 sizeof(t6),
3161 GNUNET_HELLO_ADDRESS_INFO_INBOUND);
3162 }
3163 else
3164 {
3165 GNUNET_break (0);
3166 GNUNET_free (vaddr);
3167 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3168 return;
3169 }
3170 session = create_session (plugin,
3171 address,
3172 plugin->env->get_address_type (plugin->env->cls,
3173 vaddr,
3174 alen),
3175 client,
3176 GNUNET_NO);
3177 GNUNET_break (GNUNET_NT_UNSPECIFIED != session->scope);
3178 GNUNET_HELLO_address_free (address);
3179 LOG (GNUNET_ERROR_TYPE_DEBUG,
3180 "Creating new%s session %p for peer `%s' client %p\n",
3181 GNUNET_HELLO_address_check_option (session->address,
3182 GNUNET_HELLO_ADDRESS_INFO_INBOUND)
3183 ? " inbound"
3184 : "",
3185 session,
3186 tcp_plugin_address_to_string (plugin,
3187 session->address->address,
3188 session->address->address_length),
3189 client);
3190 GNUNET_free (vaddr);
3191 (void) GNUNET_CONTAINER_multipeermap_put (
3192 plugin->sessionmap,
3193 &session->target,
3194 session,
3195 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
3196 /* Notify transport and ATS about new session */
3197 plugin->env->session_start (plugin->env->cls,
3198 session->address,
3199 session,
3200 session->scope);
3201 }
3202 else
3203 {
3204 LOG (GNUNET_ERROR_TYPE_DEBUG,
3205 "Did not obtain TCP socket address for incoming connection\n");
3206 GNUNET_break (0);
3207 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3208 return;
3209 }
3210 }
3211
3212 if (GNUNET_YES != session->expecting_welcome)
3213 {
3214 GNUNET_break_op (0);
3215 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3216 return;
3217 }
3218 session->last_activity = GNUNET_TIME_absolute_get ();
3219 session->expecting_welcome = GNUNET_NO;
3220
3221 process_pending_messages (session);
3222 GNUNET_SERVER_client_set_timeout (client,
3223 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
3224 GNUNET_SERVER_receive_done (client, GNUNET_OK);
3225}
3226
3227
3228/**
3229 * We've received data for this peer via TCP. Unbox,
3230 * compute latency and forward.
3231 *
3232 * @param cls closure
3233 * @param client identification of the client
3234 * @param message the actual message
3235 */
3236static void
3237handle_tcp_data (void *cls,
3238 struct GNUNET_SERVER_Client *client,
3239 const struct GNUNET_MessageHeader *message)
3240{
3241 struct Plugin *plugin = cls;
3242 struct GNUNET_ATS_Session *session;
3243 struct GNUNET_TIME_Relative delay;
3244 uint16_t type;
3245
3246 type = ntohs (message->type);
3247 if ((GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_WELCOME == type) ||
3248 (GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_NAT_PROBE == type))
3249 {
3250 /* We don't want to propagate WELCOME and NAT Probe messages up! */
3251 GNUNET_SERVER_receive_done (client, GNUNET_OK);
3252 return;
3253 }
3254 session = lookup_session_by_client (plugin, client);
3255 if (NULL == session)
3256 {
3257 /* No inbound session found */
3258 void *vaddr = NULL;
3259 size_t alen;
3260
3261 GNUNET_assert (GNUNET_OK ==
3262 GNUNET_SERVER_client_get_address (client, &vaddr, &alen));
3263 LOG (GNUNET_ERROR_TYPE_ERROR,
3264 "Received unexpected %u bytes of type %u from `%s'\n",
3265 (unsigned int) ntohs (message->size),
3266 (unsigned int) ntohs (message->type),
3267 GNUNET_a2s (vaddr, alen));
3268 GNUNET_break_op (0);
3269 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3270 GNUNET_free (vaddr);
3271 return;
3272 }
3273 if (GNUNET_YES == session->expecting_welcome)
3274 {
3275 /* Session is expecting WELCOME message */
3276 void *vaddr = NULL;
3277 size_t alen;
3278
3279 GNUNET_SERVER_client_get_address (client, &vaddr, &alen);
3280 LOG (GNUNET_ERROR_TYPE_ERROR,
3281 "Received unexpected %u bytes of type %u from `%s'\n",
3282 (unsigned int) ntohs (message->size),
3283 (unsigned int) ntohs (message->type),
3284 GNUNET_a2s (vaddr, alen));
3285 GNUNET_break_op (0);
3286 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3287 GNUNET_free (vaddr);
3288 return;
3289 }
3290
3291 session->last_activity = GNUNET_TIME_absolute_get ();
3292 {
3293 void *vaddr = NULL;
3294 size_t alen;
3295
3296 GNUNET_SERVER_client_get_address (client, &vaddr, &alen);
3297 LOG (GNUNET_ERROR_TYPE_DEBUG,
3298 "Passing %u bytes of type %u from `%s' at %s to transport service.\n",
3299 (unsigned int) ntohs (message->size),
3300 (unsigned int) ntohs (message->type),
3301 GNUNET_i2s (&session->target),
3302 GNUNET_a2s (vaddr, alen));
3303 GNUNET_free (vaddr);
3304 }
3305
3306 GNUNET_STATISTICS_update (plugin->env->stats,
3307 gettext_noop ("# bytes received via TCP"),
3308 ntohs (message->size),
3309 GNUNET_NO);
3310
3311 GNUNET_assert (
3312 GNUNET_CONTAINER_multipeermap_contains_value (plugin->sessionmap,
3313 &session->target,
3314 session));
3315 delay =
3316 plugin->env->receive (plugin->env->cls, session->address, session, message);
3317 reschedule_session_timeout (session);
3318 if (0 == delay.rel_value_us)
3319 {
3320 GNUNET_SERVER_receive_done (client, GNUNET_OK);
3321 }
3322 else
3323 {
3324 LOG (GNUNET_ERROR_TYPE_DEBUG,
3325 "Throttling receiving from `%s' for %s\n",
3326 GNUNET_i2s (&session->target),
3327 GNUNET_STRINGS_relative_time_to_string (delay, GNUNET_YES));
3328 GNUNET_SERVER_disable_receive_done_warning (client);
3329 GNUNET_assert (NULL == session->receive_delay_task);
3330 session->receive_delay_task =
3331 GNUNET_SCHEDULER_add_delayed (delay, &delayed_done, session);
3332 }
3333}
3334
3335
3336/**
3337 * Function called whenever a peer is connected on the "SERVER" level.
3338 * Increments number of active connections and suspends server if we
3339 * have reached the limit.
3340 *
3341 * @param cls closure
3342 * @param client identification of the client
3343 */
3344static void
3345connect_notify (void *cls, struct GNUNET_SERVER_Client *client)
3346{
3347 struct Plugin *plugin = cls;
3348
3349 if (NULL == client)
3350 return;
3351 plugin->cur_connections++;
3352 GNUNET_STATISTICS_set (plugin->env->stats,
3353 gettext_noop ("# TCP server connections active"),
3354 plugin->cur_connections,
3355 GNUNET_NO);
3356 GNUNET_STATISTICS_update (plugin->env->stats,
3357 gettext_noop ("# TCP server connect events"),
3358 1,
3359 GNUNET_NO);
3360 if (plugin->cur_connections != plugin->max_connections)
3361 return;
3362 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3363 _ ("TCP connection limit reached, suspending server\n"));
3364 GNUNET_STATISTICS_update (plugin->env->stats,
3365 gettext_noop ("# TCP service suspended"),
3366 1,
3367 GNUNET_NO);
3368 GNUNET_SERVER_suspend (
3369 plugin->server); /* Maximum number of connections rechead */
3370}
3371
3372
3373/**
3374 * Function called whenever a peer is disconnected on the "SERVER"
3375 * level. Cleans up the connection, decrements number of active
3376 * connections and if applicable resumes listening.
3377 *
3378 * @param cls closure
3379 * @param client identification of the client
3380 */
3381static void
3382disconnect_notify (void *cls, struct GNUNET_SERVER_Client *client)
3383{
3384 struct Plugin *plugin = cls;
3385 struct GNUNET_ATS_Session *session;
3386
3387 if (NULL == client)
3388 return;
3389 GNUNET_assert (plugin->cur_connections >= 1);
3390 plugin->cur_connections--;
3391 session = lookup_session_by_client (plugin, client);
3392 if (NULL == session)
3393 return; /* unknown, nothing to do */
3394 LOG (GNUNET_ERROR_TYPE_DEBUG,
3395 "Destroying session of `%s' with %s due to network-level disconnect.\n",
3396 GNUNET_i2s (&session->target),
3397 tcp_plugin_address_to_string (session->plugin,
3398 session->address->address,
3399 session->address->address_length));
3400
3401 if (plugin->cur_connections == plugin->max_connections)
3402 {
3403 GNUNET_STATISTICS_update (session->plugin->env->stats,
3404 gettext_noop ("# TCP service resumed"),
3405 1,
3406 GNUNET_NO);
3407 GNUNET_SERVER_resume (plugin->server); /* Resume server */
3408 }
3409 GNUNET_STATISTICS_set (plugin->env->stats,
3410 gettext_noop ("# TCP server connections active"),
3411 plugin->cur_connections,
3412 GNUNET_NO);
3413 GNUNET_STATISTICS_update (session->plugin->env->stats,
3414 gettext_noop (
3415 "# network-level TCP disconnect events"),
3416 1,
3417 GNUNET_NO);
3418 tcp_plugin_disconnect_session (plugin, session);
3419}
3420
3421
3422/**
3423 * We can now send a probe message, copy into buffer to really send.
3424 *
3425 * @param cls closure, a `struct TCPProbeContext`
3426 * @param size max size to copy
3427 * @param buf buffer to copy message to
3428 * @return number of bytes copied into @a buf
3429 */
3430static size_t
3431notify_send_probe (void *cls, size_t size, void *buf)
3432{
3433 struct TCPProbeContext *tcp_probe_ctx = cls;
3434 struct Plugin *plugin = tcp_probe_ctx->plugin;
3435 size_t ret;
3436
3437 tcp_probe_ctx->transmit_handle = NULL;
3438 GNUNET_CONTAINER_DLL_remove (plugin->probe_head,
3439 plugin->probe_tail,
3440 tcp_probe_ctx);
3441 if (NULL == buf)
3442 {
3443 GNUNET_CONNECTION_destroy (tcp_probe_ctx->sock);
3444 GNUNET_free (tcp_probe_ctx);
3445 return 0;
3446 }
3447 GNUNET_assert (size >= sizeof(tcp_probe_ctx->message));
3448 GNUNET_memcpy (buf, &tcp_probe_ctx->message, sizeof(tcp_probe_ctx->message));
3449 GNUNET_SERVER_connect_socket (tcp_probe_ctx->plugin->server,
3450 tcp_probe_ctx->sock);
3451 ret = sizeof(tcp_probe_ctx->message);
3452 GNUNET_free (tcp_probe_ctx);
3453 return ret;
3454}
3455
3456
3457/**
3458 * Function called by the NAT subsystem suggesting another peer wants
3459 * to connect to us via connection reversal. Try to connect back to the
3460 * given IP.
3461 *
3462 * @param cls closure
3463 * @param addr address to try
3464 * @param addrlen number of bytes in @a addr
3465 */
3466static void
3467try_connection_reversal (void *cls,
3468 const struct sockaddr *addr,
3469 socklen_t addrlen)
3470{
3471 struct Plugin *plugin = cls;
3472 struct GNUNET_CONNECTION_Handle *sock;
3473 struct TCPProbeContext *tcp_probe_ctx;
3474
3475 /**
3476 * We have received an ICMP response, ostensibly from a peer
3477 * that wants to connect to us! Send a message to establish a connection.
3478 */
3479 sock = GNUNET_CONNECTION_create_from_sockaddr (AF_INET, addr, addrlen);
3480 if (NULL == sock)
3481 {
3482 /* failed for some odd reason (out of sockets?); ignore attempt */
3483 return;
3484 }
3485
3486 tcp_probe_ctx = GNUNET_new (struct TCPProbeContext);
3487 tcp_probe_ctx->message.header.size =
3488 htons (sizeof(struct TCP_NAT_ProbeMessage));
3489 tcp_probe_ctx->message.header.type =
3490 htons (GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_NAT_PROBE);
3491 tcp_probe_ctx->message.clientIdentity = *plugin->env->my_identity;
3492 tcp_probe_ctx->plugin = plugin;
3493 tcp_probe_ctx->sock = sock;
3494 GNUNET_CONTAINER_DLL_insert (plugin->probe_head,
3495 plugin->probe_tail,
3496 tcp_probe_ctx);
3497 tcp_probe_ctx->transmit_handle =
3498 GNUNET_CONNECTION_notify_transmit_ready (sock,
3499 ntohs (tcp_probe_ctx->message
3500 .header.size),
3501 GNUNET_TIME_UNIT_FOREVER_REL,
3502 &notify_send_probe,
3503 tcp_probe_ctx);
3504}
3505
3506
3507/**
3508 * Function obtain the network type for a session
3509 *
3510 * @param cls closure (`struct Plugin *`)
3511 * @param session the session
3512 * @return the network type in HBO or #GNUNET_SYSERR
3513 */
3514static enum GNUNET_NetworkType
3515tcp_plugin_get_network (void *cls, struct GNUNET_ATS_Session *session)
3516{
3517 return session->scope;
3518}
3519
3520
3521/**
3522 * Function obtain the network type for an address.
3523 *
3524 * @param cls closure (`struct Plugin *`)
3525 * @param address the address
3526 * @return the network type
3527 */
3528static enum GNUNET_NetworkType
3529tcp_plugin_get_network_for_address (void *cls,
3530 const struct GNUNET_HELLO_Address *address)
3531{
3532 struct Plugin *plugin = cls;
3533 size_t addrlen;
3534 struct sockaddr_in a4;
3535 struct sockaddr_in6 a6;
3536 const struct IPv4TcpAddress *t4;
3537 const struct IPv6TcpAddress *t6;
3538 const void *sb;
3539 size_t sbs;
3540
3541 addrlen = address->address_length;
3542 if (addrlen == sizeof(struct IPv6TcpAddress))
3543 {
3544 GNUNET_assert (NULL != address->address); /* make static analysis happy */
3545 t6 = address->address;
3546 memset (&a6, 0, sizeof(a6));
3547#if HAVE_SOCKADDR_IN_SIN_LEN
3548 a6.sin6_len = sizeof(a6);
3549#endif
3550 a6.sin6_family = AF_INET6;
3551 a6.sin6_port = t6->t6_port;
3552 GNUNET_memcpy (&a6.sin6_addr, &t6->ipv6_addr, sizeof(struct in6_addr));
3553 sb = &a6;
3554 sbs = sizeof(a6);
3555 }
3556 else if (addrlen == sizeof(struct IPv4TcpAddress))
3557 {
3558 GNUNET_assert (NULL != address->address); /* make static analysis happy */
3559 t4 = address->address;
3560 memset (&a4, 0, sizeof(a4));
3561#if HAVE_SOCKADDR_IN_SIN_LEN
3562 a4.sin_len = sizeof(a4);
3563#endif
3564 a4.sin_family = AF_INET;
3565 a4.sin_port = t4->t4_port;
3566 a4.sin_addr.s_addr = t4->ipv4_addr;
3567 sb = &a4;
3568 sbs = sizeof(a4);
3569 }
3570 else
3571 {
3572 GNUNET_break (0);
3573 return GNUNET_NT_UNSPECIFIED;
3574 }
3575 return plugin->env->get_address_type (plugin->env->cls, sb, sbs);
3576}
3577
3578
3579/**
3580 * Return information about the given session to the
3581 * monitor callback.
3582 *
3583 * @param cls the `struct Plugin` with the monitor callback (`sic`)
3584 * @param peer peer we send information about
3585 * @param value our `struct GNUNET_ATS_Session` to send information about
3586 * @return #GNUNET_OK (continue to iterate)
3587 */
3588static int
3589send_session_info_iter (void *cls,
3590 const struct GNUNET_PeerIdentity *peer,
3591 void *value)
3592{
3593 struct Plugin *plugin = cls;
3594 struct GNUNET_ATS_Session *session = value;
3595
3596 notify_session_monitor (plugin, session, GNUNET_TRANSPORT_SS_INIT);
3597 /* FIXME: cannot tell if this is up or not from current
3598 session state... */
3599 notify_session_monitor (plugin, session, GNUNET_TRANSPORT_SS_UP);
3600 return GNUNET_OK;
3601}
3602
3603
3604/**
3605 * Begin monitoring sessions of a plugin. There can only
3606 * be one active monitor per plugin (i.e. if there are
3607 * multiple monitors, the transport service needs to
3608 * multiplex the generated events over all of them).
3609 *
3610 * @param cls closure of the plugin
3611 * @param sic callback to invoke, NULL to disable monitor;
3612 * plugin will being by iterating over all active
3613 * sessions immediately and then enter monitor mode
3614 * @param sic_cls closure for @a sic
3615 */
3616static void
3617tcp_plugin_setup_monitor (void *cls,
3618 GNUNET_TRANSPORT_SessionInfoCallback sic,
3619 void *sic_cls)
3620{
3621 struct Plugin *plugin = cls;
3622
3623 plugin->sic = sic;
3624 plugin->sic_cls = sic_cls;
3625 if (NULL != sic)
3626 {
3627 GNUNET_CONTAINER_multipeermap_iterate (plugin->sessionmap,
3628 &send_session_info_iter,
3629 plugin);
3630 /* signal end of first iteration */
3631 sic (sic_cls, NULL, NULL);
3632 }
3633}
3634
3635
3636/**
3637 * Entry point for the plugin.
3638 *
3639 * @param cls closure, the `struct GNUNET_TRANSPORT_PluginEnvironment *`
3640 * @return the `struct GNUNET_TRANSPORT_PluginFunctions *` or NULL on error
3641 */
3642void *
3643libgnunet_plugin_transport_tcp_init (void *cls)
3644{
3645 static const struct GNUNET_SERVER_MessageHandler my_handlers[] =
3646 { { &handle_tcp_welcome,
3647 NULL,
3648 GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_WELCOME,
3649 sizeof(struct WelcomeMessage) },
3650 { &handle_tcp_nat_probe,
3651 NULL,
3652 GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_NAT_PROBE,
3653 sizeof(struct TCP_NAT_ProbeMessage) },
3654 { &handle_tcp_data, NULL, GNUNET_MESSAGE_TYPE_ALL, 0 },
3655 { NULL, NULL, 0, 0 } };
3656 struct GNUNET_TRANSPORT_PluginEnvironment *env = cls;
3657 struct GNUNET_TRANSPORT_PluginFunctions *api;
3658 struct Plugin *plugin;
3659 struct LEGACY_SERVICE_Context *service;
3660 unsigned long long aport;
3661 unsigned long long bport;
3662 unsigned long long max_connections;
3663 unsigned int i;
3664 struct GNUNET_TIME_Relative idle_timeout;
3665
3666#ifdef TCP_STEALTH
3667 struct GNUNET_NETWORK_Handle *const *lsocks;
3668#endif
3669 int ret;
3670 int ret_s;
3671 struct sockaddr **addrs;
3672 socklen_t *addrlens;
3673
3674 if (NULL == env->receive)
3675 {
3676 /* run in 'stub' mode (i.e. as part of gnunet-peerinfo), don't fully
3677 initialize the plugin or the API */
3678 api = GNUNET_new (struct GNUNET_TRANSPORT_PluginFunctions);
3679 api->cls = NULL;
3680 api->address_pretty_printer = &tcp_plugin_address_pretty_printer;
3681 api->address_to_string = &tcp_plugin_address_to_string;
3682 api->string_to_address = &tcp_plugin_string_to_address;
3683 return api;
3684 }
3685
3686 GNUNET_assert (NULL != env->cfg);
3687 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (env->cfg,
3688 "transport-tcp",
3689 "MAX_CONNECTIONS",
3690 &max_connections))
3691 max_connections = 128;
3692
3693 aport = 0;
3694 if ((GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (env->cfg,
3695 "transport-tcp",
3696 "PORT",
3697 &bport)) ||
3698 (bport > 65535) ||
3699 ((GNUNET_OK == GNUNET_CONFIGURATION_get_value_number (env->cfg,
3700 "transport-tcp",
3701 "ADVERTISED-PORT",
3702 &aport)) &&
3703 (aport > 65535)))
3704 {
3705 LOG (GNUNET_ERROR_TYPE_ERROR,
3706 _ ("Require valid port number for service `%s' in configuration!\n"),
3707 "transport-tcp");
3708 return NULL;
3709 }
3710 if (0 == aport)
3711 aport = bport;
3712 if (0 == bport)
3713 aport = 0;
3714 if (0 != bport)
3715 {
3716 service = LEGACY_SERVICE_start ("transport-tcp",
3717 env->cfg,
3718 LEGACY_SERVICE_OPTION_NONE);
3719 if (NULL == service)
3720 {
3721 LOG (GNUNET_ERROR_TYPE_WARNING, _ ("Failed to start service.\n"));
3722 return NULL;
3723 }
3724 }
3725 else
3726 service = NULL;
3727
3728 api = NULL;
3729 plugin = GNUNET_new (struct Plugin);
3730 plugin->sessionmap =
3731 GNUNET_CONTAINER_multipeermap_create (max_connections, GNUNET_YES);
3732 plugin->max_connections = max_connections;
3733 plugin->open_port = bport;
3734 plugin->adv_port = aport;
3735 plugin->env = env;
3736 plugin->my_welcome.header.size = htons (sizeof(struct WelcomeMessage));
3737 plugin->my_welcome.header.type =
3738 htons (GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_WELCOME);
3739 plugin->my_welcome.clientIdentity = *plugin->env->my_identity;
3740
3741 if ((NULL != service) &&
3742 (GNUNET_YES == GNUNET_CONFIGURATION_get_value_yesno (env->cfg,
3743 "transport-tcp",
3744 "TCP_STEALTH")))
3745 {
3746#ifdef TCP_STEALTH
3747 plugin->myoptions |= TCP_OPTIONS_TCP_STEALTH;
3748 lsocks = LEGACY_SERVICE_get_listen_sockets (service);
3749 if (NULL != lsocks)
3750 {
3751 uint32_t len = sizeof(struct WelcomeMessage);
3752
3753 for (i = 0; NULL != lsocks[i]; i++)
3754 {
3755 if (
3756 (GNUNET_OK !=
3757 GNUNET_NETWORK_socket_setsockopt (lsocks[i],
3758 IPPROTO_TCP,
3759 TCP_STEALTH,
3760 env->my_identity,
3761 sizeof(
3762 struct GNUNET_PeerIdentity))) ||
3763 (GNUNET_OK !=
3764 GNUNET_NETWORK_socket_setsockopt (lsocks[i],
3765 IPPROTO_TCP,
3766 TCP_STEALTH_INTEGRITY_LEN,
3767 &len,
3768 sizeof(len))))
3769 {
3770 /* TCP STEALTH not supported by kernel */
3771 GNUNET_assert (0 == i);
3772 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3773 _ ("TCP_STEALTH not supported on this platform.\n"));
3774 goto die;
3775 }
3776 }
3777 }
3778#else
3779 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3780 _ ("TCP_STEALTH not supported on this platform.\n"));
3781 goto die;
3782#endif
3783 }
3784
3785 if ((NULL != service) &&
3786 (GNUNET_SYSERR !=
3787 (ret_s =
3788 get_server_addresses ("transport-tcp", env->cfg, &addrs, &addrlens))))
3789 {
3790 for (ret = ret_s - 1; ret >= 0; ret--)
3791 LOG (GNUNET_ERROR_TYPE_INFO,
3792 "Binding to address `%s'\n",
3793 GNUNET_a2s (addrs[ret], addrlens[ret]));
3794 plugin->nat = GNUNET_NAT_register (env->cfg,
3795 "transport-tcp",
3796 IPPROTO_TCP,
3797 (unsigned int) ret_s,
3798 (const struct sockaddr **) addrs,
3799 addrlens,
3800 &tcp_nat_port_map_callback,
3801 &try_connection_reversal,
3802 plugin);
3803 for (ret = ret_s - 1; ret >= 0; ret--)
3804 GNUNET_free (addrs[ret]);
3805 GNUNET_free (addrs);
3806 GNUNET_free (addrlens);
3807 }
3808 else
3809 {
3810 plugin->nat = GNUNET_NAT_register (plugin->env->cfg,
3811 "transport-tcp",
3812 IPPROTO_TCP,
3813 0,
3814 NULL,
3815 NULL,
3816 NULL,
3817 &try_connection_reversal,
3818 plugin);
3819 }
3820 api = GNUNET_new (struct GNUNET_TRANSPORT_PluginFunctions);
3821 api->cls = plugin;
3822 api->send = &tcp_plugin_send;
3823 api->get_session = &tcp_plugin_get_session;
3824 api->disconnect_session = &tcp_plugin_disconnect_session;
3825 api->query_keepalive_factor = &tcp_plugin_query_keepalive_factor;
3826 api->disconnect_peer = &tcp_plugin_disconnect;
3827 api->address_pretty_printer = &tcp_plugin_address_pretty_printer;
3828 api->check_address = &tcp_plugin_check_address;
3829 api->address_to_string = &tcp_plugin_address_to_string;
3830 api->string_to_address = &tcp_plugin_string_to_address;
3831 api->get_network = &tcp_plugin_get_network;
3832 api->get_network_for_address = &tcp_plugin_get_network_for_address;
3833 api->update_session_timeout = &tcp_plugin_update_session_timeout;
3834 api->update_inbound_delay = &tcp_plugin_update_inbound_delay;
3835 api->setup_monitor = &tcp_plugin_setup_monitor;
3836 plugin->service = service;
3837 if (NULL != service)
3838 {
3839 plugin->server = LEGACY_SERVICE_get_server (service);
3840 }
3841 else
3842 {
3843 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_time (env->cfg,
3844 "transport-tcp",
3845 "TIMEOUT",
3846 &idle_timeout))
3847 {
3848 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
3849 "transport-tcp",
3850 "TIMEOUT");
3851 goto die;
3852 }
3853 plugin->server = GNUNET_SERVER_create_with_sockets (NULL,
3854 plugin,
3855 NULL,
3856 idle_timeout,
3857 GNUNET_YES);
3858 }
3859 plugin->handlers = GNUNET_malloc (sizeof(my_handlers));
3860 GNUNET_memcpy (plugin->handlers, my_handlers, sizeof(my_handlers));
3861 for (i = 0;
3862 i < sizeof(my_handlers) / sizeof(struct GNUNET_SERVER_MessageHandler);
3863 i++)
3864 plugin->handlers[i].callback_cls = plugin;
3865
3866 GNUNET_SERVER_add_handlers (plugin->server, plugin->handlers);
3867 GNUNET_SERVER_connect_notify (plugin->server, &connect_notify, plugin);
3868 GNUNET_SERVER_disconnect_notify (plugin->server, &disconnect_notify, plugin);
3869 plugin->nat_wait_conns =
3870 GNUNET_CONTAINER_multipeermap_create (16, GNUNET_YES);
3871 if (0 != bport)
3872 LOG (GNUNET_ERROR_TYPE_INFO,
3873 _ ("TCP transport listening on port %llu\n"),
3874 bport);
3875 else
3876 LOG (GNUNET_ERROR_TYPE_INFO,
3877 _ ("TCP transport not listening on any port (client only)\n"));
3878 if ((aport != bport) && (0 != bport))
3879 LOG (GNUNET_ERROR_TYPE_INFO,
3880 _ ("TCP transport advertises itself as being on port %llu\n"),
3881 aport);
3882 /* Initially set connections to 0 */
3883 GNUNET_STATISTICS_set (plugin->env->stats,
3884 gettext_noop ("# TCP sessions active"),
3885 0,
3886 GNUNET_NO);
3887 return api;
3888
3889die:
3890 if (NULL != plugin->nat)
3891 GNUNET_NAT_unregister (plugin->nat);
3892 GNUNET_CONTAINER_multipeermap_destroy (plugin->sessionmap);
3893 if (NULL != service)
3894 LEGACY_SERVICE_stop (service);
3895 GNUNET_free (plugin);
3896 GNUNET_free (api);
3897 return NULL;
3898}
3899
3900
3901/**
3902 * Exit point from the plugin.
3903 *
3904 * @param cls the `struct GNUNET_TRANSPORT_PluginFunctions`
3905 * @return NULL
3906 */
3907void *
3908libgnunet_plugin_transport_tcp_done (void *cls)
3909{
3910 struct GNUNET_TRANSPORT_PluginFunctions *api = cls;
3911 struct Plugin *plugin = api->cls;
3912 struct TCPProbeContext *tcp_probe;
3913 struct PrettyPrinterContext *cur;
3914 struct PrettyPrinterContext *next;
3915
3916 if (NULL == plugin)
3917 {
3918 GNUNET_free (api);
3919 return NULL;
3920 }
3921 LOG (GNUNET_ERROR_TYPE_DEBUG, "Shutting down TCP plugin\n");
3922
3923 /* Removing leftover sessions */
3924 GNUNET_CONTAINER_multipeermap_iterate (plugin->sessionmap,
3925 &session_disconnect_it,
3926 plugin);
3927 /* Removing leftover NAT sessions */
3928 GNUNET_CONTAINER_multipeermap_iterate (plugin->nat_wait_conns,
3929 &session_disconnect_it,
3930 plugin);
3931
3932 for (cur = plugin->ppc_dll_head; NULL != cur; cur = next)
3933 {
3934 next = cur->next;
3935 GNUNET_CONTAINER_DLL_remove (plugin->ppc_dll_head,
3936 plugin->ppc_dll_tail,
3937 cur);
3938 GNUNET_RESOLVER_request_cancel (cur->resolver_handle);
3939 cur->asc (cur->asc_cls, NULL, GNUNET_OK);
3940 GNUNET_free (cur);
3941 }
3942
3943 if (NULL != plugin->service)
3944 LEGACY_SERVICE_stop (plugin->service);
3945 else
3946 GNUNET_SERVER_destroy (plugin->server);
3947 GNUNET_free (plugin->handlers);
3948 if (NULL != plugin->nat)
3949 GNUNET_NAT_unregister (plugin->nat);
3950 while (NULL != (tcp_probe = plugin->probe_head))
3951 {
3952 GNUNET_CONTAINER_DLL_remove (plugin->probe_head,
3953 plugin->probe_tail,
3954 tcp_probe);
3955 GNUNET_CONNECTION_destroy (tcp_probe->sock);
3956 GNUNET_free (tcp_probe);
3957 }
3958 GNUNET_CONTAINER_multipeermap_destroy (plugin->nat_wait_conns);
3959 GNUNET_CONTAINER_multipeermap_destroy (plugin->sessionmap);
3960 GNUNET_break (0 == plugin->cur_connections);
3961 GNUNET_free (plugin);
3962 GNUNET_free (api);
3963 return NULL;
3964}
3965
3966
3967/* end of plugin_transport_tcp.c */