• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * libwebsockets - small server side websockets and web server implementation
3  *
4  * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to
8  * deal in the Software without restriction, including without limitation the
9  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10  * sell copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22  * IN THE SOFTWARE.
23  */
24 
25 #include "private-lib-core.h"
26 
27 static int
lws_get_idlest_tsi(struct lws_context * context)28 lws_get_idlest_tsi(struct lws_context *context)
29 {
30 	unsigned int lowest = ~0;
31 	int n = 0, hit = -1;
32 
33 	for (; n < context->count_threads; n++) {
34 		lwsl_debug("%s: %d %d\n", __func__, context->pt[n].fds_count,
35 				context->fd_limit_per_thread - 1);
36 		if ((unsigned int)context->pt[n].fds_count !=
37 		    context->fd_limit_per_thread - 1 &&
38 		    (unsigned int)context->pt[n].fds_count < lowest) {
39 			lowest = context->pt[n].fds_count;
40 			hit = n;
41 		}
42 	}
43 
44 	return hit;
45 }
46 
47 struct lws *
lws_create_new_server_wsi(struct lws_vhost * vhost,int fixed_tsi)48 lws_create_new_server_wsi(struct lws_vhost *vhost, int fixed_tsi)
49 {
50 	struct lws *new_wsi;
51 	int n = fixed_tsi;
52 
53 	if (n < 0)
54 		n = lws_get_idlest_tsi(vhost->context);
55 
56 	if (n < 0) {
57 		lwsl_err("no space for new conn\n");
58 		return NULL;
59 	}
60 
61 	new_wsi = lws_zalloc(sizeof(struct lws), "new server wsi");
62 	if (new_wsi == NULL) {
63 		lwsl_err("Out of memory for new connection\n");
64 		return NULL;
65 	}
66 
67 	new_wsi->wsistate |= LWSIFR_SERVER;
68 	new_wsi->tsi = n;
69 	lwsl_debug("new wsi %p joining vhost %s, tsi %d\n", new_wsi,
70 		   vhost->name, new_wsi->tsi);
71 
72 	lws_vhost_bind_wsi(vhost, new_wsi);
73 	new_wsi->context = vhost->context;
74 	new_wsi->pending_timeout = NO_PENDING_TIMEOUT;
75 	new_wsi->rxflow_change_to = LWS_RXFLOW_ALLOW;
76 	new_wsi->retry_policy = vhost->retry_policy;
77 
78 #if defined(LWS_WITH_DETAILED_LATENCY)
79 	if (vhost->context->detailed_latency_cb)
80 		new_wsi->detlat.earliest_write_req_pre_write = lws_now_usecs();
81 #endif
82 
83 	/* initialize the instance struct */
84 
85 	lwsi_set_state(new_wsi, LRS_UNCONNECTED);
86 	new_wsi->hdr_parsing_completed = 0;
87 
88 #ifdef LWS_WITH_TLS
89 	new_wsi->tls.use_ssl = LWS_SSL_ENABLED(vhost);
90 #endif
91 
92 	/*
93 	 * these can only be set once the protocol is known
94 	 * we set an un-established connection's protocol pointer
95 	 * to the start of the supported list, so it can look
96 	 * for matching ones during the handshake
97 	 */
98 	new_wsi->protocol = vhost->protocols;
99 	new_wsi->user_space = NULL;
100 	new_wsi->desc.sockfd = LWS_SOCK_INVALID;
101 	new_wsi->position_in_fds_table = LWS_NO_FDS_POS;
102 
103 	vhost->context->count_wsi_allocated++;
104 
105 	/*
106 	 * outermost create notification for wsi
107 	 * no user_space because no protocol selection
108 	 */
109 	vhost->protocols[0].callback(new_wsi, LWS_CALLBACK_WSI_CREATE, NULL,
110 				     NULL, 0);
111 
112 	return new_wsi;
113 }
114 
115 
116 /* if not a socket, it's a raw, non-ssl file descriptor */
117 
118 static struct lws *
lws_adopt_descriptor_vhost1(struct lws_vhost * vh,lws_adoption_type type,const char * vh_prot_name,struct lws * parent,void * opaque)119 lws_adopt_descriptor_vhost1(struct lws_vhost *vh, lws_adoption_type type,
120 			    const char *vh_prot_name, struct lws *parent,
121 			    void *opaque)
122 {
123 	struct lws_context *context = vh->context;
124 	struct lws_context_per_thread *pt;
125 	struct lws *new_wsi;
126 	int n;
127 
128 	/*
129 	 * Notice that in SMP case, the wsi may be being created on an
130 	 * entirely different pt / tsi for load balancing.  In that case as
131 	 * we initialize it, it may become "live" concurrently unexpectedly...
132 	 */
133 
134 	n = -1;
135 	if (parent)
136 		n = parent->tsi;
137 	new_wsi = lws_create_new_server_wsi(vh, n);
138 	if (!new_wsi)
139 		return NULL;
140 
141 	new_wsi->opaque_user_data = opaque;
142 
143 	pt = &context->pt[(int)new_wsi->tsi];
144 	lws_stats_bump(pt, LWSSTATS_C_CONNECTIONS, 1);
145 
146 	if (parent) {
147 		new_wsi->parent = parent;
148 		new_wsi->sibling_list = parent->child_list;
149 		parent->child_list = new_wsi;
150 	}
151 
152 	if (vh_prot_name) {
153 		new_wsi->protocol = lws_vhost_name_to_protocol(new_wsi->vhost,
154 							       vh_prot_name);
155 		if (!new_wsi->protocol) {
156 			lwsl_err("Protocol %s not enabled on vhost %s\n",
157 				 vh_prot_name, new_wsi->vhost->name);
158 			goto bail;
159 		}
160 		if (lws_ensure_user_space(new_wsi)) {
161 		       lwsl_notice("OOM trying to get user_space\n");
162 			goto bail;
163 		}
164 	}
165 
166 	if (lws_role_call_adoption_bind(new_wsi, type, vh_prot_name)) {
167 		lwsl_err("%s: no role for desc type 0x%x\n", __func__, type);
168 		goto bail;
169 	}
170 
171 	/*
172 	 * he's an allocated wsi, but he's not on any fds list or child list,
173 	 * join him to the vhost's list of these kinds of incomplete wsi until
174 	 * he gets another identity (he may do async dns now...)
175 	 */
176 	lws_dll2_add_head(&new_wsi->vh_awaiting_socket,
177 			  &new_wsi->vhost->vh_awaiting_socket_owner);
178 
179 	return new_wsi;
180 
181 bail:
182        lwsl_notice("%s: exiting on bail\n", __func__);
183 	if (parent)
184 		parent->child_list = new_wsi->sibling_list;
185 	if (new_wsi->user_space)
186 		lws_free(new_wsi->user_space);
187 
188 	vh->context->count_wsi_allocated--;
189 
190 	lws_vhost_unbind_wsi(new_wsi);
191 	lws_free(new_wsi);
192 
193 	return NULL;
194 }
195 
196 static struct lws *
lws_adopt_descriptor_vhost2(struct lws * new_wsi,lws_adoption_type type,lws_sock_file_fd_type fd)197 lws_adopt_descriptor_vhost2(struct lws *new_wsi, lws_adoption_type type,
198 			    lws_sock_file_fd_type fd)
199 {
200 	struct lws_context_per_thread *pt =
201 			&new_wsi->context->pt[(int)new_wsi->tsi];
202 	int n;
203 
204 	/* enforce that every fd is nonblocking */
205 
206 	if (type & LWS_ADOPT_SOCKET) {
207 		if (lws_plat_set_nonblocking(fd.sockfd)) {
208 			lwsl_err("%s: unable to set sockfd %d nonblocking\n",
209 				 __func__, fd.sockfd);
210 			goto fail;
211 		}
212 	}
213 #if !defined(WIN32)
214 	else
215 		if (lws_plat_set_nonblocking(fd.filefd)) {
216 			lwsl_err("%s: unable to set filefd nonblocking\n",
217 				 __func__);
218 			goto fail;
219 		}
220 #endif
221 
222 	new_wsi->desc = fd;
223 
224 	if (!LWS_SSL_ENABLED(new_wsi->vhost) ||
225 	    !(type & LWS_ADOPT_SOCKET))
226 		type &= ~LWS_ADOPT_ALLOW_SSL;
227 
228 	/*
229 	 * A new connection was accepted. Give the user a chance to
230 	 * set properties of the newly created wsi. There's no protocol
231 	 * selected yet so we issue this to the vhosts's default protocol,
232 	 * itself by default protocols[0]
233 	 */
234 	new_wsi->wsistate |= LWSIFR_SERVER;
235 	n = LWS_CALLBACK_SERVER_NEW_CLIENT_INSTANTIATED;
236 	if (new_wsi->role_ops->adoption_cb[lwsi_role_server(new_wsi)])
237 		n = new_wsi->role_ops->adoption_cb[lwsi_role_server(new_wsi)];
238 
239 	if (new_wsi->context->event_loop_ops->sock_accept)
240 		if (new_wsi->context->event_loop_ops->sock_accept(new_wsi))
241 			goto fail;
242 
243 #if LWS_MAX_SMP > 1
244 	/*
245 	 * Caution: after this point the wsi is live on its service thread
246 	 * which may be concurrent to this.  We mark the wsi as still undergoing
247 	 * init in another pt so the assigned pt leaves it alone.
248 	 */
249 	new_wsi->undergoing_init_from_other_pt = 1;
250 #endif
251 
252 	if (!(type & LWS_ADOPT_ALLOW_SSL)) {
253 		lws_pt_lock(pt, __func__);
254 		if (__insert_wsi_socket_into_fds(new_wsi->context, new_wsi)) {
255 			lws_pt_unlock(pt);
256 			lwsl_err("%s: fail inserting socket\n", __func__);
257 			goto fail;
258 		}
259 		lws_pt_unlock(pt);
260 	}
261 #if defined(LWS_WITH_SERVER)
262 	 else
263 		if (lws_server_socket_service_ssl(new_wsi, fd.sockfd)) {
264 #if defined(LWS_WITH_ACCESS_LOG)
265 			lwsl_notice("%s: fail ssl negotiation: %s\n", __func__,
266 					new_wsi->simple_ip);
267 #else
268 			lwsl_info("%s: fail ssl negotiation\n", __func__);
269 #endif
270 			goto fail;
271 		}
272 #endif
273 
274 	/* he has fds visibility now, remove from vhost orphan list */
275 	lws_dll2_remove(&new_wsi->vh_awaiting_socket);
276 
277 	/*
278 	 *  by deferring callback to this point, after insertion to fds,
279 	 * lws_callback_on_writable() can work from the callback
280 	 */
281 	if ((new_wsi->protocol->callback)(new_wsi, n, new_wsi->user_space,
282 					  NULL, 0))
283 		goto fail;
284 
285 	/* role may need to do something after all adoption completed */
286 
287 	lws_role_call_adoption_bind(new_wsi, type | _LWS_ADOPT_FINISH,
288 				    new_wsi->protocol->name);
289 
290 #if LWS_MAX_SMP > 1
291 	/* its actual pt can service it now */
292 
293 	new_wsi->undergoing_init_from_other_pt = 0;
294 #endif
295 
296 	lws_cancel_service_pt(new_wsi);
297 
298 	return new_wsi;
299 
300 fail:
301 	if (type & LWS_ADOPT_SOCKET)
302 		lws_close_free_wsi(new_wsi, LWS_CLOSE_STATUS_NOSTATUS,
303 				   "adopt skt fail");
304 
305 	return NULL;
306 }
307 
308 
309 /* if not a socket, it's a raw, non-ssl file descriptor */
310 
311 struct lws *
lws_adopt_descriptor_vhost(struct lws_vhost * vh,lws_adoption_type type,lws_sock_file_fd_type fd,const char * vh_prot_name,struct lws * parent)312 lws_adopt_descriptor_vhost(struct lws_vhost *vh, lws_adoption_type type,
313 			   lws_sock_file_fd_type fd, const char *vh_prot_name,
314 			   struct lws *parent)
315 {
316 	lws_adopt_desc_t info;
317 
318 	memset(&info, 0, sizeof(info));
319 
320 	info.vh = vh;
321 	info.type = type;
322 	info.fd = fd;
323 	info.vh_prot_name = vh_prot_name;
324 	info.parent = parent;
325 
326 	return lws_adopt_descriptor_vhost_via_info(&info);
327 }
328 
329 struct lws *
lws_adopt_descriptor_vhost_via_info(const lws_adopt_desc_t * info)330 lws_adopt_descriptor_vhost_via_info(const lws_adopt_desc_t *info)
331 {
332 	struct lws *new_wsi;
333 #if defined(LWS_WITH_PEER_LIMITS)
334 	struct lws_peer *peer = NULL;
335 
336 	if (info->type & LWS_ADOPT_SOCKET) {
337 		peer = lws_get_or_create_peer(info->vh, info->fd.sockfd);
338 
339 		if (peer && info->vh->context->ip_limit_wsi &&
340 		    peer->count_wsi >= info->vh->context->ip_limit_wsi) {
341 			lwsl_notice("Peer reached wsi limit %d\n",
342 					info->vh->context->ip_limit_wsi);
343 			lws_stats_bump(&info->vh->context->pt[0],
344 					      LWSSTATS_C_PEER_LIMIT_WSI_DENIED,
345 					      1);
346 			return NULL;
347 		}
348 	}
349 #endif
350 
351 	new_wsi = lws_adopt_descriptor_vhost1(info->vh, info->type,
352 					      info->vh_prot_name, info->parent,
353 					      info->opaque);
354 	if (!new_wsi) {
355 		if (info->type & LWS_ADOPT_SOCKET)
356 			compatible_close(info->fd.sockfd);
357 		return NULL;
358 	}
359 
360 #if defined(LWS_WITH_ACCESS_LOG)
361 		lws_get_peer_simple_fd(info->fd.sockfd, new_wsi->simple_ip,
362 					sizeof(new_wsi->simple_ip));
363 #endif
364 
365 #if defined(LWS_WITH_PEER_LIMITS)
366 	if (peer)
367 		lws_peer_add_wsi(info->vh->context, peer, new_wsi);
368 #endif
369 
370 	return lws_adopt_descriptor_vhost2(new_wsi, info->type, info->fd);
371 }
372 
373 struct lws *
lws_adopt_socket_vhost(struct lws_vhost * vh,lws_sockfd_type accept_fd)374 lws_adopt_socket_vhost(struct lws_vhost *vh, lws_sockfd_type accept_fd)
375 {
376 	lws_sock_file_fd_type fd;
377 
378 	fd.sockfd = accept_fd;
379 	return lws_adopt_descriptor_vhost(vh, LWS_ADOPT_SOCKET |
380 			LWS_ADOPT_HTTP | LWS_ADOPT_ALLOW_SSL, fd, NULL, NULL);
381 }
382 
383 struct lws *
lws_adopt_socket(struct lws_context * context,lws_sockfd_type accept_fd)384 lws_adopt_socket(struct lws_context *context, lws_sockfd_type accept_fd)
385 {
386 	return lws_adopt_socket_vhost(context->vhost_list, accept_fd);
387 }
388 
389 /* Common read-buffer adoption for lws_adopt_*_readbuf */
390 static struct lws*
adopt_socket_readbuf(struct lws * wsi,const char * readbuf,size_t len)391 adopt_socket_readbuf(struct lws *wsi, const char *readbuf, size_t len)
392 {
393 	struct lws_context_per_thread *pt;
394 	struct lws_pollfd *pfd;
395 	int n;
396 
397 	if (!wsi)
398 		return NULL;
399 
400 	if (!readbuf || len == 0)
401 		return wsi;
402 
403 	if (wsi->position_in_fds_table == LWS_NO_FDS_POS)
404 		return wsi;
405 
406 	pt = &wsi->context->pt[(int)wsi->tsi];
407 
408 	n = lws_buflist_append_segment(&wsi->buflist, (const uint8_t *)readbuf,
409 				       len);
410 	if (n < 0)
411 		goto bail;
412 	if (n)
413 		lws_dll2_add_head(&wsi->dll_buflist, &pt->dll_buflist_owner);
414 
415 	/*
416 	 * we can't process the initial read data until we can attach an ah.
417 	 *
418 	 * if one is available, get it and place the data in his ah rxbuf...
419 	 * wsi with ah that have pending rxbuf get auto-POLLIN service.
420 	 *
421 	 * no autoservice because we didn't get a chance to attach the
422 	 * readbuf data to wsi or ah yet, and we will do it next if we get
423 	 * the ah.
424 	 */
425 	if (wsi->http.ah || !lws_header_table_attach(wsi, 0)) {
426 
427 		lwsl_notice("%s: calling service on readbuf ah\n", __func__);
428 
429 		/*
430 		 * unlike a normal connect, we have the headers already
431 		 * (or the first part of them anyway).
432 		 * libuv won't come back and service us without a network
433 		 * event, so we need to do the header service right here.
434 		 */
435 		pfd = &pt->fds[wsi->position_in_fds_table];
436 		pfd->revents |= LWS_POLLIN;
437 		lwsl_err("%s: calling service\n", __func__);
438 		if (lws_service_fd_tsi(wsi->context, pfd, wsi->tsi))
439 			/* service closed us */
440 			return NULL;
441 
442 		return wsi;
443 	}
444 	lwsl_err("%s: deferring handling ah\n", __func__);
445 
446 	return wsi;
447 
448 bail:
449 	lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS,
450 			   "adopt skt readbuf fail");
451 
452 	return NULL;
453 }
454 
455 #if defined(LWS_WITH_UDP)
456 #if defined(LWS_WITH_CLIENT)
457 static struct lws *
lws_create_adopt_udp2(struct lws * wsi,const char * ads,const struct addrinfo * r,int n,void * opaque)458 lws_create_adopt_udp2(struct lws *wsi, const char *ads,
459 		      const struct addrinfo *r, int n, void *opaque)
460 {
461 	lws_sock_file_fd_type sock;
462 	int bc = 1;
463 
464 	assert(wsi);
465 
466 	if (!wsi->dns_results)
467 		wsi->dns_results_next = wsi->dns_results = r;
468 
469 	if (ads && (n < 0 || !r)) {
470 		/*
471 		 * DNS lookup failed: there are no usable results.  Fail the
472 		 * overall connection request.
473 		 */
474 		lwsl_notice("%s: bad: n %d, r %p\n", __func__, n, r);
475 
476 		/*
477 		 * We didn't get a callback on a cache item and bump the
478 		 * refcount.  So don't let the cleanup continue to think it
479 		 * needs to decrement any refcount.
480 		 */
481 		wsi->dns_results_next = wsi->dns_results = NULL;
482 		goto bail;
483 	}
484 
485 	while (wsi->dns_results_next) {
486 
487 		/*
488 		 * We have done the dns lookup, identify the result we want
489 		 * if any, and then complete the adoption by binding wsi to
490 		 * socket opened on it.
491 		 *
492 		 * Ignore the weak assumptions about protocol driven by port
493 		 * number and force to DGRAM / UDP since that's what this
494 		 * function is for.
495 		 */
496 
497 #if !defined(__linux__)
498 		/* PF_PACKET is linux-only */
499 		sock.sockfd = socket(wsi->dns_results_next->ai_family,
500 				     SOCK_DGRAM, IPPROTO_UDP);
501 #else
502 		sock.sockfd = socket(wsi->pf_packet ? PF_PACKET :
503 					wsi->dns_results_next->ai_family,
504 				     SOCK_DGRAM, wsi->pf_packet ?
505 					htons(0x800) : IPPROTO_UDP);
506 #endif
507 		if (sock.sockfd == LWS_SOCK_INVALID)
508 			goto resume;
509 
510 		((struct sockaddr_in *)wsi->dns_results_next->ai_addr)->sin_port =
511 				htons(wsi->c_port);
512 
513 		if (setsockopt(sock.sockfd, SOL_SOCKET, SO_REUSEADDR, (const char *)&bc,
514 			       sizeof(bc)) < 0)
515 			lwsl_err("%s: failed to set reuse\n", __func__);
516 
517 		if (wsi->do_broadcast &&
518 		    setsockopt(sock.sockfd, SOL_SOCKET, SO_BROADCAST, (const char *)&bc,
519 			       sizeof(bc)) < 0)
520 				lwsl_err("%s: failed to set broadcast\n",
521 						__func__);
522 
523 		/* Bind the udp socket to a particular network interface */
524 
525 		if (opaque &&
526 		    lws_plat_BINDTODEVICE(sock.sockfd, (const char *)opaque))
527 			goto resume;
528 
529 		if (wsi->do_bind &&
530 		    bind(sock.sockfd, wsi->dns_results_next->ai_addr,
531 #if defined(_WIN32)
532 			 (int)wsi->dns_results_next->ai_addrlen
533 #else
534 			 sizeof(struct sockaddr)//wsi->dns_results_next->ai_addrlen
535 #endif
536 								    ) == -1) {
537 			lwsl_err("%s: bind failed\n", __func__);
538 			goto resume;
539 		}
540 
541 		if (!wsi->do_bind && !wsi->pf_packet) {
542 
543 			if (connect(sock.sockfd, wsi->dns_results_next->ai_addr,
544 				     (socklen_t)wsi->dns_results_next->ai_addrlen) == -1) {
545 				lwsl_err("%s: conn fd %d fam %d %s:%u failed "
546 					 "(salen %d) errno %d\n", __func__,
547 					 sock.sockfd,
548 					 wsi->dns_results_next->ai_addr->sa_family,
549 					 ads ? ads : "null", wsi->c_port,
550 					 (int)wsi->dns_results_next->ai_addrlen,
551 					 LWS_ERRNO);
552 				compatible_close(sock.sockfd);
553 				goto resume;
554 			}
555 
556 			memcpy(&wsi->udp->sa, wsi->dns_results_next->ai_addr,
557 			       wsi->dns_results_next->ai_addrlen);
558 			wsi->udp->salen = (socklen_t)wsi->dns_results_next->ai_addrlen;
559 		}
560 
561 		/* we connected: complete the udp socket adoption flow */
562 
563 		lws_addrinfo_clean(wsi);
564 		return lws_adopt_descriptor_vhost2(wsi,
565 						LWS_ADOPT_RAW_SOCKET_UDP, sock);
566 
567 resume:
568 		wsi->dns_results_next = wsi->dns_results_next->ai_next;
569 	}
570 
571 	lwsl_err("%s: unable to create INET socket %d\n", __func__, LWS_ERRNO);
572 	lws_addrinfo_clean(wsi);
573 
574 bail:
575 	lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS, "adopt udp2 fail");
576 
577 	return NULL;
578 }
579 
580 struct lws *
lws_create_adopt_udp(struct lws_vhost * vhost,const char * ads,int port,int flags,const char * protocol_name,const char * ifname,struct lws * parent_wsi,void * opaque,const lws_retry_bo_t * retry_policy)581 lws_create_adopt_udp(struct lws_vhost *vhost, const char *ads, int port,
582 		     int flags, const char *protocol_name, const char *ifname,
583 		     struct lws *parent_wsi, void *opaque,
584 		     const lws_retry_bo_t *retry_policy)
585 {
586 #if !defined(LWS_PLAT_OPTEE)
587 	struct lws *wsi;
588 	int n;
589 
590 	lwsl_info("%s: %s:%u\n", __func__, ads ? ads : "null", port);
591 
592 	/* create the logical wsi without any valid fd */
593 
594 	wsi = lws_adopt_descriptor_vhost1(vhost, LWS_ADOPT_RAW_SOCKET_UDP,
595 					  protocol_name, parent_wsi, opaque);
596 	if (!wsi) {
597 		lwsl_err("%s: udp wsi creation failed\n", __func__);
598 		goto bail;
599 	}
600 	wsi->do_bind = !!(flags & LWS_CAUDP_BIND);
601 	wsi->do_broadcast = !!(flags & LWS_CAUDP_BROADCAST);
602 	wsi->pf_packet = !!(flags & LWS_CAUDP_PF_PACKET);
603 	wsi->c_port = port;
604 	if (retry_policy)
605 		wsi->retry_policy = retry_policy;
606 	else
607 		wsi->retry_policy = vhost->retry_policy;
608 
609 #if !defined(LWS_WITH_SYS_ASYNC_DNS)
610 	{
611 		struct addrinfo *r, h;
612 		char buf[16];
613 
614 		memset(&h, 0, sizeof(h));
615 		h.ai_family = AF_UNSPEC;    /* Allow IPv4 or IPv6 */
616 		h.ai_socktype = SOCK_DGRAM;
617 		h.ai_protocol = IPPROTO_UDP;
618 		h.ai_flags = AI_PASSIVE;
619 #ifdef AI_ADDRCONFIG
620 		h.ai_flags |= AI_ADDRCONFIG;
621 #endif
622 
623 		/* if the dns lookup is synchronous, do the whole thing now */
624 		lws_snprintf(buf, sizeof(buf), "%u", port);
625 		n = getaddrinfo(ads, buf, &h, &r);
626 		if (n) {
627 #if !defined(LWS_PLAT_FREERTOS)
628 			lwsl_info("%s: getaddrinfo error: %s\n", __func__,
629 				  gai_strerror(n));
630 #else
631 			lwsl_info("%s: getaddrinfo error: %s\n", __func__,
632 					strerror(n));
633 #endif
634 			//freeaddrinfo(r);
635 			goto bail1;
636 		}
637 		/* complete it immediately after the blocking dns lookup
638 		 * finished... free r when connect either completed or failed */
639 		wsi = lws_create_adopt_udp2(wsi, ads, r, 0, NULL);
640 
641 		return wsi;
642 	}
643 #else
644 	if (ads) {
645 		/*
646 		 * with async dns, use the wsi as the point about which to do
647 		 * the dns lookup and have it call the second part when it's
648 		 * done.
649 		 *
650 		 * Keep a refcount on the results and free it when we connected
651 		 * or definitively failed.
652 		 *
653 		 * Notice wsi has no socket at this point (we don't know what
654 		 * kind to ask for until we get the dns back).  But it is bound
655 		 * to a vhost and can be cleaned up from that at vhost destroy.
656 		 */
657 		n = lws_async_dns_query(vhost->context, 0, ads,
658 					LWS_ADNS_RECORD_A,
659 					lws_create_adopt_udp2, wsi, (void *)ifname);
660 		lwsl_debug("%s: dns query returned %d\n", __func__, n);
661 		if (n == LADNS_RET_FAILED) {
662 			lwsl_err("%s: async dns failed\n", __func__);
663 			wsi = NULL;
664 			/*
665 			 * It was already closed by calling callback with error
666 			 * from lws_async_dns_query()
667 			 */
668 			goto bail;
669 		}
670 	} else {
671 		lwsl_debug("%s: udp adopt has no ads\n", __func__);
672 		wsi = lws_create_adopt_udp2(wsi, ads, NULL, 0, (void *)ifname);
673 	}
674 
675 	/* dns lookup is happening asynchronously */
676 
677 	lwsl_debug("%s: returning wsi %p\n", __func__, wsi);
678 	return wsi;
679 #endif
680 #if !defined(LWS_WITH_SYS_ASYNC_DNS)
681 bail1:
682 	lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS, "adopt udp2 fail");
683 	wsi = NULL;
684 #endif
685 bail:
686 	return wsi;
687 #else
688 	return NULL;
689 #endif
690 }
691 #endif
692 #endif
693 
694 struct lws *
lws_adopt_socket_readbuf(struct lws_context * context,lws_sockfd_type accept_fd,const char * readbuf,size_t len)695 lws_adopt_socket_readbuf(struct lws_context *context, lws_sockfd_type accept_fd,
696 			 const char *readbuf, size_t len)
697 {
698         return adopt_socket_readbuf(lws_adopt_socket(context, accept_fd),
699 				    readbuf, len);
700 }
701 
702 struct lws *
lws_adopt_socket_vhost_readbuf(struct lws_vhost * vhost,lws_sockfd_type accept_fd,const char * readbuf,size_t len)703 lws_adopt_socket_vhost_readbuf(struct lws_vhost *vhost,
704 			       lws_sockfd_type accept_fd,
705 			       const char *readbuf, size_t len)
706 {
707         return adopt_socket_readbuf(lws_adopt_socket_vhost(vhost, accept_fd),
708 				    readbuf, len);
709 }
710