Coverage Report

Created: 2026-01-25 06:59

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/rtpproxy/external/libre/src/sa/sa.c
Line
Count
Source
1
/**
2
 * @file sa.c  Socket Address
3
 *
4
 * Copyright (C) 2010 Creytiv.com
5
 */
6
#define _BSD_SOURCE 1
7
#define _DEFAULT_SOURCE 1
8
#include <string.h>
9
#include <re_types.h>
10
#include <re_fmt.h>
11
#include <re_list.h>
12
#include <re_sa.h>
13
#include "sa.h"
14
15
16
0
#define DEBUG_MODULE "sa"
17
#define DEBUG_LEVEL 5
18
#include <re_dbg.h>
19
20
21
/**
22
 * Initialize a Socket Address
23
 *
24
 * @param sa Socket Address
25
 * @param af Address Family
26
 */
27
void sa_init(struct sa *sa, int af)
28
14.4k
{
29
14.4k
  if (!sa)
30
0
    return;
31
32
14.4k
  memset(sa, 0, sizeof(*sa));
33
14.4k
  sa->u.sa.sa_family = af;
34
14.4k
  sa->len = sizeof(sa->u);
35
14.4k
}
36
37
38
/**
39
 * Set a Socket Address from a PL string
40
 *
41
 * @param sa   Socket Address
42
 * @param addr IP-address
43
 * @param port Port number
44
 *
45
 * @return 0 if success, otherwise errorcode
46
 */
47
int sa_set(struct sa *sa, const struct pl *addr, uint16_t port)
48
17.7k
{
49
17.7k
  char buf[64];
50
51
17.7k
  (void)pl_strcpy(addr, buf, sizeof(buf));
52
17.7k
  return sa_set_str(sa, buf, port);
53
17.7k
}
54
55
56
/**
57
 * Set a Socket Address from a string
58
 *
59
 * @param sa   Socket Address
60
 * @param addr IP-address
61
 * @param port Port number
62
 *
63
 * @return 0 if success, otherwise errorcode
64
 */
65
int sa_set_str(struct sa *sa, const char *addr, uint16_t port)
66
17.7k
{
67
17.7k
  int err;
68
69
17.7k
  if (!sa || !addr)
70
0
    return EINVAL;
71
72
17.7k
  err = net_inet_pton(addr, sa);
73
17.7k
  if (err)
74
163
    return err;
75
76
17.6k
  switch (sa->u.sa.sa_family) {
77
78
14.8k
  case AF_INET:
79
14.8k
    sa->u.in.sin_port = htons(port);
80
14.8k
    sa->len = sizeof(struct sockaddr_in);
81
14.8k
    break;
82
83
0
#ifdef HAVE_INET6
84
2.74k
  case AF_INET6:
85
2.74k
    sa->u.in6.sin6_port = htons(port);
86
2.74k
    sa->len = sizeof(struct sockaddr_in6);
87
2.74k
    break;
88
0
#endif
89
90
0
  default:
91
0
    return EAFNOSUPPORT;
92
17.6k
  }
93
94
17.6k
  return 0;
95
17.6k
}
96
97
98
/**
99
 * Set a Socket Address from an IPv4 address
100
 *
101
 * @param sa   Socket Address
102
 * @param addr IPv4 address in host order
103
 * @param port Port number
104
 *
105
 * @return 0 if success, otherwise errorcode
106
 */
107
void sa_set_in(struct sa *sa, uint32_t addr, uint16_t port)
108
685
{
109
685
  if (!sa)
110
0
    return;
111
112
685
  sa->u.in.sin_family = AF_INET;
113
685
  sa->u.in.sin_addr.s_addr = htonl(addr);
114
685
  sa->u.in.sin_port = htons(port);
115
685
  sa->len = sizeof(struct sockaddr_in);
116
685
}
117
118
119
/**
120
 * Set a Socket Address from an IPv6 address
121
 *
122
 * @param sa   Socket Address
123
 * @param addr IPv6 address
124
 * @param port Port number
125
 *
126
 * @return 0 if success, otherwise errorcode
127
 */
128
void sa_set_in6(struct sa *sa, const uint8_t *addr, uint16_t port)
129
261
{
130
261
  if (!sa)
131
0
    return;
132
133
261
#ifdef HAVE_INET6
134
261
  sa->u.in6.sin6_family = AF_INET6;
135
261
  memcpy(&sa->u.in6.sin6_addr, addr, 16);
136
261
  sa->u.in6.sin6_port = htons(port);
137
261
  sa->len = sizeof(struct sockaddr_in6);
138
#else
139
  (void)addr;
140
  (void)port;
141
#endif
142
261
}
143
144
145
/**
146
 * Set a Socket Address from a sockaddr
147
 *
148
 * @param sa Socket Address
149
 * @param s  Sockaddr
150
 *
151
 * @return 0 if success, otherwise errorcode
152
 */
153
int sa_set_sa(struct sa *sa, const struct sockaddr *s)
154
0
{
155
0
  if (!sa || !s)
156
0
    return EINVAL;
157
158
0
  switch (s->sa_family) {
159
160
0
  case AF_INET:
161
0
    memcpy(&sa->u.in, s, sizeof(struct sockaddr_in));
162
0
    sa->len = sizeof(struct sockaddr_in);
163
0
    break;
164
165
0
#ifdef HAVE_INET6
166
0
  case AF_INET6:
167
0
    memcpy(&sa->u.in6, s, sizeof(struct sockaddr_in6));
168
0
    sa->len = sizeof(struct sockaddr_in6);
169
0
    break;
170
0
#endif
171
172
0
  default:
173
0
    return EAFNOSUPPORT;
174
0
  }
175
176
0
  sa->u.sa.sa_family = s->sa_family;
177
178
0
  return 0;
179
0
}
180
181
182
/**
183
 * Set the port number on a Socket Address
184
 *
185
 * @param sa   Socket Address
186
 * @param port Port number
187
 */
188
void sa_set_port(struct sa *sa, uint16_t port)
189
16.2k
{
190
16.2k
  if (!sa)
191
0
    return;
192
193
16.2k
  switch (sa->u.sa.sa_family) {
194
195
15.7k
  case AF_INET:
196
15.7k
    sa->u.in.sin_port = htons(port);
197
15.7k
    break;
198
199
0
#ifdef HAVE_INET6
200
536
  case AF_INET6:
201
536
    sa->u.in6.sin6_port = htons(port);
202
536
    break;
203
0
#endif
204
205
0
  default:
206
0
    DEBUG_WARNING("sa_set_port: no af %d (port %u)\n",
207
0
            sa->u.sa.sa_family, port);
208
0
    break;
209
16.2k
  }
210
16.2k
}
211
212
213
/**
214
 * Set a socket address from a string of type "address:port"
215
 * IPv6 addresses must be encapsulated in square brackets.
216
 *
217
 * @param sa   Socket Address
218
 * @param str  Address and port string
219
 * @param len  Length of string
220
 *
221
 * @return 0 if success, otherwise errorcode
222
 *
223
 * Example strings:
224
 *
225
 * <pre>
226
 *   1.2.3.4:1234
227
 *   [::1]:1234
228
 *   [::]:5060
229
 * </pre>
230
 */
231
int sa_decode(struct sa *sa, const char *str, size_t len)
232
0
{
233
0
  struct pl addr, port, pl;
234
0
  const char *c;
235
236
0
  if (!sa || !str || !len)
237
0
    return EINVAL;
238
239
0
  pl.p = str;
240
0
  pl.l = len;
241
242
0
  if ('[' == str[0] && (c = pl_strchr(&pl, ']'))) {
243
0
    addr.p = str + 1;
244
0
    addr.l = c - str - 1;
245
0
    ++c;
246
0
  }
247
0
  else if (NULL != (c = pl_strchr(&pl, ':'))) {
248
0
    addr.p = str;
249
0
    addr.l = c - str;
250
0
  }
251
0
  else {
252
0
    return EINVAL;
253
0
  }
254
255
0
  if (len < (size_t)(c - str + 2))
256
0
    return EINVAL;
257
258
0
  if (':' != *c)
259
0
    return EINVAL;
260
261
0
  port.p = ++c;
262
0
  port.l = len + str - c;
263
264
0
  return sa_set(sa, &addr, pl_u32(&port));
265
0
}
266
267
268
/**
269
 * Get the Address Family of a Socket Address
270
 *
271
 * @param sa Socket Address
272
 *
273
 * @return Address Family
274
 */
275
int sa_af(const struct sa *sa)
276
0
{
277
0
  return sa ? sa->u.sa.sa_family : AF_UNSPEC;
278
0
}
279
280
281
/**
282
 * Get the IPv4-address of a Socket Address
283
 *
284
 * @param sa Socket Address
285
 *
286
 * @return IPv4 address in host order
287
 */
288
uint32_t sa_in(const struct sa *sa)
289
0
{
290
0
  return sa ? ntohl(sa->u.in.sin_addr.s_addr) : 0;
291
0
}
292
293
294
/**
295
 * Get the IPv6-address of a Socket Address
296
 *
297
 * @param sa   Socket Address
298
 * @param addr On return, contains the IPv6-address
299
 */
300
void sa_in6(const struct sa *sa, uint8_t *addr)
301
0
{
302
0
  if (!sa || !addr)
303
0
    return;
304
305
0
#ifdef HAVE_INET6
306
0
  memcpy(addr, &sa->u.in6.sin6_addr, 16);
307
0
#endif
308
0
}
309
310
311
/**
312
 * Convert a Socket Address to Presentation format
313
 *
314
 * @param sa   Socket Address
315
 * @param buf  Buffer to store presentation format
316
 * @param size Buffer size
317
 *
318
 * @return 0 if success, otherwise errorcode
319
 */
320
int sa_ntop(const struct sa *sa, char *buf, int size)
321
11.3k
{
322
11.3k
  return net_inet_ntop(sa, buf, size);
323
11.3k
}
324
325
326
/**
327
 * Get the port number from a Socket Address
328
 *
329
 * @param sa Socket Address
330
 *
331
 * @return Port number  in host order
332
 */
333
uint16_t sa_port(const struct sa *sa)
334
21.8k
{
335
21.8k
  if (!sa)
336
0
    return 0;
337
338
21.8k
  switch (sa->u.sa.sa_family) {
339
340
20.8k
  case AF_INET:
341
20.8k
    return ntohs(sa->u.in.sin_port);
342
343
0
#ifdef HAVE_INET6
344
967
  case AF_INET6:
345
967
    return ntohs(sa->u.in6.sin6_port);
346
0
#endif
347
348
0
  default:
349
0
    return 0;
350
21.8k
  }
351
21.8k
}
352
353
354
/**
355
 * Check if a Socket Address is set
356
 *
357
 * @param sa   Socket Address
358
 * @param flag Flags specifying which fields to check
359
 *
360
 * @return true if set, false if not set
361
 */
362
bool sa_isset(const struct sa *sa, int flag)
363
24.0k
{
364
24.0k
  if (!sa)
365
0
    return false;
366
367
24.0k
  switch (sa->u.sa.sa_family) {
368
369
0
  case AF_INET:
370
0
    if (flag & SA_ADDR)
371
0
      if (INADDR_ANY == sa->u.in.sin_addr.s_addr)
372
0
        return false;
373
0
    if (flag & SA_PORT)
374
0
      if (0 == sa->u.in.sin_port)
375
0
        return false;
376
0
    break;
377
378
0
#ifdef HAVE_INET6
379
0
  case AF_INET6:
380
0
    if (flag & SA_ADDR)
381
0
      if (IN6_IS_ADDR_UNSPECIFIED(&sa->u.in6.sin6_addr))
382
0
        return false;
383
0
    if (flag & SA_PORT)
384
0
      if (0 == sa->u.in6.sin6_port)
385
0
        return false;
386
0
    break;
387
0
#endif
388
389
24.0k
  default:
390
24.0k
    return false;
391
24.0k
  }
392
393
0
  return true;
394
24.0k
}
395
396
397
/**
398
 * Calculate the hash value of a Socket Address
399
 *
400
 * @param sa   Socket Address
401
 * @param flag Flags specifying which fields to use
402
 *
403
 * @return Hash value
404
 */
405
uint32_t sa_hash(const struct sa *sa, int flag)
406
6.49k
{
407
6.49k
  uint32_t v = 0;
408
409
6.49k
  if (!sa)
410
0
    return 0;
411
412
6.49k
  switch (sa->u.sa.sa_family) {
413
414
6.41k
  case AF_INET:
415
6.41k
    if (flag & SA_ADDR)
416
6.41k
      v += ntohl(sa->u.in.sin_addr.s_addr);
417
6.41k
    if (flag & SA_PORT)
418
0
      v += ntohs(sa->u.in.sin_port);
419
6.41k
    break;
420
421
0
#ifdef HAVE_INET6
422
85
  case AF_INET6:
423
85
    if (flag & SA_ADDR) {
424
85
      uint32_t *a = (uint32_t *)&sa->u.in6.sin6_addr;
425
85
      v += a[0] ^ a[1] ^ a[2] ^ a[3];
426
85
    }
427
85
    if (flag & SA_PORT)
428
0
      v += ntohs(sa->u.in6.sin6_port);
429
85
    break;
430
0
#endif
431
432
0
  default:
433
0
    DEBUG_WARNING("sa_hash: unknown af %d\n", sa->u.sa.sa_family);
434
0
    return 0;
435
6.49k
  }
436
437
6.49k
  return v;
438
6.49k
}
439
440
441
/**
442
 * Copy a Socket Address
443
 *
444
 * @param dst Socket Address to be written
445
 * @param src Socket Address to be copied
446
 */
447
void sa_cpy(struct sa *dst, const struct sa *src)
448
32.9k
{
449
32.9k
  if (!dst || !src)
450
0
    return;
451
452
32.9k
  memcpy(dst, src, sizeof(*dst));
453
32.9k
}
454
455
456
/**
457
 * Compare two Socket Address objects
458
 *
459
 * @param l    Socket Address number one
460
 * @param r    Socket Address number two
461
 * @param flag Flags specifying which fields to use
462
 *
463
 * @return true if match, false if no match
464
 */
465
bool sa_cmp(const struct sa *l, const struct sa *r, int flag)
466
22.4k
{
467
22.4k
  if (!l || !r)
468
0
    return false;
469
470
22.4k
  if (l == r)
471
0
    return true;
472
473
22.4k
  if (l->u.sa.sa_family != r->u.sa.sa_family)
474
767
    return false;
475
476
21.6k
  switch (l->u.sa.sa_family) {
477
478
18.8k
  case AF_INET:
479
18.8k
    if (flag & SA_ADDR)
480
18.8k
      if (l->u.in.sin_addr.s_addr != r->u.in.sin_addr.s_addr)
481
12.5k
        return false;
482
6.27k
    if (flag & SA_PORT)
483
6.27k
      if (l->u.in.sin_port != r->u.in.sin_port)
484
6.10k
        return false;
485
166
    break;
486
487
166
#ifdef HAVE_INET6
488
2.81k
  case AF_INET6:
489
2.81k
    if (flag & SA_ADDR)
490
2.81k
      if (memcmp(&l->u.in6.sin6_addr,
491
2.81k
           &r->u.in6.sin6_addr, 16))
492
1.57k
        return false;
493
1.24k
    if (flag & SA_PORT)
494
1.24k
      if (l->u.in6.sin6_port != r->u.in6.sin6_port)
495
330
        return false;
496
913
    break;
497
913
#endif
498
499
913
  default:
500
0
    return false;
501
21.6k
  }
502
503
1.07k
  return true;
504
21.6k
}
505
506
507
/** IPv4 Link-local test */
508
#define IN_IS_ADDR_LINKLOCAL(a)         \
509
0
  (((a) & htonl(0xffff0000)) == htonl (0xa9fe0000))
510
511
512
/**
513
 * Check if socket address is a link-local address
514
 *
515
 * @param sa Socket address
516
 *
517
 * @return true if link-local address, otherwise false
518
 */
519
bool sa_is_linklocal(const struct sa *sa)
520
0
{
521
0
  if (!sa)
522
0
    return false;
523
524
0
  switch (sa_af(sa)) {
525
526
0
  case AF_INET:
527
0
    return IN_IS_ADDR_LINKLOCAL(sa->u.in.sin_addr.s_addr);
528
529
0
#ifdef HAVE_INET6
530
0
  case AF_INET6:
531
0
    return IN6_IS_ADDR_LINKLOCAL(&sa->u.in6.sin6_addr);
532
0
#endif
533
534
0
  default:
535
0
    return false;
536
0
  }
537
0
}
538
539
540
/**
541
 * Check if socket address is a loopback address
542
 *
543
 * @param sa Socket address
544
 *
545
 * @return true if loopback address, otherwise false
546
 */
547
bool sa_is_loopback(const struct sa *sa)
548
0
{
549
0
  if (!sa)
550
0
    return false;
551
552
0
  switch (sa_af(sa)) {
553
554
0
  case AF_INET:
555
0
    return INADDR_LOOPBACK == ntohl(sa->u.in.sin_addr.s_addr);
556
557
0
#ifdef HAVE_INET6
558
0
  case AF_INET6:
559
0
    return IN6_IS_ADDR_LOOPBACK(&sa->u.in6.sin6_addr);
560
0
#endif
561
562
0
  default:
563
0
    return false;
564
0
  }
565
0
}
566
567
568
/**
569
 * Check if socket address is any/unspecified address
570
 *
571
 * @param sa Socket address
572
 *
573
 * @return true if any address, otherwise false
574
 */
575
bool sa_is_any(const struct sa *sa)
576
0
{
577
0
  if (!sa)
578
0
    return false;
579
580
0
  switch (sa_af(sa)) {
581
582
0
  case AF_INET:
583
0
    return INADDR_ANY == ntohl(sa->u.in.sin_addr.s_addr);
584
585
0
#ifdef HAVE_INET6
586
0
  case AF_INET6:
587
0
    return IN6_IS_ADDR_UNSPECIFIED(&sa->u.in6.sin6_addr);
588
0
#endif
589
590
0
  default:
591
0
    return false;
592
0
  }
593
0
}