[453] | 1 | // Copyright (c) Microsoft. All rights reserved.
|
---|
| 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
---|
| 3 |
|
---|
| 4 |
|
---|
| 5 | #include <stdbool.h>
|
---|
| 6 | #include <stdint.h>
|
---|
| 7 | #include <stdlib.h>
|
---|
| 8 |
|
---|
| 9 | // This file is OS-specific, and is identified by setting include directories
|
---|
| 10 | // in the project
|
---|
| 11 | #include "socket_async_os.h"
|
---|
| 12 |
|
---|
| 13 | #include "azure_c_shared_utility/dns_resolver.h"
|
---|
| 14 | #include "azure_c_shared_utility/gballoc.h"
|
---|
| 15 | #include "azure_c_shared_utility/crt_abstractions.h"
|
---|
| 16 | #include "azure_c_shared_utility/xlogging.h"
|
---|
| 17 |
|
---|
| 18 |
|
---|
| 19 | // EXTRACT_IPV4 pulls the uint32_t IPv4 address out of an addrinfo struct
|
---|
| 20 | // This will not be needed for the asynchronous design
|
---|
| 21 | // The default definition handles lwIP. Please add comments for other systems tested.
|
---|
| 22 | #define EXTRACT_IPV4(ptr) ((struct sockaddr_in *) ptr->ai_addr)->sin_addr.s_addr
|
---|
| 23 |
|
---|
| 24 | typedef struct
|
---|
| 25 | {
|
---|
| 26 | char* hostname;
|
---|
| 27 | int port;
|
---|
| 28 | uint32_t ip_v4;
|
---|
| 29 | bool is_complete;
|
---|
| 30 | bool is_failed;
|
---|
| 31 | struct addrinfo* addrInfo;
|
---|
| 32 | } DNSRESOLVER_INSTANCE;
|
---|
| 33 |
|
---|
| 34 | DNSRESOLVER_HANDLE dns_resolver_create(const char* hostname, int port, const DNSRESOLVER_OPTIONS* options)
|
---|
| 35 | {
|
---|
| 36 | /* Codes_SRS_dns_resolver_30_012: [ The optional options parameter shall be ignored. ]*/
|
---|
| 37 | DNSRESOLVER_INSTANCE* result;
|
---|
| 38 | (void)options;
|
---|
| 39 | if (hostname == NULL)
|
---|
| 40 | {
|
---|
| 41 | /* Codes_SRS_dns_resolver_30_011: [ If the hostname parameter is NULL, dns_resolver_create shall log an error and return NULL. ]*/
|
---|
| 42 | LogError("NULL hostname");
|
---|
| 43 | result = NULL;
|
---|
| 44 | }
|
---|
| 45 | else
|
---|
| 46 | {
|
---|
| 47 | result = malloc(sizeof(DNSRESOLVER_INSTANCE));
|
---|
| 48 | if (result == NULL)
|
---|
| 49 | {
|
---|
| 50 | /* Codes_SRS_dns_resolver_30_014: [ On any failure, dns_resolver_create shall log an error and return NULL. ]*/
|
---|
| 51 | LogError("malloc instance failed");
|
---|
| 52 | result = NULL;
|
---|
| 53 | }
|
---|
| 54 | else
|
---|
| 55 | {
|
---|
| 56 | int ms_result;
|
---|
| 57 | result->is_complete = false;
|
---|
| 58 | result->is_failed = false;
|
---|
| 59 | result->ip_v4 = 0;
|
---|
| 60 | result->port = port;
|
---|
| 61 | /* Codes_SRS_dns_resolver_30_010: [ dns_resolver_create shall make a copy of the hostname parameter to allow immediate deletion by the caller. ]*/
|
---|
| 62 | ms_result = mallocAndStrcpy_s(&result->hostname, hostname);
|
---|
| 63 | if (ms_result != 0)
|
---|
| 64 | {
|
---|
| 65 | /* Codes_SRS_dns_resolver_30_014: [ On any failure, dns_resolver_create shall log an error and return NULL. ]*/
|
---|
| 66 | free(result);
|
---|
| 67 | result = NULL;
|
---|
| 68 | }
|
---|
| 69 | }
|
---|
| 70 | }
|
---|
| 71 | return result;
|
---|
| 72 | }
|
---|
| 73 |
|
---|
| 74 | /* Codes_SRS_dns_resolver_30_021: [ dns_resolver_is_create_complete shall perform the asynchronous work of DNS lookup and log any errors. ]*/
|
---|
| 75 | bool dns_resolver_is_lookup_complete(DNSRESOLVER_HANDLE dns_in)
|
---|
| 76 | {
|
---|
| 77 | DNSRESOLVER_INSTANCE* dns = (DNSRESOLVER_INSTANCE*)dns_in;
|
---|
| 78 |
|
---|
| 79 | bool result;
|
---|
| 80 | if (dns == NULL)
|
---|
| 81 | {
|
---|
| 82 | /* Codes_SRS_dns_resolver_30_020: [ If the dns parameter is NULL, dns_resolver_is_create_complete shall log an error and return false. ]*/
|
---|
| 83 | LogError("NULL dns");
|
---|
| 84 | result = false;
|
---|
| 85 | }
|
---|
| 86 | else
|
---|
| 87 | {
|
---|
| 88 | if (dns->is_complete)
|
---|
| 89 | {
|
---|
| 90 | /* Codes_SRS_dns_resolver_30_024: [ If dns_resolver_is_create_complete has previously returned true, dns_resolver_is_create_complete shall do nothing and return true. ]*/
|
---|
| 91 | result = true;
|
---|
| 92 | }
|
---|
| 93 | else
|
---|
| 94 | {
|
---|
| 95 | char portString[16];
|
---|
| 96 | struct addrinfo *addrInfo = NULL;
|
---|
| 97 | struct addrinfo *ptr = NULL;
|
---|
| 98 | struct addrinfo hints;
|
---|
| 99 | int getAddrResult;
|
---|
| 100 |
|
---|
| 101 | //--------------------------------
|
---|
| 102 | // Setup the hints address info structure
|
---|
| 103 | // which is passed to the getaddrinfo() function
|
---|
| 104 | memset(&hints, 0, sizeof(hints));
|
---|
| 105 | hints.ai_family = AF_INET;
|
---|
| 106 | hints.ai_socktype = SOCK_STREAM;
|
---|
| 107 | hints.ai_protocol = 0;
|
---|
| 108 |
|
---|
| 109 | //--------------------------------
|
---|
| 110 | // Call getaddrinfo(). If the call succeeds,
|
---|
| 111 | // the result variable will hold a linked list
|
---|
| 112 | // of addrinfo structures containing response
|
---|
| 113 | // information
|
---|
| 114 | if (sprintf(portString, "%u", dns->port) < 0)
|
---|
| 115 | {
|
---|
| 116 | LogError("Failure: sprintf failed to encode the port.");
|
---|
| 117 | result = MU_FAILURE;
|
---|
| 118 | }
|
---|
| 119 |
|
---|
| 120 | getAddrResult = getaddrinfo(dns->hostname, portString, &hints, &addrInfo);
|
---|
| 121 | if (getAddrResult == 0)
|
---|
| 122 | {
|
---|
| 123 | dns->addrInfo = addrInfo;
|
---|
| 124 |
|
---|
| 125 | // If we find the AF_INET address, use it as the return value
|
---|
| 126 | for (ptr = addrInfo; ptr != NULL; ptr = ptr->ai_next)
|
---|
| 127 | {
|
---|
| 128 | switch (ptr->ai_family)
|
---|
| 129 | {
|
---|
| 130 | case AF_INET:
|
---|
| 131 | /* Codes_SRS_dns_resolver_30_032: [ If dns_resolver_is_create_complete has returned true and the lookup process has succeeded, dns_resolver_get_ipv4 shall return the discovered IPv4 address. ]*/
|
---|
| 132 | dns->ip_v4 = EXTRACT_IPV4(ptr);
|
---|
| 133 | break;
|
---|
| 134 | }
|
---|
| 135 | }
|
---|
| 136 | /* Codes_SRS_dns_resolver_30_033: [ If dns_resolver_is_create_complete has returned true and the lookup process has failed, dns_resolver_get_ipv4 shall return 0. ]*/
|
---|
| 137 | dns->is_failed = (dns->ip_v4 == 0);
|
---|
| 138 | }
|
---|
| 139 | else
|
---|
| 140 | {
|
---|
| 141 | /* Codes_SRS_dns_resolver_30_033: [ If dns_resolver_is_create_complete has returned true and the lookup process has failed, dns_resolver_get_ipv4 shall return 0. ]*/
|
---|
| 142 | LogInfo("Failed DNS lookup for %s: %d", dns->hostname, getAddrResult);
|
---|
| 143 | dns->is_failed = true;
|
---|
| 144 | }
|
---|
| 145 |
|
---|
| 146 | /* Codes_SRS_dns_resolver_30_021: [ dns_resolver_is_create_complete shall perform the asynchronous work of DNS lookup and log any errors. ]*/
|
---|
| 147 | // Only make one attempt at lookup for this
|
---|
| 148 | // synchronous implementation
|
---|
| 149 | dns->is_complete = true;
|
---|
| 150 |
|
---|
| 151 | // This synchronous implementation is incapable of being incomplete, so SRS_dns_resolver_30_023 does not ever happen
|
---|
| 152 | /* Codes_SRS_dns_resolver_30_023: [ If the DNS lookup process is not yet complete, dns_resolver_is_create_complete shall return false. ]*/
|
---|
| 153 | /* Codes_SRS_dns_resolver_30_022: [ If the DNS lookup process has completed, dns_resolver_is_create_complete shall return true. ]*/
|
---|
| 154 | result = true;
|
---|
| 155 | }
|
---|
| 156 | }
|
---|
| 157 |
|
---|
| 158 | return result;
|
---|
| 159 | }
|
---|
| 160 |
|
---|
| 161 | void dns_resolver_destroy(DNSRESOLVER_HANDLE dns_in)
|
---|
| 162 | {
|
---|
| 163 | DNSRESOLVER_INSTANCE* dns = (DNSRESOLVER_INSTANCE*)dns_in;
|
---|
| 164 | if (dns == NULL)
|
---|
| 165 | {
|
---|
| 166 | /* Codes_SRS_dns_resolver_30_050: [ If the dns parameter is NULL, dns_resolver_destroy shall log an error and do nothing. ]*/
|
---|
| 167 | LogError("NULL dns");
|
---|
| 168 | }
|
---|
| 169 | else
|
---|
| 170 | {
|
---|
| 171 | /* Codes_SRS_dns_resolver_30_051: [ dns_resolver_destroy shall delete all acquired resources and delete the DNSRESOLVER_HANDLE. ]*/
|
---|
| 172 | if(dns->is_complete && !dns->is_failed && dns->addrInfo != NULL)
|
---|
| 173 | {
|
---|
| 174 | freeaddrinfo(dns->addrInfo);
|
---|
| 175 | }
|
---|
| 176 |
|
---|
| 177 | if(dns->hostname != NULL)
|
---|
| 178 | {
|
---|
| 179 | free(dns->hostname);
|
---|
| 180 | }
|
---|
| 181 |
|
---|
| 182 | free(dns);
|
---|
| 183 | dns = NULL;
|
---|
| 184 | }
|
---|
| 185 | }
|
---|
| 186 |
|
---|
| 187 | uint32_t dns_resolver_get_ipv4(DNSRESOLVER_HANDLE dns_in)
|
---|
| 188 | {
|
---|
| 189 | DNSRESOLVER_INSTANCE* dns = (DNSRESOLVER_INSTANCE*)dns_in;
|
---|
| 190 | uint32_t result;
|
---|
| 191 | if (dns == NULL)
|
---|
| 192 | {
|
---|
| 193 | /* Codes_SRS_dns_resolver_30_030: [ If the dns parameter is NULL, dns_resolver_get_ipv4 shall log an error and return 0. ]*/
|
---|
| 194 | LogError("NULL dns");
|
---|
| 195 | result = 0;
|
---|
| 196 | }
|
---|
| 197 | else
|
---|
| 198 | {
|
---|
| 199 | if (dns->is_complete)
|
---|
| 200 | {
|
---|
| 201 | if (dns->is_failed)
|
---|
| 202 | {
|
---|
| 203 | /* Codes_SRS_dns_resolver_30_033: [ If dns_resolver_is_create_complete has returned true and the lookup process has failed, dns_resolver_get_ipv4 shall return 0. ]*/
|
---|
| 204 | result = 0;
|
---|
| 205 | }
|
---|
| 206 | else
|
---|
| 207 | {
|
---|
| 208 | /* Codes_SRS_dns_resolver_30_032: [ If dns_resolver_is_create_complete has returned true and the lookup process has succeeded, dns_resolver_get_ipv4 shall return the discovered IPv4 address. ]*/
|
---|
| 209 | result = dns->ip_v4;
|
---|
| 210 | }
|
---|
| 211 | }
|
---|
| 212 | else
|
---|
| 213 | {
|
---|
| 214 | /* Codes_SRS_dns_resolver_30_031: [ If dns_resolver_is_create_complete has not yet returned true, dns_resolver_get_ipv4 shall log an error and return 0. ]*/
|
---|
| 215 | LogError("dns_resolver_get_ipv4 when not complete");
|
---|
| 216 | result = 0;
|
---|
| 217 | }
|
---|
| 218 | }
|
---|
| 219 | return result;
|
---|
| 220 | }
|
---|
| 221 |
|
---|
| 222 | struct addrinfo* dns_resolver_get_addrInfo(DNSRESOLVER_HANDLE dns_in)
|
---|
| 223 | {
|
---|
| 224 | DNSRESOLVER_INSTANCE* dns = (DNSRESOLVER_INSTANCE*)dns_in;
|
---|
| 225 | struct addrinfo* result;
|
---|
| 226 | if (dns == NULL)
|
---|
| 227 | {
|
---|
| 228 | /* Codes_SRS_dns_resolver_30_030: [ If the dns parameter is NULL, dns_resolver_get_ipv4 shall log an error and return 0. ]*/
|
---|
| 229 | LogError("NULL dns");
|
---|
| 230 | result = NULL;
|
---|
| 231 | }
|
---|
| 232 | else
|
---|
| 233 | {
|
---|
| 234 | if (dns->is_complete)
|
---|
| 235 | {
|
---|
| 236 | if (dns->is_failed)
|
---|
| 237 | {
|
---|
| 238 | /* Codes_SRS_dns_resolver_30_033: [ If dns_resolver_is_create_complete has returned true and the lookup process has failed, dns_resolver_get_ipv4 shall return 0. ]*/
|
---|
| 239 | result = NULL;
|
---|
| 240 | }
|
---|
| 241 | else
|
---|
| 242 | {
|
---|
| 243 | /* Codes_SRS_dns_resolver_30_032: [ If dns_resolver_is_create_complete has returned true and the lookup process has succeeded, dns_resolver_get_ipv4 shall return the discovered IPv4 address. ]*/
|
---|
| 244 | result = dns->addrInfo;
|
---|
| 245 | }
|
---|
| 246 | }
|
---|
| 247 | else
|
---|
| 248 | {
|
---|
| 249 | /* Codes_SRS_dns_resolver_30_031: [ If dns_resolver_is_create_complete has not yet returned true, dns_resolver_get_ipv4 shall log an error and return 0. ]*/
|
---|
| 250 | LogError("dns_resolver_get_ipv4 when not complete");
|
---|
| 251 | result = NULL;
|
---|
| 252 | }
|
---|
| 253 | }
|
---|
| 254 | return result;
|
---|
| 255 | }
|
---|