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