aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2009-10-27 22:27:11 +0000
committerChristian Grothoff <christian@grothoff.org>2009-10-27 22:27:11 +0000
commitb3443c6ab7b18ee57866ac531bf9f40aa3eb5261 (patch)
tree272b88c59422b9954acb6c7ee08e4a2e9e520a70
parent64d39ac5f14b54eecc2c7cd99b04d05ff04a894f (diff)
downloadgnunet-b3443c6ab7b18ee57866ac531bf9f40aa3eb5261.tar.gz
gnunet-b3443c6ab7b18ee57866ac531bf9f40aa3eb5261.zip
allowing cancellation of resolver requests
-rw-r--r--src/include/gnunet_client_lib.h13
-rw-r--r--src/include/gnunet_resolver_service.h46
-rw-r--r--src/util/client.c151
-rw-r--r--src/util/connection.c16
-rw-r--r--src/util/network.c6
-rw-r--r--src/util/resolver_api.c599
-rw-r--r--src/util/server.c2
-rw-r--r--src/util/test_connection.c15
8 files changed, 543 insertions, 305 deletions
diff --git a/src/include/gnunet_client_lib.h b/src/include/gnunet_client_lib.h
index c78df41c7..2ba9e135f 100644
--- a/src/include/gnunet_client_lib.h
+++ b/src/include/gnunet_client_lib.h
@@ -64,10 +64,15 @@ struct GNUNET_CLIENT_Connection *GNUNET_CLIENT_connect (struct
64 *cfg); 64 *cfg);
65 65
66/** 66/**
67 * Destroy connection with the service. This will 67 * Destroy connection with the service. This will automatically
68 * automatically cancel any pending "receive" request 68 * cancel any pending "receive" request (however, the handler will
69 * (however, the handler will *NOT* be called, not 69 * *NOT* be called, not even with a NULL message). Any pending
70 * even with a NULL message). 70 * transmission request will also be cancelled UNLESS the callback for
71 * the transmission request has already been called, in which case the
72 * transmission is guaranteed to complete before the socket is fully
73 * destroyed.
74 *
75 * @param sock handle to the service connection
71 */ 76 */
72void GNUNET_CLIENT_disconnect (struct GNUNET_CLIENT_Connection *sock); 77void GNUNET_CLIENT_disconnect (struct GNUNET_CLIENT_Connection *sock);
73 78
diff --git a/src/include/gnunet_resolver_service.h b/src/include/gnunet_resolver_service.h
index b7fb1532a..f8b1e79c7 100644
--- a/src/include/gnunet_resolver_service.h
+++ b/src/include/gnunet_resolver_service.h
@@ -53,6 +53,13 @@ typedef void (*GNUNET_RESOLVER_AddressCallback) (void *cls,
53 53
54 54
55/** 55/**
56 * Handle to a request given to the resolver. Can be used to cancel
57 * the request prior to the timeout or successful execution.
58 */
59struct GNUNET_RESOLVER_RequestHandle;
60
61
62/**
56 * Convert a string to one or more IP addresses. 63 * Convert a string to one or more IP addresses.
57 * 64 *
58 * @param sched scheduler to use 65 * @param sched scheduler to use
@@ -62,8 +69,9 @@ typedef void (*GNUNET_RESOLVER_AddressCallback) (void *cls,
62 * @param callback function to call with addresses 69 * @param callback function to call with addresses
63 * @param callback_cls closure for callback 70 * @param callback_cls closure for callback
64 * @param timeout how long to try resolving 71 * @param timeout how long to try resolving
72 * @return handle that can be used to cancel the request, NULL on error
65 */ 73 */
66void 74struct GNUNET_RESOLVER_RequestHandle *
67GNUNET_RESOLVER_ip_get (struct GNUNET_SCHEDULER_Handle *sched, 75GNUNET_RESOLVER_ip_get (struct GNUNET_SCHEDULER_Handle *sched,
68 const struct GNUNET_CONFIGURATION_Handle *cfg, 76 const struct GNUNET_CONFIGURATION_Handle *cfg,
69 const char *hostname, 77 const char *hostname,
@@ -82,8 +90,9 @@ GNUNET_RESOLVER_ip_get (struct GNUNET_SCHEDULER_Handle *sched,
82 * @param callback function to call with addresses 90 * @param callback function to call with addresses
83 * @param cls closure for callback 91 * @param cls closure for callback
84 * @param timeout how long to try resolving 92 * @param timeout how long to try resolving
93 * @return handle that can be used to cancel the request, NULL on error
85 */ 94 */
86void 95struct GNUNET_RESOLVER_RequestHandle *
87GNUNET_RESOLVER_hostname_resolve (struct GNUNET_SCHEDULER_Handle *sched, 96GNUNET_RESOLVER_hostname_resolve (struct GNUNET_SCHEDULER_Handle *sched,
88 const struct GNUNET_CONFIGURATION_Handle *cfg, 97 const struct GNUNET_CONFIGURATION_Handle *cfg,
89 int domain, 98 int domain,
@@ -104,7 +113,7 @@ typedef void (*GNUNET_RESOLVER_HostnameCallback) (void *cls,
104 113
105 114
106/** 115/**
107 * Get an IP address as a string. 116 * Perform a reverse DNS lookup.
108 * 117 *
109 * @param sched scheduler to use 118 * @param sched scheduler to use
110 * @param cfg configuration to use 119 * @param cfg configuration to use
@@ -114,15 +123,30 @@ typedef void (*GNUNET_RESOLVER_HostnameCallback) (void *cls,
114 * @param timeout how long to try resolving 123 * @param timeout how long to try resolving
115 * @param callback function to call with hostnames 124 * @param callback function to call with hostnames
116 * @param cls closure for callback 125 * @param cls closure for callback
126 * @return handle that can be used to cancel the request, NULL on error
117 */ 127 */
118void GNUNET_RESOLVER_hostname_get (struct GNUNET_SCHEDULER_Handle *sched, 128struct GNUNET_RESOLVER_RequestHandle *
119 const struct GNUNET_CONFIGURATION_Handle *cfg, 129GNUNET_RESOLVER_hostname_get (struct GNUNET_SCHEDULER_Handle *sched,
120 const struct sockaddr *sa, 130 const struct GNUNET_CONFIGURATION_Handle *cfg,
121 socklen_t salen, 131 const struct sockaddr *sa,
122 int do_resolve, 132 socklen_t salen,
123 struct GNUNET_TIME_Relative timeout, 133 int do_resolve,
124 GNUNET_RESOLVER_HostnameCallback callback, 134 struct GNUNET_TIME_Relative timeout,
125 void *cls); 135 GNUNET_RESOLVER_HostnameCallback callback,
136 void *cls);
137
138
139/**
140 * Cancel a request that is still pending with the resolver.
141 * Note that a client MUST NOT cancel a request that has
142 * been completed (i.e, the callback has been called to
143 * signal timeout or the final result).
144 *
145 * @param h handle of request to cancel
146 */
147void
148GNUNET_RESOLVER_request_cancel (struct GNUNET_RESOLVER_RequestHandle *h);
149
126 150
127#if 0 /* keep Emacsens' auto-indent happy */ 151#if 0 /* keep Emacsens' auto-indent happy */
128{ 152{
diff --git a/src/util/client.c b/src/util/client.c
index 4135a15a1..8c429995c 100644
--- a/src/util/client.c
+++ b/src/util/client.c
@@ -44,6 +44,67 @@
44 */ 44 */
45#define MAX_ATTEMPTS 10 45#define MAX_ATTEMPTS 10
46 46
47
48/**
49 * Handle for a transmission request.
50 */
51struct GNUNET_CLIENT_TransmitHandle
52{
53 /**
54 * Connection state.
55 */
56 struct GNUNET_CLIENT_Connection *sock;
57
58 /**
59 * Function to call to get the data for transmission.
60 */
61 GNUNET_CONNECTION_TransmitReadyNotify notify;
62
63 /**
64 * Closure for notify.
65 */
66 void *notify_cls;
67
68 /**
69 * Handle to the transmission with the underlying
70 * connection.
71 */
72 struct GNUNET_CONNECTION_TransmitHandle *th;
73
74 /**
75 * Timeout.
76 */
77 struct GNUNET_TIME_Absolute timeout;
78
79 /**
80 * If we are re-trying and are delaying to do so,
81 * handle to the scheduled task managing the delay.
82 */
83 GNUNET_SCHEDULER_TaskIdentifier task;
84
85 /**
86 * Number of bytes requested.
87 */
88 size_t size;
89
90 /**
91 * Are we allowed to re-try to connect without telling
92 * the user (of this API) about the connection troubles?
93 */
94 int auto_retry;
95
96 /**
97 * Number of attempts left for transmitting the request. We may
98 * fail the first time (say because the service is not yet up), in
99 * which case (if auto_retry is set) we wait a bit and re-try
100 * (timeout permitting).
101 */
102 unsigned int attempts_left;
103
104};
105
106
107
47/** 108/**
48 * Struct to refer to a GNUnet TCP connection. 109 * Struct to refer to a GNUnet TCP connection.
49 * This is more than just a socket because if the server 110 * This is more than just a socket because if the server
@@ -84,6 +145,12 @@ struct GNUNET_CLIENT_Connection
84 void *receiver_handler_cls; 145 void *receiver_handler_cls;
85 146
86 /** 147 /**
148 * Handle for a pending transmission request, NULL if there is
149 * none pending.
150 */
151 struct GNUNET_CLIENT_TransmitHandle *th;
152
153 /**
87 * Handler for service test completion (NULL unless in service_test) 154 * Handler for service test completion (NULL unless in service_test)
88 */ 155 */
89 GNUNET_SCHEDULER_Task test_cb; 156 GNUNET_SCHEDULER_Task test_cb;
@@ -209,6 +276,8 @@ finish_cleanup (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
209{ 276{
210 struct GNUNET_CLIENT_Connection *sock = cls; 277 struct GNUNET_CLIENT_Connection *sock = cls;
211 278
279 if (sock->th != NULL)
280 GNUNET_CLIENT_notify_transmit_ready_cancel (sock->th);
212 GNUNET_array_grow (sock->received_buf, sock->received_size, 0); 281 GNUNET_array_grow (sock->received_buf, sock->received_size, 0);
213 GNUNET_free (sock->service_name); 282 GNUNET_free (sock->service_name);
214 GNUNET_free (sock); 283 GNUNET_free (sock);
@@ -216,13 +285,22 @@ finish_cleanup (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
216 285
217 286
218/** 287/**
219 * Destroy connection with the service. 288 * Destroy connection with the service. This will automatically
289 * cancel any pending "receive" request (however, the handler will
290 * *NOT* be called, not even with a NULL message). Any pending
291 * transmission request will also be cancelled UNLESS the callback for
292 * the transmission request has already been called, in which case the
293 * transmission is guaranteed to complete before the socket is fully
294 * destroyed.
295 *
296 * @param sock handle to the service connection
220 */ 297 */
221void 298void
222GNUNET_CLIENT_disconnect (struct GNUNET_CLIENT_Connection *sock) 299GNUNET_CLIENT_disconnect (struct GNUNET_CLIENT_Connection *sock)
223{ 300{
224 GNUNET_assert (sock->sock != NULL); 301 GNUNET_assert (sock->sock != NULL);
225 GNUNET_CONNECTION_destroy (sock->sock); 302 GNUNET_CONNECTION_destroy (sock->sock);
303 sock->sock = NULL;
226 sock->receiver_handler = NULL; 304 sock->receiver_handler = NULL;
227 if (sock->in_receive == GNUNET_YES) 305 if (sock->in_receive == GNUNET_YES)
228 sock->in_receive = GNUNET_SYSERR; 306 sock->in_receive = GNUNET_SYSERR;
@@ -546,66 +624,6 @@ GNUNET_CLIENT_service_test (struct GNUNET_SCHEDULER_Handle *sched,
546 624
547 625
548/** 626/**
549 * Handle for a transmission request.
550 */
551struct GNUNET_CLIENT_TransmitHandle
552{
553 /**
554 * Connection state.
555 */
556 struct GNUNET_CLIENT_Connection *sock;
557
558 /**
559 * Function to call to get the data for transmission.
560 */
561 GNUNET_CONNECTION_TransmitReadyNotify notify;
562
563 /**
564 * Closure for notify.
565 */
566 void *notify_cls;
567
568 /**
569 * Handle to the transmission with the underlying
570 * connection.
571 */
572 struct GNUNET_CONNECTION_TransmitHandle *th;
573
574 /**
575 * Timeout.
576 */
577 struct GNUNET_TIME_Absolute timeout;
578
579 /**
580 * If we are re-trying and are delaying to do so,
581 * handle to the scheduled task managing the delay.
582 */
583 GNUNET_SCHEDULER_TaskIdentifier task;
584
585 /**
586 * Number of bytes requested.
587 */
588 size_t size;
589
590 /**
591 * Are we allowed to re-try to connect without telling
592 * the user (of this API) about the connection troubles?
593 */
594 int auto_retry;
595
596 /**
597 * Number of attempts left for transmitting the request. We may
598 * fail the first time (say because the service is not yet up), in
599 * which case (if auto_retry is set) we wait a bit and re-try
600 * (timeout permitting).
601 */
602 unsigned int attempts_left;
603
604};
605
606
607
608/**
609 * Connection notifies us about failure or success of 627 * Connection notifies us about failure or success of
610 * a transmission request. Either pass it on to our 628 * a transmission request. Either pass it on to our
611 * user or, if possible, retry. 629 * user or, if possible, retry.
@@ -671,6 +689,7 @@ client_notify (void *cls,
671 struct GNUNET_TIME_Relative delay; 689 struct GNUNET_TIME_Relative delay;
672 690
673 th->th = NULL; 691 th->th = NULL;
692 th->sock->th = NULL;
674 if (buf == NULL) 693 if (buf == NULL)
675 { 694 {
676 delay = GNUNET_TIME_absolute_get_remaining (th->timeout); 695 delay = GNUNET_TIME_absolute_get_remaining (th->timeout);
@@ -690,6 +709,7 @@ client_notify (void *cls,
690 th->sock->sock = do_connect (th->sock->sched, 709 th->sock->sock = do_connect (th->sock->sched,
691 th->sock->service_name, 710 th->sock->service_name,
692 th->sock->cfg); 711 th->sock->cfg);
712 GNUNET_assert (NULL != th->sock->sock);
693 delay = GNUNET_TIME_relative_min (delay, GNUNET_TIME_UNIT_SECONDS); 713 delay = GNUNET_TIME_relative_min (delay, GNUNET_TIME_UNIT_SECONDS);
694 th->task = GNUNET_SCHEDULER_add_delayed (th->sock->sched, 714 th->task = GNUNET_SCHEDULER_add_delayed (th->sock->sched,
695 GNUNET_NO, 715 GNUNET_NO,
@@ -698,6 +718,7 @@ client_notify (void *cls,
698 delay, 718 delay,
699 &client_delayed_retry, 719 &client_delayed_retry,
700 th); 720 th);
721 th->sock->th = th;
701 return 0; 722 return 0;
702 } 723 }
703 GNUNET_assert (size >= th->size); 724 GNUNET_assert (size >= th->size);
@@ -738,6 +759,8 @@ GNUNET_CLIENT_notify_transmit_ready (struct GNUNET_CLIENT_Connection *sock,
738{ 759{
739 struct GNUNET_CLIENT_TransmitHandle *th; 760 struct GNUNET_CLIENT_TransmitHandle *th;
740 761
762 if (NULL != sock->th)
763 return NULL;
741 th = GNUNET_malloc (sizeof (struct GNUNET_CLIENT_TransmitHandle)); 764 th = GNUNET_malloc (sizeof (struct GNUNET_CLIENT_TransmitHandle));
742 th->sock = sock; 765 th->sock = sock;
743 th->size = size; 766 th->size = size;
@@ -753,9 +776,11 @@ GNUNET_CLIENT_notify_transmit_ready (struct GNUNET_CLIENT_Connection *sock,
753 th); 776 th);
754 if (NULL == th->th) 777 if (NULL == th->th)
755 { 778 {
779 GNUNET_break (0);
756 GNUNET_free (th); 780 GNUNET_free (th);
757 return NULL; 781 return NULL;
758 } 782 }
783 sock->th = th;
759 return th; 784 return th;
760} 785}
761 786
@@ -779,6 +804,7 @@ GNUNET_CLIENT_notify_transmit_ready_cancel (struct GNUNET_CLIENT_TransmitHandle
779 GNUNET_break (NULL != th->th); 804 GNUNET_break (NULL != th->th);
780 GNUNET_CONNECTION_notify_transmit_ready_cancel (th->th); 805 GNUNET_CONNECTION_notify_transmit_ready_cancel (th->th);
781 } 806 }
807 th->sock->th = NULL;
782 GNUNET_free (th); 808 GNUNET_free (th);
783} 809}
784 810
@@ -886,6 +912,8 @@ GNUNET_CLIENT_transmit_and_get_response (struct GNUNET_CLIENT_Connection *sock,
886 struct TARCtx *tc; 912 struct TARCtx *tc;
887 uint16_t msize; 913 uint16_t msize;
888 914
915 if (NULL != sock->th)
916 return GNUNET_SYSERR;
889 msize = ntohs(hdr->size); 917 msize = ntohs(hdr->size);
890 tc = GNUNET_malloc(sizeof (struct TARCtx) + msize); 918 tc = GNUNET_malloc(sizeof (struct TARCtx) + msize);
891 tc->sock = sock; 919 tc->sock = sock;
@@ -901,6 +929,7 @@ GNUNET_CLIENT_transmit_and_get_response (struct GNUNET_CLIENT_Connection *sock,
901 &transmit_for_response, 929 &transmit_for_response,
902 tc)) 930 tc))
903 { 931 {
932 GNUNET_break (0);
904 GNUNET_free (tc); 933 GNUNET_free (tc);
905 return GNUNET_SYSERR; 934 return GNUNET_SYSERR;
906 } 935 }
diff --git a/src/util/connection.c b/src/util/connection.c
index 2999831a3..6f2b5a349 100644
--- a/src/util/connection.c
+++ b/src/util/connection.c
@@ -771,8 +771,22 @@ try_connect_using_address (void *cls,
771 if (h->sock != NULL) 771 if (h->sock != NULL)
772 return; /* already connected */ 772 return; /* already connected */
773 if (h->dns_active == GNUNET_SYSERR) 773 if (h->dns_active == GNUNET_SYSERR)
774 return; /* already destroyed */ 774 {
775#if DEBUG_CONNECTION
776 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
777 "Connection has already been destroyed.\n");
778#endif
779 return; /* already destroyed */
780 }
775 /* try to connect */ 781 /* try to connect */
782#if DEBUG_CONNECTION
783 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
784 "Trying to connect using address `%s:%u/%s:%u'\n",
785 h->hostname,
786 h->port,
787 GNUNET_a2s (addr, addrlen),
788 h->port);
789#endif
776 ap = GNUNET_malloc (sizeof (struct AddressProbe) + addrlen); 790 ap = GNUNET_malloc (sizeof (struct AddressProbe) + addrlen);
777 ap->addr = (const struct sockaddr*) &ap[1]; 791 ap->addr = (const struct sockaddr*) &ap[1];
778 memcpy (&ap[1], addr, addrlen); 792 memcpy (&ap[1], addr, addrlen);
diff --git a/src/util/network.c b/src/util/network.c
index 30519fe38..1136614e7 100644
--- a/src/util/network.c
+++ b/src/util/network.c
@@ -29,7 +29,7 @@
29#include "disk.h" 29#include "disk.h"
30#include "gnunet_container_lib.h" 30#include "gnunet_container_lib.h"
31 31
32#define DEBUG_SOCK GNUNET_NO 32#define DEBUG_NETWORK GNUNET_YES
33 33
34#ifndef INVALID_SOCKET 34#ifndef INVALID_SOCKET
35#define INVALID_SOCKET -1 35#define INVALID_SOCKET -1
@@ -857,7 +857,7 @@ GNUNET_NETWORK_socket_select (struct GNUNET_NETWORK_FDSet *rfds,
857 if (errno == ENOTSOCK) 857 if (errno == ENOTSOCK)
858 errno = EBADF; 858 errno = EBADF;
859 859
860#if DEBUG_SOCK 860#if DEBUG_NETWORK
861 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "select"); 861 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "select");
862#endif 862#endif
863 863
@@ -889,7 +889,7 @@ GNUNET_NETWORK_socket_select (struct GNUNET_NETWORK_FDSet *rfds,
889 889
890 retcode = -1; 890 retcode = -1;
891 SetErrnoFromWinError (GetLastError ()); 891 SetErrnoFromWinError (GetLastError ());
892#if DEBUG_SOCK 892#if DEBUG_NETWORK
893 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "PeekNamedPipe"); 893 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "PeekNamedPipe");
894#endif 894#endif
895 goto select_loop_end; 895 goto select_loop_end;
diff --git a/src/util/resolver_api.c b/src/util/resolver_api.c
index 284a3cef6..e1198a9a3 100644
--- a/src/util/resolver_api.c
+++ b/src/util/resolver_api.c
@@ -33,40 +33,81 @@
33 33
34 34
35/** 35/**
36 * FIXME. 36 * Maximum supported length for a hostname
37 */ 37 */
38struct GetAddressContext 38#define MAX_HOSTNAME 1024
39
40
41/**
42 * Possible hostnames for "loopback".
43 */
44static const char *loopback[] = {
45 "localhost",
46 "ip6-localnet",
47 NULL
48};
49
50
51/**
52 * Handle to a request given to the resolver. Can be used to cancel
53 * the request prior to the timeout or successful execution. Also
54 * used to track our internal state for the request.
55 */
56struct GNUNET_RESOLVER_RequestHandle
39{ 57{
40 58
41 /** 59 /**
42 * FIXME. 60 * Callback if this is an name resolution request,
61 * otherwise NULL.
62 */
63 GNUNET_RESOLVER_AddressCallback addr_callback;
64
65 /**
66 * Callback if this is a reverse lookup request,
67 * otherwise NULL.
43 */ 68 */
44 GNUNET_RESOLVER_AddressCallback callback; 69 GNUNET_RESOLVER_HostnameCallback name_callback;
45 70
46 /** 71 /**
47 * Closure for "callback". 72 * Closure for the respective "callback".
48 */ 73 */
49 void *cls; 74 void *cls;
50 75
51 /** 76 /**
52 * FIXME. 77 * Our connection to the resolver service.
53 */ 78 */
54 struct GNUNET_CLIENT_Connection *client; 79 struct GNUNET_CLIENT_Connection *client;
55 80
56 /** 81 /**
57 * FIXME. 82 * Our scheduler.
83 */
84 struct GNUNET_SCHEDULER_Handle *sched;
85
86 /**
87 * Name of the host that we are resolving.
88 */
89 const char *hostname;
90
91 /**
92 * When should this request time out?
58 */ 93 */
59 struct GNUNET_TIME_Absolute timeout; 94 struct GNUNET_TIME_Absolute timeout;
60};
61 95
96 /**
97 * Task handle for numeric lookups.
98 */
99 GNUNET_SCHEDULER_TaskIdentifier task;
100
101 /**
102 * Desired address family.
103 */
104 int domain;
62 105
63/** 106 /**
64 * Possible hostnames for "loopback". 107 * Length of the "struct sockaddr" that follows this
65 */ 108 * struct (only for reverse lookup).
66static const char *loopback[] = { 109 */
67 "localhost", 110 socklen_t salen;
68 "ip6-localnet",
69 NULL
70}; 111};
71 112
72 113
@@ -79,9 +120,20 @@ check_config (const struct GNUNET_CONFIGURATION_Handle *cfg)
79{ 120{
80 char *hostname; 121 char *hostname;
81 unsigned int i; 122 unsigned int i;
82 struct in_addr v4; 123 struct sockaddr_in v4;
83 struct in6_addr v6; 124 struct sockaddr_in6 v6;
84 125
126 memset (&v4, 0, sizeof(v4));
127 v4.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
128 v4.sin_family = AF_INET;
129#if HAVE_SOCKADDR_IN_SIN_LEN
130 v4.sin_len = sizeof(v4);
131#endif
132 memset (&v6, 0, sizeof(v6));
133 v6.sin6_family = AF_INET6;
134#if HAVE_SOCKADDR_IN_SIN_LEN
135 v6.sin6_len = sizeof(v6);
136#endif
85 if (GNUNET_OK != 137 if (GNUNET_OK !=
86 GNUNET_CONFIGURATION_get_value_string (cfg, 138 GNUNET_CONFIGURATION_get_value_string (cfg,
87 "resolver", 139 "resolver",
@@ -94,10 +146,10 @@ check_config (const struct GNUNET_CONFIGURATION_Handle *cfg)
94 "resolver"); 146 "resolver");
95 GNUNET_assert (0); 147 GNUNET_assert (0);
96 } 148 }
97 if ( (0 == inet_pton (AF_INET, 149 if ( (1 != inet_pton (AF_INET,
98 hostname, 150 hostname,
99 &v4)) || 151 &v4)) ||
100 (0 == inet_pton (AF_INET6, 152 (1 != inet_pton (AF_INET6,
101 hostname, 153 hostname,
102 &v6)) ) 154 &v6)) )
103 { 155 {
@@ -106,14 +158,15 @@ check_config (const struct GNUNET_CONFIGURATION_Handle *cfg)
106 } 158 }
107 i = 0; 159 i = 0;
108 while (loopback[i] != NULL) 160 while (loopback[i] != NULL)
109 if (0 == strcmp (loopback[i++], hostname)) 161 if (0 == strcasecmp (loopback[i++], hostname))
110 { 162 {
111 GNUNET_free (hostname); 163 GNUNET_free (hostname);
112 return; 164 return;
113 } 165 }
114 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 166 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
115 _("Must specify `%s' for `%s' in configuration!\n"), 167 _("Must specify `%s' or numeric IP address for `%s' of `%s' in configuration!\n"),
116 "localhost", 168 "localhost",
169 "HOSTNAME",
117 "resolver"); 170 "resolver");
118 GNUNET_free (hostname); 171 GNUNET_free (hostname);
119 GNUNET_assert (0); 172 GNUNET_assert (0);
@@ -163,15 +216,16 @@ no_resolve (const struct sockaddr *sa, socklen_t salen)
163 216
164 217
165/** 218/**
166 * FIXME 219 * Process the reply from the resolver (which is presumably
220 * the numeric IP address for a name resolution request).
167 * 221 *
168 * @param cls FIXME 222 * @param cls the "GNUNET_RESOLVER_RequestHandle" for which this is a reply
169 * @param msg FIXME 223 * @param msg reply from the resolver or NULL on error
170 */ 224 */
171static void 225static void
172handle_address_response (void *cls, const struct GNUNET_MessageHeader *msg) 226handle_address_response (void *cls, const struct GNUNET_MessageHeader *msg)
173{ 227{
174 struct GetAddressContext *gac = cls; 228 struct GNUNET_RESOLVER_RequestHandle *rh = cls;
175 uint16_t size; 229 uint16_t size;
176 const struct sockaddr *sa; 230 const struct sockaddr *sa;
177 socklen_t salen; 231 socklen_t salen;
@@ -181,17 +235,17 @@ handle_address_response (void *cls, const struct GNUNET_MessageHeader *msg)
181 { 235 {
182 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 236 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
183 _("Timeout trying to resolve hostname.\n")); 237 _("Timeout trying to resolve hostname.\n"));
184 gac->callback (gac->cls, NULL, 0); 238 rh->addr_callback (rh->cls, NULL, 0);
185 GNUNET_CLIENT_disconnect (gac->client); 239 GNUNET_CLIENT_disconnect (rh->client);
186 GNUNET_free (gac); 240 GNUNET_free (rh);
187 return; 241 return;
188 } 242 }
189 if (GNUNET_MESSAGE_TYPE_RESOLVER_RESPONSE != ntohs (msg->type)) 243 if (GNUNET_MESSAGE_TYPE_RESOLVER_RESPONSE != ntohs (msg->type))
190 { 244 {
191 GNUNET_break (0); 245 GNUNET_break (0);
192 gac->callback (gac->cls, NULL, 0); 246 rh->addr_callback (rh->cls, NULL, 0);
193 GNUNET_CLIENT_disconnect (gac->client); 247 GNUNET_CLIENT_disconnect (rh->client);
194 GNUNET_free (gac); 248 GNUNET_free (rh);
195 return; 249 return;
196 } 250 }
197 251
@@ -202,9 +256,9 @@ handle_address_response (void *cls, const struct GNUNET_MessageHeader *msg)
202 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 256 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
203 _("Received end message resolving hostname.\n")); 257 _("Received end message resolving hostname.\n"));
204#endif 258#endif
205 gac->callback (gac->cls, NULL, 0); 259 rh->addr_callback (rh->cls, NULL, 0);
206 GNUNET_CLIENT_disconnect (gac->client); 260 GNUNET_CLIENT_disconnect (rh->client);
207 GNUNET_free (gac); 261 GNUNET_free (rh);
208 return; 262 return;
209 } 263 }
210 sa = (const struct sockaddr *) &msg[1]; 264 sa = (const struct sockaddr *) &msg[1];
@@ -212,56 +266,45 @@ handle_address_response (void *cls, const struct GNUNET_MessageHeader *msg)
212 if (salen < sizeof (struct sockaddr)) 266 if (salen < sizeof (struct sockaddr))
213 { 267 {
214 GNUNET_break (0); 268 GNUNET_break (0);
215 gac->callback (gac->cls, NULL, 0); 269 rh->addr_callback (rh->cls, NULL, 0);
216 GNUNET_CLIENT_disconnect (gac->client); 270 GNUNET_CLIENT_disconnect (rh->client);
217 GNUNET_free (gac); 271 GNUNET_free (rh);
218 return; 272 return;
219 } 273 }
220#if DEBUG_RESOLVER 274#if DEBUG_RESOLVER
221 { 275 {
222 char *ips = no_resolve (sa, salen); 276 char *ips = no_resolve (sa, salen);
223 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _("Resolver returns `%s'.\n"), ips); 277 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
278 "Resolver returns `%s'.\n",
279 ips);
224 GNUNET_free (ips); 280 GNUNET_free (ips);
225 } 281 }
226#endif 282#endif
227 gac->callback (gac->cls, sa, salen); 283 rh->addr_callback (rh->cls, sa, salen);
228 GNUNET_CLIENT_receive (gac->client, 284 GNUNET_CLIENT_receive (rh->client,
229 &handle_address_response, 285 &handle_address_response,
230 gac, 286 rh,
231 GNUNET_TIME_absolute_get_remaining (gac->timeout)); 287 GNUNET_TIME_absolute_get_remaining (rh->timeout));
232} 288}
233 289
234 290
235/** 291/**
236 * Convert a string to one or more IP addresses. 292 * We've been asked to lookup the address for a hostname and were
293 * given a valid numeric string. Perform the callbacks for the
294 * numeric addresses.
237 * 295 *
238 * @param sched scheduler to use 296 * @param cls struct GNUNET_RESOLVER_RequestHandle for the request
239 * @param cfg configuration to use 297 * @param tc unused scheduler context
240 * @param hostname the hostname to resolve
241 * @param domain AF_INET or AF_INET6; use AF_UNSPEC for "any"
242 * @param callback function to call with addresses
243 * @param callback_cls closure for callback
244 * @param timeout how long to try resolving
245 */ 298 */
246void 299static void
247GNUNET_RESOLVER_ip_get (struct GNUNET_SCHEDULER_Handle *sched, 300numeric_resolution (void *cls,
248 const struct GNUNET_CONFIGURATION_Handle *cfg, 301 const struct GNUNET_SCHEDULER_TaskContext *tc)
249 const char *hostname,
250 int domain,
251 struct GNUNET_TIME_Relative timeout,
252 GNUNET_RESOLVER_AddressCallback callback,
253 void *callback_cls)
254{ 302{
255 struct GNUNET_CLIENT_Connection *client; 303 struct GNUNET_RESOLVER_RequestHandle *rh = cls;
256 struct GNUNET_RESOLVER_GetMessage *msg;
257 struct GetAddressContext *actx;
258 size_t slen;
259 unsigned int i;
260 struct sockaddr_in v4; 304 struct sockaddr_in v4;
261 struct sockaddr_in6 v6; 305 struct sockaddr_in6 v6;
262 306
263 memset (&v4, 0, sizeof(v4)); 307 memset (&v4, 0, sizeof(v4));
264 v4.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
265 v4.sin_family = AF_INET; 308 v4.sin_family = AF_INET;
266#if HAVE_SOCKADDR_IN_SIN_LEN 309#if HAVE_SOCKADDR_IN_SIN_LEN
267 v4.sin_len = sizeof(v4); 310 v4.sin_len = sizeof(v4);
@@ -271,97 +314,202 @@ GNUNET_RESOLVER_ip_get (struct GNUNET_SCHEDULER_Handle *sched,
271#if HAVE_SOCKADDR_IN_SIN_LEN 314#if HAVE_SOCKADDR_IN_SIN_LEN
272 v6.sin6_len = sizeof(v6); 315 v6.sin6_len = sizeof(v6);
273#endif 316#endif
274 /* first, check if this is a numeric address */ 317
275 if ( ( (domain == AF_UNSPEC) || (domain == AF_INET) ) && 318 if ( ( (rh->domain == AF_UNSPEC) || (rh->domain == AF_INET) ) &&
276 (1 == inet_pton (AF_INET, 319 (1 == inet_pton (AF_INET,
277 hostname, 320 rh->hostname,
278 &v4.sin_addr)) ) 321 &v4.sin_addr)) )
279 { 322 {
280 callback (callback_cls, 323 rh->addr_callback (rh->cls,
281 (const struct sockaddr*) &v4, 324 (const struct sockaddr*) &v4,
282 sizeof(v4)); 325 sizeof(v4));
283 if ( (domain == AF_UNSPEC) && 326 if ( (rh->domain == AF_UNSPEC) &&
284 (1 == inet_pton (AF_INET6, 327 (1 == inet_pton (AF_INET6,
285 hostname, 328 rh->hostname,
286 &v6.sin6_addr)) ) 329 &v6.sin6_addr)) )
287 { 330 {
288 /* this can happen on some systems IF "hostname" is "localhost" */ 331 /* this can happen on some systems IF "hostname" is "localhost" */
289 callback (callback_cls, 332 rh->addr_callback (rh->cls,
290 (const struct sockaddr*) &v6, 333 (const struct sockaddr*) &v6,
291 sizeof(v6)); 334 sizeof(v6));
292 } 335 }
293 callback (callback_cls, NULL, 0); 336 rh->addr_callback (rh->cls, NULL, 0);
337 GNUNET_free (rh);
294 return; 338 return;
295 } 339 }
296 if ( ( (domain == AF_UNSPEC) || (domain == AF_INET6) ) && 340 if ( ( (rh->domain == AF_UNSPEC) || (rh->domain == AF_INET6) ) &&
297 (1 == inet_pton (AF_INET6, 341 (1 == inet_pton (AF_INET6,
298 hostname, 342 rh->hostname,
299 &v6.sin6_addr)) ) 343 &v6.sin6_addr)) )
300 { 344 {
301 callback (callback_cls, 345 rh->addr_callback (rh->cls,
302 (const struct sockaddr*) &v6, 346 (const struct sockaddr*) &v6,
303 sizeof(v6)); 347 sizeof(v6));
304 callback (callback_cls, NULL, 0); 348 rh->addr_callback (rh->cls, NULL, 0);
349 GNUNET_free (rh);
305 return; 350 return;
306 } 351 }
352 /* why are we here? this task should not have been scheduled! */
353 GNUNET_assert (0);
354 GNUNET_free (rh);
355}
356
357
358
359/**
360 * We've been asked to lookup the address for a hostname and were
361 * given a variant of "loopback". Perform the callbacks for the
362 * respective loopback numeric addresses.
363 *
364 * @param cls struct GNUNET_RESOLVER_RequestHandle for the request
365 * @param tc unused scheduler context
366 */
367static void
368loopback_resolution (void *cls,
369 const struct GNUNET_SCHEDULER_TaskContext *tc)
370{
371 struct GNUNET_RESOLVER_RequestHandle *rh = cls;
372 struct sockaddr_in v4;
373 struct sockaddr_in6 v6;
374
375 memset (&v4, 0, sizeof(v4));
376 v4.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
377 v4.sin_family = AF_INET;
378#if HAVE_SOCKADDR_IN_SIN_LEN
379 v4.sin_len = sizeof(v4);
380#endif
381 memset (&v6, 0, sizeof(v6));
382 v6.sin6_family = AF_INET6;
383#if HAVE_SOCKADDR_IN_SIN_LEN
384 v6.sin6_len = sizeof(v6);
385#endif
386 v6.sin6_addr = in6addr_loopback;
387 switch (rh->domain)
388 {
389 case AF_INET:
390 rh->addr_callback (rh->cls,
391 (const struct sockaddr*) &v4,
392 sizeof(v4));
393 break;
394 case AF_INET6:
395 rh->addr_callback (rh->cls,
396 (const struct sockaddr*) &v6,
397 sizeof(v6));
398 break;
399 case AF_UNSPEC:
400 rh->addr_callback (rh->cls,
401 (const struct sockaddr*) &v6,
402 sizeof(v6));
403 rh->addr_callback (rh->cls,
404 (const struct sockaddr*) &v4,
405 sizeof(v4));
406 break;
407 default:
408 GNUNET_break (0);
409 break;
410 }
411 rh->addr_callback (rh->cls, NULL, 0);
412 GNUNET_free (rh);
413}
414
415
416/**
417 * Convert a string to one or more IP addresses.
418 *
419 * @param sched scheduler to use
420 * @param cfg configuration to use
421 * @param hostname the hostname to resolve
422 * @param domain AF_INET or AF_INET6; use AF_UNSPEC for "any"
423 * @param callback function to call with addresses
424 * @param callback_cls closure for callback
425 * @param timeout how long to try resolving
426 * @return handle that can be used to cancel the request, NULL on error
427 */
428struct GNUNET_RESOLVER_RequestHandle *
429GNUNET_RESOLVER_ip_get (struct GNUNET_SCHEDULER_Handle *sched,
430 const struct GNUNET_CONFIGURATION_Handle *cfg,
431 const char *hostname,
432 int domain,
433 struct GNUNET_TIME_Relative timeout,
434 GNUNET_RESOLVER_AddressCallback callback,
435 void *callback_cls)
436{
437 struct GNUNET_CLIENT_Connection *client;
438 struct GNUNET_RESOLVER_GetMessage *msg;
439 struct GNUNET_RESOLVER_RequestHandle *rh;
440 size_t slen;
441 unsigned int i;
442 struct in_addr v4;
443 struct in6_addr v6;
444 char buf[GNUNET_SERVER_MAX_MESSAGE_SIZE];
445
307 check_config (cfg); 446 check_config (cfg);
308 /* then, check if this is a loopback address */
309 i = 0;
310 while (loopback[i] != NULL)
311 if (0 == strcmp (loopback[i++], hostname))
312 {
313 v4.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
314 v6.sin6_addr = in6addr_loopback;
315 switch (domain)
316 {
317 case AF_INET:
318 callback (callback_cls,
319 (const struct sockaddr*) &v4,
320 sizeof(v4));
321 break;
322 case AF_INET6:
323 callback (callback_cls,
324 (const struct sockaddr*) &v6,
325 sizeof(v6));
326 break;
327 case AF_UNSPEC:
328 callback (callback_cls,
329 (const struct sockaddr*) &v6,
330 sizeof(v6));
331 callback (callback_cls,
332 (const struct sockaddr*) &v4,
333 sizeof(v4));
334 break;
335 }
336 callback (callback_cls, NULL, 0);
337 return;
338 }
339 slen = strlen (hostname) + 1; 447 slen = strlen (hostname) + 1;
340 if (slen + sizeof (struct GNUNET_RESOLVER_GetMessage) > 448 if (slen + sizeof (struct GNUNET_RESOLVER_GetMessage) >
341 GNUNET_SERVER_MAX_MESSAGE_SIZE) 449 GNUNET_SERVER_MAX_MESSAGE_SIZE)
342 { 450 {
343 GNUNET_break (0); 451 GNUNET_break (0);
344 callback (callback_cls, NULL, 0); 452 return NULL;
345 return; 453 }
454 rh = GNUNET_malloc (sizeof(struct GNUNET_RESOLVER_RequestHandle) + slen);
455 rh->client = client;
456 rh->sched = sched;
457 rh->domain = domain;
458 rh->addr_callback = callback;
459 rh->cls = callback_cls;
460 memcpy (&rh[1], hostname, slen);
461 rh->hostname = (const char*) &rh[1];
462 rh->timeout = GNUNET_TIME_relative_to_absolute (timeout);
463
464 /* first, check if this is a numeric address */
465 if ( ( (1 == inet_pton (AF_INET,
466 hostname,
467 &v4)) &&
468 ( (domain == AF_INET) || (domain == AF_UNSPEC)) ) ||
469 ( (1 == inet_pton (AF_INET6,
470 hostname,
471 &v6)) &&
472 ( (domain == AF_INET6) || (domain == AF_UNSPEC)) ) )
473 {
474 rh->task = GNUNET_SCHEDULER_add_delayed (sched,
475 GNUNET_NO,
476 GNUNET_SCHEDULER_PRIORITY_KEEP,
477 GNUNET_SCHEDULER_NO_TASK,
478 GNUNET_TIME_UNIT_ZERO,
479 &numeric_resolution,
480 rh);
481 return rh;
346 } 482 }
483 /* then, check if this is a loopback address */
484 i = 0;
485 while (loopback[i] != NULL)
486 if (0 == strcasecmp (loopback[i++], hostname))
487 {
488 rh->task = GNUNET_SCHEDULER_add_delayed (sched,
489 GNUNET_NO,
490 GNUNET_SCHEDULER_PRIORITY_KEEP,
491 GNUNET_SCHEDULER_NO_TASK,
492 GNUNET_TIME_UNIT_ZERO,
493 &loopback_resolution,
494 rh);
495 return rh;
496 }
497
347 client = GNUNET_CLIENT_connect (sched, "resolver", cfg); 498 client = GNUNET_CLIENT_connect (sched, "resolver", cfg);
348 if (client == NULL) 499 if (client == NULL)
349 { 500 {
350 callback (callback_cls, NULL, 0); 501 GNUNET_free (rh);
351 return; 502 return NULL;
352 } 503 }
353 msg = GNUNET_malloc (sizeof (struct GNUNET_RESOLVER_GetMessage) + slen); 504 rh->client = client;
505
506 msg = (struct GNUNET_RESOLVER_GetMessage*) buf;
354 msg->header.size = 507 msg->header.size =
355 htons (sizeof (struct GNUNET_RESOLVER_GetMessage) + slen); 508 htons (sizeof (struct GNUNET_RESOLVER_GetMessage) + slen);
356 msg->header.type = htons (GNUNET_MESSAGE_TYPE_RESOLVER_REQUEST); 509 msg->header.type = htons (GNUNET_MESSAGE_TYPE_RESOLVER_REQUEST);
357 msg->direction = htonl (GNUNET_NO); 510 msg->direction = htonl (GNUNET_NO);
358 msg->domain = htonl (domain); 511 msg->domain = htonl (domain);
359 memcpy (&msg[1], hostname, slen); 512 memcpy (&msg[1], hostname, slen);
360 actx = GNUNET_malloc (sizeof (struct GetAddressContext));
361 actx->callback = callback;
362 actx->cls = callback_cls;
363 actx->client = client;
364 actx->timeout = GNUNET_TIME_relative_to_absolute (timeout);
365 513
366#if DEBUG_RESOLVER 514#if DEBUG_RESOLVER
367 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 515 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
@@ -374,56 +522,27 @@ GNUNET_RESOLVER_ip_get (struct GNUNET_SCHEDULER_Handle *sched,
374 timeout, 522 timeout,
375 GNUNET_YES, 523 GNUNET_YES,
376 &handle_address_response, 524 &handle_address_response,
377 actx)) 525 rh))
378 { 526 {
379 GNUNET_free (msg); 527 GNUNET_free (rh);
380 GNUNET_free (actx);
381 callback (callback_cls, NULL, 0);
382 GNUNET_CLIENT_disconnect (client); 528 GNUNET_CLIENT_disconnect (client);
383 return; 529 return NULL;
384 } 530 }
385 GNUNET_free (msg); 531 return rh;
386} 532}
387 533
388 534
389/** 535/**
390 * FIXME. 536 * Process response with a hostname for a reverse DNS lookup.
391 */
392struct GetHostnameContext
393{
394
395 /**
396 * FIXME.
397 */
398 GNUNET_RESOLVER_HostnameCallback callback;
399
400 /**
401 * FIXME.
402 */
403 void *cls;
404
405 /**
406 * FIXME.
407 */
408 struct GNUNET_CLIENT_Connection *client;
409
410 /**
411 * FIXME.
412 */
413 struct GNUNET_TIME_Absolute timeout;
414};
415
416
417/**
418 * FIXME.
419 * 537 *
420 * @param cls FIXME 538 * @param cls our "struct GNUNET_RESOLVER_RequestHandle" context
421 * @param msg FIXME 539 * @param msg message with the hostname, NULL on error
422 */ 540 */
423static void 541static void
424handle_hostname_response (void *cls, const struct GNUNET_MessageHeader *msg) 542handle_hostname_response (void *cls,
543 const struct GNUNET_MessageHeader *msg)
425{ 544{
426 struct GetHostnameContext *ghc = cls; 545 struct GNUNET_RESOLVER_RequestHandle *rh = cls;
427 uint16_t size; 546 uint16_t size;
428 const char *hostname; 547 const char *hostname;
429 548
@@ -431,9 +550,9 @@ handle_hostname_response (void *cls, const struct GNUNET_MessageHeader *msg)
431 { 550 {
432 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 551 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
433 _("Timeout trying to resolve IP address.\n")); 552 _("Timeout trying to resolve IP address.\n"));
434 ghc->callback (ghc->cls, NULL); 553 rh->name_callback (rh->cls, NULL);
435 GNUNET_CLIENT_disconnect (ghc->client); 554 GNUNET_CLIENT_disconnect (rh->client);
436 GNUNET_free (ghc); 555 GNUNET_free (rh);
437 return; 556 return;
438 } 557 }
439 size = ntohs (msg->size); 558 size = ntohs (msg->size);
@@ -443,32 +562,64 @@ handle_hostname_response (void *cls, const struct GNUNET_MessageHeader *msg)
443 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 562 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
444 _("Received end message resolving IP address.\n")); 563 _("Received end message resolving IP address.\n"));
445#endif 564#endif
446 ghc->callback (ghc->cls, NULL); 565 rh->name_callback (rh->cls, NULL);
447 GNUNET_CLIENT_disconnect (ghc->client); 566 GNUNET_CLIENT_disconnect (rh->client);
448 GNUNET_free (ghc); 567 GNUNET_free (rh);
449 return; 568 return;
450 } 569 }
451 hostname = (const char *) &msg[1]; 570 hostname = (const char *) &msg[1];
452 if (hostname[size - sizeof (struct GNUNET_MessageHeader) - 1] != '\0') 571 if (hostname[size - sizeof (struct GNUNET_MessageHeader) - 1] != '\0')
453 { 572 {
454 GNUNET_break (0); 573 GNUNET_break (0);
455 ghc->callback (ghc->cls, NULL); 574 rh->name_callback (rh->cls, NULL);
456 GNUNET_CLIENT_disconnect (ghc->client); 575 GNUNET_CLIENT_disconnect (rh->client);
457 GNUNET_free (ghc); 576 GNUNET_free (rh);
458 return; 577 return;
459 } 578 }
460#if DEBUG_RESOLVER 579#if DEBUG_RESOLVER
461 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 580 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
462 _("Resolver returns `%s'.\n"), hostname); 581 _("Resolver returns `%s'.\n"), hostname);
463#endif 582#endif
464 ghc->callback (ghc->cls, hostname); 583 rh->name_callback (rh->cls, hostname);
465 GNUNET_CLIENT_receive (ghc->client, 584 GNUNET_CLIENT_receive (rh->client,
466 &handle_hostname_response, 585 &handle_hostname_response,
467 ghc, 586 rh,
468 GNUNET_TIME_absolute_get_remaining (ghc->timeout)); 587 GNUNET_TIME_absolute_get_remaining (rh->timeout));
469} 588}
470 589
471 590
591
592/**
593 * We've been asked to convert an address to a string without
594 * a reverse lookup. Do it.
595 *
596 * @param cls struct GNUNET_RESOLVER_RequestHandle for the request
597 * @param tc unused scheduler context
598 */
599static void
600numeric_reverse (void *cls,
601 const struct GNUNET_SCHEDULER_TaskContext *tc)
602{
603 struct GNUNET_RESOLVER_RequestHandle *rh = cls;
604 char *result;
605
606 result = no_resolve ((const struct sockaddr*) &rh[1],
607 rh->salen);
608#if DEBUG_RESOLVER
609 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
610 _("Resolver returns `%s'.\n"), result);
611#endif
612 if (result != NULL)
613 {
614 rh->name_callback (rh->cls, result);
615 GNUNET_free (result);
616 }
617 rh->name_callback (rh->cls, NULL);
618 GNUNET_free (rh);
619}
620
621
622
472/** 623/**
473 * Get an IP address as a string. 624 * Get an IP address as a string.
474 * 625 *
@@ -480,8 +631,9 @@ handle_hostname_response (void *cls, const struct GNUNET_MessageHeader *msg)
480 * @param timeout how long to try resolving 631 * @param timeout how long to try resolving
481 * @param callback function to call with hostnames 632 * @param callback function to call with hostnames
482 * @param cls closure for callback 633 * @param cls closure for callback
634 * @return handle that can be used to cancel the request
483 */ 635 */
484void 636struct GNUNET_RESOLVER_RequestHandle *
485GNUNET_RESOLVER_hostname_get (struct GNUNET_SCHEDULER_Handle *sched, 637GNUNET_RESOLVER_hostname_get (struct GNUNET_SCHEDULER_Handle *sched,
486 const struct GNUNET_CONFIGURATION_Handle *cfg, 638 const struct GNUNET_CONFIGURATION_Handle *cfg,
487 const struct sockaddr *sa, 639 const struct sockaddr *sa,
@@ -491,41 +643,47 @@ GNUNET_RESOLVER_hostname_get (struct GNUNET_SCHEDULER_Handle *sched,
491 GNUNET_RESOLVER_HostnameCallback callback, 643 GNUNET_RESOLVER_HostnameCallback callback,
492 void *cls) 644 void *cls)
493{ 645{
494 char *result;
495 struct GNUNET_CLIENT_Connection *client; 646 struct GNUNET_CLIENT_Connection *client;
496 struct GNUNET_RESOLVER_GetMessage *msg; 647 struct GNUNET_RESOLVER_GetMessage *msg;
497 struct GetHostnameContext *hctx; 648 struct GNUNET_RESOLVER_RequestHandle *rh;
649 char buf[GNUNET_SERVER_MAX_MESSAGE_SIZE];
498 650
499 check_config (cfg); 651 check_config (cfg);
652 rh = GNUNET_malloc (sizeof (struct GNUNET_RESOLVER_RequestHandle) + salen);
653 rh->name_callback = callback;
654 rh->cls = cls;
655 rh->timeout = GNUNET_TIME_relative_to_absolute (timeout);
656 rh->sched = sched;
657 rh->salen = salen;
658 memcpy (&rh[1], sa, salen);
659
500 if (GNUNET_NO == do_resolve) 660 if (GNUNET_NO == do_resolve)
501 { 661 {
502 result = no_resolve (sa, salen); 662 rh->task = GNUNET_SCHEDULER_add_delayed (sched,
503#if DEBUG_RESOLVER 663 GNUNET_NO,
504 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 664 GNUNET_SCHEDULER_PRIORITY_KEEP,
505 _("Resolver returns `%s'.\n"), result); 665 GNUNET_SCHEDULER_NO_TASK,
506#endif 666 GNUNET_TIME_UNIT_ZERO,
507 callback (cls, result); 667 &numeric_reverse,
508 if (result != NULL) 668 rh);
509 { 669 return rh;
510 GNUNET_free (result);
511 callback (cls, NULL);
512 }
513 return;
514 } 670 }
515 if (salen + sizeof (struct GNUNET_RESOLVER_GetMessage) > 671 if (salen + sizeof (struct GNUNET_RESOLVER_GetMessage) >
516 GNUNET_SERVER_MAX_MESSAGE_SIZE) 672 GNUNET_SERVER_MAX_MESSAGE_SIZE)
517 { 673 {
518 GNUNET_break (0); 674 GNUNET_break (0);
519 callback (cls, NULL); 675 GNUNET_free (rh);
520 return; 676 return NULL;
521 } 677 }
522 client = GNUNET_CLIENT_connect (sched, "resolver", cfg); 678 client = GNUNET_CLIENT_connect (sched, "resolver", cfg);
523 if (client == NULL) 679 if (client == NULL)
524 { 680 {
525 callback (cls, NULL); 681 GNUNET_free (rh);
526 return; 682 return NULL;
527 } 683 }
528 msg = GNUNET_malloc (sizeof (struct GNUNET_RESOLVER_GetMessage) + salen); 684 rh->client = client;
685
686 msg = (struct GNUNET_RESOLVER_GetMessage*) buf;
529 msg->header.size = 687 msg->header.size =
530 htons (sizeof (struct GNUNET_RESOLVER_GetMessage) + salen); 688 htons (sizeof (struct GNUNET_RESOLVER_GetMessage) + salen);
531 msg->header.type = htons (GNUNET_MESSAGE_TYPE_RESOLVER_REQUEST); 689 msg->header.type = htons (GNUNET_MESSAGE_TYPE_RESOLVER_REQUEST);
@@ -536,36 +694,24 @@ GNUNET_RESOLVER_hostname_get (struct GNUNET_SCHEDULER_Handle *sched,
536 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 694 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
537 _("Resolver requests DNS resolution of IP address.\n")); 695 _("Resolver requests DNS resolution of IP address.\n"));
538#endif 696#endif
539 hctx = GNUNET_malloc (sizeof (struct GetHostnameContext));
540 hctx->callback = callback;
541 hctx->cls = cls;
542 hctx->client = client;
543 hctx->timeout = GNUNET_TIME_relative_to_absolute (timeout);
544 if (GNUNET_OK != 697 if (GNUNET_OK !=
545 GNUNET_CLIENT_transmit_and_get_response (client, 698 GNUNET_CLIENT_transmit_and_get_response (client,
546 &msg->header, 699 &msg->header,
547 timeout, 700 timeout,
548 GNUNET_YES, 701 GNUNET_YES,
549 &handle_hostname_response, 702 &handle_hostname_response,
550 hctx)) 703 rh))
551 { 704 {
552 GNUNET_free (msg);
553 callback (cls, NULL);
554 GNUNET_CLIENT_disconnect (client); 705 GNUNET_CLIENT_disconnect (client);
555 GNUNET_free (hctx); 706 GNUNET_free (rh);
556 return; 707 return NULL;
557 } 708 }
558 GNUNET_free (msg); 709 return rh;
559} 710}
560 711
561/**
562 * Maximum supported length of hostname
563 */
564#define MAX_HOSTNAME 1024
565
566 712
567/** 713/**
568 * Resolve our hostname to an IP address. 714 * Perform a reverse DNS lookup.
569 * 715 *
570 * @param sched scheduler to use 716 * @param sched scheduler to use
571 * @param cfg configuration to use 717 * @param cfg configuration to use
@@ -573,8 +719,9 @@ GNUNET_RESOLVER_hostname_get (struct GNUNET_SCHEDULER_Handle *sched,
573 * @param callback function to call with addresses 719 * @param callback function to call with addresses
574 * @param cls closure for callback 720 * @param cls closure for callback
575 * @param timeout how long to try resolving 721 * @param timeout how long to try resolving
722 * @return handle that can be used to cancel the request, NULL on error
576 */ 723 */
577void 724struct GNUNET_RESOLVER_RequestHandle *
578GNUNET_RESOLVER_hostname_resolve (struct GNUNET_SCHEDULER_Handle *sched, 725GNUNET_RESOLVER_hostname_resolve (struct GNUNET_SCHEDULER_Handle *sched,
579 const struct GNUNET_CONFIGURATION_Handle *cfg, 726 const struct GNUNET_CONFIGURATION_Handle *cfg,
580 int domain, 727 int domain,
@@ -589,18 +736,36 @@ GNUNET_RESOLVER_hostname_resolve (struct GNUNET_SCHEDULER_Handle *sched,
589 { 736 {
590 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR | 737 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR |
591 GNUNET_ERROR_TYPE_BULK, "gethostname"); 738 GNUNET_ERROR_TYPE_BULK, "gethostname");
592 callback (cls, NULL, 0); 739 return NULL;
593 return;
594 } 740 }
595#if DEBUG_RESOLVER 741#if DEBUG_RESOLVER
596 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 742 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
597 _("Resolving our hostname `%s'\n"), hostname); 743 _("Resolving our hostname `%s'\n"), hostname);
598#endif 744#endif
599 GNUNET_RESOLVER_ip_get (sched, 745 return GNUNET_RESOLVER_ip_get (sched,
600 cfg, hostname, domain, timeout, callback, cls); 746 cfg, hostname, domain, timeout, callback, cls);
601} 747}
602 748
603 749
750/**
751 * Cancel a request that is still pending with the resolver.
752 * Note that a client MUST NOT cancel a request that has
753 * been completed (i.e, the callback has been called to
754 * signal timeout or the final result).
755 *
756 * @param h handle of request to cancel
757 */
758void
759GNUNET_RESOLVER_request_cancel (struct GNUNET_RESOLVER_RequestHandle *h)
760{
761 if (h->client != NULL)
762 GNUNET_CLIENT_disconnect (h->client);
763 if (h->task != GNUNET_SCHEDULER_NO_TASK)
764 GNUNET_SCHEDULER_cancel (h->sched,
765 h->task);
766 GNUNET_free (h);
767}
768
604 769
605 770
606/* end of resolver_api.c */ 771/* end of resolver_api.c */
diff --git a/src/util/server.c b/src/util/server.c
index 646299718..e6a753a18 100644
--- a/src/util/server.c
+++ b/src/util/server.c
@@ -35,7 +35,7 @@
35#include "gnunet_time_lib.h" 35#include "gnunet_time_lib.h"
36#include "gnunet_disk_lib.h" 36#include "gnunet_disk_lib.h"
37 37
38#define DEBUG_SERVER GNUNET_NO 38#define DEBUG_SERVER GNUNET_YES
39 39
40/** 40/**
41 * List of arrays of message handlers. 41 * List of arrays of message handlers.
diff --git a/src/util/test_connection.c b/src/util/test_connection.c
index 30eee76ce..e144f66c1 100644
--- a/src/util/test_connection.c
+++ b/src/util/test_connection.c
@@ -144,6 +144,10 @@ make_hello (void *cls, size_t size, void *buf)
144#endif 144#endif
145 GNUNET_assert (size >= 12); 145 GNUNET_assert (size >= 12);
146 strcpy ((char *) buf, "Hello World"); 146 strcpy ((char *) buf, "Hello World");
147#if VERBOSE
148 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test destroys client socket\n");
149#endif
150 GNUNET_CONNECTION_destroy (csock);
147 return 12; 151 return 12;
148} 152}
149 153
@@ -162,13 +166,10 @@ task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
162#endif 166#endif
163 GNUNET_assert (NULL != 167 GNUNET_assert (NULL !=
164 GNUNET_CONNECTION_notify_transmit_ready (csock, 168 GNUNET_CONNECTION_notify_transmit_ready (csock,
165 12, 169 12,
166 GNUNET_TIME_UNIT_SECONDS, 170 GNUNET_TIME_UNIT_SECONDS,
167 &make_hello, NULL)); 171 &make_hello,
168#if VERBOSE 172 NULL));
169 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test destroys client socket\n");
170#endif
171 GNUNET_CONNECTION_destroy (csock);
172#if VERBOSE 173#if VERBOSE
173 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test prepares to accept\n"); 174 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test prepares to accept\n");
174#endif 175#endif