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