Coverage Report

Created: 2026-03-19 06:14

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libwebsockets/lib/core/libwebsockets.c
Line
Count
Source
1
/*
2
 * libwebsockets - small server side websockets and web server implementation
3
 *
4
 * Copyright (C) 2010 - 2020 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
#ifdef LWS_HAVE_SYS_TYPES_H
28
#include <sys/types.h>
29
#endif
30
#include <signal.h>
31
32
void
33
lws_ser_wu16be(uint8_t *b, uint16_t u)
34
0
{
35
0
  *b++ = (uint8_t)(u >> 8);
36
0
  *b = (uint8_t)u;
37
0
}
38
39
void
40
lws_ser_wu32be(uint8_t *b, uint32_t u32)
41
0
{
42
0
  *b++ = (uint8_t)(u32 >> 24);
43
0
  *b++ = (uint8_t)(u32 >> 16);
44
0
  *b++ = (uint8_t)(u32 >> 8);
45
0
  *b = (uint8_t)u32;
46
0
}
47
48
void
49
lws_ser_wu64be(uint8_t *b, uint64_t u64)
50
0
{
51
0
  lws_ser_wu32be(b, (uint32_t)(u64 >> 32));
52
0
  lws_ser_wu32be(b + 4, (uint32_t)u64);
53
0
}
54
55
uint16_t
56
lws_ser_ru16be(const uint8_t *b)
57
0
{
58
0
  return (uint16_t)((b[0] << 8) | b[1]);
59
0
}
60
61
uint32_t
62
lws_ser_ru32be(const uint8_t *b)
63
0
{
64
0
  return (unsigned int)((b[0] << 24) | (b[1] << 16) | (b[2] << 8) | b[3]);
65
0
}
66
67
uint64_t
68
lws_ser_ru64be(const uint8_t *b)
69
0
{
70
0
  return (((uint64_t)lws_ser_ru32be(b)) << 32) | lws_ser_ru32be(b + 4);
71
0
}
72
73
int
74
lws_vbi_encode(uint64_t value, void *buf)
75
0
{
76
0
  uint8_t *p = (uint8_t *)buf, b;
77
78
0
  if (value > 0xfffffff) {
79
0
    assert(0);
80
0
    return -1;
81
0
  }
82
83
0
  do {
84
0
    b = value & 0x7f;
85
0
    value >>= 7;
86
0
    if (value)
87
0
      *p++ = (0x80 | b);
88
0
    else
89
0
      *p++ = b;
90
0
  } while (value);
91
92
0
  return lws_ptr_diff(p, buf);
93
0
}
94
95
int
96
lws_vbi_decode(const void *buf, uint64_t *value, size_t len)
97
0
{
98
0
  const uint8_t *p = (const uint8_t *)buf, *end = p + len;
99
0
  uint64_t v = 0;
100
0
  int s = 0;
101
102
0
  while (p < end) {
103
0
    v |= (((uint64_t)(*p)) & 0x7f) << s;
104
0
    if (*p & 0x80) {
105
0
      *value = v;
106
107
0
      return lws_ptr_diff(p, buf);
108
0
    }
109
0
    s += 7;
110
0
    if (s >= 64)
111
0
      return 0;
112
0
    p++;
113
0
  }
114
115
0
  return 0;
116
0
}
117
118
signed char char_to_hex(const char c)
119
0
{
120
0
  if (c >= '0' && c <= '9')
121
0
    return (signed char)(c - '0');
122
123
0
  if (c >= 'a' && c <= 'f')
124
0
    return (signed char)(c - 'a' + 10);
125
126
0
  if (c >= 'A' && c <= 'F')
127
0
    return (signed char)(c - 'A' + 10);
128
129
0
  return (signed char)-1;
130
0
}
131
132
int
133
lws_hex_len_to_byte_array(const char *h, size_t hlen, uint8_t *dest, int max)
134
0
{
135
0
  uint8_t *odest = dest;
136
137
0
  while (max-- && hlen > 1) {
138
0
    int t = char_to_hex(*h++), t1;
139
140
0
    if (!*h || t < 0)
141
0
      return -1;
142
143
0
    t1 = char_to_hex(*h++);
144
0
    if (t1 < 0)
145
0
      return -1;
146
147
0
    *dest++ = (uint8_t)((t << 4) | t1);
148
0
    hlen -= 2;
149
0
  }
150
151
0
  if (max < -1)
152
0
    return -1;
153
154
0
  return lws_ptr_diff(dest, odest);
155
0
}
156
157
int
158
lws_hex_to_byte_array(const char *h, uint8_t *dest, int max)
159
0
{
160
0
  return lws_hex_len_to_byte_array(h, strlen(h), dest, max);
161
0
}
162
163
static char *hexch = "0123456789abcdef";
164
165
void
166
lws_hex_from_byte_array(const uint8_t *src, size_t slen, char *dest, size_t len)
167
0
{
168
0
  char *end = &dest[len - 1];
169
170
0
  while (slen-- && dest != end) {
171
0
    uint8_t b = *src++;
172
0
    *dest++ = hexch[b >> 4];
173
0
    if (dest == end)
174
0
      break;
175
0
    *dest++ = hexch[b & 0xf];
176
0
  }
177
178
0
  *dest = '\0';
179
0
}
180
181
int
182
lws_hex_random(struct lws_context *context, char *dest, size_t len)
183
0
{
184
0
  size_t n = ((len - 1) / 2) + 1;
185
0
  uint8_t b, *r = (uint8_t *)dest + len - n;
186
187
0
  if (lws_get_random(context, r, n) != n)
188
0
    return 1;
189
190
0
  while (len >= 3) {
191
0
    b = *r++;
192
0
    *dest++ = hexch[b >> 4];
193
0
    *dest++ = hexch[b & 0xf];
194
0
    len -= 2;
195
0
  }
196
197
0
  if (len == 2)
198
0
    *dest++ = hexch[(*r) >> 4];
199
200
0
  *dest = '\0';
201
202
0
  return 0;
203
0
}
204
205
#if defined(_DEBUG)
206
void
207
lws_assert_fourcc(uint32_t fourcc, uint32_t expected)
208
0
{
209
0
  if (fourcc == expected)
210
0
    return;
211
212
0
  lwsl_err("%s: fourcc mismatch, expected %c%c%c%c, saw %c%c%c%c\n",
213
0
      __func__, (int)(expected >> 24), (int)((expected >> 16) & 0xff),
214
0
      (int)((expected >> 8) & 0xff),(int)( expected & 0xff),
215
0
      (int)(fourcc >> 24), (int)((fourcc >> 16) & 0xff),
216
0
      (int)((fourcc >> 8) & 0xff), (int)(fourcc & 0xff));
217
218
0
  assert(0);
219
0
}
220
#endif
221
222
#if !defined(LWS_PLAT_OPTEE) && !defined(LWS_PLAT_BAREMETAL)
223
224
#if defined(LWS_WITH_FILE_OPS)
225
int lws_open(const char *__file, int __oflag, ...)
226
0
{
227
0
  va_list ap;
228
0
  int n;
229
230
0
  va_start(ap, __oflag);
231
0
  if (((__oflag & O_CREAT) == O_CREAT)
232
#if defined(O_TMPFILE)
233
    || ((__oflag & O_TMPFILE) == O_TMPFILE)
234
#endif
235
0
  )
236
#if defined(WIN32)
237
    /* last arg is really a mode_t.  But windows... */
238
    n = open(__file, __oflag, va_arg(ap, uint32_t));
239
#else
240
    /* ... and some other toolchains...
241
     *
242
     * error: second argument to 'va_arg' is of promotable type 'mode_t'
243
     * (aka 'unsigned short'); this va_arg has undefined behavior because
244
     * arguments will be promoted to 'int'
245
     */
246
0
    n = open(__file, __oflag, (mode_t)va_arg(ap, unsigned int));
247
0
#endif
248
0
  else
249
0
    n = open(__file, __oflag);
250
0
  va_end(ap);
251
252
0
  if (n != -1 && lws_plat_apply_FD_CLOEXEC(n)) {
253
0
    close(n);
254
255
0
    return -1;
256
0
  }
257
258
0
  return n;
259
0
}
260
#endif
261
#endif
262
263
int
264
lws_pthread_self_to_tsi(struct lws_context *context)
265
0
{
266
#if defined(LWS_WITH_NETWORK) && LWS_MAX_SMP > 1
267
  pthread_t ps = pthread_self();
268
  struct lws_context_per_thread *pt = &context->pt[0];
269
  int n;
270
271
  /* case that we have SMP build, but don't use it */
272
  if (context->count_threads == 1)
273
    return 0;
274
275
  for (n = 0; n < context->count_threads; n++) {
276
    if (pthread_equal(ps, pt->self))
277
      return n;
278
    pt++;
279
  }
280
281
  return -1;
282
#else
283
0
  return 0;
284
0
#endif
285
0
}
286
287
void *
288
lws_context_user(struct lws_context *context)
289
0
{
290
0
  return context->user_space;
291
0
}
292
293
void
294
lws_explicit_bzero(void *p, size_t len)
295
0
{
296
0
  volatile uint8_t *vp = p;
297
298
0
  while (len--)
299
0
    *vp++ = 0;
300
0
}
301
302
#if !(defined(LWS_PLAT_OPTEE) && !defined(LWS_WITH_NETWORK))
303
304
/**
305
 * lws_now_secs() - seconds since 1970-1-1
306
 *
307
 */
308
unsigned long
309
lws_now_secs(void)
310
0
{
311
0
  struct timeval tv;
312
313
0
  gettimeofday(&tv, NULL);
314
315
0
  return (unsigned long)tv.tv_sec;
316
0
}
317
318
#endif
319
320
#if defined(LWS_WITH_SERVER)
321
const char *
322
lws_canonical_hostname(struct lws_context *context)
323
0
{
324
0
  return (const char *)context->canonical_hostname;
325
0
}
326
#endif
327
328
int
329
lws_get_count_threads(struct lws_context *context)
330
0
{
331
0
  return context->count_threads;
332
0
}
333
334
static const unsigned char e0f4[] = {
335
  0xa0 | ((2 - 1) << 2) | 1, /* e0 */
336
  0x80 | ((4 - 1) << 2) | 1, /* e1 */
337
  0x80 | ((4 - 1) << 2) | 1, /* e2 */
338
  0x80 | ((4 - 1) << 2) | 1, /* e3 */
339
  0x80 | ((4 - 1) << 2) | 1, /* e4 */
340
  0x80 | ((4 - 1) << 2) | 1, /* e5 */
341
  0x80 | ((4 - 1) << 2) | 1, /* e6 */
342
  0x80 | ((4 - 1) << 2) | 1, /* e7 */
343
  0x80 | ((4 - 1) << 2) | 1, /* e8 */
344
  0x80 | ((4 - 1) << 2) | 1, /* e9 */
345
  0x80 | ((4 - 1) << 2) | 1, /* ea */
346
  0x80 | ((4 - 1) << 2) | 1, /* eb */
347
  0x80 | ((4 - 1) << 2) | 1, /* ec */
348
  0x80 | ((2 - 1) << 2) | 1, /* ed */
349
  0x80 | ((4 - 1) << 2) | 1, /* ee */
350
  0x80 | ((4 - 1) << 2) | 1, /* ef */
351
  0x90 | ((3 - 1) << 2) | 2, /* f0 */
352
  0x80 | ((4 - 1) << 2) | 2, /* f1 */
353
  0x80 | ((4 - 1) << 2) | 2, /* f2 */
354
  0x80 | ((4 - 1) << 2) | 2, /* f3 */
355
  0x80 | ((1 - 1) << 2) | 2, /* f4 */
356
357
  0,         /* s0 */
358
  0x80 | ((4 - 1) << 2) | 0, /* s2 */
359
  0x80 | ((4 - 1) << 2) | 1, /* s3 */
360
};
361
362
int
363
lws_check_byte_utf8(unsigned char state, unsigned char c)
364
0
{
365
0
  unsigned char s = state;
366
367
0
  if (!s) {
368
0
    if (c >= 0x80) {
369
0
      if (c < 0xc2 || c > 0xf4)
370
0
        return -1;
371
0
      if (c < 0xe0)
372
0
        return 0x80 | ((4 - 1) << 2);
373
0
      else
374
0
        return e0f4[c - 0xe0];
375
0
    }
376
377
0
    return s;
378
0
  }
379
0
  if (c < (s & 0xf0) || c >= (s & 0xf0) + 0x10 + ((s << 2) & 0x30))
380
0
    return -1;
381
382
0
  return e0f4[21 + (s & 3)];
383
0
}
384
385
int
386
lws_check_utf8(unsigned char *state, unsigned char *buf, size_t len)
387
0
{
388
0
  unsigned char s = *state;
389
390
0
  while (len--) {
391
0
    unsigned char c = *buf++;
392
393
0
    if (!s) {
394
0
      if (c >= 0x80) {
395
0
        if (c < 0xc2 || c > 0xf4)
396
0
          return 1;
397
0
        if (c < 0xe0)
398
0
          s = 0x80 | ((4 - 1) << 2);
399
0
        else
400
0
          s = e0f4[c - 0xe0];
401
0
      }
402
0
    } else {
403
0
      if (c < (s & 0xf0) ||
404
0
          c >= (s & 0xf0) + 0x10 + ((s << 2) & 0x30))
405
0
        return 1;
406
0
      s = e0f4[21 + (s & 3)];
407
0
    }
408
0
  }
409
410
0
  *state = s;
411
412
0
  return 0;
413
0
}
414
415
416
char *
417
lws_strdup(const char *s)
418
0
{
419
0
  size_t l = strlen(s) + 1;
420
0
  char *d = lws_malloc(l, "strdup");
421
422
0
  if (d)
423
0
    memcpy(d, s, l);
424
425
0
  return d;
426
0
}
427
428
const char *
429
lws_nstrstr(const char *buf, size_t len, const char *name, size_t nl)
430
0
{
431
0
  const char *end = buf + len - nl + 1;
432
0
  size_t n;
433
434
0
  if (nl > len)
435
    /* it cannot be found if the needle is longer than the haystack */
436
0
    return NULL;
437
438
0
  while (buf < end) {
439
0
    if (*buf != name[0]) {
440
0
      buf++;
441
0
      continue;
442
0
    }
443
444
0
    if (nl == 1)
445
      /* single char match, we are done */
446
0
      return buf;
447
448
0
    if (buf[nl - 1] == name[nl - 1]) {
449
      /*
450
       * This is looking interesting then... the first
451
       * and last chars match, let's check the insides
452
       */
453
0
      n = 1;
454
0
      while (n < nl && buf[n] == name[n])
455
0
        n++;
456
457
0
      if (n == nl)
458
        /* it's a hit */
459
0
        return buf;
460
0
    }
461
462
0
    buf++;
463
0
  }
464
465
0
  return NULL;
466
0
}
467
468
/*
469
 * name wants to be something like "\"myname\":"
470
 */
471
472
const char *
473
lws_json_simple_find(const char *buf, size_t len, const char *name, size_t *alen)
474
0
{
475
0
  size_t nl = strlen(name);
476
0
  const char *np = lws_nstrstr(buf, len, name, nl),
477
0
       *end = buf + len, *as;
478
0
  int qu = 0;
479
480
0
  if (!np)
481
0
    return NULL;
482
483
0
  np += nl;
484
485
0
  while (np < end && (*np == ' ' || *np == '\t'))
486
0
    np++;
487
488
0
  if (np >= end)
489
0
    return NULL;
490
491
  /*
492
   * The arg could be lots of things after "name": with JSON, commonly a
493
   * string like "mystring", true, false, null, [...] or {...} ... we want
494
   * to handle common, simple cases cheaply with this; the user can choose
495
   * a full JSON parser like lejp if it's complicated.  So if no opening
496
   * quote, return until a terminator like , ] }.  If there's an opening
497
   * quote, return until closing quote, handling escaped quotes.
498
   */
499
500
0
  if (*np == '\"') {
501
0
    qu = 1;
502
0
    np++;
503
0
  }
504
505
0
  as = np;
506
0
  while (np < end &&
507
0
         (!qu || *np != '\"') && /* end quote is EOT if quoted */
508
0
         (qu || (*np != '}' && *np != ']' && *np != ',')) /* delimiters */
509
0
  ) {
510
0
    if (qu && *np == '\\') /* skip next char if quoted escape */
511
0
      np++;
512
0
    np++;
513
0
  }
514
515
0
  *alen = (unsigned int)lws_ptr_diff(np, as);
516
517
0
  return as;
518
0
}
519
520
int
521
lws_json_simple_strcmp(const char *buf, size_t len, const char *name,
522
           const char *comp)
523
0
{
524
0
  size_t al;
525
0
  const char *hit = lws_json_simple_find(buf, len, name, &al);
526
527
0
  if (!hit)
528
0
    return -1;
529
530
0
  if (al != strlen(comp))
531
0
    return -1;
532
533
0
  return strncmp(hit, comp, al);
534
0
}
535
536
static const char *hex = "0123456789ABCDEF";
537
538
const char *
539
lws_sql_purify(char *escaped, const char *string, size_t len)
540
0
{
541
0
  const char *p = string;
542
0
  char *q = escaped;
543
544
0
  while (*p && len-- > 2) {
545
0
    if (*p == '\'') {
546
0
      *q++ = '\'';
547
0
      *q++ = '\'';
548
0
      len --;
549
0
      p++;
550
0
    } else
551
0
      *q++ = *p++;
552
0
  }
553
0
  *q = '\0';
554
555
0
  return escaped;
556
0
}
557
558
int
559
lws_sql_purify_len(const char *p)
560
0
{
561
0
  int olen = 0;
562
563
0
  while (*p) {
564
0
    if (*p++ == '\'')
565
0
      olen++;
566
0
    olen++;
567
0
  }
568
569
0
  return olen;
570
0
}
571
572
const char *
573
lws_json_purify(char *escaped, const char *string, int len, int *in_used)
574
0
{
575
0
  const char *p = string;
576
0
  char *q = escaped;
577
578
0
  if (!p) {
579
0
    escaped[0] = '\0';
580
0
    return escaped;
581
0
  }
582
583
0
  while (*p && len-- > 6) {
584
0
    if (*p == '\t') {
585
0
      p++;
586
0
      *q++ = '\\';
587
0
      *q++ = 't';
588
0
      continue;
589
0
    }
590
591
0
    if (*p == '\n') {
592
0
      p++;
593
0
      *q++ = '\\';
594
0
      *q++ = 'n';
595
0
      continue;
596
0
    }
597
598
0
    if (*p == '\r') {
599
0
      p++;
600
0
      *q++ = '\\';
601
0
      *q++ = 'r';
602
0
      continue;
603
0
    }
604
605
0
    if (*p == '\\') {
606
0
      p++;
607
0
      *q++ = '\\';
608
0
      *q++ = '\\';
609
0
      continue;
610
0
    }
611
612
0
    if (*p == '\"' || *p < 0x20) {
613
0
      *q++ = '\\';
614
0
      *q++ = 'u';
615
0
      *q++ = '0';
616
0
      *q++ = '0';
617
0
      *q++ = hex[((*p) >> 4) & 15];
618
0
      *q++ = hex[(*p) & 15];
619
0
      len -= 5;
620
0
      p++;
621
0
    } else
622
0
      *q++ = *p++;
623
0
  }
624
0
  *q = '\0';
625
626
0
  if (in_used)
627
0
    *in_used = lws_ptr_diff(p, string);
628
629
0
  return escaped;
630
0
}
631
632
int
633
lws_json_purify_len(const char *string)
634
0
{
635
0
  int len = 0;
636
0
  const char *p = string;
637
638
0
  while (*p) {
639
0
    if (*p == '\t' || *p == '\n' || *p == '\r') {
640
0
      p++;
641
0
      len += 2;
642
0
      continue;
643
0
    }
644
645
0
    if (*p == '\"' || *p == '\\' || *p < 0x20) {
646
0
      len += 6;
647
0
      p++;
648
0
      continue;
649
0
    }
650
0
    p++;
651
0
    len++;
652
0
  }
653
654
0
  return len;
655
0
}
656
657
void
658
lws_filename_purify_inplace(char *filename)
659
0
{
660
0
  while (*filename) {
661
662
0
    if (*filename == '.' && filename[1] == '.') {
663
0
      *filename = '_';
664
0
      filename[1] = '_';
665
0
    }
666
667
0
    if (*filename == ':' ||
668
0
#if !defined(WIN32)
669
0
        *filename == '\\' ||
670
0
#endif
671
0
        *filename == '$' ||
672
0
        *filename == '%')
673
0
      *filename = '_';
674
675
0
    filename++;
676
0
  }
677
0
}
678
679
const char *
680
lws_urlencode(char *escaped, const char *string, int len)
681
0
{
682
0
  const char *p = string;
683
0
  char *q = escaped;
684
685
0
  while (*p && len-- > 3) {
686
0
    if (*p == ' ') {
687
0
      *q++ = '+';
688
0
      p++;
689
0
      continue;
690
0
    }
691
0
    if ((*p >= '0' && *p <= '9') ||
692
0
        (*p >= 'A' && *p <= 'Z') ||
693
0
        (*p >= 'a' && *p <= 'z')) {
694
0
      *q++ = *p++;
695
0
      continue;
696
0
    }
697
0
    *q++ = '%';
698
0
    *q++ = hex[(*p >> 4) & 0xf];
699
0
    *q++ = hex[*p & 0xf];
700
701
0
    len -= 2;
702
0
    p++;
703
0
  }
704
0
  *q = '\0';
705
706
0
  return escaped;
707
0
}
708
709
int
710
lws_urldecode(char *string, const char *escaped, int len)
711
0
{
712
0
  int state = 0, n;
713
0
  char sum = 0;
714
715
0
  while (*escaped && len) {
716
0
    switch (state) {
717
0
    case 0:
718
0
      if (*escaped == '%') {
719
0
        state++;
720
0
        escaped++;
721
0
        continue;
722
0
      }
723
0
      if (*escaped == '+') {
724
0
        escaped++;
725
0
        *string++ = ' ';
726
0
        len--;
727
0
        continue;
728
0
      }
729
0
      *string++ = *escaped++;
730
0
      len--;
731
0
      break;
732
0
    case 1:
733
0
      n = char_to_hex(*escaped);
734
0
      if (n < 0)
735
0
        return -1;
736
0
      escaped++;
737
0
      sum = (char)(n << 4);
738
0
      state++;
739
0
      break;
740
741
0
    case 2:
742
0
      n = char_to_hex(*escaped);
743
0
      if (n < 0)
744
0
        return -1;
745
0
      escaped++;
746
0
      *string++ = (char)(sum | n);
747
0
      len--;
748
0
      state = 0;
749
0
      break;
750
0
    }
751
752
0
  }
753
0
  *string = '\0';
754
755
0
  return 0;
756
0
}
757
758
/*
759
 * Copy the url formof rel into dest, using base to fill in missing context
760
 *
761
 * If base is https://x.com/y/z.html
762
 *
763
 *   a.html               -> https://x.com/y/a/html
764
 *   ../b.html            -> https://x.com/b.html
765
 *   /c.html              -> https://x.com/c.html
766
 *   https://y.com/a.html -> https://y.com/a.html
767
 *
768
 * If base is file:///path/to/origin/basis
769
 *
770
 *   a.html               -> file:///path/to/origin/basis/a.html
771
 *   ../b.html            -> file:///path/to/origin/basis/../b.html
772
 *   /c.html              -> file:///path/to/origin/basis/c.html
773
 */
774
775
int
776
lws_http_rel_to_url(char *dest, size_t len, const char *base, const char *rel)
777
0
{
778
0
  size_t n = 0, ps = 0;
779
0
  char d = 0;
780
781
  // lwsl_err("%s: base %s, rel %s\n", __func__, base, rel);
782
783
0
  if (rel[0] == '/' && rel[1] == '/') {
784
0
    lws_snprintf(dest, len, "https:%s", rel);
785
786
0
    return 0;
787
0
  }
788
789
0
  if (!strncmp(rel, "https://", 8) ||
790
0
      !strncmp(rel, "http://", 7) ||
791
0
      !strncmp(rel, "file://", 7)) {
792
    /* rel is already a full url, just copy it */
793
0
    lws_strncpy(dest, rel, len);
794
0
    return 0;
795
0
  }
796
797
0
  if (!strncmp(base, "file://", 7)) {
798
0
    n = strlen(base);
799
0
    while (n > 7) {
800
0
      if (base[n - 1] == '/' && base[n - 2] != '/') {
801
0
        n--;
802
0
        break;
803
0
      }
804
0
      n--;
805
0
    }
806
0
    if (*rel == '/')
807
0
      rel++;
808
0
    lws_snprintf(dest, len, "%.*s/%s", (int)n, base, rel);
809
0
    return 0;
810
0
  }
811
812
  /* we're going to be using the first part of base at least */
813
814
0
  while (n < len - 2 && base[n]) {
815
0
    dest[n] = base[n];
816
0
    if (d && base[n] == '/') {
817
0
      n++;
818
0
      ps = n;
819
      //if (rel[0] == '/') {
820
0
        break;
821
      //}
822
0
    }
823
0
    if (n && base[n] == '/' && base[n - 1] == '/')
824
0
      d = 1;
825
0
    n++;
826
0
  }
827
828
0
  if (!n || n >= len - 2)
829
0
    return 1;
830
831
  /* if we did not have a '/' after the hostname, add one */
832
0
  if (dest[n - 1] != '/') {
833
0
    ps = n;
834
0
    dest[n++] = '/';
835
0
  }
836
837
  /* is rel an absolute path we should just use with the hostname? */
838
0
  if (rel[0] != '/') {
839
840
    /*
841
     * Apply the rest of the basename, without the file part,
842
     * end with last / if any
843
     */
844
845
0
    ps = n;
846
0
    while (n < len - 2 && base[n]) {
847
0
      dest[n] = base[n];
848
0
      n++;
849
0
      if (base[n] == '/')
850
0
        ps = n;
851
0
    }
852
853
0
    n = ps;
854
855
0
    if (n >= len - 2)
856
0
      return 1;
857
858
    /* if we did not have a '/' after the base path, add one */
859
0
    if (dest[n - 1] != '/')
860
0
      dest[n++] = '/';
861
0
  }
862
863
  /* append rel */
864
865
0
  if (len - n < strlen(rel) + 2)
866
0
    return 1;
867
868
0
  lws_strncpy(dest + n, rel, len - n);
869
870
0
  return 0;
871
0
}
872
873
int
874
lws_finalize_startup(struct lws_context *context, const char *where)
875
0
{
876
0
  if (lws_check_opt(context->options, LWS_SERVER_OPTION_EXPLICIT_VHOSTS)) {
877
0
    lwsl_info("%s: dropping app privs: %s\n", __func__, where);
878
0
#if defined(LWS_WITH_SYS_STATE) && defined(LWS_WITH_NETWORK)
879
0
    lws_state_transition(&context->mgr_system, LWS_SYSTATE_PRE_PRIV_DROP);
880
0
#endif
881
882
0
    if (lws_plat_drop_app_privileges(context, 1))
883
0
      return 1;
884
0
  }
885
886
0
  return 0;
887
0
}
888
889
#if !defined(LWS_PLAT_FREERTOS)
890
void
891
lws_get_effective_uid_gid(struct lws_context *context, uid_t *uid, gid_t *gid)
892
0
{
893
0
  *uid = context->uid;
894
0
  *gid = context->gid;
895
0
}
896
#endif
897
898
int
899
lws_snprintf(char *str, size_t size, const char *format, ...)
900
33
{
901
33
  va_list ap;
902
33
  int n;
903
904
33
  if (!str || !size)
905
0
    return 0;
906
907
33
  va_start(ap, format);
908
33
  n = vsnprintf(str, size, format, ap);
909
33
  va_end(ap);
910
911
33
  if (n >= (int)size)
912
0
    return (int)size;
913
914
33
  return n;
915
33
}
916
917
char *
918
lws_strncpy(char *dest, const char *src, size_t size)
919
0
{
920
0
  strncpy(dest, src, size - 1);
921
0
  dest[size - 1] = '\0';
922
923
0
  return dest;
924
0
}
925
926
int
927
lws_timingsafe_bcmp(const void *a, const void *b, uint32_t len)
928
0
{
929
0
  const uint8_t *pa = a, *pb = b;
930
0
  uint8_t sum = 0;
931
932
0
  while (len--)
933
0
    sum |= (uint8_t)(*pa++ ^ *pb++);
934
935
0
  return sum;
936
0
}
937
938
lws_tokenize_elem
939
lws_tokenize(struct lws_tokenize *ts)
940
0
{
941
0
  const char *rfc7230_delims = "(),/:;<=>?@[\\]{}";
942
0
  char c, flo = 0, d_minus = '-', d_dot = '.', d_star = '*', s_minus = '\0',
943
0
       s_dot = '\0', s_star = '\0', d_eq = '=', s_eq = '\0', d_plus = '+', s_plus = '\0', skipping = 0;
944
0
  signed char num = (ts->flags & LWS_TOKENIZE_F_NO_INTEGERS) ? 0 : -1;
945
0
  int utf8 = 0;
946
947
  /* for speed, compute the effect of the flags outside the loop */
948
949
0
  if (ts->flags & LWS_TOKENIZE_F_MINUS_NONTERM) {
950
0
    d_minus = '\0';
951
0
    s_minus = '-';
952
0
  }
953
0
  if (ts->flags & LWS_TOKENIZE_F_DOT_NONTERM) {
954
0
    d_dot = '\0';
955
0
    s_dot = '.';
956
0
  }
957
0
  if (ts->flags & LWS_TOKENIZE_F_ASTERISK_NONTERM) {
958
0
    d_star = '\0';
959
0
    s_star = '*';
960
0
  }
961
0
  if (ts->flags & LWS_TOKENIZE_F_EQUALS_NONTERM) {
962
0
    d_eq = '\0';
963
0
    s_eq = '=';
964
0
  }
965
0
  if (ts->flags & LWS_TOKENIZE_F_PLUS_NONTERM) {
966
0
    d_plus = '\0';
967
0
    s_plus = '+';
968
0
  }
969
970
0
  if (!ts->dry)
971
0
    ts->token = ts->collect;
972
0
  ts->dry = 0;
973
974
0
  if (ts->reset_token) {
975
0
    ts->effline = ts->line;
976
0
    ts->state = LWS_TOKZS_LEADING_WHITESPACE;
977
0
    ts->token_len = 0;
978
0
    ts->reset_token = 0;
979
0
  }
980
981
0
  while (ts->len) {
982
0
    c = *ts->start++;
983
0
    ts->len--;
984
985
0
    utf8 = lws_check_byte_utf8((unsigned char)utf8, (unsigned char)c);
986
0
    if (utf8 < 0)
987
0
      return LWS_TOKZE_ERR_BROKEN_UTF8;
988
989
0
    if (!c)
990
0
      break;
991
992
0
    if (skipping) {
993
0
      if (c != '\r' && c != '\n')
994
0
        continue;
995
0
      else
996
0
        skipping = 0;
997
0
    }
998
999
    /* comment */
1000
1001
0
    if (ts->flags & LWS_TOKENIZE_F_HASH_COMMENT &&
1002
0
        ts->state != LWS_TOKZS_QUOTED_STRING &&
1003
0
        c == '#') {
1004
0
      skipping = 1;
1005
0
      continue;
1006
0
    }
1007
1008
    /* whitespace */
1009
1010
0
    if (c == ' ' || c == '\t' || c == '\n' || c == '\r' ||
1011
0
        c == '\f') {
1012
0
      if (c == '\r' && !ts->crlf)
1013
0
        ts->line++;
1014
0
      if (c == '\n') {
1015
0
        ts->line++;
1016
0
        ts->crlf = 1;
1017
0
      }
1018
0
      switch (ts->state) {
1019
0
      case LWS_TOKZS_LEADING_WHITESPACE:
1020
0
      case LWS_TOKZS_TOKEN_POST_TERMINAL:
1021
0
        continue;
1022
0
      case LWS_TOKZS_QUOTED_STRING:
1023
0
        goto agg;
1024
0
      case LWS_TOKZS_TOKEN:
1025
        /* we want to scan forward to look for = */
1026
1027
0
        ts->state = LWS_TOKZS_TOKEN_POST_TERMINAL;
1028
0
        continue;
1029
0
      }
1030
0
    } else
1031
0
      ts->crlf = 0;
1032
1033
    /* quoted string */
1034
1035
0
    if (c == '\"') {
1036
0
      if (ts->state == LWS_TOKZS_TOKEN_POST_TERMINAL) {
1037
        /* report the pending token next time */
1038
0
        ts->start--;
1039
0
        ts->len++;
1040
0
        goto token_or_numeric;
1041
0
      }
1042
1043
0
      if (ts->state == LWS_TOKZS_QUOTED_STRING) {
1044
0
        ts->reset_token = 1;
1045
1046
0
        return LWS_TOKZE_QUOTED_STRING;
1047
0
      }
1048
1049
      /* starting a quoted string */
1050
1051
0
      if (ts->flags & LWS_TOKENIZE_F_COMMA_SEP_LIST) {
1052
0
        if (ts->delim == LWSTZ_DT_NEED_DELIM)
1053
0
          return LWS_TOKZE_ERR_COMMA_LIST;
1054
0
        ts->delim = LWSTZ_DT_NEED_DELIM;
1055
0
      }
1056
1057
0
      ts->state = LWS_TOKZS_QUOTED_STRING;
1058
0
      ts->token = ts->collect;
1059
0
      ts->token_len = 0;
1060
1061
0
      continue;
1062
0
    }
1063
1064
    /* token= aggregation */
1065
1066
0
    if (!(ts->flags & LWS_TOKENIZE_F_EQUALS_NONTERM) &&
1067
0
        c == '=' && (ts->state == LWS_TOKZS_TOKEN_POST_TERMINAL ||
1068
0
         ts->state == LWS_TOKZS_TOKEN)) {
1069
1070
0
      ts->reset_token = 1;
1071
1072
0
      if (num == 1)
1073
0
        return LWS_TOKZE_ERR_NUM_ON_LHS;
1074
      /* swallow the = */
1075
0
      return LWS_TOKZE_TOKEN_NAME_EQUALS;
1076
0
    }
1077
1078
    /* optional token: aggregation */
1079
1080
0
    if ((ts->flags & LWS_TOKENIZE_F_AGG_COLON) && c == ':' &&
1081
0
        (ts->state == LWS_TOKZS_TOKEN_POST_TERMINAL ||
1082
0
         ts->state == LWS_TOKZS_TOKEN)) {
1083
0
      ts->reset_token = 1;
1084
1085
      /* swallow the : */
1086
0
      return LWS_TOKZE_TOKEN_NAME_COLON;
1087
0
    }
1088
1089
    /* aggregate . in a number as a float */
1090
1091
0
    if (c == '.' && !(ts->flags & LWS_TOKENIZE_F_NO_FLOATS) &&
1092
0
        ts->state == LWS_TOKZS_TOKEN && num == 1) {
1093
0
      if (flo)
1094
0
        return LWS_TOKZE_ERR_MALFORMED_FLOAT;
1095
0
      flo = 1;
1096
0
      goto agg;
1097
0
    }
1098
1099
    /*
1100
     * Delimiter... by default anything that:
1101
     *
1102
     *  - isn't matched earlier, or
1103
     *  - is [A-Z, a-z, 0-9, _], and
1104
     *  - is not a partial utf8 char
1105
     *
1106
     * is a "delimiter", it marks the end of a token and is itself
1107
     * reported as a single LWS_TOKZE_DELIMITER each time.
1108
     *
1109
     * However with LWS_TOKENIZE_F_RFC7230_DELIMS flag, tokens may
1110
     * contain any noncontrol character that isn't defined in
1111
     * rfc7230_delims, and only characters listed there are treated
1112
     * as delimiters.
1113
     */
1114
1115
0
    if (!utf8 &&
1116
0
         ((ts->flags & LWS_TOKENIZE_F_RFC7230_DELIMS &&
1117
0
           strchr(rfc7230_delims, c) && c > 32) ||
1118
0
           ((!(ts->flags & LWS_TOKENIZE_F_RFC7230_DELIMS) &&
1119
0
            (c < '0' || c > '9') && (c < 'A' || c > 'Z') &&
1120
0
            (c < 'a' || c > 'z') && c != '_') &&
1121
0
            c != s_minus && c != s_dot && c != s_star && c != s_eq && c != s_plus) ||
1122
0
            c == d_minus ||
1123
0
      c == d_dot ||
1124
0
      c == d_star ||
1125
0
      c == d_eq ||
1126
0
      c == d_plus
1127
0
        ) &&
1128
0
        !((ts->flags & LWS_TOKENIZE_F_COLON_NONTERM) && c == ':') &&
1129
0
        !((ts->flags & LWS_TOKENIZE_F_SLASH_NONTERM) && c == '/')) {
1130
0
      switch (ts->state) {
1131
0
      case LWS_TOKZS_LEADING_WHITESPACE:
1132
0
        if (ts->flags & LWS_TOKENIZE_F_COMMA_SEP_LIST) {
1133
0
          if (c != ',' ||
1134
0
              ts->delim != LWSTZ_DT_NEED_DELIM)
1135
0
            return LWS_TOKZE_ERR_COMMA_LIST;
1136
0
          ts->delim = LWSTZ_DT_NEED_NEXT_CONTENT;
1137
0
        }
1138
1139
0
        ts->token = ts->start - 1;
1140
0
        ts->token_len = 1;
1141
0
        ts->reset_token = 1;
1142
1143
0
        return LWS_TOKZE_DELIMITER;
1144
1145
0
      case LWS_TOKZS_QUOTED_STRING:
1146
0
agg:
1147
0
        ts->collect[ts->token_len++] = c;
1148
0
        if (ts->token_len == sizeof(ts->collect) - 1)
1149
0
          return LWS_TOKZE_TOO_LONG;
1150
0
        ts->collect[ts->token_len] = '\0';
1151
0
        continue;
1152
1153
0
      case LWS_TOKZS_TOKEN_POST_TERMINAL:
1154
0
      case LWS_TOKZS_TOKEN:
1155
        /* report the delimiter next time */
1156
0
        ts->start--;
1157
0
        ts->len++;
1158
0
        goto token_or_numeric;
1159
0
      }
1160
0
    }
1161
1162
    /* anything that's not whitespace or delimiter is payload */
1163
1164
0
    switch (ts->state) {
1165
0
    case LWS_TOKZS_LEADING_WHITESPACE:
1166
1167
0
      if (ts->flags & LWS_TOKENIZE_F_COMMA_SEP_LIST) {
1168
0
        if (ts->delim == LWSTZ_DT_NEED_DELIM) {
1169
0
          ts->reset_token = 1;
1170
1171
0
          return LWS_TOKZE_ERR_COMMA_LIST;
1172
0
        }
1173
0
        ts->delim = LWSTZ_DT_NEED_DELIM;
1174
0
      }
1175
1176
0
      ts->state = LWS_TOKZS_TOKEN;
1177
0
      ts->reset_token = 1;
1178
1179
0
      ts->token = ts->collect; //ts->start - 1;
1180
0
      ts->collect[0] = c;
1181
0
      ts->token_len = 1;
1182
0
      goto checknum;
1183
1184
0
    case LWS_TOKZS_QUOTED_STRING:
1185
0
    case LWS_TOKZS_TOKEN:
1186
0
      ts->collect[ts->token_len++] = c;
1187
0
      if (ts->token_len == sizeof(ts->collect) - 1)
1188
0
        return LWS_TOKZE_TOO_LONG;
1189
0
      ts->collect[ts->token_len] = '\0';
1190
0
checknum:
1191
0
      if (!(ts->flags & LWS_TOKENIZE_F_NO_INTEGERS)) {
1192
0
        if (c < '0' || c > '9')
1193
0
          num = 0;
1194
0
        else
1195
0
          if (num < 0)
1196
0
            num = 1;
1197
0
      }
1198
0
      continue;
1199
1200
0
    case LWS_TOKZS_TOKEN_POST_TERMINAL:
1201
      /* report the new token next time */
1202
0
      ts->start--;
1203
0
      ts->len++;
1204
0
      goto token_or_numeric;
1205
0
    }
1206
0
  }
1207
1208
  /* we ran out of content */
1209
1210
0
  if (ts->flags & LWS_TOKENIZE_F_EXPECT_MORE) {
1211
0
    ts->reset_token = 0;
1212
0
    ts->dry = 1;
1213
0
    return LWS_TOKZE_WANT_READ;
1214
0
  }
1215
1216
0
  if (utf8) /* ended partway through a multibyte char */
1217
0
    return LWS_TOKZE_ERR_BROKEN_UTF8;
1218
1219
0
  if (ts->state == LWS_TOKZS_QUOTED_STRING)
1220
0
    return LWS_TOKZE_ERR_UNTERM_STRING;
1221
1222
0
  if (ts->state != LWS_TOKZS_TOKEN_POST_TERMINAL &&
1223
0
      ts->state != LWS_TOKZS_TOKEN) {
1224
0
    if ((ts->flags & LWS_TOKENIZE_F_COMMA_SEP_LIST) &&
1225
0
         ts->delim == LWSTZ_DT_NEED_NEXT_CONTENT)
1226
0
      return LWS_TOKZE_ERR_COMMA_LIST;
1227
1228
0
    return LWS_TOKZE_ENDED;
1229
0
  }
1230
1231
  /* report the pending token */
1232
1233
0
token_or_numeric:
1234
1235
0
  ts->reset_token = 1;
1236
1237
0
  if (num != 1)
1238
0
    return LWS_TOKZE_TOKEN;
1239
0
  if (flo)
1240
0
    return LWS_TOKZE_FLOAT;
1241
1242
0
  return LWS_TOKZE_INTEGER;
1243
0
}
1244
1245
1246
int
1247
lws_tokenize_cstr(struct lws_tokenize *ts, char *str, size_t max)
1248
0
{
1249
0
  if (ts->token_len + 1 >= max)
1250
0
    return 1;
1251
1252
0
  memcpy(str, ts->token, ts->token_len);
1253
0
  str[ts->token_len] = '\0';
1254
1255
0
  return 0;
1256
0
}
1257
1258
void
1259
lws_tokenize_init(struct lws_tokenize *ts, const char *start, int flags)
1260
0
{
1261
0
  ts->start = start;
1262
0
  ts->len = 0x7fffffff;
1263
0
  ts->flags = (uint16_t)(unsigned int)flags;
1264
0
  ts->delim = LWSTZ_DT_NEED_FIRST_CONTENT;
1265
0
  ts->token = NULL;
1266
0
  ts->token_len = 0;
1267
0
  ts->line = 0;
1268
0
  ts->effline = 0;
1269
0
  ts->dry = 0;
1270
0
  ts->reset_token = 0;
1271
0
  ts->crlf = 0;
1272
0
  ts->state = LWS_TOKZS_LEADING_WHITESPACE;
1273
0
}
1274
1275
1276
typedef enum {
1277
  LWS_EXPS_LITERAL,
1278
  LWS_EXPS_OPEN_OR_LIT,
1279
  LWS_EXPS_NAME_OR_CLOSE,
1280
  LWS_EXPS_DRAIN,
1281
} lws_strexp_state;
1282
1283
void
1284
lws_strexp_init(lws_strexp_t *exp, void *priv, lws_strexp_expand_cb cb,
1285
     char *out, size_t olen)
1286
0
{
1287
0
  memset(exp, 0, sizeof(*exp));
1288
0
  exp->cb = cb;
1289
0
  exp->out = out;
1290
0
  exp->olen = olen;
1291
0
  exp->state = LWS_EXPS_LITERAL;
1292
0
  exp->priv = priv;
1293
0
}
1294
1295
void
1296
lws_strexp_reset_out(lws_strexp_t *exp, char *out, size_t olen)
1297
0
{
1298
0
  exp->out = out;
1299
0
  exp->olen = olen;
1300
0
  exp->pos = 0;
1301
0
}
1302
1303
int
1304
lws_strexp_expand(lws_strexp_t *exp, const char *in, size_t len,
1305
      size_t *pused_in, size_t *pused_out)
1306
0
{
1307
0
  size_t used = 0;
1308
0
  int n;
1309
1310
0
  while (used < len) {
1311
1312
0
    switch (exp->state) {
1313
0
    case LWS_EXPS_LITERAL:
1314
0
      if (*in == '$') {
1315
0
        exp->state = LWS_EXPS_OPEN_OR_LIT;
1316
0
        break;
1317
0
      }
1318
1319
0
      if (exp->out)
1320
0
        exp->out[exp->pos] = *in;
1321
0
      exp->pos++;
1322
0
      if (exp->olen - exp->pos < 1) {
1323
0
        *pused_in = used + 1;
1324
0
        *pused_out = exp->pos;
1325
0
        return LSTRX_FILLED_OUT;
1326
0
      }
1327
0
      break;
1328
1329
0
    case LWS_EXPS_OPEN_OR_LIT:
1330
0
      if (*in == '{') {
1331
0
        exp->state = LWS_EXPS_NAME_OR_CLOSE;
1332
0
        exp->name_pos = 0;
1333
0
        exp->exp_ofs = 0;
1334
0
        break;
1335
0
      }
1336
      /* treat as a literal */
1337
0
      if (exp->olen - exp->pos < 3)
1338
0
        return -1;
1339
1340
0
      if (exp->out) {
1341
0
        exp->out[exp->pos++] = '$';
1342
0
        exp->out[exp->pos++] = *in;
1343
0
      } else
1344
0
        exp->pos += 2;
1345
0
      if (*in != '$')
1346
0
        exp->state = LWS_EXPS_LITERAL;
1347
0
      break;
1348
1349
0
    case LWS_EXPS_NAME_OR_CLOSE:
1350
0
      if (*in == '}') {
1351
0
        exp->name[exp->name_pos] = '\0';
1352
0
        exp->state = LWS_EXPS_DRAIN;
1353
0
        goto drain;
1354
0
      }
1355
0
      if (exp->name_pos >= sizeof(exp->name) - 1)
1356
0
        return LSTRX_FATAL_NAME_TOO_LONG;
1357
1358
0
      exp->name[exp->name_pos++] = *in;
1359
0
      break;
1360
1361
0
    case LWS_EXPS_DRAIN:
1362
0
drain:
1363
0
      *pused_in = used;
1364
0
      n = exp->cb(exp->priv, exp->name, exp->out, &exp->pos,
1365
0
            exp->olen, &exp->exp_ofs);
1366
0
      *pused_out = exp->pos;
1367
0
      if (n == LSTRX_FILLED_OUT ||
1368
0
          n == LSTRX_FATAL_NAME_UNKNOWN)
1369
0
        return n;
1370
1371
0
      exp->state = LWS_EXPS_LITERAL;
1372
0
      break;
1373
0
    }
1374
1375
0
    used++;
1376
0
    in++;
1377
0
  }
1378
1379
0
  if (exp->out)
1380
0
    exp->out[exp->pos] = '\0';
1381
0
  *pused_in = used;
1382
0
  *pused_out = exp->pos;
1383
1384
0
  return LSTRX_DONE;
1385
0
}
1386
1387
int
1388
lws_strcmp_wildcard(const char *wildcard, size_t wlen, const char *check,
1389
        size_t clen)
1390
0
{
1391
0
  const char *match[3], *wc[3], *wc_end = wildcard + wlen,
1392
0
       *cend = check + clen;
1393
0
  int sp = 0;
1394
1395
0
  do {
1396
1397
0
    if (wildcard == wc_end) {
1398
      /*
1399
       * We reached the end of wildcard, but not of check,
1400
       * and the last thing in wildcard was not a * or we
1401
       * would have completed already... if we can rewind,
1402
       * let's try that...
1403
       */
1404
0
      if (sp) {
1405
0
        wildcard = wc[sp - 1];
1406
0
        check = match[--sp];
1407
1408
0
        continue;
1409
0
      }
1410
1411
      /* otherwise it's the end of the road for this one */
1412
1413
0
      return 1;
1414
0
    }
1415
1416
0
    if (*wildcard == '*') {
1417
1418
0
      if (++wildcard == wc_end)
1419
         /*
1420
          * Wildcard ended on a *, so we know we will
1421
          * match unconditionally
1422
          */
1423
0
        return 0;
1424
1425
      /*
1426
       * Now we need to stick wildcard here and see if there
1427
       * is any remaining match exists, for eg b of "a*b"
1428
       */
1429
1430
0
      if (sp == LWS_ARRAY_SIZE(match)) {
1431
0
        lwsl_err("%s: exceeds * stack\n", __func__);
1432
0
        return 1; /* we can't deal with it */
1433
0
      }
1434
1435
0
      wc[sp] = wildcard;
1436
      /* if we ever pop and come back here, pick up from +1 */
1437
0
      match[sp++] = check + 1;
1438
0
      continue;
1439
0
    }
1440
1441
0
    if (*(check++) == *wildcard) {
1442
1443
0
      if (wildcard == wc_end)
1444
0
        return 0;
1445
      /*
1446
       * We're still compatible with wildcard... keep going
1447
       */
1448
0
      wildcard++;
1449
1450
0
      continue;
1451
0
    }
1452
1453
0
    if (!sp)
1454
      /*
1455
       * We're just trying to match literals, and failed...
1456
       */
1457
0
      return 1;
1458
1459
    /* we're looking for a post-* match... keep looking... */
1460
1461
0
  } while (check < cend);
1462
1463
  /*
1464
   * We reached the end of check, if also at end of wildcard we're OK
1465
   */
1466
1467
0
  return wildcard != wc_end;
1468
0
}
1469
1470
#if defined(LWS_WITH_NETWORK) && LWS_MAX_SMP > 1
1471
1472
void
1473
lws_mutex_refcount_init(struct lws_mutex_refcount *mr)
1474
{
1475
  pthread_mutex_init(&mr->lock, NULL);
1476
  mr->last_lock_reason = NULL;
1477
  mr->lock_depth = 0;
1478
  mr->metadata = 0;
1479
#ifdef __PTW32_H
1480
  /* If we use implementation of PThreads for Win that is
1481
   * distributed by VCPKG */
1482
  memset(&mr->lock_owner, 0, sizeof(pthread_t));
1483
#else
1484
  mr->lock_owner = 0;
1485
#endif
1486
}
1487
1488
void
1489
lws_mutex_refcount_destroy(struct lws_mutex_refcount *mr)
1490
{
1491
  pthread_mutex_destroy(&mr->lock);
1492
}
1493
1494
void
1495
lws_mutex_refcount_lock(struct lws_mutex_refcount *mr, const char *reason)
1496
{
1497
  /* if true, this sequence is atomic because our thread has the lock
1498
   *
1499
   *  - if true, only guy who can race to make it untrue is our thread,
1500
   *    and we are here.
1501
   *
1502
   *  - if false, only guy who could race to make it true is our thread,
1503
   *    and we are here
1504
   *
1505
   *  - it can be false and change to a different tid that is also false
1506
   */
1507
#ifdef __PTW32_H
1508
  /* If we use implementation of PThreads for Win that is
1509
   * distributed by VCPKG */
1510
  if (pthread_equal(mr->lock_owner, pthread_self()))
1511
#else
1512
  if (mr->lock_owner == pthread_self())
1513
#endif
1514
  {
1515
    /* atomic because we only change it if we own the lock */
1516
    mr->lock_depth++;
1517
    return;
1518
  }
1519
1520
  pthread_mutex_lock(&mr->lock);
1521
  /* atomic because only we can have the lock */
1522
  mr->last_lock_reason = reason;
1523
  mr->lock_owner = pthread_self();
1524
  mr->lock_depth = 1;
1525
  //lwsl_notice("tid %d: lock %s\n", mr->tid, reason);
1526
}
1527
1528
void
1529
lws_mutex_refcount_unlock(struct lws_mutex_refcount *mr)
1530
{
1531
  if (--mr->lock_depth)
1532
    /* atomic because only thread that has the lock can unlock */
1533
    return;
1534
1535
  mr->last_lock_reason = "free";
1536
#ifdef __PTW32_H
1537
  /* If we use implementation of PThreads for Win that is
1538
   * distributed by VCPKG */
1539
  memset(&mr->lock_owner, 0, sizeof(pthread_t));
1540
#else
1541
  mr->lock_owner = 0;
1542
#endif
1543
  // lwsl_notice("tid %d: unlock %s\n", mr->tid, mr->last_lock_reason);
1544
  pthread_mutex_unlock(&mr->lock);
1545
}
1546
1547
void
1548
lws_mutex_refcount_assert_held(struct lws_mutex_refcount *mr)
1549
{
1550
#ifdef __PTW32_H
1551
  /* If we use implementation of PThreads for Win that is
1552
   * distributed by VCPKG */
1553
  assert(pthread_equal(mr->lock_owner, pthread_self()) && mr->lock_depth);
1554
#else
1555
  assert(mr->lock_owner == pthread_self() && mr->lock_depth);
1556
#endif
1557
}
1558
1559
#endif /* SMP */
1560
1561
#if !defined(LWS_PLAT_FREERTOS) && !defined(LWS_PLAT_BAREMETAL)
1562
1563
void
1564
lws_switches_print_help(const char *prog, const struct lws_switches *switches,
1565
       size_t count)
1566
0
{
1567
0
  size_t i;
1568
1569
0
  lwsl_user("\nUsage: %s [options]\n", prog);
1570
0
  lwsl_user("\n");
1571
1572
0
  for (i = 0; i < count; i++)
1573
0
    lwsl_user("  %-20s %s\n", switches[i].sw, switches[i].doc);
1574
1575
0
  lwsl_user("\n");
1576
0
}
1577
1578
const char *
1579
lws_cmdline_options(int argc, const char * const *argv, const char *val, const char *last)
1580
0
{
1581
0
  int c = 1, hit = 0;
1582
0
  size_t n = 0;
1583
0
  const char *p;
1584
1585
0
  if (val)
1586
0
    n = strlen(val);
1587
1588
0
  while (c < argc) {
1589
1590
0
    if (val && strncmp(argv[c], val, n)) /* skip if not matching val */
1591
0
      goto bump;
1592
1593
0
    if (!val && argv[c][0] == '-') /* looking for non-switch */
1594
0
      goto bump;
1595
1596
0
    if (!val && argv[c][0] != '-') { /* looking for non-switch */
1597
0
      p = argv[c];
1598
0
      goto try;
1599
0
    }
1600
1601
0
    if (c < argc - 1 && !*(argv[c] + n)) {
1602
      /* coverity treats unchecked argv as "tainted" */
1603
0
      if (!argv[c + 1] || strlen(argv[c + 1]) > 1024)
1604
0
        return NULL;
1605
1606
0
      p = argv[c + 1];
1607
0
      goto try;
1608
0
    }
1609
1610
0
    if (argv[c][n] == '=') {
1611
0
      p =  &argv[c][n + 1];
1612
0
      goto try;
1613
0
    }
1614
1615
0
    p = argv[c] + n;
1616
1617
0
try:
1618
0
    if (last && !hit) {
1619
0
      if (p == last)
1620
0
        hit = 1;
1621
0
      goto bump;
1622
0
    }
1623
1624
0
    return p;
1625
0
bump:
1626
0
    c++;
1627
0
  }
1628
1629
0
  return NULL;
1630
0
}
1631
1632
const char *
1633
lws_cmdline_options_cx(const struct lws_context *cx, const char *val, const char *last)
1634
0
{
1635
0
  assert(cx->argc);
1636
1637
0
  if (!cx->stdin_argc)
1638
0
    return lws_cmdline_options((int)cx->argc, cx->argv, val, last);
1639
1640
0
  return lws_cmdline_options((int)cx->stdin_argc, cx->stdin_argv, val, last);
1641
0
}
1642
1643
const char *
1644
lws_cmdline_option_cx(const struct lws_context *cx, const char *val)
1645
0
{
1646
0
  return lws_cmdline_options_cx(cx, val, NULL);
1647
0
}
1648
1649
1650
const char *
1651
lws_cmdline_option(int argc, const char **argv, const char *val)
1652
0
{
1653
0
  return lws_cmdline_options(argc, argv, val, NULL);
1654
0
}
1655
#endif
1656
1657
#if !defined(LWS_PLAT_FREERTOS) && !defined(LWS_PLAT_BAREMETAL) && !defined(LWS_PLAT_ANDROID) && defined(LWS_WITH_NETWORK)
1658
static const char * const builtins[] = {
1659
  "-d",
1660
  "--fault-injection",
1661
  "--fault-seed",
1662
  "--ignore-sigterm",
1663
  "--ssproxy-port",
1664
  "--ssproxy-iface",
1665
  "--ssproxy-ads",
1666
};
1667
1668
enum opts {
1669
  OPT_DEBUGLEVEL,
1670
  OPT_FAULTINJECTION,
1671
  OPT_FAULT_SEED,
1672
  OPT_IGNORE_SIGTERM,
1673
  OPT_SSPROXY_PORT,
1674
  OPT_SSPROXY_IFACE,
1675
  OPT_SSPROXY_ADS,
1676
};
1677
1678
static void
1679
lws_sigterm_catch(int sig)
1680
0
{
1681
0
}
1682
#endif
1683
1684
void
1685
_lws_context_info_defaults(struct lws_context_creation_info *info,
1686
        const char *sspol)
1687
0
{
1688
0
  memset(info, 0, sizeof *info);
1689
0
        info->fd_limit_per_thread = 1 + 6 + 1;
1690
0
#if defined(LWS_WITH_NETWORK)
1691
0
        info->port = CONTEXT_PORT_NO_LISTEN;
1692
0
#endif
1693
0
#if defined(LWS_WITH_SECURE_STREAMS) && !defined(LWS_WITH_SECURE_STREAMS_STATIC_POLICY_ONLY)
1694
0
        info->pss_policies_json = sspol;
1695
0
#endif
1696
#if defined(LWS_WITH_SECURE_STREAMS_PROXY_API)
1697
        if (!sspol)
1698
          info->protocols = lws_sspc_protocols;
1699
#endif
1700
0
        info->options = LWS_SERVER_OPTION_EXPLICIT_VHOSTS |
1701
0
          LWS_SERVER_OPTION_H2_JUST_FIX_WINDOW_UPDATE_OVERFLOW |
1702
0
          LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
1703
0
}
1704
1705
void
1706
lws_default_loop_exit(struct lws_context *cx)
1707
0
{
1708
0
  if (cx) {
1709
0
    cx->interrupted = 1;
1710
0
#if defined(LWS_WITH_NETWORK)
1711
0
    lws_cancel_service(cx);
1712
0
#endif
1713
0
  }
1714
0
}
1715
1716
#if defined(LWS_WITH_NETWORK)
1717
void
1718
lws_context_default_loop_run_destroy(struct lws_context *cx)
1719
0
{
1720
        /* the default event loop, since we didn't provide an alternative one */
1721
1722
0
        while (!cx->interrupted && lws_service(cx, 0) >= 0)
1723
0
          ;
1724
1725
0
        lws_context_destroy(cx);
1726
0
}
1727
#endif
1728
1729
#if !defined(LWS_PLAT_FREERTOS) && !defined(LWS_PLAT_BAREMETAL) && !defined(LWS_PLAT_ANDROID) && defined(LWS_WITH_NETWORK)
1730
int
1731
lws_cmdline_passfail(int argc, const char **argv, int actual)
1732
0
{
1733
0
  int expected = 0;
1734
0
  const char *p;
1735
1736
0
  if ((p = lws_cmdline_option(argc, argv, "--expected-exit")))
1737
0
    expected = atoi(p);
1738
1739
0
  if (actual == expected) {
1740
0
    lwsl_user("Completed: OK (seen expected %d)\n", actual);
1741
1742
0
    return 0;
1743
0
  }
1744
1745
0
  lwsl_err("Completed: failed: exit %d, expected %d\n", actual, expected);
1746
1747
0
  return 1;
1748
0
}
1749
1750
void
1751
lws_cmdline_option_handle_builtin(int argc, const char **argv,
1752
          struct lws_context_creation_info *info)
1753
0
{
1754
0
  const char *p;
1755
0
  int n, m, logs = info->default_loglevel ? info->default_loglevel :
1756
0
        LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE;
1757
#if defined(LWS_WITH_SYS_FAULT_INJECTION)
1758
  uint64_t seed = (uint64_t)lws_now_usecs();
1759
#endif
1760
1761
0
  info->argc = argc;
1762
0
  info->argv = argv;
1763
1764
0
  for (n = 0; n < (int)LWS_ARRAY_SIZE(builtins); n++) {
1765
0
    p = lws_cmdline_option(argc, argv, builtins[n]);
1766
0
    if (!p)
1767
0
      continue;
1768
1769
0
    m = atoi(p);
1770
1771
0
    switch (n) {
1772
0
    case OPT_DEBUGLEVEL:
1773
0
      logs = m;
1774
0
      break;
1775
1776
#if defined(LWS_WITH_SECURE_STREAMS_PROXY_API)
1777
    case OPT_SSPROXY_PORT:
1778
      /* connect to ssproxy via UDS by default, else via
1779
       * tcp connection to this port */
1780
      info->ss_proxy_port = (uint16_t)atoi(p);
1781
      break;
1782
1783
    case OPT_SSPROXY_IFACE:
1784
      /* UDS "proxy.ss.lws" in abstract namespace, else this socket
1785
       * path; when -p given this can specify the network interface
1786
       * to bind to */
1787
      info->ss_proxy_bind = p;
1788
      break;
1789
1790
    case OPT_SSPROXY_ADS:
1791
      info->ss_proxy_address = p;
1792
      break;
1793
#endif
1794
1795
0
    case OPT_FAULTINJECTION:
1796
0
#if !defined(LWS_WITH_SYS_FAULT_INJECTION)
1797
0
      lwsl_err("%s: FAULT_INJECTION not built\n", __func__);
1798
0
#endif
1799
0
      lws_fi_deserialize(&info->fic, p);
1800
0
      break;
1801
1802
0
    case OPT_FAULT_SEED:
1803
#if defined(LWS_WITH_SYS_FAULT_INJECTION)
1804
      seed = (uint64_t)atoll(p);
1805
#endif
1806
0
      break;
1807
1808
0
    case OPT_IGNORE_SIGTERM:
1809
0
#if !defined(LWS_PLAT_FREERTOS)
1810
0
      signal(SIGTERM, lws_sigterm_catch);
1811
0
#endif
1812
0
      break;
1813
0
    }
1814
0
  }
1815
1816
#if defined(LWS_WITH_SYS_FAULT_INJECTION)
1817
  lws_xos_init(&info->fic.xos, seed);
1818
#endif
1819
0
  lws_set_log_level(logs, NULL);
1820
1821
#if defined(LWS_WITH_SYS_FAULT_INJECTION)
1822
  if (info->fic.fi_owner.count)
1823
    lwsl_notice("%s: Fault Injection seed %llu\n", __func__,
1824
        (unsigned long long)seed);
1825
#endif
1826
0
}
1827
#endif
1828
1829
const lws_humanize_unit_t humanize_schema_si[] = {
1830
  { "Pi", LWS_PI }, { "Ti", LWS_TI }, { "Gi", LWS_GI },
1831
  { "Mi", LWS_MI }, { "Ki", LWS_KI }, { "", 1 },
1832
  { NULL, 0 }
1833
};
1834
const lws_humanize_unit_t humanize_schema_si_bytes[] = {
1835
  { "PiB", LWS_PI }, { "TiB", LWS_TI }, { "GiB", LWS_GI },
1836
  { "MiB", LWS_MI }, { "KiB", LWS_KI }, { "B", 1 },
1837
  { NULL, 0 }
1838
};
1839
const lws_humanize_unit_t humanize_schema_us[] = {
1840
  { "y",  (uint64_t)365 * 24 * 3600 * LWS_US_PER_SEC },
1841
  { "d",  (uint64_t)24 * 3600 * LWS_US_PER_SEC },
1842
  { "hr", (uint64_t)3600 * LWS_US_PER_SEC },
1843
  { "min", 60 * LWS_US_PER_SEC },
1844
  { "s", LWS_US_PER_SEC },
1845
  { "ms", LWS_US_PER_MS },
1846
#if defined(WIN32)
1847
  { "us", 1 },
1848
#else
1849
  { "μs", 1 },
1850
#endif
1851
  { NULL, 0 }
1852
};
1853
1854
/* biggest ull is 18446744073709551615 (20 chars) */
1855
1856
static int
1857
decim(char *r, uint64_t v, char chars, char leading)
1858
0
{
1859
0
  uint64_t q = 1;
1860
0
  char *ro = r;
1861
0
  int n = 1;
1862
1863
0
  while ((leading || v > (q * 10) - 1) && n < 20 && n < chars) {
1864
0
    q = q * 10;
1865
0
    n++;
1866
0
  }
1867
1868
  /* n is how many chars needed */
1869
1870
0
  while (n--) {
1871
0
    *r++ = (char)('0' + (char)((v / q) % 10));
1872
0
    q = q / 10;
1873
0
  }
1874
1875
0
  *r = '\0';
1876
1877
0
  return lws_ptr_diff(r, ro);
1878
0
}
1879
1880
int
1881
lws_humanize(char *p, size_t len, uint64_t v, const lws_humanize_unit_t *schema)
1882
0
{
1883
0
  const lws_humanize_unit_t *s = NULL;
1884
0
  char *obuf = p, *end = p + len;
1885
1886
0
  do {
1887
0
    if (v >= schema->factor || schema->factor == 1) {
1888
0
      if (schema[1].name)
1889
0
        s = &schema[1];
1890
1891
0
      if (schema->factor == 1) {
1892
0
        p += decim(p, v, 4, 0);
1893
0
        p += lws_snprintf(p, lws_ptr_diff_size_t(end, p),
1894
0
            "%s", schema->name);
1895
0
        return lws_ptr_diff(p, obuf);
1896
0
      }
1897
1898
0
      p += decim(p, v / schema->factor, 4, 0);
1899
0
      if (s) {
1900
0
        uint64_t iif = schema->factor / s->factor;
1901
1902
0
        if (s->factor * 1000 == schema->factor ||
1903
0
            s->factor * 1024 == schema->factor) { /* decimal */
1904
0
          uint64_t d = (v % schema->factor) / (schema->factor / 1000);
1905
1906
0
          if (d) { /* we want, eg 123ms rather than 123.000ms */
1907
0
            *p++ = '.';
1908
0
            p += decim(p, d, 3, 1);
1909
0
          }
1910
0
        } else { /* imperial fraction, eg, h:m */
1911
0
          *p++ = ':';
1912
0
          p += decim(p, (v % schema->factor) / s->factor,
1913
0
              iif >= 100 ? 3 : (iif >= 10 ? 2 : 1), 1);
1914
0
        }
1915
0
      }
1916
0
      p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), "%s", schema->name);
1917
0
      return lws_ptr_diff(p, obuf);
1918
0
    }
1919
0
    schema++;
1920
0
  } while (schema->name);
1921
1922
0
  assert(0);
1923
0
  strncpy(p, "unknown value", len);
1924
1925
0
  return 0;
1926
0
}
1927
1928
int
1929
lws_humanize_pad(char *p, size_t len, uint64_t v, const lws_humanize_unit_t *schema)
1930
0
{
1931
0
       size_t m, w = 0, n = (size_t)lws_humanize(p, len, v, schema);
1932
0
  const lws_humanize_unit_t *s = schema;
1933
0
       int t;
1934
1935
0
  while (s->name) {
1936
0
    if (strlen(s->name) > w)
1937
0
      w = strlen(s->name);
1938
0
    s++;
1939
0
  }
1940
1941
0
  m = (3 + 1 + 3 + w) - (size_t)n;
1942
1943
0
       for (t = (int)n - 1; t >= 0; t--)
1944
0
               p[(size_t)t + m] = p[t];
1945
0
  p[m + n] = '\0';
1946
1947
0
       for (t = 0; t < (int)m; t++)
1948
0
    p[t] = ' ';
1949
1950
0
  return (int)(n + m);
1951
0
}
1952
1953
/*
1954
 * -1 = fail
1955
 *  0 = continue
1956
 *  1 = hit
1957
 */
1958
1959
0
#define LWS_MINILEX_FAIL_CODING 8
1960
1961
int
1962
lws_minilex_parse(const uint8_t *lex, int16_t *ps, const uint8_t c, int *match)
1963
0
{
1964
0
  if (*ps == (int16_t)-1)
1965
0
    return LWS_MINILEX_FAIL;
1966
1967
0
  while (1) {
1968
0
    if (lex[*ps] & (1 << 7)) {
1969
      /* 1-byte, fail on mismatch */
1970
0
      if ((lex[*ps] & 0x7f) != c)
1971
0
        goto nope;
1972
1973
      /* go forward */
1974
0
      if (lex[++(*ps)] == LWS_MINILEX_FAIL_CODING)
1975
0
        goto nope;
1976
1977
0
      if (lex[*ps] < LWS_MINILEX_FAIL_CODING) {
1978
        /* this is a terminal marker */
1979
0
        *match = (int)lex[++(*ps)];
1980
0
        return LWS_MINILEX_MATCH;
1981
0
      }
1982
1983
0
      return LWS_MINILEX_CONTINUE;
1984
0
    }
1985
1986
0
    if (lex[*ps] == LWS_MINILEX_FAIL_CODING)
1987
0
      goto nope;
1988
1989
    /* b7 = 0, end or 3-byte */
1990
0
    if (lex[*ps] < LWS_MINILEX_FAIL_CODING) {
1991
      /* this is a terminal marker */
1992
0
      *match = (int)lex[++(*ps)];
1993
0
      return LWS_MINILEX_MATCH;
1994
0
    }
1995
1996
0
    if (lex[*ps] == c) { /* goto-on-match */
1997
0
      *ps = (int16_t)(*ps + (lex[(*ps) + 1]) +
1998
0
                (lex[(*ps) + 2] << 8));
1999
0
      return LWS_MINILEX_CONTINUE;
2000
0
    }
2001
2002
    /* fall thru to next */
2003
0
    *ps = (int16_t)((*ps) + 3);
2004
0
  }
2005
2006
0
nope:
2007
0
  *ps = (int16_t)-1;
2008
2009
0
  return LWS_MINILEX_FAIL;
2010
0
}
2011
2012
unsigned int
2013
lws_sigbits(uintptr_t u)
2014
0
{
2015
0
  uintptr_t mask = (uintptr_t)(0xffllu << ((sizeof(u) - 1) * 8)),
2016
0
      m1   = (uintptr_t)(0x80llu << ((sizeof(u) - 1) * 8));
2017
0
  unsigned int n;
2018
2019
0
  for (n = sizeof(u) * 8; n > 0; n -= 8) {
2020
0
    if (u & mask)
2021
0
      break;
2022
0
    mask >>= 8;
2023
0
    m1 >>= 8;
2024
0
  }
2025
2026
0
  if (!n)
2027
0
    return 1; /* not bits are set, we need at least 1 to represent */
2028
2029
0
  while (!(u & m1)) {
2030
0
    n--;
2031
0
    m1 >>= 1;
2032
0
  }
2033
2034
0
  return n;
2035
0
}
2036
2037
const lws_fx_t *
2038
lws_fx_add(lws_fx_t *r, const lws_fx_t *a, const lws_fx_t *b)
2039
0
{
2040
0
  int32_t w, sf;
2041
2042
0
  w = a->whole + b->whole;
2043
0
  sf = a->frac + b->frac;
2044
0
  if (sf >= 100000000) {
2045
0
    w++;
2046
0
    r->frac = sf - 100000000;
2047
0
  } else if (sf < -100000000) {
2048
0
    w--;
2049
0
    r->frac = sf + 100000000;
2050
0
  } else
2051
0
    r->frac = sf;
2052
2053
0
  r->whole = w;
2054
2055
0
  return r;
2056
0
}
2057
2058
const lws_fx_t *
2059
lws_fx_sub(lws_fx_t *r, const lws_fx_t *a, const lws_fx_t *b)
2060
0
{
2061
0
  int32_t w;
2062
2063
0
  if (a->whole >= b->whole) {
2064
0
    w = a->whole - b->whole;
2065
0
    if (a->frac >= b->frac)
2066
0
      r->frac = a->frac - b->frac;
2067
0
    else {
2068
0
      w--;
2069
0
      r->frac = (100000000 + a->frac) - b->frac;
2070
0
    }
2071
0
  } else {
2072
0
    w = -(b->whole - a->whole);
2073
0
    if (b->frac >= a->frac)
2074
0
      r->frac = b->frac - a->frac;
2075
0
    else {
2076
0
      w++;
2077
0
      r->frac = (100000000 + b->frac) - a->frac;
2078
0
    }
2079
0
  }
2080
0
  r->whole = w;
2081
2082
0
  return r;
2083
0
}
2084
2085
const lws_fx_t *
2086
lws_fx_mul(lws_fx_t *r, const lws_fx_t *a, const lws_fx_t *b)
2087
0
{
2088
0
  int64_t _c1, _c2;
2089
0
  int32_t w, t;
2090
0
  char neg = 0;
2091
2092
0
  assert(a->frac < LWS_FX_FRACTION_MSD);
2093
0
  assert(b->frac < LWS_FX_FRACTION_MSD);
2094
2095
  /* we can't use r as a temp, because it may alias on to a, b */
2096
2097
0
  w = a->whole * b->whole;
2098
2099
0
  if (!lws_neg(a) && !lws_neg(b)) {
2100
0
    _c2 = (((int64_t)((int64_t)a->frac) * (int64_t)b->frac) /
2101
0
              LWS_FX_FRACTION_MSD);
2102
0
    _c1 = ((int64_t)a->frac * ((int64_t)b->whole)) +
2103
0
            (((int64_t)a->whole) * (int64_t)b->frac) + _c2;
2104
0
    w += (int32_t)(_c1 / LWS_FX_FRACTION_MSD);
2105
0
  } else
2106
0
    if (lws_neg(a) && !lws_neg(b)) {
2107
0
      _c2 = (((int64_t)((int64_t)-a->frac) * (int64_t)b->frac) /
2108
0
                LWS_FX_FRACTION_MSD);
2109
0
      _c1 = ((int64_t)-a->frac * (-(int64_t)b->whole)) +
2110
0
             (((int64_t)a->whole) * (int64_t)b->frac) - _c2;
2111
0
      w += (int32_t)(_c1 / LWS_FX_FRACTION_MSD);
2112
0
      neg = 1;
2113
0
    } else
2114
0
      if (!lws_neg(a) && lws_neg(b)) {
2115
0
        _c2 = (((int64_t)((int64_t)a->frac) * (int64_t)-b->frac) /
2116
0
                  LWS_FX_FRACTION_MSD);
2117
0
        _c1 = ((int64_t)a->frac * ((int64_t)b->whole)) -
2118
0
               (((int64_t)a->whole) * (int64_t)-b->frac) - _c2;
2119
0
        w += (int32_t)(_c1 / LWS_FX_FRACTION_MSD);
2120
0
        neg = 1;
2121
0
      } else {
2122
0
        _c2 = (((int64_t)((int64_t)-a->frac) * (int64_t)-b->frac) /
2123
0
                  LWS_FX_FRACTION_MSD);
2124
0
        _c1 = ((int64_t)-a->frac * ((int64_t)b->whole)) +
2125
0
               (((int64_t)a->whole) * (int64_t)-b->frac) - _c2;
2126
0
        w -= (int32_t)(_c1 / LWS_FX_FRACTION_MSD);
2127
0
      }
2128
2129
0
  t = (int32_t)(_c1 % LWS_FX_FRACTION_MSD);
2130
0
  r->whole = w; /* don't need a,b any further... now we can write to r */
2131
0
  if (neg ^ !!(t < 0))
2132
0
    r->frac = -t;
2133
0
  else
2134
0
    r->frac = t;
2135
2136
0
  return r;
2137
0
}
2138
2139
const lws_fx_t *
2140
lws_fx_div(lws_fx_t *r, const lws_fx_t *a, const lws_fx_t *b)
2141
0
{
2142
0
  int64_t _a = lws_fix64_abs(a), _b = lws_fix64_abs(b), q = 0, d, m;
2143
2144
0
  if (!_b)
2145
0
    _a = 0;
2146
0
  else {
2147
0
    int c = 64 / 2 + 1;
2148
2149
0
    while (_a && c >= 0) {
2150
0
      d = _a / _b;
2151
0
      m = (_a % _b);
2152
0
      if (m < 0)
2153
0
        m = -m;
2154
0
      _a = m << 1;
2155
0
      q += d << (c--);
2156
0
    }
2157
0
    _a = q >> 1;
2158
0
  }
2159
2160
0
  if (lws_neg(a) ^ lws_neg(b)) {
2161
0
    r->whole = -(int32_t)(_a >> 32);
2162
0
    r->frac = -(int32_t)((100000000 * (_a & 0xffffffff)) >> 32);
2163
0
  } else {
2164
0
    r->whole = (int32_t)(_a >> 32);
2165
0
    r->frac = (int32_t)((100000000 * (_a & 0xffffffff)) >> 32);
2166
0
  }
2167
2168
0
  return r;
2169
0
}
2170
2171
const lws_fx_t *
2172
lws_fx_sqrt(lws_fx_t *r, const lws_fx_t *a)
2173
0
{
2174
0
  uint64_t t, q = 0, b = 1ull << 62, v = ((uint64_t)a->whole << 32) +
2175
0
         (((uint64_t)a->frac << 32) / LWS_FX_FRACTION_MSD);
2176
2177
0
  while (b > 0x40) {
2178
0
    t = q + b;
2179
0
    if (v >= t) {
2180
0
      v -= t;
2181
0
      q = t + b;
2182
0
    }
2183
0
    v <<= 1;
2184
0
    b >>= 1;
2185
0
  }
2186
2187
0
  r->whole = (int32_t)(q >> 48);
2188
0
  r->frac = (int32_t)((((q >> 16) & 0xffffffff) *
2189
0
          LWS_FX_FRACTION_MSD) >> 32);
2190
2191
0
  return r;
2192
0
}
2193
2194
/* returns < 0 if a < b, >0 if a > b, or 0 if exactly equal */
2195
2196
int
2197
lws_fx_comp(const lws_fx_t *a, const lws_fx_t *b)
2198
0
{
2199
0
  if (a->whole < b->whole)
2200
0
    return -1;
2201
0
  if (a->whole > b->whole)
2202
0
                return 1;
2203
2204
0
  if (a->frac < b->frac)
2205
0
    return -1;
2206
2207
0
  if (a->frac > b->frac)
2208
0
    return 1;
2209
2210
0
  return 0;
2211
0
}
2212
2213
int
2214
lws_fx_roundup(const lws_fx_t *a)
2215
0
{
2216
0
  if (!a->frac)
2217
0
    return a->whole;
2218
2219
0
  if (lws_neg(a))
2220
0
    return a->whole - 1;
2221
2222
0
  return a->whole + 1;
2223
0
}
2224
2225
LWS_VISIBLE LWS_EXTERN int
2226
lws_fx_rounddown(const lws_fx_t *a)
2227
0
{
2228
0
  return a->whole;
2229
0
}
2230
2231
LWS_VISIBLE LWS_EXTERN const char *
2232
lws_fx_string(const lws_fx_t *a, char *buf, size_t size)
2233
0
{
2234
0
  int n, m = 7;
2235
2236
0
  if (lws_neg(a))
2237
0
    n = lws_snprintf(buf, size - 1, "-%d.%08d",
2238
0
         (int)(a->whole < 0 ? -a->whole : a->whole),
2239
0
         (int)(a->frac < 0 ? -a->frac : a->frac));
2240
0
  else
2241
0
    n = lws_snprintf(buf, size - 1, "%d.%08d", (int)a->whole,
2242
0
         (int)a->frac);
2243
2244
0
  while (m-- && buf[n - 1] == '0')
2245
0
    n--;
2246
2247
0
  buf[n] = '\0';
2248
2249
0
  return buf;
2250
0
}