1d4afb5ceSopenharmony_ci/*
2d4afb5ceSopenharmony_ci * libwebsockets - small server side websockets and web server implementation
3d4afb5ceSopenharmony_ci *
4d4afb5ceSopenharmony_ci * Copyright (C) 2010 - 2021 Andy Green <andy@warmcat.com>
5d4afb5ceSopenharmony_ci *
6d4afb5ceSopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a copy
7d4afb5ceSopenharmony_ci * of this software and associated documentation files (the "Software"), to
8d4afb5ceSopenharmony_ci * deal in the Software without restriction, including without limitation the
9d4afb5ceSopenharmony_ci * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10d4afb5ceSopenharmony_ci * sell copies of the Software, and to permit persons to whom the Software is
11d4afb5ceSopenharmony_ci * furnished to do so, subject to the following conditions:
12d4afb5ceSopenharmony_ci *
13d4afb5ceSopenharmony_ci * The above copyright notice and this permission notice shall be included in
14d4afb5ceSopenharmony_ci * all copies or substantial portions of the Software.
15d4afb5ceSopenharmony_ci *
16d4afb5ceSopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17d4afb5ceSopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18d4afb5ceSopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19d4afb5ceSopenharmony_ci * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20d4afb5ceSopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21d4afb5ceSopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22d4afb5ceSopenharmony_ci * IN THE SOFTWARE.
23d4afb5ceSopenharmony_ci */
24d4afb5ceSopenharmony_ci
25d4afb5ceSopenharmony_ci#include "private-lib-core.h"
26d4afb5ceSopenharmony_ci
27d4afb5ceSopenharmony_cistruct lws *
28d4afb5ceSopenharmony_cilws_client_connect_4_established(struct lws *wsi, struct lws *wsi_piggyback,
29d4afb5ceSopenharmony_ci				 ssize_t plen)
30d4afb5ceSopenharmony_ci{
31d4afb5ceSopenharmony_ci#if defined(LWS_CLIENT_HTTP_PROXYING)
32d4afb5ceSopenharmony_ci	struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi];
33d4afb5ceSopenharmony_ci#endif
34d4afb5ceSopenharmony_ci	const char *meth;
35d4afb5ceSopenharmony_ci	struct lws_pollfd pfd;
36d4afb5ceSopenharmony_ci	const char *cce = "";
37d4afb5ceSopenharmony_ci	int n, m, rawish = 0;
38d4afb5ceSopenharmony_ci
39d4afb5ceSopenharmony_ci	meth = lws_wsi_client_stash_item(wsi, CIS_METHOD,
40d4afb5ceSopenharmony_ci					 _WSI_TOKEN_CLIENT_METHOD);
41d4afb5ceSopenharmony_ci
42d4afb5ceSopenharmony_ci	if (meth && (!strcmp(meth, "RAW")
43d4afb5ceSopenharmony_ci#if defined(LWS_ROLE_MQTT)
44d4afb5ceSopenharmony_ci		     || !strcmp(meth, "MQTT")
45d4afb5ceSopenharmony_ci#endif
46d4afb5ceSopenharmony_ci	))
47d4afb5ceSopenharmony_ci		rawish = 1;
48d4afb5ceSopenharmony_ci
49d4afb5ceSopenharmony_ci	if (wsi_piggyback)
50d4afb5ceSopenharmony_ci		goto send_hs;
51d4afb5ceSopenharmony_ci
52d4afb5ceSopenharmony_ci#if defined(LWS_CLIENT_HTTP_PROXYING)
53d4afb5ceSopenharmony_ci#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
54d4afb5ceSopenharmony_ci	/* we are connected to server, or proxy */
55d4afb5ceSopenharmony_ci
56d4afb5ceSopenharmony_ci	/* http proxy */
57d4afb5ceSopenharmony_ci	if (wsi->a.vhost->http.http_proxy_port) {
58d4afb5ceSopenharmony_ci		const char *cpa;
59d4afb5ceSopenharmony_ci
60d4afb5ceSopenharmony_ci		cpa = lws_wsi_client_stash_item(wsi, CIS_ADDRESS,
61d4afb5ceSopenharmony_ci						_WSI_TOKEN_CLIENT_PEER_ADDRESS);
62d4afb5ceSopenharmony_ci		if (!cpa)
63d4afb5ceSopenharmony_ci			goto failed;
64d4afb5ceSopenharmony_ci
65d4afb5ceSopenharmony_ci		lwsl_wsi_info(wsi, "going via proxy");
66d4afb5ceSopenharmony_ci
67d4afb5ceSopenharmony_ci		plen = lws_snprintf((char *)pt->serv_buf, 256,
68d4afb5ceSopenharmony_ci			"CONNECT %s:%u HTTP/1.1\x0d\x0a"
69d4afb5ceSopenharmony_ci			"Host: %s:%u\x0d\x0a"
70d4afb5ceSopenharmony_ci			"User-agent: lws\x0d\x0a", cpa, wsi->ocport,
71d4afb5ceSopenharmony_ci						   cpa, wsi->ocport);
72d4afb5ceSopenharmony_ci
73d4afb5ceSopenharmony_ci#if defined(LWS_WITH_HTTP_BASIC_AUTH)
74d4afb5ceSopenharmony_ci		if (wsi->a.vhost->proxy_basic_auth_token[0])
75d4afb5ceSopenharmony_ci			plen += lws_snprintf((char *)pt->serv_buf + plen, 256,
76d4afb5ceSopenharmony_ci					"Proxy-authorization: basic %s\x0d\x0a",
77d4afb5ceSopenharmony_ci					wsi->a.vhost->proxy_basic_auth_token);
78d4afb5ceSopenharmony_ci#endif
79d4afb5ceSopenharmony_ci
80d4afb5ceSopenharmony_ci		plen += lws_snprintf((char *)pt->serv_buf + plen, 5,
81d4afb5ceSopenharmony_ci					"\x0d\x0a");
82d4afb5ceSopenharmony_ci
83d4afb5ceSopenharmony_ci		/* lwsl_hexdump_notice(pt->serv_buf, plen); */
84d4afb5ceSopenharmony_ci
85d4afb5ceSopenharmony_ci		/*
86d4afb5ceSopenharmony_ci		 * OK from now on we talk via the proxy, so connect to that
87d4afb5ceSopenharmony_ci		 */
88d4afb5ceSopenharmony_ci		if (wsi->stash)
89d4afb5ceSopenharmony_ci			wsi->stash->cis[CIS_ADDRESS] =
90d4afb5ceSopenharmony_ci				wsi->a.vhost->http.http_proxy_address;
91d4afb5ceSopenharmony_ci		else
92d4afb5ceSopenharmony_ci			if (lws_hdr_simple_create(wsi,
93d4afb5ceSopenharmony_ci					_WSI_TOKEN_CLIENT_PEER_ADDRESS,
94d4afb5ceSopenharmony_ci					wsi->a.vhost->http.http_proxy_address))
95d4afb5ceSopenharmony_ci			goto failed;
96d4afb5ceSopenharmony_ci		wsi->c_port = (uint16_t)wsi->a.vhost->http.http_proxy_port;
97d4afb5ceSopenharmony_ci
98d4afb5ceSopenharmony_ci		n = (int)send(wsi->desc.sockfd, (char *)pt->serv_buf,
99d4afb5ceSopenharmony_ci			      (unsigned int)plen,
100d4afb5ceSopenharmony_ci			 MSG_NOSIGNAL);
101d4afb5ceSopenharmony_ci		if (n < 0) {
102d4afb5ceSopenharmony_ci			lwsl_wsi_debug(wsi, "ERROR writing to proxy socket");
103d4afb5ceSopenharmony_ci			cce = "proxy write failed";
104d4afb5ceSopenharmony_ci			goto failed;
105d4afb5ceSopenharmony_ci		}
106d4afb5ceSopenharmony_ci
107d4afb5ceSopenharmony_ci		lws_set_timeout(wsi, PENDING_TIMEOUT_AWAITING_PROXY_RESPONSE,
108d4afb5ceSopenharmony_ci				(int)wsi->a.context->timeout_secs);
109d4afb5ceSopenharmony_ci
110d4afb5ceSopenharmony_ci		wsi->conn_port = wsi->c_port;
111d4afb5ceSopenharmony_ci		lwsi_set_state(wsi, LRS_WAITING_PROXY_REPLY);
112d4afb5ceSopenharmony_ci
113d4afb5ceSopenharmony_ci		return wsi;
114d4afb5ceSopenharmony_ci	}
115d4afb5ceSopenharmony_ci#endif
116d4afb5ceSopenharmony_ci#endif
117d4afb5ceSopenharmony_ci
118d4afb5ceSopenharmony_ci	/* coverity */
119d4afb5ceSopenharmony_ci	if (!wsi->a.protocol)
120d4afb5ceSopenharmony_ci		return NULL;
121d4afb5ceSopenharmony_ci
122d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SOCKS5)
123d4afb5ceSopenharmony_ci	if (lwsi_state(wsi) != 	LRS_ESTABLISHED)
124d4afb5ceSopenharmony_ci		switch (lws_socks5c_greet(wsi, &cce)) {
125d4afb5ceSopenharmony_ci		case -1:
126d4afb5ceSopenharmony_ci			goto failed;
127d4afb5ceSopenharmony_ci		case 1:
128d4afb5ceSopenharmony_ci			return wsi;
129d4afb5ceSopenharmony_ci		default:
130d4afb5ceSopenharmony_ci			break;
131d4afb5ceSopenharmony_ci		}
132d4afb5ceSopenharmony_ci#endif
133d4afb5ceSopenharmony_ci
134d4afb5ceSopenharmony_ci#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
135d4afb5ceSopenharmony_cisend_hs:
136d4afb5ceSopenharmony_ci
137d4afb5ceSopenharmony_ci	if (wsi_piggyback &&
138d4afb5ceSopenharmony_ci	    !lws_dll2_is_detached(&wsi->dll2_cli_txn_queue)) {
139d4afb5ceSopenharmony_ci		/*
140d4afb5ceSopenharmony_ci		 * We are pipelining on an already-established connection...
141d4afb5ceSopenharmony_ci		 * we can skip tls establishment.
142d4afb5ceSopenharmony_ci		 *
143d4afb5ceSopenharmony_ci		 * Set these queued guys to a state where they won't actually
144d4afb5ceSopenharmony_ci		 * send their headers until we decide later.
145d4afb5ceSopenharmony_ci		 */
146d4afb5ceSopenharmony_ci
147d4afb5ceSopenharmony_ci		lwsi_set_state(wsi, LRS_H2_WAITING_TO_SEND_HEADERS);
148d4afb5ceSopenharmony_ci
149d4afb5ceSopenharmony_ci		/*
150d4afb5ceSopenharmony_ci		 * we can't send our headers directly, because they have to
151d4afb5ceSopenharmony_ci		 * be sent when the parent is writeable.  The parent will check
152d4afb5ceSopenharmony_ci		 * for anybody on his client transaction queue that is in
153d4afb5ceSopenharmony_ci		 * LRS_H1C_ISSUE_HANDSHAKE2, and let them write.
154d4afb5ceSopenharmony_ci		 *
155d4afb5ceSopenharmony_ci		 * If we are trying to do this too early, before the network
156d4afb5ceSopenharmony_ci		 * connection has written his own headers, then it will just
157d4afb5ceSopenharmony_ci		 * wait in the queue until it's possible to send them.
158d4afb5ceSopenharmony_ci		 */
159d4afb5ceSopenharmony_ci		lws_callback_on_writable(wsi_piggyback);
160d4afb5ceSopenharmony_ci
161d4afb5ceSopenharmony_ci		lwsl_wsi_info(wsi, "waiting to send hdrs (par state 0x%x)",
162d4afb5ceSopenharmony_ci			      lwsi_state(wsi_piggyback));
163d4afb5ceSopenharmony_ci	} else {
164d4afb5ceSopenharmony_ci		lwsl_wsi_info(wsi, "%s %s client created own conn "
165d4afb5ceSopenharmony_ci			  "(raw %d) vh %s st 0x%x",
166d4afb5ceSopenharmony_ci			  wsi->role_ops->name, wsi->a.protocol->name, rawish,
167d4afb5ceSopenharmony_ci			  wsi->a.vhost->name, lwsi_state(wsi));
168d4afb5ceSopenharmony_ci
169d4afb5ceSopenharmony_ci		/* we are making our own connection */
170d4afb5ceSopenharmony_ci
171d4afb5ceSopenharmony_ci		if (!rawish
172d4afb5ceSopenharmony_ci#if defined(LWS_WITH_TLS)
173d4afb5ceSopenharmony_ci		    // && (!(wsi->tls.use_ssl & LCCSCF_USE_SSL) || wsi->tls.ssl)
174d4afb5ceSopenharmony_ci#endif
175d4afb5ceSopenharmony_ci		    ) {
176d4afb5ceSopenharmony_ci
177d4afb5ceSopenharmony_ci			if (lwsi_state(wsi) != LRS_H1C_ISSUE_HANDSHAKE2)
178d4afb5ceSopenharmony_ci				lwsi_set_state(wsi, LRS_H1C_ISSUE_HANDSHAKE);
179d4afb5ceSopenharmony_ci		} else {
180d4afb5ceSopenharmony_ci			/* for a method = "RAW" connection, this makes us
181d4afb5ceSopenharmony_ci			 * established */
182d4afb5ceSopenharmony_ci
183d4afb5ceSopenharmony_ci#if defined(LWS_WITH_TLS)// && !defined(LWS_WITH_MBEDTLS)
184d4afb5ceSopenharmony_ci
185d4afb5ceSopenharmony_ci			/* we have connected if we got here */
186d4afb5ceSopenharmony_ci
187d4afb5ceSopenharmony_ci			if (lwsi_state(wsi) == LRS_WAITING_CONNECT &&
188d4afb5ceSopenharmony_ci			    (wsi->tls.use_ssl & LCCSCF_USE_SSL)) {
189d4afb5ceSopenharmony_ci				int result;
190d4afb5ceSopenharmony_ci
191d4afb5ceSopenharmony_ci				//lwsi_set_state(wsi, LRS_WAITING_SSL);
192d4afb5ceSopenharmony_ci
193d4afb5ceSopenharmony_ci				/*
194d4afb5ceSopenharmony_ci				 * We can retry this... just cook the SSL BIO
195d4afb5ceSopenharmony_ci				 * the first time
196d4afb5ceSopenharmony_ci				 */
197d4afb5ceSopenharmony_ci
198d4afb5ceSopenharmony_ci				result = lws_client_create_tls(wsi, &cce, 1);
199d4afb5ceSopenharmony_ci				switch (result) {
200d4afb5ceSopenharmony_ci				case CCTLS_RETURN_DONE:
201d4afb5ceSopenharmony_ci					break;
202d4afb5ceSopenharmony_ci				case CCTLS_RETURN_RETRY:
203d4afb5ceSopenharmony_ci					lwsl_wsi_debug(wsi, "create_tls RETRY");
204d4afb5ceSopenharmony_ci					return wsi;
205d4afb5ceSopenharmony_ci				default:
206d4afb5ceSopenharmony_ci					lwsl_wsi_debug(wsi, "create_tls FAIL");
207d4afb5ceSopenharmony_ci					goto failed;
208d4afb5ceSopenharmony_ci				}
209d4afb5ceSopenharmony_ci
210d4afb5ceSopenharmony_ci				/*
211d4afb5ceSopenharmony_ci				 * We succeeded to negotiate a new client tls
212d4afb5ceSopenharmony_ci				 * tunnel.  If it's h2 alpn, we have arranged
213d4afb5ceSopenharmony_ci				 * to send the h2 prefix and set our state to
214d4afb5ceSopenharmony_ci				 * LRS_H2_WAITING_TO_SEND_HEADERS already.
215d4afb5ceSopenharmony_ci				 */
216d4afb5ceSopenharmony_ci
217d4afb5ceSopenharmony_ci				lwsl_wsi_notice(wsi, "tls established st 0x%x, "
218d4afb5ceSopenharmony_ci					    "client_h2_alpn %d", lwsi_state(wsi),
219d4afb5ceSopenharmony_ci					    wsi->client_h2_alpn);
220d4afb5ceSopenharmony_ci
221d4afb5ceSopenharmony_ci				if (lwsi_state(wsi) !=
222d4afb5ceSopenharmony_ci						LRS_H2_WAITING_TO_SEND_HEADERS)
223d4afb5ceSopenharmony_ci					lwsi_set_state(wsi,
224d4afb5ceSopenharmony_ci						LRS_H1C_ISSUE_HANDSHAKE2);
225d4afb5ceSopenharmony_ci				lws_set_timeout(wsi,
226d4afb5ceSopenharmony_ci					PENDING_TIMEOUT_AWAITING_CLIENT_HS_SEND,
227d4afb5ceSopenharmony_ci					(int)wsi->a.context->timeout_secs);
228d4afb5ceSopenharmony_ci#if 0
229d4afb5ceSopenharmony_ci				/* ensure pollin enabled */
230d4afb5ceSopenharmony_ci				if (lws_change_pollfd(wsi, 0, LWS_POLLIN))
231d4afb5ceSopenharmony_ci					lwsl_wsi_notice(wsi,
232d4afb5ceSopenharmony_ci							"unable to set POLLIN");
233d4afb5ceSopenharmony_ci#endif
234d4afb5ceSopenharmony_ci
235d4afb5ceSopenharmony_ci				goto provoke_service;
236d4afb5ceSopenharmony_ci			}
237d4afb5ceSopenharmony_ci#endif
238d4afb5ceSopenharmony_ci
239d4afb5ceSopenharmony_ci			/* clear his established timeout */
240d4afb5ceSopenharmony_ci			lws_set_timeout(wsi, NO_PENDING_TIMEOUT, 0);
241d4afb5ceSopenharmony_ci
242d4afb5ceSopenharmony_ci			m = wsi->role_ops->adoption_cb[0];
243d4afb5ceSopenharmony_ci			if (m) {
244d4afb5ceSopenharmony_ci				n = user_callback_handle_rxflow(
245d4afb5ceSopenharmony_ci						wsi->a.protocol->callback, wsi,
246d4afb5ceSopenharmony_ci						(enum lws_callback_reasons)m,
247d4afb5ceSopenharmony_ci						wsi->user_space, NULL, 0);
248d4afb5ceSopenharmony_ci				if (n < 0) {
249d4afb5ceSopenharmony_ci					lwsl_wsi_info(wsi, "RAW_PROXY_CLI_ADOPT err");
250d4afb5ceSopenharmony_ci					goto failed;
251d4afb5ceSopenharmony_ci				}
252d4afb5ceSopenharmony_ci			}
253d4afb5ceSopenharmony_ci
254d4afb5ceSopenharmony_ci			/* service.c pollout processing wants this */
255d4afb5ceSopenharmony_ci			wsi->hdr_parsing_completed = 1;
256d4afb5ceSopenharmony_ci#if defined(LWS_ROLE_MQTT)
257d4afb5ceSopenharmony_ci			if (meth && !strcmp(meth, "MQTT")) {
258d4afb5ceSopenharmony_ci#if defined(LWS_WITH_TLS)
259d4afb5ceSopenharmony_ci				if (wsi->tls.use_ssl & LCCSCF_USE_SSL) {
260d4afb5ceSopenharmony_ci					lwsi_set_state(wsi, LRS_WAITING_SSL);
261d4afb5ceSopenharmony_ci					return wsi;
262d4afb5ceSopenharmony_ci				}
263d4afb5ceSopenharmony_ci#endif
264d4afb5ceSopenharmony_ci				lwsl_wsi_info(wsi, "settings LRS_MQTTC_IDLE");
265d4afb5ceSopenharmony_ci				lwsi_set_state(wsi, LRS_MQTTC_IDLE);
266d4afb5ceSopenharmony_ci
267d4afb5ceSopenharmony_ci				/*
268d4afb5ceSopenharmony_ci				 * provoke service to issue the CONNECT
269d4afb5ceSopenharmony_ci				 * directly.
270d4afb5ceSopenharmony_ci				 */
271d4afb5ceSopenharmony_ci				lws_set_timeout(wsi,
272d4afb5ceSopenharmony_ci					PENDING_TIMEOUT_SENT_CLIENT_HANDSHAKE,
273d4afb5ceSopenharmony_ci						(int)wsi->a.context->timeout_secs);
274d4afb5ceSopenharmony_ci
275d4afb5ceSopenharmony_ci				assert(lws_socket_is_valid(wsi->desc.sockfd));
276d4afb5ceSopenharmony_ci
277d4afb5ceSopenharmony_ci				pfd.fd = wsi->desc.sockfd;
278d4afb5ceSopenharmony_ci				pfd.events = LWS_POLLIN;
279d4afb5ceSopenharmony_ci				pfd.revents = LWS_POLLOUT;
280d4afb5ceSopenharmony_ci
281d4afb5ceSopenharmony_ci				lwsl_wsi_info(wsi, "going to service fd");
282d4afb5ceSopenharmony_ci				n = lws_service_fd(wsi->a.context, &pfd);
283d4afb5ceSopenharmony_ci				if (n < 0) {
284d4afb5ceSopenharmony_ci					cce = "first service failed";
285d4afb5ceSopenharmony_ci					goto failed;
286d4afb5ceSopenharmony_ci				}
287d4afb5ceSopenharmony_ci				if (n)
288d4afb5ceSopenharmony_ci					/* returns 1 on fail after close wsi */
289d4afb5ceSopenharmony_ci					return NULL;
290d4afb5ceSopenharmony_ci				return wsi;
291d4afb5ceSopenharmony_ci			}
292d4afb5ceSopenharmony_ci#endif
293d4afb5ceSopenharmony_ci			lwsl_wsi_info(wsi, "setting ESTABLISHED");
294d4afb5ceSopenharmony_ci			lwsi_set_state(wsi, LRS_ESTABLISHED);
295d4afb5ceSopenharmony_ci
296d4afb5ceSopenharmony_ci			return wsi;
297d4afb5ceSopenharmony_ci		}
298d4afb5ceSopenharmony_ci
299d4afb5ceSopenharmony_ci		/*
300d4afb5ceSopenharmony_ci		 * provoke service to issue the handshake directly.
301d4afb5ceSopenharmony_ci		 *
302d4afb5ceSopenharmony_ci		 * we need to do it this way because in the proxy case, this is
303d4afb5ceSopenharmony_ci		 * the next state and executed only if and when we get a good
304d4afb5ceSopenharmony_ci		 * proxy response inside the state machine... but notice in
305d4afb5ceSopenharmony_ci		 * SSL case this may not have sent anything yet with 0 return,
306d4afb5ceSopenharmony_ci		 * and won't until many retries from main loop.  To stop that
307d4afb5ceSopenharmony_ci		 * becoming endless, cover with a timeout.
308d4afb5ceSopenharmony_ci		 */
309d4afb5ceSopenharmony_ci#if defined(LWS_WITH_TLS) //&& !defined(LWS_WITH_MBEDTLS)
310d4afb5ceSopenharmony_ciprovoke_service:
311d4afb5ceSopenharmony_ci#endif
312d4afb5ceSopenharmony_ci		lws_set_timeout(wsi, PENDING_TIMEOUT_SENT_CLIENT_HANDSHAKE,
313d4afb5ceSopenharmony_ci				(int)wsi->a.context->timeout_secs);
314d4afb5ceSopenharmony_ci
315d4afb5ceSopenharmony_ci		assert(lws_socket_is_valid(wsi->desc.sockfd));
316d4afb5ceSopenharmony_ci
317d4afb5ceSopenharmony_ci		pfd.fd = wsi->desc.sockfd;
318d4afb5ceSopenharmony_ci		pfd.events = LWS_POLLIN;
319d4afb5ceSopenharmony_ci		pfd.revents = LWS_POLLIN;
320d4afb5ceSopenharmony_ci
321d4afb5ceSopenharmony_ci		n = lws_service_fd(wsi->a.context, &pfd);
322d4afb5ceSopenharmony_ci		if (n < 0) {
323d4afb5ceSopenharmony_ci			cce = "first service failed";
324d4afb5ceSopenharmony_ci			goto failed;
325d4afb5ceSopenharmony_ci		}
326d4afb5ceSopenharmony_ci		if (n) /* returns 1 on failure after closing wsi */
327d4afb5ceSopenharmony_ci			return NULL;
328d4afb5ceSopenharmony_ci	}
329d4afb5ceSopenharmony_ci#endif
330d4afb5ceSopenharmony_ci	return wsi;
331d4afb5ceSopenharmony_ci
332d4afb5ceSopenharmony_cifailed:
333d4afb5ceSopenharmony_ci	lws_inform_client_conn_fail(wsi, (void *)cce, strlen(cce));
334d4afb5ceSopenharmony_ci
335d4afb5ceSopenharmony_ci	lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS, "client_connect4");
336d4afb5ceSopenharmony_ci
337d4afb5ceSopenharmony_ci	return NULL;
338d4afb5ceSopenharmony_ci}
339