Coverage Report

Created: 2025-10-10 07:08

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/haproxy/include/haproxy/port_range.h
Line
Count
Source
1
/*
2
 * include/haproxy/port_range.h
3
 * This file defines everything needed to manage port ranges
4
 *
5
 * Copyright (C) 2000-2020 Willy Tarreau - w@1wt.eu
6
 *
7
 * This library is free software; you can redistribute it and/or
8
 * modify it under the terms of the GNU Lesser General Public
9
 * License as published by the Free Software Foundation, version 2.1
10
 * exclusively.
11
 *
12
 * This library is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15
 * Lesser General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU Lesser General Public
18
 * License along with this library; if not, write to the Free Software
19
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
20
 */
21
22
#ifndef _HAPROXY_PORT_RANGE_H
23
#define _HAPROXY_PORT_RANGE_H
24
25
#include <stdlib.h>
26
#include <haproxy/api.h>
27
#include <haproxy/port_range-t.h>
28
29
#define GET_NEXT_OFF(range, off) ((off) == (range)->size - 1 ? 0 : (off) + 1)
30
31
/* return an available port from range <range>, or zero if none is left */
32
static inline int port_range_alloc_port(struct port_range *range)
33
0
{
34
0
  int ret;
35
0
  int get;
36
0
  int put;
37
38
0
  get = _HA_ATOMIC_LOAD(&range->get);
39
0
  do {
40
    /* barrier to make sure get is loaded before put */
41
0
    __ha_barrier_atomic_load();
42
0
    put = _HA_ATOMIC_LOAD(&range->put_t);
43
0
    if (unlikely(put == get))
44
0
      return 0;
45
0
    ret = range->ports[get];
46
0
  } while (!(_HA_ATOMIC_CAS(&range->get, &get, GET_NEXT_OFF(range, get))));
47
0
  return ret;
48
0
}
Unexecuted instantiation: fd.c:port_range_alloc_port
Unexecuted instantiation: server.c:port_range_alloc_port
Unexecuted instantiation: check.c:port_range_alloc_port
Unexecuted instantiation: proto_tcp.c:port_range_alloc_port
49
50
/* release port <port> into port range <range>. Does nothing if <port> is zero
51
 * nor if <range> is null. The caller is responsible for marking the port
52
 * unused by either setting the port to zero or the range to NULL.
53
 */
54
static inline void port_range_release_port(struct port_range *range, int port)
55
0
{
56
0
  int put;
57
58
0
  if (!port || !range)
59
0
    return;
60
61
0
  put = range->put_h;
62
  /* put_h is reserved for producers, so that they can each get a
63
   * free slot, put_t is what is used by consumers to know if there's
64
   * elements available or not
65
   */
66
  /* First reserve or slot, we know the ring buffer can't be full,
67
   * as we will only ever release port we allocated before
68
   */
69
0
  while (!(_HA_ATOMIC_CAS(&range->put_h, &put, GET_NEXT_OFF(range, put))));
70
0
  _HA_ATOMIC_STORE(&range->ports[put], port);
71
  /* Barrier to make sure the new port is visible before we change put_t */
72
0
  __ha_barrier_atomic_store();
73
  /* Wait until all the threads that got a slot before us are done */
74
0
  while ((volatile int)range->put_t != put)
75
0
    __ha_compiler_barrier();
76
  /* Let the world know we're done, and any potential consumer they
77
   * can use that port.
78
   */
79
0
  _HA_ATOMIC_STORE(&range->put_t, GET_NEXT_OFF(range, put));
80
0
}
Unexecuted instantiation: fd.c:port_range_release_port
Unexecuted instantiation: server.c:port_range_release_port
Unexecuted instantiation: check.c:port_range_release_port
Unexecuted instantiation: proto_tcp.c:port_range_release_port
81
82
/* return a new initialized port range of N ports. The ports are not
83
 * filled in, it's up to the caller to do it.
84
 */
85
static inline struct port_range *port_range_alloc_range(int n)
86
0
{
87
0
  struct port_range *ret;
88
0
  ret = calloc(1, sizeof(struct port_range) +
89
0
         (n + 1) * sizeof(((struct port_range *)0)->ports[0]));
90
0
  if (!ret)
91
0
    return NULL;
92
0
  ret->size = n + 1;
93
  /* Start at the first free element */
94
0
  ret->put_h = ret->put_t = n;
95
0
  return ret;
96
0
}
Unexecuted instantiation: fd.c:port_range_alloc_range
Unexecuted instantiation: server.c:port_range_alloc_range
Unexecuted instantiation: check.c:port_range_alloc_range
Unexecuted instantiation: proto_tcp.c:port_range_alloc_range
97
98
#endif /* _HAPROXY_PORT_RANGE_H */
99
100
/*
101
 * Local variables:
102
 *  c-indent-level: 8
103
 *  c-basic-offset: 8
104
 * End:
105
 */