diff options
author | Nathan S. Evans <evans@in.tum.de> | 2010-01-19 13:23:04 +0000 |
---|---|---|
committer | Nathan S. Evans <evans@in.tum.de> | 2010-01-19 13:23:04 +0000 |
commit | 71c69f178dd8ad00e917c8724c4f2417f8d9648f (patch) | |
tree | f2d68f75774acfc311f26b2a657dedc3be3e3ece /src | |
parent | 691f0bfb0a1cbd2a862c4707c40b35aba13c92f1 (diff) | |
download | gnunet-71c69f178dd8ad00e917c8724c4f2417f8d9648f.tar.gz gnunet-71c69f178dd8ad00e917c8724c4f2417f8d9648f.zip |
moderate udp support, not really tested (:
Diffstat (limited to 'src')
-rw-r--r-- | src/include/gnunet_network_lib.h | 26 | ||||
-rw-r--r-- | src/include/gnunet_protocols.h | 9 | ||||
-rw-r--r-- | src/include/gnunet_scheduler_lib.h | 4 | ||||
-rw-r--r-- | src/transport/Makefile.am | 17 | ||||
-rw-r--r-- | src/transport/plugin_transport_tcp.c | 6 | ||||
-rw-r--r-- | src/transport/plugin_transport_udp.c | 1087 | ||||
-rw-r--r-- | src/transport/test_plugin_transport_data_udp.conf | 24 | ||||
-rw-r--r-- | src/transport/test_plugin_transport_udp.c | 358 | ||||
-rw-r--r-- | src/util/network.c | 62 | ||||
-rw-r--r-- | src/util/scheduler.c | 10 |
10 files changed, 1179 insertions, 424 deletions
diff --git a/src/include/gnunet_network_lib.h b/src/include/gnunet_network_lib.h index 513787e08..71c8d4346 100644 --- a/src/include/gnunet_network_lib.h +++ b/src/include/gnunet_network_lib.h | |||
@@ -124,6 +124,27 @@ int GNUNET_NETWORK_socket_getsockopt(const struct GNUNET_NETWORK_Handle *desc, i | |||
124 | int GNUNET_NETWORK_socket_listen (const struct GNUNET_NETWORK_Handle *desc, int backlog); | 124 | int GNUNET_NETWORK_socket_listen (const struct GNUNET_NETWORK_Handle *desc, int backlog); |
125 | 125 | ||
126 | /** | 126 | /** |
127 | * How much data is available to be read on this descriptor? | ||
128 | * @param desc socket | ||
129 | */ | ||
130 | unsigned int | ||
131 | GNUNET_NETWORK_socket_recvfrom_amount (const struct GNUNET_NETWORK_Handle * desc); | ||
132 | |||
133 | /** | ||
134 | * Read data from a connected socket (always non-blocking). | ||
135 | * @param desc socket | ||
136 | * @param buffer buffer | ||
137 | * @param length length of buffer | ||
138 | * @param src_addr either the source to recv from, or all zeroes | ||
139 | * to be filled in by recvfrom | ||
140 | * @param addrlen length of the addr | ||
141 | */ | ||
142 | ssize_t | ||
143 | GNUNET_NETWORK_socket_recvfrom (const struct GNUNET_NETWORK_Handle * desc, | ||
144 | void *buffer, size_t length, | ||
145 | struct sockaddr *src_addr, socklen_t *addrlen); | ||
146 | |||
147 | /** | ||
127 | * Read data from a connected socket (always non-blocking). | 148 | * Read data from a connected socket (always non-blocking). |
128 | * | 149 | * |
129 | * @param desc socket | 150 | * @param desc socket |
@@ -248,6 +269,11 @@ void GNUNET_NETWORK_fdset_add (struct GNUNET_NETWORK_FDSet *dst, | |||
248 | void GNUNET_NETWORK_fdset_copy(struct GNUNET_NETWORK_FDSet *to, | 269 | void GNUNET_NETWORK_fdset_copy(struct GNUNET_NETWORK_FDSet *to, |
249 | const struct GNUNET_NETWORK_FDSet *from); | 270 | const struct GNUNET_NETWORK_FDSet *from); |
250 | 271 | ||
272 | /* | ||
273 | * Return file descriptor for this network handle | ||
274 | */ | ||
275 | int | ||
276 | GNUNET_NETWORK_get_fd (struct GNUNET_NETWORK_Handle *desc); | ||
251 | /** | 277 | /** |
252 | * Copy a native fd set | 278 | * Copy a native fd set |
253 | * @param to destination | 279 | * @param to destination |
diff --git a/src/include/gnunet_protocols.h b/src/include/gnunet_protocols.h index 51442958c..cdf5d0df3 100644 --- a/src/include/gnunet_protocols.h +++ b/src/include/gnunet_protocols.h | |||
@@ -242,6 +242,15 @@ extern "C" | |||
242 | */ | 242 | */ |
243 | #define GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_DATA 43 | 243 | #define GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_DATA 43 |
244 | 244 | ||
245 | /* | ||
246 | * UDP Ping message | ||
247 | */ | ||
248 | #define GNUNET_MESSAGE_TYPE_TRANSPORT_UDP_PING 51 | ||
249 | |||
250 | /* | ||
251 | * UDP Pong message | ||
252 | */ | ||
253 | #define GNUNET_MESSAGE_TYPE_TRANSPORT_UDP_PONG 52 | ||
245 | 254 | ||
246 | /** | 255 | /** |
247 | * Initial setup message from core client to core. | 256 | * Initial setup message from core client to core. |
diff --git a/src/include/gnunet_scheduler_lib.h b/src/include/gnunet_scheduler_lib.h index 9ba4399ad..3205729a3 100644 --- a/src/include/gnunet_scheduler_lib.h +++ b/src/include/gnunet_scheduler_lib.h | |||
@@ -290,7 +290,7 @@ GNUNET_SCHEDULER_add_continuation (struct GNUNET_SCHEDULER_Handle *sched, | |||
290 | * @param sched scheduler to use | 290 | * @param sched scheduler to use |
291 | * @param prerequisite_task run this task after the task with the given | 291 | * @param prerequisite_task run this task after the task with the given |
292 | * task identifier completes (and any of our other | 292 | * task identifier completes (and any of our other |
293 | * conditions, such as delay, read or write-readyness | 293 | * conditions, such as delay, read or write-readiness |
294 | * are satisfied). Use GNUNET_SCHEDULER_NO_TASK to not have any dependency | 294 | * are satisfied). Use GNUNET_SCHEDULER_NO_TASK to not have any dependency |
295 | * on completion of other tasks (this will cause the task to run as | 295 | * on completion of other tasks (this will cause the task to run as |
296 | * soon as possible). | 296 | * soon as possible). |
@@ -480,7 +480,7 @@ GNUNET_SCHEDULER_add_write_file (struct GNUNET_SCHEDULER_Handle *sched, | |||
480 | * @param prio how important is this task? | 480 | * @param prio how important is this task? |
481 | * @param prerequisite_task run this task after the task with the given | 481 | * @param prerequisite_task run this task after the task with the given |
482 | * task identifier completes (and any of our other | 482 | * task identifier completes (and any of our other |
483 | * conditions, such as delay, read or write-readyness | 483 | * conditions, such as delay, read or write-readiness |
484 | * are satisfied). Use GNUNET_SCHEDULER_NO_TASK to not have any dependency | 484 | * are satisfied). Use GNUNET_SCHEDULER_NO_TASK to not have any dependency |
485 | * on completion of other tasks. | 485 | * on completion of other tasks. |
486 | * @param delay how long should we wait? Use GNUNET_TIME_UNIT_FOREVER_REL for "forever", | 486 | * @param delay how long should we wait? Use GNUNET_TIME_UNIT_FOREVER_REL for "forever", |
diff --git a/src/transport/Makefile.am b/src/transport/Makefile.am index 02c346ef0..7d1f89a6e 100644 --- a/src/transport/Makefile.am +++ b/src/transport/Makefile.am | |||
@@ -48,6 +48,7 @@ gnunet_service_transport_LDADD = \ | |||
48 | 48 | ||
49 | plugin_LTLIBRARIES = \ | 49 | plugin_LTLIBRARIES = \ |
50 | libgnunet_plugin_transport_tcp.la \ | 50 | libgnunet_plugin_transport_tcp.la \ |
51 | libgnunet_plugin_transport_udp.la \ | ||
51 | libgnunet_plugin_transport_template.la | 52 | libgnunet_plugin_transport_template.la |
52 | # TODO: add udp, http, nat, etc. | 53 | # TODO: add udp, http, nat, etc. |
53 | 54 | ||
@@ -67,10 +68,19 @@ libgnunet_plugin_transport_template_la_LIBADD = \ | |||
67 | libgnunet_plugin_transport_template_la_LDFLAGS = \ | 68 | libgnunet_plugin_transport_template_la_LDFLAGS = \ |
68 | $(GN_PLUGIN_LDFLAGS) | 69 | $(GN_PLUGIN_LDFLAGS) |
69 | 70 | ||
71 | libgnunet_plugin_transport_udp_la_SOURCES = \ | ||
72 | plugin_transport_udp.c | ||
73 | libgnunet_plugin_transport_udp_la_LIBADD = \ | ||
74 | $(top_builddir)/src/hello/libgnunethello.la \ | ||
75 | $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \ | ||
76 | $(top_builddir)/src/util/libgnunetutil.la | ||
77 | libgnunet_plugin_transport_udp_la_LDFLAGS = \ | ||
78 | $(GN_PLUGIN_LDFLAGS) | ||
70 | 79 | ||
71 | check_PROGRAMS = \ | 80 | check_PROGRAMS = \ |
72 | test_transport_api \ | 81 | test_transport_api \ |
73 | test_plugin_transport | 82 | test_plugin_transport \ |
83 | test_plugin_transport_udp | ||
74 | # TODO: add tests for tcp, udp, http, nat, etc. | 84 | # TODO: add tests for tcp, udp, http, nat, etc. |
75 | 85 | ||
76 | TESTS = $(check_PROGRAMS) | 86 | TESTS = $(check_PROGRAMS) |
@@ -88,6 +98,11 @@ test_plugin_transport_LDADD = \ | |||
88 | $(top_builddir)/src/transport/libgnunettransport.la \ | 98 | $(top_builddir)/src/transport/libgnunettransport.la \ |
89 | $(top_builddir)/src/util/libgnunetutil.la | 99 | $(top_builddir)/src/util/libgnunetutil.la |
90 | 100 | ||
101 | test_plugin_transport_udp_SOURCES = \ | ||
102 | test_plugin_transport_udp.c | ||
103 | test_plugin_transport_udp_LDADD = \ | ||
104 | $(top_builddir)/src/transport/libgnunettransport.la \ | ||
105 | $(top_builddir)/src/util/libgnunetutil.la | ||
91 | 106 | ||
92 | EXTRA_DIST = \ | 107 | EXTRA_DIST = \ |
93 | test_transport_api_data.conf \ | 108 | test_transport_api_data.conf \ |
diff --git a/src/transport/plugin_transport_tcp.c b/src/transport/plugin_transport_tcp.c index 8c5f79fd3..2694b3f1e 100644 --- a/src/transport/plugin_transport_tcp.c +++ b/src/transport/plugin_transport_tcp.c | |||
@@ -218,7 +218,7 @@ struct PendingMessage | |||
218 | 218 | ||
219 | /** | 219 | /** |
220 | * Continuation function to call once the message | 220 | * Continuation function to call once the message |
221 | * has been sent. Can be NULL if there is no | 221 | * has been sent. Can be NULL if there is no |
222 | * continuation to call. | 222 | * continuation to call. |
223 | */ | 223 | */ |
224 | GNUNET_TRANSPORT_TransmitContinuation transmit_cont; | 224 | GNUNET_TRANSPORT_TransmitContinuation transmit_cont; |
@@ -514,7 +514,7 @@ static void process_pending_messages (struct Session *session); | |||
514 | 514 | ||
515 | /** | 515 | /** |
516 | * Function called to notify a client about the socket | 516 | * Function called to notify a client about the socket |
517 | * begin ready to queue more data. "buf" will be | 517 | * being ready to queue more data. "buf" will be |
518 | * NULL and "size" zero if the socket was closed for | 518 | * NULL and "size" zero if the socket was closed for |
519 | * writing in the meantime. | 519 | * writing in the meantime. |
520 | * | 520 | * |
@@ -1073,7 +1073,7 @@ session_try_connect (void *cls, | |||
1073 | static void | 1073 | static void |
1074 | tcp_plugin_send (void *cls, | 1074 | tcp_plugin_send (void *cls, |
1075 | const struct GNUNET_PeerIdentity *target, | 1075 | const struct GNUNET_PeerIdentity *target, |
1076 | unsigned int priority, | 1076 | unsigned int priority, |
1077 | const struct GNUNET_MessageHeader *msg, | 1077 | const struct GNUNET_MessageHeader *msg, |
1078 | struct GNUNET_TIME_Relative timeout, | 1078 | struct GNUNET_TIME_Relative timeout, |
1079 | GNUNET_TRANSPORT_TransmitContinuation cont, void *cont_cls) | 1079 | GNUNET_TRANSPORT_TransmitContinuation cont, void *cont_cls) |
diff --git a/src/transport/plugin_transport_udp.c b/src/transport/plugin_transport_udp.c index 624ca0933..d2839762e 100644 --- a/src/transport/plugin_transport_udp.c +++ b/src/transport/plugin_transport_udp.c | |||
@@ -22,15 +22,36 @@ | |||
22 | * @file transport/plugin_transport_udp.c | 22 | * @file transport/plugin_transport_udp.c |
23 | * @brief Implementation of the UDP transport service | 23 | * @brief Implementation of the UDP transport service |
24 | * @author Christian Grothoff | 24 | * @author Christian Grothoff |
25 | * @author Nathan Evans? | ||
25 | */ | 26 | */ |
26 | 27 | ||
28 | /* Notes for Nate: | ||
29 | * - Use simple network api to open ports and do select and whatnot. | ||
30 | * - For sending, just find session and send away! | ||
31 | * - All that is required is a simple linked list of known peers and | ||
32 | * how to send to them. Each will have a socket associated with it | ||
33 | * and that's pretty much it! May want to re-start over with 0.8 | ||
34 | * code now that we have a better idea. | ||
35 | * - How often to do select loop? Do with a recall thing since we | ||
36 | * don't want to use cron jobs? | ||
37 | * - First thing, set up server which listens on a UDP port. | ||
38 | * - Use plugin->env->receive to notify server of message receipt | ||
39 | * | ||
40 | */ | ||
27 | #include "platform.h" | 41 | #include "platform.h" |
28 | #include "gnunet_util.h" | 42 | #include "gnunet_hello_lib.h" |
43 | #include "gnunet_connection_lib.h" | ||
44 | #include "gnunet_os_lib.h" | ||
45 | #include "gnunet_peerinfo_service.h" | ||
29 | #include "gnunet_protocols.h" | 46 | #include "gnunet_protocols.h" |
30 | #include "gnunet_transport.h" | 47 | #include "gnunet_resolver_service.h" |
31 | #include "gnunet_stats_service.h" | 48 | #include "gnunet_server_lib.h" |
32 | #include "gnunet_upnp_service.h" | 49 | #include "gnunet_service_lib.h" |
33 | #include "ip.h" | 50 | #include "gnunet_signatures.h" |
51 | #include "gnunet_statistics_service.h" | ||
52 | #include "gnunet_transport_service.h" | ||
53 | #include "plugin_transport.h" | ||
54 | #include "transport.h" | ||
34 | 55 | ||
35 | #define DEBUG_UDP GNUNET_YES | 56 | #define DEBUG_UDP GNUNET_YES |
36 | 57 | ||
@@ -41,150 +62,200 @@ | |||
41 | #define MESSAGE_SIZE 1472 | 62 | #define MESSAGE_SIZE 1472 |
42 | 63 | ||
43 | /** | 64 | /** |
65 | * Handle for request of hostname resolution, non-NULL if pending. | ||
66 | */ | ||
67 | static struct GNUNET_RESOLVER_RequestHandle *hostname_dns; | ||
68 | |||
69 | /** | ||
44 | * Message-Packet header. | 70 | * Message-Packet header. |
45 | */ | 71 | */ |
46 | typedef struct | 72 | struct UDPMessage |
47 | { | 73 | { |
48 | /** | 74 | /** |
49 | * size of the message, in bytes, including this header. | 75 | * size of the message, in bytes, including this header. |
50 | */ | 76 | */ |
51 | GNUNET_MessageHeader header; | 77 | struct GNUNET_MessageHeader header; |
52 | 78 | ||
53 | /** | 79 | /** |
54 | * What is the identity of the sender (GNUNET_hash of public key) | 80 | * What is the identity of the sender (GNUNET_hash of public key) |
55 | */ | 81 | */ |
56 | GNUNET_PeerIdentity sender; | 82 | struct GNUNET_PeerIdentity sender; |
57 | 83 | ||
58 | } UDPMessage; | 84 | }; |
59 | 85 | ||
60 | #define MY_TRANSPORT_NAME "UDP" | 86 | /* Forward definition */ |
61 | #include "common.c" | 87 | struct Plugin; |
62 | 88 | ||
63 | /* *********** globals ************* */ | 89 | /** |
90 | * Session handle for UDP connections. | ||
91 | */ | ||
92 | struct Session | ||
93 | { | ||
64 | 94 | ||
65 | static int stat_bytesReceived; | 95 | /** |
96 | * Stored in a linked list. | ||
97 | */ | ||
98 | struct Session *next; | ||
66 | 99 | ||
67 | static int stat_bytesSent; | 100 | /** |
101 | * Pointer to the global plugin struct. | ||
102 | */ | ||
103 | struct Plugin *plugin; | ||
68 | 104 | ||
69 | static int stat_bytesDropped; | 105 | /** |
106 | * To whom are we talking to (set to our identity | ||
107 | */ | ||
108 | struct GNUNET_PeerIdentity target; | ||
70 | 109 | ||
71 | static int stat_udpConnected; | 110 | /** |
111 | * Address of the other peer if WE initiated the connection | ||
112 | * (and hence can be sure what it is), otherwise NULL. | ||
113 | */ | ||
114 | void *connect_addr; | ||
72 | 115 | ||
73 | /** | 116 | /** |
74 | * thread that listens for inbound messages | 117 | * Length of connect_addr, can be 0. |
75 | */ | 118 | */ |
76 | static struct GNUNET_SelectHandle *selector; | 119 | size_t connect_alen; |
77 | 120 | ||
78 | /** | 121 | /* |
79 | * the socket that we transmit all data with | 122 | * Random challenge number for validation |
80 | */ | 123 | */ |
81 | static struct GNUNET_SocketHandle *udp_sock; | 124 | int challenge; |
82 | 125 | ||
83 | static struct GNUNET_LoadMonitor *load_monitor; | 126 | /* |
127 | * Have we received validation (performed ping/pong) from this peer? | ||
128 | */ | ||
129 | unsigned int validated; | ||
84 | 130 | ||
131 | }; | ||
85 | 132 | ||
86 | /** | 133 | /** |
87 | * The socket of session has data waiting, process! | 134 | * Encapsulation of all of the state of the plugin. |
88 | * | ||
89 | * This function may only be called if the tcplock is | ||
90 | * already held by the caller. | ||
91 | */ | 135 | */ |
92 | static int | 136 | struct Plugin |
93 | select_message_handler (void *mh_cls, | ||
94 | struct GNUNET_SelectHandle *sh, | ||
95 | struct GNUNET_SocketHandle *sock, | ||
96 | void *sock_ctx, const GNUNET_MessageHeader * msg) | ||
97 | { | 137 | { |
98 | unsigned int len; | 138 | /** |
99 | GNUNET_TransportPacket *mp; | 139 | * Our environment. |
100 | const UDPMessage *um; | 140 | */ |
141 | struct GNUNET_TRANSPORT_PluginEnvironment *env; | ||
101 | 142 | ||
102 | len = ntohs (msg->size); | 143 | /** |
103 | if (len <= sizeof (UDPMessage)) | 144 | * List of open TCP sessions. |
104 | { | 145 | */ |
105 | GNUNET_GE_LOG (coreAPI->ectx, | 146 | struct Session *sessions; |
106 | GNUNET_GE_WARNING | GNUNET_GE_USER | GNUNET_GE_BULK, | ||
107 | _("Received malformed message via %s. Ignored.\n"), | ||
108 | "UDP"); | ||
109 | return GNUNET_SYSERR; | ||
110 | } | ||
111 | um = (const UDPMessage *) msg; | ||
112 | mp = GNUNET_malloc (sizeof (GNUNET_TransportPacket)); | ||
113 | mp->msg = GNUNET_malloc (len - sizeof (UDPMessage)); | ||
114 | memcpy (mp->msg, &um[1], len - sizeof (UDPMessage)); | ||
115 | mp->sender = um->sender; | ||
116 | mp->size = len - sizeof (UDPMessage); | ||
117 | mp->tsession = NULL; | ||
118 | coreAPI->receive (mp); | ||
119 | if (stats != NULL) | ||
120 | stats->change (stat_bytesReceived, len); | ||
121 | return GNUNET_OK; | ||
122 | } | ||
123 | 147 | ||
124 | static void * | 148 | /** |
125 | select_accept_handler (void *ah_cls, | 149 | * Handle for the statistics service. |
126 | struct GNUNET_SelectHandle *sh, | 150 | */ |
127 | struct GNUNET_SocketHandle *sock, | 151 | struct GNUNET_STATISTICS_Handle *statistics; |
128 | const void *addr, unsigned int addr_len) | ||
129 | { | ||
130 | static int nonnullpointer; | ||
131 | 152 | ||
132 | if (GNUNET_NO != is_rejected_tester (addr, addr_len)) | 153 | /** |
133 | return NULL; | 154 | * Handle to the network service. |
134 | return &nonnullpointer; | 155 | */ |
135 | } | 156 | struct GNUNET_SERVICE_Context *service; |
157 | |||
158 | /** | ||
159 | * ID of task used to update our addresses when one expires. | ||
160 | */ | ||
161 | GNUNET_SCHEDULER_TaskIdentifier address_update_task; | ||
162 | |||
163 | /** | ||
164 | * ID of select task | ||
165 | */ | ||
166 | GNUNET_SCHEDULER_TaskIdentifier select_task; | ||
167 | |||
168 | /** | ||
169 | * Port that we are actually listening on. | ||
170 | */ | ||
171 | uint16_t open_port; | ||
172 | |||
173 | /** | ||
174 | * Port that the user said we would have visible to the | ||
175 | * rest of the world. | ||
176 | */ | ||
177 | uint16_t adv_port; | ||
178 | |||
179 | /* | ||
180 | * FD Read set | ||
181 | */ | ||
182 | struct GNUNET_NETWORK_FDSet * rs; | ||
183 | |||
184 | }; | ||
136 | 185 | ||
137 | /** | 186 | /** |
138 | * Select has been forced to close a connection. | 187 | * Message used to ask a peer to validate receipt (to check an address |
139 | * Free the associated context. | 188 | * from a HELLO). Followed by the address used. Note that the |
189 | * recipients response does not affirm that he has this address, | ||
190 | * only that he got the challenge message. | ||
140 | */ | 191 | */ |
141 | static void | 192 | struct UDPPingMessage |
142 | select_close_handler (void *ch_cls, | ||
143 | struct GNUNET_SelectHandle *sh, | ||
144 | struct GNUNET_SocketHandle *sock, void *sock_ctx) | ||
145 | { | 193 | { |
146 | /* do nothing */ | 194 | |
147 | } | 195 | /** |
196 | * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_PING | ||
197 | */ | ||
198 | struct GNUNET_MessageHeader header; | ||
199 | |||
200 | /** | ||
201 | * Random challenge number (in network byte order). | ||
202 | */ | ||
203 | uint32_t challenge GNUNET_PACKED; | ||
204 | |||
205 | |||
206 | |||
207 | }; | ||
208 | |||
148 | 209 | ||
149 | /** | 210 | /** |
150 | * Establish a connection to a remote node. | 211 | * Message used to validate a HELLO. The challenge is included in the |
212 | * confirmation to make matching of replies to requests possible. The | ||
213 | * signature signs the original challenge number, our public key, the | ||
214 | * sender's address (so that the sender can check that the address we | ||
215 | * saw is plausible for him and possibly detect a MiM attack) and a | ||
216 | * timestamp (to limit replay).<p> | ||
151 | * | 217 | * |
152 | * @param hello the hello-Message for the target node | 218 | * This message is followed by the address of the |
153 | * @param tsessionPtr the session handle that is to be set | 219 | * client that we are observing (which is part of what |
154 | * @param may_reuse are we allowed to re-use an existing connection (ignored for UDP) | 220 | * is being signed). |
155 | * @return GNUNET_OK on success, GNUNET_SYSERR if the operation failed | ||
156 | */ | 221 | */ |
157 | static int | 222 | struct UDPPongMessage |
158 | udp_connect (const GNUNET_MessageHello * hello, | ||
159 | GNUNET_TSession ** tsessionPtr, int may_reuse) | ||
160 | { | 223 | { |
161 | GNUNET_TSession *tsession; | 224 | /** |
162 | 225 | * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_PONG | |
163 | tsession = GNUNET_malloc (sizeof (GNUNET_TSession)); | 226 | */ |
164 | memset (tsession, 0, sizeof (GNUNET_TSession)); | 227 | struct GNUNET_MessageHeader header; |
165 | tsession->internal = GNUNET_malloc (GNUNET_sizeof_hello (hello)); | 228 | |
166 | memcpy (tsession->internal, hello, GNUNET_sizeof_hello (hello)); | 229 | /** |
167 | tsession->ttype = myAPI.protocol_number; | 230 | * Random challenge number (in network byte order). |
168 | tsession->peer = hello->senderIdentity; | 231 | */ |
169 | *tsessionPtr = tsession; | 232 | uint32_t challenge GNUNET_PACKED; |
170 | if (stats != NULL) | 233 | |
171 | stats->change (stat_udpConnected, 1); | 234 | /* Length of addr, appended to end of message */ |
172 | return GNUNET_OK; | 235 | unsigned int addrlen; |
173 | } | 236 | }; |
237 | |||
238 | /* *********** globals ************* */ | ||
239 | |||
240 | /** | ||
241 | * the socket that we transmit all data with | ||
242 | */ | ||
243 | static struct GNUNET_NETWORK_Handle *udp_sock; | ||
244 | |||
174 | 245 | ||
175 | /** | 246 | /** |
176 | * A (core) Session is to be associated with a transport session. The | 247 | * A (core) Session is to be associated with a transport session. The |
177 | * transport service may want to know in order to call back on the | 248 | * transport service may want to know in order to call back on the |
178 | * core if the connection is being closed. | 249 | * core if the connection is being closed. |
179 | * | 250 | * |
180 | * @param tsession the session handle passed along | 251 | * @param session the session handle passed along |
181 | * from the call to receive that was made by the transport | 252 | * from the call to receive that was made by the transport |
182 | * layer | 253 | * layer |
183 | * @return GNUNET_OK if the session could be associated, | 254 | * @return GNUNET_OK if the session could be associated, |
184 | * GNUNET_SYSERR if not. | 255 | * GNUNET_SYSERR if not. |
185 | */ | 256 | */ |
186 | int | 257 | int |
187 | udp_associate (GNUNET_TSession * tsession) | 258 | udp_associate (struct Session * session) |
188 | { | 259 | { |
189 | return GNUNET_SYSERR; /* UDP connections can never be associated */ | 260 | return GNUNET_SYSERR; /* UDP connections can never be associated */ |
190 | } | 261 | } |
@@ -195,18 +266,12 @@ udp_associate (GNUNET_TSession * tsession) | |||
195 | * @param tsession the session that is closed | 266 | * @param tsession the session that is closed |
196 | * @return GNUNET_OK on success, GNUNET_SYSERR if the operation failed | 267 | * @return GNUNET_OK on success, GNUNET_SYSERR if the operation failed |
197 | */ | 268 | */ |
198 | static int | 269 | void |
199 | udp_disconnect (GNUNET_TSession * tsession) | 270 | udp_disconnect (void *cls, |
271 | const struct GNUNET_PeerIdentity * | ||
272 | target) | ||
200 | { | 273 | { |
201 | if (tsession != NULL) | 274 | return; |
202 | { | ||
203 | if (tsession->internal != NULL) | ||
204 | GNUNET_free (tsession->internal); | ||
205 | GNUNET_free (tsession); | ||
206 | if (stats != NULL) | ||
207 | stats->change (stat_udpConnected, -1); | ||
208 | } | ||
209 | return GNUNET_OK; | ||
210 | } | 275 | } |
211 | 276 | ||
212 | /** | 277 | /** |
@@ -214,385 +279,581 @@ udp_disconnect (GNUNET_TSession * tsession) | |||
214 | * restarted later! | 279 | * restarted later! |
215 | */ | 280 | */ |
216 | static int | 281 | static int |
217 | udp_transport_server_stop () | 282 | udp_transport_server_stop (void *cls) |
218 | { | 283 | { |
219 | GNUNET_GE_ASSERT (coreAPI->ectx, udp_sock != NULL); | 284 | struct Plugin *plugin = cls; |
220 | if (selector != NULL) | 285 | GNUNET_assert (udp_sock != NULL); |
286 | if (plugin->select_task != GNUNET_SCHEDULER_NO_TASK) | ||
221 | { | 287 | { |
222 | GNUNET_select_destroy (selector); | 288 | GNUNET_SCHEDULER_cancel (plugin->env->sched, plugin->select_task); |
223 | selector = NULL; | 289 | plugin->select_task = GNUNET_SCHEDULER_NO_TASK; |
224 | } | 290 | } |
225 | GNUNET_socket_destroy (udp_sock); | 291 | |
292 | GNUNET_NETWORK_socket_close (udp_sock); | ||
226 | udp_sock = NULL; | 293 | udp_sock = NULL; |
227 | return GNUNET_OK; | 294 | return GNUNET_OK; |
228 | } | 295 | } |
229 | 296 | ||
297 | static struct Session * | ||
298 | find_session(void *cls, struct Session * session_list, const struct GNUNET_PeerIdentity *peer) | ||
299 | { | ||
300 | struct Plugin *plugin = cls; | ||
301 | struct Session *pos; | ||
302 | pos = session_list; | ||
303 | |||
304 | while (pos != NULL) | ||
305 | { | ||
306 | if (memcmp(peer, &pos->target, sizeof(struct GNUNET_PeerIdentity)) == 0) | ||
307 | return pos; | ||
308 | pos = pos->next; | ||
309 | } | ||
310 | |||
311 | return NULL; | ||
312 | } | ||
313 | |||
230 | /** | 314 | /** |
231 | * Test if the transport would even try to send | 315 | * Function that can be used by the transport service to transmit |
232 | * a message of the given size and importance | 316 | * a message using the plugin. |
233 | * for the given session.<br> | ||
234 | * This function is used to check if the core should | ||
235 | * even bother to construct (and encrypt) this kind | ||
236 | * of message. | ||
237 | * | 317 | * |
238 | * @return GNUNET_YES if the transport would try (i.e. queue | 318 | * @param cls closure |
239 | * the message or call the OS to send), | 319 | * @param service_context value passed to the transport-service |
240 | * GNUNET_NO if the transport would just drop the message, | 320 | * to identify the neighbour |
241 | * GNUNET_SYSERR if the size/session is invalid | 321 | * @param target who should receive this message |
322 | * @param priority how important is the message | ||
323 | * @param msg the message to transmit | ||
324 | * @param timeout when should we time out (give up) if we can not transmit? | ||
325 | * @param cont continuation to call once the message has | ||
326 | * been transmitted (or if the transport is ready | ||
327 | * for the next transmission call; or if the | ||
328 | * peer disconnected...) | ||
329 | * @param cont_cls closure for cont | ||
242 | */ | 330 | */ |
243 | static int | 331 | static void |
244 | udp_test_would_try (GNUNET_TSession * tsession, unsigned int size, | 332 | udp_plugin_send (void *cls, |
245 | int important) | 333 | const struct GNUNET_PeerIdentity *target, |
334 | unsigned int priority, | ||
335 | const struct GNUNET_MessageHeader *msg, | ||
336 | struct GNUNET_TIME_Relative timeout, | ||
337 | GNUNET_TRANSPORT_TransmitContinuation cont, void *cont_cls) | ||
246 | { | 338 | { |
247 | const GNUNET_MessageHello *hello; | 339 | struct Plugin *plugin = cls; |
340 | struct Session *session; | ||
341 | struct UDPMessage *message; | ||
342 | int ssize; | ||
343 | size_t sent; | ||
248 | 344 | ||
249 | if (udp_sock == NULL) | 345 | session = find_session(plugin, plugin->sessions, target); |
250 | return GNUNET_SYSERR; | 346 | |
251 | if (size == 0) | 347 | if ((session == NULL) || (udp_sock == NULL)) |
252 | { | 348 | return; |
253 | GNUNET_GE_BREAK (coreAPI->ectx, 0); | 349 | |
254 | return GNUNET_SYSERR; | 350 | /* Build the message to be sent */ |
255 | } | 351 | message = GNUNET_malloc(sizeof(struct UDPMessage) + ntohs(msg->size)); |
256 | if (size > myAPI.mtu) | 352 | ssize = sizeof(struct UDPMessage) + ntohs(msg->size); |
353 | |||
354 | #if DEBUG_UDP | ||
355 | GNUNET_log_from(GNUNET_ERROR_TYPE_INFO, "udp", _ | ||
356 | ("In udp_send, ssize is %d\n"), ssize); | ||
357 | #endif | ||
358 | message->header.size = htons(ssize); | ||
359 | message->header.type = htons(0); | ||
360 | memcpy (&message->sender, plugin->env->my_identity, sizeof(struct GNUNET_PeerIdentity)); | ||
361 | memcpy (&message[1], msg, ntohs (msg->size)); | ||
362 | |||
363 | /* Actually send the message */ | ||
364 | sent = GNUNET_NETWORK_socket_sendto (udp_sock, message, ssize, session->connect_addr, | ||
365 | session->connect_alen); | ||
366 | |||
367 | if (cont != NULL) | ||
257 | { | 368 | { |
258 | GNUNET_GE_BREAK (coreAPI->ectx, 0); | 369 | if (sent == GNUNET_SYSERR) |
259 | return GNUNET_SYSERR; | 370 | cont(cont_cls, target, GNUNET_SYSERR); |
371 | else | ||
372 | cont(cont_cls, target, GNUNET_OK); | ||
260 | } | 373 | } |
261 | hello = (const GNUNET_MessageHello *) tsession->internal; | 374 | |
262 | if (hello == NULL) | 375 | return; |
263 | return GNUNET_SYSERR; | ||
264 | return GNUNET_YES; | ||
265 | } | 376 | } |
266 | 377 | ||
267 | /** | 378 | /** |
268 | * Create a UDP socket. If possible, use IPv6, otherwise | 379 | * We've received a PING from this peer via UDP. |
269 | * try IPv4. Update available_protocols accordingly. | 380 | * Send back our PONG. |
381 | * | ||
382 | * @param cls closure | ||
383 | * @param sender the Identity of the sender | ||
384 | * @param message the actual message | ||
270 | */ | 385 | */ |
271 | static struct GNUNET_NETWORK_Handle * | 386 | static void |
272 | udp_create_socket () | 387 | handle_udp_ping (void *cls, |
388 | struct GNUNET_PeerIdentity *sender, struct sockaddr_storage * addr, size_t addrlen, | ||
389 | const struct GNUNET_MessageHeader *message) | ||
273 | { | 390 | { |
274 | struct GNUNET_NETWORK_Handle *desc; | 391 | struct Plugin *plugin = cls; |
275 | 392 | struct Session *head = plugin->sessions; | |
276 | available_protocols = VERSION_AVAILABLE_NONE; | 393 | const struct UDPPingMessage *ping = (const struct UDPPingMessage *)message; |
277 | desc = NULL; | 394 | struct UDPPongMessage *pong; |
278 | if (GNUNET_YES != | 395 | struct Session *found; |
279 | GNUNET_GC_get_configuration_value_yesno (cfg, "GNUNETD", "DISABLE-IPV6", | 396 | |
280 | GNUNET_YES)) | 397 | #if DEBUG_UDP |
281 | { | 398 | GNUNET_log_from(GNUNET_ERROR_TYPE_INFO, "udp", _ |
282 | desc = GNUNET_net_socket (PF_INET6, SOCK_DGRAM, 17); | 399 | ("handling ping, challenge is %d\n"), ntohs(ping->challenge)); |
283 | } | 400 | #endif |
284 | if (NULL == desc) | 401 | found = find_session(plugin, head, sender); |
285 | { | 402 | if (found != NULL) |
286 | desc = GNUNET_net_socket (PF_INET, SOCK_DGRAM, 17); | ||
287 | if (NULL == desc) | ||
288 | { | ||
289 | GNUNET_GE_LOG_STRERROR (coreAPI->ectx, | ||
290 | GNUNET_GE_ERROR | GNUNET_GE_ADMIN | | ||
291 | GNUNET_GE_BULK, "socket"); | ||
292 | return GNUNET_SYSERR; | ||
293 | } | ||
294 | available_protocols = VERSION_AVAILABLE_IPV4; | ||
295 | } | ||
296 | else | ||
297 | { | 403 | { |
298 | available_protocols = VERSION_AVAILABLE_IPV6 | VERSION_AVAILABLE_IPV4; | 404 | pong = GNUNET_malloc(sizeof(struct UDPPongMessage) + addrlen); |
405 | pong->header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_UDP_PONG); | ||
406 | pong->header.size = htons(sizeof(struct UDPPongMessage) + addrlen); | ||
407 | pong->challenge = ping->challenge; | ||
408 | memcpy(&pong[1], addr, addrlen); | ||
409 | pong->addrlen = htons(addrlen); | ||
410 | |||
411 | udp_plugin_send(plugin, sender, GNUNET_SCHEDULER_PRIORITY_DEFAULT, &pong->header, GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30), NULL, NULL); | ||
299 | } | 412 | } |
300 | return desc; | 413 | |
414 | return; | ||
415 | |||
301 | } | 416 | } |
302 | 417 | ||
303 | /** | 418 | /** |
304 | * Send a message to the specified remote node. | 419 | * We've received a PONG from this peer via UDP. |
420 | * Great. Call validate func if we haven't already | ||
421 | * received a PONG. | ||
305 | * | 422 | * |
306 | * @param tsession the GNUNET_MessageHello identifying the remote node | 423 | * @param cls closure |
307 | * @param message what to send | 424 | * @param client identification of the client |
308 | * @param size the size of the message | 425 | * @param message the actual message |
309 | * @param important is this message "important" to override typical transmit limits? | ||
310 | * @return GNUNET_SYSERR on error, GNUNET_OK on success | ||
311 | */ | 426 | */ |
312 | static int | 427 | static void |
313 | udp_send (GNUNET_TSession * tsession, | 428 | handle_udp_pong (void *cls, |
314 | const void *message, const unsigned int size, int important) | 429 | struct GNUNET_PeerIdentity *sender, |
430 | const struct GNUNET_MessageHeader *message) | ||
315 | { | 431 | { |
316 | const GNUNET_MessageHello *hello; | 432 | struct Plugin *plugin = cls; |
317 | const HostAddress *haddr; | 433 | const struct UDPPongMessage *pong = (struct UDPPongMessage *)message; |
318 | UDPMessage *mp; | 434 | struct Session *found; |
319 | struct sockaddr_in serverAddrv4; | 435 | unsigned int addr_len; |
320 | struct sockaddr_in6 serverAddrv6; | 436 | struct sockaddr_storage addr; |
321 | struct sockaddr *serverAddr; | 437 | |
322 | socklen_t addrlen; | 438 | #if DEBUG_UDP |
323 | unsigned short available; | 439 | GNUNET_log_from(GNUNET_ERROR_TYPE_INFO, "udp", _ |
324 | int ok; | 440 | ("handling pong\n")); |
325 | int ssize; | 441 | #endif |
326 | size_t sent; | 442 | found = find_session(plugin, plugin->sessions, sender); |
327 | 443 | #if DEBUG_UDP | |
328 | GNUNET_GE_ASSERT (NULL, tsession != NULL); | 444 | GNUNET_log_from(GNUNET_ERROR_TYPE_INFO, "udp", _ |
329 | if (udp_sock == NULL) | 445 | ("found->challenge %d, pong->challenge %d\n"), found->challenge, ntohs(pong->challenge)); |
330 | return GNUNET_SYSERR; | 446 | #endif |
331 | if (size == 0) | 447 | if ((found != NULL) && (found->challenge == ntohs(pong->challenge))) |
332 | { | 448 | { |
333 | GNUNET_GE_BREAK (coreAPI->ectx, 0); | 449 | found->validated = GNUNET_YES; |
334 | return GNUNET_SYSERR; | 450 | addr_len = ntohs(pong->addrlen); |
451 | #if DEBUG_UDP | ||
452 | GNUNET_log_from(GNUNET_ERROR_TYPE_INFO, "udp", _ | ||
453 | ("found associated ping, addr is %u bytes\n"), addr_len); | ||
454 | #endif | ||
455 | memcpy(&addr, &pong[1], addr_len); | ||
456 | plugin->env->notify_validation(plugin->env->cls, "udp", sender, ntohs(pong->challenge), (char *)&addr); | ||
335 | } | 457 | } |
336 | if (size > myAPI.mtu) | 458 | else |
337 | { | 459 | { |
338 | GNUNET_GE_BREAK (coreAPI->ectx, 0); | ||
339 | return GNUNET_SYSERR; | ||
340 | } | ||
341 | hello = (const GNUNET_MessageHello *) tsession->internal; | ||
342 | if (hello == NULL) | ||
343 | return GNUNET_SYSERR; | ||
344 | 460 | ||
345 | haddr = (const HostAddress *) &hello[1]; | 461 | #if DEBUG_UDP |
346 | available = ntohs (haddr->availability) & available_protocols; | 462 | GNUNET_log_from(GNUNET_ERROR_TYPE_INFO, "udp", _ |
347 | if (available == VERSION_AVAILABLE_NONE) | 463 | ("Session not found!\n")); |
348 | return GNUNET_SYSERR; | ||
349 | if (available == (VERSION_AVAILABLE_IPV4 | VERSION_AVAILABLE_IPV6)) | ||
350 | { | ||
351 | if (GNUNET_random_u32 (GNUNET_RANDOM_QUALITY_WEAK, 2) == 0) | ||
352 | available = VERSION_AVAILABLE_IPV4; | ||
353 | else | ||
354 | available = VERSION_AVAILABLE_IPV6; | ||
355 | } | ||
356 | ssize = size + sizeof (UDPMessage); | ||
357 | mp = GNUNET_malloc (ssize); | ||
358 | mp->header.size = htons (ssize); | ||
359 | mp->header.type = 0; | ||
360 | mp->sender = *(coreAPI->my_identity); | ||
361 | memcpy (&mp[1], message, size); | ||
362 | ok = GNUNET_SYSERR; | ||
363 | |||
364 | if ((available & VERSION_AVAILABLE_IPV4) > 0) | ||
365 | { | ||
366 | memset (&serverAddrv4, 0, sizeof (serverAddrv4)); | ||
367 | #if HAVE_SOCKADDR_IN_SIN_LEN | ||
368 | serverAddrv4.sin_len = sizeof (serverAddrv4); | ||
369 | #endif | 464 | #endif |
370 | serverAddrv4.sin_family = AF_INET; | ||
371 | serverAddrv4.sin_port = haddr->port; | ||
372 | memcpy (&serverAddrv4.sin_addr, &haddr->ipv4, sizeof (struct in_addr)); | ||
373 | addrlen = sizeof (serverAddrv4); | ||
374 | serverAddr = (struct sockaddr *) &serverAddrv4; | ||
375 | } | 465 | } |
376 | else | 466 | return; |
467 | } | ||
468 | |||
469 | static void | ||
470 | udp_plugin_select (void *cls, | ||
471 | const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
472 | { | ||
473 | struct Plugin *plugin = cls; | ||
474 | struct GNUNET_TIME_Relative timeout = GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MILLISECONDS, 500); | ||
475 | char * buf; | ||
476 | struct UDPMessage *msg; | ||
477 | const struct GNUNET_MessageHeader *hdr; | ||
478 | struct GNUNET_PeerIdentity *sender; | ||
479 | unsigned int buflen; | ||
480 | socklen_t fromlen; | ||
481 | struct sockaddr_storage addr; | ||
482 | ssize_t ret; | ||
483 | |||
484 | do | ||
377 | { | 485 | { |
378 | memset (&serverAddrv6, 0, sizeof (serverAddrv6)); | 486 | buflen = GNUNET_NETWORK_socket_recvfrom_amount(udp_sock); |
379 | #if HAVE_SOCKADDR_IN_SIN_LEN | 487 | |
380 | serverAddrv6.sin6_len = sizeof (serverAddrv6); | 488 | #if DEBUG_UDP |
489 | GNUNET_log_from(GNUNET_ERROR_TYPE_INFO, "udp", _ | ||
490 | ("we expect to read %u bytes\n"), buflen); | ||
381 | #endif | 491 | #endif |
382 | serverAddrv6.sin6_family = AF_INET; | 492 | |
383 | serverAddrv6.sin6_port = haddr->port; | 493 | if (buflen == GNUNET_NO) |
384 | memcpy (&serverAddrv6.sin6_addr, &haddr->ipv6, | 494 | return; |
385 | sizeof (struct in6_addr)); | 495 | |
386 | addrlen = sizeof (serverAddrv6); | 496 | buf = GNUNET_malloc(buflen); |
387 | serverAddr = (struct sockaddr *) &serverAddrv6; | 497 | fromlen = sizeof(addr); |
388 | } | 498 | |
389 | #ifndef MINGW | 499 | #if DEBUG_UDP |
390 | if (GNUNET_YES == GNUNET_socket_send_to (udp_sock, | 500 | GNUNET_log_from(GNUNET_ERROR_TYPE_INFO, "udp", _ |
391 | GNUNET_NC_NONBLOCKING, | 501 | ("src_addr_len is %u\n"), fromlen); |
392 | mp, | ||
393 | ssize, &sent, | ||
394 | (const char *) serverAddr, | ||
395 | addrlen)) | ||
396 | #else | ||
397 | sent = | ||
398 | win_ols_sendto (udp_sock, mp, ssize, (const char *) serverAddr, addrlen); | ||
399 | if (sent != SOCKET_ERROR) | ||
400 | #endif | 502 | #endif |
401 | { | 503 | |
402 | ok = GNUNET_OK; | 504 | memset(&addr, 0, fromlen); |
403 | if (stats != NULL) | 505 | ret = GNUNET_NETWORK_socket_recvfrom(udp_sock, buf, buflen, (struct sockaddr *)&addr, &fromlen); |
404 | stats->change (stat_bytesSent, sent); | 506 | |
405 | } | 507 | #if DEBUG_UDP |
406 | else | 508 | GNUNET_log_from(GNUNET_ERROR_TYPE_INFO, "udp", _ |
407 | { | 509 | ("socket_recv returned %u, src_addr_len is %u\n"), ret, fromlen); |
408 | if (stats != NULL) | 510 | #endif |
409 | stats->change (stat_bytesDropped, ssize); | 511 | |
512 | if (ret <= 0) | ||
513 | { | ||
514 | GNUNET_free(buf); | ||
515 | return; | ||
516 | } | ||
517 | |||
518 | msg = (struct UDPMessage *)buf; | ||
519 | |||
520 | #if DEBUG_UDP | ||
521 | GNUNET_log_from(GNUNET_ERROR_TYPE_INFO, "udp", _ | ||
522 | ("header reports message size of %d\n"), ntohs(msg->header.size)); | ||
523 | |||
524 | GNUNET_log_from(GNUNET_ERROR_TYPE_INFO, "udp", _ | ||
525 | ("header reports message type of %d\n"), ntohs(msg->header.type)); | ||
526 | #endif | ||
527 | /*if (ntohs(hdr->size) < sizeof(struct UDPMessage)) | ||
528 | { | ||
529 | GNUNET_free(buf); | ||
530 | GNUNET_NETWORK_fdset_zero(plugin->rs); | ||
531 | GNUNET_NETWORK_fdset_set(plugin->rs, udp_sock); | ||
532 | break; | ||
533 | }*/ | ||
534 | hdr = (const struct GNUNET_MessageHeader *)&msg[1]; | ||
535 | sender = GNUNET_malloc(sizeof(struct GNUNET_PeerIdentity)); | ||
536 | memcpy(sender, &msg->sender, sizeof(struct GNUNET_PeerIdentity)); | ||
537 | |||
538 | #if DEBUG_UDP | ||
539 | GNUNET_log_from(GNUNET_ERROR_TYPE_INFO, "udp", _ | ||
540 | ("msg reports message size of %d\n"), ntohs(hdr->size)); | ||
541 | |||
542 | GNUNET_log_from(GNUNET_ERROR_TYPE_INFO, "udp", _ | ||
543 | ("msg reports message type of %d\n"), ntohs(hdr->type)); | ||
544 | #endif | ||
545 | |||
546 | if (ntohs(hdr->type) == GNUNET_MESSAGE_TYPE_TRANSPORT_UDP_PING) | ||
547 | { | ||
548 | handle_udp_ping(plugin, sender, &addr, fromlen, hdr); | ||
549 | } | ||
550 | |||
551 | if (ntohs(hdr->type) == GNUNET_MESSAGE_TYPE_TRANSPORT_UDP_PONG) | ||
552 | { | ||
553 | handle_udp_pong(plugin, sender, hdr); | ||
554 | } | ||
555 | |||
556 | GNUNET_free(buf); | ||
557 | |||
410 | } | 558 | } |
411 | GNUNET_free (mp); | 559 | while (GNUNET_NETWORK_socket_select (plugin->rs, |
412 | return ok; | 560 | NULL, |
561 | NULL, | ||
562 | timeout) > 0 && GNUNET_NETWORK_fdset_isset(plugin->rs, udp_sock)); | ||
563 | |||
564 | plugin->select_task = GNUNET_SCHEDULER_add_select(plugin->env->sched, GNUNET_SCHEDULER_PRIORITY_DEFAULT, GNUNET_SCHEDULER_NO_TASK, | ||
565 | GNUNET_TIME_UNIT_FOREVER_REL, plugin->rs, NULL, &udp_plugin_select, plugin); | ||
566 | |||
413 | } | 567 | } |
414 | 568 | ||
415 | /** | 569 | /** |
416 | * Start the server process to receive inbound traffic. | 570 | * Create a UDP socket. If possible, use IPv6, otherwise |
417 | * | 571 | * try IPv4. |
418 | * @return GNUNET_OK on success, GNUNET_SYSERR if the operation failed | ||
419 | */ | 572 | */ |
420 | static int | 573 | static struct GNUNET_NETWORK_Handle * |
421 | udp_transport_server_start () | 574 | udp_transport_server_start (void *cls) |
422 | { | 575 | { |
576 | struct Plugin *plugin = cls; | ||
577 | struct GNUNET_NETWORK_Handle *desc; | ||
423 | struct sockaddr_in serverAddrv4; | 578 | struct sockaddr_in serverAddrv4; |
424 | struct sockaddr_in6 serverAddrv6; | 579 | struct sockaddr_in6 serverAddrv6; |
425 | struct sockaddr *serverAddr; | 580 | struct sockaddr *serverAddr; |
426 | socklen_t addrlen; | 581 | socklen_t addrlen; |
427 | GNUNET_NETWORK_Handle *desc; | 582 | |
428 | const int on = 1; | 583 | desc = NULL; |
429 | unsigned short port; | 584 | if (GNUNET_YES != |
430 | 585 | GNUNET_CONFIGURATION_get_value_yesno (plugin->env->cfg, "GNUNETD", "DISABLE-IPV6")) | |
431 | GNUNET_GE_ASSERT (coreAPI->ectx, selector == NULL); | ||
432 | /* initialize UDP network */ | ||
433 | port = get_port (); | ||
434 | if (port != 0) | ||
435 | { | 586 | { |
436 | desc = udp_create_socket (); | 587 | desc = GNUNET_NETWORK_socket_create (PF_INET6, SOCK_DGRAM, 17); |
588 | if (desc != NULL) | ||
589 | { | ||
590 | memset (&serverAddrv6, 0, sizeof (serverAddrv6)); | ||
591 | #if HAVE_SOCKADDR_IN_SIN_LEN | ||
592 | serverAddrv6.sin6_len = sizeof (serverAddrv6); | ||
593 | #endif | ||
594 | serverAddrv6.sin6_family = AF_INET6; | ||
595 | serverAddrv6.sin6_addr = in6addr_any; | ||
596 | serverAddrv6.sin6_port = htons (plugin->open_port); | ||
597 | addrlen = sizeof (serverAddrv6); | ||
598 | serverAddr = (struct sockaddr *) &serverAddrv6; | ||
599 | } | ||
600 | } | ||
601 | if (NULL == desc) | ||
602 | { | ||
603 | desc = GNUNET_NETWORK_socket_create (PF_INET, SOCK_DGRAM, 17); | ||
437 | if (NULL == desc) | 604 | if (NULL == desc) |
438 | return GNUNET_SYSERR; | ||
439 | if (GNUNET_net_setsockopt (desc, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on)) < 0) | ||
440 | { | 605 | { |
441 | GNUNET_GE_DIE_STRERROR (coreAPI->ectx, | 606 | GNUNET_log_from(GNUNET_ERROR_TYPE_DEBUG, |
442 | GNUNET_GE_FATAL | GNUNET_GE_ADMIN | | 607 | "udp", |
443 | GNUNET_GE_IMMEDIATE, "setsockopt"); | 608 | "socket"); |
444 | return GNUNET_SYSERR; | 609 | return NULL; |
445 | } | 610 | } |
446 | if (available_protocols == VERSION_AVAILABLE_IPV4) | 611 | else |
447 | { | 612 | { |
448 | memset (&serverAddrv4, 0, sizeof (serverAddrv4)); | 613 | memset (&serverAddrv4, 0, sizeof (serverAddrv4)); |
449 | #if HAVE_SOCKADDR_IN_SIN_LEN | 614 | #if HAVE_SOCKADDR_IN_SIN_LEN |
450 | serverAddrv4.sin_len = sizeof (serverAddrv4); | 615 | serverAddrv4.sin_len = sizeof (serverAddrv4); |
451 | #endif | 616 | #endif |
452 | serverAddrv4.sin_family = AF_INET; | 617 | serverAddrv4.sin_family = AF_INET; |
453 | serverAddrv4.sin_addr.s_addr = INADDR_ANY; | 618 | serverAddrv4.sin_addr.s_addr = INADDR_ANY; |
454 | serverAddrv4.sin_port = htons (port); | 619 | serverAddrv4.sin_port = htons (plugin->open_port); |
455 | addrlen = sizeof (serverAddrv4); | 620 | addrlen = sizeof (serverAddrv4); |
456 | serverAddr = (struct sockaddr *) &serverAddrv4; | 621 | serverAddr = (struct sockaddr *) &serverAddrv4; |
457 | } | 622 | } |
458 | else | ||
459 | { | ||
460 | memset (&serverAddrv6, 0, sizeof (serverAddrv6)); | ||
461 | #if HAVE_SOCKADDR_IN_SIN_LEN | ||
462 | serverAddrv6.sin6_len = sizeof (serverAddrv6); | ||
463 | #endif | ||
464 | serverAddrv6.sin6_family = AF_INET6; | ||
465 | serverAddrv6.sin6_addr = in6addr_any; | ||
466 | serverAddrv6.sin6_port = htons (port); | ||
467 | addrlen = sizeof (serverAddrv6); | ||
468 | serverAddr = (struct sockaddr *) &serverAddrv6; | ||
469 | } | ||
470 | if (GNUNET_net_bind (desc, serverAddr, addrlen) < 0) | ||
471 | { | ||
472 | GNUNET_GE_LOG_STRERROR (coreAPI->ectx, | ||
473 | GNUNET_GE_FATAL | GNUNET_GE_ADMIN | | ||
474 | GNUNET_GE_IMMEDIATE, "bind"); | ||
475 | GNUNET_GE_LOG (coreAPI->ectx, | ||
476 | GNUNET_GE_FATAL | GNUNET_GE_ADMIN | | ||
477 | GNUNET_GE_IMMEDIATE, | ||
478 | _("Failed to bind to %s port %d.\n"), | ||
479 | MY_TRANSPORT_NAME, port); | ||
480 | if (0 != GNUNET_net_close (&desc)) | ||
481 | GNUNET_GE_LOG_STRERROR (coreAPI->ectx, | ||
482 | GNUNET_GE_ERROR | GNUNET_GE_USER | | ||
483 | GNUNET_GE_ADMIN | GNUNET_GE_BULK, | ||
484 | "close"); | ||
485 | return GNUNET_SYSERR; | ||
486 | } | ||
487 | selector = GNUNET_select_create ("udp", GNUNET_YES, coreAPI->ectx, load_monitor, desc, addrlen, 0, /* timeout */ | ||
488 | &select_message_handler, | ||
489 | NULL, | ||
490 | &select_accept_handler, | ||
491 | NULL, | ||
492 | &select_close_handler, | ||
493 | NULL, 64 * 1024, | ||
494 | 16 /* max sockets */ ); | ||
495 | if (selector == NULL) | ||
496 | return GNUNET_SYSERR; | ||
497 | } | 623 | } |
498 | desc = udp_create_socket (); | 624 | |
499 | if (NULL == desc) | 625 | if (desc != NULL) |
500 | { | 626 | { |
501 | GNUNET_GE_LOG_STRERROR (coreAPI->ectx, | 627 | GNUNET_assert(GNUNET_NETWORK_socket_bind(desc, serverAddr, addrlen) == GNUNET_OK); |
502 | GNUNET_GE_ERROR | GNUNET_GE_ADMIN | | ||
503 | GNUNET_GE_BULK, "socket"); | ||
504 | GNUNET_select_destroy (selector); | ||
505 | selector = NULL; | ||
506 | return GNUNET_SYSERR; | ||
507 | } | 628 | } |
508 | udp_sock = GNUNET_socket_create (coreAPI->ectx, load_monitor, desc); | 629 | |
509 | GNUNET_GE_ASSERT (coreAPI->ectx, udp_sock != NULL); | 630 | plugin->rs = GNUNET_NETWORK_fdset_create (); |
631 | |||
632 | GNUNET_NETWORK_fdset_zero(plugin->rs); | ||
633 | GNUNET_NETWORK_fdset_set(plugin->rs, desc); | ||
634 | |||
635 | plugin->select_task = GNUNET_SCHEDULER_add_select(plugin->env->sched, GNUNET_SCHEDULER_PRIORITY_DEFAULT, GNUNET_SCHEDULER_NO_TASK, | ||
636 | GNUNET_TIME_UNIT_FOREVER_REL, plugin->rs, NULL, &udp_plugin_select, plugin); | ||
637 | |||
638 | return desc; | ||
639 | } | ||
640 | |||
641 | /** | ||
642 | * Function that can be used by the transport service to validate that | ||
643 | * another peer is reachable at a particular address (even if we | ||
644 | * already have a connection to this peer, this function is required | ||
645 | * to establish a new one). | ||
646 | * | ||
647 | * @param cls closure | ||
648 | * @param target who should receive this message | ||
649 | * @param challenge challenge code to use | ||
650 | * @param addrlen length of the address | ||
651 | * @param addr the address | ||
652 | * @param timeout how long should we try to transmit these? | ||
653 | * @return GNUNET_OK if the transmission has been scheduled | ||
654 | */ | ||
655 | static int | ||
656 | udp_plugin_validate (void *cls, | ||
657 | const struct GNUNET_PeerIdentity *target, | ||
658 | uint32_t challenge, | ||
659 | struct GNUNET_TIME_Relative timeout, | ||
660 | const void *addr, size_t addrlen) | ||
661 | { | ||
662 | struct Plugin *plugin = cls; | ||
663 | struct Session *new_session; | ||
664 | struct UDPPongMessage *msg; | ||
665 | |||
666 | if (addrlen <= 0) | ||
667 | return GNUNET_SYSERR; | ||
668 | |||
669 | new_session = GNUNET_malloc(sizeof(struct Session)); | ||
670 | new_session->connect_addr = GNUNET_malloc(addrlen); | ||
671 | memcpy(new_session->connect_addr, addr, addrlen); | ||
672 | new_session->connect_alen = addrlen; | ||
673 | #if DEBUG_UDP | ||
674 | if (memcmp(target, plugin->env->my_identity, sizeof(struct GNUNET_PeerIdentity)) == 0) | ||
675 | { | ||
676 | GNUNET_log_from(GNUNET_ERROR_TYPE_INFO, "udp", _ | ||
677 | ("definitely adding self to session list... hmmm\n")); | ||
678 | } | ||
679 | #endif | ||
680 | memcpy(&new_session->target, target, sizeof(struct GNUNET_PeerIdentity)); | ||
681 | new_session->challenge = challenge; | ||
682 | new_session->validated = GNUNET_NO; | ||
683 | new_session->next = plugin->sessions; | ||
684 | plugin->sessions = new_session; | ||
685 | |||
686 | msg = GNUNET_malloc (sizeof (struct UDPPongMessage)); | ||
687 | msg->header.size = htons(sizeof(struct UDPPongMessage)); | ||
688 | msg->header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_UDP_PING); | ||
689 | msg->challenge = htons(challenge); | ||
690 | #if DEBUG_UDP | ||
691 | GNUNET_log_from(GNUNET_ERROR_TYPE_INFO, "udp", _ | ||
692 | ("In validate, header size is %d, type %d, challenge %u\n"), ntohs(msg->header.size), ntohs(msg->header.type), ntohl(msg->challenge)); | ||
693 | #endif | ||
694 | udp_plugin_send(plugin, target, GNUNET_SCHEDULER_PRIORITY_DEFAULT, &msg->header, timeout, NULL, NULL); | ||
695 | |||
510 | return GNUNET_OK; | 696 | return GNUNET_OK; |
511 | } | 697 | } |
512 | 698 | ||
513 | /** | 699 | /** |
700 | * Convert the transports address to a nice, human-readable | ||
701 | * format. | ||
702 | * | ||
703 | * @param cls closure | ||
704 | * @param type name of the transport that generated the address | ||
705 | * @param addr one of the addresses of the host, NULL for the last address | ||
706 | * the specific address format depends on the transport | ||
707 | * @param addrlen length of the address | ||
708 | * @param numeric should (IP) addresses be displayed in numeric form? | ||
709 | * @param timeout after how long should we give up? | ||
710 | * @param asc function to call on each string | ||
711 | * @param asc_cls closure for asc | ||
712 | */ | ||
713 | static void | ||
714 | udp_plugin_address_pretty_printer (void *cls, | ||
715 | const char *type, | ||
716 | const void *addr, | ||
717 | size_t addrlen, | ||
718 | int numeric, | ||
719 | struct GNUNET_TIME_Relative timeout, | ||
720 | GNUNET_TRANSPORT_AddressStringCallback asc, | ||
721 | void *asc_cls) | ||
722 | { | ||
723 | |||
724 | } | ||
725 | |||
726 | /** | ||
727 | * Set a quota for receiving data from the given peer; this is a | ||
728 | * per-transport limit. The transport should limit its read/select | ||
729 | * calls to stay below the quota (in terms of incoming data). | ||
730 | * | ||
731 | * @param cls closure | ||
732 | * @param target the peer for whom the quota is given | ||
733 | * @param quota_in quota for receiving/sending data in bytes per ms | ||
734 | */ | ||
735 | static void | ||
736 | udp_plugin_set_receive_quota (void *cls, | ||
737 | const struct GNUNET_PeerIdentity *target, | ||
738 | uint32_t quota_in) | ||
739 | { | ||
740 | |||
741 | } | ||
742 | |||
743 | /** | ||
744 | * Another peer has suggested an address for this | ||
745 | * peer and transport plugin. Check that this could be a valid | ||
746 | * address. If so, consider adding it to the list | ||
747 | * of addresses. | ||
748 | * | ||
749 | * @param cls closure | ||
750 | * @param addr pointer to the address | ||
751 | * @param addrlen length of addr | ||
752 | * @return GNUNET_OK if this is a plausible address for this peer | ||
753 | * and transport | ||
754 | */ | ||
755 | static int | ||
756 | udp_plugin_address_suggested (void *cls, const void *addr, size_t addrlen) | ||
757 | { | ||
758 | |||
759 | return GNUNET_SYSERR; | ||
760 | } | ||
761 | |||
762 | |||
763 | /** | ||
514 | * The exported method. Makes the core api available via a global and | 764 | * The exported method. Makes the core api available via a global and |
515 | * returns the udp transport API. | 765 | * returns the udp transport API. |
516 | */ | 766 | */ |
517 | GNUNET_TransportAPI * | 767 | void * |
518 | inittransport_udp (GNUNET_CoreAPIForTransport * core) | 768 | libgnunet_plugin_transport_udp_init (void *cls) |
519 | { | 769 | { |
520 | unsigned long long mtu; | 770 | unsigned long long mtu; |
521 | 771 | ||
522 | cfg = core->cfg; | 772 | struct GNUNET_TRANSPORT_PluginEnvironment *env = cls; |
523 | load_monitor = core->load_monitor; | 773 | struct GNUNET_TRANSPORT_PluginFunctions *api; |
524 | GNUNET_GE_ASSERT (coreAPI->ectx, sizeof (UDPMessage) == 68); | 774 | struct Plugin *plugin; |
525 | GNUNET_GE_ASSERT (coreAPI->ectx, sizeof (HostAddress) == 24); | 775 | struct GNUNET_SERVICE_Context *service; |
526 | coreAPI = core; | 776 | unsigned long long aport; |
527 | if (-1 == GNUNET_GC_get_configuration_value_number (cfg, | 777 | unsigned long long bport; |
528 | "UDP", | 778 | |
529 | "MTU", | 779 | service = GNUNET_SERVICE_start ("transport-udp", env->sched, env->cfg); |
530 | sizeof (UDPMessage) | 780 | if (service == NULL) |
531 | + | ||
532 | GNUNET_P2P_MESSAGE_OVERHEAD | ||
533 | + | ||
534 | sizeof | ||
535 | (GNUNET_MessageHeader) + | ||
536 | 32, 65500, | ||
537 | MESSAGE_SIZE, &mtu)) | ||
538 | { | 781 | { |
782 | GNUNET_log_from(GNUNET_ERROR_TYPE_WARNING, "udp", _ | ||
783 | ("Failed to start service for `%s' transport plugin.\n"), "udp"); | ||
539 | return NULL; | 784 | return NULL; |
540 | } | 785 | } |
786 | aport = 0; | ||
787 | if ((GNUNET_OK != | ||
788 | GNUNET_CONFIGURATION_get_value_number (env->cfg, | ||
789 | "transport-udp", | ||
790 | "PORT", | ||
791 | &bport)) || | ||
792 | (bport > 65535) || | ||
793 | ((GNUNET_OK == | ||
794 | GNUNET_CONFIGURATION_get_value_number (env->cfg, | ||
795 | "transport-udp", | ||
796 | "ADVERTISED-PORT", | ||
797 | &aport)) && (aport > 65535))) | ||
798 | { | ||
799 | GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, | ||
800 | "udp", | ||
801 | _ | ||
802 | ("Require valid port number for service `%s' in configuration!\n"), | ||
803 | "transport-udp"); | ||
804 | GNUNET_SERVICE_stop (service); | ||
805 | return NULL; | ||
806 | } | ||
807 | if (aport == 0) | ||
808 | aport = bport; | ||
809 | |||
810 | mtu = 1240; | ||
541 | if (mtu < 1200) | 811 | if (mtu < 1200) |
542 | GNUNET_GE_LOG (coreAPI->ectx, | 812 | GNUNET_log_from(GNUNET_ERROR_TYPE_INFO, |
543 | GNUNET_GE_ERROR | GNUNET_GE_USER | GNUNET_GE_IMMEDIATE, | 813 | "udp", |
544 | _("MTU %llu for `%s' is probably too low!\n"), mtu, "UDP"); | 814 | _("MTU %llu for `%s' is probably too low!\n"), mtu, "UDP"); |
545 | lock = GNUNET_mutex_create (GNUNET_NO); | 815 | |
546 | if (0 != | 816 | plugin = GNUNET_malloc (sizeof (struct Plugin)); |
547 | GNUNET_GC_attach_change_listener (cfg, &reload_configuration, NULL)) | 817 | plugin->open_port = bport; |
548 | { | 818 | plugin->adv_port = aport; |
549 | GNUNET_mutex_destroy (lock); | 819 | plugin->env = env; |
550 | lock = NULL; | 820 | plugin->statistics = NULL; |
551 | return NULL; | 821 | api = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_PluginFunctions)); |
552 | } | 822 | plugin->sessions = NULL; |
553 | if (GNUNET_GC_get_configuration_value_yesno (cfg, "UDP", "UPNP", GNUNET_YES) | 823 | api->cls = plugin; |
554 | == GNUNET_YES) | 824 | |
555 | { | 825 | api->validate = &udp_plugin_validate; |
556 | upnp = coreAPI->service_request ("upnp"); | 826 | api->send = &udp_plugin_send; |
557 | if (upnp == NULL) | 827 | api->disconnect = &udp_disconnect; |
558 | GNUNET_GE_LOG (coreAPI->ectx, | 828 | api->address_pretty_printer = &udp_plugin_address_pretty_printer; |
559 | GNUNET_GE_ERROR | GNUNET_GE_USER | GNUNET_GE_IMMEDIATE, | 829 | api->set_receive_quota = &udp_plugin_set_receive_quota; |
560 | "The UPnP service could not be loaded. To disable UPnP, set the " | 830 | api->address_suggested = &udp_plugin_address_suggested; |
561 | "configuration option \"UPNP\" in section \"%s\" to \"NO\"\n", | 831 | api->cost_estimate = 17; /* TODO: ATS */ |
562 | "UDP"); | 832 | plugin->service = service; |
563 | } | 833 | |
564 | stats = coreAPI->service_request ("stats"); | 834 | udp_sock = udp_transport_server_start(plugin); |
565 | if (stats != NULL) | 835 | |
566 | { | 836 | GNUNET_assert(udp_sock != NULL); |
567 | stat_bytesReceived | 837 | |
568 | = stats->create (gettext_noop ("# bytes received via UDP")); | 838 | return api; |
569 | stat_bytesSent = stats->create (gettext_noop ("# bytes sent via UDP")); | ||
570 | stat_bytesDropped | ||
571 | = stats->create (gettext_noop ("# bytes dropped by UDP (outgoing)")); | ||
572 | stat_udpConnected | ||
573 | = stats->create (gettext_noop ("# UDP connections (right now)")); | ||
574 | } | ||
575 | myAPI.protocol_number = GNUNET_TRANSPORT_PROTOCOL_NUMBER_UDP; | ||
576 | myAPI.mtu = mtu - sizeof (UDPMessage); | ||
577 | myAPI.cost = 20000; | ||
578 | myAPI.hello_verify = &verify_hello; | ||
579 | myAPI.hello_create = &create_hello; | ||
580 | myAPI.connect = &udp_connect; | ||
581 | myAPI.send = &udp_send; | ||
582 | myAPI.associate = &udp_associate; | ||
583 | myAPI.disconnect = &udp_disconnect; | ||
584 | myAPI.server_start = &udp_transport_server_start; | ||
585 | myAPI.server_stop = &udp_transport_server_stop; | ||
586 | myAPI.hello_to_address = &hello_to_address; | ||
587 | myAPI.send_now_test = &udp_test_would_try; | ||
588 | |||
589 | return &myAPI; | ||
590 | } | 839 | } |
591 | 840 | ||
592 | void | 841 | void * |
593 | donetransport_udp () | 842 | libgnunet_plugin_transport_udp_done (void *cls) |
594 | { | 843 | { |
595 | do_shutdown (); | 844 | struct GNUNET_TRANSPORT_PluginFunctions *api = cls; |
845 | struct Plugin *plugin = api->cls; | ||
846 | |||
847 | udp_transport_server_stop(plugin); | ||
848 | if (NULL != hostname_dns) | ||
849 | { | ||
850 | GNUNET_RESOLVER_request_cancel (hostname_dns); | ||
851 | hostname_dns = NULL; | ||
852 | } | ||
853 | GNUNET_SERVICE_stop (plugin->service); | ||
854 | GNUNET_free (plugin); | ||
855 | GNUNET_free (api); | ||
856 | return NULL; | ||
596 | } | 857 | } |
597 | 858 | ||
598 | /* end of udp.c */ | 859 | /* end of plugin_transport_udp.c */ |
diff --git a/src/transport/test_plugin_transport_data_udp.conf b/src/transport/test_plugin_transport_data_udp.conf new file mode 100644 index 000000000..7583a868b --- /dev/null +++ b/src/transport/test_plugin_transport_data_udp.conf | |||
@@ -0,0 +1,24 @@ | |||
1 | [PATHS] | ||
2 | SERVICEHOME = /tmp/test-gnunetd-plugin-transport/ | ||
3 | |||
4 | [resolver] | ||
5 | PORT = 2364 | ||
6 | |||
7 | [transport] | ||
8 | PORT = 2365 | ||
9 | PLUGINS = udp | ||
10 | |||
11 | [arm] | ||
12 | PORT = 2366 | ||
13 | |||
14 | [statistics] | ||
15 | PORT = 2367 | ||
16 | |||
17 | [transport-udp] | ||
18 | PORT = 2368 | ||
19 | |||
20 | [peerinfo] | ||
21 | PORT = 2369 | ||
22 | |||
23 | [testing] | ||
24 | WEAKRANDOM = YES | ||
diff --git a/src/transport/test_plugin_transport_udp.c b/src/transport/test_plugin_transport_udp.c new file mode 100644 index 000000000..85740c256 --- /dev/null +++ b/src/transport/test_plugin_transport_udp.c | |||
@@ -0,0 +1,358 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | (C) 2009 Christian Grothoff (and other contributing authors) | ||
4 | |||
5 | GNUnet is free software; you can redistribute it and/or modify | ||
6 | it under the terms of the GNU General Public License as published | ||
7 | by the Free Software Foundation; either version 2, or (at your | ||
8 | option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU General Public License | ||
16 | along with GNUnet; see the file COPYING. If not, write to the | ||
17 | Free Software Foundation, Inc., 59 Temple Place - Suite 330, | ||
18 | Boston, MA 02111-1307, USA. | ||
19 | */ | ||
20 | /** | ||
21 | * @file transport/test_transport_api.c | ||
22 | * @brief testcase for transport_api.c | ||
23 | * @author Sailor Siraj | ||
24 | * @author Christian Grothoff | ||
25 | */ | ||
26 | |||
27 | #include "platform.h" | ||
28 | #include "gnunet_constants.h" | ||
29 | #include "gnunet_getopt_lib.h" | ||
30 | #include "gnunet_hello_lib.h" | ||
31 | #include "gnunet_os_lib.h" | ||
32 | #include "gnunet_peerinfo_service.h" | ||
33 | #include "gnunet_plugin_lib.h" | ||
34 | #include "gnunet_protocols.h" | ||
35 | #include "gnunet_program_lib.h" | ||
36 | #include "gnunet_signatures.h" | ||
37 | #include "plugin_transport.h" | ||
38 | #include "transport.h" | ||
39 | |||
40 | #define VERBOSE GNUNET_NO | ||
41 | |||
42 | /** | ||
43 | * How long until we give up on transmitting the message? | ||
44 | */ | ||
45 | #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30) | ||
46 | |||
47 | /** | ||
48 | * Our public key. | ||
49 | */ | ||
50 | static struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded my_public_key; | ||
51 | |||
52 | /** | ||
53 | * Our identity. | ||
54 | */ | ||
55 | static struct GNUNET_PeerIdentity my_identity; | ||
56 | |||
57 | /** | ||
58 | * Our private key. | ||
59 | */ | ||
60 | static struct GNUNET_CRYPTO_RsaPrivateKey *my_private_key; | ||
61 | |||
62 | /** | ||
63 | * Our scheduler. | ||
64 | */ | ||
65 | struct GNUNET_SCHEDULER_Handle *sched; | ||
66 | |||
67 | /** | ||
68 | * Our configuration. | ||
69 | */ | ||
70 | const struct GNUNET_CONFIGURATION_Handle *cfg; | ||
71 | |||
72 | /** | ||
73 | * Number of neighbours we'd like to have. | ||
74 | */ | ||
75 | static uint32_t max_connect_per_transport; | ||
76 | |||
77 | /** | ||
78 | * Environment for this plugin. | ||
79 | */ | ||
80 | struct GNUNET_TRANSPORT_PluginEnvironment env; | ||
81 | |||
82 | /** | ||
83 | *handle for the api provided by this plugin | ||
84 | */ | ||
85 | struct GNUNET_TRANSPORT_PluginFunctions *api; | ||
86 | |||
87 | /** | ||
88 | * Did the test pass or fail? | ||
89 | */ | ||
90 | static int ok; | ||
91 | |||
92 | /** | ||
93 | * Initialize Environment for this plugin | ||
94 | */ | ||
95 | static void | ||
96 | receive(void *cls, | ||
97 | struct GNUNET_TIME_Relative | ||
98 | latency, | ||
99 | const struct GNUNET_PeerIdentity | ||
100 | * peer, | ||
101 | const struct GNUNET_MessageHeader | ||
102 | * message) | ||
103 | { | ||
104 | /* do nothing */ | ||
105 | } | ||
106 | |||
107 | void notify_address(void *cls, | ||
108 | const char *name, | ||
109 | const void *addr, | ||
110 | size_t addrlen, | ||
111 | struct | ||
112 | GNUNET_TIME_Relative | ||
113 | expires) | ||
114 | { | ||
115 | } | ||
116 | |||
117 | /** | ||
118 | * Function called when the service shuts | ||
119 | * down. Unloads our plugins. | ||
120 | * | ||
121 | * @param cls closure | ||
122 | * @param cfg configuration to use | ||
123 | */ | ||
124 | static void | ||
125 | unload_plugins (void *cls, | ||
126 | const struct GNUNET_CONFIGURATION_Handle *cfg) | ||
127 | { | ||
128 | GNUNET_assert (NULL == GNUNET_PLUGIN_unload ("libgnunet_plugin_transport_udp",api)); | ||
129 | if (my_private_key != NULL) | ||
130 | GNUNET_CRYPTO_rsa_key_free (my_private_key); | ||
131 | |||
132 | } | ||
133 | |||
134 | |||
135 | static void | ||
136 | unload_task (void *cls, | ||
137 | const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
138 | { | ||
139 | struct GNUNET_CONFIGURATION_Handle *cfg = cls; | ||
140 | unload_plugins (NULL, cfg); | ||
141 | } | ||
142 | |||
143 | |||
144 | static GNUNET_SCHEDULER_TaskIdentifier validation_timeout_task; | ||
145 | |||
146 | |||
147 | static void | ||
148 | validation_notification (void *cls, | ||
149 | const char *name, | ||
150 | const struct GNUNET_PeerIdentity *peer, | ||
151 | uint32_t challenge, | ||
152 | const char *sender_addr) | ||
153 | { | ||
154 | if (validation_timeout_task != GNUNET_SCHEDULER_NO_TASK) | ||
155 | { | ||
156 | GNUNET_SCHEDULER_cancel (sched, validation_timeout_task); | ||
157 | validation_timeout_task = GNUNET_SCHEDULER_NO_TASK; | ||
158 | } | ||
159 | |||
160 | GNUNET_assert (challenge == 42); | ||
161 | |||
162 | ok = 0; /* if the last test succeeded, report success */ | ||
163 | |||
164 | GNUNET_SCHEDULER_add_continuation (sched, | ||
165 | &unload_task, | ||
166 | (void*) cfg, | ||
167 | GNUNET_SCHEDULER_REASON_PREREQ_DONE); | ||
168 | } | ||
169 | |||
170 | |||
171 | static void | ||
172 | validation_failed (void *cls, | ||
173 | const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
174 | { | ||
175 | validation_timeout_task = GNUNET_SCHEDULER_NO_TASK; | ||
176 | GNUNET_break (0); /* output error */ | ||
177 | /* the "validation_notification" was not called | ||
178 | in a timely fashion; we should set an error | ||
179 | code for main and shut down */ | ||
180 | unload_plugins (NULL, cfg); | ||
181 | } | ||
182 | |||
183 | |||
184 | /** | ||
185 | * Simple example test that invokes | ||
186 | * the "validate" function of the plugin | ||
187 | * and tries to see if the plugin would | ||
188 | * succeed to validate its own address. | ||
189 | * (This test is not well-written since | ||
190 | * we hand-compile the address which | ||
191 | * kind-of works for TCP but would not | ||
192 | * work for other plugins; we should ask | ||
193 | * the plugin about its address instead...). | ||
194 | */ | ||
195 | /* FIXME: won't work on IPv6 enabled systems where IPv4 mapping | ||
196 | * isn't enabled (eg. FreeBSD > 4) | ||
197 | */ | ||
198 | static void | ||
199 | test_validation () | ||
200 | { | ||
201 | struct sockaddr_in soaddr; | ||
202 | |||
203 | memset (&soaddr, 0, sizeof(soaddr)); | ||
204 | #if HAVE_SOCKADDR_IN_SIN_LEN | ||
205 | soaddr.sin_len = sizeof (soaddr); | ||
206 | #endif | ||
207 | soaddr.sin_family = AF_INET; | ||
208 | soaddr.sin_port = htons(2368 /* FIXME: get from config! */); | ||
209 | soaddr.sin_addr.s_addr = htonl (INADDR_LOOPBACK); | ||
210 | |||
211 | /* add job to catch failure (timeout) */ | ||
212 | validation_timeout_task = | ||
213 | GNUNET_SCHEDULER_add_delayed (sched, | ||
214 | TIMEOUT, | ||
215 | &validation_failed, | ||
216 | NULL); | ||
217 | |||
218 | api->validate (api->cls, | ||
219 | &my_identity, | ||
220 | 42, | ||
221 | TIMEOUT, | ||
222 | &soaddr, | ||
223 | sizeof(soaddr)); | ||
224 | } | ||
225 | |||
226 | |||
227 | static void setup_plugin_environment() | ||
228 | { | ||
229 | env.cfg = cfg; | ||
230 | env.sched = sched; | ||
231 | env.my_public_key = &my_public_key; | ||
232 | env.my_private_key = my_private_key; | ||
233 | env.my_identity = &my_identity; | ||
234 | env.cls=&env; | ||
235 | env.receive=&receive; | ||
236 | env.notify_address=¬ify_address; | ||
237 | env.notify_validation = &validation_notification; | ||
238 | env.max_connections = max_connect_per_transport; | ||
239 | } | ||
240 | static int retx; | ||
241 | |||
242 | /** | ||
243 | * Runs the test. | ||
244 | * | ||
245 | * @param cls closure | ||
246 | * @param s scheduler to use | ||
247 | * @param c configuration to use | ||
248 | */ | ||
249 | static void | ||
250 | run (void *cls, | ||
251 | struct GNUNET_SCHEDULER_Handle *s, | ||
252 | char *const *args, | ||
253 | const char *cfgfile, | ||
254 | const struct GNUNET_CONFIGURATION_Handle *c) | ||
255 | { | ||
256 | unsigned long long tneigh; | ||
257 | char *keyfile; | ||
258 | char *libname; | ||
259 | |||
260 | sched = s; | ||
261 | cfg = c; | ||
262 | /* parse configuration */ | ||
263 | if ((GNUNET_OK != | ||
264 | GNUNET_CONFIGURATION_get_value_number (c, | ||
265 | "TRANSPORT", | ||
266 | "NEIGHBOUR_LIMIT", | ||
267 | &tneigh)) || | ||
268 | (GNUNET_OK != | ||
269 | GNUNET_CONFIGURATION_get_value_filename (c, | ||
270 | "GNUNETD", | ||
271 | "HOSTKEY", &keyfile))) | ||
272 | { | ||
273 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
274 | _("Transport service is lacking key configuration settings. Exiting.\n")); | ||
275 | GNUNET_SCHEDULER_shutdown (s); | ||
276 | return; | ||
277 | } | ||
278 | max_connect_per_transport = (uint32_t) tneigh; | ||
279 | my_private_key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile); | ||
280 | GNUNET_free (keyfile); | ||
281 | if (my_private_key == NULL) | ||
282 | { | ||
283 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
284 | _("Transport service could not access hostkey. Exiting.\n")); | ||
285 | GNUNET_SCHEDULER_shutdown (s); | ||
286 | return; | ||
287 | } | ||
288 | GNUNET_CRYPTO_rsa_key_get_public (my_private_key, | ||
289 | &my_public_key); | ||
290 | GNUNET_CRYPTO_hash (&my_public_key, | ||
291 | sizeof (my_public_key), | ||
292 | &my_identity.hashPubKey); | ||
293 | |||
294 | /* load plugins... */ | ||
295 | setup_plugin_environment(); | ||
296 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
297 | _("Loading udp transport plugin\n")); | ||
298 | GNUNET_asprintf (&libname, "libgnunet_plugin_transport_udp"); | ||
299 | |||
300 | api = GNUNET_PLUGIN_load(libname, &env); | ||
301 | GNUNET_free (libname); | ||
302 | if (api == NULL) | ||
303 | { | ||
304 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
305 | _("Failed to load transport plugin for udp\n")); | ||
306 | /* FIXME: set some error code for main */ | ||
307 | return; | ||
308 | } | ||
309 | test_validation (); | ||
310 | } | ||
311 | |||
312 | |||
313 | /** | ||
314 | * The main function for the transport service. | ||
315 | * | ||
316 | * @param argc number of arguments from the command line | ||
317 | * @param argv command line arguments | ||
318 | * @return 0 ok, 1 on error | ||
319 | */ | ||
320 | int | ||
321 | main (int argc, char *const *argv) | ||
322 | { | ||
323 | static struct GNUNET_GETOPT_CommandLineOption options[] = { | ||
324 | GNUNET_GETOPT_OPTION_END | ||
325 | }; | ||
326 | int ret; | ||
327 | char *const argv_prog[] = { | ||
328 | "test_plugin_transport", | ||
329 | "-c", | ||
330 | "test_plugin_transport_data_udp.conf", | ||
331 | "-L", | ||
332 | #if VERBOSE | ||
333 | "DEBUG", | ||
334 | #else | ||
335 | "WARNING", | ||
336 | #endif | ||
337 | NULL | ||
338 | }; | ||
339 | GNUNET_log_setup ("test-plugin-transport", | ||
340 | #if VERBOSE | ||
341 | "DEBUG", | ||
342 | #else | ||
343 | "WARNING", | ||
344 | #endif | ||
345 | NULL); | ||
346 | ok = 1; /* set to fail */ | ||
347 | ret = (GNUNET_OK == | ||
348 | GNUNET_PROGRAM_run (5, | ||
349 | argv_prog, | ||
350 | "test-plugin-transport", | ||
351 | "testcase", | ||
352 | options, | ||
353 | &run, NULL)) ? ok : 1; | ||
354 | GNUNET_DISK_directory_remove ("/tmp/test-gnunetd-plugin-transport"); | ||
355 | return ret; | ||
356 | } | ||
357 | |||
358 | /* end of test_plugin_transport_udp.c */ | ||
diff --git a/src/util/network.c b/src/util/network.c index d889fa94b..398f2b51a 100644 --- a/src/util/network.c +++ b/src/util/network.c | |||
@@ -355,6 +355,62 @@ GNUNET_NETWORK_socket_listen (const struct GNUNET_NETWORK_Handle *desc, | |||
355 | 355 | ||
356 | 356 | ||
357 | /** | 357 | /** |
358 | * How much data is available to be read on this descriptor? | ||
359 | * | ||
360 | * Returns GNUNET_NO if no data is available, or on error! | ||
361 | * @param desc socket | ||
362 | */ | ||
363 | unsigned int | ||
364 | GNUNET_NETWORK_socket_recvfrom_amount (const struct GNUNET_NETWORK_Handle * desc) | ||
365 | { | ||
366 | int error; | ||
367 | unsigned int pending; | ||
368 | |||
369 | /* How much is there to be read? */ | ||
370 | error = ioctl(desc->fd, FIONREAD, &pending); | ||
371 | GNUNET_log_from(GNUNET_ERROR_TYPE_INFO, "udp", _ | ||
372 | ("pending is %u bytes, error is %d\n"), pending, error); | ||
373 | |||
374 | if (error == 0) | ||
375 | return pending; | ||
376 | else | ||
377 | return GNUNET_NO; | ||
378 | } | ||
379 | |||
380 | /** | ||
381 | * Read data from a connected socket (always non-blocking). | ||
382 | * @param desc socket | ||
383 | * @param buffer buffer | ||
384 | * @param length length of buffer | ||
385 | * @param src_addr either the source to recv from, or all zeroes | ||
386 | * to be filled in by recvfrom | ||
387 | * @param addrlen length of the addr | ||
388 | */ | ||
389 | ssize_t | ||
390 | GNUNET_NETWORK_socket_recvfrom (const struct GNUNET_NETWORK_Handle * desc, | ||
391 | void *buffer, size_t length, | ||
392 | struct sockaddr *src_addr, socklen_t *addrlen) | ||
393 | { | ||
394 | int ret; | ||
395 | int flags; | ||
396 | flags = 0; | ||
397 | |||
398 | #ifdef MSG_DONTWAIT | ||
399 | flags |= MSG_DONTWAIT; | ||
400 | |||
401 | #endif /* */ | ||
402 | ret = recvfrom (desc->fd, buffer, length, flags, src_addr, addrlen); | ||
403 | |||
404 | #ifdef MINGW | ||
405 | if (SOCKET_ERROR == ret) | ||
406 | SetErrnoFromWinsockError (WSAGetLastError ()); | ||
407 | |||
408 | #endif /* */ | ||
409 | return ret; | ||
410 | } | ||
411 | |||
412 | |||
413 | /** | ||
358 | * Read data from a connected socket (always non-blocking). | 414 | * Read data from a connected socket (always non-blocking). |
359 | * @param desc socket | 415 | * @param desc socket |
360 | * @param buffer buffer | 416 | * @param buffer buffer |
@@ -643,6 +699,12 @@ GNUNET_NETWORK_fdset_copy (struct GNUNET_NETWORK_FDSet *to, | |||
643 | #endif | 699 | #endif |
644 | } | 700 | } |
645 | 701 | ||
702 | int | ||
703 | GNUNET_NETWORK_get_fd (struct GNUNET_NETWORK_Handle *desc) | ||
704 | { | ||
705 | return desc->fd; | ||
706 | } | ||
707 | |||
646 | /** | 708 | /** |
647 | * Copy a native fd set | 709 | * Copy a native fd set |
648 | * | 710 | * |
diff --git a/src/util/scheduler.c b/src/util/scheduler.c index a8e5add3e..6b12c7d1a 100644 --- a/src/util/scheduler.c +++ b/src/util/scheduler.c | |||
@@ -365,7 +365,7 @@ check_ready (struct GNUNET_SCHEDULER_Handle *handle, | |||
365 | { | 365 | { |
366 | #if DEBUG_TASKS | 366 | #if DEBUG_TASKS |
367 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 367 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
368 | "Checking readyness of task: %llu / %p\n", | 368 | "Checking readiness of task: %llu / %p\n", |
369 | pos->id, pos->callback_cls); | 369 | pos->id, pos->callback_cls); |
370 | #endif | 370 | #endif |
371 | next = pos->next; | 371 | next = pos->next; |
@@ -406,7 +406,7 @@ GNUNET_SCHEDULER_shutdown (struct GNUNET_SCHEDULER_Handle *sched) | |||
406 | pos->reason |= GNUNET_SCHEDULER_REASON_SHUTDOWN; | 406 | pos->reason |= GNUNET_SCHEDULER_REASON_SHUTDOWN; |
407 | /* we don't move the task into the ready queue yet; check_ready | 407 | /* we don't move the task into the ready queue yet; check_ready |
408 | will do that later, possibly adding additional | 408 | will do that later, possibly adding additional |
409 | readyness-factors */ | 409 | readiness-factors */ |
410 | pos = pos->next; | 410 | pos = pos->next; |
411 | } | 411 | } |
412 | for (i=0;i<GNUNET_SCHEDULER_PRIORITY_COUNT;i++) | 412 | for (i=0;i<GNUNET_SCHEDULER_PRIORITY_COUNT;i++) |
@@ -417,7 +417,7 @@ GNUNET_SCHEDULER_shutdown (struct GNUNET_SCHEDULER_Handle *sched) | |||
417 | pos->reason |= GNUNET_SCHEDULER_REASON_SHUTDOWN; | 417 | pos->reason |= GNUNET_SCHEDULER_REASON_SHUTDOWN; |
418 | /* we don't move the task into the ready queue yet; check_ready | 418 | /* we don't move the task into the ready queue yet; check_ready |
419 | will do that later, possibly adding additional | 419 | will do that later, possibly adding additional |
420 | readyness-factors */ | 420 | readiness-factors */ |
421 | pos = pos->next; | 421 | pos = pos->next; |
422 | } | 422 | } |
423 | } | 423 | } |
@@ -773,7 +773,7 @@ GNUNET_SCHEDULER_add_continuation (struct GNUNET_SCHEDULER_Handle *sched, | |||
773 | * @param sched scheduler to use | 773 | * @param sched scheduler to use |
774 | * @param prerequisite_task run this task after the task with the given | 774 | * @param prerequisite_task run this task after the task with the given |
775 | * task identifier completes (and any of our other | 775 | * task identifier completes (and any of our other |
776 | * conditions, such as delay, read or write-readyness | 776 | * conditions, such as delay, read or write-readiness |
777 | * are satisfied). Use GNUNET_SCHEDULER_NO_TASK to not have any dependency | 777 | * are satisfied). Use GNUNET_SCHEDULER_NO_TASK to not have any dependency |
778 | * on completion of other tasks (this will cause the task to run as | 778 | * on completion of other tasks (this will cause the task to run as |
779 | * soon as possible). | 779 | * soon as possible). |
@@ -1044,7 +1044,7 @@ GNUNET_SCHEDULER_add_write_file (struct GNUNET_SCHEDULER_Handle * sched, | |||
1044 | * @param prio how important is this task? | 1044 | * @param prio how important is this task? |
1045 | * @param prerequisite_task run this task after the task with the given | 1045 | * @param prerequisite_task run this task after the task with the given |
1046 | * task identifier completes (and any of our other | 1046 | * task identifier completes (and any of our other |
1047 | * conditions, such as delay, read or write-readyness | 1047 | * conditions, such as delay, read or write-readiness |
1048 | * are satisfied). Use GNUNET_SCHEDULER_NO_TASK to not have any dependency | 1048 | * are satisfied). Use GNUNET_SCHEDULER_NO_TASK to not have any dependency |
1049 | * on completion of other tasks. | 1049 | * on completion of other tasks. |
1050 | * @param delay how long should we wait? Use GNUNET_TIME_UNIT_FOREVER_REL for "forever", | 1050 | * @param delay how long should we wait? Use GNUNET_TIME_UNIT_FOREVER_REL for "forever", |