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