quickjs-tart

quickjs-based runtime for wallet-core logic
Log | Files | Refs | README | LICENSE

fake_addrinfo.c (5762B)


      1 /***************************************************************************
      2  *                                  _   _ ____  _
      3  *  Project                     ___| | | |  _ \| |
      4  *                             / __| | | | |_) | |
      5  *                            | (__| |_| |  _ <| |___
      6  *                             \___|\___/|_| \_\_____|
      7  *
      8  * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
      9  *
     10  * This software is licensed as described in the file COPYING, which
     11  * you should have received as part of this distribution. The terms
     12  * are also available at https://curl.se/docs/copyright.html.
     13  *
     14  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
     15  * copies of the Software, and permit persons to whom the Software is
     16  * furnished to do so, under the terms of the COPYING file.
     17  *
     18  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
     19  * KIND, either express or implied.
     20  *
     21  * SPDX-License-Identifier: curl
     22  *
     23  ***************************************************************************/
     24 
     25 #include "curl_setup.h"
     26 #include "fake_addrinfo.h"
     27 
     28 #ifdef USE_FAKE_GETADDRINFO
     29 
     30 #include <string.h>
     31 #include <stdlib.h>
     32 #include <ares.h>
     33 
     34 /* The last 3 #include files should be in this order */
     35 #include "curl_printf.h"
     36 #include "curl_memory.h"
     37 #include "memdebug.h"
     38 
     39 void r_freeaddrinfo(struct addrinfo *cahead)
     40 {
     41   struct addrinfo *canext;
     42   struct addrinfo *ca;
     43 
     44   for(ca = cahead; ca; ca = canext) {
     45     canext = ca->ai_next;
     46     free(ca);
     47   }
     48 }
     49 
     50 struct context {
     51   struct ares_addrinfo *result;
     52 };
     53 
     54 static void async_addrinfo_cb(void *userp, int status, int timeouts,
     55                               struct ares_addrinfo *result)
     56 {
     57   struct context *ctx = (struct context *)userp;
     58   (void)timeouts;
     59   if(ARES_SUCCESS == status) {
     60     ctx->result = result;
     61   }
     62 }
     63 
     64 /* convert the c-ares version into the "native" version */
     65 static struct addrinfo *mk_getaddrinfo(const struct ares_addrinfo *aihead)
     66 {
     67   const struct ares_addrinfo_node *ai;
     68   struct addrinfo *ca;
     69   struct addrinfo *cafirst = NULL;
     70   struct addrinfo *calast = NULL;
     71   const char *name = aihead->name;
     72 
     73   /* traverse the addrinfo list */
     74   for(ai = aihead->nodes; ai != NULL; ai = ai->ai_next) {
     75     size_t ss_size;
     76     size_t namelen = name ? strlen(name) + 1 : 0;
     77     /* ignore elements with unsupported address family, */
     78     /* settle family-specific sockaddr structure size.  */
     79     if(ai->ai_family == AF_INET)
     80       ss_size = sizeof(struct sockaddr_in);
     81     else if(ai->ai_family == AF_INET6)
     82       ss_size = sizeof(struct sockaddr_in6);
     83     else
     84       continue;
     85 
     86     /* ignore elements without required address info */
     87     if(!ai->ai_addr || !(ai->ai_addrlen > 0))
     88       continue;
     89 
     90     /* ignore elements with bogus address size */
     91     if((size_t)ai->ai_addrlen < ss_size)
     92       continue;
     93 
     94     ca = malloc(sizeof(struct addrinfo) + ss_size + namelen);
     95     if(!ca) {
     96       r_freeaddrinfo(cafirst);
     97       return NULL;
     98     }
     99 
    100     /* copy each structure member individually, member ordering, */
    101     /* size, or padding might be different for each platform.    */
    102 
    103     ca->ai_flags     = ai->ai_flags;
    104     ca->ai_family    = ai->ai_family;
    105     ca->ai_socktype  = ai->ai_socktype;
    106     ca->ai_protocol  = ai->ai_protocol;
    107     ca->ai_addrlen   = (curl_socklen_t)ss_size;
    108     ca->ai_addr      = NULL;
    109     ca->ai_canonname = NULL;
    110     ca->ai_next      = NULL;
    111 
    112     ca->ai_addr = (void *)((char *)ca + sizeof(struct addrinfo));
    113     memcpy(ca->ai_addr, ai->ai_addr, ss_size);
    114 
    115     if(namelen) {
    116       ca->ai_canonname = (void *)((char *)ca->ai_addr + ss_size);
    117       memcpy(ca->ai_canonname, name, namelen);
    118 
    119       /* the name is only pointed to by the first entry in the "real"
    120          addrinfo chain, so stop now */
    121       name = NULL;
    122     }
    123 
    124     /* if the return list is empty, this becomes the first element */
    125     if(!cafirst)
    126       cafirst = ca;
    127 
    128     /* add this element last in the return list */
    129     if(calast)
    130       calast->ai_next = ca;
    131     calast = ca;
    132   }
    133 
    134   return cafirst;
    135 }
    136 
    137 /*
    138   RETURN VALUE
    139 
    140   getaddrinfo() returns 0 if it succeeds, or one of the following nonzero
    141   error codes:
    142 
    143   ...
    144 */
    145 int r_getaddrinfo(const char *node,
    146                   const char *service,
    147                   const struct addrinfo *hints,
    148                   struct addrinfo **res)
    149 {
    150   int status;
    151   struct context ctx;
    152   struct ares_options options;
    153   int optmask = 0;
    154   struct ares_addrinfo_hints ahints;
    155   ares_channel channel;
    156   int rc = 0;
    157 
    158   memset(&options, 0, sizeof(options));
    159   optmask      |= ARES_OPT_EVENT_THREAD;
    160   options.evsys = ARES_EVSYS_DEFAULT;
    161 
    162   memset(&ahints, 0, sizeof(ahints));
    163   memset(&ctx, 0, sizeof(ctx));
    164 
    165   if(hints) {
    166     ahints.ai_flags = hints->ai_flags;
    167     ahints.ai_family = hints->ai_family;
    168     ahints.ai_socktype = hints->ai_socktype;
    169     ahints.ai_protocol = hints->ai_protocol;
    170   }
    171 
    172   status = ares_init_options(&channel, &options, optmask);
    173   if(status)
    174     return EAI_MEMORY; /* major problem */
    175 
    176   else {
    177     const char *env = getenv("CURL_DNS_SERVER");
    178     if(env) {
    179       rc = ares_set_servers_ports_csv(channel, env);
    180       if(rc) {
    181         fprintf(stderr, "ares_set_servers_ports_csv failed: %d", rc);
    182         /* Cleanup */
    183         ares_destroy(channel);
    184         return EAI_MEMORY; /* we can't run */
    185       }
    186     }
    187   }
    188 
    189   ares_getaddrinfo(channel, node, service, &ahints,
    190                    async_addrinfo_cb, &ctx);
    191 
    192   /* Wait until no more requests are left to be processed */
    193   ares_queue_wait_empty(channel, -1);
    194 
    195   if(ctx.result) {
    196     /* convert the c-ares version */
    197     *res = mk_getaddrinfo(ctx.result);
    198     /* free the old */
    199     ares_freeaddrinfo(ctx.result);
    200   }
    201   else
    202     rc = EAI_NONAME; /* got nothing */
    203 
    204   /* Cleanup */
    205   ares_destroy(channel);
    206 
    207   return rc;
    208 }
    209 
    210 #endif /* USE_FAKE_GETADDRINFO */