aboutsummaryrefslogtreecommitdiff
path: root/src/util
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2009-10-01 16:23:25 +0000
committerChristian Grothoff <christian@grothoff.org>2009-10-01 16:23:25 +0000
commitf0aa7bc0a136b1e436018ef72e1c814f04c33379 (patch)
treed52c0ad69e3507610fb3271f1f5273bd4d05c124 /src/util
parent028a762caf0c2e1cc7b23a9dc4becf9859d13c15 (diff)
downloadgnunet-f0aa7bc0a136b1e436018ef72e1c814f04c33379.tar.gz
gnunet-f0aa7bc0a136b1e436018ef72e1c814f04c33379.zip
moving resolver to util, making DNS lookups asynchronous in util
Diffstat (limited to 'src/util')
-rw-r--r--src/util/Makefile.am20
-rw-r--r--src/util/client.c68
-rw-r--r--src/util/connection.c926
-rw-r--r--src/util/gnunet-service-resolver.c492
-rw-r--r--src/util/resolver.h63
-rw-r--r--src/util/resolver_api.c589
-rw-r--r--src/util/server.c46
-rw-r--r--src/util/test_client.c2
-rw-r--r--src/util/test_connection.c11
-rw-r--r--src/util/test_connection_receive_cancel.c25
-rw-r--r--src/util/test_connection_timeout.c10
-rw-r--r--src/util/test_connection_timeout_no_connect.c10
-rw-r--r--src/util/test_connection_transmit_cancel.c10
-rw-r--r--src/util/test_resolver_api.c212
-rw-r--r--src/util/test_resolver_api_data.conf6
-rw-r--r--src/util/test_server.c9
-rw-r--r--src/util/test_server_disconnect.c2
-rw-r--r--src/util/test_server_with_client.c2
-rw-r--r--src/util/test_service_data.conf3
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
70bin_PROGRAMS = \
71 gnunet-service-resolver
72
73gnunet_service_resolver_SOURCES = \
74 gnunet-service-resolver.c
75gnunet_service_resolver_LDADD = \
76 $(top_builddir)/src/util/libgnunetutil.la \
77 $(GN_LIBINTL)
78
79
69plugin_LTLIBRARIES = \ 80plugin_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
158test_container_multihashmap_LDADD = \ 170test_container_multihashmap_LDADD = \
159 $(top_builddir)/src/util/libgnunetutil.la 171 $(top_builddir)/src/util/libgnunetutil.la
160 172
161test_container_heap_SOURCES = \ 173test_container_heap_SOURCES = \
162 test_container_heap.c 174 test_container_heap.c
163test_container_heap_LDADD = \ 175test_container_heap_LDADD = \
@@ -268,6 +280,11 @@ test_pseudonym_SOURCES = \
268test_pseudonym_LDADD = \ 280test_pseudonym_LDADD = \
269 $(top_builddir)/src/util/libgnunetutil.la 281 $(top_builddir)/src/util/libgnunetutil.la
270 282
283test_resolver_api_SOURCES = \
284 test_resolver_api.c
285test_resolver_api_LDADD = \
286 $(top_builddir)/src/util/libgnunetutil.la
287
271test_scheduler_SOURCES = \ 288test_scheduler_SOURCES = \
272 test_scheduler.c 289 test_scheduler.c
273test_scheduler_LDADD = \ 290test_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 */
208static void 216static void
209check_complete (struct GNUNET_CLIENT_Connection *conn) 217check_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 */
49static int address_families[] = 51enum 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 */
52struct GNUNET_CONNECTION_TransmitHandle 78struct 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 */
120struct 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 */
437static void
438retry_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 */
360static void 452static void
361try_lookup (struct GNUNET_CONNECTION_Handle *sock) 453receive_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; 463static void
375#if 0 464destroy_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], 477static void
389 sock->hostname, 478transmit_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 */
486static void
487connect_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 */
414static int 540static void
415try_connect (struct GNUNET_CONNECTION_Handle *sock) 541connect_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 */
500static void 589static void
501connect_continuation (void *cls, 590connect_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 */
640static void
641destroy_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, 713static void
563 delay, 714try_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 */
825static void
826retry_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 */
593struct GNUNET_CONNECTION_Handle * 855struct GNUNET_CONNECTION_Handle *
594GNUNET_CONNECTION_create_from_connect (struct GNUNET_SCHEDULER_Handle 856GNUNET_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
699int 947int
700GNUNET_CONNECTION_check (struct GNUNET_CONNECTION_Handle *sock) 948GNUNET_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 */
712static void
713destroy_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,
771void 964void
772GNUNET_CONNECTION_destroy (struct GNUNET_CONNECTION_Handle *sock) 965GNUNET_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 */
895static void 1096static void
896receive_again (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) 1097receive_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 */
961GNUNET_SCHEDULER_TaskIdentifier 1152void
962GNUNET_CONNECTION_receive (struct GNUNET_CONNECTION_Handle *sock, 1153GNUNET_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 */
992void * 1193void *
993GNUNET_CONNECTION_receive_cancel (struct GNUNET_CONNECTION_Handle *sock, 1194GNUNET_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 */
1094static void 1305static void
1095transmit_ready (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) 1306transmit_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
39struct 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
50static struct IPCache *head;
51
52
53
54
55#if HAVE_GETNAMEINFO
56static void
57getnameinfo_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
72static void
73gethostbyaddr_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
96static void
97cache_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 */
119static void
120get_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
201static int
202getaddrinfo_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
255static int
256gethostbyname2_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
311static int
312gethostbyname_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 */
351static void
352get_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 */
385static void
386handle_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 */
439static 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 */
453static void
454run (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 */
470int
471main (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 */
43struct 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 */
38struct 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 */
71static 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 */
84static void
85check_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 */
121static char *
122no_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
156static void
157handle_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
220static size_t
221transmit_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 */
260void
261GNUNET_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
369struct 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
379static void
380handle_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
428static size_t
429transmit_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 */
469void
470GNUNET_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 */
560void
561GNUNET_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 */
869static GNUNET_SCHEDULER_TaskIdentifier 860static void
870sock_receive (void *cls, 861sock_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 */
885static void 875static void
886sock_receive_cancel (void *cls, GNUNET_SCHEDULER_TaskIdentifier ti) 876sock_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
43static struct GNUNET_NETWORK_Handle *ls; 43static struct GNUNET_NETWORK_Handle *ls;
44 44
45 45static 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
41static struct GNUNET_NETWORK_Handle *ls; 41static struct GNUNET_NETWORK_Handle *ls;
42 42
43static GNUNET_SCHEDULER_TaskIdentifier receive_task; 43static 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
108receive_cancel_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) 105receive_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
38static struct GNUNET_NETWORK_Handle *ls; 38static struct GNUNET_NETWORK_Handle *ls;
39 39
40static 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
34static struct GNUNET_CONNECTION_Handle *csock; 34static struct GNUNET_CONNECTION_Handle *csock;
35 35
36static struct GNUNET_CONFIGURATION_Handle *cfg;
37
36static size_t 38static size_t
37handle_timeout (void *cls, size_t size, void *buf) 39handle_timeout (void *cls, size_t size, void *buf)
38{ 40{
@@ -51,8 +53,8 @@ handle_timeout (void *cls, size_t size, void *buf)
51static void 53static void
52task_timeout (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) 54task_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
34static struct GNUNET_CONFIGURATION_Handle *cfg;
35
34 36
35static size_t 37static size_t
36not_run (void *cls, size_t size, void *buf) 38not_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
36static void
37check_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
52static void
53check_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
76static void
77check_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
100static void
101check_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
125static void
126run (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
158static int
159check ()
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
195int
196main (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]
2SERVICEHOME = /tmp/test-gnunetd-statistics/
3
4[resolver]
5PORT = 22354
6HOSTNAME = 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
69static GNUNET_SCHEDULER_TaskIdentifier 69static GNUNET_SCHEDULER_TaskIdentifier ti;
70
71
72static void
70my_receive (void *cls, 73my_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
111static void 114static void
112my_cancel (void *cls, GNUNET_SCHEDULER_TaskIdentifier ti) 115my_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;
24REJECT_FROM6=AB:CD:EF::00;AB:CD::00/40; 24REJECT_FROM6=AB:CD:EF::00;AB:CD::00/40;
25HOSTNAME=::1 25HOSTNAME=::1
26ALLOW_SHUTDOWN=YES 26ALLOW_SHUTDOWN=YES
27
28[resolver]
29HOSTNAME=localhost