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