diff options
Diffstat (limited to 'src/util')
-rw-r--r-- | src/util/.gitignore | 4 | ||||
-rw-r--r-- | src/util/Makefile.am | 16 | ||||
-rw-r--r-- | src/util/client.c | 13 | ||||
-rw-r--r-- | src/util/crypto_hash.c | 26 | ||||
-rw-r--r-- | src/util/dnsparser.c | 125 | ||||
-rw-r--r-- | src/util/gnunet-service-resolver.c | 1173 | ||||
-rw-r--r-- | src/util/gnunet-timeout-w32.c | 191 | ||||
-rw-r--r-- | src/util/gnunet-timeout.c | 128 | ||||
-rw-r--r-- | src/util/resolver.h | 4 | ||||
-rw-r--r-- | src/util/resolver_api.c | 26 | ||||
-rw-r--r-- | src/util/scheduler.c | 189 | ||||
-rw-r--r-- | src/util/strings.c | 39 |
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 | |||
69 | perf_crypto_symmetric | 69 | perf_crypto_symmetric |
70 | perf_crypto_rsa | 70 | perf_crypto_rsa |
71 | perf_crypto_ecc_dlog | 71 | perf_crypto_ecc_dlog |
72 | test_hexcoder | ||
73 | test_regex | ||
74 | test_tun | ||
75 | gnunet-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 | ||
167 | libexec_PROGRAMS = \ | 167 | libexec_PROGRAMS = \ |
168 | gnunet-service-resolver \ | 168 | gnunet-service-resolver \ |
169 | gnunet-timeout \ | ||
169 | $(W32CONSOLEHELPER) | 170 | $(W32CONSOLEHELPER) |
170 | 171 | ||
171 | bin_SCRIPTS =\ | 172 | bin_SCRIPTS =\ |
@@ -192,6 +193,15 @@ endif | |||
192 | endif | 193 | endif |
193 | 194 | ||
194 | 195 | ||
196 | if !MINGW | ||
197 | gnunet_timeout_SOURCES = \ | ||
198 | gnunet-timeout.c | ||
199 | else | ||
200 | gnunet_timeout_SOURCES = \ | ||
201 | gnunet-timeout-w32.c | ||
202 | endif | ||
203 | |||
204 | |||
195 | do_subst = $(SED) -e 's,[@]PYTHON[@],$(PYTHON),g' | 205 | do_subst = $(SED) -e 's,[@]PYTHON[@],$(PYTHON),g' |
196 | 206 | ||
197 | gnunet-qr: gnunet-qr.py.in Makefile | 207 | gnunet-qr: gnunet-qr.py.in Makefile |
@@ -334,12 +344,12 @@ test_hexcoder_LDADD = \ | |||
334 | test_tun_SOURCES = \ | 344 | test_tun_SOURCES = \ |
335 | test_tun.c | 345 | test_tun.c |
336 | test_tun_LDADD = \ | 346 | test_tun_LDADD = \ |
337 | libgnunetutil.la | 347 | libgnunetutil.la |
338 | 348 | ||
339 | test_regex_SOURCES = \ | 349 | test_regex_SOURCES = \ |
340 | test_regex.c | 350 | test_regex.c |
341 | test_regex_LDADD = \ | 351 | test_regex_LDADD = \ |
342 | libgnunetutil.la | 352 | libgnunetutil.la |
343 | 353 | ||
344 | test_os_start_process_SOURCES = \ | 354 | test_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 | */ |
374 | void | 377 | void |
375 | GNUNET_CRYPTO_hmac (const struct GNUNET_CRYPTO_AuthKey *key, | 378 | GNUNET_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 | */ | ||
412 | void | ||
413 | GNUNET_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 | */ |
404 | struct GNUNET_HashContext | 426 | struct 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 | */ | ||
767 | struct GNUNET_DNSPARSER_Record * | ||
768 | GNUNET_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 | */ | ||
818 | struct GNUNET_DNSPARSER_SoaRecord * | ||
819 | GNUNET_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 | */ | ||
835 | struct GNUNET_DNSPARSER_CertRecord * | ||
836 | GNUNET_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 | */ | ||
851 | struct GNUNET_DNSPARSER_MxRecord * | ||
852 | GNUNET_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 | */ | ||
867 | struct GNUNET_DNSPARSER_SrvRecord * | ||
868 | GNUNET_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 | |||
31 | struct 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 | */ |
33 | struct IPCache | 43 | struct 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 | */ |
80 | static struct IPCache *cache_head; | 97 | static 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 | */ |
85 | static struct IPCache *cache_tail; | 102 | static struct ResolveCache *cache_tail; |
86 | 103 | ||
87 | /** | 104 | /** |
88 | * Pipe for asynchronously notifying about resolve result | 105 | * context of dnsstub library |
89 | */ | 106 | */ |
90 | static struct GNUNET_DISK_PipeHandle *resolve_result_pipe; | 107 | static struct GNUNET_DNSSTUB_Context *dnsstub_ctx; |
91 | 108 | ||
92 | /** | ||
93 | * Task for reading from resolve_result_pipe | ||
94 | */ | ||
95 | static struct GNUNET_SCHEDULER_Task *resolve_result_pipe_task; | ||
96 | 109 | ||
97 | 110 | void 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 | */ | ||
104 | static void | ||
105 | getnameinfo_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 | 144 | static char* |
145 | extract_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 | */ |
166 | static void | 159 | static ssize_t |
167 | gethostbyaddr_resolve (struct IPCache *cache) | 160 | lookup_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 | /** | 208 | static char * |
189 | * Resolve the given request using the available methods. | 209 | make_reverse_hostname (const void *ip, int af) |
190 | * | ||
191 | * @param cache the request to resolve (and where to store the result) | ||
192 | */ | ||
193 | static void | ||
194 | cache_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 | */ | ||
214 | static void | 259 | static void |
215 | notify_service_client_done (void *cls) | 260 | send_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 | */ | ||
233 | static void | ||
234 | get_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 | ¬ify_service_client_done, | ||
330 | client); | ||
331 | GNUNET_MQ_send (mq, | ||
332 | env); | ||
333 | } | 301 | } |
334 | 302 | ||
335 | 303 | ||
336 | #if HAVE_GETADDRINFO_A | ||
337 | struct AsyncCls | ||
338 | { | ||
339 | struct gaicb *host; | ||
340 | struct sigevent *sig; | ||
341 | struct GNUNET_MQ_Handle *mq; | ||
342 | uint32_t request_id; | ||
343 | }; | ||
344 | |||
345 | |||
346 | static void | 304 | static void |
347 | resolve_result_pipe_cb (void *cls) | 305 | send_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; | 321 | static void |
365 | for (struct addrinfo *pos = host->ar_result; pos != NULL; pos = pos->ai_next) | 322 | handle_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 | ||
415 | static void | 398 | static void |
416 | handle_async_result (union sigval val) | 399 | handle_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 | ||
425 | static int | 417 | static int |
426 | getaddrinfo_a_resolve (struct GNUNET_MQ_Handle *mq, | 418 | resolve_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 | 480 | static const char * |
471 | static int | 481 | get_hostname (struct ResolveCache *cache_entry) |
472 | getaddrinfo_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 | 494 | static const uint16_t * |
572 | 495 | get_record_type (struct ResolveCache *cache_entry) | |
573 | |||
574 | static int | ||
575 | gethostbyname2_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) | 503 | static const struct GNUNET_TIME_Absolute * |
592 | { | 504 | get_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 | ||
656 | static int | 512 | static int |
657 | gethostbyname_resolve (struct GNUNET_MQ_Handle *mq, | 513 | remove_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 | */ |
701 | static void | 540 | static int |
702 | get_ip_from_hostname (struct GNUNET_SERVICE_Client *client, | 541 | try_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 | ¬ify_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 | ||
642 | static void | ||
643 | process_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 | |
719 | static void | ||
720 | shutdown_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 | ||
736 | static void | ||
737 | init_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, | |||
923 | GNUNET_SERVICE_MAIN | 817 | GNUNET_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 | */ | ||
956 | void __attribute__ ((destructor)) | ||
957 | GNUNET_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 | |||
29 | int | ||
30 | main (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 | |||
32 | static pid_t child; | ||
33 | |||
34 | |||
35 | static void | ||
36 | sigchld_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 | |||
66 | static void | ||
67 | sigint_handler (int val) | ||
68 | { | ||
69 | kill (0, | ||
70 | val); | ||
71 | exit (val); | ||
72 | } | ||
73 | |||
74 | |||
75 | int | ||
76 | main (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 | */ |
69 | static struct GNUNET_RESOLVER_RequestHandle *req_tail; | 69 | static 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 | // */ |
74 | static 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 | ||
914 | static uint16_t | ||
915 | get_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 * | |||
2164 | GNUNET_SCHEDULER_driver_init (const struct GNUNET_SCHEDULER_Driver *driver) | 2174 | GNUNET_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 | */ |
1956 | size_t | 1956 | size_t |
1957 | GNUNET_STRINGS_base64_encode (const char *data, | 1957 | GNUNET_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 | */ |
2019 | size_t | 2020 | size_t |
2020 | GNUNET_STRINGS_base64_decode (const char *data, | 2021 | GNUNET_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 | } |
2071 | END: | 2074 | END: |
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 */ |