• 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
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