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 #include <libwebsockets.h>
26 #include "private-lib-core.h"
27
28 struct lws *
lws_client_connect_via_info(const struct lws_client_connect_info * i)29 lws_client_connect_via_info(const struct lws_client_connect_info *i)
30 {
31 const char *local = i->protocol;
32 struct lws *wsi, *safe = NULL;
33 const struct lws_protocols *p;
34 const char *cisin[CIS_COUNT];
35 int tid = 0, n, m;
36 size_t size;
37 char *pc;
38
39 if (i->context->requested_kill)
40 return NULL;
41
42 if (!i->context->protocol_init_done)
43 if (lws_protocol_init(i->context))
44 return NULL;
45
46 /*
47 * If we have .local_protocol_name, use it to select the local protocol
48 * handler to bind to. Otherwise use .protocol if http[s].
49 */
50 if (i->local_protocol_name)
51 local = i->local_protocol_name;
52
53 lws_stats_bump(&i->context->pt[tid], LWSSTATS_C_CONNS_CLIENT, 1);
54
55 /* PHASE 1: create a bare wsi */
56
57 wsi = lws_zalloc(sizeof(struct lws), "client wsi");
58 if (wsi == NULL)
59 goto bail;
60
61 /*
62 * Until we exit, we can report connection failure directly to the
63 * caller without needing to call through to protocol CONNECTION_ERROR.
64 */
65 wsi->client_suppress_CONNECTION_ERROR = 1;
66
67 wsi->context = i->context;
68 wsi->desc.sockfd = LWS_SOCK_INVALID;
69 wsi->seq = i->seq;
70 wsi->flags = i->ssl_connection;
71 if (i->retry_and_idle_policy)
72 wsi->retry_policy = i->retry_and_idle_policy;
73 else
74 wsi->retry_policy = &i->context->default_retry;
75
76 #if defined(LWS_WITH_DETAILED_LATENCY)
77 if (i->context->detailed_latency_cb)
78 wsi->detlat.earliest_write_req_pre_write = lws_now_usecs();
79 #endif
80
81 wsi->vhost = NULL;
82 if (!i->vhost) {
83 struct lws_vhost *v = i->context->vhost_list;
84 if (v && !strcmp(v->name, "system"))
85 v = v->vhost_next;
86 lws_vhost_bind_wsi(v, wsi);
87 } else
88 lws_vhost_bind_wsi(i->vhost, wsi);
89
90 if (!wsi->vhost) {
91 lwsl_err("%s: No vhost in the context\n", __func__);
92
93 goto bail;
94 }
95
96 #if LWS_MAX_SMP > 1
97 tid = wsi->vhost->protocols[0].callback(wsi, LWS_CALLBACK_GET_THREAD_ID,
98 NULL, NULL, 0);
99 #endif
100
101 /*
102 * PHASE 2: if SMP, bind the client to whatever tsi the current thread
103 * represents
104 */
105
106 #if LWS_MAX_SMP > 1
107 lws_context_lock(i->context, "client find tsi");
108
109 for (n = 0; n < i->context->count_threads; n++)
110 if (i->context->pt[n].service_tid == tid) {
111 lwsl_info("%s: client binds to caller tsi %d\n",
112 __func__, n);
113 wsi->tsi = n;
114 #if defined(LWS_WITH_DETAILED_LATENCY)
115 wsi->detlat.tsi = n;
116 #endif
117 break;
118 }
119
120 /*
121 * this binding is sort of provisional, since when we try to insert
122 * into the pt fds, there may be no space and it will fail
123 */
124
125 lws_context_unlock(i->context);
126 #endif
127
128 /*
129 * PHASE 3: Choose an initial role for the wsi and do role-specific init
130 *
131 * Note the initial role may not reflect the final role, eg,
132 * we may want ws, but first we have to go through h1 to get that
133 */
134
135 if (lws_role_call_client_bind(wsi, i) < 0) {
136 lwsl_err("%s: unable to bind to role\n", __func__);
137
138 goto bail;
139 }
140 lwsl_info("%s: role binding to %s\n", __func__, wsi->role_ops->name);
141
142 /*
143 * PHASE 4: fill up the wsi with stuff from the connect_info as far as
144 * it can go. It's uncertain because not only is our connection
145 * going to complete asynchronously, we might have bound to h1 and not
146 * even be able to get ahold of an ah immediately.
147 */
148
149 wsi->user_space = NULL;
150 wsi->pending_timeout = NO_PENDING_TIMEOUT;
151 wsi->position_in_fds_table = LWS_NO_FDS_POS;
152 wsi->ocport = wsi->c_port = i->port;
153 wsi->sys_tls_client_cert = i->sys_tls_client_cert;
154
155 #if defined(LWS_ROLE_H2)
156 wsi->txc.manual_initial_tx_credit = (int32_t)i->manual_initial_tx_credit;
157 #endif
158
159 wsi->protocol = &wsi->vhost->protocols[0];
160 wsi->client_pipeline = !!(i->ssl_connection & LCCSCF_PIPELINE);
161 wsi->client_no_follow_redirect = !!(i->ssl_connection &
162 LCCSCF_HTTP_NO_FOLLOW_REDIRECT);
163
164 /*
165 * PHASE 5: handle external user_space now, generic alloc is done in
166 * role finalization
167 */
168
169 if (i->userdata) {
170 wsi->user_space_externally_allocated = 1;
171 wsi->user_space = i->userdata;
172 }
173
174 if (local) {
175 lwsl_info("%s: protocol binding to %s\n", __func__, local);
176 p = lws_vhost_name_to_protocol(wsi->vhost, local);
177 if (p)
178 lws_bind_protocol(wsi, p, __func__);
179 else
180 lwsl_err("%s: unknown protocol %s\n", __func__, local);
181
182 lwsl_info("%s: wsi %p: %s %s entry\n",
183 __func__, wsi, wsi->role_ops->name,
184 wsi->protocol ? wsi->protocol->name : "none");
185 }
186
187 /*
188 * PHASE 5: handle external user_space now, generic alloc is done in
189 * role finalization
190 */
191
192 if (!wsi->user_space && i->userdata) {
193 wsi->user_space_externally_allocated = 1;
194 wsi->user_space = i->userdata;
195 }
196
197 #if defined(LWS_WITH_TLS)
198 wsi->tls.use_ssl = i->ssl_connection;
199 #else
200 if (i->ssl_connection & LCCSCF_USE_SSL) {
201 lwsl_err("%s: lws not configured for tls\n", __func__);
202 goto bail;
203 }
204 #endif
205
206 /*
207 * PHASE 6: stash the things from connect_info that we can't process
208 * right now, eg, if http binding, without an ah. If h1 and no ah, we
209 * will go on the ah waiting list and process those things later (after
210 * the connect_info and maybe the things pointed to have gone out of
211 * scope)
212 *
213 * However these things are stashed in a generic way at this point,
214 * with no relationship to http or ah
215 */
216
217 cisin[CIS_ADDRESS] = i->address;
218 cisin[CIS_PATH] = i->path;
219 cisin[CIS_HOST] = i->host;
220 cisin[CIS_ORIGIN] = i->origin;
221 cisin[CIS_PROTOCOL] = i->protocol;
222 cisin[CIS_METHOD] = i->method;
223 cisin[CIS_IFACE] = i->iface;
224 cisin[CIS_ALPN] = i->alpn;
225
226 size = sizeof(*wsi->stash);
227
228 /*
229 * Let's overallocate the stash object with space for all the args
230 * in one hit.
231 */
232 for (n = 0; n < CIS_COUNT; n++)
233 if (cisin[n])
234 size += strlen(cisin[n]) + 1;
235
236 wsi->stash = lws_malloc(size, "client stash");
237 if (!wsi->stash) {
238 lwsl_err("%s: OOM\n", __func__);
239 goto bail1;
240 }
241 /* all the pointers default to NULL, but no need to zero the args */
242 memset(wsi->stash, 0, sizeof(*wsi->stash));
243
244 wsi->opaque_user_data = wsi->stash->opaque_user_data =
245 i->opaque_user_data;
246 pc = (char *)&wsi->stash[1];
247
248 for (n = 0; n < CIS_COUNT; n++)
249 if (cisin[n]) {
250 wsi->stash->cis[n] = pc;
251 m = (int)strlen(cisin[n]) + 1;
252 memcpy(pc, cisin[n], m);
253 pc += m;
254 }
255
256 /*
257 * at this point user callbacks like
258 * LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER will be interested to
259 * know the parent... eg for proxying we can grab extra headers from
260 * the parent's incoming ah and add them to the child client handshake
261 */
262
263 if (i->parent_wsi) {
264 lwsl_info("%s: created child %p of parent %p\n", __func__,
265 wsi, i->parent_wsi);
266 wsi->parent = i->parent_wsi;
267 safe = wsi->sibling_list = i->parent_wsi->child_list;
268 i->parent_wsi->child_list = wsi;
269 }
270
271 /*
272 * PHASE 7: Do any role-specific finalization processing. We can still
273 * see important info things via wsi->stash
274 */
275
276 if (wsi->role_ops->client_bind) {
277 int n = wsi->role_ops->client_bind(wsi, NULL);
278
279 if (n && i->parent_wsi) {
280 /* unpick from parent */
281
282 i->parent_wsi->child_list = safe;
283 }
284
285 if (n < 0)
286 /* we didn't survive, wsi is freed */
287 goto bail2;
288
289 if (n)
290 /* something else failed, wsi needs freeing */
291 goto bail;
292 }
293
294 /* let the caller's optional wsi storage have the wsi we created */
295
296 if (i->pwsi)
297 *i->pwsi = wsi;
298
299 /* PHASE 8: notify protocol with role-specific connected callback */
300
301 /* raw socket per se doesn't want this... raw socket proxy wants it... */
302
303 if (wsi->role_ops != &role_ops_raw_skt ||
304 (i->local_protocol_name &&
305 !strcmp(i->local_protocol_name, "raw-proxy"))) {
306 lwsl_debug("%s: wsi %p: adoption cb %d to %s %s\n", __func__,
307 wsi, wsi->role_ops->adoption_cb[0],
308 wsi->role_ops->name, wsi->protocol->name);
309
310 wsi->protocol->callback(wsi, wsi->role_ops->adoption_cb[0],
311 wsi->user_space, NULL, 0);
312 }
313
314 #if defined(LWS_WITH_HUBBUB)
315 if (i->uri_replace_to)
316 wsi->http.rw = lws_rewrite_create(wsi, html_parser_cb,
317 i->uri_replace_from,
318 i->uri_replace_to);
319 #endif
320
321 if (i->method && (!strcmp(i->method, "RAW") // ||
322 // !strcmp(i->method, "MQTT")
323 )) {
324
325 /*
326 * Not for MQTT here, since we don't know if we will
327 * pipeline it or not...
328 */
329
330 #if defined(LWS_WITH_TLS)
331
332 wsi->tls.ssl = NULL;
333
334 if (wsi->tls.use_ssl & LCCSCF_USE_SSL) {
335 const char *cce = NULL;
336
337 switch (
338 #if !defined(LWS_WITH_SYS_ASYNC_DNS)
339 lws_client_create_tls(wsi, &cce, 1)
340 #else
341 lws_client_create_tls(wsi, &cce, 0)
342 #endif
343 ) {
344 case 1:
345 return wsi;
346 case 0:
347 break;
348 default:
349 goto bail3;
350 }
351 }
352 #endif
353
354 /* fallthru */
355
356 wsi = lws_http_client_connect_via_info2(wsi);
357 }
358
359 if (wsi)
360 /*
361 * If it subsequently fails, report CONNECTION_ERROR,
362 * because we're going to return a non-error return now.
363 */
364 wsi->client_suppress_CONNECTION_ERROR = 0;
365
366 return wsi;
367
368 #if defined(LWS_WITH_TLS)
369 bail3:
370 lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS, "tls start fail");
371
372 return NULL;
373 #endif
374
375 bail1:
376 lws_free_set_NULL(wsi->stash);
377
378 bail:
379 lws_free(wsi);
380 #if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
381 bail2:
382 #endif
383
384 if (i->ssl_connection & LCCSCF_USE_SSL)
385 lws_tls_restrict_return(i->context);
386
387 if (i->pwsi)
388 *i->pwsi = NULL;
389
390 lws_stats_bump(&i->context->pt[tid], LWSSTATS_C_CONNS_CLIENT_FAILED, 1);
391
392 return NULL;
393 }
394