• 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 #ifndef _WINSOCK_DEPRECATED_NO_WARNINGS
26 #define _WINSOCK_DEPRECATED_NO_WARNINGS
27 #endif
28 #include "private-lib-core.h"
29 
30 
31 int
_lws_plat_service_forced_tsi(struct lws_context * context,int tsi)32 _lws_plat_service_forced_tsi(struct lws_context *context, int tsi)
33 {
34 	struct lws_context_per_thread *pt = &context->pt[tsi];
35 	int m, n;
36 
37 	lws_service_flag_pending(context, tsi);
38 
39 	/* any socket with events to service? */
40 	for (n = 0; n < (int)pt->fds_count; n++) {
41 		if (!pt->fds[n].revents)
42 			continue;
43 
44 		m = lws_service_fd_tsi(context, &pt->fds[n], tsi);
45 		if (m < 0)
46 			return -1;
47 		/* if something closed, retry this slot */
48 		if (m)
49 			n--;
50 	}
51 
52 	lws_service_do_ripe_rxflow(pt);
53 
54 	return 0;
55 }
56 
57 
58 int
_lws_plat_service_tsi(struct lws_context * context,int timeout_ms,int tsi)59 _lws_plat_service_tsi(struct lws_context *context, int timeout_ms, int tsi)
60 {
61 	struct lws_context_per_thread *pt;
62 	WSANETWORKEVENTS networkevents;
63 	struct lws_pollfd *pfd;
64 	lws_usec_t timeout_us;
65 	struct lws *wsi;
66 	unsigned int i;
67 	DWORD ev;
68 	int n;
69 	unsigned int eIdx;
70 	int interrupt_requested;
71 
72 	/* stay dead once we are dead */
73 	if (context == NULL || !context->vhost_list)
74 		return 1;
75 
76 	pt = &context->pt[tsi];
77 
78 	if (!pt->service_tid_detected) {
79 		struct lws _lws;
80 
81 		memset(&_lws, 0, sizeof(_lws));
82 		_lws.context = context;
83 
84 		pt->service_tid = context->vhost_list->
85 			protocols[0].callback(&_lws, LWS_CALLBACK_GET_THREAD_ID,
86 						  NULL, NULL, 0);
87 		pt->service_tid_detected = 1;
88 	}
89 
90 	if (timeout_ms < 0)
91 		timeout_ms = 0;
92 	else
93 		/* force a default timeout of 23 days */
94 		timeout_ms = 2000000000;
95 	timeout_us = ((lws_usec_t)timeout_ms) * LWS_US_PER_MS;
96 
97 	if (context->event_loop_ops->run_pt)
98 		context->event_loop_ops->run_pt(context, tsi);
99 
100 	for (i = 0; i < pt->fds_count; ++i) {
101 		pfd = &pt->fds[i];
102 
103 		if (!(pfd->events & LWS_POLLOUT))
104 			continue;
105 
106 		wsi = wsi_from_fd(context, pfd->fd);
107 		if (!wsi || wsi->listener)
108 			continue;
109 		if (wsi->sock_send_blocking)
110 			continue;
111 		pfd->revents = LWS_POLLOUT;
112 		n = lws_service_fd(context, pfd);
113 		if (n < 0)
114 			return -1;
115 
116 		/*
117 		 * Force WSAWaitForMultipleEvents() to check events
118 		 * and then return immediately.
119 		 */
120 		timeout_us = 0;
121 
122 		/* if something closed, retry this slot */
123 		if (n)
124 			i--;
125 	}
126 
127 	/*
128 	 * is there anybody with pending stuff that needs service forcing?
129 	 */
130 	if (!lws_service_adjust_timeout(context, 1, tsi))
131 		_lws_plat_service_forced_tsi(context, tsi);
132 
133 	/*
134 	 * service pending callbakcs and get maximum wait time
135 	 */
136 	{
137 		lws_usec_t us;
138 
139 		lws_pt_lock(pt, __func__);
140 		/* don't stay in poll wait longer than next hr timeout */
141 		us = __lws_sul_service_ripe(&pt->pt_sul_owner, lws_now_usecs());
142 		if (us && us < timeout_us)
143 			timeout_us = us;
144 
145 		lws_pt_unlock(pt);
146 	}
147 
148 	for (n = 0; n < (int)pt->fds_count; n++)
149 		WSAEventSelect(pt->fds[n].fd, pt->events,
150 		       FD_READ | (!!(pt->fds[n].events & LWS_POLLOUT) * FD_WRITE) |
151 		       FD_OOB | FD_ACCEPT |
152 		       FD_CONNECT | FD_CLOSE | FD_QOS |
153 		       FD_ROUTING_INTERFACE_CHANGE |
154 		       FD_ADDRESS_LIST_CHANGE);
155 
156 	ev = WSAWaitForMultipleEvents(1, &pt->events, FALSE,
157 				      (DWORD)(timeout_us / LWS_US_PER_MS), FALSE);
158 	if (ev == WSA_WAIT_EVENT_0) {
159 		EnterCriticalSection(&pt->interrupt_lock);
160 		interrupt_requested = pt->interrupt_requested;
161 		pt->interrupt_requested = 0;
162 		LeaveCriticalSection(&pt->interrupt_lock);
163 		if (interrupt_requested) {
164 			lws_broadcast(pt, LWS_CALLBACK_EVENT_WAIT_CANCELLED,
165 				      NULL, 0);
166 			return 0;
167 		}
168 
169 #if defined(LWS_WITH_TLS)
170 		if (pt->context->tls_ops &&
171 		    pt->context->tls_ops->fake_POLLIN_for_buffered)
172 			pt->context->tls_ops->fake_POLLIN_for_buffered(pt);
173 #endif
174 
175 		for (eIdx = 0; eIdx < pt->fds_count; ++eIdx) {
176 			unsigned int err;
177 
178 			if (WSAEnumNetworkEvents(pt->fds[eIdx].fd, pt->events,
179 					&networkevents) == SOCKET_ERROR) {
180 				lwsl_err("WSAEnumNetworkEvents() failed "
181 					 "with error %d\n", LWS_ERRNO);
182 				return -1;
183 			}
184 
185 			if (!networkevents.lNetworkEvents)
186 				networkevents.lNetworkEvents = LWS_POLLOUT;
187 
188 			pfd = &pt->fds[eIdx];
189 			pfd->revents = (short)networkevents.lNetworkEvents;
190 
191 			err = networkevents.iErrorCode[FD_CONNECT_BIT];
192 
193 			if ((networkevents.lNetworkEvents & FD_CONNECT) &&
194 			     err && err != LWS_EALREADY &&
195 			     err != LWS_EINPROGRESS && err != LWS_EWOULDBLOCK &&
196 			     err != WSAEINVAL) {
197 				lwsl_debug("Unable to connect errno=%d\n", err);
198 				pfd->revents |= LWS_POLLHUP;
199 			}
200 
201 			if (pfd->revents & LWS_POLLOUT) {
202 				wsi = wsi_from_fd(context, pfd->fd);
203 				if (wsi)
204 					wsi->sock_send_blocking = 0;
205 			}
206 			 /* if something closed, retry this slot */
207 			if (pfd->revents & LWS_POLLHUP)
208 				--eIdx;
209 
210 			if (pfd->revents) {
211 				recv(pfd->fd, NULL, 0, 0);
212 				lws_service_fd_tsi(context, pfd, tsi);
213 			}
214 		}
215 
216 		return 0;
217 	}
218 
219 	// if (ev == WSA_WAIT_TIMEOUT) { }
220 	// if (ev == WSA_WAIT_FAILED)
221 		// return 0;
222 
223 	return 0;
224 }
225 
226 int
lws_plat_service(struct lws_context * context,int timeout_ms)227 lws_plat_service(struct lws_context *context, int timeout_ms)
228 {
229 	return _lws_plat_service_tsi(context, timeout_ms, 0);
230 }
231