diff options
Diffstat (limited to 'src/util')
-rw-r--r-- | src/util/Makefile.am | 20 | ||||
-rw-r--r-- | src/util/client.c | 68 | ||||
-rw-r--r-- | src/util/connection.c | 926 | ||||
-rw-r--r-- | src/util/gnunet-service-resolver.c | 492 | ||||
-rw-r--r-- | src/util/resolver.h | 63 | ||||
-rw-r--r-- | src/util/resolver_api.c | 589 | ||||
-rw-r--r-- | src/util/server.c | 46 | ||||
-rw-r--r-- | src/util/test_client.c | 2 | ||||
-rw-r--r-- | src/util/test_connection.c | 11 | ||||
-rw-r--r-- | src/util/test_connection_receive_cancel.c | 25 | ||||
-rw-r--r-- | src/util/test_connection_timeout.c | 10 | ||||
-rw-r--r-- | src/util/test_connection_timeout_no_connect.c | 10 | ||||
-rw-r--r-- | src/util/test_connection_transmit_cancel.c | 10 | ||||
-rw-r--r-- | src/util/test_resolver_api.c | 212 | ||||
-rw-r--r-- | src/util/test_resolver_api_data.conf | 6 | ||||
-rw-r--r-- | src/util/test_server.c | 9 | ||||
-rw-r--r-- | src/util/test_server_disconnect.c | 2 | ||||
-rw-r--r-- | src/util/test_server_with_client.c | 2 | ||||
-rw-r--r-- | src/util/test_service_data.conf | 3 |
19 files changed, 2062 insertions, 444 deletions
diff --git a/src/util/Makefile.am b/src/util/Makefile.am index 240c86247..f69c64b9f 100644 --- a/src/util/Makefile.am +++ b/src/util/Makefile.am | |||
@@ -46,6 +46,7 @@ libgnunetutil_la_SOURCES = \ | |||
46 | plugin.c \ | 46 | plugin.c \ |
47 | program.c \ | 47 | program.c \ |
48 | pseudonym.c \ | 48 | pseudonym.c \ |
49 | resolver_api.c \ | ||
49 | scheduler.c \ | 50 | scheduler.c \ |
50 | server.c \ | 51 | server.c \ |
51 | server_tc.c \ | 52 | server_tc.c \ |
@@ -66,6 +67,16 @@ libgnunetutil_la_LDFLAGS = \ | |||
66 | -version-info 4:0:0 | 67 | -version-info 4:0:0 |
67 | 68 | ||
68 | 69 | ||
70 | bin_PROGRAMS = \ | ||
71 | gnunet-service-resolver | ||
72 | |||
73 | gnunet_service_resolver_SOURCES = \ | ||
74 | gnunet-service-resolver.c | ||
75 | gnunet_service_resolver_LDADD = \ | ||
76 | $(top_builddir)/src/util/libgnunetutil.la \ | ||
77 | $(GN_LIBINTL) | ||
78 | |||
79 | |||
69 | plugin_LTLIBRARIES = \ | 80 | plugin_LTLIBRARIES = \ |
70 | libgnunet_plugin_test.la | 81 | libgnunet_plugin_test.la |
71 | 82 | ||
@@ -106,6 +117,7 @@ check_PROGRAMS = \ | |||
106 | test_plugin \ | 117 | test_plugin \ |
107 | test_program \ | 118 | test_program \ |
108 | test_pseudonym \ | 119 | test_pseudonym \ |
120 | test_resolver_api \ | ||
109 | test_scheduler \ | 121 | test_scheduler \ |
110 | test_scheduler_delay \ | 122 | test_scheduler_delay \ |
111 | test_server \ | 123 | test_server \ |
@@ -157,7 +169,7 @@ test_container_multihashmap_SOURCES = \ | |||
157 | test_container_multihashmap.c | 169 | test_container_multihashmap.c |
158 | test_container_multihashmap_LDADD = \ | 170 | test_container_multihashmap_LDADD = \ |
159 | $(top_builddir)/src/util/libgnunetutil.la | 171 | $(top_builddir)/src/util/libgnunetutil.la |
160 | 172 | ||
161 | test_container_heap_SOURCES = \ | 173 | test_container_heap_SOURCES = \ |
162 | test_container_heap.c | 174 | test_container_heap.c |
163 | test_container_heap_LDADD = \ | 175 | test_container_heap_LDADD = \ |
@@ -268,6 +280,11 @@ test_pseudonym_SOURCES = \ | |||
268 | test_pseudonym_LDADD = \ | 280 | test_pseudonym_LDADD = \ |
269 | $(top_builddir)/src/util/libgnunetutil.la | 281 | $(top_builddir)/src/util/libgnunetutil.la |
270 | 282 | ||
283 | test_resolver_api_SOURCES = \ | ||
284 | test_resolver_api.c | ||
285 | test_resolver_api_LDADD = \ | ||
286 | $(top_builddir)/src/util/libgnunetutil.la | ||
287 | |||
271 | test_scheduler_SOURCES = \ | 288 | test_scheduler_SOURCES = \ |
272 | test_scheduler.c | 289 | test_scheduler.c |
273 | test_scheduler_LDADD = \ | 290 | test_scheduler_LDADD = \ |
@@ -319,4 +336,5 @@ EXTRA_DIST = \ | |||
319 | test_container_meta_data_image.jpg \ | 336 | test_container_meta_data_image.jpg \ |
320 | test_program_data.conf \ | 337 | test_program_data.conf \ |
321 | test_pseudonym_data.conf \ | 338 | test_pseudonym_data.conf \ |
339 | test_resolver_api_data.conf \ | ||
322 | test_service_data.conf | 340 | test_service_data.conf |
diff --git a/src/util/client.c b/src/util/client.c index 2da392fb4..bdb258b73 100644 --- a/src/util/client.c +++ b/src/util/client.c | |||
@@ -61,11 +61,6 @@ struct GNUNET_CLIENT_Connection | |||
61 | char *service_name; | 61 | char *service_name; |
62 | 62 | ||
63 | /** | 63 | /** |
64 | * ID of task used for receiving. | ||
65 | */ | ||
66 | GNUNET_SCHEDULER_TaskIdentifier receiver_task; | ||
67 | |||
68 | /** | ||
69 | * Handler for current receiver task. | 64 | * Handler for current receiver task. |
70 | */ | 65 | */ |
71 | GNUNET_CLIENT_MessageHandler receiver_handler; | 66 | GNUNET_CLIENT_MessageHandler receiver_handler; |
@@ -110,6 +105,14 @@ struct GNUNET_CLIENT_Connection | |||
110 | */ | 105 | */ |
111 | int msg_complete; | 106 | int msg_complete; |
112 | 107 | ||
108 | /** | ||
109 | * Are we currently busy doing receive-processing? | ||
110 | * GNUNET_YES if so, GNUNET_NO if not, GNUNET_SYSERR | ||
111 | * if the handle should be destroyed as soon as the | ||
112 | * receive processing is done. | ||
113 | */ | ||
114 | int in_receive; | ||
115 | |||
113 | }; | 116 | }; |
114 | 117 | ||
115 | 118 | ||
@@ -156,6 +159,7 @@ GNUNET_CLIENT_connect (struct GNUNET_SCHEDULER_Handle *sched, | |||
156 | return NULL; | 159 | return NULL; |
157 | } | 160 | } |
158 | sock = GNUNET_CONNECTION_create_from_connect (sched, | 161 | sock = GNUNET_CONNECTION_create_from_connect (sched, |
162 | cfg, | ||
159 | hostname, | 163 | hostname, |
160 | port, | 164 | port, |
161 | GNUNET_SERVER_MAX_MESSAGE_SIZE); | 165 | GNUNET_SERVER_MAX_MESSAGE_SIZE); |
@@ -195,15 +199,19 @@ GNUNET_CLIENT_disconnect (struct GNUNET_CLIENT_Connection *sock) | |||
195 | GNUNET_CONNECTION_destroy (sock->sock); | 199 | GNUNET_CONNECTION_destroy (sock->sock); |
196 | sock->sock = NULL; | 200 | sock->sock = NULL; |
197 | sock->receiver_handler = NULL; | 201 | sock->receiver_handler = NULL; |
198 | GNUNET_SCHEDULER_add_after (sock->sched, | 202 | if (sock->in_receive == GNUNET_YES) |
199 | GNUNET_YES, | 203 | sock->in_receive = GNUNET_SYSERR; |
200 | GNUNET_SCHEDULER_PRIORITY_KEEP, | 204 | else |
201 | sock->receiver_task, &finish_cleanup, sock); | 205 | GNUNET_SCHEDULER_add_after (sock->sched, |
206 | GNUNET_YES, | ||
207 | GNUNET_SCHEDULER_PRIORITY_KEEP, | ||
208 | GNUNET_SCHEDULER_NO_TASK, | ||
209 | &finish_cleanup, sock); | ||
202 | } | 210 | } |
203 | 211 | ||
204 | 212 | ||
205 | /** | 213 | /** |
206 | * check if message is complete | 214 | * Check if message is complete |
207 | */ | 215 | */ |
208 | static void | 216 | static void |
209 | check_complete (struct GNUNET_CLIENT_Connection *conn) | 217 | check_complete (struct GNUNET_CLIENT_Connection *conn) |
@@ -238,8 +246,14 @@ receive_helper (void *cls, | |||
238 | struct GNUNET_TIME_Relative remaining; | 246 | struct GNUNET_TIME_Relative remaining; |
239 | 247 | ||
240 | GNUNET_assert (conn->msg_complete == GNUNET_NO); | 248 | GNUNET_assert (conn->msg_complete == GNUNET_NO); |
241 | conn->receiver_task = GNUNET_SCHEDULER_NO_TASK; | 249 | if (GNUNET_SYSERR == conn->in_receive) |
242 | 250 | GNUNET_SCHEDULER_add_after (conn->sched, | |
251 | GNUNET_YES, | ||
252 | GNUNET_SCHEDULER_PRIORITY_KEEP, | ||
253 | GNUNET_SCHEDULER_NO_TASK, | ||
254 | &finish_cleanup, | ||
255 | conn); | ||
256 | conn->in_receive = GNUNET_NO; | ||
243 | if ((available == 0) || (conn->sock == NULL) || (errCode != 0)) | 257 | if ((available == 0) || (conn->sock == NULL) || (errCode != 0)) |
244 | { | 258 | { |
245 | /* signal timeout! */ | 259 | /* signal timeout! */ |
@@ -291,8 +305,15 @@ receive_task (void *scls, const struct GNUNET_SCHEDULER_TaskContext *tc) | |||
291 | char mbuf[msize]; | 305 | char mbuf[msize]; |
292 | struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader*) mbuf; | 306 | struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader*) mbuf; |
293 | 307 | ||
308 | if (GNUNET_SYSERR == sock->in_receive) | ||
309 | GNUNET_SCHEDULER_add_after (sock->sched, | ||
310 | GNUNET_YES, | ||
311 | GNUNET_SCHEDULER_PRIORITY_KEEP, | ||
312 | GNUNET_SCHEDULER_NO_TASK, | ||
313 | &finish_cleanup, | ||
314 | sock); | ||
315 | sock->in_receive = GNUNET_NO; | ||
294 | GNUNET_assert (GNUNET_YES == sock->msg_complete); | 316 | GNUNET_assert (GNUNET_YES == sock->msg_complete); |
295 | sock->receiver_task = GNUNET_SCHEDULER_NO_TASK; | ||
296 | GNUNET_assert (sock->received_pos >= msize); | 317 | GNUNET_assert (sock->received_pos >= msize); |
297 | memcpy (msg, cmsg, msize); | 318 | memcpy (msg, cmsg, msize); |
298 | memmove (sock->received_buf, | 319 | memmove (sock->received_buf, |
@@ -326,22 +347,21 @@ GNUNET_CLIENT_receive (struct GNUNET_CLIENT_Connection *sock, | |||
326 | handler (handler_cls, NULL); | 347 | handler (handler_cls, NULL); |
327 | return; | 348 | return; |
328 | } | 349 | } |
329 | GNUNET_assert (sock->receiver_task == | ||
330 | GNUNET_SCHEDULER_NO_TASK); | ||
331 | sock->receiver_handler = handler; | 350 | sock->receiver_handler = handler; |
332 | sock->receiver_handler_cls = handler_cls; | 351 | sock->receiver_handler_cls = handler_cls; |
333 | sock->receive_timeout = GNUNET_TIME_relative_to_absolute (timeout); | 352 | sock->receive_timeout = GNUNET_TIME_relative_to_absolute (timeout); |
353 | sock->in_receive = GNUNET_YES; | ||
334 | if (GNUNET_YES == sock->msg_complete) | 354 | if (GNUNET_YES == sock->msg_complete) |
335 | sock->receiver_task = GNUNET_SCHEDULER_add_after (sock->sched, | 355 | GNUNET_SCHEDULER_add_after (sock->sched, |
336 | GNUNET_YES, | 356 | GNUNET_YES, |
337 | GNUNET_SCHEDULER_PRIORITY_KEEP, | 357 | GNUNET_SCHEDULER_PRIORITY_KEEP, |
338 | GNUNET_SCHEDULER_NO_TASK, | 358 | GNUNET_SCHEDULER_NO_TASK, |
339 | &receive_task, sock); | 359 | &receive_task, sock); |
340 | else | 360 | else |
341 | sock->receiver_task = GNUNET_CONNECTION_receive (sock->sock, | 361 | GNUNET_CONNECTION_receive (sock->sock, |
342 | GNUNET_SERVER_MAX_MESSAGE_SIZE, | 362 | GNUNET_SERVER_MAX_MESSAGE_SIZE, |
343 | timeout, | 363 | timeout, |
344 | &receive_helper, sock); | 364 | &receive_helper, sock); |
345 | } | 365 | } |
346 | 366 | ||
347 | 367 | ||
diff --git a/src/util/connection.c b/src/util/connection.c index fa6542325..a3e9101ea 100644 --- a/src/util/connection.c +++ b/src/util/connection.c | |||
@@ -38,17 +38,43 @@ | |||
38 | #include "platform.h" | 38 | #include "platform.h" |
39 | #include "gnunet_common.h" | 39 | #include "gnunet_common.h" |
40 | #include "gnunet_connection_lib.h" | 40 | #include "gnunet_connection_lib.h" |
41 | #include "gnunet_container_lib.h" | ||
42 | #include "gnunet_resolver_service.h" | ||
41 | #include "gnunet_scheduler_lib.h" | 43 | #include "gnunet_scheduler_lib.h" |
42 | 44 | ||
43 | #define DEBUG_CONNECTION GNUNET_NO | 45 | #define DEBUG_CONNECTION GNUNET_NO |
44 | 46 | ||
47 | |||
45 | /** | 48 | /** |
46 | * List of address families to give as hints to | 49 | * Possible functions to call after connect failed or succeeded. |
47 | * getaddrinfo, in reverse order of preference. | ||
48 | */ | 50 | */ |
49 | static int address_families[] = | 51 | enum ConnectContinuations |
50 | { AF_INET, AF_INET6, AF_UNSPEC }; | 52 | { |
53 | /** | ||
54 | * Call nothing. | ||
55 | */ | ||
56 | CC_NONE = 0, | ||
57 | |||
58 | /** | ||
59 | * Call "receive_again". | ||
60 | */ | ||
61 | CC_RECEIVE_AGAIN = 1, | ||
62 | |||
63 | /** | ||
64 | * Call "transmit_ready". | ||
65 | */ | ||
66 | CC_TRANSMIT_READY = 2, | ||
67 | |||
68 | /** | ||
69 | * Call "destroy_continuation". | ||
70 | */ | ||
71 | CC_DESTROY_CONTINUATION = 4 | ||
72 | }; | ||
73 | |||
51 | 74 | ||
75 | /** | ||
76 | * Transmission handle. There can only be one for each connection. | ||
77 | */ | ||
52 | struct GNUNET_CONNECTION_TransmitHandle | 78 | struct GNUNET_CONNECTION_TransmitHandle |
53 | { | 79 | { |
54 | 80 | ||
@@ -86,6 +112,51 @@ struct GNUNET_CONNECTION_TransmitHandle | |||
86 | 112 | ||
87 | }; | 113 | }; |
88 | 114 | ||
115 | |||
116 | /** | ||
117 | * During connect, we try multiple possible IP addresses | ||
118 | * to find out which one might work. | ||
119 | */ | ||
120 | struct AddressProbe | ||
121 | { | ||
122 | |||
123 | /** | ||
124 | * This is a linked list. | ||
125 | */ | ||
126 | struct AddressProbe *next; | ||
127 | |||
128 | /** | ||
129 | * This is a doubly-linked list. | ||
130 | */ | ||
131 | struct AddressProbe *prev; | ||
132 | |||
133 | /** | ||
134 | * The address; do not free (allocated at the end of this struct). | ||
135 | */ | ||
136 | const struct sockaddr *addr; | ||
137 | |||
138 | /** | ||
139 | * Underlying OS's socket. | ||
140 | */ | ||
141 | struct GNUNET_NETWORK_Handle *sock; | ||
142 | |||
143 | /** | ||
144 | * Connection for which we are probing. | ||
145 | */ | ||
146 | struct GNUNET_CONNECTION_Handle *h; | ||
147 | |||
148 | /** | ||
149 | * Lenth of addr. | ||
150 | */ | ||
151 | socklen_t addrlen; | ||
152 | |||
153 | /** | ||
154 | * Task waiting for the socket to finish connecting. | ||
155 | */ | ||
156 | GNUNET_SCHEDULER_TaskIdentifier task; | ||
157 | }; | ||
158 | |||
159 | |||
89 | /** | 160 | /** |
90 | * @brief handle for a network socket | 161 | * @brief handle for a network socket |
91 | */ | 162 | */ |
@@ -98,14 +169,21 @@ struct GNUNET_CONNECTION_Handle | |||
98 | struct GNUNET_SCHEDULER_Handle *sched; | 169 | struct GNUNET_SCHEDULER_Handle *sched; |
99 | 170 | ||
100 | /** | 171 | /** |
101 | * Address information for connect (may be NULL). | 172 | * Configuration to use. |
173 | */ | ||
174 | const struct GNUNET_CONFIGURATION_Handle *cfg; | ||
175 | |||
176 | /** | ||
177 | * Linked list of sockets we are currently trying out | ||
178 | * (during connect). | ||
102 | */ | 179 | */ |
103 | struct addrinfo *ai; | 180 | struct AddressProbe *ap_head; |
104 | 181 | ||
105 | /** | 182 | /** |
106 | * Index for the next struct addrinfo for connect attempts (may be NULL) | 183 | * Linked list of sockets we are currently trying out |
184 | * (during connect). | ||
107 | */ | 185 | */ |
108 | struct addrinfo *ai_pos; | 186 | struct AddressProbe *ap_tail; |
109 | 187 | ||
110 | /** | 188 | /** |
111 | * Network address of the other end-point, may be NULL. | 189 | * Network address of the other end-point, may be NULL. |
@@ -119,6 +197,21 @@ struct GNUNET_CONNECTION_Handle | |||
119 | char *hostname; | 197 | char *hostname; |
120 | 198 | ||
121 | /** | 199 | /** |
200 | * Underlying OS's socket, set to NULL after fatal errors. | ||
201 | */ | ||
202 | struct GNUNET_NETWORK_Handle *sock; | ||
203 | |||
204 | /** | ||
205 | * Function to call on data received, NULL if no receive is pending. | ||
206 | */ | ||
207 | GNUNET_CONNECTION_Receiver receiver; | ||
208 | |||
209 | /** | ||
210 | * Closure for receiver. | ||
211 | */ | ||
212 | void *receiver_cls; | ||
213 | |||
214 | /** | ||
122 | * Pointer to our write buffer. | 215 | * Pointer to our write buffer. |
123 | */ | 216 | */ |
124 | char *write_buffer; | 217 | char *write_buffer; |
@@ -146,17 +239,6 @@ struct GNUNET_CONNECTION_Handle | |||
146 | socklen_t addrlen; | 239 | socklen_t addrlen; |
147 | 240 | ||
148 | /** | 241 | /** |
149 | * Offset in our address family list | ||
150 | * that we used last. | ||
151 | */ | ||
152 | int af_fam_offset; | ||
153 | |||
154 | /** | ||
155 | * Connect task that we may need to wait for. | ||
156 | */ | ||
157 | GNUNET_SCHEDULER_TaskIdentifier connect_task; | ||
158 | |||
159 | /** | ||
160 | * Read task that we may need to wait for. | 242 | * Read task that we may need to wait for. |
161 | */ | 243 | */ |
162 | GNUNET_SCHEDULER_TaskIdentifier read_task; | 244 | GNUNET_SCHEDULER_TaskIdentifier read_task; |
@@ -172,36 +254,32 @@ struct GNUNET_CONNECTION_Handle | |||
172 | struct GNUNET_CONNECTION_TransmitHandle nth; | 254 | struct GNUNET_CONNECTION_TransmitHandle nth; |
173 | 255 | ||
174 | /** | 256 | /** |
175 | * Underlying OS's socket, set to NULL after fatal errors. | 257 | * Timeout for receiving (in absolute time). |
176 | */ | ||
177 | struct GNUNET_NETWORK_Handle *sock; | ||
178 | |||
179 | /** | ||
180 | * Port to connect to. | ||
181 | */ | 258 | */ |
182 | uint16_t port; | 259 | struct GNUNET_TIME_Absolute receive_timeout; |
183 | 260 | ||
184 | /** | 261 | /** |
185 | * Function to call on data received, NULL | 262 | * Functions to call after connect failed or succeeded. |
186 | * if no receive is pending. | ||
187 | */ | 263 | */ |
188 | GNUNET_CONNECTION_Receiver receiver; | 264 | enum ConnectContinuations ccs; |
189 | 265 | ||
190 | /** | 266 | /** |
191 | * Closure for receiver. | 267 | * Maximum number of bytes to read (for receiving). |
192 | */ | 268 | */ |
193 | void *receiver_cls; | 269 | size_t max; |
194 | 270 | ||
195 | /** | 271 | /** |
196 | * Timeout for receiving (in absolute time). | 272 | * Are we still waiting for DNS replies (on connect)? |
273 | * GNUNET_YES if we are, GNUNET_NO if we are not waiting for DNS, | ||
274 | * GNUNET_SYSERR if destroying the handle was deferred due to | ||
275 | * a pending DNS lookup. | ||
197 | */ | 276 | */ |
198 | struct GNUNET_TIME_Absolute receive_timeout; | 277 | int dns_active; |
199 | 278 | ||
200 | /** | 279 | /** |
201 | * Maximum number of bytes to read | 280 | * Port to connect to. |
202 | * (for receiving). | ||
203 | */ | 281 | */ |
204 | size_t max; | 282 | uint16_t port; |
205 | 283 | ||
206 | }; | 284 | }; |
207 | 285 | ||
@@ -351,230 +429,413 @@ GNUNET_CONNECTION_get_address (struct GNUNET_CONNECTION_Handle *sock, | |||
351 | 429 | ||
352 | 430 | ||
353 | /** | 431 | /** |
354 | * Perform a DNS lookup for the hostname associated | 432 | * It is time to re-try connecting. |
355 | * with the current socket, iterating over the address | 433 | * |
356 | * families as specified in the "address_families" array. | 434 | * @param cls the handle for the connection that should be re-tried |
435 | * @param tc unused scheduler taks context | ||
436 | */ | ||
437 | static void | ||
438 | retry_connect_continuation (void *cls, | ||
439 | const struct GNUNET_SCHEDULER_TaskContext *tc); | ||
440 | |||
441 | |||
442 | /** | ||
443 | * This function is called after establishing a connection either has | ||
444 | * succeeded or timed out. Note that it is possible that the attempt | ||
445 | * timed out and that we're immediately retrying. If we are retrying, | ||
446 | * we need to wait again (or timeout); if we succeeded, we need to | ||
447 | * wait for data (or timeout). | ||
357 | * | 448 | * |
358 | * @param sock the socket for which to do the lookup | 449 | * @param cls our connection handle |
450 | * @param tc task context describing why we are here | ||
359 | */ | 451 | */ |
360 | static void | 452 | static void |
361 | try_lookup (struct GNUNET_CONNECTION_Handle *sock) | 453 | receive_again (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); |
362 | { | ||
363 | struct addrinfo hints; | ||
364 | int ec; | ||
365 | 454 | ||
366 | GNUNET_assert (0 < strlen (sock->hostname)); /* sanity check */ | 455 | |
367 | while ( (sock->ai_pos == NULL) && | 456 | /** |
368 | (sock->af_fam_offset > 0) ) | 457 | * Scheduler let us know that the connect task is finished (or was |
369 | { | 458 | * cancelled due to shutdown). Now really clean up. |
370 | if (sock->ai != NULL) | 459 | * |
371 | freeaddrinfo (sock->ai); | 460 | * @param cls our "struct GNUNET_CONNECTION_Handle *" |
372 | memset (&hints, 0, sizeof (hints)); | 461 | * @param tc unused |
373 | hints.ai_family = address_families[--sock->af_fam_offset]; | 462 | */ |
374 | hints.ai_socktype = SOCK_STREAM; | 463 | static void |
375 | #if 0 | 464 | destroy_continuation (void *cls, |
376 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | 465 | const struct GNUNET_SCHEDULER_TaskContext *tc); |
377 | _("`%s' tries to resolve address family %d and hostname `%s:%u'\n"), | 466 | |
378 | "getaddrinfo", | 467 | |
379 | address_families[sock->af_fam_offset], | 468 | |
380 | sock->hostname, | 469 | /** |
381 | sock->port); | 470 | * See if we are now connected. If not, wait longer for |
382 | #endif | 471 | * connect to succeed. If connected, we should be able |
383 | ec = getaddrinfo (sock->hostname, NULL, &hints, &sock->ai); | 472 | * to write now as well, unless we timed out. |
384 | #if 0 | 473 | * |
385 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | 474 | * @param cls our connection handle |
386 | _("`%s' returned from resolving address family %d and hostname `%s:%u'\n"), | 475 | * @param tc task context describing why we are here |
387 | "getaddrinfo", | 476 | */ |
388 | address_families[sock->af_fam_offset], | 477 | static void |
389 | sock->hostname, | 478 | transmit_ready (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); |
390 | sock->port); | 479 | |
480 | |||
481 | /** | ||
482 | * We've failed for good to establish a connection. | ||
483 | * | ||
484 | * @param h the connection we tried to establish | ||
485 | */ | ||
486 | static void | ||
487 | connect_fail_continuation (struct GNUNET_CONNECTION_Handle *h) | ||
488 | { | ||
489 | #if DEBUG_CONNECTION | ||
490 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
491 | "Failed to establish TCP connection to `%s:%u', no further addresses to try.\n", | ||
492 | h->hostname, | ||
493 | h->port); | ||
391 | #endif | 494 | #endif |
392 | if (0 != ec) | 495 | /* connect failed / timed out */ |
393 | { | 496 | GNUNET_break (h->ap_head == NULL); |
394 | GNUNET_log (GNUNET_ERROR_TYPE_INFO | GNUNET_ERROR_TYPE_BULK, | 497 | GNUNET_break (h->ap_tail == NULL); |
395 | _("`%s' failed for address family %d and hostname `%s:%u': %s\n"), | 498 | GNUNET_break (h->dns_active == GNUNET_NO); |
396 | "getaddrinfo", | 499 | GNUNET_break (h->sock == NULL); |
397 | address_families[sock->af_fam_offset], | 500 | |
398 | sock->hostname, | 501 | /* FIXME: trigger delayed reconnect attempt... */ |
399 | sock->port, | 502 | /* trigger jobs that used to wait on "connect_task" */ |
400 | gai_strerror (ec)); | 503 | if (0 != (h->ccs & CC_RECEIVE_AGAIN)) |
401 | sock->ai = NULL; | 504 | { |
402 | } | 505 | h->ccs -= CC_RECEIVE_AGAIN; |
403 | sock->ai_pos = sock->ai; | 506 | h->read_task = GNUNET_SCHEDULER_add_after (h->sched, |
507 | GNUNET_NO, | ||
508 | GNUNET_SCHEDULER_PRIORITY_KEEP, | ||
509 | GNUNET_SCHEDULER_NO_TASK, | ||
510 | &receive_again, | ||
511 | h); | ||
512 | } | ||
513 | if (0 != (h->ccs & CC_TRANSMIT_READY)) | ||
514 | { | ||
515 | h->ccs -= CC_TRANSMIT_READY; | ||
516 | h->write_task = GNUNET_SCHEDULER_add_after (h->sched, | ||
517 | GNUNET_NO, | ||
518 | GNUNET_SCHEDULER_PRIORITY_KEEP, | ||
519 | GNUNET_SCHEDULER_NO_TASK, | ||
520 | &transmit_ready, | ||
521 | h); | ||
522 | } | ||
523 | if (0 != (h->ccs & CC_DESTROY_CONTINUATION)) | ||
524 | { | ||
525 | h->ccs -= CC_DESTROY_CONTINUATION; | ||
526 | GNUNET_SCHEDULER_add_continuation (h->sched, | ||
527 | GNUNET_NO, | ||
528 | &destroy_continuation, | ||
529 | h, | ||
530 | GNUNET_SCHEDULER_REASON_TIMEOUT); | ||
404 | } | 531 | } |
405 | } | 532 | } |
406 | 533 | ||
407 | 534 | ||
408 | /** | 535 | /** |
409 | * Initiate asynchronous TCP connect request. | 536 | * We've succeeded in establishing a connection. |
410 | * | 537 | * |
411 | * @param sock what socket to connect | 538 | * @param h the connection we tried to establish |
412 | * @return GNUNET_SYSERR error (no more addresses to try) | ||
413 | */ | 539 | */ |
414 | static int | 540 | static void |
415 | try_connect (struct GNUNET_CONNECTION_Handle *sock) | 541 | connect_success_continuation (struct GNUNET_CONNECTION_Handle *h) |
416 | { | 542 | { |
417 | struct GNUNET_NETWORK_Handle *s; | 543 | #if DEBUG_CONNECTION |
418 | 544 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | |
419 | if (sock->addr != NULL) | 545 | "Connection to `%s' succeeded!\n", |
546 | GNUNET_a2s(h->addr, h->addrlen)); | ||
547 | #endif | ||
548 | /* trigger jobs that waited for the connection */ | ||
549 | if (0 != (h->ccs & CC_RECEIVE_AGAIN)) | ||
420 | { | 550 | { |
421 | GNUNET_free (sock->addr); | 551 | h->ccs -= CC_RECEIVE_AGAIN; |
422 | sock->addr = NULL; | 552 | h->read_task = GNUNET_SCHEDULER_add_after (h->sched, |
423 | sock->addrlen = 0; | 553 | GNUNET_NO, |
554 | GNUNET_SCHEDULER_PRIORITY_KEEP, | ||
555 | GNUNET_SCHEDULER_NO_TASK, | ||
556 | &receive_again, | ||
557 | h); | ||
424 | } | 558 | } |
425 | while (1) | 559 | if (0 != (h->ccs & CC_TRANSMIT_READY)) |
426 | { | 560 | { |
427 | if (sock->ai_pos == NULL) | 561 | h->ccs -= CC_TRANSMIT_READY; |
428 | try_lookup (sock); | 562 | h->write_task = |
429 | if (sock->ai_pos == NULL) | 563 | GNUNET_SCHEDULER_add_write_net (h->sched, |
430 | { | 564 | GNUNET_NO, |
431 | /* no more addresses to try, fatal! */ | 565 | GNUNET_SCHEDULER_PRIORITY_KEEP, |
432 | return GNUNET_SYSERR; | 566 | GNUNET_SCHEDULER_NO_TASK, |
433 | } | 567 | GNUNET_TIME_absolute_get_remaining (h->nth.transmit_timeout), |
434 | switch (sock->ai_pos->ai_family) | 568 | h->sock, &transmit_ready, h); |
435 | { | 569 | } |
436 | case AF_INET: | 570 | if (0 != (h->ccs & CC_DESTROY_CONTINUATION)) |
437 | ((struct sockaddr_in *) sock->ai_pos->ai_addr)->sin_port = | 571 | { |
438 | htons (sock->port); | 572 | h->ccs -= CC_DESTROY_CONTINUATION; |
439 | break; | 573 | GNUNET_SCHEDULER_add_continuation (h->sched, |
440 | case AF_INET6: | 574 | GNUNET_NO, |
441 | ((struct sockaddr_in6 *) sock->ai_pos->ai_addr)->sin6_port = | 575 | &destroy_continuation, |
442 | htons (sock->port); | 576 | h, |
443 | break; | 577 | GNUNET_SCHEDULER_REASON_PREREQ_DONE); |
444 | default: | ||
445 | sock->ai_pos = sock->ai_pos->ai_next; | ||
446 | continue; | ||
447 | } | ||
448 | s = GNUNET_NETWORK_socket_socket (sock->ai_pos->ai_family, SOCK_STREAM, 0); | ||
449 | if (s == NULL) | ||
450 | { | ||
451 | /* maybe unsupported address family, try next */ | ||
452 | GNUNET_log_strerror (GNUNET_ERROR_TYPE_INFO, "socket"); | ||
453 | sock->ai_pos = sock->ai_pos->ai_next; | ||
454 | continue; | ||
455 | } | ||
456 | #ifndef MINGW | ||
457 | if (GNUNET_OK != GNUNET_NETWORK_socket_set_inheritable (s)) | ||
458 | GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
459 | "GNUNET_NETWORK_socket_set_inheritable"); | ||
460 | #endif | ||
461 | if (GNUNET_SYSERR == GNUNET_NETWORK_socket_set_blocking (s, GNUNET_NO)) | ||
462 | { | ||
463 | /* we'll treat this one as fatal */ | ||
464 | GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (s)); | ||
465 | return GNUNET_SYSERR; | ||
466 | } | ||
467 | #if DEBUG_CONNECTION | ||
468 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
469 | _("Trying to connect to `%s'\n"), | ||
470 | GNUNET_a2s(sock->ai_pos->ai_addr, | ||
471 | sock->ai_pos->ai_addrlen)); | ||
472 | #endif | ||
473 | if ((GNUNET_OK != GNUNET_NETWORK_socket_connect (s, | ||
474 | sock->ai_pos->ai_addr, | ||
475 | sock->ai_pos->ai_addrlen)) && (errno != EINPROGRESS)) | ||
476 | { | ||
477 | /* maybe refused / unsupported address, try next */ | ||
478 | GNUNET_log_strerror (GNUNET_ERROR_TYPE_INFO, "connect"); | ||
479 | GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (s)); | ||
480 | sock->ai_pos = sock->ai_pos->ai_next; | ||
481 | continue; | ||
482 | } | ||
483 | break; | ||
484 | } | 578 | } |
485 | /* got one! copy address information! */ | ||
486 | sock->addrlen = sock->ai_pos->ai_addrlen; | ||
487 | sock->addr = GNUNET_malloc (sock->addrlen); | ||
488 | memcpy (sock->addr, sock->ai_pos->ai_addr, sock->addrlen); | ||
489 | sock->ai_pos = sock->ai_pos->ai_next; | ||
490 | sock->sock = s; | ||
491 | return GNUNET_OK; | ||
492 | } | 579 | } |
493 | 580 | ||
494 | 581 | ||
495 | /** | 582 | /** |
496 | * Scheduler let us know that we're either ready to | 583 | * Scheduler let us know that we're either ready to write on the |
497 | * write on the socket OR connect timed out. Do the | 584 | * socket OR connect timed out. Do the right thing. |
498 | * right thing. | 585 | * |
586 | * @param ap the address we were probing | ||
587 | * @param tc success or failure info about the connect attempt. | ||
499 | */ | 588 | */ |
500 | static void | 589 | static void |
501 | connect_continuation (void *cls, | 590 | connect_probe_continuation (void *cls, |
502 | const struct GNUNET_SCHEDULER_TaskContext *tc) | 591 | const struct GNUNET_SCHEDULER_TaskContext *tc) |
503 | { | 592 | { |
504 | struct GNUNET_CONNECTION_Handle *sock = cls; | 593 | struct AddressProbe *ap = cls; |
505 | struct GNUNET_TIME_Relative delay; | 594 | struct GNUNET_CONNECTION_Handle *h = ap->h; |
595 | struct AddressProbe *pos; | ||
596 | int error; | ||
506 | unsigned int len; | 597 | unsigned int len; |
507 | int error; | ||
508 | 598 | ||
509 | GNUNET_assert (0 < strlen (sock->hostname)); /* sanity check */ | 599 | GNUNET_CONTAINER_DLL_remove (h->ap_head, h->ap_tail, ap); |
510 | /* nobody needs to wait for us anymore... */ | 600 | |
511 | sock->connect_task = GNUNET_SCHEDULER_NO_TASK; | ||
512 | /* Note: write-ready does NOT mean connect succeeded, | ||
513 | we need to use getsockopt to be sure */ | ||
514 | len = sizeof (error); | 601 | len = sizeof (error); |
515 | errno = 0; | 602 | errno = 0; |
516 | error = 0; | 603 | error = 0; |
517 | if ((0 == (tc->reason & GNUNET_SCHEDULER_REASON_WRITE_READY)) || | 604 | if ( (0 == (tc->reason & GNUNET_SCHEDULER_REASON_WRITE_READY)) || |
518 | (GNUNET_OK != GNUNET_NETWORK_socket_getsockopt (sock->sock, SOL_SOCKET, SO_ERROR, &error, &len)) || | 605 | (GNUNET_OK != GNUNET_NETWORK_socket_getsockopt (ap->sock, SOL_SOCKET, SO_ERROR, &error, &len)) || |
519 | (error != 0) || (errno != 0)) | 606 | (error != 0) || (errno != 0) ) |
607 | { | ||
608 | GNUNET_NETWORK_socket_close (ap->sock); | ||
609 | GNUNET_free (ap); | ||
610 | if ( (NULL == h->ap_head) && | ||
611 | (h->dns_active == GNUNET_NO) ) | ||
612 | connect_fail_continuation (h); | ||
613 | return; | ||
614 | } | ||
615 | h->sock = ap->sock; | ||
616 | GNUNET_assert (h->addr == NULL); | ||
617 | h->addr = GNUNET_malloc (ap->addrlen); | ||
618 | memcpy (h->addr, ap->addr, ap->addrlen); | ||
619 | h->addrlen = ap->addrlen; | ||
620 | GNUNET_free (ap); | ||
621 | /* cancel all other attempts */ | ||
622 | while (NULL != (pos = h->ap_head)) | ||
623 | { | ||
624 | GNUNET_NETWORK_socket_close (pos->sock); | ||
625 | GNUNET_SCHEDULER_cancel (h->sched, pos->task); | ||
626 | GNUNET_CONTAINER_DLL_remove (h->ap_head, h->ap_tail, pos); | ||
627 | GNUNET_free (pos); | ||
628 | } | ||
629 | connect_success_continuation (h); | ||
630 | } | ||
631 | |||
632 | |||
633 | /** | ||
634 | * Scheduler let us know that the connect task is finished (or was | ||
635 | * cancelled due to shutdown). Now really clean up. | ||
636 | * | ||
637 | * @param cls our "struct GNUNET_CONNECTION_Handle *" | ||
638 | * @param tc unused | ||
639 | */ | ||
640 | static void | ||
641 | destroy_continuation (void *cls, | ||
642 | const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
643 | { | ||
644 | struct GNUNET_CONNECTION_Handle *sock = cls; | ||
645 | GNUNET_CONNECTION_TransmitReadyNotify notify; | ||
646 | |||
647 | if (sock->dns_active == GNUNET_YES) | ||
648 | { | ||
649 | sock->dns_active = GNUNET_SYSERR; | ||
650 | return; | ||
651 | } | ||
652 | if (0 != (sock->ccs & CC_TRANSMIT_READY)) | ||
653 | { | ||
654 | sock->ccs |= CC_DESTROY_CONTINUATION; | ||
655 | return; | ||
656 | } | ||
657 | if (sock->write_task != GNUNET_SCHEDULER_NO_TASK) | ||
658 | { | ||
659 | GNUNET_SCHEDULER_add_after (sock->sched, | ||
660 | GNUNET_YES, | ||
661 | GNUNET_SCHEDULER_PRIORITY_KEEP, | ||
662 | sock->write_task, | ||
663 | &destroy_continuation, sock); | ||
664 | return; | ||
665 | } | ||
666 | if (sock->sock != NULL) | ||
520 | { | 667 | { |
521 | #if DEBUG_CONNECTION | 668 | #if DEBUG_CONNECTION |
522 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 669 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Shutting down socket.\n"); |
523 | "Failed to establish TCP connection to `%s:%u': %s\n", | ||
524 | GNUNET_a2s(sock->addr, sock->addrlen), | ||
525 | STRERROR (GNUNET_MAX (error, errno))); | ||
526 | #endif | 670 | #endif |
527 | /* connect failed / timed out */ | 671 | GNUNET_NETWORK_socket_shutdown (sock->sock, SHUT_RDWR); |
528 | GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock->sock)); | 672 | } |
529 | sock->sock = NULL; | 673 | if (0 != (sock->ccs & CC_RECEIVE_AGAIN)) |
530 | if (GNUNET_SYSERR == try_connect (sock)) | 674 | { |
675 | sock->ccs |= CC_DESTROY_CONTINUATION; | ||
676 | return; | ||
677 | } | ||
678 | if (sock->read_task != GNUNET_SCHEDULER_NO_TASK) | ||
679 | { | ||
680 | GNUNET_SCHEDULER_add_after (sock->sched, | ||
681 | GNUNET_YES, | ||
682 | GNUNET_SCHEDULER_PRIORITY_KEEP, | ||
683 | sock->read_task, | ||
684 | &destroy_continuation, sock); | ||
685 | return; | ||
686 | } | ||
687 | if (NULL != (notify = sock->nth.notify_ready)) | ||
688 | { | ||
689 | sock->nth.notify_ready = NULL; | ||
690 | notify (sock->nth.notify_ready_cls, 0, NULL); | ||
691 | if (sock->nth.timeout_task != GNUNET_SCHEDULER_NO_TASK) | ||
531 | { | 692 | { |
532 | /* failed for good */ | 693 | GNUNET_SCHEDULER_cancel (sock->sched, sock->nth.timeout_task); |
533 | #if DEBUG_CONNECTION | 694 | sock->nth.timeout_task = GNUNET_SCHEDULER_NO_TASK; |
534 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
535 | "Failed to establish TCP connection to `%s:%u', no further addresses to try.\n", | ||
536 | sock->hostname, | ||
537 | sock->port); | ||
538 | #endif | ||
539 | /* connect failed / timed out */ | ||
540 | GNUNET_break (sock->ai_pos == NULL); | ||
541 | freeaddrinfo (sock->ai); | ||
542 | sock->ai = NULL; | ||
543 | return; | ||
544 | } | 695 | } |
545 | delay = GNUNET_CONNECTION_CONNECT_RETRY_TIMEOUT; | 696 | } |
546 | if (sock->nth.notify_ready != NULL) | 697 | if (sock->sock != NULL) |
547 | delay = GNUNET_TIME_relative_min (delay, | 698 | GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock->sock)); |
548 | GNUNET_TIME_absolute_get_remaining (sock->nth.transmit_timeout)); | 699 | GNUNET_free_non_null (sock->addr); |
549 | if (sock->receiver != NULL) | 700 | GNUNET_free_non_null (sock->hostname); |
550 | delay = GNUNET_TIME_relative_min (delay, | 701 | GNUNET_free (sock); |
551 | GNUNET_TIME_absolute_get_remaining (sock->receive_timeout)); | 702 | } |
552 | delay.value /= (1 + sock->af_fam_offset); | 703 | |
553 | #if DEBUG_CONNECTION | 704 | |
554 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 705 | /** |
555 | "Will try to connect to `%s' for %llu ms\n", | 706 | * Try to establish a socket connection given the specified address. |
556 | GNUNET_a2s (sock->addr, | 707 | * This function is called by the resolver once we have a DNS reply. |
557 | sock->addrlen), | 708 | * |
558 | delay.value); | 709 | * @param cls our "struct GNUNET_CONNECTION_Handle *" |
559 | #endif | 710 | * @param addr address to try, NULL for "last call" |
560 | sock->connect_task = GNUNET_SCHEDULER_add_write_net (tc->sched, GNUNET_NO, /* abort on shutdown */ | 711 | * @param addrlen length of addr |
561 | GNUNET_SCHEDULER_PRIORITY_KEEP, | 712 | */ |
562 | GNUNET_SCHEDULER_NO_TASK, | 713 | static void |
563 | delay, | 714 | try_connect_using_address (void *cls, |
564 | sock->sock, | 715 | const struct sockaddr * addr, |
565 | &connect_continuation, | 716 | socklen_t addrlen) |
566 | sock); | 717 | { |
718 | struct GNUNET_CONNECTION_Handle *h = cls; | ||
719 | struct AddressProbe *ap; | ||
720 | struct GNUNET_TIME_Relative delay; | ||
721 | |||
722 | if (addr == NULL) | ||
723 | { | ||
724 | if (h->dns_active == GNUNET_SYSERR) | ||
725 | { | ||
726 | h->dns_active = GNUNET_NO; | ||
727 | GNUNET_SCHEDULER_add_after (h->sched, | ||
728 | GNUNET_YES, | ||
729 | GNUNET_SCHEDULER_PRIORITY_KEEP, | ||
730 | h->read_task, | ||
731 | &destroy_continuation, | ||
732 | h); | ||
733 | return; | ||
734 | } | ||
735 | h->dns_active = GNUNET_NO; | ||
736 | if (NULL == h->ap_head) | ||
737 | connect_fail_continuation (h); | ||
567 | return; | 738 | return; |
568 | } | 739 | } |
569 | /* connect succeeded! clean up "ai" */ | 740 | if (h->sock != NULL) |
741 | return; /* already connected */ | ||
742 | if (h->dns_active == GNUNET_SYSERR) | ||
743 | return; /* already destroyed */ | ||
744 | /* try to connect */ | ||
745 | ap = GNUNET_malloc (sizeof (struct AddressProbe) + addrlen); | ||
746 | ap->addr = (const struct sockaddr*) &ap[1]; | ||
747 | memcpy (&ap[1], addr, addrlen); | ||
748 | ap->addrlen = addrlen; | ||
749 | ap->h = h; | ||
750 | |||
751 | switch (ap->addr->sa_family) | ||
752 | { | ||
753 | case AF_INET: | ||
754 | ((struct sockaddr_in *) ap->addr)->sin_port = htons (h->port); | ||
755 | break; | ||
756 | case AF_INET6: | ||
757 | ((struct sockaddr_in6 *) ap->addr)->sin6_port = htons (h->port); | ||
758 | break; | ||
759 | default: | ||
760 | GNUNET_break (0); | ||
761 | GNUNET_free (ap); | ||
762 | return; /* not supported by us */ | ||
763 | } | ||
764 | ap->sock = GNUNET_NETWORK_socket_socket (ap->addr->sa_family, SOCK_STREAM, 0); | ||
765 | if (ap->sock == NULL) | ||
766 | { | ||
767 | GNUNET_free (ap); | ||
768 | return; /* not supported by OS */ | ||
769 | } | ||
770 | #ifndef MINGW | ||
771 | if (GNUNET_OK != GNUNET_NETWORK_socket_set_inheritable (ap->sock)) | ||
772 | GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
773 | "GNUNET_NETWORK_socket_set_inheritable"); | ||
774 | #endif | ||
775 | if (GNUNET_SYSERR == GNUNET_NETWORK_socket_set_blocking (ap->sock, GNUNET_NO)) | ||
776 | { | ||
777 | /* we might want to treat this one as fatal... */ | ||
778 | GNUNET_break (0); | ||
779 | GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (ap->sock)); | ||
780 | GNUNET_free (ap); | ||
781 | return; | ||
782 | } | ||
570 | #if DEBUG_CONNECTION | 783 | #if DEBUG_CONNECTION |
571 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 784 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, |
572 | "Connection to `%s' succeeded!\n", | 785 | _("Trying to connect to `%s'\n"), |
573 | GNUNET_a2s(sock->addr, sock->addrlen)); | 786 | GNUNET_a2s(ap->addr, |
787 | ap->addrlen)); | ||
574 | #endif | 788 | #endif |
575 | freeaddrinfo (sock->ai); | 789 | if ( (GNUNET_OK != GNUNET_NETWORK_socket_connect (ap->sock, |
576 | sock->ai_pos = NULL; | 790 | ap->addr, |
577 | sock->ai = NULL; | 791 | ap->addrlen)) && |
792 | (errno != EINPROGRESS)) | ||
793 | { | ||
794 | /* maybe refused / unsupported address, try next */ | ||
795 | GNUNET_log_strerror (GNUNET_ERROR_TYPE_INFO, "connect"); | ||
796 | GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (ap->sock)); | ||
797 | GNUNET_free (ap); | ||
798 | return; | ||
799 | } | ||
800 | GNUNET_CONTAINER_DLL_insert (h->ap_head, h->ap_tail, ap); | ||
801 | delay = GNUNET_CONNECTION_CONNECT_RETRY_TIMEOUT; | ||
802 | if (h->nth.notify_ready != NULL) | ||
803 | delay = GNUNET_TIME_relative_min (delay, | ||
804 | GNUNET_TIME_absolute_get_remaining (h->nth.transmit_timeout)); | ||
805 | if (h->receiver != NULL) | ||
806 | delay = GNUNET_TIME_relative_min (delay, | ||
807 | GNUNET_TIME_absolute_get_remaining (h->receive_timeout)); | ||
808 | ap->task = GNUNET_SCHEDULER_add_write_net (h->sched, | ||
809 | GNUNET_NO, | ||
810 | GNUNET_SCHEDULER_PRIORITY_KEEP, | ||
811 | GNUNET_SCHEDULER_NO_TASK, | ||
812 | delay, | ||
813 | ap->sock, | ||
814 | &connect_probe_continuation, | ||
815 | ap); | ||
816 | } | ||
817 | |||
818 | |||
819 | /** | ||
820 | * It is time to re-try connecting. | ||
821 | * | ||
822 | * @param cls the handle for the connection that should be re-tried | ||
823 | * @param tc unused scheduler taks context | ||
824 | */ | ||
825 | static void | ||
826 | retry_connect_continuation (void *cls, | ||
827 | const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
828 | { | ||
829 | struct GNUNET_CONNECTION_Handle *sock = cls; | ||
830 | |||
831 | sock->dns_active = GNUNET_YES; | ||
832 | GNUNET_RESOLVER_ip_get (sock->sched, | ||
833 | sock->cfg, | ||
834 | sock->hostname, | ||
835 | AF_UNSPEC, | ||
836 | GNUNET_CONNECTION_CONNECT_RETRY_TIMEOUT, | ||
837 | &try_connect_using_address, | ||
838 | sock); | ||
578 | } | 839 | } |
579 | 840 | ||
580 | 841 | ||
@@ -584,6 +845,7 @@ connect_continuation (void *cls, | |||
584 | * yet been established. This function only creates TCP connections. | 845 | * yet been established. This function only creates TCP connections. |
585 | * | 846 | * |
586 | * @param sched scheduler to use | 847 | * @param sched scheduler to use |
848 | * @param cfg configuration to use | ||
587 | * @param hostname name of the host to connect to | 849 | * @param hostname name of the host to connect to |
588 | * @param port port to connect to | 850 | * @param port port to connect to |
589 | * @param maxbuf maximum write buffer size for the socket (use | 851 | * @param maxbuf maximum write buffer size for the socket (use |
@@ -591,37 +853,23 @@ connect_continuation (void *cls, | |||
591 | * @return the socket handle | 853 | * @return the socket handle |
592 | */ | 854 | */ |
593 | struct GNUNET_CONNECTION_Handle * | 855 | struct GNUNET_CONNECTION_Handle * |
594 | GNUNET_CONNECTION_create_from_connect (struct GNUNET_SCHEDULER_Handle | 856 | GNUNET_CONNECTION_create_from_connect (struct GNUNET_SCHEDULER_Handle *sched, |
595 | *sched, const char *hostname, | 857 | const struct GNUNET_CONFIGURATION_Handle *cfg, |
596 | uint16_t port, size_t maxbuf) | 858 | const char *hostname, |
859 | uint16_t port, size_t maxbuf) | ||
597 | { | 860 | { |
598 | struct GNUNET_CONNECTION_Handle *ret; | 861 | struct GNUNET_CONNECTION_Handle *ret; |
599 | 862 | ||
600 | GNUNET_assert (0 < strlen (hostname)); /* sanity check */ | 863 | GNUNET_assert (0 < strlen (hostname)); /* sanity check */ |
601 | ret = GNUNET_malloc (sizeof (struct GNUNET_CONNECTION_Handle) + maxbuf); | 864 | ret = GNUNET_malloc (sizeof (struct GNUNET_CONNECTION_Handle) + maxbuf); |
602 | ret->sock = NULL; | 865 | ret->cfg = cfg; |
603 | ret->sched = sched; | 866 | ret->sched = sched; |
604 | ret->write_buffer = (char *) &ret[1]; | 867 | ret->write_buffer = (char *) &ret[1]; |
605 | ret->write_buffer_size = maxbuf; | 868 | ret->write_buffer_size = maxbuf; |
606 | ret->port = port; | 869 | ret->port = port; |
607 | ret->af_fam_offset = sizeof (address_families) / sizeof(address_families[0]); | ||
608 | ret->hostname = GNUNET_strdup (hostname); | 870 | ret->hostname = GNUNET_strdup (hostname); |
609 | if (GNUNET_SYSERR == try_connect (ret)) | 871 | retry_connect_continuation (ret, NULL); |
610 | { | ||
611 | if (NULL != ret->ai) | ||
612 | freeaddrinfo (ret->ai); | ||
613 | GNUNET_free (ret->hostname); | ||
614 | GNUNET_free (ret); | ||
615 | return NULL; | ||
616 | } | ||
617 | ret->connect_task = GNUNET_SCHEDULER_add_write_net (sched, GNUNET_NO, /* abort on shutdown */ | ||
618 | GNUNET_SCHEDULER_PRIORITY_KEEP, | ||
619 | GNUNET_SCHEDULER_NO_TASK, | ||
620 | GNUNET_CONNECTION_CONNECT_RETRY_TIMEOUT, | ||
621 | ret->sock, | ||
622 | &connect_continuation, ret); | ||
623 | return ret; | 872 | return ret; |
624 | |||
625 | } | 873 | } |
626 | 874 | ||
627 | 875 | ||
@@ -699,69 +947,14 @@ GNUNET_CONNECTION_create_from_sockaddr (struct GNUNET_SCHEDULER_Handle | |||
699 | int | 947 | int |
700 | GNUNET_CONNECTION_check (struct GNUNET_CONNECTION_Handle *sock) | 948 | GNUNET_CONNECTION_check (struct GNUNET_CONNECTION_Handle *sock) |
701 | { | 949 | { |
702 | if (sock->ai != NULL) | 950 | if ( (sock->ap_head != NULL) || |
951 | (sock->dns_active == GNUNET_YES) ) | ||
703 | return GNUNET_YES; /* still trying to connect */ | 952 | return GNUNET_YES; /* still trying to connect */ |
704 | return (sock->sock == NULL) ? GNUNET_NO : GNUNET_YES; | 953 | return (sock->sock == NULL) ? GNUNET_NO : GNUNET_YES; |
705 | } | 954 | } |
706 | 955 | ||
707 | 956 | ||
708 | /** | 957 | /** |
709 | * Scheduler let us know that the connect task is finished (or was | ||
710 | * cancelled due to shutdown). Now really clean up. | ||
711 | */ | ||
712 | static void | ||
713 | destroy_continuation (void *cls, | ||
714 | const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
715 | { | ||
716 | struct GNUNET_CONNECTION_Handle *sock = cls; | ||
717 | GNUNET_CONNECTION_TransmitReadyNotify notify; | ||
718 | |||
719 | if (sock->write_task != GNUNET_SCHEDULER_NO_TASK) | ||
720 | { | ||
721 | GNUNET_SCHEDULER_add_after (sock->sched, | ||
722 | GNUNET_YES, | ||
723 | GNUNET_SCHEDULER_PRIORITY_KEEP, | ||
724 | sock->write_task, | ||
725 | &destroy_continuation, sock); | ||
726 | return; | ||
727 | } | ||
728 | if (sock->sock != NULL) | ||
729 | { | ||
730 | #if DEBUG_CONNECTION | ||
731 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Shutting down socket.\n"); | ||
732 | #endif | ||
733 | GNUNET_NETWORK_socket_shutdown (sock->sock, SHUT_RDWR); | ||
734 | } | ||
735 | if (sock->read_task != GNUNET_SCHEDULER_NO_TASK) | ||
736 | { | ||
737 | GNUNET_SCHEDULER_add_after (sock->sched, | ||
738 | GNUNET_YES, | ||
739 | GNUNET_SCHEDULER_PRIORITY_KEEP, | ||
740 | sock->read_task, | ||
741 | &destroy_continuation, sock); | ||
742 | return; | ||
743 | } | ||
744 | if (NULL != (notify = sock->nth.notify_ready)) | ||
745 | { | ||
746 | sock->nth.notify_ready = NULL; | ||
747 | notify (sock->nth.notify_ready_cls, 0, NULL); | ||
748 | if (sock->nth.timeout_task != GNUNET_SCHEDULER_NO_TASK) | ||
749 | { | ||
750 | GNUNET_SCHEDULER_cancel (sock->sched, sock->nth.timeout_task); | ||
751 | sock->nth.timeout_task = GNUNET_SCHEDULER_NO_TASK; | ||
752 | } | ||
753 | } | ||
754 | if (sock->sock != NULL) | ||
755 | GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock->sock)); | ||
756 | GNUNET_free_non_null (sock->addr); | ||
757 | if (sock->ai != NULL) | ||
758 | freeaddrinfo (sock->ai); | ||
759 | GNUNET_free_non_null (sock->hostname); | ||
760 | GNUNET_free (sock); | ||
761 | } | ||
762 | |||
763 | |||
764 | /** | ||
765 | * Close the socket and free associated resources. Pending | 958 | * Close the socket and free associated resources. Pending |
766 | * transmissions are simply dropped. A pending receive call will be | 959 | * transmissions are simply dropped. A pending receive call will be |
767 | * called with an error code of "EPIPE". | 960 | * called with an error code of "EPIPE". |
@@ -771,17 +964,22 @@ destroy_continuation (void *cls, | |||
771 | void | 964 | void |
772 | GNUNET_CONNECTION_destroy (struct GNUNET_CONNECTION_Handle *sock) | 965 | GNUNET_CONNECTION_destroy (struct GNUNET_CONNECTION_Handle *sock) |
773 | { | 966 | { |
774 | if (sock->write_buffer_off == 0) | 967 | if ( (sock->write_buffer_off == 0) && |
775 | sock->ai_pos = NULL; /* if we're still trying to connect and have | 968 | (sock->dns_active == GNUNET_YES) ) |
776 | no message pending, stop trying! */ | 969 | { |
970 | sock->dns_active = GNUNET_SYSERR; /* if we're still trying to connect and have | ||
971 | no message pending, stop trying! */ | ||
972 | return; | ||
973 | } | ||
777 | GNUNET_assert (sock->sched != NULL); | 974 | GNUNET_assert (sock->sched != NULL); |
778 | GNUNET_SCHEDULER_add_after (sock->sched, | 975 | GNUNET_SCHEDULER_add_after (sock->sched, |
779 | GNUNET_YES, | 976 | GNUNET_YES, |
780 | GNUNET_SCHEDULER_PRIORITY_KEEP, | 977 | GNUNET_SCHEDULER_PRIORITY_KEEP, |
781 | sock->connect_task, | 978 | GNUNET_SCHEDULER_NO_TASK, |
782 | &destroy_continuation, sock); | 979 | &destroy_continuation, sock); |
783 | } | 980 | } |
784 | 981 | ||
982 | |||
785 | /** | 983 | /** |
786 | * Tell the receiver callback that a timeout was reached. | 984 | * Tell the receiver callback that a timeout was reached. |
787 | */ | 985 | */ |
@@ -891,6 +1089,9 @@ RETRY: | |||
891 | * timed out and that we're immediately retrying. If we are retrying, | 1089 | * timed out and that we're immediately retrying. If we are retrying, |
892 | * we need to wait again (or timeout); if we succeeded, we need to | 1090 | * we need to wait again (or timeout); if we succeeded, we need to |
893 | * wait for data (or timeout). | 1091 | * wait for data (or timeout). |
1092 | * | ||
1093 | * @param cls our connection handle | ||
1094 | * @param tc task context describing why we are here | ||
894 | */ | 1095 | */ |
895 | static void | 1096 | static void |
896 | receive_again (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | 1097 | receive_again (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) |
@@ -899,8 +1100,7 @@ receive_again (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | |||
899 | struct GNUNET_TIME_Absolute now; | 1100 | struct GNUNET_TIME_Absolute now; |
900 | 1101 | ||
901 | sh->read_task = GNUNET_SCHEDULER_NO_TASK; | 1102 | sh->read_task = GNUNET_SCHEDULER_NO_TASK; |
902 | if ((sh->sock == NULL) && | 1103 | if (sh->sock == NULL) |
903 | (sh->connect_task == GNUNET_SCHEDULER_NO_TASK)) | ||
904 | { | 1104 | { |
905 | /* not connected and no longer trying */ | 1105 | /* not connected and no longer trying */ |
906 | #if DEBUG_CONNECTION | 1106 | #if DEBUG_CONNECTION |
@@ -921,25 +1121,17 @@ receive_again (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | |||
921 | signal_timeout (sh); | 1121 | signal_timeout (sh); |
922 | return; | 1122 | return; |
923 | } | 1123 | } |
924 | if (sh->connect_task != GNUNET_SCHEDULER_NO_TASK) | 1124 | GNUNET_assert (sh->sock != NULL); |
925 | { | ||
926 | /* connect was retried */ | ||
927 | sh->read_task = GNUNET_SCHEDULER_add_after (tc->sched, | ||
928 | GNUNET_YES, | ||
929 | GNUNET_SCHEDULER_PRIORITY_KEEP, | ||
930 | sh->connect_task, | ||
931 | &receive_again, sh); | ||
932 | return; | ||
933 | } | ||
934 | /* connect succeeded, wait for data! */ | 1125 | /* connect succeeded, wait for data! */ |
935 | sh->read_task = GNUNET_SCHEDULER_add_read_net (tc->sched, | 1126 | sh->read_task = GNUNET_SCHEDULER_add_read_net (tc->sched, |
936 | GNUNET_YES, | 1127 | GNUNET_YES, |
937 | GNUNET_SCHEDULER_PRIORITY_KEEP, | 1128 | GNUNET_SCHEDULER_PRIORITY_KEEP, |
938 | sh->connect_task, | 1129 | GNUNET_SCHEDULER_NO_TASK, |
939 | GNUNET_TIME_absolute_get_remaining | 1130 | GNUNET_TIME_absolute_get_remaining |
940 | (sh->receive_timeout), | 1131 | (sh->receive_timeout), |
941 | sh->sock, &receive_ready, | 1132 | sh->sock, |
942 | sh); | 1133 | &receive_ready, |
1134 | sh); | ||
943 | } | 1135 | } |
944 | 1136 | ||
945 | 1137 | ||
@@ -956,9 +1148,8 @@ receive_again (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | |||
956 | * @param timeout maximum amount of time to wait (use -1 for "forever") | 1148 | * @param timeout maximum amount of time to wait (use -1 for "forever") |
957 | * @param receiver function to call with received data | 1149 | * @param receiver function to call with received data |
958 | * @param receiver_cls closure for receiver | 1150 | * @param receiver_cls closure for receiver |
959 | * @return scheduler task ID used for receiving, GNUNET_SCHEDULER_NO_TASK on error | ||
960 | */ | 1151 | */ |
961 | GNUNET_SCHEDULER_TaskIdentifier | 1152 | void |
962 | GNUNET_CONNECTION_receive (struct GNUNET_CONNECTION_Handle *sock, | 1153 | GNUNET_CONNECTION_receive (struct GNUNET_CONNECTION_Handle *sock, |
963 | size_t max, | 1154 | size_t max, |
964 | struct GNUNET_TIME_Relative timeout, | 1155 | struct GNUNET_TIME_Relative timeout, |
@@ -967,16 +1158,27 @@ GNUNET_CONNECTION_receive (struct GNUNET_CONNECTION_Handle *sock, | |||
967 | struct GNUNET_SCHEDULER_TaskContext tc; | 1158 | struct GNUNET_SCHEDULER_TaskContext tc; |
968 | 1159 | ||
969 | GNUNET_assert ((sock->read_task == GNUNET_SCHEDULER_NO_TASK) && | 1160 | GNUNET_assert ((sock->read_task == GNUNET_SCHEDULER_NO_TASK) && |
1161 | (0 == (sock->ccs & CC_RECEIVE_AGAIN)) && | ||
970 | (sock->receiver == NULL)); | 1162 | (sock->receiver == NULL)); |
971 | sock->receiver = receiver; | 1163 | sock->receiver = receiver; |
972 | sock->receiver_cls = receiver_cls; | 1164 | sock->receiver_cls = receiver_cls; |
973 | sock->receive_timeout = GNUNET_TIME_relative_to_absolute (timeout); | 1165 | sock->receive_timeout = GNUNET_TIME_relative_to_absolute (timeout); |
974 | sock->max = max; | 1166 | sock->max = max; |
975 | memset (&tc, 0, sizeof (tc)); | 1167 | if (sock->sock != NULL) |
976 | tc.sched = sock->sched; | 1168 | { |
977 | tc.reason = GNUNET_SCHEDULER_REASON_PREREQ_DONE; | 1169 | memset (&tc, 0, sizeof (tc)); |
978 | receive_again (sock, &tc); | 1170 | tc.sched = sock->sched; |
979 | return sock->read_task; | 1171 | tc.reason = GNUNET_SCHEDULER_REASON_PREREQ_DONE; |
1172 | receive_again (sock, &tc); | ||
1173 | return; | ||
1174 | } | ||
1175 | if ( (sock->dns_active != GNUNET_YES) && | ||
1176 | (sock->ap_head == NULL) ) | ||
1177 | { | ||
1178 | receiver (receiver_cls, NULL, 0, NULL, 0, ETIMEDOUT); | ||
1179 | return; | ||
1180 | } | ||
1181 | sock->ccs += CC_RECEIVE_AGAIN; | ||
980 | } | 1182 | } |
981 | 1183 | ||
982 | 1184 | ||
@@ -986,16 +1188,22 @@ GNUNET_CONNECTION_receive (struct GNUNET_CONNECTION_Handle *sock, | |||
986 | * for the cancellation to be valid. | 1188 | * for the cancellation to be valid. |
987 | * | 1189 | * |
988 | * @param sock socket handle | 1190 | * @param sock socket handle |
989 | * @param task task identifier returned from the receive call | 1191 | * @return closure of the original receiver callback closure |
990 | * @return closure of the original receiver callback | ||
991 | */ | 1192 | */ |
992 | void * | 1193 | void * |
993 | GNUNET_CONNECTION_receive_cancel (struct GNUNET_CONNECTION_Handle *sock, | 1194 | GNUNET_CONNECTION_receive_cancel (struct GNUNET_CONNECTION_Handle *sock) |
994 | GNUNET_SCHEDULER_TaskIdentifier task) | ||
995 | { | 1195 | { |
996 | GNUNET_assert (sock->read_task == task); | 1196 | if (sock->read_task != GNUNET_SCHEDULER_NO_TASK) |
997 | GNUNET_assert (sock == GNUNET_SCHEDULER_cancel (sock->sched, task)); | 1197 | { |
998 | sock->read_task = GNUNET_SCHEDULER_NO_TASK; | 1198 | GNUNET_assert (sock == GNUNET_SCHEDULER_cancel (sock->sched, |
1199 | sock->read_task)); | ||
1200 | sock->read_task = GNUNET_SCHEDULER_NO_TASK; | ||
1201 | } | ||
1202 | else | ||
1203 | { | ||
1204 | GNUNET_assert (0 != (sock->ccs & CC_RECEIVE_AGAIN)); | ||
1205 | sock->ccs -= CC_RECEIVE_AGAIN; | ||
1206 | } | ||
999 | sock->receiver = NULL; | 1207 | sock->receiver = NULL; |
1000 | return sock->receiver_cls; | 1208 | return sock->receiver_cls; |
1001 | } | 1209 | } |
@@ -1090,6 +1298,9 @@ transmit_error (struct GNUNET_CONNECTION_Handle *sock) | |||
1090 | * See if we are now connected. If not, wait longer for | 1298 | * See if we are now connected. If not, wait longer for |
1091 | * connect to succeed. If connected, we should be able | 1299 | * connect to succeed. If connected, we should be able |
1092 | * to write now as well, unless we timed out. | 1300 | * to write now as well, unless we timed out. |
1301 | * | ||
1302 | * @param cls our connection handle | ||
1303 | * @param tc task context describing why we are here | ||
1093 | */ | 1304 | */ |
1094 | static void | 1305 | static void |
1095 | transmit_ready (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | 1306 | transmit_ready (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) |
@@ -1100,19 +1311,6 @@ transmit_ready (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | |||
1100 | 1311 | ||
1101 | GNUNET_assert (sock->write_task != GNUNET_SCHEDULER_NO_TASK); | 1312 | GNUNET_assert (sock->write_task != GNUNET_SCHEDULER_NO_TASK); |
1102 | sock->write_task = GNUNET_SCHEDULER_NO_TASK; | 1313 | sock->write_task = GNUNET_SCHEDULER_NO_TASK; |
1103 | if (sock->connect_task != GNUNET_SCHEDULER_NO_TASK) | ||
1104 | { | ||
1105 | /* still waiting for connect */ | ||
1106 | GNUNET_assert (sock->write_task == | ||
1107 | GNUNET_SCHEDULER_NO_TASK); | ||
1108 | sock->write_task = | ||
1109 | GNUNET_SCHEDULER_add_delayed (tc->sched, GNUNET_NO, | ||
1110 | GNUNET_SCHEDULER_PRIORITY_KEEP, | ||
1111 | sock->connect_task, | ||
1112 | GNUNET_TIME_UNIT_ZERO, &transmit_ready, | ||
1113 | sock); | ||
1114 | return; | ||
1115 | } | ||
1116 | if ( (sock->sock == NULL) || | 1314 | if ( (sock->sock == NULL) || |
1117 | ( (0 != (tc->reason & GNUNET_SCHEDULER_REASON_TIMEOUT)) && | 1315 | ( (0 != (tc->reason & GNUNET_SCHEDULER_REASON_TIMEOUT)) && |
1118 | (0 == (tc->reason & GNUNET_SCHEDULER_REASON_PREREQ_DONE)) && | 1316 | (0 == (tc->reason & GNUNET_SCHEDULER_REASON_PREREQ_DONE)) && |
@@ -1225,8 +1423,9 @@ GNUNET_CONNECTION_notify_transmit_ready (struct GNUNET_CONNECTION_Handle | |||
1225 | GNUNET_assert (notify != NULL); | 1423 | GNUNET_assert (notify != NULL); |
1226 | GNUNET_assert (sock->write_buffer_size >= size); | 1424 | GNUNET_assert (sock->write_buffer_size >= size); |
1227 | 1425 | ||
1228 | if ((sock->sock == NULL) && | 1426 | if ( (sock->sock == NULL) && |
1229 | (sock->connect_task == GNUNET_SCHEDULER_NO_TASK)) | 1427 | (sock->ap_head == NULL) && |
1428 | (sock->dns_active != GNUNET_YES) ) | ||
1230 | { | 1429 | { |
1231 | #if DEBUG_CONNECTION | 1430 | #if DEBUG_CONNECTION |
1232 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 1431 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
@@ -1253,21 +1452,16 @@ GNUNET_CONNECTION_notify_transmit_ready (struct GNUNET_CONNECTION_Handle | |||
1253 | sock); | 1452 | sock); |
1254 | if (sock->write_task == GNUNET_SCHEDULER_NO_TASK) | 1453 | if (sock->write_task == GNUNET_SCHEDULER_NO_TASK) |
1255 | { | 1454 | { |
1256 | if (sock->connect_task == GNUNET_SCHEDULER_NO_TASK) | 1455 | if (sock->sock != NULL) |
1257 | sock->write_task = GNUNET_SCHEDULER_add_write_net (sock->sched, | 1456 | sock->write_task = GNUNET_SCHEDULER_add_write_net (sock->sched, |
1258 | GNUNET_NO, | 1457 | GNUNET_NO, |
1259 | GNUNET_SCHEDULER_PRIORITY_KEEP, | 1458 | GNUNET_SCHEDULER_PRIORITY_KEEP, |
1260 | GNUNET_SCHEDULER_NO_TASK, | 1459 | GNUNET_SCHEDULER_NO_TASK, |
1261 | GNUNET_TIME_absolute_get_remaining (sock->nth.transmit_timeout), | 1460 | GNUNET_TIME_absolute_get_remaining (sock->nth.transmit_timeout), |
1262 | sock->sock, | 1461 | sock->sock, |
1263 | &transmit_ready, sock); | 1462 | &transmit_ready, sock); |
1264 | else | 1463 | else |
1265 | sock->write_task = GNUNET_SCHEDULER_add_delayed (sock->sched, | 1464 | sock->ccs |= CC_TRANSMIT_READY; |
1266 | GNUNET_NO, | ||
1267 | GNUNET_SCHEDULER_PRIORITY_KEEP, | ||
1268 | sock->connect_task, | ||
1269 | GNUNET_TIME_UNIT_ZERO, | ||
1270 | &transmit_ready, sock); | ||
1271 | } | 1465 | } |
1272 | return &sock->nth; | 1466 | return &sock->nth; |
1273 | } | 1467 | } |
diff --git a/src/util/gnunet-service-resolver.c b/src/util/gnunet-service-resolver.c new file mode 100644 index 000000000..304f11b7b --- /dev/null +++ b/src/util/gnunet-service-resolver.c | |||
@@ -0,0 +1,492 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | (C) 2007, 2008, 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 | /** | ||
22 | * @file resolver/gnunet-service-resolver.c | ||
23 | * @brief code to do DNS resolution | ||
24 | * @author Christian Grothoff | ||
25 | */ | ||
26 | |||
27 | #include <stdlib.h> | ||
28 | #include "platform.h" | ||
29 | #include "gnunet_disk_lib.h" | ||
30 | #include "gnunet_getopt_lib.h" | ||
31 | #include "gnunet_protocols.h" | ||
32 | #include "gnunet_service_lib.h" | ||
33 | #include "gnunet_statistics_service.h" | ||
34 | #include "gnunet_strings_lib.h" | ||
35 | #include "gnunet_time_lib.h" | ||
36 | #include "resolver.h" | ||
37 | |||
38 | |||
39 | struct IPCache | ||
40 | { | ||
41 | struct IPCache *next; | ||
42 | char *addr; | ||
43 | struct sockaddr *sa; | ||
44 | struct GNUNET_TIME_Absolute last_refresh; | ||
45 | struct GNUNET_TIME_Absolute last_request; | ||
46 | unsigned int salen; | ||
47 | }; | ||
48 | |||
49 | |||
50 | static struct IPCache *head; | ||
51 | |||
52 | |||
53 | |||
54 | |||
55 | #if HAVE_GETNAMEINFO | ||
56 | static void | ||
57 | getnameinfo_resolve (struct IPCache *cache) | ||
58 | { | ||
59 | char hostname[256]; | ||
60 | |||
61 | if (0 == getnameinfo (cache->sa, | ||
62 | cache->salen, | ||
63 | hostname, | ||
64 | sizeof(hostname), | ||
65 | NULL, 0, 0)) | ||
66 | cache->addr = GNUNET_strdup (hostname); | ||
67 | } | ||
68 | #endif | ||
69 | |||
70 | |||
71 | #if HAVE_GETHOSTBYADDR | ||
72 | static void | ||
73 | gethostbyaddr_resolve (struct IPCache *cache) | ||
74 | { | ||
75 | struct hostent *ent; | ||
76 | |||
77 | switch (cache->sa->sa_family) | ||
78 | { | ||
79 | case AF_INET: | ||
80 | ent = gethostbyaddr (&((struct sockaddr_in *) cache->sa)->sin_addr, | ||
81 | sizeof (struct in_addr), AF_INET); | ||
82 | break; | ||
83 | case AF_INET6: | ||
84 | ent = gethostbyaddr (&((struct sockaddr_in6 *) cache->sa)->sin6_addr, | ||
85 | sizeof (struct in6_addr), AF_INET6); | ||
86 | break; | ||
87 | default: | ||
88 | ent = NULL; | ||
89 | } | ||
90 | if (ent != NULL) | ||
91 | cache->addr = GNUNET_strdup (ent->h_name); | ||
92 | } | ||
93 | #endif | ||
94 | |||
95 | |||
96 | static void | ||
97 | cache_resolve (struct IPCache *cache) | ||
98 | { | ||
99 | #if HAVE_GETNAMEINFO | ||
100 | if (cache->addr == NULL) | ||
101 | getnameinfo_resolve (cache); | ||
102 | #endif | ||
103 | #if HAVE_GETHOSTBYADDR | ||
104 | if (cache->addr == NULL) | ||
105 | gethostbyaddr_resolve (cache); | ||
106 | #endif | ||
107 | } | ||
108 | |||
109 | |||
110 | |||
111 | /** | ||
112 | * Get an IP address as a string (works for both IPv4 and IPv6). Note | ||
113 | * that the resolution happens asynchronously and that the first call | ||
114 | * may not immediately result in the FQN (but instead in a | ||
115 | * human-readable IP address). | ||
116 | * | ||
117 | * @param sa should be of type "struct sockaddr*" | ||
118 | */ | ||
119 | static void | ||
120 | get_ip_as_string (struct GNUNET_SERVER_Client *client, | ||
121 | const struct sockaddr *sav, socklen_t salen) | ||
122 | { | ||
123 | struct IPCache *cache; | ||
124 | struct IPCache *prev; | ||
125 | struct GNUNET_TIME_Absolute now; | ||
126 | struct GNUNET_SERVER_TransmitContext *tc; | ||
127 | |||
128 | if (salen < sizeof (struct sockaddr)) | ||
129 | { | ||
130 | GNUNET_break (0); | ||
131 | return; | ||
132 | } | ||
133 | now = GNUNET_TIME_absolute_get (); | ||
134 | cache = head; | ||
135 | prev = NULL; | ||
136 | while ((cache != NULL) && | ||
137 | ((cache->salen != salen) || (0 != memcmp (cache->sa, sav, salen)))) | ||
138 | { | ||
139 | if (GNUNET_TIME_absolute_get_duration (cache->last_request).value < | ||
140 | 60 * 60 * 1000) | ||
141 | { | ||
142 | if (prev != NULL) | ||
143 | { | ||
144 | prev->next = cache->next; | ||
145 | GNUNET_free_non_null (cache->addr); | ||
146 | GNUNET_free (cache->sa); | ||
147 | GNUNET_free (cache); | ||
148 | cache = prev->next; | ||
149 | } | ||
150 | else | ||
151 | { | ||
152 | head = cache->next; | ||
153 | GNUNET_free_non_null (cache->addr); | ||
154 | GNUNET_free (cache->sa); | ||
155 | GNUNET_free (cache); | ||
156 | cache = head; | ||
157 | } | ||
158 | continue; | ||
159 | } | ||
160 | prev = cache; | ||
161 | cache = cache->next; | ||
162 | } | ||
163 | if (cache != NULL) | ||
164 | { | ||
165 | cache->last_request = now; | ||
166 | if (GNUNET_TIME_absolute_get_duration (cache->last_request).value < | ||
167 | 60 * 60 * 1000) | ||
168 | { | ||
169 | GNUNET_free_non_null (cache->addr); | ||
170 | cache->addr = NULL; | ||
171 | cache->salen = 0; | ||
172 | cache_resolve (cache); | ||
173 | } | ||
174 | } | ||
175 | else | ||
176 | { | ||
177 | cache = GNUNET_malloc (sizeof (struct IPCache)); | ||
178 | cache->next = head; | ||
179 | cache->salen = salen; | ||
180 | cache->sa = GNUNET_malloc (salen); | ||
181 | memcpy (cache->sa, sav, salen); | ||
182 | cache->last_request = GNUNET_TIME_absolute_get (); | ||
183 | cache->last_refresh = GNUNET_TIME_absolute_get (); | ||
184 | cache->addr = NULL; | ||
185 | cache_resolve (cache); | ||
186 | head = cache; | ||
187 | } | ||
188 | tc = GNUNET_SERVER_transmit_context_create (client); | ||
189 | if (cache->addr != NULL) | ||
190 | GNUNET_SERVER_transmit_context_append (tc, | ||
191 | cache->addr, | ||
192 | strlen (cache->addr) + 1, | ||
193 | GNUNET_MESSAGE_TYPE_RESOLVER_RESPONSE); | ||
194 | GNUNET_SERVER_transmit_context_append (tc, NULL, 0, | ||
195 | GNUNET_MESSAGE_TYPE_RESOLVER_RESPONSE); | ||
196 | GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL); | ||
197 | } | ||
198 | |||
199 | |||
200 | #if HAVE_GETADDRINFO | ||
201 | static int | ||
202 | getaddrinfo_resolve (struct GNUNET_SERVER_TransmitContext *tc, | ||
203 | const char *hostname, int domain) | ||
204 | { | ||
205 | int s; | ||
206 | struct addrinfo hints; | ||
207 | struct addrinfo *result; | ||
208 | struct addrinfo *pos; | ||
209 | |||
210 | memset (&hints, 0, sizeof (struct addrinfo)); | ||
211 | // FIXME in PlibC | ||
212 | #ifndef MINGW | ||
213 | hints.ai_family = domain; | ||
214 | #else | ||
215 | hints.ai_family = AF_INET; | ||
216 | #endif | ||
217 | hints.ai_socktype = SOCK_STREAM; /* go for TCP */ | ||
218 | |||
219 | if (0 != (s = getaddrinfo (hostname, NULL, &hints, &result))) | ||
220 | { | ||
221 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
222 | _("Could not resolve `%s' (%s): %s\n"), hostname, | ||
223 | (domain == | ||
224 | AF_INET) ? "IPv4" : ((domain == | ||
225 | AF_INET6) ? "IPv6" : "any"), | ||
226 | gai_strerror (s)); | ||
227 | if ((s == EAI_BADFLAGS) || (s == EAI_MEMORY) || | ||
228 | #ifndef MINGW | ||
229 | (s == EAI_SYSTEM) | ||
230 | #else | ||
231 | // FIXME NILS | ||
232 | 1 | ||
233 | #endif | ||
234 | ) | ||
235 | return GNUNET_NO; /* other function may still succeed */ | ||
236 | return GNUNET_SYSERR; | ||
237 | } | ||
238 | if (result == NULL) | ||
239 | return GNUNET_SYSERR; | ||
240 | pos = result; | ||
241 | while (pos != NULL) | ||
242 | { | ||
243 | GNUNET_SERVER_transmit_context_append (tc, | ||
244 | result->ai_addr, | ||
245 | result->ai_addrlen, | ||
246 | GNUNET_MESSAGE_TYPE_RESOLVER_RESPONSE); | ||
247 | pos = pos->ai_next; | ||
248 | } | ||
249 | freeaddrinfo (result); | ||
250 | return GNUNET_OK; | ||
251 | } | ||
252 | #endif | ||
253 | |||
254 | #if HAVE_GETHOSTBYNAME2 | ||
255 | static int | ||
256 | gethostbyname2_resolve (struct GNUNET_SERVER_TransmitContext *tc, | ||
257 | const char *hostname, int domain) | ||
258 | { | ||
259 | struct hostent *hp; | ||
260 | struct sockaddr_in a4; | ||
261 | struct sockaddr_in6 a6; | ||
262 | int ret1; | ||
263 | int ret2; | ||
264 | |||
265 | if (domain == AF_UNSPEC) | ||
266 | { | ||
267 | ret1 = gethostbyname2_resolve (tc, hostname, AF_INET); | ||
268 | ret2 = gethostbyname2_resolve (tc, hostname, AF_INET6); | ||
269 | if ((ret1 == GNUNET_OK) || (ret2 == GNUNET_OK)) | ||
270 | return GNUNET_OK; | ||
271 | if ((ret1 == GNUNET_SYSERR) || (ret2 == GNUNET_SYSERR)) | ||
272 | return GNUNET_SYSERR; | ||
273 | return GNUNET_NO; | ||
274 | } | ||
275 | hp = gethostbyname2 (hostname, domain); | ||
276 | if (hp == NULL) | ||
277 | { | ||
278 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
279 | _("Could not find IP of host `%s': %s\n"), | ||
280 | hostname, hstrerror (h_errno)); | ||
281 | return GNUNET_SYSERR; | ||
282 | } | ||
283 | GNUNET_assert (hp->h_addrtype == domain); | ||
284 | if (domain == AF_INET) | ||
285 | { | ||
286 | GNUNET_assert (hp->h_length == sizeof (struct in_addr)); | ||
287 | memset (&a4, 0, sizeof (a4)); | ||
288 | a4.sin_family = AF_INET; | ||
289 | memcpy (&a4.sin_addr, hp->h_addr_list[0], hp->h_length); | ||
290 | GNUNET_SERVER_transmit_context_append (tc, | ||
291 | &a4, | ||
292 | sizeof (a4), | ||
293 | GNUNET_MESSAGE_TYPE_RESOLVER_RESPONSE); | ||
294 | } | ||
295 | else | ||
296 | { | ||
297 | GNUNET_assert (hp->h_length == sizeof (struct in6_addr)); | ||
298 | memset (&a6, 0, sizeof (a6)); | ||
299 | a6.sin6_family = AF_INET6; | ||
300 | memcpy (&a6.sin6_addr, hp->h_addr_list[0], hp->h_length); | ||
301 | GNUNET_SERVER_transmit_context_append (tc, | ||
302 | &a6, | ||
303 | sizeof (a6), | ||
304 | GNUNET_MESSAGE_TYPE_RESOLVER_RESPONSE); | ||
305 | } | ||
306 | return GNUNET_OK; | ||
307 | } | ||
308 | #endif | ||
309 | |||
310 | #if HAVE_GETHOSTBYNAME | ||
311 | static int | ||
312 | gethostbyname_resolve (struct GNUNET_SERVER_TransmitContext *tc, | ||
313 | const char *hostname) | ||
314 | { | ||
315 | struct hostent *hp; | ||
316 | struct sockaddr_in addr; | ||
317 | |||
318 | hp = GETHOSTBYNAME (hostname); | ||
319 | if (hp == NULL) | ||
320 | { | ||
321 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
322 | _("Could not find IP of host `%s': %s\n"), | ||
323 | hostname, hstrerror (h_errno)); | ||
324 | return GNUNET_SYSERR; | ||
325 | } | ||
326 | if (hp->h_addrtype != AF_INET) | ||
327 | { | ||
328 | GNUNET_break (0); | ||
329 | return GNUNET_SYSERR; | ||
330 | } | ||
331 | GNUNET_assert (hp->h_length == sizeof (struct in_addr)); | ||
332 | memset (&addr, 0, sizeof (addr)); | ||
333 | addr.sin_family = AF_INET; | ||
334 | memcpy (&addr.sin_addr, hp->h_addr_list[0], hp->h_length); | ||
335 | GNUNET_SERVER_transmit_context_append (tc, | ||
336 | &addr, | ||
337 | sizeof (addr), | ||
338 | GNUNET_MESSAGE_TYPE_RESOLVER_RESPONSE); | ||
339 | return GNUNET_OK; | ||
340 | } | ||
341 | #endif | ||
342 | |||
343 | |||
344 | /** | ||
345 | * Convert a string to an IP address. | ||
346 | * | ||
347 | * @param client where to send the IP address | ||
348 | * @param hostname the hostname to resolve | ||
349 | * @param domain AF_INET or AF_INET6; use AF_UNSPEC for "any" | ||
350 | */ | ||
351 | static void | ||
352 | get_ip_from_hostname (struct GNUNET_SERVER_Client *client, | ||
353 | const char *hostname, int domain) | ||
354 | { | ||
355 | int ret; | ||
356 | struct GNUNET_SERVER_TransmitContext *tc; | ||
357 | |||
358 | tc = GNUNET_SERVER_transmit_context_create (client); | ||
359 | ret = GNUNET_NO; | ||
360 | #if HAVE_GETADDRINFO | ||
361 | if (ret == GNUNET_NO) | ||
362 | ret = getaddrinfo_resolve (tc, hostname, domain); | ||
363 | #endif | ||
364 | #if HAVE_GETHOSTBYNAME2 | ||
365 | if (ret == GNUNET_NO) | ||
366 | ret = gethostbyname2_resolve (tc, hostname, domain); | ||
367 | #endif | ||
368 | #if HAVE_GETHOSTBYNAME | ||
369 | if ((ret == GNUNET_NO) && ((domain == AF_UNSPEC) || (domain == PF_INET))) | ||
370 | gethostbyname_resolve (tc, hostname); | ||
371 | #endif | ||
372 | GNUNET_SERVER_transmit_context_append (tc, NULL, 0, | ||
373 | GNUNET_MESSAGE_TYPE_RESOLVER_RESPONSE); | ||
374 | GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL); | ||
375 | } | ||
376 | |||
377 | |||
378 | /** | ||
379 | * Handle GET-message. | ||
380 | * | ||
381 | * @param cls closure | ||
382 | * @param client identification of the client | ||
383 | * @param message the actual message | ||
384 | */ | ||
385 | static void | ||
386 | handle_get (void *cls, | ||
387 | struct GNUNET_SERVER_Client *client, | ||
388 | const struct GNUNET_MessageHeader *message) | ||
389 | { | ||
390 | uint16_t msize; | ||
391 | const struct GNUNET_RESOLVER_GetMessage *msg; | ||
392 | const char *hostname; | ||
393 | uint16_t size; | ||
394 | int direction; | ||
395 | int domain; | ||
396 | |||
397 | msize = ntohs (message->size); | ||
398 | if (msize < sizeof (struct GNUNET_RESOLVER_GetMessage)) | ||
399 | { | ||
400 | GNUNET_break (0); | ||
401 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); | ||
402 | return; | ||
403 | } | ||
404 | msg = (const struct GNUNET_RESOLVER_GetMessage *) message; | ||
405 | size = msize - sizeof (struct GNUNET_RESOLVER_GetMessage); | ||
406 | direction = ntohl (msg->direction); | ||
407 | domain = ntohl (msg->domain); | ||
408 | if (direction == GNUNET_NO) | ||
409 | { | ||
410 | /* IP from hostname */ | ||
411 | hostname = (const char *) &msg[1]; | ||
412 | if (hostname[size - 1] != '\0') | ||
413 | { | ||
414 | GNUNET_break (0); | ||
415 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); | ||
416 | return; | ||
417 | } | ||
418 | #if DEBUG_RESOLVER | ||
419 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
420 | _("Resolver asked to look up `%s'.\n"), hostname); | ||
421 | #endif | ||
422 | get_ip_from_hostname (client, hostname, domain); | ||
423 | } | ||
424 | else | ||
425 | { | ||
426 | #if DEBUG_RESOLVER | ||
427 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
428 | _("Resolver asked to look up IP address.\n")); | ||
429 | #endif | ||
430 | get_ip_as_string (client, (const struct sockaddr *) &msg[1], size); | ||
431 | } | ||
432 | } | ||
433 | |||
434 | |||
435 | /** | ||
436 | * List of handlers for the messages understood by this | ||
437 | * service. | ||
438 | */ | ||
439 | static struct GNUNET_SERVER_MessageHandler handlers[] = { | ||
440 | {&handle_get, NULL, GNUNET_MESSAGE_TYPE_RESOLVER_REQUEST, 0}, | ||
441 | {NULL, NULL, 0, 0} | ||
442 | }; | ||
443 | |||
444 | |||
445 | /** | ||
446 | * Process resolver requests. | ||
447 | * | ||
448 | * @param cls closure | ||
449 | * @param sched scheduler to use | ||
450 | * @param server the initialized server | ||
451 | * @param cfg configuration to use | ||
452 | */ | ||
453 | static void | ||
454 | run (void *cls, | ||
455 | struct GNUNET_SCHEDULER_Handle *sched, | ||
456 | struct GNUNET_SERVER_Handle *server, | ||
457 | const struct GNUNET_CONFIGURATION_Handle *cfg) | ||
458 | { | ||
459 | GNUNET_SERVER_add_handlers (server, handlers); | ||
460 | } | ||
461 | |||
462 | |||
463 | /** | ||
464 | * The main function for the resolver service. | ||
465 | * | ||
466 | * @param argc number of arguments from the command line | ||
467 | * @param argv command line arguments | ||
468 | * @return 0 ok, 1 on error | ||
469 | */ | ||
470 | int | ||
471 | main (int argc, char *const *argv) | ||
472 | { | ||
473 | int ret; | ||
474 | struct IPCache *pos; | ||
475 | |||
476 | ret = (GNUNET_OK == | ||
477 | GNUNET_SERVICE_run (argc, | ||
478 | argv, | ||
479 | "resolver", &run, NULL, NULL, NULL)) ? 0 : 1; | ||
480 | |||
481 | while (head != NULL) | ||
482 | { | ||
483 | pos = head->next; | ||
484 | GNUNET_free_non_null (head->addr); | ||
485 | GNUNET_free (head->sa); | ||
486 | GNUNET_free (head); | ||
487 | head = pos; | ||
488 | } | ||
489 | return ret; | ||
490 | } | ||
491 | |||
492 | /* end of gnunet-service-resolver.c */ | ||
diff --git a/src/util/resolver.h b/src/util/resolver.h new file mode 100644 index 000000000..31637f01d --- /dev/null +++ b/src/util/resolver.h | |||
@@ -0,0 +1,63 @@ | |||
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 | /** | ||
22 | * @author Christian Grothoff | ||
23 | * @file resolver/resolver.h | ||
24 | */ | ||
25 | #ifndef RESOLVER_H | ||
26 | #define RESOLVER_H | ||
27 | |||
28 | #include "gnunet_common.h" | ||
29 | |||
30 | #define DEBUG_RESOLVER GNUNET_NO | ||
31 | |||
32 | /** | ||
33 | * Request for the resolver. Followed by either | ||
34 | * the "struct sockaddr" or the 0-terminated hostname. | ||
35 | * | ||
36 | * The response will be one or more messages of type | ||
37 | * RESOLVER_RESPONSE, each with the message header | ||
38 | * immediately followed by the requested data | ||
39 | * (hostname or struct sockaddr, depending on direction). | ||
40 | * The last RESOLVER_RESPONSE will just be a header | ||
41 | * without any data (used to indicate the end of the list). | ||
42 | */ | ||
43 | struct GNUNET_RESOLVER_GetMessage | ||
44 | { | ||
45 | /** | ||
46 | * Type: GNUNET_MESSAGE_TYPE_STATISTICS_VALUE | ||
47 | */ | ||
48 | struct GNUNET_MessageHeader header; | ||
49 | |||
50 | /** | ||
51 | * GNUNET_YES to get hostname from IP, | ||
52 | * GNUNET_NO to get IP from hostname. | ||
53 | */ | ||
54 | int32_t direction GNUNET_PACKED; | ||
55 | |||
56 | /** | ||
57 | * Domain to use (AF_INET, AF_INET6 or AF_UNSPEC). | ||
58 | */ | ||
59 | int32_t domain GNUNET_PACKED; | ||
60 | |||
61 | }; | ||
62 | |||
63 | #endif | ||
diff --git a/src/util/resolver_api.c b/src/util/resolver_api.c new file mode 100644 index 000000000..dcda3141e --- /dev/null +++ b/src/util/resolver_api.c | |||
@@ -0,0 +1,589 @@ | |||
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 | /** | ||
22 | * @file resolver/resolver_api.c | ||
23 | * @brief resolver for writing a tool | ||
24 | * @author Christian Grothoff | ||
25 | */ | ||
26 | #include "platform.h" | ||
27 | #include "gnunet_getopt_lib.h" | ||
28 | #include "gnunet_client_lib.h" | ||
29 | #include "gnunet_protocols.h" | ||
30 | #include "gnunet_resolver_service.h" | ||
31 | #include "gnunet_server_lib.h" | ||
32 | #include "resolver.h" | ||
33 | |||
34 | |||
35 | /** | ||
36 | * FIXME. | ||
37 | */ | ||
38 | struct GetAddressContext | ||
39 | { | ||
40 | |||
41 | /** | ||
42 | * FIXME. | ||
43 | */ | ||
44 | GNUNET_RESOLVER_AddressCallback callback; | ||
45 | |||
46 | /** | ||
47 | * Closure for "callback". | ||
48 | */ | ||
49 | void *cls; | ||
50 | |||
51 | /** | ||
52 | * FIXME. | ||
53 | */ | ||
54 | struct GNUNET_RESOLVER_GetMessage *msg; | ||
55 | |||
56 | /** | ||
57 | * FIXME. | ||
58 | */ | ||
59 | struct GNUNET_CLIENT_Connection *client; | ||
60 | |||
61 | /** | ||
62 | * FIXME. | ||
63 | */ | ||
64 | struct GNUNET_TIME_Absolute timeout; | ||
65 | }; | ||
66 | |||
67 | |||
68 | /** | ||
69 | * Possible hostnames for "loopback". | ||
70 | */ | ||
71 | static const char *loopback[] = { | ||
72 | "localhost", | ||
73 | "127.0.0.1", | ||
74 | "ip6-localnet", | ||
75 | "::1", | ||
76 | NULL | ||
77 | }; | ||
78 | |||
79 | |||
80 | /** | ||
81 | * Check that the resolver service runs on localhost | ||
82 | * (or equivalent). | ||
83 | */ | ||
84 | static void | ||
85 | check_config (const struct GNUNET_CONFIGURATION_Handle *cfg) | ||
86 | { | ||
87 | char *hostname; | ||
88 | unsigned int i; | ||
89 | |||
90 | if (GNUNET_OK != | ||
91 | GNUNET_CONFIGURATION_get_value_string (cfg, | ||
92 | "resolver", | ||
93 | "HOSTNAME", | ||
94 | &hostname)) | ||
95 | { | ||
96 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
97 | _("Must specify `%s' for `%s' in configuration!\n"), | ||
98 | "HOSTNAME", | ||
99 | "resolver"); | ||
100 | GNUNET_assert (0); | ||
101 | } | ||
102 | i = 0; | ||
103 | while (loopback[i] != NULL) | ||
104 | if (0 == strcmp (loopback[i++], hostname)) | ||
105 | { | ||
106 | GNUNET_free (hostname); | ||
107 | return; | ||
108 | } | ||
109 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
110 | _("Must specify `%s' for `%s' in configuration!\n"), | ||
111 | "localhost", | ||
112 | "resolver"); | ||
113 | GNUNET_free (hostname); | ||
114 | GNUNET_assert (0); | ||
115 | } | ||
116 | |||
117 | |||
118 | /** | ||
119 | * Convert IP address to string without DNS resolution. | ||
120 | */ | ||
121 | static char * | ||
122 | no_resolve (const struct sockaddr *sa, socklen_t salen) | ||
123 | { | ||
124 | char *ret; | ||
125 | char inet4[INET_ADDRSTRLEN]; | ||
126 | char inet6[INET6_ADDRSTRLEN]; | ||
127 | |||
128 | if (salen < sizeof (struct sockaddr)) | ||
129 | return NULL; | ||
130 | switch (sa->sa_family) | ||
131 | { | ||
132 | case AF_INET: | ||
133 | if (salen != sizeof (struct sockaddr_in)) | ||
134 | return NULL; | ||
135 | inet_ntop (AF_INET, | ||
136 | &((struct sockaddr_in *) sa)->sin_addr, | ||
137 | inet4, INET_ADDRSTRLEN); | ||
138 | ret = GNUNET_strdup (inet4); | ||
139 | break; | ||
140 | case AF_INET6: | ||
141 | if (salen != sizeof (struct sockaddr_in6)) | ||
142 | return NULL; | ||
143 | inet_ntop (AF_INET6, | ||
144 | &((struct sockaddr_in6 *) sa)->sin6_addr, | ||
145 | inet6, INET6_ADDRSTRLEN); | ||
146 | ret = GNUNET_strdup (inet6); | ||
147 | break; | ||
148 | default: | ||
149 | ret = NULL; | ||
150 | break; | ||
151 | } | ||
152 | return ret; | ||
153 | } | ||
154 | |||
155 | |||
156 | static void | ||
157 | handle_address_response (void *cls, const struct GNUNET_MessageHeader *msg) | ||
158 | { | ||
159 | struct GetAddressContext *gac = cls; | ||
160 | uint16_t size; | ||
161 | const struct sockaddr *sa; | ||
162 | socklen_t salen; | ||
163 | |||
164 | |||
165 | if (msg == NULL) | ||
166 | { | ||
167 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
168 | _("Timeout trying to resolve hostname.\n")); | ||
169 | gac->callback (gac->cls, NULL, 0); | ||
170 | GNUNET_CLIENT_disconnect (gac->client); | ||
171 | GNUNET_free (gac); | ||
172 | return; | ||
173 | } | ||
174 | if (GNUNET_MESSAGE_TYPE_RESOLVER_RESPONSE != ntohs (msg->type)) | ||
175 | { | ||
176 | GNUNET_break (0); | ||
177 | gac->callback (gac->cls, NULL, 0); | ||
178 | GNUNET_CLIENT_disconnect (gac->client); | ||
179 | GNUNET_free (gac); | ||
180 | return; | ||
181 | } | ||
182 | |||
183 | size = ntohs (msg->size); | ||
184 | if (size == sizeof (struct GNUNET_MessageHeader)) | ||
185 | { | ||
186 | #if DEBUG_RESOLVER | ||
187 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
188 | _("Received end message resolving hostname.\n")); | ||
189 | #endif | ||
190 | gac->callback (gac->cls, NULL, 0); | ||
191 | GNUNET_CLIENT_disconnect (gac->client); | ||
192 | GNUNET_free (gac); | ||
193 | return; | ||
194 | } | ||
195 | sa = (const struct sockaddr *) &msg[1]; | ||
196 | salen = size - sizeof (struct GNUNET_MessageHeader); | ||
197 | if (salen < sizeof (struct sockaddr)) | ||
198 | { | ||
199 | GNUNET_break (0); | ||
200 | gac->callback (gac->cls, NULL, 0); | ||
201 | GNUNET_CLIENT_disconnect (gac->client); | ||
202 | GNUNET_free (gac); | ||
203 | return; | ||
204 | } | ||
205 | #if DEBUG_RESOLVER | ||
206 | { | ||
207 | char *ips = no_resolve (sa, salen); | ||
208 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _("Resolver returns `%s'.\n"), ips); | ||
209 | GNUNET_free (ips); | ||
210 | } | ||
211 | #endif | ||
212 | gac->callback (gac->cls, sa, salen); | ||
213 | GNUNET_CLIENT_receive (gac->client, | ||
214 | &handle_address_response, | ||
215 | gac, | ||
216 | GNUNET_TIME_absolute_get_remaining (gac->timeout)); | ||
217 | } | ||
218 | |||
219 | |||
220 | static size_t | ||
221 | transmit_get_ip (void *cls, size_t size, void *buf) | ||
222 | { | ||
223 | struct GetAddressContext *actx = cls; | ||
224 | uint16_t ms; | ||
225 | |||
226 | if (buf == NULL) | ||
227 | { | ||
228 | /* timeout / error */ | ||
229 | GNUNET_free (actx->msg); | ||
230 | actx->callback (actx->cls, NULL, 0); | ||
231 | GNUNET_CLIENT_disconnect (actx->client); | ||
232 | GNUNET_free (actx); | ||
233 | return 0; | ||
234 | } | ||
235 | ms = ntohs (actx->msg->header.size); | ||
236 | GNUNET_assert (size >= ms); | ||
237 | memcpy (buf, actx->msg, ms); | ||
238 | GNUNET_free (actx->msg); | ||
239 | actx->msg = NULL; | ||
240 | GNUNET_CLIENT_receive (actx->client, | ||
241 | &handle_address_response, | ||
242 | actx, | ||
243 | GNUNET_TIME_absolute_get_remaining (actx->timeout)); | ||
244 | return ms; | ||
245 | } | ||
246 | |||
247 | |||
248 | |||
249 | /** | ||
250 | * Convert a string to one or more IP addresses. | ||
251 | * | ||
252 | * @param sched scheduler to use | ||
253 | * @param cfg configuration to use | ||
254 | * @param hostname the hostname to resolve | ||
255 | * @param domain AF_INET or AF_INET6; use AF_UNSPEC for "any" | ||
256 | * @param callback function to call with addresses | ||
257 | * @param callback_cls closure for callback | ||
258 | * @param timeout how long to try resolving | ||
259 | */ | ||
260 | void | ||
261 | GNUNET_RESOLVER_ip_get (struct GNUNET_SCHEDULER_Handle *sched, | ||
262 | const struct GNUNET_CONFIGURATION_Handle *cfg, | ||
263 | const char *hostname, | ||
264 | int domain, | ||
265 | struct GNUNET_TIME_Relative timeout, | ||
266 | GNUNET_RESOLVER_AddressCallback callback, | ||
267 | void *callback_cls) | ||
268 | { | ||
269 | struct GNUNET_CLIENT_Connection *client; | ||
270 | struct GNUNET_RESOLVER_GetMessage *msg; | ||
271 | struct GetAddressContext *actx; | ||
272 | size_t slen; | ||
273 | unsigned int i; | ||
274 | struct sockaddr_in v4; | ||
275 | struct sockaddr_in6 v6; | ||
276 | |||
277 | check_config (cfg); | ||
278 | i = 0; | ||
279 | while (loopback[i] != NULL) | ||
280 | if (0 == strcmp (loopback[i++], hostname)) | ||
281 | { | ||
282 | memset (&v4, 0, sizeof(v4)); | ||
283 | #if HAVE_SOCKADDR_IN_SIN_LEN | ||
284 | v4.sin_len = sizeof (v4); | ||
285 | #endif | ||
286 | v4.sin_family = AF_INET; | ||
287 | v4.sin_addr.s_addr = htonl (INADDR_LOOPBACK); | ||
288 | |||
289 | memset (&v6, 0, sizeof(v6)); | ||
290 | #if HAVE_SOCKADDR_IN_SIN_LEN | ||
291 | v6.sin6_len = sizeof (v6); | ||
292 | #endif | ||
293 | v6.sin6_family = AF_INET6; | ||
294 | v6.sin6_addr = in6addr_loopback; | ||
295 | |||
296 | switch (domain) | ||
297 | { | ||
298 | case AF_INET: | ||
299 | callback (callback_cls, | ||
300 | (const struct sockaddr*) &v4, | ||
301 | sizeof(v4)); | ||
302 | break; | ||
303 | case AF_INET6: | ||
304 | callback (callback_cls, | ||
305 | (const struct sockaddr*) &v6, | ||
306 | sizeof(v6)); | ||
307 | break; | ||
308 | case AF_UNSPEC: | ||
309 | callback (callback_cls, | ||
310 | (const struct sockaddr*) &v4, | ||
311 | sizeof(v4)); | ||
312 | callback (callback_cls, | ||
313 | (const struct sockaddr*) &v6, | ||
314 | sizeof(v6)); | ||
315 | break; | ||
316 | } | ||
317 | callback (callback_cls, NULL, 0); | ||
318 | return; | ||
319 | } | ||
320 | slen = strlen (hostname) + 1; | ||
321 | if (slen + sizeof (struct GNUNET_RESOLVER_GetMessage) > | ||
322 | GNUNET_SERVER_MAX_MESSAGE_SIZE) | ||
323 | { | ||
324 | GNUNET_break (0); | ||
325 | callback (callback_cls, NULL, 0); | ||
326 | return; | ||
327 | } | ||
328 | client = GNUNET_CLIENT_connect (sched, "resolver", cfg); | ||
329 | if (client == NULL) | ||
330 | { | ||
331 | callback (callback_cls, NULL, 0); | ||
332 | return; | ||
333 | } | ||
334 | msg = GNUNET_malloc (sizeof (struct GNUNET_RESOLVER_GetMessage) + slen); | ||
335 | msg->header.size = | ||
336 | htons (sizeof (struct GNUNET_RESOLVER_GetMessage) + slen); | ||
337 | msg->header.type = htons (GNUNET_MESSAGE_TYPE_RESOLVER_REQUEST); | ||
338 | msg->direction = htonl (GNUNET_NO); | ||
339 | msg->domain = htonl (domain); | ||
340 | memcpy (&msg[1], hostname, slen); | ||
341 | actx = GNUNET_malloc (sizeof (struct GetAddressContext)); | ||
342 | actx->callback = callback; | ||
343 | actx->cls = callback_cls; | ||
344 | actx->client = client; | ||
345 | actx->timeout = GNUNET_TIME_relative_to_absolute (timeout); | ||
346 | actx->msg = msg; | ||
347 | |||
348 | #if DEBUG_RESOLVER | ||
349 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
350 | _("Resolver requests DNS resolution of hostname `%s'.\n"), | ||
351 | hostname); | ||
352 | #endif | ||
353 | if (NULL == | ||
354 | GNUNET_CLIENT_notify_transmit_ready (client, | ||
355 | slen + | ||
356 | sizeof (struct | ||
357 | GNUNET_RESOLVER_GetMessage), | ||
358 | timeout, &transmit_get_ip, actx)) | ||
359 | { | ||
360 | GNUNET_free (msg); | ||
361 | GNUNET_free (actx); | ||
362 | callback (callback_cls, NULL, 0); | ||
363 | GNUNET_CLIENT_disconnect (client); | ||
364 | return; | ||
365 | } | ||
366 | } | ||
367 | |||
368 | |||
369 | struct GetHostnameContext | ||
370 | { | ||
371 | GNUNET_RESOLVER_HostnameCallback callback; | ||
372 | void *cls; | ||
373 | struct GNUNET_RESOLVER_GetMessage *msg; | ||
374 | struct GNUNET_CLIENT_Connection *client; | ||
375 | struct GNUNET_TIME_Absolute timeout; | ||
376 | }; | ||
377 | |||
378 | |||
379 | static void | ||
380 | handle_hostname_response (void *cls, const struct GNUNET_MessageHeader *msg) | ||
381 | { | ||
382 | struct GetHostnameContext *ghc = cls; | ||
383 | uint16_t size; | ||
384 | const char *hostname; | ||
385 | |||
386 | if (msg == NULL) | ||
387 | { | ||
388 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
389 | _("Timeout trying to resolve IP address.\n")); | ||
390 | ghc->callback (ghc->cls, NULL); | ||
391 | GNUNET_CLIENT_disconnect (ghc->client); | ||
392 | GNUNET_free (ghc); | ||
393 | return; | ||
394 | } | ||
395 | size = ntohs (msg->size); | ||
396 | if (size == sizeof (struct GNUNET_MessageHeader)) | ||
397 | { | ||
398 | #if DEBUG_RESOLVER | ||
399 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
400 | _("Received end message resolving IP address.\n")); | ||
401 | #endif | ||
402 | ghc->callback (ghc->cls, NULL); | ||
403 | GNUNET_CLIENT_disconnect (ghc->client); | ||
404 | GNUNET_free (ghc); | ||
405 | return; | ||
406 | } | ||
407 | hostname = (const char *) &msg[1]; | ||
408 | if (hostname[size - sizeof (struct GNUNET_MessageHeader) - 1] != '\0') | ||
409 | { | ||
410 | GNUNET_break (0); | ||
411 | ghc->callback (ghc->cls, NULL); | ||
412 | GNUNET_CLIENT_disconnect (ghc->client); | ||
413 | GNUNET_free (ghc); | ||
414 | return; | ||
415 | } | ||
416 | #if DEBUG_RESOLVER | ||
417 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
418 | _("Resolver returns `%s'.\n"), hostname); | ||
419 | #endif | ||
420 | ghc->callback (ghc->cls, hostname); | ||
421 | GNUNET_CLIENT_receive (ghc->client, | ||
422 | &handle_hostname_response, | ||
423 | ghc, | ||
424 | GNUNET_TIME_absolute_get_remaining (ghc->timeout)); | ||
425 | } | ||
426 | |||
427 | |||
428 | static size_t | ||
429 | transmit_get_hostname (void *cls, size_t size, void *buf) | ||
430 | { | ||
431 | struct GetHostnameContext *hctx = cls; | ||
432 | uint16_t msize; | ||
433 | |||
434 | if (buf == NULL) | ||
435 | { | ||
436 | GNUNET_free (hctx->msg); | ||
437 | hctx->callback (hctx->cls, NULL); | ||
438 | GNUNET_CLIENT_disconnect (hctx->client); | ||
439 | GNUNET_free (hctx); | ||
440 | return 0; | ||
441 | } | ||
442 | msize = ntohs (hctx->msg->header.size); | ||
443 | GNUNET_assert (size >= msize); | ||
444 | memcpy (buf, hctx->msg, msize); | ||
445 | GNUNET_free (hctx->msg); | ||
446 | hctx->msg = NULL; | ||
447 | GNUNET_CLIENT_receive (hctx->client, | ||
448 | &handle_hostname_response, | ||
449 | hctx, | ||
450 | GNUNET_TIME_absolute_get_remaining (hctx->timeout)); | ||
451 | return msize; | ||
452 | } | ||
453 | |||
454 | |||
455 | |||
456 | |||
457 | /** | ||
458 | * Get an IP address as a string. | ||
459 | * | ||
460 | * @param sched scheduler to use | ||
461 | * @param cfg configuration to use | ||
462 | * @param sa host address | ||
463 | * @param salen length of host address | ||
464 | * @param do_resolve use GNUNET_NO to return numeric hostname | ||
465 | * @param timeout how long to try resolving | ||
466 | * @param callback function to call with hostnames | ||
467 | * @param cls closure for callback | ||
468 | */ | ||
469 | void | ||
470 | GNUNET_RESOLVER_hostname_get (struct GNUNET_SCHEDULER_Handle *sched, | ||
471 | const struct GNUNET_CONFIGURATION_Handle *cfg, | ||
472 | const struct sockaddr *sa, | ||
473 | socklen_t salen, | ||
474 | int do_resolve, | ||
475 | struct GNUNET_TIME_Relative timeout, | ||
476 | GNUNET_RESOLVER_HostnameCallback callback, | ||
477 | void *cls) | ||
478 | { | ||
479 | char *result; | ||
480 | struct GNUNET_CLIENT_Connection *client; | ||
481 | struct GNUNET_RESOLVER_GetMessage *msg; | ||
482 | struct GetHostnameContext *hctx; | ||
483 | |||
484 | check_config (cfg); | ||
485 | if (GNUNET_NO == do_resolve) | ||
486 | { | ||
487 | result = no_resolve (sa, salen); | ||
488 | #if DEBUG_RESOLVER | ||
489 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
490 | _("Resolver returns `%s'.\n"), result); | ||
491 | #endif | ||
492 | callback (cls, result); | ||
493 | if (result != NULL) | ||
494 | { | ||
495 | GNUNET_free (result); | ||
496 | callback (cls, NULL); | ||
497 | } | ||
498 | return; | ||
499 | } | ||
500 | if (salen + sizeof (struct GNUNET_RESOLVER_GetMessage) > | ||
501 | GNUNET_SERVER_MAX_MESSAGE_SIZE) | ||
502 | { | ||
503 | GNUNET_break (0); | ||
504 | callback (cls, NULL); | ||
505 | return; | ||
506 | } | ||
507 | client = GNUNET_CLIENT_connect (sched, "resolver", cfg); | ||
508 | if (client == NULL) | ||
509 | { | ||
510 | callback (cls, NULL); | ||
511 | return; | ||
512 | } | ||
513 | msg = GNUNET_malloc (sizeof (struct GNUNET_RESOLVER_GetMessage) + salen); | ||
514 | msg->header.size = | ||
515 | htons (sizeof (struct GNUNET_RESOLVER_GetMessage) + salen); | ||
516 | msg->header.type = htons (GNUNET_MESSAGE_TYPE_RESOLVER_REQUEST); | ||
517 | msg->direction = htonl (GNUNET_YES); | ||
518 | msg->domain = htonl (sa->sa_family); | ||
519 | memcpy (&msg[1], sa, salen); | ||
520 | #if DEBUG_RESOLVER | ||
521 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
522 | _("Resolver requests DNS resolution of IP address.\n")); | ||
523 | #endif | ||
524 | hctx = GNUNET_malloc (sizeof (struct GetHostnameContext)); | ||
525 | hctx->callback = callback; | ||
526 | hctx->cls = cls; | ||
527 | hctx->client = client; | ||
528 | hctx->timeout = GNUNET_TIME_relative_to_absolute (timeout); | ||
529 | hctx->msg = msg; | ||
530 | if (NULL == | ||
531 | GNUNET_CLIENT_notify_transmit_ready (client, | ||
532 | sizeof (struct | ||
533 | GNUNET_RESOLVER_GetMessage) | ||
534 | + salen, timeout, | ||
535 | &transmit_get_hostname, hctx)) | ||
536 | { | ||
537 | GNUNET_free (msg); | ||
538 | callback (cls, NULL); | ||
539 | GNUNET_CLIENT_disconnect (client); | ||
540 | GNUNET_free (hctx); | ||
541 | } | ||
542 | } | ||
543 | |||
544 | /** | ||
545 | * Maximum supported length of hostname | ||
546 | */ | ||
547 | #define MAX_HOSTNAME 1024 | ||
548 | |||
549 | |||
550 | /** | ||
551 | * Resolve our hostname to an IP address. | ||
552 | * | ||
553 | * @param sched scheduler to use | ||
554 | * @param cfg configuration to use | ||
555 | * @param domain AF_INET or AF_INET6; use AF_UNSPEC for "any" | ||
556 | * @param callback function to call with addresses | ||
557 | * @param cls closure for callback | ||
558 | * @param timeout how long to try resolving | ||
559 | */ | ||
560 | void | ||
561 | GNUNET_RESOLVER_hostname_resolve (struct GNUNET_SCHEDULER_Handle *sched, | ||
562 | const struct GNUNET_CONFIGURATION_Handle *cfg, | ||
563 | int domain, | ||
564 | struct GNUNET_TIME_Relative timeout, | ||
565 | GNUNET_RESOLVER_AddressCallback callback, | ||
566 | void *cls) | ||
567 | { | ||
568 | char hostname[MAX_HOSTNAME]; | ||
569 | |||
570 | check_config (cfg); | ||
571 | if (0 != gethostname (hostname, sizeof (hostname) - 1)) | ||
572 | { | ||
573 | GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR | | ||
574 | GNUNET_ERROR_TYPE_BULK, "gethostname"); | ||
575 | callback (cls, NULL, 0); | ||
576 | return; | ||
577 | } | ||
578 | #if DEBUG_RESOLVER | ||
579 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
580 | _("Resolving our hostname `%s'\n"), hostname); | ||
581 | #endif | ||
582 | GNUNET_RESOLVER_ip_get (sched, | ||
583 | cfg, hostname, domain, timeout, callback, cls); | ||
584 | } | ||
585 | |||
586 | |||
587 | |||
588 | |||
589 | /* end of resolver_api.c */ | ||
diff --git a/src/util/server.c b/src/util/server.c index 086c94996..303c370db 100644 --- a/src/util/server.c +++ b/src/util/server.c | |||
@@ -223,12 +223,6 @@ struct GNUNET_SERVER_Client | |||
223 | struct GNUNET_TIME_Absolute last_activity; | 223 | struct GNUNET_TIME_Absolute last_activity; |
224 | 224 | ||
225 | /** | 225 | /** |
226 | * Current task identifier for the receive call | ||
227 | * (or GNUNET_SCHEDULER_NO_TASK for none). | ||
228 | */ | ||
229 | GNUNET_SCHEDULER_TaskIdentifier my_receive; | ||
230 | |||
231 | /** | ||
232 | * How many bytes in the "incoming_buffer" are currently | 226 | * How many bytes in the "incoming_buffer" are currently |
233 | * valid? (starting at offset 0). | 227 | * valid? (starting at offset 0). |
234 | */ | 228 | */ |
@@ -626,7 +620,6 @@ shutdown_incoming_processing (struct GNUNET_SERVER_Client *client) | |||
626 | struct NotifyList *n; | 620 | struct NotifyList *n; |
627 | unsigned int rc; | 621 | unsigned int rc; |
628 | 622 | ||
629 | GNUNET_assert (client->my_receive == GNUNET_SCHEDULER_NO_TASK); | ||
630 | rc = client->reference_count; | 623 | rc = client->reference_count; |
631 | if (client->server != NULL) | 624 | if (client->server != NULL) |
632 | { | 625 | { |
@@ -745,7 +738,6 @@ process_incoming (void *cls, | |||
745 | const char *cbuf = buf; | 738 | const char *cbuf = buf; |
746 | size_t maxcpy; | 739 | size_t maxcpy; |
747 | 740 | ||
748 | client->my_receive = GNUNET_SCHEDULER_NO_TASK; | ||
749 | if ((buf == NULL) || | 741 | if ((buf == NULL) || |
750 | (available == 0) || | 742 | (available == 0) || |
751 | (errCode != 0) || | 743 | (errCode != 0) || |
@@ -809,10 +801,10 @@ process_incoming (void *cls, | |||
809 | (GNUNET_YES != client->shutdown_now) && (client->server != NULL)) | 801 | (GNUNET_YES != client->shutdown_now) && (client->server != NULL)) |
810 | { | 802 | { |
811 | /* Finally, keep receiving! */ | 803 | /* Finally, keep receiving! */ |
812 | client->my_receive = client->receive (client->client_closure, | 804 | client->receive (client->client_closure, |
813 | GNUNET_SERVER_MAX_MESSAGE_SIZE, | 805 | GNUNET_SERVER_MAX_MESSAGE_SIZE, |
814 | server->idle_timeout, | 806 | server->idle_timeout, |
815 | &process_incoming, client); | 807 | &process_incoming, client); |
816 | } | 808 | } |
817 | if (GNUNET_YES == client->shutdown_now) | 809 | if (GNUNET_YES == client->shutdown_now) |
818 | shutdown_incoming_processing (client); | 810 | shutdown_incoming_processing (client); |
@@ -830,10 +822,10 @@ restart_processing (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | |||
830 | 822 | ||
831 | process_client_buffer (client); | 823 | process_client_buffer (client); |
832 | if (0 == client->suspended) | 824 | if (0 == client->suspended) |
833 | client->my_receive = client->receive (client->client_closure, | 825 | client->receive (client->client_closure, |
834 | GNUNET_SERVER_MAX_MESSAGE_SIZE, | 826 | GNUNET_SERVER_MAX_MESSAGE_SIZE, |
835 | client->server->idle_timeout, | 827 | client->server->idle_timeout, |
836 | &process_incoming, client); | 828 | &process_incoming, client); |
837 | } | 829 | } |
838 | 830 | ||
839 | 831 | ||
@@ -849,10 +841,10 @@ add_client (struct GNUNET_SERVER_Handle *server, | |||
849 | client->last_activity = GNUNET_TIME_absolute_get (); | 841 | client->last_activity = GNUNET_TIME_absolute_get (); |
850 | client->next = server->clients; | 842 | client->next = server->clients; |
851 | server->clients = client; | 843 | server->clients = client; |
852 | client->my_receive = client->receive (client->client_closure, | 844 | client->receive (client->client_closure, |
853 | GNUNET_SERVER_MAX_MESSAGE_SIZE, | 845 | GNUNET_SERVER_MAX_MESSAGE_SIZE, |
854 | server->idle_timeout, | 846 | server->idle_timeout, |
855 | &process_incoming, client); | 847 | &process_incoming, client); |
856 | } | 848 | } |
857 | 849 | ||
858 | 850 | ||
@@ -864,15 +856,14 @@ add_client (struct GNUNET_SERVER_Handle *server, | |||
864 | * @param timeout when should this operation time out | 856 | * @param timeout when should this operation time out |
865 | * @param receiver function to call for processing | 857 | * @param receiver function to call for processing |
866 | * @param receiver_cls closure for receiver | 858 | * @param receiver_cls closure for receiver |
867 | * @return task identifier that can be used to cancel the operation | ||
868 | */ | 859 | */ |
869 | static GNUNET_SCHEDULER_TaskIdentifier | 860 | static void |
870 | sock_receive (void *cls, | 861 | sock_receive (void *cls, |
871 | size_t max, | 862 | size_t max, |
872 | struct GNUNET_TIME_Relative timeout, | 863 | struct GNUNET_TIME_Relative timeout, |
873 | GNUNET_CONNECTION_Receiver receiver, void *receiver_cls) | 864 | GNUNET_CONNECTION_Receiver receiver, void *receiver_cls) |
874 | { | 865 | { |
875 | return GNUNET_CONNECTION_receive (cls, max, timeout, receiver, receiver_cls); | 866 | GNUNET_CONNECTION_receive (cls, max, timeout, receiver, receiver_cls); |
876 | } | 867 | } |
877 | 868 | ||
878 | 869 | ||
@@ -880,12 +871,11 @@ sock_receive (void *cls, | |||
880 | * Wrapper to cancel receiving from a socket. | 871 | * Wrapper to cancel receiving from a socket. |
881 | * | 872 | * |
882 | * @param cls handle to the GNUNET_CONNECTION_Handle to cancel | 873 | * @param cls handle to the GNUNET_CONNECTION_Handle to cancel |
883 | * @param ti task ID that was returned by GNUNET_CONNECTION_receive | ||
884 | */ | 874 | */ |
885 | static void | 875 | static void |
886 | sock_receive_cancel (void *cls, GNUNET_SCHEDULER_TaskIdentifier ti) | 876 | sock_receive_cancel (void *cls) |
887 | { | 877 | { |
888 | GNUNET_CONNECTION_receive_cancel (cls, ti); | 878 | GNUNET_CONNECTION_receive_cancel (cls); |
889 | } | 879 | } |
890 | 880 | ||
891 | 881 | ||
@@ -1112,9 +1102,7 @@ GNUNET_SERVER_client_disconnect (struct GNUNET_SERVER_Client *client) | |||
1112 | { | 1102 | { |
1113 | if (client->server == NULL) | 1103 | if (client->server == NULL) |
1114 | return; /* already disconnected */ | 1104 | return; /* already disconnected */ |
1115 | GNUNET_assert (client->my_receive != GNUNET_SCHEDULER_NO_TASK); | 1105 | client->receive_cancel (client->client_closure); |
1116 | client->receive_cancel (client->client_closure, client->my_receive); | ||
1117 | client->my_receive = GNUNET_SCHEDULER_NO_TASK; | ||
1118 | shutdown_incoming_processing (client); | 1106 | shutdown_incoming_processing (client); |
1119 | } | 1107 | } |
1120 | 1108 | ||
diff --git a/src/util/test_client.c b/src/util/test_client.c index 008e686a3..cda8025ac 100644 --- a/src/util/test_client.c +++ b/src/util/test_client.c | |||
@@ -185,6 +185,8 @@ check () | |||
185 | GNUNET_CONFIGURATION_set_value_number (cfg, MYNAME, "PORT", PORT); | 185 | GNUNET_CONFIGURATION_set_value_number (cfg, MYNAME, "PORT", PORT); |
186 | GNUNET_CONFIGURATION_set_value_string (cfg, | 186 | GNUNET_CONFIGURATION_set_value_string (cfg, |
187 | MYNAME, "HOSTNAME", "localhost"); | 187 | MYNAME, "HOSTNAME", "localhost"); |
188 | GNUNET_CONFIGURATION_set_value_string (cfg, | ||
189 | "resolver", "HOSTNAME", "localhost"); | ||
188 | ok = 1; | 190 | ok = 1; |
189 | GNUNET_SCHEDULER_run (&task, &ok); | 191 | GNUNET_SCHEDULER_run (&task, &ok); |
190 | GNUNET_CONFIGURATION_destroy (cfg); | 192 | GNUNET_CONFIGURATION_destroy (cfg); |
diff --git a/src/util/test_connection.c b/src/util/test_connection.c index f3a907165..888b9d015 100644 --- a/src/util/test_connection.c +++ b/src/util/test_connection.c | |||
@@ -27,7 +27,7 @@ | |||
27 | #include "gnunet_scheduler_lib.h" | 27 | #include "gnunet_scheduler_lib.h" |
28 | #include "gnunet_time_lib.h" | 28 | #include "gnunet_time_lib.h" |
29 | 29 | ||
30 | #define VERBOSE GNUNET_NO | 30 | #define VERBOSE GNUNET_YES |
31 | 31 | ||
32 | #define PORT 12435 | 32 | #define PORT 12435 |
33 | 33 | ||
@@ -42,7 +42,7 @@ static size_t sofar; | |||
42 | 42 | ||
43 | static struct GNUNET_NETWORK_Handle *ls; | 43 | static struct GNUNET_NETWORK_Handle *ls; |
44 | 44 | ||
45 | 45 | static struct GNUNET_CONFIGURATION_Handle *cfg; | |
46 | 46 | ||
47 | /** | 47 | /** |
48 | * Create and initialize a listen socket for the server. | 48 | * Create and initialize a listen socket for the server. |
@@ -154,7 +154,8 @@ task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | |||
154 | lsock = GNUNET_CONNECTION_create_from_existing (tc->sched, ls, 0); | 154 | lsock = GNUNET_CONNECTION_create_from_existing (tc->sched, ls, 0); |
155 | GNUNET_assert (lsock != NULL); | 155 | GNUNET_assert (lsock != NULL); |
156 | csock = GNUNET_CONNECTION_create_from_connect (tc->sched, | 156 | csock = GNUNET_CONNECTION_create_from_connect (tc->sched, |
157 | "localhost", PORT, 1024); | 157 | cfg, |
158 | "localhost", PORT, 1024); | ||
158 | GNUNET_assert (csock != NULL); | 159 | GNUNET_assert (csock != NULL); |
159 | #if VERBOSE | 160 | #if VERBOSE |
160 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test asks for write notification\n"); | 161 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test asks for write notification\n"); |
@@ -190,7 +191,11 @@ check () | |||
190 | int ok; | 191 | int ok; |
191 | 192 | ||
192 | ok = 1; | 193 | ok = 1; |
194 | cfg = GNUNET_CONFIGURATION_create (); | ||
195 | GNUNET_CONFIGURATION_set_value_string (cfg, | ||
196 | "resolver", "HOSTNAME", "localhost"); | ||
193 | GNUNET_SCHEDULER_run (&task, &ok); | 197 | GNUNET_SCHEDULER_run (&task, &ok); |
198 | GNUNET_CONFIGURATION_destroy (cfg); | ||
194 | return ok; | 199 | return ok; |
195 | } | 200 | } |
196 | 201 | ||
diff --git a/src/util/test_connection_receive_cancel.c b/src/util/test_connection_receive_cancel.c index 49df185b7..6434228f7 100644 --- a/src/util/test_connection_receive_cancel.c +++ b/src/util/test_connection_receive_cancel.c | |||
@@ -40,9 +40,7 @@ static struct GNUNET_CONNECTION_Handle *lsock; | |||
40 | 40 | ||
41 | static struct GNUNET_NETWORK_Handle *ls; | 41 | static struct GNUNET_NETWORK_Handle *ls; |
42 | 42 | ||
43 | static GNUNET_SCHEDULER_TaskIdentifier receive_task; | 43 | static struct GNUNET_CONFIGURATION_Handle *cfg; |
44 | |||
45 | |||
46 | 44 | ||
47 | 45 | ||
48 | /** | 46 | /** |
@@ -95,12 +93,11 @@ run_accept_cancel (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | |||
95 | GNUNET_assert (asock != NULL); | 93 | GNUNET_assert (asock != NULL); |
96 | GNUNET_assert (GNUNET_YES == GNUNET_CONNECTION_check (asock)); | 94 | GNUNET_assert (GNUNET_YES == GNUNET_CONNECTION_check (asock)); |
97 | GNUNET_CONNECTION_destroy (lsock); | 95 | GNUNET_CONNECTION_destroy (lsock); |
98 | receive_task | 96 | GNUNET_CONNECTION_receive (asock, |
99 | = GNUNET_CONNECTION_receive (asock, | 97 | 1024, |
100 | 1024, | 98 | GNUNET_TIME_relative_multiply |
101 | GNUNET_TIME_relative_multiply | 99 | (GNUNET_TIME_UNIT_SECONDS, 5), &dead_receive, |
102 | (GNUNET_TIME_UNIT_SECONDS, 5), &dead_receive, | 100 | cls); |
103 | cls); | ||
104 | } | 101 | } |
105 | 102 | ||
106 | 103 | ||
@@ -108,7 +105,7 @@ static void | |||
108 | receive_cancel_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | 105 | receive_cancel_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) |
109 | { | 106 | { |
110 | int *ok = cls; | 107 | int *ok = cls; |
111 | GNUNET_CONNECTION_receive_cancel (asock, receive_task); | 108 | GNUNET_CONNECTION_receive_cancel (asock); |
112 | GNUNET_CONNECTION_destroy (csock); | 109 | GNUNET_CONNECTION_destroy (csock); |
113 | GNUNET_CONNECTION_destroy (asock); | 110 | GNUNET_CONNECTION_destroy (asock); |
114 | *ok = 0; | 111 | *ok = 0; |
@@ -122,8 +119,8 @@ task_receive_cancel (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | |||
122 | ls = open_listen_socket (); | 119 | ls = open_listen_socket (); |
123 | lsock = GNUNET_CONNECTION_create_from_existing (tc->sched, ls, 0); | 120 | lsock = GNUNET_CONNECTION_create_from_existing (tc->sched, ls, 0); |
124 | GNUNET_assert (lsock != NULL); | 121 | GNUNET_assert (lsock != NULL); |
125 | csock = GNUNET_CONNECTION_create_from_connect (tc->sched, | 122 | csock = GNUNET_CONNECTION_create_from_connect (tc->sched, cfg, |
126 | "localhost", PORT, 1024); | 123 | "localhost", PORT, 1024); |
127 | GNUNET_assert (csock != NULL); | 124 | GNUNET_assert (csock != NULL); |
128 | GNUNET_SCHEDULER_add_read_net (tc->sched, | 125 | GNUNET_SCHEDULER_add_read_net (tc->sched, |
129 | GNUNET_NO, | 126 | GNUNET_NO, |
@@ -150,7 +147,11 @@ check_receive_cancel () | |||
150 | int ok; | 147 | int ok; |
151 | 148 | ||
152 | ok = 1; | 149 | ok = 1; |
150 | cfg = GNUNET_CONFIGURATION_create (); | ||
151 | GNUNET_CONFIGURATION_set_value_string (cfg, | ||
152 | "resolver", "HOSTNAME", "localhost"); | ||
153 | GNUNET_SCHEDULER_run (&task_receive_cancel, &ok); | 153 | GNUNET_SCHEDULER_run (&task_receive_cancel, &ok); |
154 | GNUNET_CONFIGURATION_destroy (cfg); | ||
154 | return ok; | 155 | return ok; |
155 | } | 156 | } |
156 | 157 | ||
diff --git a/src/util/test_connection_timeout.c b/src/util/test_connection_timeout.c index 2a1ce58f3..73433e434 100644 --- a/src/util/test_connection_timeout.c +++ b/src/util/test_connection_timeout.c | |||
@@ -37,6 +37,8 @@ static struct GNUNET_CONNECTION_Handle *lsock; | |||
37 | 37 | ||
38 | static struct GNUNET_NETWORK_Handle *ls; | 38 | static struct GNUNET_NETWORK_Handle *ls; |
39 | 39 | ||
40 | static struct GNUNET_CONFIGURATION_Handle *cfg; | ||
41 | |||
40 | 42 | ||
41 | /** | 43 | /** |
42 | * Create and initialize a listen socket for the server. | 44 | * Create and initialize a listen socket for the server. |
@@ -105,8 +107,8 @@ task_timeout (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | |||
105 | ls = open_listen_socket (); | 107 | ls = open_listen_socket (); |
106 | lsock = GNUNET_CONNECTION_create_from_existing (tc->sched, ls, 0); | 108 | lsock = GNUNET_CONNECTION_create_from_existing (tc->sched, ls, 0); |
107 | GNUNET_assert (lsock != NULL); | 109 | GNUNET_assert (lsock != NULL); |
108 | csock = GNUNET_CONNECTION_create_from_connect (tc->sched, | 110 | csock = GNUNET_CONNECTION_create_from_connect (tc->sched, cfg, |
109 | "localhost", PORT, 1024); | 111 | "localhost", PORT, 1024); |
110 | GNUNET_assert (csock != NULL); | 112 | GNUNET_assert (csock != NULL); |
111 | GNUNET_assert (NULL != | 113 | GNUNET_assert (NULL != |
112 | GNUNET_CONNECTION_notify_transmit_ready (csock, | 114 | GNUNET_CONNECTION_notify_transmit_ready (csock, |
@@ -126,7 +128,11 @@ check_timeout () | |||
126 | int ok; | 128 | int ok; |
127 | 129 | ||
128 | ok = 1; | 130 | ok = 1; |
131 | cfg = GNUNET_CONFIGURATION_create (); | ||
132 | GNUNET_CONFIGURATION_set_value_string (cfg, | ||
133 | "resolver", "HOSTNAME", "localhost"); | ||
129 | GNUNET_SCHEDULER_run (&task_timeout, &ok); | 134 | GNUNET_SCHEDULER_run (&task_timeout, &ok); |
135 | GNUNET_CONFIGURATION_destroy (cfg); | ||
130 | return ok; | 136 | return ok; |
131 | } | 137 | } |
132 | 138 | ||
diff --git a/src/util/test_connection_timeout_no_connect.c b/src/util/test_connection_timeout_no_connect.c index 6a6d32f38..84d50b4fb 100644 --- a/src/util/test_connection_timeout_no_connect.c +++ b/src/util/test_connection_timeout_no_connect.c | |||
@@ -33,6 +33,8 @@ | |||
33 | 33 | ||
34 | static struct GNUNET_CONNECTION_Handle *csock; | 34 | static struct GNUNET_CONNECTION_Handle *csock; |
35 | 35 | ||
36 | static struct GNUNET_CONFIGURATION_Handle *cfg; | ||
37 | |||
36 | static size_t | 38 | static size_t |
37 | handle_timeout (void *cls, size_t size, void *buf) | 39 | handle_timeout (void *cls, size_t size, void *buf) |
38 | { | 40 | { |
@@ -51,8 +53,8 @@ handle_timeout (void *cls, size_t size, void *buf) | |||
51 | static void | 53 | static void |
52 | task_timeout (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | 54 | task_timeout (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) |
53 | { | 55 | { |
54 | csock = GNUNET_CONNECTION_create_from_connect (tc->sched, | 56 | csock = GNUNET_CONNECTION_create_from_connect (tc->sched, cfg, |
55 | "localhost", PORT, 1024); | 57 | "localhost", PORT, 1024); |
56 | GNUNET_assert (csock != NULL); | 58 | GNUNET_assert (csock != NULL); |
57 | GNUNET_assert (NULL != | 59 | GNUNET_assert (NULL != |
58 | GNUNET_CONNECTION_notify_transmit_ready (csock, | 60 | GNUNET_CONNECTION_notify_transmit_ready (csock, |
@@ -72,7 +74,11 @@ check_timeout () | |||
72 | int ok; | 74 | int ok; |
73 | 75 | ||
74 | ok = 1; | 76 | ok = 1; |
77 | cfg = GNUNET_CONFIGURATION_create (); | ||
78 | GNUNET_CONFIGURATION_set_value_string (cfg, | ||
79 | "resolver", "HOSTNAME", "localhost"); | ||
75 | GNUNET_SCHEDULER_run (&task_timeout, &ok); | 80 | GNUNET_SCHEDULER_run (&task_timeout, &ok); |
81 | GNUNET_CONFIGURATION_destroy (cfg); | ||
76 | return ok; | 82 | return ok; |
77 | } | 83 | } |
78 | 84 | ||
diff --git a/src/util/test_connection_transmit_cancel.c b/src/util/test_connection_transmit_cancel.c index 642ea0d4c..5ec19bdb1 100644 --- a/src/util/test_connection_transmit_cancel.c +++ b/src/util/test_connection_transmit_cancel.c | |||
@@ -31,6 +31,8 @@ | |||
31 | 31 | ||
32 | #define PORT 12435 | 32 | #define PORT 12435 |
33 | 33 | ||
34 | static struct GNUNET_CONFIGURATION_Handle *cfg; | ||
35 | |||
34 | 36 | ||
35 | static size_t | 37 | static size_t |
36 | not_run (void *cls, size_t size, void *buf) | 38 | not_run (void *cls, size_t size, void *buf) |
@@ -48,8 +50,8 @@ task_transmit_cancel (void *cls, | |||
48 | struct GNUNET_CONNECTION_TransmitHandle *th; | 50 | struct GNUNET_CONNECTION_TransmitHandle *th; |
49 | struct GNUNET_CONNECTION_Handle *csock; | 51 | struct GNUNET_CONNECTION_Handle *csock; |
50 | 52 | ||
51 | csock = GNUNET_CONNECTION_create_from_connect (tc->sched, | 53 | csock = GNUNET_CONNECTION_create_from_connect (tc->sched, cfg, |
52 | "localhost", PORT, 1024); | 54 | "localhost", PORT, 1024); |
53 | GNUNET_assert (csock != NULL); | 55 | GNUNET_assert (csock != NULL); |
54 | th = GNUNET_CONNECTION_notify_transmit_ready (csock, | 56 | th = GNUNET_CONNECTION_notify_transmit_ready (csock, |
55 | 12, | 57 | 12, |
@@ -72,7 +74,11 @@ check_transmit_cancel () | |||
72 | int ok; | 74 | int ok; |
73 | 75 | ||
74 | ok = 1; | 76 | ok = 1; |
77 | cfg = GNUNET_CONFIGURATION_create (); | ||
78 | GNUNET_CONFIGURATION_set_value_string (cfg, | ||
79 | "resolver", "HOSTNAME", "localhost"); | ||
75 | GNUNET_SCHEDULER_run (&task_transmit_cancel, &ok); | 80 | GNUNET_SCHEDULER_run (&task_transmit_cancel, &ok); |
81 | GNUNET_CONFIGURATION_destroy (cfg); | ||
76 | return ok; | 82 | return ok; |
77 | } | 83 | } |
78 | 84 | ||
diff --git a/src/util/test_resolver_api.c b/src/util/test_resolver_api.c new file mode 100644 index 000000000..295217c30 --- /dev/null +++ b/src/util/test_resolver_api.c | |||
@@ -0,0 +1,212 @@ | |||
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 resolver/test_resolver_api.c | ||
22 | * @brief testcase for resolver_api.c | ||
23 | */ | ||
24 | #include "platform.h" | ||
25 | #include "gnunet_common.h" | ||
26 | #include "gnunet_getopt_lib.h" | ||
27 | #include "gnunet_os_lib.h" | ||
28 | #include "gnunet_program_lib.h" | ||
29 | #include "gnunet_scheduler_lib.h" | ||
30 | #include "gnunet_resolver_service.h" | ||
31 | #include "resolver.h" | ||
32 | |||
33 | #define VERBOSE GNUNET_NO | ||
34 | |||
35 | |||
36 | static void | ||
37 | check_hostname (void *cls, const struct sockaddr *sa, socklen_t salen) | ||
38 | { | ||
39 | int *ok = cls; | ||
40 | |||
41 | if (salen == 0) | ||
42 | { | ||
43 | (*ok) &= ~8; | ||
44 | return; | ||
45 | } | ||
46 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
47 | _("Got IP address `%s' for our host.\n"), | ||
48 | GNUNET_a2s (sa, salen)); | ||
49 | } | ||
50 | |||
51 | |||
52 | static void | ||
53 | check_localhost_num (void *cls, const char *hostname) | ||
54 | { | ||
55 | int *ok = cls; | ||
56 | if (hostname == NULL) | ||
57 | return; | ||
58 | if (0 == strcmp (hostname, "127.0.0.1")) | ||
59 | { | ||
60 | #if DEBUG_RESOLVER | ||
61 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
62 | "Received correct hostname `%s'.\n", hostname); | ||
63 | #endif | ||
64 | (*ok) &= ~4; | ||
65 | } | ||
66 | else | ||
67 | { | ||
68 | #if DEBUG_RESOLVER | ||
69 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
70 | "Received invalid hostname `%s'.\n", hostname); | ||
71 | #endif | ||
72 | GNUNET_break (0); | ||
73 | } | ||
74 | } | ||
75 | |||
76 | static void | ||
77 | check_localhost (void *cls, const char *hostname) | ||
78 | { | ||
79 | int *ok = cls; | ||
80 | if (hostname == NULL) | ||
81 | return; | ||
82 | if (0 == strcmp (hostname, "localhost")) | ||
83 | { | ||
84 | #if DEBUG_RESOLVER | ||
85 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
86 | "Received correct hostname `%s'.\n", hostname); | ||
87 | #endif | ||
88 | (*ok) &= ~2; | ||
89 | } | ||
90 | else | ||
91 | { | ||
92 | #if DEBUG_RESOLVER | ||
93 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
94 | "Received invalid hostname `%s'.\n", hostname); | ||
95 | #endif | ||
96 | GNUNET_break (0); | ||
97 | } | ||
98 | } | ||
99 | |||
100 | static void | ||
101 | check_127 (void *cls, const struct sockaddr *sa, socklen_t salen) | ||
102 | { | ||
103 | int *ok = cls; | ||
104 | const struct sockaddr_in *sai = (const struct sockaddr_in *) sa; | ||
105 | |||
106 | if (sa == NULL) | ||
107 | return; | ||
108 | GNUNET_assert (sizeof (struct sockaddr_in) == salen); | ||
109 | if (sai->sin_addr.s_addr == htonl (INADDR_LOOPBACK)) | ||
110 | { | ||
111 | #if DEBUG_RESOLVER | ||
112 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received correct address.\n"); | ||
113 | #endif | ||
114 | (*ok) &= ~1; | ||
115 | } | ||
116 | else | ||
117 | { | ||
118 | #if DEBUG_RESOLVER | ||
119 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received incorrect address.\n"); | ||
120 | #endif | ||
121 | GNUNET_break (0); | ||
122 | } | ||
123 | } | ||
124 | |||
125 | static void | ||
126 | run (void *cls, | ||
127 | struct GNUNET_SCHEDULER_Handle *sched, | ||
128 | char *const *args, | ||
129 | const char *cfgfile, | ||
130 | const struct GNUNET_CONFIGURATION_Handle *cfg) | ||
131 | { | ||
132 | struct sockaddr_in sa; | ||
133 | struct GNUNET_TIME_Relative timeout = | ||
134 | GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, | ||
135 | 2500); | ||
136 | memset (&sa, 0, sizeof (sa)); | ||
137 | sa.sin_family = AF_INET; | ||
138 | sa.sin_addr.s_addr = htonl (INADDR_LOOPBACK); | ||
139 | GNUNET_RESOLVER_ip_get (sched, | ||
140 | cfg, | ||
141 | "localhost", AF_INET, timeout, &check_127, cls); | ||
142 | GNUNET_RESOLVER_hostname_get (sched, | ||
143 | cfg, | ||
144 | (const struct sockaddr *) &sa, | ||
145 | sizeof (struct sockaddr), | ||
146 | GNUNET_YES, timeout, &check_localhost, cls); | ||
147 | GNUNET_RESOLVER_hostname_get (sched, | ||
148 | cfg, | ||
149 | (const struct sockaddr *) &sa, | ||
150 | sizeof (struct sockaddr), | ||
151 | GNUNET_NO, | ||
152 | timeout, &check_localhost_num, cls); | ||
153 | GNUNET_RESOLVER_hostname_resolve (sched, | ||
154 | cfg, | ||
155 | AF_UNSPEC, timeout, &check_hostname, cls); | ||
156 | } | ||
157 | |||
158 | static int | ||
159 | check () | ||
160 | { | ||
161 | int ok = 1 + 2 + 4 + 8; | ||
162 | pid_t pid; | ||
163 | char *const argv[] = { "test-resolver-api", | ||
164 | "-c", | ||
165 | "test_resolver_api_data.conf", | ||
166 | #if VERBOSE | ||
167 | "-L", "DEBUG", | ||
168 | #endif | ||
169 | NULL | ||
170 | }; | ||
171 | struct GNUNET_GETOPT_CommandLineOption options[] = { | ||
172 | GNUNET_GETOPT_OPTION_END | ||
173 | }; | ||
174 | pid = GNUNET_OS_start_process ("gnunet-service-resolver", | ||
175 | "gnunet-service-resolver", | ||
176 | #if VERBOSE | ||
177 | "-L", "DEBUG", | ||
178 | #endif | ||
179 | "-c", "test_resolver_api_data.conf", NULL); | ||
180 | sleep (1); | ||
181 | GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, | ||
182 | argv, "test-resolver-api", "nohelp", | ||
183 | options, &run, &ok); | ||
184 | if (0 != PLIBC_KILL (pid, SIGTERM)) | ||
185 | { | ||
186 | GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); | ||
187 | ok = 1; | ||
188 | } | ||
189 | GNUNET_OS_process_wait(pid); | ||
190 | if (ok != 0) | ||
191 | fprintf (stderr, "Missed some resolutions: %u\n", ok); | ||
192 | return ok; | ||
193 | } | ||
194 | |||
195 | int | ||
196 | main (int argc, char *argv[]) | ||
197 | { | ||
198 | int ret; | ||
199 | |||
200 | GNUNET_log_setup ("test-resolver-api", | ||
201 | #if VERBOSE | ||
202 | "DEBUG", | ||
203 | #else | ||
204 | "WARNING", | ||
205 | #endif | ||
206 | NULL); | ||
207 | ret = check (); | ||
208 | |||
209 | return ret; | ||
210 | } | ||
211 | |||
212 | /* end of test_resolver_api.c */ | ||
diff --git a/src/util/test_resolver_api_data.conf b/src/util/test_resolver_api_data.conf new file mode 100644 index 000000000..d7a9be758 --- /dev/null +++ b/src/util/test_resolver_api_data.conf | |||
@@ -0,0 +1,6 @@ | |||
1 | [PATHS] | ||
2 | SERVICEHOME = /tmp/test-gnunetd-statistics/ | ||
3 | |||
4 | [resolver] | ||
5 | PORT = 22354 | ||
6 | HOSTNAME = localhost | ||
diff --git a/src/util/test_server.c b/src/util/test_server.c index 96b27558e..eadc03568 100644 --- a/src/util/test_server.c +++ b/src/util/test_server.c | |||
@@ -66,7 +66,10 @@ signal_timeout (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | |||
66 | } | 66 | } |
67 | 67 | ||
68 | 68 | ||
69 | static GNUNET_SCHEDULER_TaskIdentifier | 69 | static GNUNET_SCHEDULER_TaskIdentifier ti; |
70 | |||
71 | |||
72 | static void | ||
70 | my_receive (void *cls, | 73 | my_receive (void *cls, |
71 | size_t max, | 74 | size_t max, |
72 | struct GNUNET_TIME_Relative timeout, | 75 | struct GNUNET_TIME_Relative timeout, |
@@ -104,12 +107,12 @@ my_receive (void *cls, | |||
104 | default: | 107 | default: |
105 | GNUNET_assert (0); | 108 | GNUNET_assert (0); |
106 | } | 109 | } |
107 | return ret; | 110 | ti = ret; |
108 | } | 111 | } |
109 | 112 | ||
110 | 113 | ||
111 | static void | 114 | static void |
112 | my_cancel (void *cls, GNUNET_SCHEDULER_TaskIdentifier ti) | 115 | my_cancel (void *cls) |
113 | { | 116 | { |
114 | GNUNET_SCHEDULER_cancel (sched, ti); | 117 | GNUNET_SCHEDULER_cancel (sched, ti); |
115 | } | 118 | } |
diff --git a/src/util/test_server_disconnect.c b/src/util/test_server_disconnect.c index 6c83961e0..84e9c7ccd 100644 --- a/src/util/test_server_disconnect.c +++ b/src/util/test_server_disconnect.c | |||
@@ -202,6 +202,8 @@ task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | |||
202 | GNUNET_CONFIGURATION_set_value_number (cfg, "test", "PORT", PORT); | 202 | GNUNET_CONFIGURATION_set_value_number (cfg, "test", "PORT", PORT); |
203 | GNUNET_CONFIGURATION_set_value_string (cfg, "test", "HOSTNAME", | 203 | GNUNET_CONFIGURATION_set_value_string (cfg, "test", "HOSTNAME", |
204 | "localhost"); | 204 | "localhost"); |
205 | GNUNET_CONFIGURATION_set_value_string (cfg, "resolver", "HOSTNAME", | ||
206 | "localhost"); | ||
205 | client = GNUNET_CLIENT_connect (tc->sched, "test", cfg); | 207 | client = GNUNET_CLIENT_connect (tc->sched, "test", cfg); |
206 | GNUNET_assert (client != NULL); | 208 | GNUNET_assert (client != NULL); |
207 | GNUNET_CLIENT_notify_transmit_ready (client, | 209 | GNUNET_CLIENT_notify_transmit_ready (client, |
diff --git a/src/util/test_server_with_client.c b/src/util/test_server_with_client.c index 9348f0d80..4f3048f34 100644 --- a/src/util/test_server_with_client.c +++ b/src/util/test_server_with_client.c | |||
@@ -176,6 +176,8 @@ task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | |||
176 | GNUNET_CONFIGURATION_set_value_number (cfg, "test", "PORT", PORT); | 176 | GNUNET_CONFIGURATION_set_value_number (cfg, "test", "PORT", PORT); |
177 | GNUNET_CONFIGURATION_set_value_string (cfg, "test", "HOSTNAME", | 177 | GNUNET_CONFIGURATION_set_value_string (cfg, "test", "HOSTNAME", |
178 | "localhost"); | 178 | "localhost"); |
179 | GNUNET_CONFIGURATION_set_value_string (cfg, "resolver", "HOSTNAME", | ||
180 | "localhost"); | ||
179 | client = GNUNET_CLIENT_connect (tc->sched, "test", cfg); | 181 | client = GNUNET_CLIENT_connect (tc->sched, "test", cfg); |
180 | GNUNET_assert (client != NULL); | 182 | GNUNET_assert (client != NULL); |
181 | GNUNET_CLIENT_notify_transmit_ready (client, | 183 | GNUNET_CLIENT_notify_transmit_ready (client, |
diff --git a/src/util/test_service_data.conf b/src/util/test_service_data.conf index 92c723619..d3a3e8278 100644 --- a/src/util/test_service_data.conf +++ b/src/util/test_service_data.conf | |||
@@ -24,3 +24,6 @@ ACCEPT_FROM6=::1; | |||
24 | REJECT_FROM6=AB:CD:EF::00;AB:CD::00/40; | 24 | REJECT_FROM6=AB:CD:EF::00;AB:CD::00/40; |
25 | HOSTNAME=::1 | 25 | HOSTNAME=::1 |
26 | ALLOW_SHUTDOWN=YES | 26 | ALLOW_SHUTDOWN=YES |
27 | |||
28 | [resolver] | ||
29 | HOSTNAME=localhost | ||