• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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