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
rops_handle_POLLIN_listen(struct lws_context_per_thread * pt,struct lws * wsi,struct lws_pollfd * pollfd)28 rops_handle_POLLIN_listen(struct lws_context_per_thread *pt, struct lws *wsi,
29 struct lws_pollfd *pollfd)
30 {
31 struct lws_context *context = wsi->context;
32 lws_sockfd_type accept_fd = LWS_SOCK_INVALID;
33 lws_sock_file_fd_type fd;
34 struct sockaddr_storage cli_addr;
35 socklen_t clilen;
36
37 memset(&cli_addr, 0, sizeof(cli_addr));
38
39 /* if our vhost is going down, ignore it */
40
41 if (wsi->vhost->being_destroyed)
42 return LWS_HPI_RET_HANDLED;
43
44 /* pollin means a client has connected to us then
45 *
46 * pollout is a hack on esp32 for background accepts signalling
47 * they completed
48 */
49
50 do {
51 struct lws *cwsi;
52 int opts = LWS_ADOPT_SOCKET | LWS_ADOPT_ALLOW_SSL;
53
54 if (!(pollfd->revents & (LWS_POLLIN | LWS_POLLOUT)) ||
55 !(pollfd->events & LWS_POLLIN))
56 break;
57
58 #if defined(LWS_WITH_TLS)
59 /*
60 * can we really accept it, with regards to SSL limit?
61 * another vhost may also have had POLLIN on his
62 * listener this round and used it up already
63 */
64 if (wsi->vhost->tls.use_ssl &&
65 context->simultaneous_ssl_restriction &&
66 context->simultaneous_ssl ==
67 context->simultaneous_ssl_restriction)
68 /*
69 * no... ignore it, he won't come again until
70 * we are below the simultaneous_ssl_restriction
71 * limit and POLLIN is enabled on him again
72 */
73 break;
74 #endif
75 /* listen socket got an unencrypted connection... */
76
77 clilen = sizeof(cli_addr);
78
79 /*
80 * We cannot identify the peer who is in the listen
81 * socket connect queue before we accept it; even if
82 * we could, not accepting it due to PEER_LIMITS would
83 * block the connect queue for other legit peers.
84 */
85
86 accept_fd = accept((int)pollfd->fd,
87 (struct sockaddr *)&cli_addr, &clilen);
88 if (accept_fd == LWS_SOCK_INVALID) {
89 if (LWS_ERRNO == LWS_EAGAIN ||
90 LWS_ERRNO == LWS_EWOULDBLOCK) {
91 break;
92 }
93 lwsl_err("accept: %s\n", strerror(LWS_ERRNO));
94 return LWS_HPI_RET_HANDLED;
95 }
96
97 if (context->being_destroyed) {
98 compatible_close(accept_fd);
99 return LWS_HPI_RET_PLEASE_CLOSE_ME;
100 }
101
102 lws_plat_set_socket_options(wsi->vhost, accept_fd, 0);
103
104 #if defined(LWS_WITH_IPV6)
105 lwsl_debug("accepted new conn port %u on fd=%d\n",
106 ((cli_addr.ss_family == AF_INET6) ?
107 ntohs(((struct sockaddr_in6 *) &cli_addr)->sin6_port) :
108 ntohs(((struct sockaddr_in *) &cli_addr)->sin_port)),
109 accept_fd);
110 #else
111 {
112 struct sockaddr_in sain;
113
114 memcpy(&sain, &cli_addr, sizeof(sain));
115 lwsl_debug("accepted new conn port %u on fd=%d\n",
116 ntohs(sain.sin_port),
117 accept_fd);
118 }
119 #endif
120
121 /*
122 * look at who we connected to and give user code a
123 * chance to reject based on client IP. There's no
124 * protocol selected yet so we issue this to
125 * protocols[0]
126 */
127 if ((wsi->vhost->protocols[0].callback)(wsi,
128 LWS_CALLBACK_FILTER_NETWORK_CONNECTION,
129 NULL,
130 (void *)(lws_intptr_t)accept_fd, 0)) {
131 lwsl_debug("Callback denied net connection\n");
132 compatible_close(accept_fd);
133 return LWS_HPI_RET_PLEASE_CLOSE_ME;
134 }
135
136 if (!(wsi->vhost->options &
137 LWS_SERVER_OPTION_ADOPT_APPLY_LISTEN_ACCEPT_CONFIG))
138 opts |= LWS_ADOPT_HTTP;
139
140 #if defined(LWS_WITH_TLS)
141 if (!wsi->vhost->tls.use_ssl)
142 #endif
143 opts &= ~LWS_ADOPT_ALLOW_SSL;
144
145 fd.sockfd = accept_fd;
146 cwsi = lws_adopt_descriptor_vhost(wsi->vhost, opts, fd,
147 NULL, NULL);
148 if (!cwsi) {
149 lwsl_info("%s: vh %s: adopt failed\n", __func__,
150 wsi->vhost->name);
151
152 /* already closed cleanly as necessary */
153 return LWS_HPI_RET_WSI_ALREADY_DIED;
154 }
155 /*
156 if (lws_server_socket_service_ssl(cwsi, accept_fd)) {
157 lws_close_free_wsi(cwsi, LWS_CLOSE_STATUS_NOSTATUS,
158 "listen svc fail");
159 return LWS_HPI_RET_WSI_ALREADY_DIED;
160 }
161
162 lwsl_info("%s: new wsi %p: wsistate 0x%lx, role_ops %s\n",
163 __func__, cwsi, (unsigned long)cwsi->wsistate,
164 cwsi->role_ops->name);
165 */
166
167 } while (pt->fds_count < context->fd_limit_per_thread - 1 &&
168 wsi->position_in_fds_table != LWS_NO_FDS_POS &&
169 lws_poll_listen_fd(&pt->fds[wsi->position_in_fds_table]) > 0);
170
171 return LWS_HPI_RET_HANDLED;
172 }
173
rops_handle_POLLOUT_listen(struct lws * wsi)174 int rops_handle_POLLOUT_listen(struct lws *wsi)
175 {
176 return LWS_HP_RET_USER_SERVICE;
177 }
178
179 const struct lws_role_ops role_ops_listen = {
180 /* role name */ "listen",
181 /* alpn id */ NULL,
182 /* check_upgrades */ NULL,
183 /* pt_init_destroy */ NULL,
184 /* init_vhost */ NULL,
185 /* destroy_vhost */ NULL,
186 /* service_flag_pending */ NULL,
187 /* handle_POLLIN */ rops_handle_POLLIN_listen,
188 /* handle_POLLOUT */ rops_handle_POLLOUT_listen,
189 /* perform_user_POLLOUT */ NULL,
190 /* callback_on_writable */ NULL,
191 /* tx_credit */ NULL,
192 /* write_role_protocol */ NULL,
193 /* encapsulation_parent */ NULL,
194 /* alpn_negotiated */ NULL,
195 /* close_via_role_protocol */ NULL,
196 /* close_role */ NULL,
197 /* close_kill_connection */ NULL,
198 /* destroy_role */ NULL,
199 /* adoption_bind */ NULL,
200 /* client_bind */ NULL,
201 /* issue_keepalive */ NULL,
202 /* adoption_cb clnt, srv */ { 0, 0 },
203 /* rx_cb clnt, srv */ { 0, 0 },
204 /* writeable cb clnt, srv */ { 0, 0 },
205 /* close cb clnt, srv */ { 0, 0 },
206 /* protocol_bind_cb c,s */ { 0, 0 },
207 /* protocol_unbind_cb c,s */ { 0, 0 },
208 /* file_handle */ 0,
209 };
210