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 | }
|
---|