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