1 #include <sys/socket.h>
2 #include <netinet/in.h>
3 #include <netinet/tcp.h>
4 #include <netdb.h>
5 #include <arpa/inet.h>
6 #include <stdint.h>
7 #include <string.h>
8 #include <poll.h>
9 #include <time.h>
10 #include <ctype.h>
11 #include <unistd.h>
12 #include <errno.h>
13 #include <pthread.h>
14 #include "stdio_impl.h"
15 #include "syscall.h"
16 #include "lookup.h"
17 #include <errno.h>
18
19 #define LARGE_LATENCY 500
20 #define RR_A 1
21 #define RR_AAAA 28
22 #define MIN_WAIT_V6 80
23
24 struct type_ctx {
25 int count_v4;
26 int count_v6;
27 };
28
cleanup(void * p)29 static void cleanup(void *p)
30 {
31 struct pollfd *pfd = p;
32 for (int i=0; pfd[i].fd >= -1; i++)
33 if (pfd[i].fd >= 0) __syscall(SYS_close, pfd[i].fd);
34 }
35
mtime()36 static unsigned long mtime()
37 {
38 struct timespec ts;
39 if (clock_gettime(CLOCK_MONOTONIC, &ts) < 0 && errno == ENOSYS)
40 clock_gettime(CLOCK_REALTIME, &ts);
41 return (unsigned long)ts.tv_sec * 1000
42 + ts.tv_nsec / 1000000;
43 }
44
start_tcp(struct pollfd * pfd,int family,const void * sa,socklen_t sl,const unsigned char * q,int ql,int netid)45 static int start_tcp(struct pollfd *pfd, int family, const void *sa,
46 socklen_t sl, const unsigned char *q, int ql, int netid)
47 {
48 struct msghdr mh = {
49 .msg_name = (void *)sa,
50 .msg_namelen = sl,
51 .msg_iovlen = 2,
52 .msg_iov = (struct iovec [2]){
53 { .iov_base = (uint8_t[]){ ql>>8, ql }, .iov_len = 2 },
54 { .iov_base = (void *)q, .iov_len = ql } }
55 };
56 int r;
57 int fd = socket(family, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
58 #ifndef __LITEOS__
59 if (fd < 0) {
60 MUSL_LOGW("%{public}s: %{public}d: create TCP socket failed, errno id: %{public}d",
61 __func__, __LINE__, errno);
62 }
63 /**
64 * Todo FwmarkClient::BindSocket
65 */
66 if (netid > 0) {
67 res_bind_socket(fd, netid);
68 }
69 #endif
70 pfd->fd = fd;
71 pfd->events = POLLOUT;
72 if (!setsockopt(fd, IPPROTO_TCP, TCP_FASTOPEN_CONNECT,
73 &(int){1}, sizeof(int))) {
74 r = sendmsg(fd, &mh, MSG_FASTOPEN|MSG_NOSIGNAL);
75 if (r == ql+2) pfd->events = POLLIN;
76 if (r >= 0) return r;
77 if (errno == EINPROGRESS) return 0;
78 }
79 r = connect(fd, sa, sl);
80 if (!r || errno == EINPROGRESS) return 0;
81 close(fd);
82 pfd->fd = -1;
83 return -1;
84 }
85
step_mh(struct msghdr * mh,size_t n)86 static void step_mh(struct msghdr *mh, size_t n)
87 {
88 /* Adjust iovec in msghdr to skip first n bytes. */
89 while (mh->msg_iovlen && n >= mh->msg_iov->iov_len) {
90 n -= mh->msg_iov->iov_len;
91 mh->msg_iov++;
92 mh->msg_iovlen--;
93 }
94 if (!mh->msg_iovlen) return;
95 mh->msg_iov->iov_base = (char *)mh->msg_iov->iov_base + n;
96 mh->msg_iov->iov_len -= n;
97 }
98
99 // equal to answer buffer size
100 #define BPBUF_SIZE 4800
101
type_parse_callback(void * c,int rr,const void * data,int len,const void * packet,int plen)102 static int type_parse_callback(void *c, int rr, const void *data, int len, const void *packet, int plen)
103 {
104 struct type_ctx *ctx = c;
105
106 switch (rr) {
107 case RR_A:
108 if (len != 4) {
109 return -1;
110 }
111 ctx->count_v4++;
112 break;
113 case RR_AAAA:
114 if (len != 16) {
115 return -1;
116 }
117 ctx->count_v6++;
118 break;
119 default:
120 break;
121 }
122
123 return 0;
124 }
125
126 /* Internal contract for __res_msend[_rc]: asize must be >=512, nqueries
127 * must be sufficiently small to be safe as VLA size. In practice it's
128 * either 1 or 2, anyway. */
129
__res_msend_rc(int nqueries,const unsigned char * const * queries,const int * qlens,unsigned char * const * answers,int * alens,int asize,const struct resolvconf * conf)130 int __res_msend_rc(int nqueries, const unsigned char *const *queries,
131 const int *qlens, unsigned char *const *answers, int *alens, int asize,
132 const struct resolvconf *conf)
133 {
134 return res_msend_rc_ext(0, nqueries, queries, qlens, answers, alens, asize, conf, NULL);
135 }
136
res_msend_rc_ext(int netid,int nqueries,const unsigned char * const * queries,const int * qlens,unsigned char * const * answers,int * alens,int asize,const struct resolvconf * conf,int * dns_errno)137 int res_msend_rc_ext(int netid, int nqueries, const unsigned char *const *queries,
138 const int *qlens, unsigned char *const *answers, int *alens, int asize,
139 const struct resolvconf *conf, int *dns_errno)
140 {
141 int fd;
142 int timeout, attempts, retry_interval, servfail_retry;
143 union {
144 struct sockaddr_in sin;
145 struct sockaddr_in6 sin6;
146 } sa = {0}, ns[MAXNS] = {{0}};
147 socklen_t sl = sizeof sa.sin;
148 int nns = 0;
149 int family = AF_INET;
150 int rlen;
151 int next;
152 int i, j;
153 int cs;
154 struct pollfd pfd[nqueries+2];
155 int qpos[nqueries], apos[nqueries], retry[nqueries];
156 unsigned char alen_buf[nqueries][2];
157 int r;
158 unsigned long t0, t1, t2, t3, temp_t;
159 struct type_ctx ctx;
160 uint8_t nres_v4, end_query;
161 int blens[2] = {0};
162 unsigned char *bp[2] = { NULL, NULL };
163 #if OHOS_DNS_PROXY_BY_NETSYS
164 int retry_count = 0;
165 int retry_limit;
166 int nv4 = 0, nv6 = 0;
167 int iv4[MAXNS] = {0}, iv6[MAXNS] = {0};
168 int first_try[MAXNS] = {0}, sec_try[MAXNS] = {0};
169 int try_ns[MAXNS] = {0};
170 bool multiV4 = false;
171 int last_retry = 0;
172 #endif
173
174 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs);
175
176 timeout = 1000*conf->timeout;
177 attempts = conf->attempts;
178
179 for (nns=0; nns<conf->nns; nns++) {
180 const struct address *iplit = &conf->ns[nns];
181 if (iplit->family == AF_INET) {
182 memcpy(&ns[nns].sin.sin_addr, iplit->addr, 4);
183 ns[nns].sin.sin_port = htons(53);
184 ns[nns].sin.sin_family = AF_INET;
185 #if OHOS_DNS_PROXY_BY_NETSYS
186 iv4[nv4] = nns;
187 nv4++;
188 #endif
189 } else {
190 sl = sizeof sa.sin6;
191 memcpy(&ns[nns].sin6.sin6_addr, iplit->addr, 16);
192 ns[nns].sin6.sin6_port = htons(53);
193 ns[nns].sin6.sin6_scope_id = iplit->scopeid;
194 ns[nns].sin6.sin6_family = family = AF_INET6;
195 #if OHOS_DNS_PROXY_BY_NETSYS
196 iv6[nv6] = nns;
197 nv6++;
198 #endif
199 }
200 }
201 #if OHOS_DNS_PROXY_BY_NETSYS
202 /* If public dns added by netsys, nv4 > 3, else if public dns added by net, nv4 > 2 */
203 if ((nv4 > 3 && conf->nns != conf->non_public) || (nv4 > 2 && conf->nns == conf->non_public)) {
204 multiV4 = true;
205 }
206 if (multiV4) {
207 if (nv6 > 0) {
208 /* Use two v4 and all v6 dns for first try, use other v4 for second try */
209 first_try[0] = iv4[0];
210 first_try[1] = iv4[1];
211 for (int k = 0; k < nv6; k++) {
212 first_try[2+k] = iv6[k]; // v6 index starts from 2
213 }
214 for (int l = 2; l < nv4; l++) {
215 sec_try[l-2] = iv4[l]; // ignore the first 2 v4
216 }
217 } else if (nv4 > 4) { // if v4 <= 4, multiV4 is false
218 for (int k = 0; k < 4; k++) { // use 4 v4 for the first try
219 first_try[k] = iv4[k];
220 }
221 for (int l = 4; l < nv4; l++) {
222 sec_try[l-4] = iv4[l]; // ignore the first 4 v4
223 }
224 } else {
225 multiV4 = false;
226 }
227 }
228 #endif
229
230 /* Get local address and open/bind a socket */
231 fd = socket(family, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
232 #ifndef __LITEOS__
233 if (fd < 0) {
234 MUSL_LOGW("%{public}s: %{public}d: create UDP socket failed, errno id: %{public}d",
235 __func__, __LINE__, errno);
236 }
237 #endif
238
239 /* Handle case where system lacks IPv6 support */
240 if (fd < 0 && family == AF_INET6 && errno == EAFNOSUPPORT) {
241 for (i=0; i<nns && conf->ns[nns].family == AF_INET6; i++);
242 if (i==nns) {
243 #ifndef __LITEOS__
244 MUSL_LOGW("%{public}s: %{public}d: system lacks IPv6 support: %{public}d",
245 __func__, __LINE__, errno);
246 #endif
247 pthread_setcancelstate(cs, 0);
248 return DNS_FAIL_REASON_LACK_V6_SUPPORT;
249 }
250 fd = socket(AF_INET, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
251 family = AF_INET;
252 sl = sizeof sa.sin;
253 }
254
255 #ifndef __LITEOS__
256 /**
257 * Todo FwmarkClient::BindSocket
258 */
259 if (netid > 0) {
260 res_bind_socket(fd, netid);
261 }
262 #endif
263
264 /* Convert any IPv4 addresses in a mixed environment to v4-mapped */
265 if (fd >= 0 && family == AF_INET6) {
266 setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &(int){0}, sizeof 0);
267 for (i=0; i<nns; i++) {
268 if (ns[i].sin.sin_family != AF_INET) continue;
269 memcpy(ns[i].sin6.sin6_addr.s6_addr+12,
270 &ns[i].sin.sin_addr, 4);
271 memcpy(ns[i].sin6.sin6_addr.s6_addr,
272 "\0\0\0\0\0\0\0\0\0\0\xff\xff", 12);
273 ns[i].sin6.sin6_family = AF_INET6;
274 ns[i].sin6.sin6_flowinfo = 0;
275 ns[i].sin6.sin6_scope_id = 0;
276 }
277 }
278
279 sa.sin.sin_family = family;
280 if (fd < 0 || bind(fd, (void *)&sa, sl) < 0) {
281 #ifndef __LITEOS__
282 MUSL_LOGW("%{public}s: %{public}d: AF_INET fd failed or bind failed, fd: %{public}d, errno: %{public}d",
283 __func__, __LINE__, fd, errno);
284 #endif
285 if (fd >= 0) close(fd);
286 pthread_setcancelstate(cs, 0);
287 return DNS_FAIL_REASON_CREATE_UDP_SOCKET_FAILED;
288 }
289
290 /* Past this point, there are no errors. Each individual query will
291 * yield either no reply (indicated by zero length) or an answer
292 * packet which is up to the caller to interpret. */
293
294 for (i=0; i<nqueries; i++) pfd[i].fd = -1;
295 pfd[nqueries].fd = fd;
296 pfd[nqueries].events = POLLIN;
297 pfd[nqueries+1].fd = -2;
298
299 pthread_cleanup_push(cleanup, pfd);
300 pthread_setcancelstate(cs, 0);
301
302 memset(alens, 0, sizeof *alens * nqueries);
303
304 retry_interval = timeout / attempts;
305 next = 0;
306 t0 = t2 = mtime();
307 t1 = t2 - retry_interval;
308 t3 = 0;
309 temp_t = 0;
310 nres_v4 = 0;
311 end_query = 0;
312
313 for (; t2-t0 < timeout; t2=mtime()) {
314 #if OHOS_DNS_PROXY_BY_NETSYS
315 retry_count++;
316 #endif
317 /* This is the loop exit condition: that all queries
318 * have an accepted answer. */
319 for (i=0; i<nqueries && alens[i]>0; i++);
320 if (i==nqueries) break;
321
322 /* if the temp_t timeout, return result immediately. */
323 if (end_query) {
324 goto out;
325 }
326
327 if (t2-t1 >= retry_interval) {
328 /* if the first query round timeout, determine whether
329 * to return based on the num of answers. */
330 if (nres_v4 > 0) {
331 goto out;
332 }
333 /* Query all configured namservers in parallel */
334 for (i=0; i<nqueries; i++) {
335 retry[i] = 0;
336 #if OHOS_DNS_PROXY_BY_NETSYS
337 if (multiV4) {
338 retry[i] = last_retry;
339 }
340 #endif
341 if (!alens[i]) {
342 #if OHOS_DNS_PROXY_BY_NETSYS
343 if (multiV4) {
344 if (retry_count <= 1) {
345 retry_limit = (nv6 > 0) ? (2 + nv6) : 4; // 2 v4 and all v6 or 4 v4
346 memcpy(try_ns, first_try, MAXNS * sizeof(int));
347 } else {
348 retry_limit = (nv6 > 0) ? (nv4 - 2) : (nv4 - 4); // ignore the first 2 or 4 v4
349 memcpy(try_ns, sec_try, MAXNS * sizeof(int));
350 }
351 for (j=0; j<retry_limit; j++) {
352 if (sendto(fd, queries[i], qlens[i], MSG_NOSIGNAL, (void *)&ns[try_ns[j]], sl) == -1) {
353 int errno_code = errno;
354 #ifndef __LITEOS__
355 MUSL_LOGW("%{public}s: %{public}d: sendto failed, errno id: %{public}d",
356 __func__, __LINE__, errno_code);
357 #endif
358 if (dns_errno) {
359 *dns_errno = errno_code;
360 }
361 }
362 }
363 } else {
364 /* First time only use non public ns, public ns is used after first query failed */
365 if (retry_count <= 1 && conf->non_public > 0) {
366 retry_limit = conf->non_public;
367 } else {
368 retry_limit = nns;
369 }
370 for (j=0; j<retry_limit; j++) {
371 if (sendto(fd, queries[i], qlens[i], MSG_NOSIGNAL, (void *)&ns[j], sl) == -1) {
372 int errno_code = errno;
373 #ifndef __LITEOS__
374 MUSL_LOGW("%{public}s: %{public}d: sendto failed, errno id: %{public}d",
375 __func__, __LINE__, errno_code);
376 #endif
377 if (dns_errno) {
378 *dns_errno = errno_code;
379 }
380 }
381 }
382 }
383 #else
384 for (j=0; j<nns; j++) {
385 if (sendto(fd, queries[i], qlens[i], MSG_NOSIGNAL, (void *)&ns[j], sl) == -1) {
386 int errno_code = errno;
387 #ifndef __LITEOS__
388 MUSL_LOGW("%{public}s: %{public}d: sendto failed, errno id: %{public}d",
389 __func__, __LINE__, errno_code);
390 #endif
391 if (dns_errno) {
392 *dns_errno = errno_code;
393 }
394 }
395 }
396 #endif
397 }
398 }
399 t1 = t2;
400 servfail_retry = 2 * nqueries;
401 }
402
403 unsigned long remaining_time = t1 + retry_interval - t2;
404 if (nres_v4 > 0) {
405 if (!temp_t) {
406 /* The first time to receive a v4 */
407 temp_t = t2 - t1;
408 t3 = t2;
409
410 if (temp_t <= LARGE_LATENCY && temp_t > 0) {
411 remaining_time = MIN_WAIT_V6;
412 end_query = 1;
413 } else {
414 #ifndef __LITEOS__
415 MUSL_LOGW("%{public}s: %{public}d: has v4 addr but large latency.", __func__, __LINE__);
416 #endif
417 goto out;
418 }
419 } else {
420 /* This is not the first time to receive a v4 */
421 if (t2 > t3 + MIN_WAIT_V6) {
422 #ifndef __LITEOS__
423 MUSL_LOGW("%{public}s: %{public}d: t2 > t3 + MIN_WAIT_V6 %{public}ld, %{public}ld",
424 __func__, __LINE__, t2, t3);
425 #endif
426 goto out;
427 }
428 remaining_time = t3 + MIN_WAIT_V6 - t2;
429 if (remaining_time > MIN_WAIT_V6) {
430 #ifndef __LITEOS__
431 MUSL_LOGW("%{public}s: %{public}d: remaining_time error", __func__, __LINE__);
432 #endif
433 goto out;
434 }
435 end_query = 1;
436 }
437 }
438
439 /* Wait for a response, or until time to retry */
440 if (poll(pfd, nqueries+1, remaining_time) <= 0) continue;
441 end_query = 0;
442
443 while (next < nqueries) {
444 struct msghdr mh = {
445 .msg_name = (void *)&sa,
446 .msg_namelen = sl,
447 .msg_iovlen = 1,
448 .msg_iov = (struct iovec []){
449 { .iov_base = (void *)answers[next],
450 .iov_len = asize }
451 }
452 };
453 rlen = recvmsg(fd, &mh, 0);
454 if (rlen < 0) {
455 #ifndef __LITEOS__
456 if (errno != EAGAIN) {
457 MUSL_LOGW("%{public}s: %{public}d: recvmsg failed, errno id: %{public}d",
458 __func__, __LINE__, errno);
459 }
460 #endif
461 break;
462 }
463
464 /* Ignore non-identifiable packets */
465 if (rlen < 4) continue;
466
467 /* Ignore replies from addresses we didn't send to */
468 switch (sa.sin.sin_family) {
469 // for ipv4 response, need to compare family, port and address
470 case AF_INET:
471 for (j = 0; j < nns; j++) {
472 if (ns[j].sin.sin_family == AF_INET && ns[j].sin.sin_port == sa.sin.sin_port && (
473 ns[j].sin.sin_addr.s_addr == INADDR_ANY ||
474 ns[j].sin.sin_addr.s_addr == sa.sin.sin_addr.s_addr)) {
475 break;
476 }
477 }
478 break;
479 // for ipv6 response, need to compare family, port and address, flowinfo and scopeid is not necessary
480 case AF_INET6:
481 for (j = 0; j < nns; j++) {
482 if (ns[j].sin6.sin6_family == AF_INET6 &&
483 ns[j].sin6.sin6_port == sa.sin6.sin6_port && (
484 IN6_IS_ADDR_UNSPECIFIED(&ns[j].sin6.sin6_addr) ||
485 IN6_ARE_ADDR_EQUAL(&ns[j].sin6.sin6_addr, &sa.sin6.sin6_addr))) {
486 break;
487 }
488 }
489 break;
490 default:
491 j = nns;
492 break;
493 }
494 if (j==nns) {
495 #ifndef __LITEOS__
496 MUSL_LOGW("%{public}s: %{public}d: replies from wrong addresses, ignore it", __func__, __LINE__);
497 #endif
498 continue;
499 }
500
501 /* Find which query this answer goes with, if any */
502 for (i=next; i<nqueries && (
503 answers[next][0] != queries[i][0] ||
504 answers[next][1] != queries[i][1] ); i++);
505 if (i==nqueries) continue;
506 if (alens[i]) continue;
507
508 /* Only accept positive or negative responses;
509 * retry immediately on server failure, and ignore
510 * all other codes such as refusal. */
511 switch (answers[next][3] & 15) {
512 case 0:
513 break;
514 case 3:
515 if (retry[i] + 1 < nns) {
516 retry[i]++;
517 #if OHOS_DNS_PROXY_BY_NETSYS
518 if (multiV4) {
519 last_retry = retry[i];
520 }
521 #endif
522 continue;
523 } else {
524 #ifndef __LITEOS__
525 MUSL_LOGW("%{public}s: %{public}d: retry failed for %{public}d nameservers, and get no such name",
526 __func__, __LINE__, retry[i]);
527 #endif
528 break;
529 }
530 case 2:
531 if (servfail_retry && servfail_retry--)
532 sendto(fd, queries[i],
533 qlens[i], MSG_NOSIGNAL,
534 (void *)&ns[j], sl);
535 default:
536 continue;
537 }
538
539 /* Store answer in the right slot, or update next
540 * available temp slot if it's already in place. */
541 alens[i] = rlen;
542 if (i == next)
543 for (; next<nqueries && alens[next]; next++);
544 else
545 memcpy(answers[i], answers[next], rlen);
546
547 ctx.count_v4 = 0;
548 ctx.count_v6 = 0;
549 __dns_parse(answers[i], alens[i], type_parse_callback, &ctx);
550 nres_v4 += ctx.count_v4;
551 #ifndef __LITEOS__
552 if (ctx.count_v4 == 0 && ctx.count_v6 == 0) {
553 MUSL_LOGW("%{public}s: %{public}d: response have no ip.", __func__, __LINE__);
554 }
555 #endif
556
557 /* If answer is truncated (TC bit), before fallback to TCP, restore the UDP answer*/
558 if ((answers[i][2] & 2) || (mh.msg_flags & MSG_TRUNC)) {
559 if (bp[i] == NULL) {
560 bp[i] = calloc(1, sizeof(unsigned char) * BPBUF_SIZE);
561 /* If fail to calloc backup buffer, only use TCP even if it fails*/
562 if (bp[i] != NULL) {
563 blens[i] = rlen;
564 memcpy(bp[i], answers[i], rlen);
565 }
566 }
567 }
568
569 /* Ignore further UDP if all slots full or TCP-mode */
570 if (next == nqueries) pfd[nqueries].events = 0;
571
572 /* If answer is truncated (TC bit), fallback to TCP */
573 if ((answers[i][2] & 2) || (mh.msg_flags & MSG_TRUNC)) {
574 #ifndef __LITEOS__
575 MUSL_LOGW("%{public}s: %{public}d: fallback to TCP, msg_flags: %{public}d",
576 __func__, __LINE__, mh.msg_flags);
577 #endif
578 alens[i] = -1;
579 nres_v4 = 0;
580 if (dns_errno) {
581 *dns_errno = FALLBACK_TCP_QUERY;
582 }
583 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, 0);
584 r = start_tcp(pfd+i, family, ns+j, sl, queries[i], qlens[i], netid);
585 pthread_setcancelstate(cs, 0);
586 if (r >= 0) {
587 qpos[i] = r;
588 apos[i] = 0;
589 }
590 continue;
591 }
592 }
593
594 for (i=0; i<nqueries; i++) if (pfd[i].revents & POLLOUT) {
595 struct msghdr mh = {
596 .msg_iovlen = 2,
597 .msg_iov = (struct iovec [2]){
598 { .iov_base = (uint8_t[]){ qlens[i]>>8, qlens[i] }, .iov_len = 2 },
599 { .iov_base = (void *)queries[i], .iov_len = qlens[i] } }
600 };
601 step_mh(&mh, qpos[i]);
602 r = sendmsg(pfd[i].fd, &mh, MSG_NOSIGNAL);
603 if (r < 0) goto out;
604 qpos[i] += r;
605 if (qpos[i] == qlens[i]+2)
606 pfd[i].events = POLLIN;
607 }
608
609 for (i=0; i<nqueries; i++) if (pfd[i].revents & POLLIN) {
610 struct msghdr mh = {
611 .msg_iovlen = 2,
612 .msg_iov = (struct iovec [2]){
613 { .iov_base = alen_buf[i], .iov_len = 2 },
614 { .iov_base = answers[i], .iov_len = asize } }
615 };
616 step_mh(&mh, apos[i]);
617 r = recvmsg(pfd[i].fd, &mh, 0);
618 if (r <= 0) goto out;
619 apos[i] += r;
620 if (apos[i] < 2) continue;
621 int alen = alen_buf[i][0]*256 + alen_buf[i][1];
622 if (alen < 13) goto out;
623 if (apos[i] < alen+2 && apos[i] < asize+2)
624 continue;
625 int rcode = answers[i][3] & 15;
626 if (rcode != 0 && rcode != 3)
627 goto out;
628
629 /* Storing the length here commits the accepted answer.
630 * Immediately close TCP socket so as not to consume
631 * resources we no longer need. */
632 alens[i] = alen;
633 __syscall(SYS_close, pfd[i].fd);
634 pfd[i].fd = -1;
635 }
636 }
637 out:
638 pthread_cleanup_pop(1);
639 /* Disregard any incomplete TCP results and try to reuse UDP */
640 for (i = 0; i < nqueries; i++) {
641 if (alens[i] < 0) {
642 if (blens[i] != 0 && bp[i] != NULL) {
643 alens[i] = blens[i];
644 memcpy(answers[i], bp[i], blens[i]);
645 #ifndef __LITEOS__
646 MUSL_LOGW("%{public}s: %{public}d: rollback to UDP", __func__, __LINE__);
647 #endif
648 } else {
649 alens[i] = 0;
650 }
651 }
652 if (bp[i] != NULL) {
653 free(bp[i]);
654 }
655 }
656
657 return 0;
658 }
659
__res_msend(int nqueries,const unsigned char * const * queries,const int * qlens,unsigned char * const * answers,int * alens,int asize)660 int __res_msend(int nqueries, const unsigned char *const *queries,
661 const int *qlens, unsigned char *const *answers, int *alens, int asize)
662 {
663 struct resolvconf conf;
664 if (__get_resolv_conf(&conf, 0, 0) < 0) return -1;
665 return __res_msend_rc(nqueries, queries, qlens, answers, alens, asize, &conf);
666 }
667