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 = ~0u;
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,const char * desc)48 lws_create_new_server_wsi(struct lws_vhost *vhost, int fixed_tsi, const char *desc)
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 lws_context_lock(vhost->context, __func__);
62 new_wsi = __lws_wsi_create_with_role(vhost->context, n, NULL);
63 lws_context_unlock(vhost->context);
64 if (new_wsi == NULL) {
65 lwsl_err("Out of memory for new connection\n");
66 return NULL;
67 }
68
69 __lws_lc_tag(&vhost->context->lcg[
70 #if defined(LWS_ROLE_H2) || defined(LWS_ROLE_MQTT)
71 strcmp(desc, "adopted") ? LWSLCG_WSI_MUX :
72 #endif
73 LWSLCG_WSI_SERVER], &new_wsi->lc, desc);
74
75 new_wsi->wsistate |= LWSIFR_SERVER;
76 new_wsi->tsi = (char)n;
77 lwsl_debug("%s joining vhost %s, tsi %d\n", new_wsi->lc.gutag,
78 vhost->name, new_wsi->tsi);
79
80 lws_vhost_bind_wsi(vhost, new_wsi);
81 new_wsi->rxflow_change_to = LWS_RXFLOW_ALLOW;
82 new_wsi->retry_policy = vhost->retry_policy;
83
84 /* initialize the instance struct */
85
86 lwsi_set_state(new_wsi, LRS_UNCONNECTED);
87 new_wsi->hdr_parsing_completed = 0;
88
89 #ifdef LWS_WITH_TLS
90 new_wsi->tls.use_ssl = LWS_SSL_ENABLED(vhost);
91 #endif
92
93 /*
94 * these can only be set once the protocol is known
95 * we set an un-established connection's protocol pointer
96 * to the start of the supported list, so it can look
97 * for matching ones during the handshake
98 */
99 new_wsi->a.protocol = vhost->protocols;
100 new_wsi->user_space = NULL;
101
102 /*
103 * outermost create notification for wsi
104 * no user_space because no protocol selection
105 */
106 vhost->protocols[0].callback(new_wsi, LWS_CALLBACK_WSI_CREATE, NULL,
107 NULL, 0);
108
109 return new_wsi;
110 }
111
112
113 /* if not a socket, it's a raw, non-ssl file descriptor
114 * req cx lock, acq pt lock, acq vh lock
115 */
116
117 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,const char * fi_wsi_name)118 __lws_adopt_descriptor_vhost1(struct lws_vhost *vh, lws_adoption_type type,
119 const char *vh_prot_name, struct lws *parent,
120 void *opaque, const char *fi_wsi_name)
121 {
122 struct lws_context *context = vh->context;
123 struct lws_context_per_thread *pt;
124 struct lws *new_wsi;
125 int n;
126
127 /*
128 * Notice that in SMP case, the wsi may be being created on an
129 * entirely different pt / tsi for load balancing. In that case as
130 * we initialize it, it may become "live" concurrently unexpectedly...
131 */
132
133 lws_context_assert_lock_held(vh->context);
134
135 n = -1;
136 if (parent)
137 n = parent->tsi;
138 new_wsi = lws_create_new_server_wsi(vh, n, "adopted");
139 if (!new_wsi)
140 return NULL;
141
142 /* bring in specific fault injection rules early */
143 lws_fi_inherit_copy(&new_wsi->fic, &context->fic, "wsi", fi_wsi_name);
144
145 if (lws_fi(&new_wsi->fic, "createfail")) {
146 lws_fi_destroy(&new_wsi->fic);
147
148 return NULL;
149 }
150
151 new_wsi->a.opaque_user_data = opaque;
152
153 pt = &context->pt[(int)new_wsi->tsi];
154 lws_pt_lock(pt, __func__);
155
156 if (parent) {
157 new_wsi->parent = parent;
158 new_wsi->sibling_list = parent->child_list;
159 parent->child_list = new_wsi;
160 }
161
162 if (vh_prot_name) {
163 new_wsi->a.protocol = lws_vhost_name_to_protocol(new_wsi->a.vhost,
164 vh_prot_name);
165 if (!new_wsi->a.protocol) {
166 lwsl_err("Protocol %s not enabled on vhost %s\n",
167 vh_prot_name, new_wsi->a.vhost->name);
168 goto bail;
169 }
170 if (lws_ensure_user_space(new_wsi)) {
171 lwsl_notice("OOM trying to get user_space\n");
172 goto bail;
173 }
174 }
175
176 if (!LWS_SSL_ENABLED(new_wsi->a.vhost) ||
177 !(type & LWS_ADOPT_SOCKET))
178 type &= (unsigned int)~LWS_ADOPT_ALLOW_SSL;
179
180 if (lws_role_call_adoption_bind(new_wsi, (int)type, vh_prot_name)) {
181 lwsl_err("%s: no role for desc type 0x%x\n", __func__, type);
182 goto bail;
183 }
184
185 #if defined(LWS_WITH_SERVER)
186 if (new_wsi->role_ops)
187 lws_metrics_tag_wsi_add(new_wsi, "role", new_wsi->role_ops->name);
188 #endif
189
190 lws_pt_unlock(pt);
191
192 /*
193 * he's an allocated wsi, but he's not on any fds list or child list,
194 * join him to the vhost's list of these kinds of incomplete wsi until
195 * he gets another identity (he may do async dns now...)
196 */
197 lws_vhost_lock(new_wsi->a.vhost);
198 lws_dll2_add_head(&new_wsi->vh_awaiting_socket,
199 &new_wsi->a.vhost->vh_awaiting_socket_owner);
200 lws_vhost_unlock(new_wsi->a.vhost);
201
202 return new_wsi;
203
204 bail:
205 lwsl_notice("%s: exiting on bail\n", __func__);
206 if (parent)
207 parent->child_list = new_wsi->sibling_list;
208 if (new_wsi->user_space)
209 lws_free(new_wsi->user_space);
210
211 lws_fi_destroy(&new_wsi->fic);
212
213 lws_pt_unlock(pt);
214 __lws_vhost_unbind_wsi(new_wsi); /* req cx, acq vh lock */
215
216 lws_free(new_wsi);
217
218 return NULL;
219 }
220
221 #if defined(LWS_WITH_SERVER) && defined(LWS_WITH_SECURE_STREAMS)
222
223 /*
224 * If the incoming wsi is bound to a vhost that is a ss server, this creates
225 * an accepted ss bound to the wsi.
226 *
227 * For h1 or raw, we can do the binding here, but for muxed protocols like h2
228 * or mqtt we have to do it not on the nwsi but on the stream. And for h2 we
229 * start off bound to h1 role, since we don't know if we will upgrade to h2
230 * until we meet the server.
231 *
232 * 1) No tls is assumed to mean no muxed protocol so can do it at adopt.
233 *
234 * 2) After alpn if not muxed we can do it.
235 *
236 * 3) For muxed, do it at the nwsi migration and on new stream
237 */
238
239 int
lws_adopt_ss_server_accept(struct lws * new_wsi)240 lws_adopt_ss_server_accept(struct lws *new_wsi)
241 {
242 struct lws_context_per_thread *pt =
243 &new_wsi->a.context->pt[(int)new_wsi->tsi];
244 lws_ss_handle_t *h;
245 void *pv, **ppv;
246
247 if (!new_wsi->a.vhost->ss_handle)
248 return 0;
249
250 pv = (char *)&new_wsi->a.vhost->ss_handle[1];
251
252 /*
253 * Yes... the vhost is pointing to its secure stream representing the
254 * server... we want to create an accepted SS and bind it to new_wsi,
255 * the info/ssi from the server SS (so the SS callbacks defined there),
256 * the opaque_user_data of the server object and the policy of it.
257 */
258
259 ppv = (void **)((char *)pv +
260 new_wsi->a.vhost->ss_handle->info.opaque_user_data_offset);
261
262 /*
263 * indicate we are an accepted connection referencing the
264 * server object
265 */
266
267 new_wsi->a.vhost->ss_handle->info.flags |= LWSSSINFLAGS_SERVER;
268
269 if (lws_ss_create(new_wsi->a.context, new_wsi->tsi,
270 &new_wsi->a.vhost->ss_handle->info,
271 *ppv, &h, NULL, NULL)) {
272 lwsl_err("%s: accept ss creation failed\n", __func__);
273 goto fail1;
274 }
275
276 /*
277 * We made a fresh accepted SS conn from the server pieces,
278 * now bind the wsi... the problem is, this is the nwsi if it's
279 * h2.
280 */
281
282 h->wsi = new_wsi;
283 new_wsi->a.opaque_user_data = h;
284 h->info.flags |= LWSSSINFLAGS_ACCEPTED;
285 /* indicate wsi should invalidate any ss link to it on close */
286 new_wsi->for_ss = 1;
287
288 // lwsl_notice("%s: opaq %p, role %s\n", __func__,
289 // new_wsi->a.opaque_user_data, new_wsi->role_ops->name);
290
291 h->policy = new_wsi->a.vhost->ss_handle->policy;
292
293 /* apply requested socket options */
294 if (lws_plat_set_socket_options_ip(new_wsi->desc.sockfd,
295 h->policy->priority,
296 (LCCSCF_IP_LOW_LATENCY *
297 !!(h->policy->flags & LWSSSPOLF_ATTR_LOW_LATENCY)) |
298 (LCCSCF_IP_HIGH_THROUGHPUT *
299 !!(h->policy->flags & LWSSSPOLF_ATTR_HIGH_THROUGHPUT)) |
300 (LCCSCF_IP_HIGH_RELIABILITY *
301 !!(h->policy->flags & LWSSSPOLF_ATTR_HIGH_RELIABILITY)) |
302 (LCCSCF_IP_LOW_COST *
303 !!(h->policy->flags & LWSSSPOLF_ATTR_LOW_COST))))
304 lwsl_warn("%s: %s: unable to set ip options\n",
305 __func__, new_wsi->lc.gutag);
306
307 /*
308 * add us to the list of clients that came in from the server
309 */
310
311 lws_pt_lock(pt, __func__);
312 lws_dll2_add_tail(&h->cli_list, &new_wsi->a.vhost->ss_handle->src_list);
313 lws_pt_unlock(pt);
314
315 /*
316 * Let's give it appropriate state notifications
317 */
318
319 if (lws_ss_event_helper(h, LWSSSCS_CREATING))
320 goto fail;
321 if (lws_ss_event_helper(h, LWSSSCS_CONNECTING))
322 goto fail;
323
324 /* defer CONNECTED until we see if he is upgrading */
325
326 // if (lws_ss_event_helper(h, LWSSSCS_CONNECTED))
327 // goto fail;
328
329 // lwsl_notice("%s: accepted ss complete, pcol %s\n", __func__,
330 // new_wsi->a.protocol->name);
331
332 return 0;
333
334 fail:
335 lws_ss_destroy(&h);
336 fail1:
337 return 1;
338 }
339
340 #endif
341
342
343 static struct lws *
lws_adopt_descriptor_vhost2(struct lws * new_wsi,lws_adoption_type type,lws_sock_file_fd_type fd)344 lws_adopt_descriptor_vhost2(struct lws *new_wsi, lws_adoption_type type,
345 lws_sock_file_fd_type fd)
346 {
347 struct lws_context_per_thread *pt =
348 &new_wsi->a.context->pt[(int)new_wsi->tsi];
349 int n;
350
351 /* enforce that every fd is nonblocking */
352
353 if (type & LWS_ADOPT_SOCKET) {
354 if (lws_plat_set_nonblocking(fd.sockfd)) {
355 lwsl_err("%s: unable to set sockfd %d nonblocking\n",
356 __func__, fd.sockfd);
357 goto fail;
358 }
359 }
360 #if !defined(WIN32)
361 else
362 if (lws_plat_set_nonblocking(fd.filefd)) {
363 lwsl_err("%s: unable to set filefd nonblocking\n",
364 __func__);
365 goto fail;
366 }
367 #endif
368
369 new_wsi->desc = fd;
370
371 if (!LWS_SSL_ENABLED(new_wsi->a.vhost) ||
372 !(type & LWS_ADOPT_SOCKET))
373 type &= (unsigned int)~LWS_ADOPT_ALLOW_SSL;
374
375 /*
376 * A new connection was accepted. Give the user a chance to
377 * set properties of the newly created wsi. There's no protocol
378 * selected yet so we issue this to the vhosts's default protocol,
379 * itself by default protocols[0]
380 */
381 new_wsi->wsistate |= LWSIFR_SERVER;
382 n = LWS_CALLBACK_SERVER_NEW_CLIENT_INSTANTIATED;
383 if (new_wsi->role_ops->adoption_cb[lwsi_role_server(new_wsi)])
384 n = new_wsi->role_ops->adoption_cb[lwsi_role_server(new_wsi)];
385
386 if (new_wsi->a.context->event_loop_ops->sock_accept)
387 if (new_wsi->a.context->event_loop_ops->sock_accept(new_wsi))
388 goto fail;
389
390 #if LWS_MAX_SMP > 1
391 /*
392 * Caution: after this point the wsi is live on its service thread
393 * which may be concurrent to this. We mark the wsi as still undergoing
394 * init in another pt so the assigned pt leaves it alone.
395 */
396 new_wsi->undergoing_init_from_other_pt = 1;
397 #endif
398
399 if (!(type & LWS_ADOPT_ALLOW_SSL)) {
400 lws_pt_lock(pt, __func__);
401 if (__insert_wsi_socket_into_fds(new_wsi->a.context, new_wsi)) {
402 lws_pt_unlock(pt);
403 lwsl_err("%s: fail inserting socket\n", __func__);
404 goto fail;
405 }
406 lws_pt_unlock(pt);
407 }
408 #if defined(LWS_WITH_SERVER)
409 else
410 if (lws_server_socket_service_ssl(new_wsi, fd.sockfd, 0)) {
411 lwsl_info("%s: fail ssl negotiation\n", __func__);
412
413 goto fail;
414 }
415 #endif
416
417 lws_vhost_lock(new_wsi->a.vhost);
418 /* he has fds visibility now, remove from vhost orphan list */
419 lws_dll2_remove(&new_wsi->vh_awaiting_socket);
420 lws_vhost_unlock(new_wsi->a.vhost);
421
422 /*
423 * by deferring callback to this point, after insertion to fds,
424 * lws_callback_on_writable() can work from the callback
425 */
426 if ((new_wsi->a.protocol->callback)(new_wsi, (enum lws_callback_reasons)n, new_wsi->user_space,
427 NULL, 0))
428 goto fail;
429
430 /* role may need to do something after all adoption completed */
431
432 lws_role_call_adoption_bind(new_wsi, (int)type | _LWS_ADOPT_FINISH,
433 new_wsi->a.protocol->name);
434
435 #if defined(LWS_WITH_SERVER) && defined(LWS_WITH_SECURE_STREAMS)
436 /*
437 * Did we come from an accepted client connection to a ss server?
438 *
439 * !!! For mux protocols, this will cause an additional inactive ss
440 * representing the nwsi. Doing that allows us to support both h1
441 * (here) and h2 (at __lws_wsi_server_new())
442 */
443
444 lwsl_info("%s: %s, vhost %s\n", __func__, new_wsi->lc.gutag,
445 new_wsi->a.vhost->lc.gutag);
446
447 if (lws_adopt_ss_server_accept(new_wsi))
448 goto fail;
449 #endif
450
451 #if LWS_MAX_SMP > 1
452 /* its actual pt can service it now */
453
454 new_wsi->undergoing_init_from_other_pt = 0;
455 #endif
456
457 lws_cancel_service_pt(new_wsi);
458
459 return new_wsi;
460
461 fail:
462 if (type & LWS_ADOPT_SOCKET)
463 lws_close_free_wsi(new_wsi, LWS_CLOSE_STATUS_NOSTATUS,
464 "adopt skt fail");
465
466 return NULL;
467 }
468
469
470 /* if not a socket, it's a raw, non-ssl file descriptor */
471
472 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)473 lws_adopt_descriptor_vhost(struct lws_vhost *vh, lws_adoption_type type,
474 lws_sock_file_fd_type fd, const char *vh_prot_name,
475 struct lws *parent)
476 {
477 lws_adopt_desc_t info;
478
479 memset(&info, 0, sizeof(info));
480
481 info.vh = vh;
482 info.type = type;
483 info.fd = fd;
484 info.vh_prot_name = vh_prot_name;
485 info.parent = parent;
486
487 return lws_adopt_descriptor_vhost_via_info(&info);
488 }
489
490 struct lws *
lws_adopt_descriptor_vhost_via_info(const lws_adopt_desc_t * info)491 lws_adopt_descriptor_vhost_via_info(const lws_adopt_desc_t *info)
492 {
493 socklen_t slen = sizeof(lws_sockaddr46);
494 struct lws *new_wsi;
495
496 #if defined(LWS_WITH_PEER_LIMITS)
497 struct lws_peer *peer = NULL;
498
499 if (info->type & LWS_ADOPT_SOCKET) {
500 peer = lws_get_or_create_peer(info->vh, info->fd.sockfd);
501
502 if (peer && info->vh->context->ip_limit_wsi &&
503 peer->count_wsi >= info->vh->context->ip_limit_wsi) {
504 lwsl_info("Peer reached wsi limit %d\n",
505 info->vh->context->ip_limit_wsi);
506 if (info->vh->context->pl_notify_cb)
507 info->vh->context->pl_notify_cb(
508 info->vh->context,
509 info->fd.sockfd,
510 &peer->sa46);
511 compatible_close(info->fd.sockfd);
512 return NULL;
513 }
514 }
515 #endif
516
517 lws_context_lock(info->vh->context, __func__);
518
519 new_wsi = __lws_adopt_descriptor_vhost1(info->vh, info->type,
520 info->vh_prot_name, info->parent,
521 info->opaque, info->fi_wsi_name);
522 if (!new_wsi) {
523 if (info->type & LWS_ADOPT_SOCKET)
524 compatible_close(info->fd.sockfd);
525 goto bail;
526 }
527
528 if (info->type & LWS_ADOPT_SOCKET &&
529 getpeername(info->fd.sockfd, (struct sockaddr *)&new_wsi->sa46_peer,
530 &slen) < 0)
531 lwsl_info("%s: getpeername failed\n", __func__);
532
533 #if defined(LWS_WITH_PEER_LIMITS)
534 if (peer)
535 lws_peer_add_wsi(info->vh->context, peer, new_wsi);
536 #endif
537
538 new_wsi = lws_adopt_descriptor_vhost2(new_wsi, info->type, info->fd);
539
540 bail:
541 lws_context_unlock(info->vh->context);
542
543 return new_wsi;
544 }
545
546 struct lws *
lws_adopt_socket_vhost(struct lws_vhost * vh,lws_sockfd_type accept_fd)547 lws_adopt_socket_vhost(struct lws_vhost *vh, lws_sockfd_type accept_fd)
548 {
549 lws_sock_file_fd_type fd;
550
551 fd.sockfd = accept_fd;
552 return lws_adopt_descriptor_vhost(vh, LWS_ADOPT_SOCKET |
553 LWS_ADOPT_HTTP | LWS_ADOPT_ALLOW_SSL, fd, NULL, NULL);
554 }
555
556 struct lws *
lws_adopt_socket(struct lws_context * context,lws_sockfd_type accept_fd)557 lws_adopt_socket(struct lws_context *context, lws_sockfd_type accept_fd)
558 {
559 return lws_adopt_socket_vhost(context->vhost_list, accept_fd);
560 }
561
562 /* Common read-buffer adoption for lws_adopt_*_readbuf */
563 static struct lws*
adopt_socket_readbuf(struct lws * wsi,const char * readbuf,size_t len)564 adopt_socket_readbuf(struct lws *wsi, const char *readbuf, size_t len)
565 {
566 struct lws_context_per_thread *pt;
567 struct lws_pollfd *pfd;
568 int n;
569
570 if (!wsi)
571 return NULL;
572
573 if (!readbuf || len == 0)
574 return wsi;
575
576 if (wsi->position_in_fds_table == LWS_NO_FDS_POS)
577 return wsi;
578
579 pt = &wsi->a.context->pt[(int)wsi->tsi];
580
581 n = lws_buflist_append_segment(&wsi->buflist, (const uint8_t *)readbuf,
582 len);
583 if (n < 0)
584 goto bail;
585 if (n)
586 lws_dll2_add_head(&wsi->dll_buflist, &pt->dll_buflist_owner);
587
588 /*
589 * we can't process the initial read data until we can attach an ah.
590 *
591 * if one is available, get it and place the data in his ah rxbuf...
592 * wsi with ah that have pending rxbuf get auto-POLLIN service.
593 *
594 * no autoservice because we didn't get a chance to attach the
595 * readbuf data to wsi or ah yet, and we will do it next if we get
596 * the ah.
597 */
598 if (wsi->http.ah || !lws_header_table_attach(wsi, 0)) {
599
600 lwsl_notice("%s: calling service on readbuf ah\n", __func__);
601
602 /*
603 * unlike a normal connect, we have the headers already
604 * (or the first part of them anyway).
605 * libuv won't come back and service us without a network
606 * event, so we need to do the header service right here.
607 */
608 pfd = &pt->fds[wsi->position_in_fds_table];
609 pfd->revents |= LWS_POLLIN;
610 lwsl_err("%s: calling service\n", __func__);
611 if (lws_service_fd_tsi(wsi->a.context, pfd, wsi->tsi))
612 /* service closed us */
613 return NULL;
614
615 return wsi;
616 }
617 lwsl_err("%s: deferring handling ah\n", __func__);
618
619 return wsi;
620
621 bail:
622 lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS,
623 "adopt skt readbuf fail");
624
625 return NULL;
626 }
627
628 #if defined(LWS_WITH_UDP)
629 #if defined(LWS_WITH_CLIENT)
630
631 /*
632 * This is the ASYNC_DNS callback target for udp client, it's analogous to
633 * connect3()
634 */
635
636 static struct lws *
lws_create_adopt_udp2(struct lws * wsi,const char * ads,const struct addrinfo * r,int n,void * opaque)637 lws_create_adopt_udp2(struct lws *wsi, const char *ads,
638 const struct addrinfo *r, int n, void *opaque)
639 {
640 lws_sock_file_fd_type sock;
641 int bc = 1, m;
642
643 assert(wsi);
644
645 if (ads && (n < 0 || !r)) {
646 /*
647 * DNS lookup failed: there are no usable results. Fail the
648 * overall connection request.
649 */
650 lwsl_notice("%s: bad: n %d, r %p\n", __func__, n, r);
651
652 goto bail;
653 }
654
655 m = lws_sort_dns(wsi, r);
656 #if defined(LWS_WITH_SYS_ASYNC_DNS)
657 lws_async_dns_freeaddrinfo(&r);
658 #else
659 freeaddrinfo((struct addrinfo *)r);
660 #endif
661 if (m)
662 goto bail;
663
664 while (lws_dll2_get_head(&wsi->dns_sorted_list)) {
665 lws_dns_sort_t *s = lws_container_of(
666 lws_dll2_get_head(&wsi->dns_sorted_list),
667 lws_dns_sort_t, list);
668
669 /*
670 * Remove it from the head, but don't free it yet... we are
671 * taking responsibility to free it
672 */
673 lws_dll2_remove(&s->list);
674
675 /*
676 * We have done the dns lookup, identify the result we want
677 * if any, and then complete the adoption by binding wsi to
678 * socket opened on it.
679 *
680 * Ignore the weak assumptions about protocol driven by port
681 * number and force to DGRAM / UDP since that's what this
682 * function is for.
683 */
684
685 #if !defined(__linux__)
686 sock.sockfd = socket(s->dest.sa4.sin_family,
687 SOCK_DGRAM, IPPROTO_UDP);
688 #else
689 /* PF_PACKET is linux-only */
690 sock.sockfd = socket(wsi->pf_packet ? PF_PACKET :
691 s->dest.sa4.sin_family,
692 SOCK_DGRAM, wsi->pf_packet ?
693 htons(0x800) : IPPROTO_UDP);
694 #endif
695 if (sock.sockfd == LWS_SOCK_INVALID)
696 goto resume;
697
698 /* ipv6 udp!!! */
699
700 if (s->af == AF_INET)
701 s->dest.sa4.sin_port = htons(wsi->c_port);
702 #if defined(LWS_WITH_IPV6)
703 else
704 s->dest.sa6.sin6_port = htons(wsi->c_port);
705 #endif
706
707 if (setsockopt(sock.sockfd, SOL_SOCKET, SO_REUSEADDR,
708 (const char *)&bc, sizeof(bc)) < 0)
709 lwsl_err("%s: failed to set reuse\n", __func__);
710
711 if (wsi->do_broadcast &&
712 setsockopt(sock.sockfd, SOL_SOCKET, SO_BROADCAST,
713 (const char *)&bc, sizeof(bc)) < 0)
714 lwsl_err("%s: failed to set broadcast\n", __func__);
715
716 /* Bind the udp socket to a particular network interface */
717
718 if (opaque &&
719 lws_plat_BINDTODEVICE(sock.sockfd, (const char *)opaque))
720 goto resume;
721
722 if (wsi->do_bind &&
723 bind(sock.sockfd, sa46_sockaddr(&s->dest),
724 #if defined(_WIN32)
725 (int)sa46_socklen(&s->dest)
726 #else
727 sizeof(struct sockaddr)
728 #endif
729 ) == -1) {
730 lwsl_err("%s: bind failed\n", __func__);
731 goto resume;
732 }
733
734 if (!wsi->do_bind && !wsi->pf_packet) {
735 #if !defined(__APPLE__)
736 if (connect(sock.sockfd, sa46_sockaddr(&s->dest),
737 sa46_socklen(&s->dest)) == -1 &&
738 errno != EADDRNOTAVAIL /* openbsd */ ) {
739 lwsl_err("%s: conn fd %d fam %d %s:%u failed "
740 "errno %d\n", __func__, sock.sockfd,
741 s->dest.sa4.sin_family,
742 ads ? ads : "null", wsi->c_port,
743 LWS_ERRNO);
744 compatible_close(sock.sockfd);
745 goto resume;
746 }
747 #endif
748 }
749
750 if (wsi->udp)
751 wsi->udp->sa46 = s->dest;
752 wsi->sa46_peer = s->dest;
753
754 /* we connected: complete the udp socket adoption flow */
755
756 #if defined(LWS_WITH_SYS_ASYNC_DNS)
757 if (wsi->a.context->async_dns.wsi == wsi)
758 wsi->a.context->async_dns.dns_server_connected = 1;
759 #endif
760
761 lws_free(s);
762 lws_addrinfo_clean(wsi);
763 return lws_adopt_descriptor_vhost2(wsi,
764 LWS_ADOPT_RAW_SOCKET_UDP, sock);
765
766 resume:
767 lws_free(s);
768 }
769
770 lwsl_err("%s: unable to create INET socket %d\n", __func__, LWS_ERRNO);
771 lws_addrinfo_clean(wsi);
772
773 #if defined(LWS_WITH_SYS_ASYNC_DNS)
774 if (wsi->a.context->async_dns.wsi == wsi)
775 lws_async_dns_drop_server(wsi->a.context);
776 #endif
777
778 bail:
779
780 /* caller must close */
781
782 return NULL;
783 }
784
785 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,const char * fi_wsi_name)786 lws_create_adopt_udp(struct lws_vhost *vhost, const char *ads, int port,
787 int flags, const char *protocol_name, const char *ifname,
788 struct lws *parent_wsi, void *opaque,
789 const lws_retry_bo_t *retry_policy, const char *fi_wsi_name)
790 {
791 #if !defined(LWS_PLAT_OPTEE)
792 struct lws *wsi;
793 int n;
794
795 lwsl_info("%s: %s:%u\n", __func__, ads ? ads : "null", port);
796
797 /* create the logical wsi without any valid fd */
798
799 lws_context_lock(vhost->context, __func__);
800
801 wsi = __lws_adopt_descriptor_vhost1(vhost, LWS_ADOPT_SOCKET |
802 LWS_ADOPT_RAW_SOCKET_UDP,
803 protocol_name, parent_wsi, opaque,
804 fi_wsi_name);
805
806 lws_context_unlock(vhost->context);
807 if (!wsi) {
808 lwsl_err("%s: udp wsi creation failed\n", __func__);
809 goto bail;
810 }
811
812 // lwsl_notice("%s: role %s\n", __func__, wsi->role_ops->name);
813
814 wsi->do_bind = !!(flags & LWS_CAUDP_BIND);
815 wsi->do_broadcast = !!(flags & LWS_CAUDP_BROADCAST);
816 wsi->pf_packet = !!(flags & LWS_CAUDP_PF_PACKET);
817 wsi->c_port = (uint16_t)(unsigned int)port;
818 if (retry_policy)
819 wsi->retry_policy = retry_policy;
820 else
821 wsi->retry_policy = vhost->retry_policy;
822
823 #if !defined(LWS_WITH_SYS_ASYNC_DNS)
824 {
825 struct addrinfo *r, h;
826 char buf[16];
827
828 memset(&h, 0, sizeof(h));
829 h.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */
830 h.ai_socktype = SOCK_DGRAM;
831 h.ai_protocol = IPPROTO_UDP;
832 #if defined(AI_PASSIVE)
833 h.ai_flags = AI_PASSIVE;
834 #endif
835 #ifdef AI_ADDRCONFIG
836 h.ai_flags |= AI_ADDRCONFIG;
837 #endif
838
839 /* if the dns lookup is synchronous, do the whole thing now */
840 lws_snprintf(buf, sizeof(buf), "%u", port);
841 n = getaddrinfo(ads, buf, &h, &r);
842 if (n) {
843 #if !defined(LWS_PLAT_FREERTOS)
844 lwsl_info("%s: getaddrinfo error: %s\n", __func__,
845 gai_strerror(n));
846 #else
847 lwsl_info("%s: getaddrinfo error: %s\n", __func__,
848 strerror(n));
849 #endif
850 //freeaddrinfo(r);
851 goto bail1;
852 }
853 /*
854 * With synchronous dns, complete it immediately after the
855 * blocking dns lookup finished... free r when connect either
856 * completed or failed
857 */
858 wsi = lws_create_adopt_udp2(wsi, ads, r, 0, NULL);
859
860 return wsi;
861 }
862 #else
863 if (ads) {
864 /*
865 * with async dns, use the wsi as the point about which to do
866 * the dns lookup and have it call the second part when it's
867 * done.
868 *
869 * Keep a refcount on the results and free it when we connected
870 * or definitively failed.
871 *
872 * Notice wsi has no socket at this point (we don't know what
873 * kind to ask for until we get the dns back). But it is bound
874 * to a vhost and can be cleaned up from that at vhost destroy.
875 */
876 n = lws_async_dns_query(vhost->context, 0, ads,
877 LWS_ADNS_RECORD_A,
878 lws_create_adopt_udp2, wsi,
879 (void *)ifname);
880 // lwsl_notice("%s: dns query returned %d\n", __func__, n);
881 if (n == LADNS_RET_FAILED) {
882 lwsl_err("%s: async dns failed\n", __func__);
883 wsi = NULL;
884 /*
885 * It was already closed by calling callback with error
886 * from lws_async_dns_query()
887 */
888 goto bail;
889 }
890 } else {
891 lwsl_debug("%s: udp adopt has no ads\n", __func__);
892 wsi = lws_create_adopt_udp2(wsi, ads, NULL, 0, (void *)ifname);
893 }
894
895 /* dns lookup is happening asynchronously */
896
897 // lwsl_notice("%s: returning wsi %p\n", __func__, wsi);
898
899 return wsi;
900 #endif
901 #if !defined(LWS_WITH_SYS_ASYNC_DNS)
902 bail1:
903 lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS, "adopt udp2 fail");
904 wsi = NULL;
905 #endif
906 bail:
907 return wsi;
908 #else
909 return NULL;
910 #endif
911 }
912 #endif
913 #endif
914
915 struct lws *
lws_adopt_socket_readbuf(struct lws_context * context,lws_sockfd_type accept_fd,const char * readbuf,size_t len)916 lws_adopt_socket_readbuf(struct lws_context *context, lws_sockfd_type accept_fd,
917 const char *readbuf, size_t len)
918 {
919 return adopt_socket_readbuf(lws_adopt_socket(context, accept_fd),
920 readbuf, len);
921 }
922
923 struct lws *
lws_adopt_socket_vhost_readbuf(struct lws_vhost * vhost,lws_sockfd_type accept_fd,const char * readbuf,size_t len)924 lws_adopt_socket_vhost_readbuf(struct lws_vhost *vhost,
925 lws_sockfd_type accept_fd,
926 const char *readbuf, size_t len)
927 {
928 return adopt_socket_readbuf(lws_adopt_socket_vhost(vhost, accept_fd),
929 readbuf, len);
930 }
931