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