aboutsummaryrefslogtreecommitdiff
path: root/src/util
diff options
context:
space:
mode:
Diffstat (limited to 'src/util')
-rw-r--r--src/util/.gitignore4
-rw-r--r--src/util/Makefile.am16
-rw-r--r--src/util/client.c13
-rw-r--r--src/util/crypto_hash.c26
-rw-r--r--src/util/dnsparser.c125
-rw-r--r--src/util/gnunet-service-resolver.c1173
-rw-r--r--src/util/gnunet-timeout-w32.c191
-rw-r--r--src/util/gnunet-timeout.c128
-rw-r--r--src/util/resolver.h4
-rw-r--r--src/util/resolver_api.c26
-rw-r--r--src/util/scheduler.c189
-rw-r--r--src/util/strings.c39
12 files changed, 1155 insertions, 779 deletions
diff --git a/src/util/.gitignore b/src/util/.gitignore
index 23139a1ab..7b190ca76 100644
--- a/src/util/.gitignore
+++ b/src/util/.gitignore
@@ -69,3 +69,7 @@ perf_crypto_hash
69perf_crypto_symmetric 69perf_crypto_symmetric
70perf_crypto_rsa 70perf_crypto_rsa
71perf_crypto_ecc_dlog 71perf_crypto_ecc_dlog
72test_hexcoder
73test_regex
74test_tun
75gnunet-timeout
diff --git a/src/util/Makefile.am b/src/util/Makefile.am
index ec7bcb016..4ae073c2c 100644
--- a/src/util/Makefile.am
+++ b/src/util/Makefile.am
@@ -166,6 +166,7 @@ lib_LTLIBRARIES = libgnunetutil.la
166 166
167libexec_PROGRAMS = \ 167libexec_PROGRAMS = \
168 gnunet-service-resolver \ 168 gnunet-service-resolver \
169 gnunet-timeout \
169 $(W32CONSOLEHELPER) 170 $(W32CONSOLEHELPER)
170 171
171bin_SCRIPTS =\ 172bin_SCRIPTS =\
@@ -192,6 +193,15 @@ endif
192endif 193endif
193 194
194 195
196if !MINGW
197gnunet_timeout_SOURCES = \
198 gnunet-timeout.c
199else
200gnunet_timeout_SOURCES = \
201 gnunet-timeout-w32.c
202endif
203
204
195do_subst = $(SED) -e 's,[@]PYTHON[@],$(PYTHON),g' 205do_subst = $(SED) -e 's,[@]PYTHON[@],$(PYTHON),g'
196 206
197gnunet-qr: gnunet-qr.py.in Makefile 207gnunet-qr: gnunet-qr.py.in Makefile
@@ -334,12 +344,12 @@ test_hexcoder_LDADD = \
334test_tun_SOURCES = \ 344test_tun_SOURCES = \
335 test_tun.c 345 test_tun.c
336test_tun_LDADD = \ 346test_tun_LDADD = \
337 libgnunetutil.la 347 libgnunetutil.la
338 348
339test_regex_SOURCES = \ 349test_regex_SOURCES = \
340 test_regex.c 350 test_regex.c
341test_regex_LDADD = \ 351test_regex_LDADD = \
342 libgnunetutil.la 352 libgnunetutil.la
343 353
344test_os_start_process_SOURCES = \ 354test_os_start_process_SOURCES = \
345 test_os_start_process.c 355 test_os_start_process.c
@@ -622,4 +632,4 @@ EXTRA_DIST = \
622 test_resolver_api_data.conf \ 632 test_resolver_api_data.conf \
623 test_service_data.conf \ 633 test_service_data.conf \
624 test_speedup_data.conf \ 634 test_speedup_data.conf \
625 gnunet-qr.py.in 635 gnunet-qr.py.in
diff --git a/src/util/client.c b/src/util/client.c
index 44e326eab..1f569255a 100644
--- a/src/util/client.c
+++ b/src/util/client.c
@@ -11,7 +11,7 @@
11 WITHOUT ANY WARRANTY; without even the implied warranty of 11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details. 13 Affero General Public License for more details.
14 14
15 You should have received a copy of the GNU Affero General Public License 15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>. 16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17*/ 17*/
@@ -721,6 +721,17 @@ test_service_configuration (const char *service_name,
721 &unixpath)) && 721 &unixpath)) &&
722 (0 < strlen (unixpath))) 722 (0 < strlen (unixpath)))
723 ret = GNUNET_OK; 723 ret = GNUNET_OK;
724 else if ((GNUNET_OK ==
725 GNUNET_CONFIGURATION_have_value (cfg,
726 service_name,
727 "UNIXPATH")))
728 {
729 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
730 service_name,
731 "UNIXPATH",
732 _("not a valid filename"));
733 return GNUNET_SYSERR; /* UNIXPATH specified but invalid! */
734 }
724 GNUNET_free_non_null (unixpath); 735 GNUNET_free_non_null (unixpath);
725#endif 736#endif
726 737
diff --git a/src/util/crypto_hash.c b/src/util/crypto_hash.c
index 8410b7835..fe1f58df7 100644
--- a/src/util/crypto_hash.c
+++ b/src/util/crypto_hash.c
@@ -365,14 +365,17 @@ GNUNET_CRYPTO_hmac_derive_key_v (struct GNUNET_CRYPTO_AuthKey *key,
365 365
366/** 366/**
367 * Calculate HMAC of a message (RFC 2104) 367 * Calculate HMAC of a message (RFC 2104)
368 * TODO: Shouldn' this be the standard hmac function and
369 * the above be renamed?
368 * 370 *
369 * @param key secret key 371 * @param key secret key
372 * @param key_len secret key length
370 * @param plaintext input plaintext 373 * @param plaintext input plaintext
371 * @param plaintext_len length of @a plaintext 374 * @param plaintext_len length of @a plaintext
372 * @param hmac where to store the hmac 375 * @param hmac where to store the hmac
373 */ 376 */
374void 377void
375GNUNET_CRYPTO_hmac (const struct GNUNET_CRYPTO_AuthKey *key, 378GNUNET_CRYPTO_hmac_raw (const void *key, size_t key_len,
376 const void *plaintext, size_t plaintext_len, 379 const void *plaintext, size_t plaintext_len,
377 struct GNUNET_HashCode *hmac) 380 struct GNUNET_HashCode *hmac)
378{ 381{
@@ -390,7 +393,7 @@ GNUNET_CRYPTO_hmac (const struct GNUNET_CRYPTO_AuthKey *key,
390 { 393 {
391 gcry_md_reset (md); 394 gcry_md_reset (md);
392 } 395 }
393 gcry_md_setkey (md, key->key, sizeof (key->key)); 396 gcry_md_setkey (md, key, key_len);
394 gcry_md_write (md, plaintext, plaintext_len); 397 gcry_md_write (md, plaintext, plaintext_len);
395 mc = gcry_md_read (md, GCRY_MD_SHA512); 398 mc = gcry_md_read (md, GCRY_MD_SHA512);
396 GNUNET_assert (NULL != mc); 399 GNUNET_assert (NULL != mc);
@@ -399,6 +402,25 @@ GNUNET_CRYPTO_hmac (const struct GNUNET_CRYPTO_AuthKey *key,
399 402
400 403
401/** 404/**
405 * Calculate HMAC of a message (RFC 2104)
406 *
407 * @param key secret key
408 * @param plaintext input plaintext
409 * @param plaintext_len length of @a plaintext
410 * @param hmac where to store the hmac
411 */
412void
413GNUNET_CRYPTO_hmac (const struct GNUNET_CRYPTO_AuthKey *key,
414 const void *plaintext, size_t plaintext_len,
415 struct GNUNET_HashCode *hmac)
416{
417 GNUNET_CRYPTO_hmac_raw ((void*) key->key, sizeof (key->key),
418 plaintext, plaintext_len,
419 hmac);
420}
421
422
423/**
402 * Context for cummulative hashing. 424 * Context for cummulative hashing.
403 */ 425 */
404struct GNUNET_HashContext 426struct GNUNET_HashContext
diff --git a/src/util/dnsparser.c b/src/util/dnsparser.c
index cce68f2ee..24f1b18cf 100644
--- a/src/util/dnsparser.c
+++ b/src/util/dnsparser.c
@@ -11,7 +11,7 @@
11 WITHOUT ANY WARRANTY; without even the implied warranty of 11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details. 13 Affero General Public License for more details.
14 14
15 You should have received a copy of the GNU Affero General Public License 15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>. 16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */ 17 */
@@ -759,6 +759,122 @@ GNUNET_DNSPARSER_parse (const char *udp_payload,
759 759
760 760
761/** 761/**
762 * Duplicate (deep-copy) the given DNS record
763 *
764 * @param r the record
765 * @return the newly allocated record
766 */
767struct GNUNET_DNSPARSER_Record *
768GNUNET_DNSPARSER_duplicate_record (const struct GNUNET_DNSPARSER_Record *r)
769{
770 struct GNUNET_DNSPARSER_Record *dup = GNUNET_memdup (r, sizeof (*r));
771
772 dup->name = GNUNET_strdup (r->name);
773 switch (r->type)
774 {
775 case GNUNET_DNSPARSER_TYPE_NS:
776 case GNUNET_DNSPARSER_TYPE_CNAME:
777 case GNUNET_DNSPARSER_TYPE_PTR:
778 {
779 dup->data.hostname = GNUNET_strdup (r->data.hostname);
780 break;
781 }
782 case GNUNET_DNSPARSER_TYPE_SOA:
783 {
784 dup->data.soa = GNUNET_DNSPARSER_duplicate_soa_record (r->data.soa);
785 break;
786 }
787 case GNUNET_DNSPARSER_TYPE_CERT:
788 {
789 dup->data.cert = GNUNET_DNSPARSER_duplicate_cert_record (r->data.cert);
790 break;
791 }
792 case GNUNET_DNSPARSER_TYPE_MX:
793 {
794 dup->data.mx = GNUNET_DNSPARSER_duplicate_mx_record (r->data.mx);
795 break;
796 }
797 case GNUNET_DNSPARSER_TYPE_SRV:
798 {
799 dup->data.srv = GNUNET_DNSPARSER_duplicate_srv_record (r->data.srv);
800 break;
801 }
802 default:
803 {
804 dup->data.raw.data = GNUNET_memdup (r->data.raw.data,
805 r->data.raw.data_len);
806 }
807 }
808 return dup;
809}
810
811
812/**
813 * Duplicate (deep-copy) the given DNS record
814 *
815 * @param r the record
816 * @return the newly allocated record
817 */
818struct GNUNET_DNSPARSER_SoaRecord *
819GNUNET_DNSPARSER_duplicate_soa_record (const struct GNUNET_DNSPARSER_SoaRecord *r)
820{
821 struct GNUNET_DNSPARSER_SoaRecord *dup = GNUNET_memdup (r, sizeof (*r));
822
823 dup->mname = GNUNET_strdup (r->mname);
824 dup->rname = GNUNET_strdup (r->rname);
825 return dup;
826}
827
828
829/**
830 * Duplicate (deep-copy) the given DNS record
831 *
832 * @param r the record
833 * @return the newly allocated record
834 */
835struct GNUNET_DNSPARSER_CertRecord *
836GNUNET_DNSPARSER_duplicate_cert_record (const struct GNUNET_DNSPARSER_CertRecord *r)
837{
838 struct GNUNET_DNSPARSER_CertRecord *dup = GNUNET_memdup (r, sizeof (*r));
839
840 dup->certificate_data = GNUNET_strdup (r->certificate_data);
841 return dup;
842}
843
844
845/**
846 * Duplicate (deep-copy) the given DNS record
847 *
848 * @param r the record
849 * @return the newly allocated record
850 */
851struct GNUNET_DNSPARSER_MxRecord *
852GNUNET_DNSPARSER_duplicate_mx_record (const struct GNUNET_DNSPARSER_MxRecord *r)
853{
854 struct GNUNET_DNSPARSER_MxRecord *dup = GNUNET_memdup (r, sizeof (*r));
855
856 dup->mxhost = GNUNET_strdup (r->mxhost);
857 return dup;
858}
859
860
861/**
862 * Duplicate (deep-copy) the given DNS record
863 *
864 * @param r the record
865 * @return the newly allocated record
866 */
867struct GNUNET_DNSPARSER_SrvRecord *
868GNUNET_DNSPARSER_duplicate_srv_record (const struct GNUNET_DNSPARSER_SrvRecord *r)
869{
870 struct GNUNET_DNSPARSER_SrvRecord *dup = GNUNET_memdup (r, sizeof (*r));
871
872 dup->target = GNUNET_strdup (r->target);
873 return dup;
874}
875
876
877/**
762 * Free memory taken by a packet. 878 * Free memory taken by a packet.
763 * 879 *
764 * @param p packet to free 880 * @param p packet to free
@@ -840,8 +956,11 @@ GNUNET_DNSPARSER_builder_add_name (char *dst,
840 len = dot - idna_name; 956 len = dot - idna_name;
841 if ( (len >= 64) || (0 == len) ) 957 if ( (len >= 64) || (0 == len) )
842 { 958 {
843 GNUNET_break (0); 959 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
844 goto fail; /* segment too long or empty */ 960 "Invalid DNS name `%s': label with %u characters encountered\n",
961 name,
962 (unsigned int) len);
963 goto fail; /* label too long or empty */
845 } 964 }
846 dst[pos++] = (char) (uint8_t) len; 965 dst[pos++] = (char) (uint8_t) len;
847 GNUNET_memcpy (&dst[pos], 966 GNUNET_memcpy (&dst[pos],
diff --git a/src/util/gnunet-service-resolver.c b/src/util/gnunet-service-resolver.c
index d90d8ec10..5b890261b 100644
--- a/src/util/gnunet-service-resolver.c
+++ b/src/util/gnunet-service-resolver.c
@@ -27,721 +27,559 @@
27#include "gnunet_statistics_service.h" 27#include "gnunet_statistics_service.h"
28#include "resolver.h" 28#include "resolver.h"
29 29
30
31struct Record
32{
33 struct Record *next;
34
35 struct Record *prev;
36
37 struct GNUNET_DNSPARSER_Record *record;
38};
39
30/** 40/**
31 * A cached DNS lookup result (for reverse lookup). 41 * A cached DNS lookup result.
32 */ 42 */
33struct IPCache 43struct ResolveCache
34{ 44{
35 /** 45 /**
36 * This is a doubly linked list. 46 * This is a doubly linked list.
37 */ 47 */
38 struct IPCache *next; 48 struct ResolveCache *next;
39 49
40 /** 50 /**
41 * This is a doubly linked list. 51 * This is a doubly linked list.
42 */ 52 */
43 struct IPCache *prev; 53 struct ResolveCache *prev;
44 54
45 /** 55 /**
46 * Hostname in human-readable form. 56 * type of queried DNS record
47 */ 57 */
48 char *addr; 58 uint16_t record_type;
49 59
50 /** 60 /**
51 * Binary IP address, allocated at the end of this struct. 61 * a pointer to the request_id if a query for this hostname/record_type
62 * is currently pending, NULL otherwise.
52 */ 63 */
53 const void *ip; 64 int16_t *request_id;
54 65
55 /** 66 /**
56 * Last time this entry was updated. 67 * The client that queried the records contained in this cache entry.
57 */ 68 */
58 struct GNUNET_TIME_Absolute last_refresh; 69 struct GNUNET_SERVICE_Client *client;
59 70
60 /** 71 /**
61 * Last time this entry was requested. 72 * head of a double linked list containing the lookup results
62 */ 73 */
63 struct GNUNET_TIME_Absolute last_request; 74 struct Record *records_head;
64 75
65 /** 76 /**
66 * Number of bytes in ip. 77 * tail of a double linked list containing the lookup results
67 */ 78 */
68 size_t ip_len; 79 struct Record *records_tail;
69 80
70 /** 81 /**
71 * Address family of the IP. 82 * handle for cancelling a request
72 */ 83 */
73 int af; 84 struct GNUNET_DNSSTUB_RequestSocket *resolve_handle;
85
86 /**
87 * handle for the resolution timeout task
88 */
89 struct GNUNET_SCHEDULER_Task *timeout_task;
90
74}; 91};
75 92
76 93
77/** 94/**
78 * Start of the linked list of cached DNS lookup results. 95 * Start of the linked list of cached DNS lookup results.
79 */ 96 */
80static struct IPCache *cache_head; 97static struct ResolveCache *cache_head;
81 98
82/** 99/**
83 * Tail of the linked list of cached DNS lookup results. 100 * Tail of the linked list of cached DNS lookup results.
84 */ 101 */
85static struct IPCache *cache_tail; 102static struct ResolveCache *cache_tail;
86 103
87/** 104/**
88 * Pipe for asynchronously notifying about resolve result 105 * context of dnsstub library
89 */ 106 */
90static struct GNUNET_DISK_PipeHandle *resolve_result_pipe; 107static struct GNUNET_DNSSTUB_Context *dnsstub_ctx;
91 108
92/**
93 * Task for reading from resolve_result_pipe
94 */
95static struct GNUNET_SCHEDULER_Task *resolve_result_pipe_task;
96 109
97 110void free_cache_entry (struct ResolveCache *entry)
98#if HAVE_GETNAMEINFO
99/**
100 * Resolve the given request using getnameinfo
101 *
102 * @param cache the request to resolve (and where to store the result)
103 */
104static void
105getnameinfo_resolve (struct IPCache *cache)
106{ 111{
107 char hostname[256]; 112 struct Record *pos;
108 const struct sockaddr *sa; 113 struct Record *next;
109 struct sockaddr_in v4; 114
110 struct sockaddr_in6 v6; 115 next = entry->records_head;
111 size_t salen; 116 while (NULL != (pos = next))
112 int ret;
113
114 switch (cache->af)
115 { 117 {
116 case AF_INET: 118 next = pos->next;
117 GNUNET_assert (cache->ip_len == sizeof (struct in_addr)); 119 GNUNET_CONTAINER_DLL_remove (entry->records_head,
118 sa = (const struct sockaddr*) &v4; 120 entry->records_tail,
119 memset (&v4, 0, sizeof (v4)); 121 pos);
120 v4.sin_addr = * (const struct in_addr*) cache->ip; 122 if (NULL != pos->record)
121 v4.sin_family = AF_INET; 123 {
122#if HAVE_SOCKADDR_IN_SIN_LEN 124 GNUNET_DNSPARSER_free_record (pos->record);
123 v4.sin_len = sizeof (v4); 125 GNUNET_free (pos->record);
124#endif 126 }
125 salen = sizeof (v4); 127 GNUNET_free (pos);
126 break;
127 case AF_INET6:
128 GNUNET_assert (cache->ip_len == sizeof (struct in6_addr));
129 sa = (const struct sockaddr*) &v6;
130 memset (&v6, 0, sizeof (v6));
131 v6.sin6_addr = * (const struct in6_addr*) cache->ip;
132 v6.sin6_family = AF_INET6;
133#if HAVE_SOCKADDR_IN_SIN_LEN
134 v6.sin6_len = sizeof (v6);
135#endif
136 salen = sizeof (v6);
137 break;
138 default:
139 GNUNET_assert (0);
140 } 128 }
141 129 if (NULL != entry->resolve_handle)
142 if (0 ==
143 (ret = getnameinfo (sa, salen,
144 hostname, sizeof (hostname),
145 NULL,
146 0, 0)))
147 { 130 {
148 cache->addr = GNUNET_strdup (hostname); 131 GNUNET_DNSSTUB_resolve_cancel (entry->resolve_handle);
132 entry->resolve_handle = NULL;
149 } 133 }
150 else 134 if (NULL != entry->timeout_task)
151 { 135 {
152 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 136 GNUNET_SCHEDULER_cancel (entry->timeout_task);
153 "getnameinfo failed: %s\n", 137 entry->timeout_task = NULL;
154 gai_strerror (ret));
155 } 138 }
139 GNUNET_free_non_null (entry->request_id);
140 GNUNET_free (entry);
156} 141}
157#endif
158 142
159 143
160#if HAVE_GETHOSTBYADDR 144static char*
145extract_dns_server (const char* line, size_t line_len)
146{
147 if (0 == strncmp (line, "nameserver ", 11))
148 return GNUNET_strndup (line + 11, line_len - 11);
149 return NULL;
150}
151
152
161/** 153/**
162 * Resolve the given request using gethostbyaddr 154 * reads the list of nameservers from /etc/resolve.conf
163 * 155 *
164 * @param cache the request to resolve (and where to store the result) 156 * @param server_addrs[out] a list of null-terminated server address strings
157 * @return the number of server addresses in @server_addrs, -1 on error
165 */ 158 */
166static void 159static ssize_t
167gethostbyaddr_resolve (struct IPCache *cache) 160lookup_dns_servers (char ***server_addrs)
168{ 161{
169 struct hostent *ent; 162 struct GNUNET_DISK_FileHandle *fh;
170 163 char buf[2048];
171 ent = gethostbyaddr (cache->ip, 164 ssize_t bytes_read;
172 cache->ip_len, 165 size_t read_offset = 0;
173 cache->af); 166 unsigned int num_dns_servers = 0;
174 if (NULL != ent) 167
168 fh = GNUNET_DISK_file_open ("/etc/resolv.conf",
169 GNUNET_DISK_OPEN_READ,
170 GNUNET_DISK_PERM_NONE);
171 if (NULL == fh)
175 { 172 {
176 cache->addr = GNUNET_strdup (ent->h_name); 173 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
174 "Could not open /etc/resolv.conf. "
175 "DNS resolution will not be possible.\n");
176 return -1;
177 } 177 }
178 else 178 bytes_read = GNUNET_DISK_file_read (fh,
179 buf,
180 sizeof (buf));
181 *server_addrs = NULL;
182 while (read_offset < bytes_read)
179 { 183 {
180 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 184 char *newline;
181 "gethostbyaddr failed: %s\n", 185 size_t line_len;
182 hstrerror (h_errno)); 186 char *dns_server;
187
188 newline = strchr (buf + read_offset, '\n');
189 if (NULL == newline)
190 {
191 break;
192 }
193 line_len = newline - buf - read_offset;
194 dns_server = extract_dns_server (buf + read_offset, line_len);
195 if (NULL != dns_server)
196 {
197 GNUNET_array_append (*server_addrs,
198 num_dns_servers,
199 dns_server);
200 }
201 read_offset += line_len + 1;
183 } 202 }
203 GNUNET_DISK_file_close (fh);
204 return num_dns_servers;
184} 205}
185#endif
186 206
187 207
188/** 208static char *
189 * Resolve the given request using the available methods. 209make_reverse_hostname (const void *ip, int af)
190 *
191 * @param cache the request to resolve (and where to store the result)
192 */
193static void
194cache_resolve (struct IPCache *cache)
195{ 210{
196#if HAVE_GETNAMEINFO 211 char *buf = GNUNET_new_array (80, char);
197 if (NULL == cache->addr) 212 int pos = 0;
198 getnameinfo_resolve (cache); 213 if (AF_INET == af)
199#endif 214 {
200#if HAVE_GETHOSTBYADDR 215 struct in_addr *addr = (struct in_addr *)ip;
201 if (NULL == cache->addr) 216 uint32_t ip_int = addr->s_addr;
202 gethostbyaddr_resolve (cache); 217 for (int i = 3; i >= 0; i--)
203#endif 218 {
219 int n = GNUNET_snprintf (buf + pos,
220 80 - pos,
221 "%u.",
222 ((uint8_t *)&ip_int)[i]);
223 if (n < 0)
224 {
225 GNUNET_free (buf);
226 return NULL;
227 }
228 pos += n;
229 }
230 pos += GNUNET_snprintf (buf + pos, 80 - pos, "in-addr.arpa");
231 }
232 else if (AF_INET6 == af)
233 {
234 struct in6_addr *addr = (struct in6_addr *)ip;
235 for (int i = 15; i >= 0; i--)
236 {
237 int n = GNUNET_snprintf (buf + pos, 80 - pos, "%x.", addr->s6_addr[i] & 0xf);
238 if (n < 0)
239 {
240 GNUNET_free (buf);
241 return NULL;
242 }
243 pos += n;
244 n = GNUNET_snprintf (buf + pos, 80 - pos, "%x.", addr->s6_addr[i] >> 4);
245 if (n < 0)
246 {
247 GNUNET_free (buf);
248 return NULL;
249 }
250 pos += n;
251 }
252 pos += GNUNET_snprintf (buf + pos, 80 - pos, "ip6.arpa");
253 }
254 buf[pos] = '\0';
255 return buf;
204} 256}
205 257
206 258
207/**
208 * Function called after the replies for the request have all
209 * been transmitted to the client, and we can now read the next
210 * request from the client.
211 *
212 * @param cls the `struct GNUNET_SERVICE_Client` to continue with
213 */
214static void 259static void
215notify_service_client_done (void *cls) 260send_reply (struct GNUNET_DNSPARSER_Record *record,
261 uint16_t request_id,
262 struct GNUNET_SERVICE_Client *client)
216{ 263{
217 struct GNUNET_SERVICE_Client *client = cls;
218
219 GNUNET_SERVICE_client_continue (client);
220}
221
222
223/**
224 * Get an IP address as a string (works for both IPv4 and IPv6). Note
225 * that the resolution happens asynchronously and that the first call
226 * may not immediately result in the FQN (but instead in a
227 * human-readable IP address).
228 *
229 * @param client handle to the client making the request (for sending the reply)
230 * @param af AF_INET or AF_INET6
231 * @param ip `struct in_addr` or `struct in6_addr`
232 */
233static void
234get_ip_as_string (struct GNUNET_SERVICE_Client *client,
235 int af,
236 const void *ip,
237 uint32_t request_id)
238{
239 struct IPCache *pos;
240 struct IPCache *next;
241 struct GNUNET_TIME_Absolute now;
242 struct GNUNET_MQ_Envelope *env;
243 struct GNUNET_MQ_Handle *mq;
244 struct GNUNET_RESOLVER_ResponseMessage *msg; 264 struct GNUNET_RESOLVER_ResponseMessage *msg;
245 size_t ip_len; 265 struct GNUNET_MQ_Envelope *env;
246 struct in6_addr ix; 266 void *payload;
247 size_t alen; 267 size_t payload_len;
248 268
249 switch (af) 269 switch (record->type)
250 {
251 case AF_INET:
252 ip_len = sizeof (struct in_addr);
253 break;
254 case AF_INET6:
255 ip_len = sizeof (struct in6_addr);
256 break;
257 default:
258 GNUNET_assert (0);
259 }
260 now = GNUNET_TIME_absolute_get ();
261 next = cache_head;
262 while ( (NULL != (pos = next)) &&
263 ( (pos->af != af) ||
264 (pos->ip_len != ip_len) ||
265 (0 != memcmp (pos->ip, ip, ip_len))) )
266 { 270 {
267 next = pos->next; 271 case GNUNET_DNSPARSER_TYPE_PTR:
268 if (GNUNET_TIME_absolute_get_duration (pos->last_request).rel_value_us <
269 60 * 60 * 1000 * 1000LL)
270 { 272 {
271 GNUNET_CONTAINER_DLL_remove (cache_head, 273 char *hostname = record->data.hostname;
272 cache_tail, 274 payload = hostname;
273 pos); 275 payload_len = strlen (hostname) + 1;
274 GNUNET_free_non_null (pos->addr); 276 break;
275 GNUNET_free (pos);
276 continue;
277 } 277 }
278 } 278 case GNUNET_DNSPARSER_TYPE_A:
279 if (NULL != pos) 279 case GNUNET_DNSPARSER_TYPE_AAAA:
280 {
281 if ( (1 == inet_pton (af,
282 pos->ip,
283 &ix)) &&
284 (GNUNET_TIME_absolute_get_duration (pos->last_request).rel_value_us >
285 120 * 1000 * 1000LL) )
286 { 280 {
287 /* try again if still numeric AND 2 minutes have expired */ 281 payload = record->data.raw.data;
288 GNUNET_free_non_null (pos->addr); 282 payload_len = record->data.raw.data_len;
289 pos->addr = NULL; 283 break;
290 cache_resolve (pos); 284 }
291 pos->last_request = now; 285 default:
286 {
287 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
288 "Cannot handle DNS response type: unimplemented\n");
289 return;
292 } 290 }
293 } 291 }
294 else
295 {
296 pos = GNUNET_malloc (sizeof (struct IPCache) + ip_len);
297 pos->ip = &pos[1];
298 GNUNET_memcpy (&pos[1],
299 ip,
300 ip_len);
301 pos->last_request = now;
302 pos->last_refresh = now;
303 pos->ip_len = ip_len;
304 pos->af = af;
305 GNUNET_CONTAINER_DLL_insert (cache_head,
306 cache_tail,
307 pos);
308 cache_resolve (pos);
309 }
310 if (NULL != pos->addr)
311 alen = strlen (pos->addr) + 1;
312 else
313 alen = 0;
314 mq = GNUNET_SERVICE_client_get_mq (client);
315 env = GNUNET_MQ_msg_extra (msg, 292 env = GNUNET_MQ_msg_extra (msg,
316 alen, 293 payload_len,
317 GNUNET_MESSAGE_TYPE_RESOLVER_RESPONSE); 294 GNUNET_MESSAGE_TYPE_RESOLVER_RESPONSE);
318 msg->id = request_id; 295 msg->id = request_id;
319 GNUNET_memcpy (&msg[1], 296 GNUNET_memcpy (&msg[1],
320 pos->addr, 297 payload,
321 alen); 298 payload_len);
322 GNUNET_MQ_send (mq, 299 GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client),
323 env); 300 env);
324 // send end message
325 env = GNUNET_MQ_msg (msg,
326 GNUNET_MESSAGE_TYPE_RESOLVER_RESPONSE);
327 msg->id = request_id;
328 GNUNET_MQ_notify_sent (env,
329 &notify_service_client_done,
330 client);
331 GNUNET_MQ_send (mq,
332 env);
333} 301}
334 302
335 303
336#if HAVE_GETADDRINFO_A
337struct AsyncCls
338{
339 struct gaicb *host;
340 struct sigevent *sig;
341 struct GNUNET_MQ_Handle *mq;
342 uint32_t request_id;
343};
344
345
346static void 304static void
347resolve_result_pipe_cb (void *cls) 305send_end_msg (uint16_t request_id,
306 struct GNUNET_SERVICE_Client *client)
348{ 307{
349 struct AsyncCls *async_cls;
350 struct gaicb *host;
351 struct GNUNET_RESOLVER_ResponseMessage *msg; 308 struct GNUNET_RESOLVER_ResponseMessage *msg;
352 struct GNUNET_MQ_Envelope *env; 309 struct GNUNET_MQ_Envelope *env;
353 310
354 GNUNET_DISK_file_read (GNUNET_DISK_pipe_handle (resolve_result_pipe, 311 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
355 GNUNET_DISK_PIPE_END_READ), 312 "Sending end message\n");
356 &async_cls, 313 env = GNUNET_MQ_msg (msg,
357 sizeof (struct AsyncCls *)); 314 GNUNET_MESSAGE_TYPE_RESOLVER_RESPONSE);
358 resolve_result_pipe_task = 315 msg->id = request_id;
359 GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, 316 GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client),
360 GNUNET_DISK_pipe_handle (resolve_result_pipe, 317 env);
361 GNUNET_DISK_PIPE_END_READ), 318}
362 &resolve_result_pipe_cb, 319
363 NULL); 320
364 host = async_cls->host; 321static void
365 for (struct addrinfo *pos = host->ar_result; pos != NULL; pos = pos->ai_next) 322handle_resolve_result (void *cls,
323 const struct GNUNET_TUN_DnsHeader *dns,
324 size_t dns_len)
325{
326 struct ResolveCache *cache = cls;
327 struct GNUNET_DNSPARSER_Packet *parsed;
328 uint16_t request_id = *cache->request_id;
329 struct GNUNET_SERVICE_Client *client = cache->client;
330
331 parsed = GNUNET_DNSPARSER_parse ((const char *)dns,
332 dns_len);
333 if (NULL == parsed)
334 {
335 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
336 "Failed to parse DNS reply (request ID %u\n",
337 request_id);
338 return;
339 }
340 if (request_id != ntohs (parsed->id))
341 {
342 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
343 "Request ID in DNS reply does not match\n");
344 return;
345 }
346 else if (0 == parsed->num_answers)
347 {
348 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
349 "DNS reply (request ID %u) contains no answers\n",
350 request_id);
351 GNUNET_CONTAINER_DLL_remove (cache_head,
352 cache_tail,
353 cache);
354 free_cache_entry (cache);
355 cache = NULL;
356 }
357 else
366 { 358 {
367 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 359 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
368 "Lookup result for hostname %s: %s (request ID %u)\n", 360 "Got reply for request ID %u\n",
369 host->ar_name, 361 request_id);
370 GNUNET_a2s (pos->ai_addr, pos->ai_addrlen), 362 for (unsigned int i = 0; i != parsed->num_answers; i++)
371 async_cls->request_id);
372 switch (pos->ai_family)
373 { 363 {
374 case AF_INET: 364 struct Record *cache_entry = GNUNET_new (struct Record);
375 env = GNUNET_MQ_msg_extra (msg, 365 struct GNUNET_DNSPARSER_Record *record = &parsed->answers[i];
376 sizeof (struct in_addr), 366 cache_entry->record = GNUNET_DNSPARSER_duplicate_record (record);
377 GNUNET_MESSAGE_TYPE_RESOLVER_RESPONSE); 367 GNUNET_CONTAINER_DLL_insert (cache->records_head,
378 msg->id = async_cls->request_id; 368 cache->records_tail,
379 GNUNET_memcpy (&msg[1], 369 cache_entry);
380 &((struct sockaddr_in*) pos->ai_addr)->sin_addr, 370 send_reply (cache_entry->record,
381 sizeof (struct in_addr)); 371 request_id,
382 GNUNET_MQ_send (async_cls->mq, 372 cache->client);
383 env);
384 break;
385 case AF_INET6:
386 env = GNUNET_MQ_msg_extra (msg,
387 sizeof (struct in6_addr),
388 GNUNET_MESSAGE_TYPE_RESOLVER_RESPONSE);
389 msg->id = async_cls->request_id;
390 GNUNET_memcpy (&msg[1],
391 &((struct sockaddr_in6*) pos->ai_addr)->sin6_addr,
392 sizeof (struct in6_addr));
393 GNUNET_MQ_send (async_cls->mq,
394 env);
395 break;
396 default:
397 /* unsupported, skip */
398 break;
399 } 373 }
374 GNUNET_free_non_null (cache->request_id);
375 cache->request_id = NULL;
400 } 376 }
401 // send end message 377 send_end_msg (request_id,
402 env = GNUNET_MQ_msg (msg, 378 client);
403 GNUNET_MESSAGE_TYPE_RESOLVER_RESPONSE); 379 if (NULL != cache)
404 msg->id = async_cls->request_id; 380 cache->client = NULL;
405 GNUNET_MQ_send (async_cls->mq, 381 if (NULL != cache)
406 env); 382 {
407 freeaddrinfo (host->ar_result); 383 if (NULL != cache->timeout_task)
408 GNUNET_free ((struct gaicb *)host->ar_request); // free hints 384 {
409 GNUNET_free (host); 385 GNUNET_SCHEDULER_cancel (cache->timeout_task);
410 GNUNET_free (async_cls->sig); 386 cache->timeout_task = NULL;
411 GNUNET_free (async_cls); 387 }
388 if (NULL != cache->resolve_handle)
389 {
390 GNUNET_DNSSTUB_resolve_cancel (cache->resolve_handle);
391 cache->resolve_handle = NULL;
392 }
393 }
394 GNUNET_DNSPARSER_free_packet (parsed);
412} 395}
413 396
414 397
415static void 398static void
416handle_async_result (union sigval val) 399handle_resolve_timeout (void *cls)
417{ 400{
418 GNUNET_DISK_file_write (GNUNET_DISK_pipe_handle (resolve_result_pipe, 401 struct ResolveCache *cache = cls;
419 GNUNET_DISK_PIPE_END_WRITE), 402
420 &val.sival_ptr, 403 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
421 sizeof (val.sival_ptr)); 404 "timeout!\n");
405 if (NULL != cache->resolve_handle)
406 {
407 GNUNET_DNSSTUB_resolve_cancel (cache->resolve_handle);
408 cache->resolve_handle = NULL;
409 }
410 GNUNET_CONTAINER_DLL_remove (cache_head,
411 cache_tail,
412 cache);
413 free_cache_entry (cache);
422} 414}
423 415
424 416
425static int 417static int
426getaddrinfo_a_resolve (struct GNUNET_MQ_Handle *mq, 418resolve_and_cache (const char* hostname,
427 const char *hostname, 419 uint16_t record_type,
428 int af, 420 uint16_t request_id,
429 uint32_t request_id) 421 struct GNUNET_SERVICE_Client *client)
430{ 422{
431 int ret; 423 char *packet_buf;
432 struct gaicb *host; 424 size_t packet_size;
433 struct addrinfo *hints; 425 struct GNUNET_DNSPARSER_Query query;
434 struct sigevent *sig; 426 struct GNUNET_DNSPARSER_Packet packet;
435 struct AsyncCls *async_cls; 427 struct ResolveCache *cache;
436 428 struct GNUNET_TIME_Relative timeout =
437 host = GNUNET_new (struct gaicb); 429 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5);
438 hints = GNUNET_new (struct addrinfo); 430
439 sig = GNUNET_new (struct sigevent); 431 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
440 async_cls = GNUNET_new (struct AsyncCls); 432 "resolve_and_cache\n");
441 memset (hints, 433 query.name = (char *)hostname;
434 query.type = record_type;
435 query.dns_traffic_class = GNUNET_TUN_DNS_CLASS_INTERNET;
436 memset (&packet,
442 0, 437 0,
443 sizeof (struct addrinfo)); 438 sizeof (packet));
444 memset (sig, 439 packet.num_queries = 1;
445 0, 440 packet.queries = &query;
446 sizeof (struct sigevent)); 441 packet.id = htons (request_id);
447 hints->ai_family = af; 442 packet.flags.recursion_desired = 1;
448 hints->ai_socktype = SOCK_STREAM; /* go for TCP */ 443 if (GNUNET_OK !=
449 host->ar_name = hostname; 444 GNUNET_DNSPARSER_pack (&packet,
450 host->ar_service = NULL; 445 UINT16_MAX,
451 host->ar_request = hints; 446 &packet_buf,
452 host->ar_result = NULL; 447 &packet_size))
453 sig->sigev_notify = SIGEV_THREAD; 448 {
454 sig->sigev_value.sival_ptr = async_cls; 449 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
455 sig->sigev_notify_function = &handle_async_result; 450 "Failed to pack query for hostname `%s'\n",
456 async_cls->host = host; 451 hostname);
457 async_cls->sig = sig;
458 async_cls->mq = mq;
459 async_cls->request_id = request_id;
460 ret = getaddrinfo_a (GAI_NOWAIT,
461 &host,
462 1,
463 sig);
464 if (0 != ret)
465 return GNUNET_SYSERR; 452 return GNUNET_SYSERR;
453
454 }
455 cache = GNUNET_malloc (sizeof (struct ResolveCache));
456 cache->record_type = record_type;
457 cache->request_id = GNUNET_memdup (&request_id, sizeof (request_id));
458 cache->client = client;
459 cache->timeout_task = GNUNET_SCHEDULER_add_delayed (timeout,
460 &handle_resolve_timeout,
461 cache);
462 cache->resolve_handle =
463 GNUNET_DNSSTUB_resolve (dnsstub_ctx,
464 packet_buf,
465 packet_size,
466 &handle_resolve_result,
467 cache);
468 GNUNET_CONTAINER_DLL_insert (cache_head,
469 cache_tail,
470 cache);
471 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
472 "resolve %s, request_id = %u\n",
473 hostname,
474 request_id);
475 GNUNET_free (packet_buf);
466 return GNUNET_OK; 476 return GNUNET_OK;
467} 477}
468 478
469 479
470#elif HAVE_GETADDRINFO 480static const char *
471static int 481get_hostname (struct ResolveCache *cache_entry)
472getaddrinfo_resolve (struct GNUNET_MQ_Handle *mq,
473 const char *hostname,
474 int af,
475 uint32_t request_id)
476{ 482{
477 int s; 483 if (NULL != cache_entry->records_head)
478 struct addrinfo hints;
479 struct addrinfo *result;
480 struct addrinfo *pos;
481 struct GNUNET_RESOLVER_ResponseMessage *msg;
482 struct GNUNET_MQ_Envelope *env;
483
484#ifdef WINDOWS
485 /* Due to a bug, getaddrinfo will not return a mix of different families */
486 if (AF_UNSPEC == af)
487 { 484 {
488 int ret1; 485 GNUNET_assert (NULL != cache_entry->records_head);
489 int ret2; 486 GNUNET_assert (NULL != cache_entry->records_head->record);
490 ret1 = getaddrinfo_resolve (mq, 487 GNUNET_assert (NULL != cache_entry->records_head->record->name);
491 hostname, 488 return cache_entry->records_head->record->name;
492 AF_INET,
493 request_id);
494 ret2 = getaddrinfo_resolve (mq,
495 hostname,
496 AF_INET6,
497 request_id);
498 if ( (ret1 == GNUNET_OK) ||
499 (ret2 == GNUNET_OK) )
500 return GNUNET_OK;
501 if ( (ret1 == GNUNET_SYSERR) ||
502 (ret2 == GNUNET_SYSERR) )
503 return GNUNET_SYSERR;
504 return GNUNET_NO;
505 } 489 }
506#endif 490 return NULL;
507
508 memset (&hints,
509 0,
510 sizeof (struct addrinfo));
511 hints.ai_family = af;
512 hints.ai_socktype = SOCK_STREAM; /* go for TCP */
513
514 if (0 != (s = getaddrinfo (hostname,
515 NULL,
516 &hints,
517 &result)))
518 {
519 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
520 _("Could not resolve `%s' (%s): %s\n"),
521 hostname,
522 (af ==
523 AF_INET) ? "IPv4" : ((af == AF_INET6) ? "IPv6" : "any"),
524 gai_strerror (s));
525 if ( (s == EAI_BADFLAGS) ||
526#ifndef WINDOWS
527 (s == EAI_SYSTEM) ||
528#endif
529 (s == EAI_MEMORY) )
530 return GNUNET_NO; /* other function may still succeed */
531 return GNUNET_SYSERR;
532 }
533 if (NULL == result)
534 return GNUNET_SYSERR;
535 for (pos = result; pos != NULL; pos = pos->ai_next)
536 {
537 switch (pos->ai_family)
538 {
539 case AF_INET:
540 env = GNUNET_MQ_msg_extra (msg,
541 sizeof (struct in_addr),
542 GNUNET_MESSAGE_TYPE_RESOLVER_RESPONSE);
543 msg->id = request_id;
544 GNUNET_memcpy (&msg[1],
545 &((struct sockaddr_in*) pos->ai_addr)->sin_addr,
546 sizeof (struct in_addr));
547 GNUNET_MQ_send (mq,
548 env);
549 break;
550 case AF_INET6:
551 env = GNUNET_MQ_msg_extra (msg,
552 sizeof (struct in6_addr),
553 GNUNET_MESSAGE_TYPE_RESOLVER_RESPONSE);
554 msg->id = request_id;
555 GNUNET_memcpy (&msg[1],
556 &((struct sockaddr_in6*) pos->ai_addr)->sin6_addr,
557 sizeof (struct in6_addr));
558 GNUNET_MQ_send (mq,
559 env);
560 break;
561 default:
562 /* unsupported, skip */
563 break;
564 }
565 }
566 freeaddrinfo (result);
567 return GNUNET_OK;
568} 491}
569 492
570 493
571#elif HAVE_GETHOSTBYNAME2 494static const uint16_t *
572 495get_record_type (struct ResolveCache *cache_entry)
573
574static int
575gethostbyname2_resolve (struct GNUNET_MQ_Handle *mq,
576 const char *hostname,
577 int af,
578 uint32_t request_id)
579{ 496{
580 struct hostent *hp; 497 if (NULL != cache_entry->records_head)
581 int ret1; 498 return &cache_entry->record_type;
582 int ret2; 499 return NULL;
583 struct GNUNET_MQ_Envelope *env; 500}
584 struct GNUNET_RESOLVER_ResponseMessage *msg;
585 501
586#ifdef WINDOWS
587 /* gethostbyname2() in plibc is a compat dummy that calls gethostbyname(). */
588 return GNUNET_NO;
589#endif
590 502
591 if (af == AF_UNSPEC) 503static const struct GNUNET_TIME_Absolute *
592 { 504get_expiration_time (struct ResolveCache *cache_entry)
593 ret1 = gethostbyname2_resolve (mq, 505{
594 hostname, 506 if (NULL != cache_entry->records_head)
595 AF_INET, 507 return &cache_entry->records_head->record->expiration_time;
596 request_id); 508 return NULL;
597 ret2 = gethostbyname2_resolve (mq,
598 hostname,
599 AF_INET6,
600 request_id);
601 if ( (ret1 == GNUNET_OK) ||
602 (ret2 == GNUNET_OK) )
603 return GNUNET_OK;
604 if ( (ret1 == GNUNET_SYSERR) ||
605 (ret2 == GNUNET_SYSERR) )
606 return GNUNET_SYSERR;
607 return GNUNET_NO;
608 }
609 hp = gethostbyname2 (hostname,
610 af);
611 if (hp == NULL)
612 {
613 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
614 _("Could not find IP of host `%s': %s\n"),
615 hostname,
616 hstrerror (h_errno));
617 return GNUNET_SYSERR;
618 }
619 GNUNET_assert (hp->h_addrtype == af);
620 switch (af)
621 {
622 case AF_INET:
623 GNUNET_assert (hp->h_length == sizeof (struct in_addr));
624 env = GNUNET_MQ_msg_extra (msg,
625 hp->h_length,
626 GNUNET_MESSAGE_TYPE_RESOLVER_RESPONSE);
627 msg->id = request_id;
628 GNUNET_memcpy (&msg[1],
629 hp->h_addr_list[0],
630 hp->h_length);
631 GNUNET_MQ_send (mq,
632 env);
633 break;
634 case AF_INET6:
635 GNUNET_assert (hp->h_length == sizeof (struct in6_addr));
636 env = GNUNET_MQ_msg_extra (msg,
637 hp->h_length,
638 GNUNET_MESSAGE_TYPE_RESOLVER_RESPONSE);
639 msg->id = request_id;
640 GNUNET_memcpy (&msg[1],
641 hp->h_addr_list[0],
642 hp->h_length);
643 GNUNET_MQ_send (mq,
644 env);
645 break;
646 default:
647 GNUNET_break (0);
648 return GNUNET_SYSERR;
649 }
650 return GNUNET_OK;
651} 509}
652 510
653#elif HAVE_GETHOSTBYNAME
654
655 511
656static int 512static int
657gethostbyname_resolve (struct GNUNET_MQ_Handle *mq, 513remove_if_expired (struct ResolveCache *cache_entry)
658 const char *hostname,
659 uint32_t request_id)
660{ 514{
661 struct hostent *hp; 515 struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
662 struct GNUNET_RESOLVER_ResponseMessage *msg;
663 struct GNUNET_MQ_Envelope *env;
664 516
665 hp = GETHOSTBYNAME (hostname); 517 if ( (NULL != cache_entry->records_head) &&
666 if (NULL == hp) 518 (now.abs_value_us > get_expiration_time (cache_entry)->abs_value_us) )
667 { 519 {
668 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 520 GNUNET_CONTAINER_DLL_remove (cache_head,
669 _("Could not find IP of host `%s': %s\n"), 521 cache_tail,
670 hostname, 522 cache_entry);
671 hstrerror (h_errno)); 523 free_cache_entry (cache_entry);
672 return GNUNET_SYSERR; 524 return GNUNET_YES;
673 }
674 if (hp->h_addrtype != AF_INET)
675 {
676 GNUNET_break (0);
677 return GNUNET_SYSERR;
678 } 525 }
679 GNUNET_assert (hp->h_length == sizeof (struct in_addr)); 526 return GNUNET_NO;
680 env = GNUNET_MQ_msg_extra (msg,
681 hp->h_length,
682 GNUNET_MESSAGE_TYPE_RESOLVER_RESPONSE);
683 msg->id = request_id;
684 GNUNET_memcpy (&msg[1],
685 hp->h_addr_list[0],
686 hp->h_length);
687 GNUNET_MQ_send (mq,
688 env);
689 return GNUNET_OK;
690} 527}
691#endif
692 528
693 529
694/** 530/**
695 * Convert a string to an IP address. 531 * Get an IP address as a string (works for both IPv4 and IPv6). Note
532 * that the resolution happens asynchronously and that the first call
533 * may not immediately result in the FQN (but instead in a
534 * human-readable IP address).
696 * 535 *
697 * @param client where to send the IP address 536 * @param client handle to the client making the request (for sending the reply)
698 * @param hostname the hostname to resolve 537 * @param af AF_INET or AF_INET6
699 * @param af AF_INET or AF_INET6; use AF_UNSPEC for "any" 538 * @param ip `struct in_addr` or `struct in6_addr`
700 */ 539 */
701static void 540static int
702get_ip_from_hostname (struct GNUNET_SERVICE_Client *client, 541try_cache (const char *hostname,
703 const char *hostname, 542 uint16_t record_type,
704 int af, 543 uint16_t request_id,
705 uint32_t request_id) 544 struct GNUNET_SERVICE_Client *client)
706{ 545{
707 struct GNUNET_MQ_Envelope *env; 546 struct ResolveCache *pos;
708 struct GNUNET_RESOLVER_ResponseMessage *msg; 547 struct ResolveCache *next;
709 struct GNUNET_MQ_Handle *mq; 548
710 549 next = cache_head;
711 mq = GNUNET_SERVICE_client_get_mq (client); 550 while ( (NULL != (pos = next)) &&
712#if HAVE_GETADDRINFO_A 551 ( (NULL == pos->records_head) ||
713 getaddrinfo_a_resolve (mq, 552 (0 != strcmp (get_hostname (pos), hostname)) ||
714 hostname, 553 (*get_record_type (pos) != record_type) ) )
715 af, 554 {
716 request_id); 555 next = pos->next;
717 GNUNET_SERVICE_client_continue (client); 556 remove_if_expired (pos);
718 return; 557 }
719#elif HAVE_GETADDRINFO 558 if (NULL != pos)
720 getaddrinfo_resolve (mq, 559 {
721 hostname, 560 if (GNUNET_NO == remove_if_expired (pos))
722 af, 561 {
723 request_id); 562 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
724#elif HAVE_GETHOSTBYNAME2 563 "found cache entry for '%s', record type '%u'\n",
725 gethostbyname2_resolve (mq, 564 hostname,
726 hostname, 565 record_type);
727 af, 566 struct Record *cache_pos = pos->records_head;
728 request_id); 567 while (NULL != cache_pos)
729#elif HAVE_GETHOSTBYNAME 568 {
730 if ( ( (af == AF_UNSPEC) || 569 send_reply (cache_pos->record,
731 (af == PF_INET) ) ) 570 request_id,
732 gethostbyname_resolve (mq, 571 client);
733 hostname, 572 cache_pos = cache_pos->next;
734 request_id); 573 }
735#endif 574 send_end_msg (request_id,
736 // send end message 575 client);
737 env = GNUNET_MQ_msg (msg, 576 return GNUNET_YES;
738 GNUNET_MESSAGE_TYPE_RESOLVER_RESPONSE); 577 }
739 msg->id = request_id; 578 }
740 GNUNET_MQ_notify_sent (env, 579 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
741 &notify_service_client_done, 580 "no cache entry for '%s'\n",
742 client); 581 hostname);
743 GNUNET_MQ_send (mq, 582 return GNUNET_NO;
744 env);
745} 583}
746 584
747 585
@@ -801,6 +639,23 @@ check_get (void *cls,
801} 639}
802 640
803 641
642static void
643process_get (const char *hostname,
644 uint16_t record_type,
645 uint16_t request_id,
646 struct GNUNET_SERVICE_Client *client)
647{
648 if (GNUNET_NO == try_cache (hostname, record_type, request_id, client))
649 {
650 int result = resolve_and_cache (hostname,
651 record_type,
652 request_id,
653 client);
654 GNUNET_assert (GNUNET_OK == result);
655 }
656}
657
658
804/** 659/**
805 * Handle GET-message. 660 * Handle GET-message.
806 * 661 *
@@ -812,45 +667,100 @@ handle_get (void *cls,
812 const struct GNUNET_RESOLVER_GetMessage *msg) 667 const struct GNUNET_RESOLVER_GetMessage *msg)
813{ 668{
814 struct GNUNET_SERVICE_Client *client = cls; 669 struct GNUNET_SERVICE_Client *client = cls;
815 const void *ip;
816 int direction; 670 int direction;
817 int af; 671 int af;
818 uint32_t id; 672 uint16_t request_id;
673 const char *hostname;
819 674
820 direction = ntohl (msg->direction); 675 direction = ntohl (msg->direction);
821 af = ntohl (msg->af); 676 af = ntohl (msg->af);
822 id = ntohl (msg->id); 677 request_id = ntohs (msg->id);
823 if (GNUNET_NO == direction) 678 if (GNUNET_NO == direction)
824 { 679 {
825 /* IP from hostname */ 680 /* IP from hostname */
826 const char *hostname; 681 hostname = GNUNET_strdup ((const char *) &msg[1]);
827 682 switch (af)
828 hostname = (const char *) &msg[1]; 683 {
829 get_ip_from_hostname (client, 684 case AF_UNSPEC:
830 hostname, 685 {
831 af, 686 process_get (hostname, GNUNET_DNSPARSER_TYPE_ALL, request_id, client);
832 id); 687 break;
833 return; 688 }
689 case AF_INET:
690 {
691 process_get (hostname, GNUNET_DNSPARSER_TYPE_A, request_id, client);
692 break;
693 }
694 case AF_INET6:
695 {
696 process_get (hostname, GNUNET_DNSPARSER_TYPE_AAAA, request_id, client);
697 break;
698 }
699 default:
700 {
701 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
702 "got invalid af: %d\n",
703 af);
704 GNUNET_assert (0);
705 }
706 }
707 }
708 else
709 {
710 /* hostname from IP */
711 hostname = make_reverse_hostname (&msg[1], af);
712 process_get (hostname, GNUNET_DNSPARSER_TYPE_PTR, request_id, client);
834 } 713 }
835 ip = &msg[1]; 714 GNUNET_free_non_null ((char *)hostname);
715 GNUNET_SERVICE_client_continue (client);
716}
836 717
837#if !defined(GNUNET_CULL_LOGGING) 718
719static void
720shutdown_task (void *cls)
721{
722 (void) cls;
723 struct ResolveCache *pos;
724
725 while (NULL != (pos = cache_head))
838 { 726 {
839 char buf[INET6_ADDRSTRLEN]; 727 GNUNET_CONTAINER_DLL_remove (cache_head,
728 cache_tail,
729 pos);
730 free_cache_entry (pos);
731 }
732 GNUNET_DNSSTUB_stop (dnsstub_ctx);
733}
734
840 735
736static void
737init_cb (void *cls,
738 const struct GNUNET_CONFIGURATION_Handle *cfg,
739 struct GNUNET_SERVICE_Handle *sh)
740{
741 (void) cfg;
742 (void) sh;
743
744 GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
745 cls);
746 dnsstub_ctx = GNUNET_DNSSTUB_start (128);
747 char **dns_servers;
748 ssize_t num_dns_servers = lookup_dns_servers (&dns_servers);
749 if (0 == num_dns_servers)
750 {
751 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
752 "no DNS server available. DNS resolution will not be possible.\n");
753 }
754 for (int i = 0; i != num_dns_servers; i++)
755 {
756 int result = GNUNET_DNSSTUB_add_dns_ip (dnsstub_ctx, dns_servers[i]);
841 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 757 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
842 "Resolver asked to look up IP address `%s (request ID %u)'.\n", 758 "Adding DNS server '%s': %s\n",
843 inet_ntop (af, 759 dns_servers[i],
844 ip, 760 GNUNET_OK == result ? "success" : "failure");
845 buf, 761 GNUNET_free (dns_servers[i]);
846 sizeof (buf)),
847 id);
848 } 762 }
849#endif 763 GNUNET_free_non_null (dns_servers);
850 get_ip_as_string (client,
851 af,
852 ip,
853 id);
854} 764}
855 765
856 766
@@ -870,19 +780,6 @@ connect_cb (void *cls,
870 (void) cls; 780 (void) cls;
871 (void) mq; 781 (void) mq;
872 782
873#if HAVE_GETADDRINFO_A
874 resolve_result_pipe = GNUNET_DISK_pipe (GNUNET_NO,
875 GNUNET_NO,
876 GNUNET_NO,
877 GNUNET_NO);
878 GNUNET_assert (NULL != resolve_result_pipe);
879 resolve_result_pipe_task =
880 GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
881 GNUNET_DISK_pipe_handle (resolve_result_pipe,
882 GNUNET_DISK_PIPE_END_READ),
883 &resolve_result_pipe_cb,
884 NULL);
885#endif
886 return c; 783 return c;
887} 784}
888 785
@@ -900,19 +797,16 @@ disconnect_cb (void *cls,
900 void *internal_cls) 797 void *internal_cls)
901{ 798{
902 (void) cls; 799 (void) cls;
800 struct ResolveCache *pos = cache_head;
903 801
904#if HAVE_GETADDRINFO_A 802 while (NULL != pos)
905 if (NULL != resolve_result_pipe_task)
906 {
907 GNUNET_SCHEDULER_cancel (resolve_result_pipe_task);
908 resolve_result_pipe_task = NULL;
909 }
910 if (NULL != resolve_result_pipe)
911 { 803 {
912 GNUNET_DISK_pipe_close (resolve_result_pipe); 804 if (pos->client == c)
913 resolve_result_pipe = NULL; 805 {
806 pos->client = NULL;
807 }
808 pos = pos->next;
914 } 809 }
915#endif
916 GNUNET_assert (c == internal_cls); 810 GNUNET_assert (c == internal_cls);
917} 811}
918 812
@@ -923,7 +817,7 @@ disconnect_cb (void *cls,
923GNUNET_SERVICE_MAIN 817GNUNET_SERVICE_MAIN
924("resolver", 818("resolver",
925 GNUNET_SERVICE_OPTION_NONE, 819 GNUNET_SERVICE_OPTION_NONE,
926 NULL, 820 &init_cb,
927 &connect_cb, 821 &connect_cb,
928 &disconnect_cb, 822 &disconnect_cb,
929 NULL, 823 NULL,
@@ -950,23 +844,4 @@ GNUNET_RESOLVER_memory_init ()
950#endif 844#endif
951 845
952 846
953/**
954 * Free globals on exit.
955 */
956void __attribute__ ((destructor))
957GNUNET_RESOLVER_memory_done ()
958{
959 struct IPCache *pos;
960
961 while (NULL != (pos = cache_head))
962 {
963 GNUNET_CONTAINER_DLL_remove (cache_head,
964 cache_tail,
965 pos);
966 GNUNET_free_non_null (pos->addr);
967 GNUNET_free (pos);
968 }
969}
970
971
972/* end of gnunet-service-resolver.c */ 847/* end of gnunet-service-resolver.c */
diff --git a/src/util/gnunet-timeout-w32.c b/src/util/gnunet-timeout-w32.c
new file mode 100644
index 000000000..78b268fe2
--- /dev/null
+++ b/src/util/gnunet-timeout-w32.c
@@ -0,0 +1,191 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2010 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17*/
18
19/**
20 * @file src/util/gnunet-timeout-w32.c
21 * @brief small tool starting a child process, waiting that it terminates or killing it after a given timeout period
22 * @author LRN
23 */
24
25#include <windows.h>
26#include <sys/types.h>
27#include <stdio.h>
28
29int
30main (int argc, char *argv[])
31{
32 int i;
33 DWORD wait_result;
34 wchar_t *commandline;
35 wchar_t **wargv;
36 wchar_t *arg;
37 unsigned int cmdlen;
38 STARTUPINFOW start;
39 PROCESS_INFORMATION proc;
40
41 wchar_t wpath[MAX_PATH + 1];
42
43 wchar_t *pathbuf;
44 DWORD pathbuf_len, alloc_len;
45 wchar_t *ptr;
46 wchar_t *non_const_filename;
47 wchar_t *wcmd;
48 int wargc;
49 int timeout = 0;
50 ssize_t wrote;
51
52 HANDLE job;
53
54 if (argc < 3)
55 {
56 printf
57 ("arg 1: timeout in sec., arg 2: executable, arg<n> arguments\n");
58 exit (1);
59 }
60
61 timeout = atoi (argv[1]);
62
63 if (timeout == 0)
64 timeout = 600;
65
66 commandline = GetCommandLineW ();
67 if (commandline == NULL)
68 {
69 printf ("Failed to get commandline: %lu\n", GetLastError ());
70 exit (2);
71 }
72
73 wargv = CommandLineToArgvW (commandline, &wargc);
74 if (wargv == NULL || wargc <= 1)
75 {
76 printf ("Failed to get parse commandline: %lu\n", GetLastError ());
77 exit (3);
78 }
79
80 job = CreateJobObject (NULL, NULL);
81 if (job == NULL)
82 {
83 printf ("Failed to create a job: %lu\n", GetLastError ());
84 exit (4);
85 }
86
87 pathbuf_len = GetEnvironmentVariableW (L"PATH", (wchar_t *) &pathbuf, 0);
88
89 alloc_len = pathbuf_len + 1;
90
91 pathbuf = malloc (alloc_len * sizeof (wchar_t));
92
93 ptr = pathbuf;
94
95 alloc_len = GetEnvironmentVariableW (L"PATH", ptr, pathbuf_len);
96
97 cmdlen = wcslen (wargv[2]);
98 if (cmdlen < 5 || wcscmp (&wargv[2][cmdlen - 4], L".exe") != 0)
99 {
100 non_const_filename = malloc (sizeof (wchar_t) * (cmdlen + 5));
101 swprintf (non_const_filename, cmdlen + 5, L"%S.exe", wargv[2]);
102 }
103 else
104 {
105 non_const_filename = wcsdup (wargv[2]);
106 }
107
108 /* Check that this is the full path. If it isn't, search. */
109 if (non_const_filename[1] == L':')
110 swprintf (wpath, sizeof (wpath) / sizeof (wchar_t), L"%S", non_const_filename);
111 else if (!SearchPathW
112 (pathbuf, non_const_filename, NULL, sizeof (wpath) / sizeof (wchar_t),
113 wpath, NULL))
114 {
115 printf ("Failed to get find executable: %lu\n", GetLastError ());
116 exit (5);
117 }
118 free (pathbuf);
119 free (non_const_filename);
120
121 cmdlen = wcslen (wpath) + 4;
122 i = 3;
123 while (NULL != (arg = wargv[i++]))
124 cmdlen += wcslen (arg) + 4;
125
126 wcmd = malloc (sizeof (wchar_t) * (cmdlen + 1));
127 wrote = 0;
128 i = 2;
129 while (NULL != (arg = wargv[i++]))
130 {
131 /* This is to escape trailing slash */
132 wchar_t arg_lastchar = arg[wcslen (arg) - 1];
133 if (wrote == 0)
134 {
135 wrote += swprintf (&wcmd[wrote], cmdlen + 1 - wrote, L"\"%S%S\" ", wpath,
136 arg_lastchar == L'\\' ? L"\\" : L"");
137 }
138 else
139 {
140 if (wcschr (arg, L' ') != NULL)
141 wrote += swprintf (&wcmd[wrote], cmdlen + 1 - wrote, L"\"%S%S\"%S", arg,
142 arg_lastchar == L'\\' ? L"\\" : L"", i == wargc ? L"" : L" ");
143 else
144 wrote += swprintf (&wcmd[wrote], cmdlen + 1 - wrote, L"%S%S%S", arg,
145 arg_lastchar == L'\\' ? L"\\" : L"", i == wargc ? L"" : L" ");
146 }
147 }
148
149 LocalFree (wargv);
150
151 memset (&start, 0, sizeof (start));
152 start.cb = sizeof (start);
153
154 if (!CreateProcessW (wpath, wcmd, NULL, NULL, TRUE, CREATE_SUSPENDED,
155 NULL, NULL, &start, &proc))
156 {
157 wprintf (L"Failed to get spawn process `%S' with arguments `%S': %lu\n", wpath, wcmd, GetLastError ());
158 exit (6);
159 }
160
161 AssignProcessToJobObject (job, proc.hProcess);
162
163 ResumeThread (proc.hThread);
164 CloseHandle (proc.hThread);
165
166 free (wcmd);
167
168 wait_result = WaitForSingleObject (proc.hProcess, timeout * 1000);
169 if (wait_result == WAIT_OBJECT_0)
170 {
171 DWORD status;
172 wait_result = GetExitCodeProcess (proc.hProcess, &status);
173 CloseHandle (proc.hProcess);
174 if (wait_result != 0)
175 {
176 printf ("Test process exited with result %lu\n", status);
177 TerminateJobObject (job, status);
178 exit (status);
179 }
180 printf ("Test process exited (failed to obtain exit status)\n");
181 TerminateJobObject (job, 0);
182 exit (0);
183 }
184 printf ("Child processes were killed after timeout of %u seconds\n",
185 timeout);
186 TerminateJobObject (job, 1);
187 CloseHandle (proc.hProcess);
188 exit (1);
189}
190
191/* end of timeout_watchdog_w32.c */
diff --git a/src/util/gnunet-timeout.c b/src/util/gnunet-timeout.c
new file mode 100644
index 000000000..8dfb6ad17
--- /dev/null
+++ b/src/util/gnunet-timeout.c
@@ -0,0 +1,128 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2010 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17*/
18
19/**
20 * @file src/util/gnunet-timeout.c
21 * @brief small tool starting a child process, waiting that it terminates or killing it after a given timeout period
22 * @author Matthias Wachs
23 */
24
25#include <sys/types.h>
26#include <sys/wait.h>
27#include <signal.h>
28#include <stdio.h>
29#include <stdlib.h>
30#include <unistd.h>
31
32static pid_t child;
33
34
35static void
36sigchld_handler (int val)
37{
38 int status = 0;
39 int ret = 0;
40
41 (void) val;
42 waitpid (child,
43 &status,
44 0);
45 if (WIFEXITED (status) != 0)
46 {
47 ret = WEXITSTATUS (status);
48 fprintf (stderr,
49 "Process exited with result %u\n",
50 ret);
51 exit (ret); /* return same status code */
52 }
53 if (WIFSIGNALED (status) != 0)
54 {
55 ret = WTERMSIG (status);
56 fprintf (stderr,
57 "Process received signal %u\n",
58 ret);
59 kill (getpid (),
60 ret); /* kill self with the same signal */
61 }
62 exit (-1);
63}
64
65
66static void
67sigint_handler (int val)
68{
69 kill (0,
70 val);
71 exit (val);
72}
73
74
75int
76main (int argc,
77 char *argv[])
78{
79 int timeout = 0;
80 pid_t gpid = 0;
81
82 if (argc < 3)
83 {
84 fprintf (stderr,
85 "arg 1: timeout in sec., arg 2: executable, arg<n> arguments\n");
86 exit (-1);
87 }
88
89 timeout = atoi (argv[1]);
90
91 if (timeout == 0)
92 timeout = 600;
93
94 /* with getpgid() it does not compile, but getpgrp is the BSD version and working */
95 gpid = getpgrp ();
96
97 signal (SIGCHLD, sigchld_handler);
98 signal (SIGABRT, sigint_handler);
99 signal (SIGFPE, sigint_handler);
100 signal (SIGILL, sigint_handler);
101 signal (SIGINT, sigint_handler);
102 signal (SIGSEGV, sigint_handler);
103 signal (SIGTERM, sigint_handler);
104
105 child = fork ();
106 if (child == 0)
107 {
108 /* int setpgrp(pid_t pid, pid_t pgid); is not working on this machine */
109 //setpgrp (0, pid_t gpid);
110 if (-1 != gpid)
111 setpgid (0, gpid);
112 execvp (argv[2],
113 &argv[2]);
114 exit (-1);
115 }
116 if (child > 0)
117 {
118 sleep (timeout);
119 printf ("Child processes were killed after timeout of %u seconds\n",
120 timeout);
121 kill (0,
122 SIGTERM);
123 exit (3);
124 }
125 exit (-1);
126}
127
128/* end of timeout_watchdog.c */
diff --git a/src/util/resolver.h b/src/util/resolver.h
index a0f105afa..07851d052 100644
--- a/src/util/resolver.h
+++ b/src/util/resolver.h
@@ -60,7 +60,7 @@ struct GNUNET_RESOLVER_GetMessage
60 * identifies the request and is contained in the response message. The 60 * identifies the request and is contained in the response message. The
61 * client has to match response to request by this identifier. 61 * client has to match response to request by this identifier.
62 */ 62 */
63 uint32_t id GNUNET_PACKED; 63 uint16_t id GNUNET_PACKED;
64 64
65 /* followed by 0-terminated string for A/AAAA-lookup or 65 /* followed by 0-terminated string for A/AAAA-lookup or
66 by 'struct in_addr' / 'struct in6_addr' for reverse lookup */ 66 by 'struct in_addr' / 'struct in6_addr' for reverse lookup */
@@ -79,7 +79,7 @@ struct GNUNET_RESOLVER_ResponseMessage
79 * identifies the request this message responds to. The client 79 * identifies the request this message responds to. The client
80 * has to match response to request by this identifier. 80 * has to match response to request by this identifier.
81 */ 81 */
82 uint32_t id GNUNET_PACKED; 82 uint16_t id GNUNET_PACKED;
83 83
84 /* followed by 0-terminated string for response to a reverse lookup 84 /* followed by 0-terminated string for response to a reverse lookup
85 * or by 'struct in_addr' / 'struct in6_addr' for response to 85 * or by 'struct in_addr' / 'struct in6_addr' for response to
diff --git a/src/util/resolver_api.c b/src/util/resolver_api.c
index b94819f06..8a054327b 100644
--- a/src/util/resolver_api.c
+++ b/src/util/resolver_api.c
@@ -68,10 +68,10 @@ static struct GNUNET_RESOLVER_RequestHandle *req_head;
68 */ 68 */
69static struct GNUNET_RESOLVER_RequestHandle *req_tail; 69static struct GNUNET_RESOLVER_RequestHandle *req_tail;
70 70
71/** 71///**
72 * ID of the last request we sent to the service 72// * ID of the last request we sent to the service
73 */ 73// */
74static uint32_t last_request_id; 74//static uint16_t last_request_id;
75 75
76/** 76/**
77 * How long should we wait to reconnect? 77 * How long should we wait to reconnect?
@@ -445,7 +445,7 @@ process_requests ()
445 GNUNET_MESSAGE_TYPE_RESOLVER_REQUEST); 445 GNUNET_MESSAGE_TYPE_RESOLVER_REQUEST);
446 msg->direction = htonl (rh->direction); 446 msg->direction = htonl (rh->direction);
447 msg->af = htonl (rh->af); 447 msg->af = htonl (rh->af);
448 msg->id = htonl (rh->id); 448 msg->id = htons (rh->id);
449 GNUNET_memcpy (&msg[1], 449 GNUNET_memcpy (&msg[1],
450 &rh[1], 450 &rh[1],
451 rh->data_len); 451 rh->data_len);
@@ -491,7 +491,7 @@ handle_response (void *cls,
491 struct GNUNET_RESOLVER_RequestHandle *rh = req_head; 491 struct GNUNET_RESOLVER_RequestHandle *rh = req_head;
492 uint16_t size; 492 uint16_t size;
493 char *nret; 493 char *nret;
494 uint32_t request_id = msg->id; 494 uint16_t request_id = msg->id;
495 495
496 for (; rh != NULL; rh = rh->next) 496 for (; rh != NULL; rh = rh->next)
497 { 497 {
@@ -911,6 +911,14 @@ handle_lookup_timeout (void *cls)
911} 911}
912 912
913 913
914static uint16_t
915get_request_id ()
916{
917 return (uint16_t) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
918 UINT16_MAX);
919}
920
921
914/** 922/**
915 * Convert a string to one or more IP addresses. 923 * Convert a string to one or more IP addresses.
916 * 924 *
@@ -945,7 +953,8 @@ GNUNET_RESOLVER_ip_get (const char *hostname,
945 hostname); 953 hostname);
946 rh = GNUNET_malloc (sizeof (struct GNUNET_RESOLVER_RequestHandle) + slen); 954 rh = GNUNET_malloc (sizeof (struct GNUNET_RESOLVER_RequestHandle) + slen);
947 rh->af = af; 955 rh->af = af;
948 rh->id = ++last_request_id; 956 //rh->id = ++last_request_id;
957 rh->id = get_request_id ();
949 rh->addr_callback = callback; 958 rh->addr_callback = callback;
950 rh->cls = callback_cls; 959 rh->cls = callback_cls;
951 GNUNET_memcpy (&rh[1], 960 GNUNET_memcpy (&rh[1],
@@ -1092,7 +1101,8 @@ GNUNET_RESOLVER_hostname_get (const struct sockaddr *sa,
1092 rh->name_callback = callback; 1101 rh->name_callback = callback;
1093 rh->cls = cls; 1102 rh->cls = cls;
1094 rh->af = sa->sa_family; 1103 rh->af = sa->sa_family;
1095 rh->id = ++last_request_id; 1104 //rh->id = ++last_request_id;
1105 rh->id = get_request_id ();
1096 rh->timeout = GNUNET_TIME_relative_to_absolute (timeout); 1106 rh->timeout = GNUNET_TIME_relative_to_absolute (timeout);
1097 GNUNET_memcpy (&rh[1], 1107 GNUNET_memcpy (&rh[1],
1098 ip, 1108 ip,
diff --git a/src/util/scheduler.c b/src/util/scheduler.c
index 93d133d1b..5d3836639 100644
--- a/src/util/scheduler.c
+++ b/src/util/scheduler.c
@@ -965,8 +965,6 @@ GNUNET_SCHEDULER_cancel (struct GNUNET_SCHEDULER_Task *task)
965 965
966 /* scheduler must be running */ 966 /* scheduler must be running */
967 GNUNET_assert (NULL != scheduler_driver); 967 GNUNET_assert (NULL != scheduler_driver);
968 GNUNET_assert ( (NULL != active_task) ||
969 (GNUNET_NO == task->lifeness) );
970 is_fd_task = (NULL != task->fds); 968 is_fd_task = (NULL != task->fds);
971 if (is_fd_task) 969 if (is_fd_task)
972 { 970 {
@@ -1056,9 +1054,9 @@ GNUNET_SCHEDULER_add_with_reason_and_priority (GNUNET_SCHEDULER_TaskCallback tas
1056{ 1054{
1057 struct GNUNET_SCHEDULER_Task *t; 1055 struct GNUNET_SCHEDULER_Task *t;
1058 1056
1057 /* scheduler must be running */
1058 GNUNET_assert (NULL != scheduler_driver);
1059 GNUNET_assert (NULL != task); 1059 GNUNET_assert (NULL != task);
1060 GNUNET_assert ((NULL != active_task) ||
1061 (GNUNET_SCHEDULER_REASON_STARTUP == reason));
1062 t = GNUNET_new (struct GNUNET_SCHEDULER_Task); 1060 t = GNUNET_new (struct GNUNET_SCHEDULER_Task);
1063 t->read_fd = -1; 1061 t->read_fd = -1;
1064 t->write_fd = -1; 1062 t->write_fd = -1;
@@ -1099,7 +1097,8 @@ GNUNET_SCHEDULER_add_at_with_priority (struct GNUNET_TIME_Absolute at,
1099 struct GNUNET_SCHEDULER_Task *pos; 1097 struct GNUNET_SCHEDULER_Task *pos;
1100 struct GNUNET_SCHEDULER_Task *prev; 1098 struct GNUNET_SCHEDULER_Task *prev;
1101 1099
1102 GNUNET_assert (NULL != active_task); 1100 /* scheduler must be running */
1101 GNUNET_assert (NULL != scheduler_driver);
1103 GNUNET_assert (NULL != task); 1102 GNUNET_assert (NULL != task);
1104 t = GNUNET_new (struct GNUNET_SCHEDULER_Task); 1103 t = GNUNET_new (struct GNUNET_SCHEDULER_Task);
1105 t->callback = task; 1104 t->callback = task;
@@ -1286,7 +1285,8 @@ GNUNET_SCHEDULER_add_shutdown (GNUNET_SCHEDULER_TaskCallback task,
1286{ 1285{
1287 struct GNUNET_SCHEDULER_Task *t; 1286 struct GNUNET_SCHEDULER_Task *t;
1288 1287
1289 GNUNET_assert (NULL != active_task); 1288 /* scheduler must be running */
1289 GNUNET_assert (NULL != scheduler_driver);
1290 GNUNET_assert (NULL != task); 1290 GNUNET_assert (NULL != task);
1291 t = GNUNET_new (struct GNUNET_SCHEDULER_Task); 1291 t = GNUNET_new (struct GNUNET_SCHEDULER_Task);
1292 t->callback = task; 1292 t->callback = task;
@@ -1403,7 +1403,8 @@ add_without_sets (struct GNUNET_TIME_Relative delay,
1403{ 1403{
1404 struct GNUNET_SCHEDULER_Task *t; 1404 struct GNUNET_SCHEDULER_Task *t;
1405 1405
1406 GNUNET_assert (NULL != active_task); 1406 /* scheduler must be running */
1407 GNUNET_assert (NULL != scheduler_driver);
1407 GNUNET_assert (NULL != task); 1408 GNUNET_assert (NULL != task);
1408 t = GNUNET_new (struct GNUNET_SCHEDULER_Task); 1409 t = GNUNET_new (struct GNUNET_SCHEDULER_Task);
1409 init_fd_info (t, 1410 init_fd_info (t,
@@ -1832,7 +1833,6 @@ GNUNET_SCHEDULER_add_select (enum GNUNET_SCHEDULER_Priority prio,
1832 1833
1833 /* scheduler must be running */ 1834 /* scheduler must be running */
1834 GNUNET_assert (NULL != scheduler_driver); 1835 GNUNET_assert (NULL != scheduler_driver);
1835 GNUNET_assert (NULL != active_task);
1836 GNUNET_assert (NULL != task); 1836 GNUNET_assert (NULL != task);
1837 int no_rs = (NULL == rs); 1837 int no_rs = (NULL == rs);
1838 int no_ws = (NULL == ws); 1838 int no_ws = (NULL == ws);
@@ -2022,99 +2022,109 @@ GNUNET_SCHEDULER_do_work (struct GNUNET_SCHEDULER_Handle *sh)
2022 if (timeout.abs_value_us > now.abs_value_us) 2022 if (timeout.abs_value_us > now.abs_value_us)
2023 { 2023 {
2024 /** 2024 /**
2025 * The driver called this function before the current timeout was 2025 * The event loop called this function before the current timeout was
2026 * reached (and no FD tasks are ready). This can happen in the 2026 * reached (and no FD tasks are ready). This is acceptable if
2027 * rare case when the system time is changed while the driver is 2027 *
2028 * waiting for the timeout, so we handle this gracefully. It might 2028 * - the system time was changed while the driver was waiting for
2029 * also be a programming error in the driver though. 2029 * the timeout
2030 * - an external event loop called GNUnet API functions outside of
2031 * the callbacks called in GNUNET_SCHEDULER_do_work and thus
2032 * wasn't notified about the new timeout
2033 *
2034 * It might also mean we are busy-waiting because of a programming
2035 * error in the external event loop.
2030 */ 2036 */
2031 LOG (GNUNET_ERROR_TYPE_DEBUG, 2037 LOG (GNUNET_ERROR_TYPE_DEBUG,
2032 "GNUNET_SCHEDULER_do_work did not find any ready " 2038 "GNUNET_SCHEDULER_do_work did not find any ready "
2033 "tasks and timeout has not been reached yet.\n"); 2039 "tasks and timeout has not been reached yet.\n");
2034 return GNUNET_NO;
2035 } 2040 }
2036 /** 2041 else
2037 * the current timeout was reached but no ready tasks were found, 2042 {
2038 * internal scheduler error! 2043 /**
2039 */ 2044 * the current timeout was reached but no ready tasks were found,
2040 GNUNET_assert (0); 2045 * internal scheduler error!
2041 } 2046 */
2042 2047 GNUNET_assert (0);
2043 /* find out which task priority level we are going to 2048 }
2044 process this time */
2045 max_priority_added = GNUNET_SCHEDULER_PRIORITY_KEEP;
2046 GNUNET_assert (NULL == ready_head[GNUNET_SCHEDULER_PRIORITY_KEEP]);
2047 /* yes, p>0 is correct, 0 is "KEEP" which should
2048 * always be an empty queue (see assertion)! */
2049 for (p = GNUNET_SCHEDULER_PRIORITY_COUNT - 1; p > 0; p--)
2050 {
2051 pos = ready_head[p];
2052 if (NULL != pos)
2053 break;
2054 } 2049 }
2055 GNUNET_assert (NULL != pos); /* ready_count wrong? */ 2050 else
2056
2057 /* process all tasks at this priority level, then yield */
2058 while (NULL != (pos = ready_head[p]))
2059 { 2051 {
2060 GNUNET_CONTAINER_DLL_remove (ready_head[p], 2052 /* find out which task priority level we are going to
2061 ready_tail[p], 2053 process this time */
2062 pos); 2054 max_priority_added = GNUNET_SCHEDULER_PRIORITY_KEEP;
2063 ready_count--; 2055 GNUNET_assert (NULL == ready_head[GNUNET_SCHEDULER_PRIORITY_KEEP]);
2064 current_priority = pos->priority; 2056 /* yes, p>0 is correct, 0 is "KEEP" which should
2065 current_lifeness = pos->lifeness; 2057 * always be an empty queue (see assertion)! */
2066 active_task = pos; 2058 for (p = GNUNET_SCHEDULER_PRIORITY_COUNT - 1; p > 0; p--)
2067#if PROFILE_DELAYS
2068 if (GNUNET_TIME_absolute_get_duration (pos->start_time).rel_value_us >
2069 DELAY_THRESHOLD.rel_value_us)
2070 { 2059 {
2071 LOG (GNUNET_ERROR_TYPE_DEBUG, 2060 pos = ready_head[p];
2072 "Task %p took %s to be scheduled\n", 2061 if (NULL != pos)
2073 pos, 2062 break;
2074 GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_duration (pos->start_time),
2075 GNUNET_YES));
2076 } 2063 }
2077#endif 2064 GNUNET_assert (NULL != pos); /* ready_count wrong? */
2078 tc.reason = pos->reason; 2065
2079 GNUNET_NETWORK_fdset_zero (sh->rs); 2066 /* process all tasks at this priority level, then yield */
2080 GNUNET_NETWORK_fdset_zero (sh->ws); 2067 while (NULL != (pos = ready_head[p]))
2081 // FIXME: do we have to remove FdInfos from fds if they are not ready?
2082 tc.fds_len = pos->fds_len;
2083 tc.fds = pos->fds;
2084 for (unsigned int i = 0; i != pos->fds_len; ++i)
2085 { 2068 {
2086 struct GNUNET_SCHEDULER_FdInfo *fdi = &pos->fds[i]; 2069 GNUNET_CONTAINER_DLL_remove (ready_head[p],
2087 if (0 != (GNUNET_SCHEDULER_ET_IN & fdi->et)) 2070 ready_tail[p],
2071 pos);
2072 ready_count--;
2073 current_priority = pos->priority;
2074 current_lifeness = pos->lifeness;
2075 active_task = pos;
2076#if PROFILE_DELAYS
2077 if (GNUNET_TIME_absolute_get_duration (pos->start_time).rel_value_us >
2078 DELAY_THRESHOLD.rel_value_us)
2088 { 2079 {
2089 GNUNET_NETWORK_fdset_set_native (sh->rs, 2080 LOG (GNUNET_ERROR_TYPE_DEBUG,
2090 fdi->sock); 2081 "Task %p took %s to be scheduled\n",
2082 pos,
2083 GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_duration (pos->start_time),
2084 GNUNET_YES));
2091 } 2085 }
2092 if (0 != (GNUNET_SCHEDULER_ET_OUT & fdi->et)) 2086#endif
2087 tc.reason = pos->reason;
2088 GNUNET_NETWORK_fdset_zero (sh->rs);
2089 GNUNET_NETWORK_fdset_zero (sh->ws);
2090 // FIXME: do we have to remove FdInfos from fds if they are not ready?
2091 tc.fds_len = pos->fds_len;
2092 tc.fds = pos->fds;
2093 for (unsigned int i = 0; i != pos->fds_len; ++i)
2093 { 2094 {
2094 GNUNET_NETWORK_fdset_set_native (sh->ws, 2095 struct GNUNET_SCHEDULER_FdInfo *fdi = &pos->fds[i];
2095 fdi->sock); 2096 if (0 != (GNUNET_SCHEDULER_ET_IN & fdi->et))
2097 {
2098 GNUNET_NETWORK_fdset_set_native (sh->rs,
2099 fdi->sock);
2100 }
2101 if (0 != (GNUNET_SCHEDULER_ET_OUT & fdi->et))
2102 {
2103 GNUNET_NETWORK_fdset_set_native (sh->ws,
2104 fdi->sock);
2105 }
2096 } 2106 }
2097 } 2107 tc.read_ready = sh->rs;
2098 tc.read_ready = sh->rs; 2108 tc.write_ready = sh->ws;
2099 tc.write_ready = sh->ws; 2109 LOG (GNUNET_ERROR_TYPE_DEBUG,
2100 LOG (GNUNET_ERROR_TYPE_DEBUG, 2110 "Running task %p\n",
2101 "Running task %p\n", 2111 pos);
2102 pos); 2112 GNUNET_assert (NULL != pos->callback);
2103 GNUNET_assert (NULL != pos->callback); 2113 pos->callback (pos->callback_cls);
2104 pos->callback (pos->callback_cls); 2114 if (NULL != pos->fds)
2105 if (NULL != pos->fds)
2106 {
2107 int del_result = scheduler_driver->del (scheduler_driver->cls, pos);
2108 if (GNUNET_OK != del_result)
2109 { 2115 {
2110 LOG (GNUNET_ERROR_TYPE_ERROR, 2116 int del_result = scheduler_driver->del (scheduler_driver->cls, pos);
2111 "driver could not delete task %p\n", pos); 2117 if (GNUNET_OK != del_result)
2112 GNUNET_assert (0); 2118 {
2119 LOG (GNUNET_ERROR_TYPE_ERROR,
2120 "driver could not delete task %p\n", pos);
2121 GNUNET_assert (0);
2122 }
2113 } 2123 }
2124 active_task = NULL;
2125 dump_backtrace (pos);
2126 destroy_task (pos);
2114 } 2127 }
2115 active_task = NULL;
2116 dump_backtrace (pos);
2117 destroy_task (pos);
2118 } 2128 }
2119 shutdown_if_no_lifeness (); 2129 shutdown_if_no_lifeness ();
2120 if (0 == ready_count) 2130 if (0 == ready_count)
@@ -2164,12 +2174,12 @@ struct GNUNET_SCHEDULER_Handle *
2164GNUNET_SCHEDULER_driver_init (const struct GNUNET_SCHEDULER_Driver *driver) 2174GNUNET_SCHEDULER_driver_init (const struct GNUNET_SCHEDULER_Driver *driver)
2165{ 2175{
2166 struct GNUNET_SCHEDULER_Handle *sh; 2176 struct GNUNET_SCHEDULER_Handle *sh;
2167 struct GNUNET_SCHEDULER_Task tsk;
2168 const struct GNUNET_DISK_FileHandle *pr; 2177 const struct GNUNET_DISK_FileHandle *pr;
2169 2178
2170 /* general set-up */ 2179 /* scheduler must not be running */
2171 GNUNET_assert (NULL == active_task); 2180 GNUNET_assert (NULL == scheduler_driver);
2172 GNUNET_assert (NULL == shutdown_pipe_handle); 2181 GNUNET_assert (NULL == shutdown_pipe_handle);
2182 /* general set-up */
2173 sh = GNUNET_new (struct GNUNET_SCHEDULER_Handle); 2183 sh = GNUNET_new (struct GNUNET_SCHEDULER_Handle);
2174 shutdown_pipe_handle = GNUNET_DISK_pipe (GNUNET_NO, 2184 shutdown_pipe_handle = GNUNET_DISK_pipe (GNUNET_NO,
2175 GNUNET_NO, 2185 GNUNET_NO,
@@ -2204,10 +2214,6 @@ GNUNET_SCHEDULER_driver_init (const struct GNUNET_SCHEDULER_Driver *driver)
2204 /* Setup initial tasks */ 2214 /* Setup initial tasks */
2205 current_priority = GNUNET_SCHEDULER_PRIORITY_DEFAULT; 2215 current_priority = GNUNET_SCHEDULER_PRIORITY_DEFAULT;
2206 current_lifeness = GNUNET_NO; 2216 current_lifeness = GNUNET_NO;
2207 memset (&tsk,
2208 0,
2209 sizeof (tsk));
2210 active_task = &tsk;
2211 install_parent_control_task = 2217 install_parent_control_task =
2212 GNUNET_SCHEDULER_add_now (&install_parent_control_handler, 2218 GNUNET_SCHEDULER_add_now (&install_parent_control_handler,
2213 NULL); 2219 NULL);
@@ -2217,7 +2223,6 @@ GNUNET_SCHEDULER_driver_init (const struct GNUNET_SCHEDULER_Driver *driver)
2217 &shutdown_pipe_cb, 2223 &shutdown_pipe_cb,
2218 NULL); 2224 NULL);
2219 current_lifeness = GNUNET_YES; 2225 current_lifeness = GNUNET_YES;
2220 active_task = NULL;
2221 scheduler_driver->set_wakeup (scheduler_driver->cls, 2226 scheduler_driver->set_wakeup (scheduler_driver->cls,
2222 get_timeout ()); 2227 get_timeout ());
2223 /* begin main event loop */ 2228 /* begin main event loop */
diff --git a/src/util/strings.c b/src/util/strings.c
index 5ed195933..ea3c8cfb9 100644
--- a/src/util/strings.c
+++ b/src/util/strings.c
@@ -11,7 +11,7 @@
11 WITHOUT ANY WARRANTY; without even the implied warranty of 11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details. 13 Affero General Public License for more details.
14 14
15 You should have received a copy of the GNU Affero General Public License 15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>. 16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17*/ 17*/
@@ -1947,27 +1947,27 @@ static char *cvt =
1947/** 1947/**
1948 * Encode into Base64. 1948 * Encode into Base64.
1949 * 1949 *
1950 * @param data the data to encode 1950 * @param in the data to encode
1951 * @param len the length of the input 1951 * @param len the length of the input
1952 * @param output where to write the output (*output should be NULL, 1952 * @param output where to write the output (*output should be NULL,
1953 * is allocated) 1953 * is allocated)
1954 * @return the size of the output 1954 * @return the size of the output
1955 */ 1955 */
1956size_t 1956size_t
1957GNUNET_STRINGS_base64_encode (const char *data, 1957GNUNET_STRINGS_base64_encode (const void *in,
1958 size_t len, 1958 size_t len,
1959 char **output) 1959 char **output)
1960{ 1960{
1961 size_t i; 1961 const char *data = in;
1962 char c;
1963 size_t ret; 1962 size_t ret;
1964 char *opt; 1963 char *opt;
1965 1964
1966 ret = 0; 1965 ret = 0;
1967 opt = GNUNET_malloc (2 + (len * 4 / 3) + 8); 1966 opt = GNUNET_malloc (2 + (len * 4 / 3) + 8);
1968 *output = opt; 1967 for (size_t i = 0; i < len; ++i)
1969 for (i = 0; i < len; ++i)
1970 { 1968 {
1969 char c;
1970
1971 c = (data[i] >> 2) & 0x3f; 1971 c = (data[i] >> 2) & 0x3f;
1972 opt[ret++] = cvt[(int) c]; 1972 opt[ret++] = cvt[(int) c];
1973 c = (data[i] << 4) & 0x3f; 1973 c = (data[i] << 4) & 0x3f;
@@ -1997,6 +1997,7 @@ GNUNET_STRINGS_base64_encode (const char *data,
1997 } 1997 }
1998 } 1998 }
1999 opt[ret++] = FILLCHAR; 1999 opt[ret++] = FILLCHAR;
2000 *output = opt;
2000 return ret; 2001 return ret;
2001} 2002}
2002 2003
@@ -2018,11 +2019,10 @@ GNUNET_STRINGS_base64_encode (const char *data,
2018 */ 2019 */
2019size_t 2020size_t
2020GNUNET_STRINGS_base64_decode (const char *data, 2021GNUNET_STRINGS_base64_decode (const char *data,
2021 size_t len, char **output) 2022 size_t len,
2023 void **out)
2022{ 2024{
2023 size_t i; 2025 char *output;
2024 char c;
2025 char c1;
2026 size_t ret = 0; 2026 size_t ret = 0;
2027 2027
2028#define CHECK_CRLF while (data[i] == '\r' || data[i] == '\n') {\ 2028#define CHECK_CRLF while (data[i] == '\r' || data[i] == '\n') {\
@@ -2031,12 +2031,15 @@ GNUNET_STRINGS_base64_decode (const char *data,
2031 if (i >= len) goto END; \ 2031 if (i >= len) goto END; \
2032 } 2032 }
2033 2033
2034 *output = GNUNET_malloc ((len * 3 / 4) + 8); 2034 output = GNUNET_malloc ((len * 3 / 4) + 8);
2035 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 2035 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2036 "base64_decode decoding len=%d\n", 2036 "base64_decode decoding len=%d\n",
2037 (int) len); 2037 (int) len);
2038 for (i = 0; i < len; ++i) 2038 for (size_t i = 0; i < len; ++i)
2039 { 2039 {
2040 char c;
2041 char c1;
2042
2040 CHECK_CRLF; 2043 CHECK_CRLF;
2041 if (FILLCHAR == data[i]) 2044 if (FILLCHAR == data[i])
2042 break; 2045 break;
@@ -2045,7 +2048,7 @@ GNUNET_STRINGS_base64_decode (const char *data,
2045 CHECK_CRLF; 2048 CHECK_CRLF;
2046 c1 = (char) cvtfind (data[i]); 2049 c1 = (char) cvtfind (data[i]);
2047 c = (c << 2) | ((c1 >> 4) & 0x3); 2050 c = (c << 2) | ((c1 >> 4) & 0x3);
2048 (*output)[ret++] = c; 2051 output[ret++] = c;
2049 if (++i < len) 2052 if (++i < len)
2050 { 2053 {
2051 CHECK_CRLF; 2054 CHECK_CRLF;
@@ -2054,7 +2057,7 @@ GNUNET_STRINGS_base64_decode (const char *data,
2054 break; 2057 break;
2055 c = (char) cvtfind (c); 2058 c = (char) cvtfind (c);
2056 c1 = ((c1 << 4) & 0xf0) | ((c >> 2) & 0xf); 2059 c1 = ((c1 << 4) & 0xf0) | ((c >> 2) & 0xf);
2057 (*output)[ret++] = c1; 2060 output[ret++] = c1;
2058 } 2061 }
2059 if (++i < len) 2062 if (++i < len)
2060 { 2063 {
@@ -2065,15 +2068,13 @@ GNUNET_STRINGS_base64_decode (const char *data,
2065 2068
2066 c1 = (char) cvtfind (c1); 2069 c1 = (char) cvtfind (c1);
2067 c = ((c << 6) & 0xc0) | c1; 2070 c = ((c << 6) & 0xc0) | c1;
2068 (*output)[ret++] = c; 2071 output[ret++] = c;
2069 } 2072 }
2070 } 2073 }
2071END: 2074END:
2075 *out = output;
2072 return ret; 2076 return ret;
2073} 2077}
2074 2078
2075 2079
2076
2077
2078
2079/* end of strings.c */ 2080/* end of strings.c */