| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209 |
- /***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) Daniel Stenberg, <[email protected]>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at https://curl.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * SPDX-License-Identifier: curl
- *
- ***************************************************************************/
- #include "curl_setup.h"
- #include "fake_addrinfo.h"
- #ifdef USE_FAKE_GETADDRINFO
- #include <string.h>
- #include <stdlib.h>
- #include <ares.h>
- /* The last 2 #include files should be in this order */
- #include "curl_memory.h"
- #include "memdebug.h"
- void r_freeaddrinfo(struct addrinfo *cahead)
- {
- struct addrinfo *canext;
- struct addrinfo *ca;
- for(ca = cahead; ca; ca = canext) {
- canext = ca->ai_next;
- free(ca);
- }
- }
- struct context {
- struct ares_addrinfo *result;
- };
- static void async_addrinfo_cb(void *userp, int status, int timeouts,
- struct ares_addrinfo *result)
- {
- struct context *ctx = (struct context *)userp;
- (void)timeouts;
- if(ARES_SUCCESS == status) {
- ctx->result = result;
- }
- }
- /* convert the c-ares version into the "native" version */
- static struct addrinfo *mk_getaddrinfo(const struct ares_addrinfo *aihead)
- {
- const struct ares_addrinfo_node *ai;
- struct addrinfo *ca;
- struct addrinfo *cafirst = NULL;
- struct addrinfo *calast = NULL;
- const char *name = aihead->name;
- /* traverse the addrinfo list */
- for(ai = aihead->nodes; ai != NULL; ai = ai->ai_next) {
- size_t ss_size;
- size_t namelen = name ? strlen(name) + 1 : 0;
- /* ignore elements with unsupported address family, */
- /* settle family-specific sockaddr structure size. */
- if(ai->ai_family == AF_INET)
- ss_size = sizeof(struct sockaddr_in);
- else if(ai->ai_family == AF_INET6)
- ss_size = sizeof(struct sockaddr_in6);
- else
- continue;
- /* ignore elements without required address info */
- if(!ai->ai_addr || !(ai->ai_addrlen > 0))
- continue;
- /* ignore elements with bogus address size */
- if((size_t)ai->ai_addrlen < ss_size)
- continue;
- ca = malloc(sizeof(struct addrinfo) + ss_size + namelen);
- if(!ca) {
- r_freeaddrinfo(cafirst);
- return NULL;
- }
- /* copy each structure member individually, member ordering, */
- /* size, or padding might be different for each platform. */
- ca->ai_flags = ai->ai_flags;
- ca->ai_family = ai->ai_family;
- ca->ai_socktype = ai->ai_socktype;
- ca->ai_protocol = ai->ai_protocol;
- ca->ai_addrlen = (curl_socklen_t)ss_size;
- ca->ai_addr = NULL;
- ca->ai_canonname = NULL;
- ca->ai_next = NULL;
- ca->ai_addr = (void *)((char *)ca + sizeof(struct addrinfo));
- memcpy(ca->ai_addr, ai->ai_addr, ss_size);
- if(namelen) {
- ca->ai_canonname = (void *)((char *)ca->ai_addr + ss_size);
- memcpy(ca->ai_canonname, name, namelen);
- /* the name is only pointed to by the first entry in the "real"
- addrinfo chain, so stop now */
- name = NULL;
- }
- /* if the return list is empty, this becomes the first element */
- if(!cafirst)
- cafirst = ca;
- /* add this element last in the return list */
- if(calast)
- calast->ai_next = ca;
- calast = ca;
- }
- return cafirst;
- }
- /*
- RETURN VALUE
- getaddrinfo() returns 0 if it succeeds, or one of the following nonzero
- error codes:
- ...
- */
- int r_getaddrinfo(const char *node,
- const char *service,
- const struct addrinfo *hints,
- struct addrinfo **res)
- {
- int status;
- struct context ctx;
- struct ares_options options;
- int optmask = 0;
- struct ares_addrinfo_hints ahints;
- ares_channel channel;
- int rc = 0;
- memset(&options, 0, sizeof(options));
- optmask |= ARES_OPT_EVENT_THREAD;
- options.evsys = ARES_EVSYS_DEFAULT;
- memset(&ahints, 0, sizeof(ahints));
- memset(&ctx, 0, sizeof(ctx));
- if(hints) {
- ahints.ai_flags = hints->ai_flags;
- ahints.ai_family = hints->ai_family;
- ahints.ai_socktype = hints->ai_socktype;
- ahints.ai_protocol = hints->ai_protocol;
- }
- status = ares_init_options(&channel, &options, optmask);
- if(status)
- return EAI_MEMORY; /* major problem */
- else {
- const char *env = getenv("CURL_DNS_SERVER");
- if(env) {
- rc = ares_set_servers_ports_csv(channel, env);
- if(rc) {
- curl_mfprintf(stderr, "ares_set_servers_ports_csv failed: %d", rc);
- /* Cleanup */
- ares_destroy(channel);
- return EAI_MEMORY; /* we can't run */
- }
- }
- }
- ares_getaddrinfo(channel, node, service, &ahints,
- async_addrinfo_cb, &ctx);
- /* Wait until no more requests are left to be processed */
- ares_queue_wait_empty(channel, -1);
- if(ctx.result) {
- /* convert the c-ares version */
- *res = mk_getaddrinfo(ctx.result);
- /* free the old */
- ares_freeaddrinfo(ctx.result);
- }
- else
- rc = EAI_NONAME; /* got nothing */
- /* Cleanup */
- ares_destroy(channel);
- return rc;
- }
- #endif /* USE_FAKE_GETADDRINFO */
|