• 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 			compatible_close(info->fd.sockfd);
347 			return NULL;
348 		}
349 	}
350 #endif
351 
352 	new_wsi = lws_adopt_descriptor_vhost1(info->vh, info->type,
353 					      info->vh_prot_name, info->parent,
354 					      info->opaque);
355 	if (!new_wsi) {
356 		if (info->type & LWS_ADOPT_SOCKET)
357 			compatible_close(info->fd.sockfd);
358 		return NULL;
359 	}
360 
361 #if defined(LWS_WITH_ACCESS_LOG)
362 		lws_get_peer_simple_fd(info->fd.sockfd, new_wsi->simple_ip,
363 					sizeof(new_wsi->simple_ip));
364 #endif
365 
366 #if defined(LWS_WITH_PEER_LIMITS)
367 	if (peer)
368 		lws_peer_add_wsi(info->vh->context, peer, new_wsi);
369 #endif
370 
371 	return lws_adopt_descriptor_vhost2(new_wsi, info->type, info->fd);
372 }
373 
374 struct lws *
lws_adopt_socket_vhost(struct lws_vhost * vh,lws_sockfd_type accept_fd)375 lws_adopt_socket_vhost(struct lws_vhost *vh, lws_sockfd_type accept_fd)
376 {
377 	lws_sock_file_fd_type fd;
378 
379 	fd.sockfd = accept_fd;
380 	return lws_adopt_descriptor_vhost(vh, LWS_ADOPT_SOCKET |
381 			LWS_ADOPT_HTTP | LWS_ADOPT_ALLOW_SSL, fd, NULL, NULL);
382 }
383 
384 struct lws *
lws_adopt_socket(struct lws_context * context,lws_sockfd_type accept_fd)385 lws_adopt_socket(struct lws_context *context, lws_sockfd_type accept_fd)
386 {
387 	return lws_adopt_socket_vhost(context->vhost_list, accept_fd);
388 }
389 
390 /* Common read-buffer adoption for lws_adopt_*_readbuf */
391 static struct lws*
adopt_socket_readbuf(struct lws * wsi,const char * readbuf,size_t len)392 adopt_socket_readbuf(struct lws *wsi, const char *readbuf, size_t len)
393 {
394 	struct lws_context_per_thread *pt;
395 	struct lws_pollfd *pfd;
396 	int n;
397 
398 	if (!wsi)
399 		return NULL;
400 
401 	if (!readbuf || len == 0)
402 		return wsi;
403 
404 	if (wsi->position_in_fds_table == LWS_NO_FDS_POS)
405 		return wsi;
406 
407 	pt = &wsi->context->pt[(int)wsi->tsi];
408 
409 	n = lws_buflist_append_segment(&wsi->buflist, (const uint8_t *)readbuf,
410 				       len);
411 	if (n < 0)
412 		goto bail;
413 	if (n)
414 		lws_dll2_add_head(&wsi->dll_buflist, &pt->dll_buflist_owner);
415 
416 	/*
417 	 * we can't process the initial read data until we can attach an ah.
418 	 *
419 	 * if one is available, get it and place the data in his ah rxbuf...
420 	 * wsi with ah that have pending rxbuf get auto-POLLIN service.
421 	 *
422 	 * no autoservice because we didn't get a chance to attach the
423 	 * readbuf data to wsi or ah yet, and we will do it next if we get
424 	 * the ah.
425 	 */
426 	if (wsi->http.ah || !lws_header_table_attach(wsi, 0)) {
427 
428 		lwsl_notice("%s: calling service on readbuf ah\n", __func__);
429 
430 		/*
431 		 * unlike a normal connect, we have the headers already
432 		 * (or the first part of them anyway).
433 		 * libuv won't come back and service us without a network
434 		 * event, so we need to do the header service right here.
435 		 */
436 		pfd = &pt->fds[wsi->position_in_fds_table];
437 		pfd->revents |= LWS_POLLIN;
438 		lwsl_err("%s: calling service\n", __func__);
439 		if (lws_service_fd_tsi(wsi->context, pfd, wsi->tsi))
440 			/* service closed us */
441 			return NULL;
442 
443 		return wsi;
444 	}
445 	lwsl_err("%s: deferring handling ah\n", __func__);
446 
447 	return wsi;
448 
449 bail:
450 	lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS,
451 			   "adopt skt readbuf fail");
452 
453 	return NULL;
454 }
455 
456 #if defined(LWS_WITH_UDP)
457 #if defined(LWS_WITH_CLIENT)
458 static struct lws *
lws_create_adopt_udp2(struct lws * wsi,const char * ads,const struct addrinfo * r,int n,void * opaque)459 lws_create_adopt_udp2(struct lws *wsi, const char *ads,
460 		      const struct addrinfo *r, int n, void *opaque)
461 {
462 	lws_sock_file_fd_type sock;
463 	int bc = 1;
464 
465 	assert(wsi);
466 
467 	if (!wsi->dns_results)
468 		wsi->dns_results_next = wsi->dns_results = r;
469 
470 	if (ads && (n < 0 || !r)) {
471 		/*
472 		 * DNS lookup failed: there are no usable results.  Fail the
473 		 * overall connection request.
474 		 */
475 		lwsl_notice("%s: bad: n %d, r %p\n", __func__, n, r);
476 
477 		/*
478 		 * We didn't get a callback on a cache item and bump the
479 		 * refcount.  So don't let the cleanup continue to think it
480 		 * needs to decrement any refcount.
481 		 */
482 		wsi->dns_results_next = wsi->dns_results = NULL;
483 		goto bail;
484 	}
485 
486 	while (wsi->dns_results_next) {
487 
488 		/*
489 		 * We have done the dns lookup, identify the result we want
490 		 * if any, and then complete the adoption by binding wsi to
491 		 * socket opened on it.
492 		 *
493 		 * Ignore the weak assumptions about protocol driven by port
494 		 * number and force to DGRAM / UDP since that's what this
495 		 * function is for.
496 		 */
497 
498 #if !defined(__linux__)
499 		/* PF_PACKET is linux-only */
500 		sock.sockfd = socket(wsi->dns_results_next->ai_family,
501 				     SOCK_DGRAM, IPPROTO_UDP);
502 #else
503 		sock.sockfd = socket(wsi->pf_packet ? PF_PACKET :
504 					wsi->dns_results_next->ai_family,
505 				     SOCK_DGRAM, wsi->pf_packet ?
506 					htons(0x800) : IPPROTO_UDP);
507 #endif
508 		if (sock.sockfd == LWS_SOCK_INVALID)
509 			goto resume;
510 
511 		((struct sockaddr_in *)wsi->dns_results_next->ai_addr)->sin_port =
512 				htons(wsi->c_port);
513 
514 		if (setsockopt(sock.sockfd, SOL_SOCKET, SO_REUSEADDR, (const char *)&bc,
515 			       sizeof(bc)) < 0)
516 			lwsl_err("%s: failed to set reuse\n", __func__);
517 
518 		if (wsi->do_broadcast &&
519 		    setsockopt(sock.sockfd, SOL_SOCKET, SO_BROADCAST, (const char *)&bc,
520 			       sizeof(bc)) < 0)
521 				lwsl_err("%s: failed to set broadcast\n",
522 						__func__);
523 
524 		/* Bind the udp socket to a particular network interface */
525 
526 		if (opaque &&
527 		    lws_plat_BINDTODEVICE(sock.sockfd, (const char *)opaque))
528 			goto resume;
529 
530 		if (wsi->do_bind &&
531 		    bind(sock.sockfd, wsi->dns_results_next->ai_addr,
532 #if defined(_WIN32)
533 			 (int)wsi->dns_results_next->ai_addrlen
534 #else
535 			 sizeof(struct sockaddr)//wsi->dns_results_next->ai_addrlen
536 #endif
537 								    ) == -1) {
538 			lwsl_err("%s: bind failed\n", __func__);
539 			goto resume;
540 		}
541 
542 		if (!wsi->do_bind && !wsi->pf_packet) {
543 
544 			if (connect(sock.sockfd, wsi->dns_results_next->ai_addr,
545 				     (socklen_t)wsi->dns_results_next->ai_addrlen) == -1) {
546 				lwsl_err("%s: conn fd %d fam %d %s:%u failed "
547 					 "(salen %d) errno %d\n", __func__,
548 					 sock.sockfd,
549 					 wsi->dns_results_next->ai_addr->sa_family,
550 					 ads ? ads : "null", wsi->c_port,
551 					 (int)wsi->dns_results_next->ai_addrlen,
552 					 LWS_ERRNO);
553 				compatible_close(sock.sockfd);
554 				goto resume;
555 			}
556 
557 			memcpy(&wsi->udp->sa, wsi->dns_results_next->ai_addr,
558 			       wsi->dns_results_next->ai_addrlen);
559 			wsi->udp->salen = (socklen_t)wsi->dns_results_next->ai_addrlen;
560 		}
561 
562 		/* we connected: complete the udp socket adoption flow */
563 
564 		lws_addrinfo_clean(wsi);
565 		return lws_adopt_descriptor_vhost2(wsi,
566 						LWS_ADOPT_RAW_SOCKET_UDP, sock);
567 
568 resume:
569 		wsi->dns_results_next = wsi->dns_results_next->ai_next;
570 	}
571 
572 	lwsl_err("%s: unable to create INET socket %d\n", __func__, LWS_ERRNO);
573 	lws_addrinfo_clean(wsi);
574 
575 bail:
576 	lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS, "adopt udp2 fail");
577 
578 	return NULL;
579 }
580 
581 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)582 lws_create_adopt_udp(struct lws_vhost *vhost, const char *ads, int port,
583 		     int flags, const char *protocol_name, const char *ifname,
584 		     struct lws *parent_wsi, void *opaque,
585 		     const lws_retry_bo_t *retry_policy)
586 {
587 #if !defined(LWS_PLAT_OPTEE)
588 	struct lws *wsi;
589 	int n;
590 
591 	lwsl_info("%s: %s:%u\n", __func__, ads ? ads : "null", port);
592 
593 	/* create the logical wsi without any valid fd */
594 
595 	wsi = lws_adopt_descriptor_vhost1(vhost, LWS_ADOPT_RAW_SOCKET_UDP,
596 					  protocol_name, parent_wsi, opaque);
597 	if (!wsi) {
598 		lwsl_err("%s: udp wsi creation failed\n", __func__);
599 		goto bail;
600 	}
601 	wsi->do_bind = !!(flags & LWS_CAUDP_BIND);
602 	wsi->do_broadcast = !!(flags & LWS_CAUDP_BROADCAST);
603 	wsi->pf_packet = !!(flags & LWS_CAUDP_PF_PACKET);
604 	wsi->c_port = port;
605 	if (retry_policy)
606 		wsi->retry_policy = retry_policy;
607 	else
608 		wsi->retry_policy = vhost->retry_policy;
609 
610 #if !defined(LWS_WITH_SYS_ASYNC_DNS)
611 	{
612 		struct addrinfo *r, h;
613 		char buf[16];
614 
615 		memset(&h, 0, sizeof(h));
616 		h.ai_family = AF_UNSPEC;    /* Allow IPv4 or IPv6 */
617 		h.ai_socktype = SOCK_DGRAM;
618 		h.ai_protocol = IPPROTO_UDP;
619 		h.ai_flags = AI_PASSIVE;
620 #ifdef AI_ADDRCONFIG
621 		h.ai_flags |= AI_ADDRCONFIG;
622 #endif
623 
624 		/* if the dns lookup is synchronous, do the whole thing now */
625 		lws_snprintf(buf, sizeof(buf), "%u", port);
626 		n = getaddrinfo(ads, buf, &h, &r);
627 		if (n) {
628 #if !defined(LWS_PLAT_FREERTOS)
629 			lwsl_info("%s: getaddrinfo error: %s\n", __func__,
630 				  gai_strerror(n));
631 #else
632 			lwsl_info("%s: getaddrinfo error: %s\n", __func__,
633 					strerror(n));
634 #endif
635 			//freeaddrinfo(r);
636 			goto bail1;
637 		}
638 		/* complete it immediately after the blocking dns lookup
639 		 * finished... free r when connect either completed or failed */
640 		wsi = lws_create_adopt_udp2(wsi, ads, r, 0, NULL);
641 
642 		return wsi;
643 	}
644 #else
645 	if (ads) {
646 		/*
647 		 * with async dns, use the wsi as the point about which to do
648 		 * the dns lookup and have it call the second part when it's
649 		 * done.
650 		 *
651 		 * Keep a refcount on the results and free it when we connected
652 		 * or definitively failed.
653 		 *
654 		 * Notice wsi has no socket at this point (we don't know what
655 		 * kind to ask for until we get the dns back).  But it is bound
656 		 * to a vhost and can be cleaned up from that at vhost destroy.
657 		 */
658 		n = lws_async_dns_query(vhost->context, 0, ads,
659 					LWS_ADNS_RECORD_A,
660 					lws_create_adopt_udp2, wsi, (void *)ifname);
661 		lwsl_debug("%s: dns query returned %d\n", __func__, n);
662 		if (n == LADNS_RET_FAILED) {
663 			lwsl_err("%s: async dns failed\n", __func__);
664 			wsi = NULL;
665 			/*
666 			 * It was already closed by calling callback with error
667 			 * from lws_async_dns_query()
668 			 */
669 			goto bail;
670 		}
671 	} else {
672 		lwsl_debug("%s: udp adopt has no ads\n", __func__);
673 		wsi = lws_create_adopt_udp2(wsi, ads, NULL, 0, (void *)ifname);
674 	}
675 
676 	/* dns lookup is happening asynchronously */
677 
678 	lwsl_debug("%s: returning wsi %p\n", __func__, wsi);
679 	return wsi;
680 #endif
681 #if !defined(LWS_WITH_SYS_ASYNC_DNS)
682 bail1:
683 	lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS, "adopt udp2 fail");
684 	wsi = NULL;
685 #endif
686 bail:
687 	return wsi;
688 #else
689 	return NULL;
690 #endif
691 }
692 #endif
693 #endif
694 
695 struct lws *
lws_adopt_socket_readbuf(struct lws_context * context,lws_sockfd_type accept_fd,const char * readbuf,size_t len)696 lws_adopt_socket_readbuf(struct lws_context *context, lws_sockfd_type accept_fd,
697 			 const char *readbuf, size_t len)
698 {
699         return adopt_socket_readbuf(lws_adopt_socket(context, accept_fd),
700 				    readbuf, len);
701 }
702 
703 struct lws *
lws_adopt_socket_vhost_readbuf(struct lws_vhost * vhost,lws_sockfd_type accept_fd,const char * readbuf,size_t len)704 lws_adopt_socket_vhost_readbuf(struct lws_vhost *vhost,
705 			       lws_sockfd_type accept_fd,
706 			       const char *readbuf, size_t len)
707 {
708         return adopt_socket_readbuf(lws_adopt_socket_vhost(vhost, accept_fd),
709 				    readbuf, len);
710 }
711