Coverage Report

Created: 2026-04-01 06:25

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libwebsockets/lib/secure-streams/secure-streams.c
Line
Count
Source
1
/*
2
 * libwebsockets - small server side websockets and web server implementation
3
 *
4
 * Copyright (C) 2019 - 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
static const struct ss_pcols *ss_pcols[] = {
28
#if defined(LWS_ROLE_H1)
29
  &ss_pcol_h1,    /* LWSSSP_H1 */
30
#else
31
  NULL,
32
#endif
33
#if defined(LWS_ROLE_H2)
34
  &ss_pcol_h2,    /* LWSSSP_H2 */
35
#else
36
  NULL,
37
#endif
38
#if defined(LWS_ROLE_WS)
39
  &ss_pcol_ws,    /* LWSSSP_WS */
40
#else
41
  NULL,
42
#endif
43
#if defined(LWS_ROLE_MQTT)
44
  &ss_pcol_mqtt,    /* LWSSSP_MQTT */
45
#else
46
  NULL,
47
#endif
48
  &ss_pcol_raw,   /* LWSSSP_RAW */
49
  NULL,
50
};
51
52
static const char *state_names[] = {
53
  "(unset)",
54
  "LWSSSCS_CREATING",
55
  "LWSSSCS_DISCONNECTED",
56
  "LWSSSCS_UNREACHABLE",
57
  "LWSSSCS_AUTH_FAILED",
58
  "LWSSSCS_CONNECTED",
59
  "LWSSSCS_CONNECTING",
60
  "LWSSSCS_DESTROYING",
61
  "LWSSSCS_POLL",
62
  "LWSSSCS_ALL_RETRIES_FAILED",
63
  "LWSSSCS_QOS_ACK_REMOTE",
64
  "LWSSSCS_QOS_NACK_REMOTE",
65
  "LWSSSCS_QOS_ACK_LOCAL",
66
  "LWSSSCS_QOS_NACK_LOCAL",
67
  "LWSSSCS_TIMEOUT",
68
  "LWSSSCS_SERVER_TXN",
69
  "LWSSSCS_SERVER_UPGRADE",
70
  "LWSSSCS_EVENT_WAIT_CANCELLED",
71
  "LWSSSCS_UPSTREAM_LINK_RETRY",
72
};
73
74
/*
75
 * For each "current state", set bit offsets for valid "next states".
76
 *
77
 * Since there are complicated ways to arrive at state transitions like proxying
78
 * and asynchronous destruction etc, so we monitor the state transitions we are
79
 * giving the ss user code to ensure we never deliver illegal state transitions
80
 * (because we will assert if we have bugs that do it)
81
 */
82
83
const uint32_t ss_state_txn_validity[] = {
84
85
  /* if we was last in this state...  we can legally go to these states */
86
87
  [0]       = (1 << LWSSSCS_CREATING) |
88
            (1 << LWSSSCS_DESTROYING),
89
90
  [LWSSSCS_CREATING]    = (1 << LWSSSCS_CONNECTING) |
91
            (1 << LWSSSCS_TIMEOUT) |
92
            (1 << LWSSSCS_POLL) |
93
            (1 << LWSSSCS_SERVER_UPGRADE) |
94
            (1 << LWSSSCS_DESTROYING),
95
96
  [LWSSSCS_DISCONNECTED]    = (1 << LWSSSCS_CONNECTING) |
97
            (1 << LWSSSCS_CONNECTED) |
98
            (1 << LWSSSCS_TIMEOUT) |
99
            (1 << LWSSSCS_POLL) |
100
            (1 << LWSSSCS_DESTROYING) |
101
            (1 << LWSSSCS_UNREACHABLE), /* sai-power talking to tasmota */
102
103
  [LWSSSCS_UNREACHABLE]   = (1 << LWSSSCS_ALL_RETRIES_FAILED) |
104
            (1 << LWSSSCS_TIMEOUT) |
105
            (1 << LWSSSCS_POLL) |
106
            (1 << LWSSSCS_UNREACHABLE) |
107
            (1 << LWSSSCS_CONNECTING) |
108
            /* win conn failure > retry > succ */
109
            (1 << LWSSSCS_CONNECTED) |
110
            (1 << LWSSSCS_DESTROYING),
111
112
  [LWSSSCS_AUTH_FAILED]   = (1 << LWSSSCS_ALL_RETRIES_FAILED) |
113
            (1 << LWSSSCS_TIMEOUT) |
114
            (1 << LWSSSCS_CONNECTING) |
115
            (1 << LWSSSCS_DESTROYING),
116
117
  [LWSSSCS_CONNECTED]   = (1 << LWSSSCS_SERVER_UPGRADE) |
118
            (1 << LWSSSCS_SERVER_TXN) |
119
            (1 << LWSSSCS_AUTH_FAILED) |
120
            (1 << LWSSSCS_QOS_ACK_REMOTE) |
121
            (1 << LWSSSCS_QOS_NACK_REMOTE) |
122
            (1 << LWSSSCS_QOS_ACK_LOCAL) |
123
            (1 << LWSSSCS_QOS_NACK_LOCAL) |
124
            (1 << LWSSSCS_DISCONNECTED) |
125
            (1 << LWSSSCS_TIMEOUT) |
126
            (1 << LWSSSCS_CONNECTING) |
127
            (1 << LWSSSCS_POLL) | /* proxy retry */
128
            (1 << LWSSSCS_DESTROYING),
129
130
  [LWSSSCS_CONNECTING]    = (1 << LWSSSCS_UNREACHABLE) |
131
            (1 << LWSSSCS_AUTH_FAILED) |
132
            (1 << LWSSSCS_CONNECTING) |
133
            (1 << LWSSSCS_CONNECTED) |
134
            (1 << LWSSSCS_QOS_ACK_REMOTE) |
135
            (1 << LWSSSCS_QOS_NACK_REMOTE) |
136
            (1 << LWSSSCS_TIMEOUT) |
137
            (1 << LWSSSCS_POLL) |
138
            (1 << LWSSSCS_ALL_RETRIES_FAILED) | /* via timeout in this state */
139
            (1 << LWSSSCS_DISCONNECTED) | /* proxy retry */
140
            (1 << LWSSSCS_DESTROYING),
141
142
  [LWSSSCS_DESTROYING]    = 0,
143
144
  [LWSSSCS_POLL]      = (1 << LWSSSCS_CONNECTING) |
145
            (1 << LWSSSCS_TIMEOUT) |
146
            (1 << LWSSSCS_ALL_RETRIES_FAILED) |
147
            (1 << LWSSSCS_DESTROYING),
148
149
  [LWSSSCS_ALL_RETRIES_FAILED]  = (1 << LWSSSCS_CONNECTING) |
150
            (1 << LWSSSCS_POLL) |
151
            (1 << LWSSSCS_TIMEOUT) |
152
            (1 << LWSSSCS_UNREACHABLE) |
153
            (1 << LWSSSCS_DESTROYING),
154
155
  [LWSSSCS_QOS_ACK_REMOTE]  = (1 << LWSSSCS_DISCONNECTED) |
156
            (1 << LWSSSCS_TIMEOUT) |
157
            (1 << LWSSSCS_CONNECTING) |
158
#if defined(LWS_ROLE_MQTT)
159
            (1 << LWSSSCS_QOS_ACK_REMOTE) |
160
            (1 << LWSSSCS_QOS_NACK_REMOTE) |
161
#endif
162
            (1 << LWSSSCS_DESTROYING),
163
164
  [LWSSSCS_QOS_NACK_REMOTE] = (1 << LWSSSCS_DISCONNECTED) |
165
            (1 << LWSSSCS_TIMEOUT) |
166
#if defined(LWS_ROLE_MQTT)
167
            (1 << LWSSSCS_QOS_ACK_REMOTE) |
168
            (1 << LWSSSCS_QOS_NACK_REMOTE) |
169
#endif
170
            (1 << LWSSSCS_DESTROYING),
171
172
  [LWSSSCS_QOS_ACK_LOCAL]   = (1 << LWSSSCS_DISCONNECTED) |
173
            (1 << LWSSSCS_TIMEOUT) |
174
            (1 << LWSSSCS_DESTROYING),
175
176
  [LWSSSCS_QOS_NACK_LOCAL]  = (1 << LWSSSCS_DESTROYING) |
177
            (1 << LWSSSCS_TIMEOUT),
178
179
  /* he can get the timeout at any point and take no action... */
180
  [LWSSSCS_TIMEOUT]   = (1 << LWSSSCS_CONNECTING) |
181
            (1 << LWSSSCS_CONNECTED) |
182
            (1 << LWSSSCS_QOS_ACK_REMOTE) |
183
            (1 << LWSSSCS_QOS_NACK_REMOTE) |
184
            (1 << LWSSSCS_POLL) |
185
            (1 << LWSSSCS_TIMEOUT) |
186
            (1 << LWSSSCS_DISCONNECTED) |
187
            (1 << LWSSSCS_UNREACHABLE) |
188
            (1 << LWSSSCS_DESTROYING),
189
190
  [LWSSSCS_SERVER_TXN]    = (1 << LWSSSCS_DISCONNECTED) |
191
            (1 << LWSSSCS_TIMEOUT) |
192
            (1 << LWSSSCS_SERVER_TXN) |
193
            (1 << LWSSSCS_DESTROYING),
194
195
  [LWSSSCS_SERVER_UPGRADE]  = (1 << LWSSSCS_SERVER_UPGRADE) |
196
                      (1 << LWSSSCS_SERVER_TXN) |
197
            (1 << LWSSSCS_TIMEOUT) |
198
            (1 << LWSSSCS_DISCONNECTED) |
199
            (1 << LWSSSCS_DESTROYING),
200
};
201
202
#if defined(LWS_WITH_CONMON)
203
204
/*
205
 * Convert any conmon data to JSON and attach to the ss handle.
206
 */
207
208
lws_ss_state_return_t
209
lws_conmon_ss_json(lws_ss_handle_t *h)
210
0
{
211
0
  char ads[48], *end, *buf, *obuf;
212
0
  const struct addrinfo *ai;
213
0
  lws_ss_state_return_t ret = LWSSSSRET_OK;
214
0
  struct lws_conmon cm;
215
0
  size_t len = 500;
216
217
0
  if (!h->policy || !(h->policy->flags & LWSSSPOLF_PERF) || !h->wsi ||
218
0
      h->wsi->perf_done)
219
0
    return LWSSSSRET_OK;
220
221
0
  if (h->conmon_json)
222
0
    lws_free_set_NULL(h->conmon_json);
223
224
0
  h->conmon_json = lws_malloc(len, __func__);
225
0
  if (!h->conmon_json)
226
0
    return LWSSSSRET_OK;
227
228
0
  obuf = buf = h->conmon_json;
229
0
  end = buf + len - 1;
230
231
0
  lws_conmon_wsi_take(h->wsi, &cm);
232
233
0
  lws_sa46_write_numeric_address(&cm.peer46, ads, sizeof(ads));
234
0
  buf += lws_snprintf(buf, lws_ptr_diff_size_t(end, buf),
235
0
         "{\"peer\":\"%s\","
236
0
          "\"dns_us\":%u,"
237
0
          "\"dns_disp\":%u,"
238
0
          "\"sockconn_us\":%u,"
239
0
          "\"tls_us\":%u,"
240
0
          "\"txn_resp_us\":%u,"
241
0
          "\"dns\":[",
242
0
        ads,
243
0
        (unsigned int)cm.ciu_dns,
244
0
        (unsigned int)cm.dns_disposition,
245
0
        (unsigned int)cm.ciu_sockconn,
246
0
        (unsigned int)cm.ciu_tls,
247
0
        (unsigned int)cm.ciu_txn_resp);
248
249
0
  ai = cm.dns_results_copy;
250
0
  while (ai) {
251
0
    lws_sa46_write_numeric_address((lws_sockaddr46 *)ai->ai_addr, ads, sizeof(ads));
252
0
    buf += lws_snprintf(buf, lws_ptr_diff_size_t(end, buf), "\"%s\"", ads);
253
0
    if (ai->ai_next && buf < end - 2)
254
0
      *buf++ = ',';
255
0
    ai = ai->ai_next;
256
0
  }
257
258
0
  buf += lws_snprintf(buf, lws_ptr_diff_size_t(end, buf), "]");
259
260
0
  switch (cm.pcol) {
261
0
  case LWSCONMON_PCOL_HTTP:
262
0
    buf += lws_snprintf(buf, lws_ptr_diff_size_t(end, buf),
263
0
         ",\"prot_specific\":{\"protocol\":\"http\",\"resp\":%u}",
264
0
         (unsigned int)cm.protocol_specific.http.response);
265
0
    break;
266
0
  default:
267
0
    break;
268
0
  }
269
270
0
  buf += lws_snprintf(buf, lws_ptr_diff_size_t(end, buf), "}");
271
272
  /*
273
   * This destroys the DNS list in the lws_conmon that we took
274
   * responsibility for when we used lws_conmon_wsi_take()
275
   */
276
277
0
  lws_conmon_release(&cm);
278
279
0
  h->conmon_len = (uint16_t)lws_ptr_diff(buf, obuf);
280
281
#if defined(LWS_WITH_SECURE_STREAMS_PROXY_API)
282
  if (h->proxy_onward) {
283
284
    /*
285
     * ask to forward it on the proxy link
286
     */
287
288
    h->conn_if_sspc_onw->txp_path.ops_onw->proxy_req_write(
289
        h->conn_if_sspc_onw->txp_path.priv_onw);
290
291
    return LWSSSSRET_OK;
292
  }
293
#endif
294
295
  /*
296
   * We can deliver it directly
297
   */
298
299
0
  if (h->info.rx)
300
0
    ret = h->info.rx(ss_to_userobj(h), (uint8_t *)h->conmon_json,
301
0
         (unsigned int)h->conmon_len,
302
0
         (int)(LWSSS_FLAG_SOM | LWSSS_FLAG_EOM |
303
0
             LWSSS_FLAG_PERF_JSON));
304
305
0
  lws_free_set_NULL(h->conmon_json);
306
307
0
  return ret;
308
0
}
309
#endif
310
311
int
312
lws_ss_check_next_state(lws_lifecycle_t *lc, uint8_t *prevstate,
313
      lws_ss_constate_t cs)
314
0
{
315
0
  if (cs >= LWSSSCS_USER_BASE ||
316
0
      cs == LWSSSCS_EVENT_WAIT_CANCELLED ||
317
0
      cs == LWSSSCS_SERVER_TXN ||
318
0
      cs == LWSSSCS_UPSTREAM_LINK_RETRY)
319
    /*
320
     * we can't judge user or transient states, leave the old state
321
     * and just wave them through
322
     */
323
0
    return 0;
324
325
0
  if (cs >= LWS_ARRAY_SIZE(ss_state_txn_validity)) {
326
    /* we don't recognize this state as usable */
327
0
    lwsl_err("%s: %s: bad new state %u\n", __func__, lc->gutag, cs);
328
0
    assert(0);
329
0
    return 1;
330
0
  }
331
332
0
  if (*prevstate >= LWS_ARRAY_SIZE(ss_state_txn_validity)) {
333
    /* existing state is broken */
334
0
    lwsl_err("%s: %s: bad existing state %u\n", __func__,
335
0
       lc->gutag, (unsigned int)*prevstate);
336
0
    assert(0);
337
0
    return 1;
338
0
  }
339
340
0
  if (ss_state_txn_validity[*prevstate] & (1u << cs)) {
341
342
0
    lwsl_debug("%s: %s: %s -> %s\n", __func__, lc->gutag,
343
0
          lws_ss_state_name(*prevstate),
344
0
          lws_ss_state_name(cs));
345
346
    /* this is explicitly allowed, update old state to new */
347
0
    *prevstate = (uint8_t)cs;
348
349
0
    return 0;
350
0
  }
351
352
0
  lwsl_err("%s: %s: transition from %s -> %s is illegal\n", __func__,
353
0
     lc->gutag, lws_ss_state_name(*prevstate),
354
0
     lws_ss_state_name(cs));
355
356
0
  assert(0);
357
358
0
  return 1;
359
0
}
360
361
int
362
lws_ss_check_next_state_ss(lws_ss_handle_t *ss, uint8_t *prevstate,
363
         lws_ss_constate_t cs)
364
0
{
365
0
  if (cs >= LWSSSCS_USER_BASE ||
366
0
      cs == LWSSSCS_EVENT_WAIT_CANCELLED ||
367
0
      cs == LWSSSCS_UPSTREAM_LINK_RETRY)
368
    /*
369
     * we can't judge user or transient states, leave the old state
370
     * and just wave them through
371
     */
372
0
    return 0;
373
374
0
  if (cs >= LWS_ARRAY_SIZE(ss_state_txn_validity)) {
375
    /* we don't recognize this state as usable */
376
0
    lwsl_ss_err(ss, "bad new state %u", cs);
377
0
    assert(0);
378
0
    return 1;
379
0
  }
380
381
0
  if (*prevstate >= LWS_ARRAY_SIZE(ss_state_txn_validity)) {
382
    /* existing state is broken */
383
0
    lwsl_ss_err(ss, "bad existing state %u",
384
0
        (unsigned int)*prevstate);
385
0
    assert(0);
386
0
    return 1;
387
0
  }
388
389
0
  if (ss_state_txn_validity[*prevstate] & (1u << cs)) {
390
391
0
    lwsl_ss_debug(ss, "%s -> %s",
392
0
             lws_ss_state_name(*prevstate),
393
0
             lws_ss_state_name(cs));
394
395
    /* this is explicitly allowed, update old state to new */
396
0
    *prevstate = (uint8_t)cs;
397
398
0
    return 0;
399
0
  }
400
401
0
  lwsl_ss_err(ss, "transition from %s -> %s is illegal",
402
0
        lws_ss_state_name(*prevstate),
403
0
        lws_ss_state_name(cs));
404
405
0
  assert(0);
406
407
0
  return 1;
408
0
}
409
410
const char *
411
lws_ss_state_name(lws_ss_constate_t state)
412
0
{
413
0
  if (state >= LWSSSCS_USER_BASE)
414
0
    return "user state";
415
416
0
  if (state >= (int)LWS_ARRAY_SIZE(state_names))
417
0
    return "unknown";
418
419
0
  return state_names[state];
420
0
}
421
422
lws_ss_state_return_t
423
lws_ss_event_helper(lws_ss_handle_t *h, lws_ss_constate_t cs)
424
0
{
425
0
  lws_ss_state_return_t r;
426
427
0
  if (!h)
428
0
    return LWSSSSRET_OK;
429
430
0
  if (lws_ss_check_next_state_ss(h, &h->prev_ss_state, cs))
431
0
    return LWSSSSRET_DESTROY_ME;
432
433
0
  if (cs == LWSSSCS_CONNECTED)
434
0
    h->ss_dangling_connected = 1;
435
0
  if (cs == LWSSSCS_DISCONNECTED) {
436
0
    h->ss_dangling_connected = 0;
437
438
0
    h->subseq = 0;
439
0
    h->txn_ok = 0;
440
0
    h->txn_resp_set = 0;
441
0
    h->txn_resp_pending = 0;
442
0
    h->hanging_som = 0;
443
0
    h->inside_msg = 0;
444
0
    h->inside_connect = 0;
445
0
    h->proxy_onward = 0;
446
0
    h->wsi = NULL;
447
0
    h->u.http.good_respcode = 0;
448
0
    h->seqstate = SSSEQ_IDLE;
449
0
  }
450
451
0
  if (h->info.state) {
452
0
    h->h_in_svc = h;
453
0
    r = h->info.state(ss_to_userobj(h), NULL, cs,
454
0
      cs == LWSSSCS_UNREACHABLE &&
455
0
      h->wsi && h->wsi->dns_reachability);
456
0
    h->h_in_svc = NULL;
457
458
0
#if defined(LWS_WITH_SERVER)
459
0
    if ((h->info.flags & LWSSSINFLAGS_ACCEPTED) &&
460
0
        cs == LWSSSCS_DISCONNECTED)
461
0
      r = LWSSSSRET_DESTROY_ME;
462
0
#endif
463
0
    return r;
464
0
  }
465
466
0
  return LWSSSSRET_OK;
467
0
}
468
469
int
470
_lws_ss_handle_state_ret_CAN_DESTROY_HANDLE(lws_ss_state_return_t r, struct lws *wsi,
471
       lws_ss_handle_t **ph)
472
0
{
473
0
  if (r == LWSSSSRET_DESTROY_ME) {
474
0
    lwsl_info("%s: DESTROY ME: %s, %s\n", __func__,
475
0
        lws_wsi_tag(wsi), lws_ss_tag(*ph));
476
0
    if (wsi) {
477
0
      lws_set_opaque_user_data(wsi, NULL);
478
0
      lws_set_timeout(wsi, 1, LWS_TO_KILL_ASYNC);
479
0
    } else {
480
0
      if ((*ph)->wsi) {
481
0
        lws_set_opaque_user_data((*ph)->wsi, NULL);
482
0
        lws_set_timeout((*ph)->wsi, 1, LWS_TO_KILL_ASYNC);
483
0
      }
484
0
    }
485
0
    (*ph)->wsi = NULL;
486
0
    lws_ss_destroy(ph);
487
0
  }
488
489
0
  return -1; /* close connection */
490
0
}
491
492
static void
493
lws_ss_timeout_sul_check_cb(lws_sorted_usec_list_t *sul)
494
0
{
495
0
  lws_ss_state_return_t r;
496
0
  lws_ss_handle_t *h = lws_container_of(sul, lws_ss_handle_t, sul);
497
498
0
  lwsl_info("%s: retrying %s after backoff\n", __func__, lws_ss_tag(h));
499
  /* we want to retry... */
500
0
  h->seqstate = SSSEQ_DO_RETRY;
501
502
0
  r = _lws_ss_request_tx(h);
503
0
  _lws_ss_handle_state_ret_CAN_DESTROY_HANDLE(r, NULL, &h);
504
0
}
505
506
int
507
lws_ss_exp_cb_metadata(void *priv, const char *name, char *out, size_t *pos,
508
      size_t olen, size_t *exp_ofs)
509
0
{
510
0
  lws_ss_handle_t *h = (lws_ss_handle_t *)priv;
511
0
  const char *replace = NULL;
512
0
  size_t total, budget;
513
0
  lws_ss_metadata_t *md = lws_ss_policy_metadata(h->policy, name),
514
0
        *hmd = lws_ss_get_handle_metadata(h, name);
515
516
0
  if (!md) {
517
0
    lwsl_err("%s: Unknown metadata %s\n", __func__, name);
518
519
0
    return LSTRX_FATAL_NAME_UNKNOWN;
520
0
  }
521
522
0
  if (!hmd)
523
0
    return LSTRX_FILLED_OUT;
524
525
0
  replace = hmd->value__may_own_heap;
526
527
0
  if (!replace)
528
0
    return LSTRX_DONE;
529
530
0
  total = hmd->length;
531
532
0
  budget = olen - *pos;
533
0
  total -= *exp_ofs;
534
0
  if (total < budget)
535
0
    budget = total;
536
537
0
  if (out)
538
0
    memcpy(out + *pos, replace + (*exp_ofs), budget);
539
0
  *exp_ofs += budget;
540
0
  *pos += budget;
541
542
0
  if (budget == total)
543
0
    return LSTRX_DONE;
544
545
0
  return LSTRX_FILLED_OUT;
546
0
}
547
548
int
549
lws_ss_set_timeout_us(lws_ss_handle_t *h, lws_usec_t us)
550
0
{
551
0
  struct lws_context_per_thread *pt = &h->context->pt[h->tsi];
552
553
0
  h->sul.cb = lws_ss_timeout_sul_check_cb;
554
0
  __lws_sul_insert_us(&pt->pt_sul_owner[
555
0
              !!(h->policy->flags & LWSSSPOLF_WAKE_SUSPEND__VALIDITY)],
556
0
        &h->sul, us);
557
558
0
  return 0;
559
0
}
560
561
lws_ss_state_return_t
562
_lws_ss_backoff(lws_ss_handle_t *h, lws_usec_t us_override)
563
0
{
564
0
  uint64_t ms;
565
0
  char conceal;
566
567
0
  lws_service_assert_loop_thread(h->context, h->tsi);
568
569
0
  if (h->seqstate == SSSEQ_RECONNECT_WAIT)
570
0
    return LWSSSSRET_OK;
571
572
  /* figure out what we should do about another retry */
573
574
0
  lwsl_info("%s: %s: retry backoff after failure\n", __func__, lws_ss_tag(h));
575
0
  ms = lws_retry_get_delay_ms(h->context, h->policy->retry_bo,
576
0
            &h->retry, &conceal);
577
0
  if (!conceal) {
578
0
    lwsl_info("%s: %s: abandon conn attempt \n",__func__, lws_ss_tag(h));
579
580
0
    if (h->seqstate == SSSEQ_IDLE) /* been here? */
581
0
      return LWSSSSRET_OK;
582
583
0
    h->seqstate = SSSEQ_IDLE;
584
585
0
    return lws_ss_event_helper(h, LWSSSCS_ALL_RETRIES_FAILED);
586
0
  }
587
588
  /* Only increase our planned backoff, or go with it */
589
590
0
  if (us_override < (lws_usec_t)ms * LWS_US_PER_MS)
591
0
    us_override = (lws_usec_t)(ms * LWS_US_PER_MS);
592
593
0
  h->seqstate = SSSEQ_RECONNECT_WAIT;
594
0
  lws_ss_set_timeout_us(h, us_override);
595
596
0
  lwsl_info("%s: %s: retry wait %dms\n", __func__, lws_ss_tag(h),
597
0
              (int)(us_override / 1000));
598
599
0
  return LWSSSSRET_OK;
600
0
}
601
602
lws_ss_state_return_t
603
lws_ss_backoff(lws_ss_handle_t *h)
604
0
{
605
0
  return _lws_ss_backoff(h, 0);
606
0
}
607
608
#if defined(LWS_WITH_SYS_SMD)
609
610
/*
611
 * Local SMD <-> SS
612
 *
613
 * We pass received messages through to the SS handler synchronously, using the
614
 * lws service thread context.
615
 *
616
 * After the SS is created and registered, still nothing is going to come here
617
 * until the peer sends us his rx_class_mask and we update his registration with
618
 * it, because from SS creation his rx_class_mask defaults to 0.
619
 */
620
621
static int
622
lws_smd_ss_cb(void *opaque, lws_smd_class_t _class,
623
        lws_usec_t timestamp, void *buf, size_t len)
624
0
{
625
0
  lws_ss_handle_t *h = (lws_ss_handle_t *)opaque;
626
0
  uint8_t *p = (uint8_t *)buf - LWS_SMD_SS_RX_HEADER_LEN;
627
628
0
  lws_service_assert_loop_thread(h->context, h->tsi);
629
630
  /*
631
   * When configured with SS enabled, lws over-allocates
632
   * LWS_SMD_SS_RX_HEADER_LEN bytes behind the payload of the queued
633
   * message, for prepending serialized class and timestamp data in-band
634
   * with the payload.
635
   */
636
637
0
  lws_ser_wu64be(p, _class);
638
0
  lws_ser_wu64be(p + 8, (uint64_t)timestamp);
639
640
0
  if (h->info.rx)
641
0
    h->info.rx((void *)(h + 1), p, len + LWS_SMD_SS_RX_HEADER_LEN,
642
0
          LWSSS_FLAG_SOM | LWSSS_FLAG_EOM);
643
644
0
  return 0;
645
0
}
646
647
static void
648
lws_ss_smd_tx_cb(lws_sorted_usec_list_t *sul)
649
0
{
650
0
  lws_ss_handle_t *h = lws_container_of(sul, lws_ss_handle_t, u.smd.sul_write);
651
0
  uint8_t buf[LWS_SMD_SS_RX_HEADER_LEN + LWS_SMD_MAX_PAYLOAD], *p;
652
0
  size_t len = sizeof(buf);
653
0
  lws_smd_class_t _class;
654
0
  int flags = 0, n;
655
656
0
  lws_service_assert_loop_thread(h->context, h->tsi);
657
658
0
  if (!h->info.tx)
659
0
    return;
660
661
0
  n = h->info.tx(h + 1, h->txord++, buf, &len, &flags);
662
0
  if (n)
663
    /* nonzero return means don't want to send anything */
664
0
    return;
665
666
0
  if (len < LWS_SMD_SS_RX_HEADER_LEN) {
667
0
    lwsl_ss_notice(h, "smd message undersize: tx len %d vs %d",
668
0
        (int)len, (int)LWS_SMD_SS_RX_HEADER_LEN);
669
0
    lwsl_hexdump_notice(buf, len);
670
0
    return;
671
0
  }
672
0
  _class = (lws_smd_class_t)lws_ser_ru64be(buf);
673
0
  p = lws_smd_msg_alloc(h->context, _class, len - LWS_SMD_SS_RX_HEADER_LEN);
674
0
  if (!p) {
675
    // this can be rejected if nobody listening for this class
676
    //lwsl_notice("%s: failed to alloc\n", __func__);
677
0
    return;
678
0
  }
679
680
0
  memcpy(p, buf + LWS_SMD_SS_RX_HEADER_LEN, len - LWS_SMD_SS_RX_HEADER_LEN);
681
0
  if (lws_smd_msg_send(h->context, p)) {
682
0
    lwsl_notice("%s: failed to queue\n", __func__);
683
0
    return;
684
0
  }
685
0
}
686
687
#endif
688
689
#if defined(LWS_WITH_FILE_OPS)
690
static void
691
lws_ss_fops_sul_cb(lws_sorted_usec_list_t *sul)
692
0
{
693
0
  lws_ss_handle_t *h = lws_container_of(sul, lws_ss_handle_t, fops_sul);
694
0
  lws_ss_state_return_t r = LWSSSSRET_DISCONNECT_ME;
695
0
  lws_filepos_t amount;
696
0
  uint8_t lump[1400];
697
698
0
  amount = sizeof(lump);
699
0
  if (lws_vfs_file_read(h->fop_fd, &amount, lump, sizeof(lump)))
700
0
    goto disconn;
701
702
0
  r = h->info.rx(h + 1, lump, (size_t)amount,
703
0
      (!h->fop_fd->pos ? LWSSS_FLAG_SOM : 0) |
704
0
      (h->fop_fd->pos == h->fop_fd->len ?
705
0
          LWSSS_FLAG_EOM : 0));
706
0
  if (!r) {
707
0
    if (h->fop_fd->pos != h->fop_fd->len)
708
0
      lws_sul_schedule(h->context, 0, &h->fops_sul,
709
0
           lws_ss_fops_sul_cb, 1);
710
0
    return;
711
0
  }
712
713
0
disconn:
714
0
  lws_vfs_file_close(&h->fop_fd);
715
716
0
  if (lws_ss_event_helper(h, LWSSSCS_DISCONNECTED))
717
0
    return;
718
719
0
  if (r == LWSSSSRET_DESTROY_ME)
720
0
    lws_ss_destroy(&h);
721
0
}
722
#endif
723
724
lws_ss_state_return_t
725
_lws_ss_client_connect(lws_ss_handle_t *h, int is_retry, void *conn_if_sspc_onw)
726
0
{
727
0
  const char *prot, *_prot, *ipath, *_ipath, *ads, *_ads;
728
0
  struct lws_client_connect_info i;
729
0
  const struct ss_pcols *ssp;
730
0
  size_t used_in, used_out;
731
0
  union lws_ss_contemp ct;
732
0
  lws_ss_state_return_t r;
733
0
  int port, _port, tls;
734
0
  char *path, ep[LHP_URL_LEN];
735
0
  lws_strexp_t exp;
736
0
  struct lws *wsi;
737
738
0
  lws_service_assert_loop_thread(h->context, h->tsi);
739
740
0
  if (!h->policy) {
741
0
    lwsl_err("%s: ss with no policy\n", __func__);
742
743
0
    return LWSSSSRET_OK;
744
0
  }
745
746
0
#if defined(LWS_WITH_SERVER)
747
  /*
748
   * We are already bound to a sink?
749
   */
750
751
0
  if (h->sink_local_bind)
752
0
    return 0;
753
0
#endif
754
755
0
  if (!is_retry)
756
0
    h->retry = 0;
757
758
0
#if defined(LWS_WITH_SYS_SMD)
759
0
  if (h->policy == &pol_smd) {
760
761
0
    if (h->u.smd.smd_peer)
762
0
      return LWSSSSRET_OK;
763
764
    // lwsl_notice("%s: received connect for _lws_smd, registering for class mask 0x%x\n",
765
    //    __func__, h->info.manual_initial_tx_credit);
766
767
0
    h->u.smd.smd_peer = lws_smd_register(h->context, h,
768
0
          (h->info.flags & LWSSSINFLAGS_PROXIED) ?
769
0
            LWSSMDREG_FLAG_PROXIED_SS : 0,
770
0
          (lws_smd_class_t)h->info.manual_initial_tx_credit,
771
0
          lws_smd_ss_cb);
772
0
    if (!h->u.smd.smd_peer)
773
0
      return LWSSSSRET_TX_DONT_SEND;
774
775
0
    if (lws_ss_event_helper(h, LWSSSCS_CONNECTING))
776
0
      return LWSSSSRET_TX_DONT_SEND;
777
778
0
    if (lws_ss_event_helper(h, LWSSSCS_CONNECTED))
779
0
      return LWSSSSRET_TX_DONT_SEND;
780
0
    return LWSSSSRET_OK;
781
0
  }
782
0
#endif
783
784
  /*
785
   * We're going to substitute ${metadata} in the endpoint at connection-
786
   * time, so this can be set dynamically...
787
   */
788
789
0
  lws_strexp_init(&exp, (void *)h, lws_ss_exp_cb_metadata, ep, sizeof(ep));
790
791
0
  if (lws_strexp_expand(&exp, h->policy->endpoint,
792
0
            strlen(h->policy->endpoint),
793
0
            &used_in, &used_out) != LSTRX_DONE) {
794
0
    lwsl_err("%s: address strexp failed\n", __func__);
795
796
0
    return LWSSSSRET_TX_DONT_SEND;
797
0
  }
798
799
  /*
800
   * ... in some cases, we might want the user to be able to override
801
   * some policy settings by what he provided in there.  For example,
802
   * if he set the endpoint to "https://myendpoint.com:4443/mypath" it
803
   * might be quite convenient to override the policy to follow the info
804
   * that was given for at least server, port and the url path.
805
   */
806
807
0
  _port = port = h->policy->port;
808
0
  _prot = prot = NULL;
809
0
  _ipath = ipath = "";
810
0
  _ads = ads = ep;
811
812
0
#if defined(LWS_WITH_FILE_OPS)
813
0
  if (!strncmp(ep, "file://", 7)) {
814
0
    lws_fop_flags_t fl = 0;
815
0
    h->fop_fd = lws_vfs_file_open(h->context->fops, ep + 7, &fl);
816
817
    /* we opened the file */
818
819
0
    r = lws_ss_event_helper(h, LWSSSCS_CONNECTING);
820
0
    if (r) {
821
0
      lws_vfs_file_close(&h->fop_fd);
822
0
      return r;
823
0
    }
824
825
0
    if (!h->fop_fd) {
826
0
      lws_vfs_file_close(&h->fop_fd);
827
0
      lwsl_ss_warn(h, "Unable to find %s", ep);
828
0
      goto fail_out;
829
0
    }
830
831
0
    r = lws_ss_event_helper(h, LWSSSCS_CONNECTED);
832
0
    if (r) {
833
0
      lws_vfs_file_close(&h->fop_fd);
834
0
      return r;
835
0
    }
836
837
    /* start issuing the file as rx next time around the event loop */
838
0
    lws_sul_schedule(h->context, 0, &h->fops_sul,
839
0
         lws_ss_fops_sul_cb, 1);
840
841
0
    return LWSSSSRET_OK;
842
0
  }
843
0
#endif
844
845
0
  if (strchr(ep, ':') &&
846
0
      !lws_parse_uri(ep, &_prot, &_ads, &_port, &_ipath)) {
847
0
    lwsl_debug("%s: using uri parse results '%s' '%s' %d '%s'\n",
848
0
        __func__, _prot, _ads, _port, _ipath);
849
0
    prot = _prot;
850
0
    ads = _ads;
851
0
    port = _port;
852
0
    ipath = _ipath;
853
0
  }
854
855
0
  memset(&i, 0, sizeof i); /* otherwise uninitialized garbage */
856
0
  i.context = h->context;
857
0
  tls = !!(h->policy->flags & LWSSSPOLF_TLS);
858
859
0
  if (prot && (!strcmp(prot, "http") || !strcmp(prot, "ws") ||
860
0
         !strcmp(prot, "mqtt")))
861
0
    tls = 0;
862
863
0
  if (tls) {
864
0
    lwsl_info("%s: using tls\n", __func__);
865
0
    i.ssl_connection = LCCSCF_USE_SSL;
866
867
0
    if (!h->policy->trust.store)
868
0
      lwsl_info("%s: using platform trust store\n", __func__);
869
0
    else {
870
871
0
      i.vhost = lws_get_vhost_by_name(h->context,
872
0
          h->policy->trust.store->name);
873
0
      if (!i.vhost) {
874
0
        lwsl_err("%s: missing vh for policy %s\n",
875
0
           __func__,
876
0
           h->policy->trust.store->name);
877
878
0
        return -1;
879
0
      }
880
0
    }
881
0
  }
882
883
0
  if (h->policy->flags & LWSSSPOLF_WAKE_SUSPEND__VALIDITY)
884
0
    i.ssl_connection |= LCCSCF_WAKE_SUSPEND__VALIDITY;
885
886
  /* translate policy attributes to IP ToS flags */
887
888
0
  if (h->policy->flags & LWSSSPOLF_ATTR_LOW_LATENCY)
889
0
    i.ssl_connection |= LCCSCF_IP_LOW_LATENCY;
890
0
  if (h->policy->flags & LWSSSPOLF_ATTR_HIGH_THROUGHPUT)
891
0
    i.ssl_connection |= LCCSCF_IP_HIGH_THROUGHPUT;
892
0
  if (h->policy->flags & LWSSSPOLF_ATTR_HIGH_RELIABILITY)
893
0
    i.ssl_connection |= LCCSCF_IP_HIGH_RELIABILITY;
894
0
  if (h->policy->flags & LWSSSPOLF_ATTR_LOW_COST)
895
0
    i.ssl_connection |= LCCSCF_IP_LOW_COST;
896
0
  if (h->policy->flags & LWSSSPOLF_PERF) /* collect conmon stats on this */
897
0
    i.ssl_connection |= LCCSCF_CONMON;
898
899
  /* mark the connection with the streamtype priority from the policy */
900
901
0
  i.priority = h->policy->priority;
902
903
0
  i.ssl_connection |= LCCSCF_SECSTREAM_CLIENT;
904
905
0
  if (conn_if_sspc_onw) {
906
0
    i.ssl_connection |= LCCSCF_SECSTREAM_PROXY_ONWARD;
907
0
    h->conn_if_sspc_onw = conn_if_sspc_onw;
908
0
  }
909
910
911
0
  i.address   = ads;
912
0
  i.port      = port;
913
0
  i.host      = i.address;
914
0
  i.origin    = i.address;
915
0
  i.opaque_user_data  = h;
916
0
  i.retry_and_idle_policy = h->policy->retry_bo;
917
0
  i.sys_tls_client_cert = h->policy->client_cert;
918
919
0
  i.path      = ipath;
920
    /* if this is not "", munge should use it instead of policy
921
     * url path
922
     */
923
924
0
  ssp = ss_pcols[(int)h->policy->protocol];
925
0
  if (!ssp) {
926
0
    lwsl_err("%s: unsupported protocol\n", __func__);
927
928
0
    return LWSSSSRET_TX_DONT_SEND;
929
0
  }
930
0
  i.alpn = ssp->alpn;
931
932
  /*
933
   * For http, we can get the method from the http object, override in
934
   * the protocol-specific munge callback below if not http
935
   */
936
0
  i.method = h->policy->u.http.method;
937
0
  i.protocol = ssp->protocol->name; /* lws protocol name */
938
0
  i.local_protocol_name = i.protocol;
939
940
0
  path = lws_malloc(h->context->max_http_header_data, __func__);
941
0
  if (!path) {
942
0
    lwsl_warn("%s: OOM on path prealloc\n", __func__);
943
0
    return LWSSSSRET_TX_DONT_SEND;
944
0
  }
945
946
0
  if (ssp->munge) /* eg, raw doesn't use; endpoint strexp already done */
947
0
    ssp->munge(h, path, h->context->max_http_header_data, &i, &ct);
948
949
0
  i.pwsi = &h->wsi;
950
951
0
  lwsl_info("%s: connecting %s, '%s' '%s' %s\n", __func__, i.method,
952
0
      i.alpn, i.address, i.path);
953
954
#if defined(LWS_WITH_SYS_METRICS)
955
  /* possibly already hanging connect retry... */
956
  if (!h->cal_txn.mt)
957
    lws_metrics_caliper_bind(h->cal_txn, h->context->mth_ss_conn);
958
959
  if (h->policy->streamtype)
960
    lws_metrics_tag_add(&h->cal_txn.mtags_owner, "ss",
961
            h->policy->streamtype);
962
#endif
963
964
0
  h->txn_ok = 0;
965
0
  r = lws_ss_event_helper(h, LWSSSCS_CONNECTING);
966
0
  if (r) {
967
0
    lws_free(path);
968
0
    return r;
969
0
  }
970
971
0
  h->inside_connect = 1;
972
0
  h->pending_ret = LWSSSSRET_OK;
973
0
  wsi = lws_client_connect_via_info(&i);
974
0
  h->inside_connect = 0;
975
0
  lws_free(path);
976
0
  if (!wsi) {
977
    /*
978
     * We already found that we could not connect, without even
979
     * having to go around the event loop
980
     */
981
982
0
    if (h->pending_ret)
983
0
      return h->pending_ret;
984
985
0
#if defined(LWS_WITH_FILE_OPS)
986
0
fail_out:
987
0
#endif
988
0
    if (h->prev_ss_state != LWSSSCS_UNREACHABLE &&
989
0
        h->prev_ss_state != LWSSSCS_ALL_RETRIES_FAILED) {
990
      /*
991
       * blocking DNS failure can get to unreachable via
992
       * CCE, and unreachable can get to ALL_RETRIES_FAILED
993
       */
994
0
      r = lws_ss_event_helper(h, LWSSSCS_UNREACHABLE);
995
0
      if (r)
996
0
        return r;
997
998
0
      r = lws_ss_backoff(h);
999
0
      if (r)
1000
0
        return r;
1001
0
    }
1002
1003
0
    return LWSSSSRET_TX_DONT_SEND;
1004
0
  }
1005
1006
0
  return LWSSSSRET_OK;
1007
0
}
1008
1009
lws_ss_state_return_t
1010
lws_ss_client_connect(lws_ss_handle_t *h)
1011
0
{
1012
0
  lws_ss_state_return_t r;
1013
1014
0
  lws_service_assert_loop_thread(h->context, h->tsi);
1015
1016
0
  r = _lws_ss_client_connect(h, 0, 0);
1017
1018
0
  return r;
1019
0
}
1020
1021
int
1022
lws_ss_adopt_raw(struct lws_ss_handle *h, lws_sock_file_fd_type fd)
1023
0
{
1024
0
  const struct ss_pcols *ssp;
1025
0
  lws_ss_state_return_t r;
1026
0
    lws_adopt_desc_t desc;
1027
0
    struct lws *wsi;
1028
1029
0
    if (!h->policy || !h->policy->protocol)
1030
0
    return 1;
1031
1032
0
    ssp = ss_pcols[(int)h->policy->protocol];
1033
0
    if (!ssp)
1034
0
    return 1;
1035
1036
0
  memset(&desc, 0, sizeof(desc));
1037
1038
0
  desc.vh = lws_ss_get_vhost(h) ? lws_ss_get_vhost(h) :
1039
0
        lws_get_vhost_by_name(h->context, "_ss_default");
1040
0
  if (desc.vh == NULL)
1041
0
    return 1;
1042
0
  desc.vh_prot_name = ssp->protocol->name;
1043
0
  desc.type = LWS_ADOPT_RAW_FILE_DESC;
1044
0
  desc.fd = fd;
1045
0
  desc.opaque = h;
1046
1047
0
  wsi = lws_adopt_descriptor_vhost_via_info(&desc);
1048
0
  if (!wsi) {
1049
0
    lwsl_ss_warn(h, "Failed to adopt pipe\n");
1050
0
    return 1;
1051
0
  }
1052
1053
0
  lwsl_wsi_notice(wsi, "Adopted fd %d\n", fd.filefd);
1054
1055
0
  h->wsi = wsi;
1056
0
  wsi->for_ss = 1;
1057
0
  h->txn_ok = 0;
1058
1059
0
  r = lws_ss_event_helper(h, LWSSSCS_CONNECTING);
1060
0
  if (r)
1061
0
    goto bail;
1062
0
  r = lws_ss_event_helper(h, LWSSSCS_CONNECTED);
1063
0
  if (r)
1064
0
    goto bail;
1065
1066
0
  if (lws_change_pollfd(wsi, 0, LWS_POLLIN))
1067
0
    lwsl_ss_warn(h, "Failed to set POLLIN\n");
1068
1069
0
  return 0;
1070
1071
0
bail:
1072
0
  r = lws_ss_event_helper(h, LWSSSCS_DISCONNECTED);
1073
0
  if (r)
1074
0
    goto bail;
1075
1076
0
  lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS,
1077
0
             "ss adopt skt fail");
1078
1079
0
  return 1;
1080
0
}
1081
1082
/*
1083
 * Public API
1084
 */
1085
1086
/*
1087
 * Create either a stream or a sink
1088
 */
1089
1090
int
1091
lws_ss_create(struct lws_context *context, int tsi, const lws_ss_info_t *ssi,
1092
        void *opaque_user_data, lws_ss_handle_t **ppss,
1093
        void *reserved, const char **ppayload_fmt)
1094
0
{
1095
0
  struct lws_context_per_thread *pt = &context->pt[tsi];
1096
0
  const lws_ss_policy_t *pol;
1097
0
  lws_ss_state_return_t r;
1098
0
  lws_ss_metadata_t *smd;
1099
0
#if defined(LWS_WITH_SERVER)
1100
0
  lws_ss_sinks_t *sn;
1101
0
#endif
1102
0
  lws_ss_handle_t *h;
1103
0
  size_t size;
1104
0
  void **v;
1105
0
  char *p;
1106
0
  int n;
1107
1108
0
  lws_service_assert_loop_thread(context, tsi);
1109
1110
#if defined(LWS_WITH_SECURE_STREAMS_CPP)
1111
  pol = ssi->policy;
1112
  if (!pol) {
1113
#endif
1114
1115
#if defined(LWS_WITH_SYS_FAULT_INJECTION)
1116
    lws_fi_ctx_t temp_fic;
1117
1118
    /*
1119
     * We have to do a temp inherit from context to find out
1120
     * early if we are supposed to inject a fault concealing
1121
     * the policy
1122
     */
1123
1124
    memset(&temp_fic, 0, sizeof(temp_fic));
1125
    lws_xos_init(&temp_fic.xos, lws_xos(&context->fic.xos));
1126
    lws_fi_inherit_copy(&temp_fic, &context->fic, "ss", ssi->streamtype);
1127
1128
    if (lws_fi(&temp_fic, "ss_no_streamtype_policy"))
1129
      pol = NULL;
1130
    else
1131
      pol = lws_ss_policy_lookup(context, ssi->streamtype);
1132
1133
    lws_fi_destroy(&temp_fic);
1134
#else
1135
0
    pol = lws_ss_policy_lookup(context, ssi->streamtype);
1136
0
#endif
1137
0
    if (!pol) {
1138
0
      lwsl_cx_info(context, "unknown stream type %s",
1139
0
          ssi->streamtype);
1140
0
      return 1;
1141
0
    }
1142
#if defined(LWS_WITH_SECURE_STREAMS_CPP)
1143
  }
1144
#endif
1145
1146
0
#if defined(LWS_WITH_SERVER)
1147
0
  if (ssi->flags & LWSSSINFLAGS_REGISTER_SINK) {
1148
1149
    /*
1150
     * This can register a secure streams sink as well as normal
1151
     * secure streams connections.  If that's what's happening,
1152
     * confirm the policy agrees that this streamtype should be
1153
     * directed to a sink.
1154
     */
1155
0
    if (!(pol->flags & LWSSSPOLF_LOCAL_SINK)) {
1156
      /*
1157
       * Caller wanted to create a sink for this streamtype,
1158
       * but the policy does not agree the streamtype should
1159
       * be routed to a local sink.
1160
       */
1161
0
      lwsl_err("%s: %s policy does not allow local sink\n",
1162
0
         __func__, ssi->streamtype);
1163
1164
0
      return 1;
1165
0
    }
1166
1167
0
    sn = lws_zalloc(sizeof(*sn), __func__);
1168
0
    if (!sn)
1169
0
      return 1;
1170
1171
0
    sn->info = *ssi;
1172
0
    sn->info.flags = (uint8_t)((sn->info.flags &
1173
0
            ~(LWSSSINFLAGS_REGISTER_SINK)) |
1174
0
        LWSSSINFLAGS_ACCEPTED_SINK);
1175
0
    lws_dll2_add_tail(&sn->list, &context->sinks);
1176
1177
0
    lwsl_cx_notice(context, "registered sink %s", ssi->streamtype);
1178
1179
0
    return 0;
1180
0
  }
1181
0
#endif
1182
1183
  /*
1184
   * We overallocate and point to things in the overallocation...
1185
   *
1186
   * 1) the user_alloc from the stream info
1187
   * 2) as many metadata pointer structs as the policy tells
1188
   * 3) the streamtype name (length is not aligned)
1189
   *
1190
   * ... when we come to destroy it, just one free to do.
1191
   */
1192
1193
0
  size = sizeof(*h) + ssi->user_alloc +
1194
0
      (ssi->streamtype ? strlen(ssi->streamtype): 0) + 1;
1195
0
  size += pol->metadata_count * sizeof(lws_ss_metadata_t);
1196
1197
0
  h = lws_zalloc(size, __func__);
1198
0
  if (!h)
1199
0
    return 2;
1200
1201
0
  h->lc.log_cx = context->log_cx;
1202
1203
0
  n = LWSLCG_WSI_SS_CLIENT;
1204
0
#if defined(LWS_WITH_SERVER)
1205
0
  if (pol->flags & LWSSSPOLF_LOCAL_SINK) {
1206
0
    if (ssi->flags & LWSSSINFLAGS_ACCEPTED_SINK)
1207
0
      n = LWSLCG_WSI_SSP_SINK;
1208
0
    else
1209
0
      n = LWSLCG_WSI_SSP_SOURCE;
1210
0
  }
1211
0
#endif
1212
1213
0
  if (ssi->sss_protocol_version)
1214
0
    __lws_lc_tag(context, &context->lcg[n], &h->lc, "%s|v%u|%u",
1215
0
           ssi->streamtype ? ssi->streamtype : "nostreamtype",
1216
0
           (unsigned int)ssi->sss_protocol_version,
1217
0
           (unsigned int)ssi->client_pid);
1218
0
  else
1219
0
    __lws_lc_tag(context, &context->lcg[n], &h->lc, "%s",
1220
0
           ssi->streamtype ? ssi->streamtype : "nostreamtype");
1221
1222
#if defined(LWS_WITH_SYS_FAULT_INJECTION)
1223
  h->fic.name = "ss";
1224
  lws_xos_init(&h->fic.xos, lws_xos(&context->fic.xos));
1225
  if (ssi->fic.fi_owner.count)
1226
    lws_fi_import(&h->fic, &ssi->fic);
1227
1228
  lws_fi_inherit_copy(&h->fic, &context->fic, "ss", ssi->streamtype);
1229
#endif
1230
1231
0
#if defined(LWS_WITH_SERVER)
1232
0
  if (pol->flags & LWSSSPOLF_LOCAL_SINK) {
1233
1234
0
    if ((ssi->flags & LWSSSINFLAGS_ACCEPTED_SINK) &&
1235
0
        opaque_user_data /* coverity */) {
1236
      /*
1237
       * We are recursing to create the accepted sink, do
1238
       * the binding while still in create so any downstream
1239
       * actions understand our situation from the start
1240
       */
1241
0
      h->sink_local_bind = (struct lws_ss_handle *)
1242
0
              opaque_user_data;
1243
0
      h->sink_local_bind->sink_local_bind = h;
1244
0
    } else {
1245
1246
      /* we are creating an ss connected to a sink... find the sink */
1247
1248
0
      lws_start_foreach_dll(struct lws_dll2 *, d,
1249
0
                lws_dll2_get_head(&context->sinks)) {
1250
0
        sn = lws_container_of(d, lws_ss_sinks_t, list);
1251
1252
0
        if (!strcmp(sn->info.streamtype, ssi->streamtype)) {
1253
0
          lws_ss_handle_t *has;
1254
1255
          /*
1256
           * How does the sink feel about us joining?
1257
           */
1258
1259
0
          if (sn->info.state(h + 1, h, LWSSSCS_SINK_JOIN,
1260
0
                  sn->accepts.count)) {
1261
0
            lwsl_ss_notice(h, "sink rejected");
1262
0
            goto fail_creation;
1263
0
          }
1264
1265
          /*
1266
           * Recurse to instantiate an accepted sink SS
1267
           * for us to bind to... pass bind source handle
1268
           * in as opaque data
1269
           */
1270
1271
0
          if (lws_ss_create(context, tsi, &sn->info,
1272
0
                h, &has, NULL, NULL)) {
1273
0
            lwsl_ss_err(h, "sink accept failed");
1274
0
            goto fail_creation;
1275
0
          }
1276
1277
0
          lws_dll2_add_tail(&has->sink_bind, &sn->accepts);
1278
1279
0
          lwsl_ss_notice(h, "bound to sink");
1280
0
          break;
1281
0
        }
1282
1283
0
      } lws_end_foreach_dll(d);
1284
1285
0
      if (!h->sink_local_bind) {
1286
0
        lwsl_cx_err(context, "no sink %s", ssi->streamtype);
1287
0
        goto fail_creation;
1288
0
      }
1289
0
    }
1290
0
  }
1291
0
#endif
1292
1293
0
  h->info = *ssi;
1294
0
  h->policy = pol;
1295
0
  h->context = context;
1296
0
  h->tsi = (uint8_t)tsi;
1297
1298
0
  if (h->info.flags & LWSSSINFLAGS_PROXIED)
1299
0
    h->proxy_onward = 1;
1300
1301
  /* start of overallocated area */
1302
0
  p = (char *)(h + 1);
1303
1304
  /* set the handle pointer in the user data struct */
1305
0
  v = (void **)(p + ssi->handle_offset);
1306
0
  *v = h;
1307
1308
  /* set the opaque user data in the user data struct */
1309
0
  v = (void **)(p + ssi->opaque_user_data_offset);
1310
0
  *v = opaque_user_data;
1311
1312
0
  p += ssi->user_alloc;
1313
1314
0
  if (pol->metadata_count) {
1315
0
    h->metadata = (lws_ss_metadata_t *)p;
1316
0
    p += pol->metadata_count * sizeof(lws_ss_metadata_t);
1317
1318
0
    lwsl_cx_info(context, "%s metadata count %d",
1319
0
        pol->streamtype, pol->metadata_count);
1320
0
  }
1321
1322
0
  smd = pol->metadata;
1323
0
  for (n = 0; n < pol->metadata_count; n++) {
1324
0
    h->metadata[n].name = smd->name;
1325
0
    if (n + 1 == pol->metadata_count)
1326
0
      h->metadata[n].next = NULL;
1327
0
    else
1328
0
      h->metadata[n].next = &h->metadata[n + 1];
1329
0
    smd = smd->next;
1330
0
  }
1331
1332
0
  if (ssi->streamtype)
1333
0
    memcpy(p, ssi->streamtype, strlen(ssi->streamtype) + 1);
1334
  /* don't mark accepted ss as being the server */
1335
0
  if (ssi->flags & LWSSSINFLAGS_SERVER)
1336
0
    h->info.flags &= (uint8_t)~LWSSSINFLAGS_SERVER;
1337
0
  h->info.streamtype = p;
1338
1339
0
  lws_pt_lock(pt, __func__);
1340
0
  lws_dll2_add_head(&h->list, &pt->ss_owner);
1341
0
  lws_pt_unlock(pt);
1342
1343
0
  if (ppss)
1344
0
    *ppss = h;
1345
1346
0
  if (ppayload_fmt)
1347
0
    *ppayload_fmt = pol->payload_fmt;
1348
1349
0
  if (ssi->flags & LWSSSINFLAGS_SERVER)
1350
    /*
1351
     * return early for accepted connection flow
1352
     */
1353
0
    return 0;
1354
1355
0
#if defined(LWS_WITH_SYS_SMD)
1356
  /*
1357
   * For a local Secure Streams connection
1358
   */
1359
0
  if (!(ssi->flags & LWSSSINFLAGS_PROXIED) &&
1360
0
      pol == &pol_smd) {
1361
1362
    /*
1363
     * So he has asked to be wired up to SMD over a SS link.
1364
     * Register him as an smd participant in his own right.
1365
     *
1366
     * Just for this case, ssi->manual_initial_tx_credit is used
1367
     * to set the rx class mask (this is part of the SS serialization
1368
     * format as well)
1369
     */
1370
0
    h->u.smd.smd_peer = lws_smd_register(context, h, 0,
1371
0
                 (lws_smd_class_t)ssi->manual_initial_tx_credit,
1372
0
                 lws_smd_ss_cb);
1373
0
    if (!h->u.smd.smd_peer || lws_fi(&h->fic, "ss_create_smd"))
1374
0
      goto fail_creation;
1375
0
    lwsl_cx_info(context, "registered SS SMD");
1376
0
  }
1377
0
#endif
1378
1379
0
#if defined(LWS_WITH_SERVER)
1380
0
  if (h->policy->flags & LWSSSPOLF_SERVER) {
1381
0
    const struct lws_protocols *pprot[3], **ppp = &pprot[0];
1382
0
    struct lws_context_creation_info i;
1383
0
    struct lws_vhost *vho = NULL;
1384
1385
0
    lwsl_cx_info(context, "creating server");
1386
1387
0
    if (h->policy->endpoint &&
1388
0
        h->policy->endpoint[0] == '!') {
1389
      /*
1390
       * There's already a vhost existing that we want to
1391
       * bind to, we don't have to specify and create one.
1392
       *
1393
       * The vhost must enable any protocols that we want.
1394
       */
1395
1396
0
      vho = lws_get_vhost_by_name(context,
1397
0
                &h->policy->endpoint[1]);
1398
0
      if (!vho || lws_fi(&h->fic, "ss_create_vhost")) {
1399
0
        lwsl_err("%s: no vhost %s\n", __func__,
1400
0
            &h->policy->endpoint[1]);
1401
0
        goto fail_creation;
1402
0
      }
1403
1404
0
      goto extant;
1405
0
    }
1406
1407
    /*
1408
     * This streamtype represents a server, we're being asked to
1409
     * instantiate a corresponding vhost for it
1410
     */
1411
1412
0
    memset(&i, 0, sizeof i);
1413
1414
0
    i.iface   = h->policy->endpoint;
1415
0
    i.vhost_name  = h->policy->streamtype;
1416
0
    i.port    = h->policy->port;
1417
1418
0
    if (i.iface && i.iface[0] == '+') {
1419
0
      i.iface++;
1420
0
      i.options |= LWS_SERVER_OPTION_UNIX_SOCK;
1421
0
    }
1422
1423
0
    if (!ss_pcols[h->policy->protocol] ||
1424
0
        lws_fi(&h->fic, "ss_create_pcol")) {
1425
0
      lwsl_err("%s: unsupp protocol", __func__);
1426
0
      goto fail_creation;
1427
0
    }
1428
1429
0
    *ppp++ = ss_pcols[h->policy->protocol]->protocol;
1430
1431
0
#if defined(LWS_ROLE_WS)
1432
0
    if (h->policy->u.http.u.ws.subprotocol)
1433
      /*
1434
       * He names a ws subprotocol, ie, we want to support
1435
       * ss-ws protocol in this vhost
1436
       */
1437
0
      *ppp++ = &protocol_secstream_ws;
1438
1439
0
    i.extensions = context->extensions;
1440
0
#endif
1441
1442
0
    *ppp = NULL;
1443
0
    i.pprotocols = pprot;
1444
1445
0
#if defined(LWS_WITH_TLS)
1446
0
    if (h->policy->flags & LWSSSPOLF_TLS) {
1447
0
      if (!h->policy->trust.server.cert) {
1448
0
        lwsl_ss_err(h, "Policy lacks tls cert");
1449
0
        goto fail_creation;
1450
0
      }
1451
0
      i.options |= LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
1452
0
      i.server_ssl_cert_mem =
1453
0
        h->policy->trust.server.cert->ca_der;
1454
0
      i.server_ssl_cert_mem_len = (unsigned int)
1455
0
        h->policy->trust.server.cert->ca_der_len;
1456
0
      i.server_ssl_private_key_mem =
1457
0
        h->policy->trust.server.key->ca_der;
1458
0
      i.server_ssl_private_key_mem_len = (unsigned int)
1459
0
        h->policy->trust.server.key->ca_der_len;
1460
0
    }
1461
0
#endif
1462
1463
0
    if (!lws_fi(&h->fic, "ss_srv_vh_fail"))
1464
0
      vho = lws_create_vhost(context, &i);
1465
0
    else
1466
0
      vho = NULL;
1467
0
    if (!vho) {
1468
0
      lwsl_cx_err(context, "failed to create vh");
1469
0
      goto fail_creation;
1470
0
    }
1471
1472
0
extant:
1473
1474
    /*
1475
     * Mark this vhost as having to apply ss server semantics to
1476
     * any incoming accepted connection
1477
     */
1478
0
    vho->ss_handle = h;
1479
1480
0
    r = lws_ss_event_helper(h, LWSSSCS_CREATING);
1481
0
    lwsl_cx_info(context, "CREATING returned status %d", (int)r);
1482
0
    if (r == LWSSSSRET_DESTROY_ME ||
1483
0
        lws_fi(&h->fic, "ss_create_destroy_me"))
1484
0
      goto fail_creation;
1485
1486
0
    lwsl_cx_notice(context, "created server %s",
1487
0
        h->policy->streamtype);
1488
1489
0
    return 0;
1490
0
  }
1491
0
#endif
1492
1493
#if defined(LWS_WITH_SECURE_STREAMS_STATIC_POLICY_ONLY)
1494
1495
  /*
1496
   * For static policy case, dynamically ref / instantiate the related
1497
   * trust store and vhost.  We do it by logical ss rather than connection
1498
   * because we don't want to expose the latency of creating the x.509
1499
   * trust store at the first connection.
1500
   *
1501
   * But it might be given the tls linkup takes time anyway, it can move
1502
   * to the ss connect code instead.
1503
   */
1504
1505
  if (!lws_ss_policy_ref_trust_store(context, h->policy, 1 /* do the ref */) ||
1506
      lws_fi(&h->fic, "ss_create_no_ts")) {
1507
    lwsl_err("%s: unable to get vhost / trust store\n", __func__);
1508
    goto fail_creation;
1509
  }
1510
#else
1511
#if defined(LWS_WITH_SECURE_STREAMS_CPP)
1512
        if (!ssi->streamtype &&
1513
      !lws_ss_policy_ref_trust_store(context, h->policy, 1 /* do the ref */)) {
1514
    lwsl_err("%s: unable to get vhost / trust store\n", __func__);
1515
    goto fail_creation;
1516
  }
1517
#endif
1518
0
#endif
1519
1520
0
  r = lws_ss_event_helper(h, LWSSSCS_CREATING);
1521
0
  lwsl_ss_info(h, "CREATING returned status %d", (int)r);
1522
0
  if (r == LWSSSSRET_DESTROY_ME ||
1523
0
      lws_fi(&h->fic, "ss_create_destroy_me"))
1524
0
    goto fail_creation;
1525
1526
0
  n = 0;
1527
0
#if defined(LWS_WITH_SYS_SMD)
1528
0
  if (!(ssi->flags & LWSSSINFLAGS_PROXIED) &&
1529
0
      pol == &pol_smd)
1530
0
    n = 1;
1531
0
#endif
1532
0
#if defined(LWS_WITH_SERVER)
1533
0
  if (h->sink_local_bind)
1534
0
    n = 1;
1535
0
#endif
1536
1537
0
  if (n) {
1538
0
    r = lws_ss_event_helper(h, LWSSSCS_CONNECTING);
1539
0
    if (r || lws_fi(&h->fic, "ss_create_smd_1"))
1540
0
      goto fail_creation;
1541
0
    r = lws_ss_event_helper(h, LWSSSCS_CONNECTED);
1542
0
    if (r || lws_fi(&h->fic, "ss_create_smd_2"))
1543
0
      goto fail_creation;
1544
0
  }
1545
1546
0
  if (
1547
0
#if defined(LWS_WITH_SERVER)
1548
0
      !h->sink_local_bind &&
1549
0
#endif
1550
0
      ((h->policy->flags & LWSSSPOLF_NAILED_UP)
1551
0
#if defined(LWS_WITH_SYS_SMD)
1552
0
    || ((h->policy == &pol_smd) //&&
1553
        //(ssi->flags & LWSSSINFLAGS_PROXIED))
1554
0
        )
1555
0
#endif
1556
0
          )) {
1557
0
    r = _lws_ss_client_connect(h, 0, 0);
1558
0
    if (lws_fi(&h->fic, "ss_create_conn"))
1559
0
      r = LWSSSSRET_DESTROY_ME;
1560
0
    switch (r) {
1561
0
    case LWSSSSRET_OK:
1562
0
      break;
1563
0
    case LWSSSSRET_TX_DONT_SEND:
1564
0
    case LWSSSSRET_DISCONNECT_ME:
1565
0
      if (lws_ss_backoff(h) == LWSSSSRET_DESTROY_ME)
1566
0
        goto fail_creation;
1567
0
      break;
1568
0
    case LWSSSSRET_DESTROY_ME:
1569
0
      goto fail_creation;
1570
0
    }
1571
0
  }
1572
1573
0
  return 0;
1574
1575
0
fail_creation:
1576
1577
0
  if (ppss)
1578
0
    *ppss = NULL;
1579
1580
0
#if defined(LWS_WITH_SERVER)
1581
0
  lws_dll2_remove(&h->sink_bind);
1582
0
#endif
1583
0
  lws_ss_destroy(&h);
1584
1585
0
  return 1;
1586
0
}
1587
1588
void *
1589
lws_ss_to_user_object(struct lws_ss_handle *h)
1590
0
{
1591
0
  return (void *)(h + 1);
1592
0
}
1593
1594
void
1595
lws_ss_destroy(lws_ss_handle_t **ppss)
1596
0
{
1597
0
  struct lws_context_per_thread *pt;
1598
0
#if defined(LWS_WITH_SERVER)
1599
0
  struct lws_vhost *v = NULL;
1600
0
  lws_ss_handle_t *hlb;
1601
0
#endif
1602
0
  lws_ss_handle_t *h = *ppss;
1603
0
  lws_ss_metadata_t *pmd;
1604
1605
0
  if (!h)
1606
0
    return;
1607
1608
0
  lws_service_assert_loop_thread(h->context, h->tsi);
1609
1610
0
  if (h == h->h_in_svc) {
1611
0
    lwsl_err("%s: illegal destroy, return LWSSSSRET_DESTROY_ME instead\n",
1612
0
        __func__);
1613
0
    assert(0);
1614
0
    return;
1615
0
  }
1616
1617
0
  if (h->destroying) {
1618
0
    lwsl_info("%s: reentrant destroy\n", __func__);
1619
0
    return;
1620
0
  }
1621
0
  h->destroying = 1;
1622
1623
0
#if defined(LWS_WITH_CONMON)
1624
0
  if (h->conmon_json)
1625
0
    lws_free_set_NULL(h->conmon_json);
1626
0
#endif
1627
1628
0
  if (h->wsi) {
1629
0
    lwsl_warn("%s: conn->ss->wsi %d %d\n", __func__,
1630
0
        h->wsi->bound_ss_proxy_conn, h->wsi->client_proxy_onward);
1631
1632
0
    if (h->wsi->bound_ss_proxy_conn) {
1633
0
      struct lws_sss_proxy_conn *conn = (struct lws_sss_proxy_conn *)
1634
0
        lws_get_opaque_user_data(h->wsi);
1635
1636
0
      if (!conn)
1637
0
        return;
1638
1639
0
      conn->ss = NULL;
1640
0
    }
1641
1642
    /*
1643
     * Don't let the wsi point to us any more,
1644
     * we (the ss object bound to the wsi) are going away now
1645
     */
1646
0
    lws_set_opaque_user_data(h->wsi, NULL);
1647
0
    lws_set_timeout(h->wsi, 1, LWS_TO_KILL_SYNC);
1648
0
  }
1649
1650
0
#if defined(LWS_WITH_SERVER)
1651
0
  lws_dll2_remove(&h->sink_bind);
1652
0
#endif
1653
1654
  /*
1655
   * if we bound an smd registration to the SS, unregister it
1656
   */
1657
1658
0
#if defined(LWS_WITH_SYS_SMD)
1659
0
  if (h->policy == &pol_smd) {
1660
0
    lws_sul_cancel(&h->u.smd.sul_write);
1661
1662
0
    if (h->u.smd.smd_peer) {
1663
0
      lws_smd_unregister(h->u.smd.smd_peer);
1664
0
      h->u.smd.smd_peer = NULL;
1665
0
    }
1666
0
  }
1667
0
#endif
1668
1669
0
  pt = &h->context->pt[h->tsi];
1670
1671
0
  lws_pt_lock(pt, __func__);
1672
0
  *ppss = NULL;
1673
0
  lws_dll2_remove(&h->list);
1674
0
#if defined(LWS_WITH_FILE_OPS)
1675
0
  lws_sul_cancel(&h->fops_sul);
1676
0
  if (h->fop_fd)
1677
0
    lws_vfs_file_close(&h->fop_fd);
1678
0
#endif
1679
0
#if defined(LWS_WITH_SERVER)
1680
0
  lws_dll2_remove(&h->cli_list);
1681
0
  lws_dll2_remove(&h->sink_bind);
1682
0
  lws_sul_cancel(&h->sul_txreq);
1683
0
  hlb = h->sink_local_bind;
1684
0
  if (hlb) {
1685
0
    h->sink_local_bind = NULL;
1686
0
    lws_ss_destroy(&hlb);
1687
0
  }
1688
0
#endif
1689
0
  lws_dll2_remove(&h->to_list);
1690
1691
0
  lws_sul_cancel(&h->sul_timeout);
1692
1693
  /*
1694
   * for lss, DESTROYING deletes the C++ lss object, making the
1695
   * self-defined h->policy radioactive
1696
   */
1697
1698
0
#if defined(LWS_WITH_SERVER)
1699
0
  if (h->policy && (h->policy->flags & LWSSSPOLF_SERVER))
1700
0
    v = lws_get_vhost_by_name(h->context, h->policy->streamtype);
1701
0
#endif
1702
1703
  /*
1704
   * Since we also come here to unpick create, it's possible we failed
1705
   * the creation before issuing any states, even CREATING.  We should
1706
   * only issue cleanup states on destroy if we previously got as far as
1707
   * issuing CREATING.
1708
   */
1709
1710
0
  if (h->prev_ss_state) {
1711
0
    if (h->ss_dangling_connected)
1712
0
      (void)lws_ss_event_helper(h, LWSSSCS_DISCONNECTED);
1713
1714
0
    (void)lws_ss_event_helper(h, LWSSSCS_DESTROYING);
1715
0
  }
1716
1717
0
  lws_pt_unlock(pt);
1718
1719
  /* in proxy case, metadata value on heap may need cleaning up */
1720
1721
0
  pmd = h->metadata;
1722
0
  while (pmd) {
1723
0
    lwsl_info("%s: pmd %p\n", __func__, pmd);
1724
0
    if (pmd->value_on_lws_heap)
1725
0
      lws_free_set_NULL(pmd->value__may_own_heap);
1726
1727
0
    pmd = pmd->next;
1728
0
  }
1729
1730
#if defined(LWS_WITH_SS_DIRECT_PROTOCOL_STR)
1731
  {
1732
1733
    lws_ss_metadata_t *imd;
1734
1735
    pmd = h->instant_metadata;
1736
1737
    while (pmd) {
1738
      imd = pmd;
1739
      pmd = pmd->next;
1740
1741
      lwsl_info("%s: instant md %p\n", __func__, imd);
1742
      lws_free(imd);
1743
    }
1744
    h->instant_metadata = NULL;
1745
1746
    if (h->imd_ac)
1747
      lwsac_free(&h->imd_ac);
1748
  }
1749
#endif
1750
1751
0
  lws_sul_cancel(&h->sul);
1752
1753
#if defined(LWS_WITH_SECURE_STREAMS_STATIC_POLICY_ONLY)
1754
1755
  /*
1756
   * For static policy case, dynamically ref / instantiate the related
1757
   * trust store and vhost.  We do it by logical ss rather than connection
1758
   * because we don't want to expose the latency of creating the x.509
1759
   * trust store at the first connection.
1760
   *
1761
   * But it might be given the tls linkup takes time anyway, it can move
1762
   * to the ss connect code instead.
1763
   */
1764
1765
  if (h->policy)
1766
    lws_ss_policy_unref_trust_store(h->context, h->policy);
1767
#else
1768
#if defined(LWS_WITH_SECURE_STREAMS_CPP)
1769
  if (!h->info.streamtype || !*(h->info.streamtype))
1770
    lws_ss_policy_unref_trust_store(h->context, h->policy);
1771
#endif
1772
0
#endif
1773
1774
0
#if defined(LWS_WITH_SERVER)
1775
0
  if (v && (h->info.flags & LWSSSINFLAGS_SERVER))
1776
    /*
1777
     * For server, the policy describes a vhost that implements the
1778
     * server, when we take down the ss, we take down the related
1779
     * vhost (if it got that far)
1780
     */
1781
0
    lws_vhost_destroy(v);
1782
0
#endif
1783
1784
#if defined(LWS_WITH_SYS_FAULT_INJECTION)
1785
  lws_fi_destroy(&h->fic);
1786
#endif
1787
1788
#if defined(LWS_WITH_SYS_METRICS)
1789
  /*
1790
   * If any hanging caliper measurement, dump it, and free any tags
1791
   */
1792
  lws_metrics_caliper_report_hist(h->cal_txn, (struct lws *)NULL);
1793
  lws_metrics_tags_destroy(&h->cal_txn.mtags_owner);
1794
#endif
1795
1796
0
  lws_sul_cancel(&h->sul_timeout);
1797
1798
  /* confirm no sul left scheduled in handle or user allocation object */
1799
0
  lws_sul_debug_zombies(h->context, h, sizeof(*h) + h->info.user_alloc,
1800
0
            __func__);
1801
1802
0
  __lws_lc_untag(h->context, &h->lc);
1803
1804
0
  lws_explicit_bzero((void *)h, sizeof(*h) + h->info.user_alloc);
1805
1806
0
  lws_free_set_NULL(h);
1807
0
}
1808
1809
#if defined(LWS_WITH_SERVER)
1810
void
1811
lws_ss_server_ack(struct lws_ss_handle *h, int nack)
1812
0
{
1813
0
  h->txn_resp = nack;
1814
0
  h->txn_resp_set = 1;
1815
0
}
1816
1817
void
1818
lws_ss_server_foreach_client(struct lws_ss_handle *h, lws_sssfec_cb cb,
1819
           void *arg)
1820
0
{
1821
0
  lws_start_foreach_dll_safe(struct lws_dll2 *, d, d1, h->src_list.head) {
1822
0
    struct lws_ss_handle *hh =
1823
0
      lws_container_of(d, struct lws_ss_handle, cli_list);
1824
1825
0
    cb(hh, arg);
1826
1827
0
  } lws_end_foreach_dll_safe(d, d1);
1828
0
}
1829
1830
/*
1831
 * Deal with tx requests between source and accepted sink... h is the guy who
1832
 * requested the write
1833
 */
1834
1835
static void
1836
lws_ss_sink_txreq_cb(lws_sorted_usec_list_t *sul)
1837
0
{
1838
0
  struct lws_ss_handle *h = lws_container_of(sul, struct lws_ss_handle,
1839
0
               sul_txreq);
1840
0
  uint8_t buf[1380 + LWS_PRE];
1841
0
  size_t size = sizeof(buf) - LWS_PRE;
1842
0
  lws_ss_state_return_t r;
1843
0
  int flags = 0;
1844
1845
  /* !!! just let writes happen for now */
1846
1847
0
  assert(h->sink_local_bind);
1848
1849
  /* collect the source tx */
1850
0
  r = h->info.tx(h + 1, 0, buf + LWS_PRE, &size, &flags);
1851
0
  switch (r) {
1852
0
  case LWSSSSRET_OK:
1853
0
    if (!h->sink_local_bind->info.rx) {
1854
0
      lwsl_ss_warn(h->sink_local_bind, "No RX cb");
1855
0
      break;
1856
0
    }
1857
0
    r = h->sink_local_bind->info.rx(&h->sink_local_bind[1],
1858
0
             buf + LWS_PRE, size, flags);
1859
0
    _lws_ss_handle_state_ret_CAN_DESTROY_HANDLE(r, NULL,
1860
0
                  &h->sink_local_bind);
1861
0
    break;
1862
0
  case LWSSSSRET_TX_DONT_SEND:
1863
0
    break;
1864
0
  default:
1865
0
    _lws_ss_handle_state_ret_CAN_DESTROY_HANDLE(r, NULL, &h);
1866
0
    break;
1867
0
  }
1868
0
}
1869
#endif
1870
1871
lws_ss_state_return_t
1872
lws_ss_request_tx(lws_ss_handle_t *h)
1873
0
{
1874
0
  lws_ss_state_return_t r;
1875
1876
0
  r = _lws_ss_request_tx(h);
1877
1878
0
  return r;
1879
0
}
1880
1881
lws_ss_state_return_t
1882
_lws_ss_request_tx(lws_ss_handle_t *h)
1883
0
{
1884
0
  lws_ss_state_return_t r;
1885
1886
  // lwsl_notice("%s: h %p, wsi %p\n", __func__, h, h->wsi);
1887
1888
0
  lws_service_assert_loop_thread(h->context, h->tsi);
1889
1890
0
  if (h->wsi) {
1891
0
    lws_callback_on_writable(h->wsi);
1892
1893
0
    return LWSSSSRET_OK;
1894
0
  }
1895
1896
0
  if (!h->policy) {
1897
    /* avoid crash */
1898
0
    lwsl_err("%s: null policy\n", __func__);
1899
0
    return LWSSSSRET_OK;
1900
0
  }
1901
1902
0
  if (h->policy->flags & LWSSSPOLF_SERVER)
1903
0
    return LWSSSSRET_OK;
1904
1905
0
#if defined(LWS_WITH_SERVER)
1906
0
  if (h->sink_local_bind) {
1907
    /*
1908
     * We are bound to a local sink / source
1909
     */
1910
1911
0
    lwsl_ss_notice(h->sink_local_bind, "Req tx");
1912
1913
0
    lws_sul_schedule(h->context, 0, &h->sink_local_bind->sul_txreq,
1914
0
         lws_ss_sink_txreq_cb, 1);
1915
1916
0
    return LWSSSSRET_OK;
1917
0
  }
1918
0
#endif
1919
1920
  /*
1921
   * there's currently no wsi / connection associated with the ss handle
1922
   */
1923
1924
0
#if defined(LWS_WITH_SYS_SMD)
1925
0
  if (h->policy == &pol_smd) {
1926
    /*
1927
     * He's an _lws_smd... and no wsi... since we're just going
1928
     * to queue it, we could call his tx() right here, but rather
1929
     * than surprise him let's set a sul to do it next time around
1930
     * the event loop
1931
     */
1932
1933
0
    lws_sul_schedule(h->context, 0, &h->u.smd.sul_write,
1934
0
         lws_ss_smd_tx_cb, 1);
1935
1936
0
    return LWSSSSRET_OK;
1937
0
  }
1938
0
#endif
1939
1940
0
  if (h->seqstate != SSSEQ_IDLE &&
1941
0
      h->seqstate != SSSEQ_DO_RETRY)
1942
0
    return LWSSSSRET_OK;
1943
1944
0
  h->seqstate = SSSEQ_TRY_CONNECT;
1945
0
  if (h->prev_ss_state != LWSSSCS_POLL) { /* possible if we were created
1946
             * before we could action it */
1947
0
    r = lws_ss_event_helper(h, LWSSSCS_POLL);
1948
0
    if (r)
1949
0
      return r;
1950
0
  }
1951
1952
  /*
1953
   * Retries operate via lws_ss_request_tx(), explicitly ask for a
1954
   * reconnection to clear the retry limit
1955
   */
1956
0
  r = _lws_ss_client_connect(h, 1, 0);
1957
0
  if (r == LWSSSSRET_DESTROY_ME)
1958
0
    return r;
1959
1960
0
  if (r)
1961
0
    return lws_ss_backoff(h);
1962
1963
0
  return LWSSSSRET_OK;
1964
0
}
1965
1966
lws_ss_state_return_t
1967
lws_ss_request_tx_len(lws_ss_handle_t *h, unsigned long len)
1968
0
{
1969
0
  lws_service_assert_loop_thread(h->context, h->tsi);
1970
1971
0
  if (h->wsi && h->policy &&
1972
0
      (h->policy->protocol == LWSSSP_H1 ||
1973
0
       h->policy->protocol == LWSSSP_H2 ||
1974
0
       h->policy->protocol == LWSSSP_WS))
1975
0
    h->wsi->http.writeable_len = len;
1976
0
  else
1977
0
    h->writeable_len = len;
1978
1979
0
  return lws_ss_request_tx(h);
1980
0
}
1981
1982
/*
1983
 * private helpers
1984
 */
1985
1986
/* used on context destroy when iterating listed lws_ss on a pt */
1987
1988
int
1989
lws_ss_destroy_dll(struct lws_dll2 *d, void *user)
1990
0
{
1991
0
  lws_ss_handle_t *h = lws_container_of(d, lws_ss_handle_t, list);
1992
1993
0
  lws_ss_destroy(&h);
1994
1995
0
  return 0;
1996
0
}
1997
1998
int
1999
lws_ss_cancel_notify_dll(struct lws_dll2 *d, void *user)
2000
0
{
2001
0
  lws_ss_handle_t *h = lws_container_of(d, lws_ss_handle_t, list);
2002
2003
0
  if (lws_ss_event_helper(h, LWSSSCS_EVENT_WAIT_CANCELLED))
2004
0
    lwsl_warn("%s: cancel event ignores return\n", __func__);
2005
2006
0
  return 0;
2007
0
}
2008
2009
struct lws_context *
2010
lws_ss_get_context(struct lws_ss_handle *h)
2011
0
{
2012
0
  return h->context;
2013
0
}
2014
2015
struct lws_vhost *
2016
lws_ss_get_vhost(struct lws_ss_handle *h)
2017
0
{
2018
0
  if (!h->wsi)
2019
0
    return NULL;
2020
0
  return h->wsi->a.vhost;
2021
0
}
2022
2023
2024
const char *
2025
lws_ss_rideshare(struct lws_ss_handle *h)
2026
0
{
2027
0
  if (!h->rideshare)
2028
0
    return h->policy->streamtype;
2029
2030
0
  return h->rideshare->streamtype;
2031
0
}
2032
2033
int
2034
lws_ss_add_peer_tx_credit(struct lws_ss_handle *h, int32_t bump)
2035
0
{
2036
0
  const struct ss_pcols *ssp;
2037
2038
0
  lws_service_assert_loop_thread(h->context, h->tsi);
2039
2040
0
  ssp = ss_pcols[(int)h->policy->protocol];
2041
2042
0
  if (h->wsi && ssp && ssp->tx_cr_add)
2043
0
    return ssp->tx_cr_add(h, bump);
2044
2045
0
  return 0;
2046
0
}
2047
2048
int
2049
lws_ss_get_est_peer_tx_credit(struct lws_ss_handle *h)
2050
0
{
2051
0
  const struct ss_pcols *ssp;
2052
2053
0
  lws_service_assert_loop_thread(h->context, h->tsi);
2054
2055
0
  ssp = ss_pcols[(int)h->policy->protocol];
2056
2057
0
  if (h->wsi && ssp && ssp->tx_cr_add)
2058
0
    return ssp->tx_cr_est(h);
2059
2060
0
  return 0;
2061
0
}
2062
2063
/*
2064
 * protocol-independent handler for ss timeout
2065
 */
2066
2067
static void
2068
lws_ss_to_cb(lws_sorted_usec_list_t *sul)
2069
0
{
2070
0
  lws_ss_handle_t *h = lws_container_of(sul, lws_ss_handle_t, sul_timeout);
2071
0
  lws_ss_state_return_t r;
2072
2073
0
  r = lws_ss_event_helper(h, LWSSSCS_TIMEOUT);
2074
0
  if (r != LWSSSSRET_DISCONNECT_ME && r != LWSSSSRET_DESTROY_ME)
2075
0
    return;
2076
2077
0
  if (h->wsi)
2078
0
    lws_set_timeout(h->wsi, 1, LWS_TO_KILL_ASYNC);
2079
2080
0
  _lws_ss_handle_state_ret_CAN_DESTROY_HANDLE(r, h->wsi, &h);
2081
0
}
2082
2083
2084
void
2085
lws_ss_start_timeout(struct lws_ss_handle *h, unsigned int timeout_ms)
2086
0
{
2087
0
  lws_service_assert_loop_thread(h->context, h->tsi);
2088
2089
0
  if (!timeout_ms && !h->policy->timeout_ms)
2090
0
    return;
2091
2092
2093
0
  lws_sul_schedule(h->context, 0, &h->sul_timeout, lws_ss_to_cb,
2094
0
       (timeout_ms ? timeout_ms : h->policy->timeout_ms) *
2095
0
       LWS_US_PER_MS);
2096
0
}
2097
2098
void
2099
lws_ss_cancel_timeout(struct lws_ss_handle *h)
2100
0
{
2101
0
  lws_service_assert_loop_thread(h->context, h->tsi);
2102
0
  lws_sul_cancel(&h->sul_timeout);
2103
0
}
2104
2105
void
2106
lws_ss_change_handlers(struct lws_ss_handle *h,
2107
  lws_ss_state_return_t (*rx)(void *userobj, const uint8_t *buf,
2108
            size_t len, int flags),
2109
  lws_ss_state_return_t (*tx)(void *userobj, lws_ss_tx_ordinal_t ord,
2110
            uint8_t *buf, size_t *len, int *flags),
2111
  lws_ss_state_return_t (*state)(void *userobj, void *h_src /* ss handle type */,
2112
               lws_ss_constate_t state,
2113
               lws_ss_tx_ordinal_t ack))
2114
0
{
2115
0
  if (rx)
2116
0
    h->info.rx = rx;
2117
0
  if (tx)
2118
0
    h->info.tx = tx;
2119
0
  if (state)
2120
0
    h->info.state = state;
2121
0
}
2122
2123
const char *
2124
lws_ss_tag(struct lws_ss_handle *h)
2125
0
{
2126
0
  if (!h)
2127
0
    return "[null ss]";
2128
0
  return lws_lc_tag(&h->lc);
2129
0
}
2130
2131
struct lws_log_cx *
2132
lwsl_ss_get_cx(struct lws_ss_handle *ss)
2133
0
{
2134
0
  if (!ss)
2135
0
    return NULL;
2136
2137
0
  return ss->lc.log_cx;
2138
0
}
2139
2140
void
2141
lws_log_prepend_ss(struct lws_log_cx *cx, void *obj, char **p, char *e)
2142
0
{
2143
0
  struct lws_ss_handle *h = (struct lws_ss_handle *)obj;
2144
2145
0
  *p += lws_snprintf(*p, lws_ptr_diff_size_t(e, (*p)), "%s: ",
2146
0
      lws_ss_tag(h));
2147
0
}
2148
2149
void
2150
lws_ss_validity_confirmed(struct lws_ss_handle *h)
2151
0
{
2152
0
  if (h->wsi)
2153
0
    lws_validity_confirmed(h->wsi);
2154
0
}
2155
2156
2157
#if defined(_DEBUG)
2158
void
2159
lws_ss_assert_extant(struct lws_context *cx, int tsi, struct lws_ss_handle *h)
2160
0
{
2161
0
  struct lws_context_per_thread *pt = &cx->pt[tsi];
2162
2163
0
  lws_start_foreach_dll_safe(struct lws_dll2 *, d, d1, pt->ss_owner.head) {
2164
0
    struct lws_ss_handle *h1 = lws_container_of(d,
2165
0
            struct lws_ss_handle, list);
2166
2167
0
    if (h == h1)
2168
0
      return; /* okay */
2169
2170
0
  } lws_end_foreach_dll_safe(d, d1);
2171
2172
  /*
2173
   * The ss handle is not listed in the pt ss handle owner...
2174
   */
2175
2176
0
  assert(0);
2177
0
}
2178
#endif
2179
2180
void
2181
lws_ss_dump_extant(struct lws_context *cx, int tsi)
2182
0
{
2183
0
#if (_LWS_ENABLED_LOGS & LLL_NOTICE)
2184
0
  struct lws_context_per_thread *pt = &cx->pt[tsi];
2185
2186
0
  lwsl_cx_notice(cx, "pt%d SS Rollcall (%d members)", tsi, (int)pt->ss_owner.count);
2187
2188
0
  lws_start_foreach_dll_safe(struct lws_dll2 *, d, d1, pt->ss_owner.head) {
2189
0
    struct lws_ss_handle *h = lws_container_of(d,
2190
0
            struct lws_ss_handle, list);
2191
2192
0
    lwsl_ss_notice(h, "rollcall");
2193
0
  } lws_end_foreach_dll_safe(d, d1);
2194
0
#endif
2195
0
}
2196