|
|
@ -456,17 +456,17 @@ static int has_free_ports_loc(struct local_intf *loc, unsigned int num_ports) { |
|
|
return 0; |
|
|
return 0; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
if (num_ports > g_hash_table_size(loc->spec->port_pool.free_ports_ht)) { |
|
|
|
|
|
|
|
|
if (num_ports > loc->spec->port_pool.free_ports_q.length) { |
|
|
ilog(LOG_ERR, "Didn't find %d ports available for " STR_FORMAT "/%s", |
|
|
ilog(LOG_ERR, "Didn't find %d ports available for " STR_FORMAT "/%s", |
|
|
num_ports, STR_FMT(&loc->logical->name), |
|
|
num_ports, STR_FMT(&loc->logical->name), |
|
|
sockaddr_print_buf(&loc->spec->local_address.addr)); |
|
|
sockaddr_print_buf(&loc->spec->local_address.addr)); |
|
|
return 0; |
|
|
return 0; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
__C_DBG("Found %d ports available for " STR_FORMAT "/%s from total of %d free ports", |
|
|
|
|
|
|
|
|
__C_DBG("Found %d ports available for " STR_FORMAT "/%s from total of %u free ports", |
|
|
num_ports, STR_FMT(&loc->logical->name), |
|
|
num_ports, STR_FMT(&loc->logical->name), |
|
|
sockaddr_print_buf(&loc->spec->local_address.addr), |
|
|
sockaddr_print_buf(&loc->spec->local_address.addr), |
|
|
g_hash_table_size(loc->spec->port_pool.free_ports_ht)); |
|
|
|
|
|
|
|
|
loc->spec->port_pool.free_ports_q.length); |
|
|
|
|
|
|
|
|
return 1; |
|
|
return 1; |
|
|
} |
|
|
} |
|
|
@ -682,39 +682,34 @@ int is_local_endpoint(const struct intf_address *addr, unsigned int port) { |
|
|
/** |
|
|
/** |
|
|
* This function just (globally) reserves a port number, it doesn't provide any binding/unbinding. |
|
|
* This function just (globally) reserves a port number, it doesn't provide any binding/unbinding. |
|
|
*/ |
|
|
*/ |
|
|
static void reserve_port(GQueue * free_ports_q, GHashTable * free_ports_ht, |
|
|
|
|
|
|
|
|
static void reserve_port(struct port_pool *pp, |
|
|
GList * value_looked_up, unsigned int port) { |
|
|
GList * value_looked_up, unsigned int port) { |
|
|
|
|
|
|
|
|
g_queue_delete_link(free_ports_q, value_looked_up); |
|
|
|
|
|
g_hash_table_remove(free_ports_ht, GUINT_TO_POINTER(port)); |
|
|
|
|
|
|
|
|
g_queue_delete_link(&pp->free_ports_q, value_looked_up); |
|
|
|
|
|
pp->free_ports[port] = NULL; |
|
|
} |
|
|
} |
|
|
/** |
|
|
/** |
|
|
* This function just releases reserved port number, it doesn't provide any binding/unbinding. |
|
|
* This function just releases reserved port number, it doesn't provide any binding/unbinding. |
|
|
*/ |
|
|
*/ |
|
|
static void release_reserved_port(GQueue * free_ports_q, GHashTable * free_ports_ht, |
|
|
|
|
|
unsigned int port) { |
|
|
|
|
|
|
|
|
|
|
|
g_queue_push_tail(free_ports_q, GUINT_TO_POINTER(port)); |
|
|
|
|
|
GList * l = free_ports_q->tail; |
|
|
|
|
|
g_hash_table_replace(free_ports_ht, GUINT_TO_POINTER(port), l); |
|
|
|
|
|
|
|
|
static void release_reserved_port(struct port_pool *pp, unsigned int port) { |
|
|
|
|
|
g_queue_push_tail(&pp->free_ports_q, GUINT_TO_POINTER(port)); |
|
|
|
|
|
GList * l = pp->free_ports_q.tail; |
|
|
|
|
|
pp->free_ports[port] = l; |
|
|
} |
|
|
} |
|
|
/* Append a list of free ports within the min-max range */ |
|
|
/* Append a list of free ports within the min-max range */ |
|
|
static void __append_free_ports_to_int(struct intf_spec *spec) { |
|
|
static void __append_free_ports_to_int(struct intf_spec *spec) { |
|
|
unsigned int ports_amount, count; |
|
|
unsigned int ports_amount, count; |
|
|
|
|
|
|
|
|
GQueue * free_ports_q = &spec->port_pool.free_ports_q; |
|
|
|
|
|
GHashTable ** free_ports_ht = &spec->port_pool.free_ports_ht; |
|
|
|
|
|
|
|
|
|
|
|
if (!*free_ports_ht) |
|
|
|
|
|
*free_ports_ht = g_hash_table_new(g_direct_hash, g_direct_equal); |
|
|
|
|
|
|
|
|
struct port_pool *pp = &spec->port_pool; |
|
|
|
|
|
GQueue * free_ports_q = &pp->free_ports_q; |
|
|
|
|
|
|
|
|
if (spec->port_pool.max < spec->port_pool.min) { |
|
|
|
|
|
|
|
|
if (pp->max < pp->min) { |
|
|
ilog(LOG_WARNING, "Ports range: max value cannot be less than min"); |
|
|
ilog(LOG_WARNING, "Ports range: max value cannot be less than min"); |
|
|
return; |
|
|
return; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
/* range of possible ports */ |
|
|
/* range of possible ports */ |
|
|
ports_amount = spec->port_pool.max - spec->port_pool.min + 1; |
|
|
|
|
|
|
|
|
ports_amount = pp->max - pp->min + 1; |
|
|
count = ports_amount; |
|
|
count = ports_amount; |
|
|
|
|
|
|
|
|
if (ports_amount == 0) { |
|
|
if (ports_amount == 0) { |
|
|
@ -726,7 +721,7 @@ static void __append_free_ports_to_int(struct intf_spec *spec) { |
|
|
|
|
|
|
|
|
/* create an array to store the initial values within the range */ |
|
|
/* create an array to store the initial values within the range */ |
|
|
for (int i = 0; i < ports_amount; i++) |
|
|
for (int i = 0; i < ports_amount; i++) |
|
|
port_values[i] = spec->port_pool.min + i; |
|
|
|
|
|
|
|
|
port_values[i] = pp->min + i; |
|
|
|
|
|
|
|
|
/* generate N random numbers within the given range without duplicates, |
|
|
/* generate N random numbers within the given range without duplicates, |
|
|
* using the rolling dice algorithm */ |
|
|
* using the rolling dice algorithm */ |
|
|
@ -735,14 +730,14 @@ static void __append_free_ports_to_int(struct intf_spec *spec) { |
|
|
int j = ssl_random() % count; |
|
|
int j = ssl_random() % count; |
|
|
int value = port_values[j]; |
|
|
int value = port_values[j]; |
|
|
|
|
|
|
|
|
mutex_lock(&spec->port_pool.free_list_lock); |
|
|
|
|
|
|
|
|
mutex_lock(&pp->free_list_lock); |
|
|
g_queue_push_tail(free_ports_q, GUINT_TO_POINTER(value)); |
|
|
g_queue_push_tail(free_ports_q, GUINT_TO_POINTER(value)); |
|
|
/* store this new GList as value into the hash table */ |
|
|
/* store this new GList as value into the hash table */ |
|
|
GList * l = free_ports_q->tail; |
|
|
GList * l = free_ports_q->tail; |
|
|
/* The value retrieved from the hash table would then point |
|
|
/* The value retrieved from the hash table would then point |
|
|
* into the queue for quick removal */ |
|
|
* into the queue for quick removal */ |
|
|
g_hash_table_replace(*free_ports_ht, GUINT_TO_POINTER(value), l); |
|
|
|
|
|
mutex_unlock(&spec->port_pool.free_list_lock); |
|
|
|
|
|
|
|
|
pp->free_ports[value] = l; |
|
|
|
|
|
mutex_unlock(&pp->free_list_lock); |
|
|
|
|
|
|
|
|
port_values[j] = port_values[count - 1]; |
|
|
port_values[j] = port_values[count - 1]; |
|
|
count--; |
|
|
count--; |
|
|
@ -902,20 +897,16 @@ void interfaces_exclude_port(unsigned int port) { |
|
|
struct intf_spec *spec; |
|
|
struct intf_spec *spec; |
|
|
|
|
|
|
|
|
struct port_pool *pp; |
|
|
struct port_pool *pp; |
|
|
GQueue * free_ports_q; |
|
|
|
|
|
GHashTable * free_ports_ht; |
|
|
|
|
|
|
|
|
|
|
|
intf_spec_ht_iter iter; |
|
|
intf_spec_ht_iter iter; |
|
|
t_hash_table_iter_init(&iter, __intf_spec_addr_type_hash); |
|
|
t_hash_table_iter_init(&iter, __intf_spec_addr_type_hash); |
|
|
while (t_hash_table_iter_next(&iter, NULL, &spec)) { |
|
|
while (t_hash_table_iter_next(&iter, NULL, &spec)) { |
|
|
pp = &spec->port_pool; |
|
|
pp = &spec->port_pool; |
|
|
free_ports_q = &pp->free_ports_q; |
|
|
|
|
|
free_ports_ht = pp->free_ports_ht; |
|
|
|
|
|
|
|
|
|
|
|
mutex_lock(&pp->free_list_lock); |
|
|
mutex_lock(&pp->free_list_lock); |
|
|
ll = g_hash_table_lookup(free_ports_ht, GUINT_TO_POINTER(port)); |
|
|
|
|
|
|
|
|
ll = pp->free_ports[port]; |
|
|
if (ll) |
|
|
if (ll) |
|
|
reserve_port(free_ports_q, free_ports_ht, ll, port); |
|
|
|
|
|
|
|
|
reserve_port(pp, ll, port); |
|
|
mutex_unlock(&pp->free_list_lock); |
|
|
mutex_unlock(&pp->free_list_lock); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
@ -996,9 +987,6 @@ static void release_port_now(socket_t *r, struct intf_spec *spec) { |
|
|
unsigned int port = r->local.port; |
|
|
unsigned int port = r->local.port; |
|
|
struct port_pool *pp = &spec->port_pool; |
|
|
struct port_pool *pp = &spec->port_pool; |
|
|
|
|
|
|
|
|
GQueue * free_ports_q = &pp->free_ports_q; |
|
|
|
|
|
GHashTable * free_ports_ht = pp->free_ports_ht; |
|
|
|
|
|
|
|
|
|
|
|
__C_DBG("Trying to release the port '%u'", port); |
|
|
__C_DBG("Trying to release the port '%u'", port); |
|
|
|
|
|
|
|
|
if (close_socket(r) == 0) { |
|
|
if (close_socket(r) == 0) { |
|
|
@ -1008,7 +996,7 @@ static void release_port_now(socket_t *r, struct intf_spec *spec) { |
|
|
|
|
|
|
|
|
/* first return the engaged port back */ |
|
|
/* first return the engaged port back */ |
|
|
mutex_lock(&pp->free_list_lock); |
|
|
mutex_lock(&pp->free_list_lock); |
|
|
release_reserved_port(free_ports_q, free_ports_ht, port); |
|
|
|
|
|
|
|
|
release_reserved_port(pp, port); |
|
|
mutex_unlock(&pp->free_list_lock); |
|
|
mutex_unlock(&pp->free_list_lock); |
|
|
} else { |
|
|
} else { |
|
|
ilog(LOG_WARNING, "Unable to close the socket for port '%u'", port); |
|
|
ilog(LOG_WARNING, "Unable to close the socket for port '%u'", port); |
|
|
@ -1066,7 +1054,6 @@ int __get_consecutive_ports(socket_q *out, unsigned int num_ports, unsigned int |
|
|
|
|
|
|
|
|
struct port_pool * pp = &spec->port_pool; /* port pool for a given local interface */ |
|
|
struct port_pool * pp = &spec->port_pool; /* port pool for a given local interface */ |
|
|
GQueue * free_ports_q; |
|
|
GQueue * free_ports_q; |
|
|
GHashTable * free_ports_ht; |
|
|
|
|
|
|
|
|
|
|
|
if (num_ports == 0) { |
|
|
if (num_ports == 0) { |
|
|
ilog(LOG_ERR, "Number of ports to be engaged is '%d', can't handle it like that", |
|
|
ilog(LOG_ERR, "Number of ports to be engaged is '%d', can't handle it like that", |
|
|
@ -1081,10 +1068,9 @@ int __get_consecutive_ports(socket_q *out, unsigned int num_ports, unsigned int |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
free_ports_q = &pp->free_ports_q; |
|
|
free_ports_q = &pp->free_ports_q; |
|
|
free_ports_ht = pp->free_ports_ht; |
|
|
|
|
|
|
|
|
|
|
|
/* a presence of free lists data is critical for us */ |
|
|
/* a presence of free lists data is critical for us */ |
|
|
if (!(free_ports_q && free_ports_q->head) || !free_ports_ht) { |
|
|
|
|
|
|
|
|
if (!(free_ports_q && free_ports_q->head)) { |
|
|
ilog(LOG_ERR, "Failure while trying to get a list of free ports"); |
|
|
ilog(LOG_ERR, "Failure while trying to get a list of free ports"); |
|
|
goto fail; |
|
|
goto fail; |
|
|
} |
|
|
} |
|
|
@ -1093,14 +1079,14 @@ int __get_consecutive_ports(socket_q *out, unsigned int num_ports, unsigned int |
|
|
if (wanted_start_port > 0) { |
|
|
if (wanted_start_port > 0) { |
|
|
ilog(LOG_DEBUG, "A specific port value is requested, wanted_start_port: '%d'", wanted_start_port); |
|
|
ilog(LOG_DEBUG, "A specific port value is requested, wanted_start_port: '%d'", wanted_start_port); |
|
|
mutex_lock(&pp->free_list_lock); |
|
|
mutex_lock(&pp->free_list_lock); |
|
|
GList *l = g_hash_table_lookup(free_ports_ht, GUINT_TO_POINTER(wanted_start_port)); |
|
|
|
|
|
|
|
|
GList *l = pp->free_ports[wanted_start_port]; |
|
|
if (!l) { |
|
|
if (!l) { |
|
|
/* if engaged already, just select any other (so default logic) */ |
|
|
/* if engaged already, just select any other (so default logic) */ |
|
|
ilog(LOG_WARN, "This requested port has been already engaged, can't take it."); |
|
|
ilog(LOG_WARN, "This requested port has been already engaged, can't take it."); |
|
|
wanted_start_port = 0; /* take what is proposed by FIFO instead */ |
|
|
wanted_start_port = 0; /* take what is proposed by FIFO instead */ |
|
|
} else { |
|
|
} else { |
|
|
/* we got the port, and we are sure it wasn't engaged */ |
|
|
/* we got the port, and we are sure it wasn't engaged */ |
|
|
reserve_port(free_ports_q, free_ports_ht, l, wanted_start_port); |
|
|
|
|
|
|
|
|
reserve_port(pp, l, wanted_start_port); |
|
|
port = wanted_start_port; |
|
|
port = wanted_start_port; |
|
|
} |
|
|
} |
|
|
mutex_unlock(&pp->free_list_lock); |
|
|
mutex_unlock(&pp->free_list_lock); |
|
|
@ -1155,14 +1141,14 @@ new_cycle: |
|
|
ilog(LOG_ERR, "Failure while trying to get a port from the list"); |
|
|
ilog(LOG_ERR, "Failure while trying to get a port from the list"); |
|
|
goto fail; |
|
|
goto fail; |
|
|
} |
|
|
} |
|
|
g_hash_table_remove(free_ports_ht, GUINT_TO_POINTER(port)); /* RTP */ |
|
|
|
|
|
|
|
|
pp->free_ports[port] = NULL; /* RTP */ |
|
|
mutex_unlock(&pp->free_list_lock); |
|
|
mutex_unlock(&pp->free_list_lock); |
|
|
|
|
|
|
|
|
/* ports for RTP must be even, if there is an additional port for RTCP */ |
|
|
/* ports for RTP must be even, if there is an additional port for RTCP */ |
|
|
if (num_ports > 1 && (port & 1)) { |
|
|
if (num_ports > 1 && (port & 1)) { |
|
|
/* return port for RTP back and try again */ |
|
|
/* return port for RTP back and try again */ |
|
|
mutex_lock(&pp->free_list_lock); |
|
|
mutex_lock(&pp->free_list_lock); |
|
|
release_reserved_port(free_ports_q, free_ports_ht, port); |
|
|
|
|
|
|
|
|
release_reserved_port(pp, port); |
|
|
mutex_unlock(&pp->free_list_lock); |
|
|
mutex_unlock(&pp->free_list_lock); |
|
|
goto new_cycle; |
|
|
goto new_cycle; |
|
|
} |
|
|
} |
|
|
@ -1174,11 +1160,11 @@ new_cycle: |
|
|
additional_port++; |
|
|
additional_port++; |
|
|
|
|
|
|
|
|
mutex_lock(&pp->free_list_lock); |
|
|
mutex_lock(&pp->free_list_lock); |
|
|
GList *l = g_hash_table_lookup(free_ports_ht, GUINT_TO_POINTER(additional_port)); |
|
|
|
|
|
|
|
|
GList *l = pp->free_ports[additional_port]; |
|
|
|
|
|
|
|
|
if (!l) { |
|
|
if (!l) { |
|
|
/* return port for RTP back and try again */ |
|
|
/* return port for RTP back and try again */ |
|
|
release_reserved_port(free_ports_q, free_ports_ht, port); |
|
|
|
|
|
|
|
|
release_reserved_port(pp, port); |
|
|
mutex_unlock(&pp->free_list_lock); |
|
|
mutex_unlock(&pp->free_list_lock); |
|
|
|
|
|
|
|
|
/* check if we managed to enagage anything in previous for-cycles */ |
|
|
/* check if we managed to enagage anything in previous for-cycles */ |
|
|
@ -1186,14 +1172,14 @@ new_cycle: |
|
|
{ |
|
|
{ |
|
|
mutex_lock(&pp->free_list_lock); |
|
|
mutex_lock(&pp->free_list_lock); |
|
|
/* return additional ports back */ |
|
|
/* return additional ports back */ |
|
|
release_reserved_port(free_ports_q, free_ports_ht, additional_port); |
|
|
|
|
|
|
|
|
release_reserved_port(pp, additional_port); |
|
|
mutex_unlock(&pp->free_list_lock); |
|
|
mutex_unlock(&pp->free_list_lock); |
|
|
} |
|
|
} |
|
|
goto new_cycle; |
|
|
goto new_cycle; |
|
|
|
|
|
|
|
|
} else { |
|
|
} else { |
|
|
/* engage this port right away */ |
|
|
/* engage this port right away */ |
|
|
reserve_port(free_ports_q, free_ports_ht, l, additional_port); |
|
|
|
|
|
|
|
|
reserve_port(pp, l, additional_port); |
|
|
mutex_unlock(&pp->free_list_lock); |
|
|
mutex_unlock(&pp->free_list_lock); |
|
|
|
|
|
|
|
|
/* track for which additional ports, we have to open sockets */ |
|
|
/* track for which additional ports, we have to open sockets */ |
|
|
@ -1221,7 +1207,7 @@ new_cycle: |
|
|
while ((port = GPOINTER_TO_UINT(g_queue_pop_head(&ports_to_engage)))) |
|
|
while ((port = GPOINTER_TO_UINT(g_queue_pop_head(&ports_to_engage)))) |
|
|
{ |
|
|
{ |
|
|
mutex_lock(&pp->free_list_lock); |
|
|
mutex_lock(&pp->free_list_lock); |
|
|
release_reserved_port(free_ports_q, free_ports_ht, port); |
|
|
|
|
|
|
|
|
release_reserved_port(pp, port); |
|
|
mutex_unlock(&pp->free_list_lock); |
|
|
mutex_unlock(&pp->free_list_lock); |
|
|
} |
|
|
} |
|
|
/* ports which are already bound to a socket, will be freed by `free_port()` */ |
|
|
/* ports which are already bound to a socket, will be freed by `free_port()` */ |
|
|
@ -3244,9 +3230,6 @@ void interfaces_free(void) { |
|
|
struct intf_spec *spec; |
|
|
struct intf_spec *spec; |
|
|
while (t_hash_table_iter_next(&s_iter, NULL, &spec)) { |
|
|
while (t_hash_table_iter_next(&s_iter, NULL, &spec)) { |
|
|
struct port_pool *pp = &spec->port_pool; |
|
|
struct port_pool *pp = &spec->port_pool; |
|
|
if (pp->free_ports_ht) { |
|
|
|
|
|
g_hash_table_destroy(pp->free_ports_ht); |
|
|
|
|
|
} |
|
|
|
|
|
g_queue_clear(&pp->free_ports_q); |
|
|
g_queue_clear(&pp->free_ports_q); |
|
|
mutex_destroy(&pp->free_list_lock); |
|
|
mutex_destroy(&pp->free_list_lock); |
|
|
g_slice_free1(sizeof(*spec), spec); |
|
|
g_slice_free1(sizeof(*spec), spec); |
|
|
|