xref: /aosp_15_r20/external/libwebsockets/lib/plat/windows/windows-service.c (revision 1c60b9aca93fdbc9b5f19b2d2194c91294b22281)
1 /*
2  * libwebsockets - small server side websockets and web server implementation
3  *
4  * Copyright (C) 2010 - 2021 Andy Green <[email protected]>
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, r;
36 
37 	r = 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 r;
55 }
56 
57 extern void lws_client_conn_wait_timeout(lws_sorted_usec_list_t *sul);
58 
59 int
_lws_plat_service_tsi(struct lws_context * context,int timeout_ms,int tsi)60 _lws_plat_service_tsi(struct lws_context *context, int timeout_ms, int tsi)
61 {
62 	struct lws_context_per_thread *pt;
63 	struct lws_pollfd *pfd;
64 	lws_usec_t timeout_us;
65 	struct lws *wsi;
66 	unsigned int i;
67 	int n;
68 
69 	/* stay dead once we are dead */
70 	if (context == NULL)
71 		return 1;
72 
73 	pt = &context->pt[tsi];
74 
75 	if (!pt->service_tid_detected && context->vhost_list) {
76 		lws_fakewsi_def_plwsa(pt);
77 
78 		lws_fakewsi_prep_plwsa_ctx(context);
79 
80 		pt->service_tid = context->vhost_list->
81 			protocols[0].callback((struct lws *)plwsa,
82 					LWS_CALLBACK_GET_THREAD_ID,
83 						  NULL, NULL, 0);
84 		pt->service_tid_detected = 1;
85 	}
86 
87 	if (timeout_ms < 0)
88 		timeout_ms = 0;
89 	else
90 		/* force a default timeout of 23 days */
91 		timeout_ms = 2000000000;
92 	timeout_us = ((lws_usec_t)timeout_ms) * LWS_US_PER_MS;
93 
94 	if (context->event_loop_ops->run_pt)
95 		context->event_loop_ops->run_pt(context, tsi);
96 
97 	for (i = 0; i < pt->fds_count; ++i) {
98 		pfd = &pt->fds[i];
99 
100 		if (!(pfd->events & LWS_POLLOUT))
101 			continue;
102 
103 		wsi = wsi_from_fd(context, pfd->fd);
104 		if (!wsi || wsi->listener)
105 			continue;
106 		if (wsi->sock_send_blocking)
107 			continue;
108 		pfd->revents = LWS_POLLOUT;
109 		n = lws_service_fd(context, pfd);
110 		if (n < 0)
111 			return -1;
112 
113 		/*
114 		 * Force WSAWaitForMultipleEvents() to check events
115 		 * and then return immediately.
116 		 */
117 		timeout_us = 0;
118 
119 		/* if something closed, retry this slot */
120 		if (n)
121 			i--;
122 	}
123 
124 	/*
125 	 * service pending callbacks and get maximum wait time
126 	 */
127 	{
128 		lws_usec_t us;
129 
130 		lws_pt_lock(pt, __func__);
131 		/* don't stay in poll wait longer than next hr timeout */
132 		us = __lws_sul_service_ripe(pt->pt_sul_owner,
133 					    LWS_COUNT_PT_SUL_OWNERS,
134 					    lws_now_usecs());
135 		if (us && us < timeout_us)
136 			/*
137 			 * If something wants zero wait, that's OK, but if the next sul
138 			 * coming ripe is an interval less than our wait resolution,
139 			 * bump it to be the wait resolution.
140 			 */
141 			timeout_us = us < context->us_wait_resolution ?
142 					context->us_wait_resolution : us;
143 
144 		lws_pt_unlock(pt);
145 	}
146 
147 	if (_lws_plat_service_forced_tsi(context, tsi))
148 		timeout_us = 0;
149 
150 	/*
151 	 * is there anybody with pending stuff that needs service forcing?
152 	 */
153 
154 	if (!lws_service_adjust_timeout(context, 1, tsi))
155 		timeout_us = 0;
156 
157 //	lwsl_notice("%s: in %dms, count %d\n", __func__, (int)(timeout_us / 1000), pt->fds_count);
158 //	for (n = 0; n < (int)pt->fds_count; n++)
159 //		lwsl_notice("%s: fd %d ev 0x%x POLLIN %d, POLLOUT %d\n", __func__, (int)pt->fds[n].fd, (int)pt->fds[n].events, POLLIN, POLLOUT);
160 	int d = WSAPoll((WSAPOLLFD *)&pt->fds[0], pt->fds_count, (int)(timeout_us / LWS_US_PER_MS));
161 	if (d < 0) {
162 		lwsl_err("%s: WSAPoll failed: count %d, err %d: %d\n", __func__, pt->fds_count, d, WSAGetLastError());
163 		return 0;
164 	}
165 //	lwsl_notice("%s: out\n", __func__);
166 
167 #if defined(LWS_WITH_TLS)
168 	if (pt->context->tls_ops &&
169 	    pt->context->tls_ops->fake_POLLIN_for_buffered)
170 		pt->context->tls_ops->fake_POLLIN_for_buffered(pt);
171 #endif
172 
173 	for (n = 0; n < (int)pt->fds_count; n++)
174 		if (pt->fds[n].fd != LWS_SOCK_INVALID && pt->fds[n].revents) {
175 //			lwsl_notice("%s: idx %d, revents 0x%x\n", __func__, n, pt->fds[n].revents);
176 			lws_service_fd_tsi(context, &pt->fds[n], tsi);
177 		}
178 
179 	return 0;
180 }
181 
182 int
lws_plat_service(struct lws_context * context,int timeout_ms)183 lws_plat_service(struct lws_context *context, int timeout_ms)
184 {
185 	return _lws_plat_service_tsi(context, timeout_ms, 0);
186 }
187