| @@ -1,26 +1,16 @@ | ||
| c-ares version 1.9.0 | ||
|
|
||
| Changed: | ||
|
|
||
| o Added ares_parse_soa_reply | ||
|
|
||
| Fixed: | ||
|
|
||
| o libcares.pc generation for static MingW* cross builds | ||
| o ares_dup: UDP and TCP port byte order in saved options | ||
|
|
||
| Thanks go to these friendly people for their efforts and contributions: | ||
|
|
||
| Yang Tse, Nick Alcock, Marko Kreen | ||
|
|
||
| Have fun! |
| @@ -0,0 +1,188 @@ | ||
|
|
||
| /* Copyright 1998 by the Massachusetts Institute of Technology. | ||
| * Copyright (C) 2009 by Jakub Hrozek <jhrozek@redhat.com> | ||
| * | ||
| * Permission to use, copy, modify, and distribute this | ||
| * software and its documentation for any purpose and without | ||
| * fee is hereby granted, provided that the above copyright | ||
| * notice appear in all copies and that both that copyright | ||
| * notice and this permission notice appear in supporting | ||
| * documentation, and that the name of M.I.T. not be used in | ||
| * advertising or publicity pertaining to distribution of the | ||
| * software without specific, written prior permission. | ||
| * M.I.T. makes no representations about the suitability of | ||
| * this software for any purpose. It is provided "as is" | ||
| * without express or implied warranty. | ||
| */ | ||
|
|
||
| #include "ares_setup.h" | ||
|
|
||
| #ifdef HAVE_SYS_SOCKET_H | ||
| # include <sys/socket.h> | ||
| #endif | ||
| #ifdef HAVE_NETINET_IN_H | ||
| # include <netinet/in.h> | ||
| #endif | ||
| #ifdef HAVE_NETDB_H | ||
| # include <netdb.h> | ||
| #endif | ||
| #ifdef HAVE_ARPA_INET_H | ||
| # include <arpa/inet.h> | ||
| #endif | ||
| #ifdef HAVE_ARPA_NAMESER_H | ||
| # include <arpa/nameser.h> | ||
| #else | ||
| # include "nameser.h" | ||
| #endif | ||
| #ifdef HAVE_ARPA_NAMESER_COMPAT_H | ||
| # include <arpa/nameser_compat.h> | ||
| #endif | ||
|
|
||
| #include <stdlib.h> | ||
| #include <string.h> | ||
| #include "ares.h" | ||
| #include "ares_dns.h" | ||
| #include "ares_data.h" | ||
| #include "ares_private.h" | ||
|
|
||
| /* AIX portability check */ | ||
| #ifndef T_NAPTR | ||
| #define T_NAPTR 35 /* naming authority pointer */ | ||
| #endif | ||
|
|
||
| int | ||
| ares_parse_naptr_reply (const unsigned char *abuf, int alen, | ||
| struct ares_naptr_reply **naptr_out) | ||
| { | ||
| unsigned int qdcount, ancount, i; | ||
| const unsigned char *aptr, *vptr; | ||
| int status, rr_type, rr_class, rr_len; | ||
| long len; | ||
| char *hostname = NULL, *rr_name = NULL; | ||
| struct ares_naptr_reply *naptr_head = NULL; | ||
| struct ares_naptr_reply *naptr_last = NULL; | ||
| struct ares_naptr_reply *naptr_curr; | ||
|
|
||
| /* Set *naptr_out to NULL for all failure cases. */ | ||
| *naptr_out = NULL; | ||
|
|
||
| /* Give up if abuf doesn't have room for a header. */ | ||
| if (alen < HFIXEDSZ) | ||
| return ARES_EBADRESP; | ||
|
|
||
| /* Fetch the question and answer count from the header. */ | ||
| qdcount = DNS_HEADER_QDCOUNT (abuf); | ||
| ancount = DNS_HEADER_ANCOUNT (abuf); | ||
| if (qdcount != 1) | ||
| return ARES_EBADRESP; | ||
| if (ancount == 0) | ||
| return ARES_ENODATA; | ||
|
|
||
| /* Expand the name from the question, and skip past the question. */ | ||
| aptr = abuf + HFIXEDSZ; | ||
| status = ares_expand_name (aptr, abuf, alen, &hostname, &len); | ||
| if (status != ARES_SUCCESS) | ||
| return status; | ||
|
|
||
| if (aptr + len + QFIXEDSZ > abuf + alen) | ||
| { | ||
| free (hostname); | ||
| return ARES_EBADRESP; | ||
| } | ||
| aptr += len + QFIXEDSZ; | ||
|
|
||
| /* Examine each answer resource record (RR) in turn. */ | ||
| for (i = 0; i < ancount; i++) | ||
| { | ||
| /* Decode the RR up to the data field. */ | ||
| status = ares_expand_name (aptr, abuf, alen, &rr_name, &len); | ||
| if (status != ARES_SUCCESS) | ||
| { | ||
| break; | ||
| } | ||
| aptr += len; | ||
| if (aptr + RRFIXEDSZ > abuf + alen) | ||
| { | ||
| status = ARES_EBADRESP; | ||
| break; | ||
| } | ||
| rr_type = DNS_RR_TYPE (aptr); | ||
| rr_class = DNS_RR_CLASS (aptr); | ||
| rr_len = DNS_RR_LEN (aptr); | ||
| aptr += RRFIXEDSZ; | ||
|
|
||
| /* Check if we are really looking at a NAPTR record */ | ||
| if (rr_class == C_IN && rr_type == T_NAPTR) | ||
| { | ||
| /* parse the NAPTR record itself */ | ||
|
|
||
| /* Allocate storage for this NAPTR answer appending it to the list */ | ||
| naptr_curr = ares_malloc_data(ARES_DATATYPE_NAPTR_REPLY); | ||
| if (!naptr_curr) | ||
| { | ||
| status = ARES_ENOMEM; | ||
| break; | ||
| } | ||
| if (naptr_last) | ||
| { | ||
| naptr_last->next = naptr_curr; | ||
| } | ||
| else | ||
| { | ||
| naptr_head = naptr_curr; | ||
| } | ||
| naptr_last = naptr_curr; | ||
|
|
||
| vptr = aptr; | ||
| naptr_curr->order = DNS__16BIT(vptr); | ||
| vptr += sizeof(unsigned short); | ||
| naptr_curr->preference = DNS__16BIT(vptr); | ||
| vptr += sizeof(unsigned short); | ||
|
|
||
| status = ares_expand_string(vptr, abuf, alen, &naptr_curr->flags, &len); | ||
| if (status != ARES_SUCCESS) | ||
| break; | ||
| vptr += len; | ||
|
|
||
| status = ares_expand_string(vptr, abuf, alen, &naptr_curr->service, &len); | ||
| if (status != ARES_SUCCESS) | ||
| break; | ||
| vptr += len; | ||
|
|
||
| status = ares_expand_string(vptr, abuf, alen, &naptr_curr->regexp, &len); | ||
| if (status != ARES_SUCCESS) | ||
| break; | ||
| vptr += len; | ||
|
|
||
| status = ares_expand_name(vptr, abuf, alen, &naptr_curr->replacement, &len); | ||
| if (status != ARES_SUCCESS) | ||
| break; | ||
| } | ||
|
|
||
| /* Don't lose memory in the next iteration */ | ||
| free (rr_name); | ||
| rr_name = NULL; | ||
|
|
||
| /* Move on to the next record */ | ||
| aptr += rr_len; | ||
| } | ||
|
|
||
| if (hostname) | ||
| free (hostname); | ||
| if (rr_name) | ||
| free (rr_name); | ||
|
|
||
| /* clean up on error */ | ||
| if (status != ARES_SUCCESS) | ||
| { | ||
| if (naptr_head) | ||
| ares_free_data (naptr_head); | ||
| return status; | ||
| } | ||
|
|
||
| /* everything looks fine, return the data */ | ||
| *naptr_out = naptr_head; | ||
|
|
||
| return ARES_SUCCESS; | ||
| } | ||
|
|
| @@ -0,0 +1,135 @@ | ||
|
|
||
| /* Copyright 1998 by the Massachusetts Institute of Technology. | ||
| * Copyright (C) 2012 Marko Kreen <markokr@gmail.com> | ||
| * | ||
| * Permission to use, copy, modify, and distribute this | ||
| * software and its documentation for any purpose and without | ||
| * fee is hereby granted, provided that the above copyright | ||
| * notice appear in all copies and that both that copyright | ||
| * notice and this permission notice appear in supporting | ||
| * documentation, and that the name of M.I.T. not be used in | ||
| * advertising or publicity pertaining to distribution of the | ||
| * software without specific, written prior permission. | ||
| * M.I.T. makes no representations about the suitability of | ||
| * this software for any purpose. It is provided "as is" | ||
| * without express or implied warranty. | ||
| */ | ||
|
|
||
| #include "ares_setup.h" | ||
|
|
||
| #ifdef HAVE_SYS_SOCKET_H | ||
| # include <sys/socket.h> | ||
| #endif | ||
| #ifdef HAVE_NETINET_IN_H | ||
| # include <netinet/in.h> | ||
| #endif | ||
| #ifdef HAVE_NETDB_H | ||
| # include <netdb.h> | ||
| #endif | ||
| #ifdef HAVE_ARPA_INET_H | ||
| # include <arpa/inet.h> | ||
| #endif | ||
| #ifdef HAVE_ARPA_NAMESER_H | ||
| # include <arpa/nameser.h> | ||
| #else | ||
| # include "nameser.h" | ||
| #endif | ||
| #ifdef HAVE_ARPA_NAMESER_COMPAT_H | ||
| # include <arpa/nameser_compat.h> | ||
| #endif | ||
|
|
||
| #include <stdlib.h> | ||
| #include <string.h> | ||
| #include "ares.h" | ||
| #include "ares_dns.h" | ||
| #include "ares_data.h" | ||
| #include "ares_private.h" | ||
|
|
||
| int | ||
| ares_parse_soa_reply(const unsigned char *abuf, int alen, | ||
| struct ares_soa_reply **soa_out) | ||
| { | ||
| const unsigned char *aptr; | ||
| long len; | ||
| char *qname = NULL, *rr_name = NULL; | ||
| struct ares_soa_reply *soa = NULL; | ||
| int qdcount, ancount; | ||
| int status; | ||
|
|
||
| if (alen < HFIXEDSZ) | ||
| return ARES_EBADRESP; | ||
|
|
||
| /* parse message header */ | ||
| qdcount = DNS_HEADER_QDCOUNT(abuf); | ||
| ancount = DNS_HEADER_ANCOUNT(abuf); | ||
| if (qdcount != 1 || ancount != 1) | ||
| return ARES_EBADRESP; | ||
| aptr = abuf + HFIXEDSZ; | ||
|
|
||
| /* query name */ | ||
| status = ares__expand_name_for_response(aptr, abuf, alen, &qname, &len); | ||
| if (status != ARES_SUCCESS) | ||
| goto failed_stat; | ||
| aptr += len; | ||
|
|
||
| /* skip qtype & qclass */ | ||
| if (aptr + QFIXEDSZ > abuf + alen) | ||
| goto failed; | ||
| aptr += QFIXEDSZ; | ||
|
|
||
| /* rr_name */ | ||
| status = ares__expand_name_for_response(aptr, abuf, alen, &rr_name, &len); | ||
| if (status != ARES_SUCCESS) | ||
| goto failed_stat; | ||
| aptr += len; | ||
|
|
||
| /* skip rr_type, rr_class, rr_ttl, rr_rdlen */ | ||
| if (aptr + RRFIXEDSZ > abuf + alen) | ||
| goto failed; | ||
| aptr += RRFIXEDSZ; | ||
|
|
||
| /* allocate result struct */ | ||
| soa = ares_malloc_data(ARES_DATATYPE_SOA_REPLY); | ||
| if (!soa) | ||
| return ARES_ENOMEM; | ||
|
|
||
| /* nsname */ | ||
| status = ares__expand_name_for_response(aptr, abuf, alen, &soa->nsname, &len); | ||
| if (status != ARES_SUCCESS) | ||
| goto failed_stat; | ||
| aptr += len; | ||
|
|
||
| /* hostmaster */ | ||
| status = ares__expand_name_for_response(aptr, abuf, alen, &soa->hostmaster, &len); | ||
| if (status != ARES_SUCCESS) | ||
| goto failed_stat; | ||
| aptr += len; | ||
|
|
||
| /* integer fields */ | ||
| if (aptr + 5 * 4 > abuf + alen) | ||
| goto failed; | ||
| soa->serial = DNS__32BIT(aptr + 0 * 4); | ||
| soa->refresh = DNS__32BIT(aptr + 1 * 4); | ||
| soa->retry = DNS__32BIT(aptr + 2 * 4); | ||
| soa->expire = DNS__32BIT(aptr + 3 * 4); | ||
| soa->minttl = DNS__32BIT(aptr + 4 * 4); | ||
|
|
||
| free(qname); | ||
| free(rr_name); | ||
|
|
||
| *soa_out = soa; | ||
|
|
||
| return ARES_SUCCESS; | ||
|
|
||
| failed: | ||
| status = ARES_EBADRESP; | ||
|
|
||
| failed_stat: | ||
| ares_free_data(soa); | ||
| if (qname) | ||
| free(qname); | ||
| if (rr_name) | ||
| free(rr_name); | ||
| return status; | ||
| } | ||
|
|
| @@ -0,0 +1,97 @@ | ||
| /* Copyright Joyent, Inc. and other Node contributors. All rights reserved. | ||
| * | ||
| * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
| * of this software and associated documentation files (the "Software"), to | ||
| * deal in the Software without restriction, including without limitation the | ||
| * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or | ||
| * sell copies of the Software, and to permit persons to whom the Software is | ||
| * furnished to do so, subject to the following conditions: | ||
| * | ||
| * The above copyright notice and this permission notice shall be included in | ||
| * all copies or substantial portions of the Software. | ||
| * | ||
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
| * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
| * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS | ||
| * IN THE SOFTWARE. | ||
| */ | ||
|
|
||
| #include "task.h" | ||
| #include "uv.h" | ||
|
|
||
| #include <stdio.h> | ||
| #include <stdlib.h> | ||
|
|
||
| #define NUM_PINGS (1000 * 1000) | ||
|
|
||
| static unsigned int callbacks; | ||
| static volatile int done; | ||
|
|
||
|
|
||
| static void async_cb(uv_async_t* handle, int status) { | ||
| if (++callbacks == NUM_PINGS) | ||
| uv_close((uv_handle_t*) handle, NULL); | ||
| } | ||
|
|
||
|
|
||
| static void pummel(void* arg) { | ||
| while (!done) | ||
| uv_async_send((uv_async_t*) arg); | ||
| } | ||
|
|
||
|
|
||
| static int test_async_pummel(int nthreads) { | ||
| uv_thread_t* tids; | ||
| uv_async_t handle; | ||
| uint64_t time; | ||
| int i; | ||
|
|
||
| tids = calloc(nthreads, sizeof(tids[0])); | ||
| ASSERT(tids != NULL); | ||
|
|
||
| ASSERT(0 == uv_async_init(uv_default_loop(), &handle, async_cb)); | ||
|
|
||
| for (i = 0; i < nthreads; i++) | ||
| ASSERT(0 == uv_thread_create(tids + i, pummel, &handle)); | ||
|
|
||
| time = uv_hrtime(); | ||
|
|
||
| ASSERT(0 == uv_run(uv_default_loop())); | ||
|
|
||
| time = uv_hrtime() - time; | ||
| done = 1; | ||
|
|
||
| for (i = 0; i < nthreads; i++) | ||
| ASSERT(0 == uv_thread_join(tids + i)); | ||
|
|
||
| printf("%s callbacks in %.2f seconds (%s/sec)\n", | ||
| fmt(callbacks), | ||
| time / 1e9, | ||
| fmt(callbacks / (time / 1e9))); | ||
|
|
||
| free(tids); | ||
| return 0; | ||
| } | ||
|
|
||
|
|
||
| BENCHMARK_IMPL(async_pummel_1) { | ||
| return test_async_pummel(1); | ||
| } | ||
|
|
||
|
|
||
| BENCHMARK_IMPL(async_pummel_2) { | ||
| return test_async_pummel(2); | ||
| } | ||
|
|
||
|
|
||
| BENCHMARK_IMPL(async_pummel_4) { | ||
| return test_async_pummel(4); | ||
| } | ||
|
|
||
|
|
||
| BENCHMARK_IMPL(async_pummel_8) { | ||
| return test_async_pummel(8); | ||
| } |
| @@ -0,0 +1,137 @@ | ||
| /* Copyright Joyent, Inc. and other Node contributors. All rights reserved. | ||
| * | ||
| * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
| * of this software and associated documentation files (the "Software"), to | ||
| * deal in the Software without restriction, including without limitation the | ||
| * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or | ||
| * sell copies of the Software, and to permit persons to whom the Software is | ||
| * furnished to do so, subject to the following conditions: | ||
| * | ||
| * The above copyright notice and this permission notice shall be included in | ||
| * all copies or substantial portions of the Software. | ||
| * | ||
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
| * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
| * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS | ||
| * IN THE SOFTWARE. | ||
| */ | ||
|
|
||
| #include "task.h" | ||
| #include "uv.h" | ||
|
|
||
| #include <stdio.h> | ||
| #include <stdlib.h> | ||
|
|
||
| #define NUM_PINGS (1000 * 1000) | ||
|
|
||
| struct ctx { | ||
| uv_loop_t* loop; | ||
| uv_thread_t thread; | ||
| uv_async_t main_async; /* wake up main thread */ | ||
| uv_async_t worker_async; /* wake up worker */ | ||
| unsigned int nthreads; | ||
| unsigned int main_sent; | ||
| unsigned int main_seen; | ||
| unsigned int worker_sent; | ||
| unsigned int worker_seen; | ||
| }; | ||
|
|
||
|
|
||
| static void worker_async_cb(uv_async_t* handle, int status) { | ||
| struct ctx* ctx = container_of(handle, struct ctx, worker_async); | ||
|
|
||
| ASSERT(0 == uv_async_send(&ctx->main_async)); | ||
| ctx->worker_sent++; | ||
| ctx->worker_seen++; | ||
|
|
||
| if (ctx->worker_sent >= NUM_PINGS) | ||
| uv_close((uv_handle_t*) &ctx->worker_async, NULL); | ||
| } | ||
|
|
||
|
|
||
| static void main_async_cb(uv_async_t* handle, int status) { | ||
| struct ctx* ctx = container_of(handle, struct ctx, main_async); | ||
|
|
||
| ASSERT(0 == uv_async_send(&ctx->worker_async)); | ||
| ctx->main_sent++; | ||
| ctx->main_seen++; | ||
|
|
||
| if (ctx->main_sent >= NUM_PINGS) | ||
| uv_close((uv_handle_t*) &ctx->main_async, NULL); | ||
| } | ||
|
|
||
|
|
||
| static void worker(void* arg) { | ||
| struct ctx* ctx = arg; | ||
| ASSERT(0 == uv_async_send(&ctx->main_async)); | ||
| ASSERT(0 == uv_run(ctx->loop)); | ||
| } | ||
|
|
||
|
|
||
| static int test_async(int nthreads) { | ||
| struct ctx* threads; | ||
| struct ctx* ctx; | ||
| uint64_t time; | ||
| int i; | ||
|
|
||
| threads = calloc(nthreads, sizeof(threads[0])); | ||
| ASSERT(threads != NULL); | ||
|
|
||
| for (i = 0; i < nthreads; i++) { | ||
| ctx = threads + i; | ||
| ctx->nthreads = nthreads; | ||
| ctx->loop = uv_loop_new(); | ||
| ASSERT(ctx->loop != NULL); | ||
| ASSERT(0 == uv_async_init(ctx->loop, &ctx->worker_async, worker_async_cb)); | ||
| ASSERT(0 == uv_async_init(uv_default_loop(), &ctx->main_async, main_async_cb)); | ||
| ASSERT(0 == uv_thread_create(&ctx->thread, worker, ctx)); | ||
| } | ||
|
|
||
| time = uv_hrtime(); | ||
|
|
||
| ASSERT(0 == uv_run(uv_default_loop())); | ||
|
|
||
| for (i = 0; i < nthreads; i++) | ||
| ASSERT(0 == uv_thread_join(&threads[i].thread)); | ||
|
|
||
| time = uv_hrtime() - time; | ||
|
|
||
| for (i = 0; i < nthreads; i++) { | ||
| ctx = threads + i; | ||
| ASSERT(ctx->worker_sent == NUM_PINGS); | ||
| ASSERT(ctx->worker_seen == NUM_PINGS); | ||
| ASSERT(ctx->main_sent == (unsigned int) NUM_PINGS); | ||
| ASSERT(ctx->main_seen == (unsigned int) NUM_PINGS); | ||
| } | ||
|
|
||
| printf("%.2f sec (%s/sec)\n", | ||
| time / 1e9, | ||
| fmt(NUM_PINGS / (time / 1e9))); | ||
|
|
||
| free(threads); | ||
|
|
||
| return 0; | ||
| } | ||
|
|
||
|
|
||
| BENCHMARK_IMPL(async1) { | ||
| return test_async(1); | ||
| } | ||
|
|
||
|
|
||
| BENCHMARK_IMPL(async2) { | ||
| return test_async(2); | ||
| } | ||
|
|
||
|
|
||
| BENCHMARK_IMPL(async4) { | ||
| return test_async(4); | ||
| } | ||
|
|
||
|
|
||
| BENCHMARK_IMPL(async8) { | ||
| return test_async(8); | ||
| } |
| @@ -43,35 +43,6 @@ struct async_req { | ||
| }; | ||
|
|
||
|
|
||
| static void warmup(const char* path) { | ||
| uv_fs_t reqs[MAX_CONCURRENT_REQS]; | ||
| int i; | ||
| @@ -36,11 +36,6 @@ | ||
| static int close_cb_called = 0; | ||
|
|
||
|
|
||
| static void close_cb(uv_handle_t* handle) { | ||
| close_cb_called++; | ||
| } | ||