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