addresspool: return reason of failure

Let gst_rtsp_address_pool_reserve_address() return the reason why
the address could not be reserved.

Fixes https://bugzilla.gnome.org/show_bug.cgi?id=708229
This commit is contained in:
Patrick Radizi 2013-09-24 17:30:18 +02:00 committed by Wim Taymans
parent c7bed54b87
commit 7b0ad7c25f
4 changed files with 160 additions and 85 deletions

View file

@ -585,64 +585,26 @@ gst_rtsp_address_pool_dump (GstRTSPAddressPool * pool)
g_mutex_unlock (&priv->lock);
}
/**
* gst_rtsp_address_pool_reserve_address:
* @pool: a #GstRTSPAddressPool
* @address: The IP address to reserve
* @port: The first port to reserve
* @n_ports: The number of ports
* @ttl: The requested ttl
*
* Take a specific address and ports from @pool. @n_ports consecutive
* ports will be allocated of which the first one can be found in
* @port.
*
* If @ttl is 0, @address should be a unicast address. If @ttl > 0, @address
* should be a valid multicast address.
*
* Returns: a #GstRTSPAddress that should be freed with gst_rtsp_address_free
* after use or %NULL when no address could be acquired.
*/
GstRTSPAddress *
gst_rtsp_address_pool_reserve_address (GstRTSPAddressPool * pool,
const gchar * address, guint port, guint n_ports, guint ttl)
static GList *
find_address_in_ranges (GList * addresses, Addr * addr, guint port,
guint n_ports, guint ttl)
{
GstRTSPAddressPoolPrivate *priv;
Addr input_addr;
GList *walk, *next;
AddrRange *result;
GstRTSPAddress *addr;
gboolean is_multicast;
g_return_val_if_fail (GST_IS_RTSP_ADDRESS_POOL (pool), NULL);
g_return_val_if_fail (address != NULL, NULL);
g_return_val_if_fail (port > 0, NULL);
g_return_val_if_fail (n_ports > 0, NULL);
priv = pool->priv;
result = NULL;
addr = NULL;
is_multicast = ttl != 0;
if (!fill_address (address, port, &input_addr, is_multicast))
goto invalid;
g_mutex_lock (&priv->lock);
/* go over available ranges */
for (walk = priv->addresses; walk; walk = next) {
for (walk = addresses; walk; walk = next) {
AddrRange *range;
gint skip_port, skip_addr;
range = walk->data;
next = walk->next;
/* Not the right type of address */
if (range->min.size != input_addr.size)
if (range->min.size != addr->size)
continue;
/* Check that the address is in the interval */
if (memcmp (range->min.bytes, input_addr.bytes, input_addr.size) > 0 ||
memcmp (range->max.bytes, input_addr.bytes, input_addr.size) < 0)
if (memcmp (range->min.bytes, addr->bytes, addr->size) > 0 ||
memcmp (range->max.bytes, addr->bytes, addr->size) < 0)
continue;
/* Make sure the requested ports are inside the range */
@ -652,38 +614,112 @@ gst_rtsp_address_pool_reserve_address (GstRTSPAddressPool * pool,
if (ttl != range->ttl)
continue;
break;
}
return walk;
}
/**
* gst_rtsp_address_pool_reserve_address:
* @pool: a #GstRTSPAddressPool
* @ip_address: The IP address to reserve
* @port: The first port to reserve
* @n_ports: The number of ports
* @ttl: The requested ttl
* @address: (out) storage for a #GstRTSPAddress
*
* Take a specific address and ports from @pool. @n_ports consecutive
* ports will be allocated of which the first one can be found in
* @port.
*
* If @ttl is 0, @address should be a unicast address. If @ttl > 0, @address
* should be a valid multicast address.
*
* Returns: #GST_RTSP_ADDRESS_POOL_OK if an address was reserved. The address
* is returned in @address and should be freed with gst_rtsp_address_free
* after use.
*/
GstRTSPAddressPoolResult
gst_rtsp_address_pool_reserve_address (GstRTSPAddressPool * pool,
const gchar * ip_address, guint port, guint n_ports, guint ttl,
GstRTSPAddress ** address)
{
GstRTSPAddressPoolPrivate *priv;
Addr input_addr;
GList *list;
AddrRange *addr_range;
GstRTSPAddress *addr;
gboolean is_multicast;
GstRTSPAddressPoolResult result;
g_return_val_if_fail (GST_IS_RTSP_ADDRESS_POOL (pool),
GST_RTSP_ADDRESS_POOL_EINVAL);
g_return_val_if_fail (ip_address != NULL, GST_RTSP_ADDRESS_POOL_EINVAL);
g_return_val_if_fail (port > 0, GST_RTSP_ADDRESS_POOL_EINVAL);
g_return_val_if_fail (n_ports > 0, GST_RTSP_ADDRESS_POOL_EINVAL);
g_return_val_if_fail (address != NULL, GST_RTSP_ADDRESS_POOL_EINVAL);
priv = pool->priv;
addr_range = NULL;
addr = NULL;
is_multicast = ttl != 0;
if (!fill_address (ip_address, port, &input_addr, is_multicast))
goto invalid;
g_mutex_lock (&priv->lock);
list = find_address_in_ranges (priv->addresses, &input_addr, port, n_ports,
ttl);
if (list != NULL) {
AddrRange *range = list->data;
gint skip_port, skip_addr;
skip_addr = diff_address (&input_addr, &range->min);
skip_port = port - range->min.port;
/* we found a range, remove from the list */
priv->addresses = g_list_delete_link (priv->addresses, walk);
priv->addresses = g_list_delete_link (priv->addresses, list);
/* now split and exit our loop */
result = split_range (pool, range, skip_addr, skip_port, n_ports);
priv->allocated = g_list_prepend (priv->allocated, result);
break;
addr_range = split_range (pool, range, skip_addr, skip_port, n_ports);
priv->allocated = g_list_prepend (priv->allocated, addr_range);
}
if (addr_range) {
addr = g_slice_new0 (GstRTSPAddress);
addr->pool = g_object_ref (pool);
addr->address = get_address_string (&addr_range->min);
addr->n_ports = n_ports;
addr->port = addr_range->min.port;
addr->ttl = addr_range->ttl;
addr->priv = addr_range;
result = GST_RTSP_ADDRESS_POOL_OK;
GST_DEBUG_OBJECT (pool, "reserved address %s:%u ttl %u", addr->address,
addr->port, addr->ttl);
} else {
/* We failed to reserve the address. Check if it was because the address
* was already in use or if it wasn't in the pool to begin with */
list = find_address_in_ranges (priv->allocated, &input_addr, port, n_ports,
ttl);
if (list != NULL) {
result = GST_RTSP_ADDRESS_POOL_ERESERVED;
} else {
result = GST_RTSP_ADDRESS_POOL_ERANGE;
}
}
g_mutex_unlock (&priv->lock);
if (result) {
addr = g_slice_new0 (GstRTSPAddress);
addr->pool = g_object_ref (pool);
addr->address = get_address_string (&result->min);
addr->n_ports = n_ports;
addr->port = result->min.port;
addr->ttl = result->ttl;
addr->priv = result;
GST_DEBUG_OBJECT (pool, "reserved address %s:%u ttl %u", addr->address,
addr->port, addr->ttl);
}
return addr;
*address = addr;
return result;
/* ERRORS */
invalid:
{
GST_ERROR_OBJECT (pool, "invalid address %s:%u/%u/%u", address,
GST_ERROR_OBJECT (pool, "invalid address %s:%u/%u/%u", ip_address,
port, n_ports, ttl);
return NULL;
*address = NULL;
return GST_RTSP_ADDRESS_POOL_EINVAL;
}
}

View file

@ -33,6 +33,27 @@ G_BEGIN_DECLS
#define GST_RTSP_ADDRESS_POOL_CAST(obj) ((GstRTSPAddressPool*)(obj))
#define GST_RTSP_ADDRESS_POOL_CLASS_CAST(klass) ((GstRTSPAddressPoolClass*)(klass))
/**
* GstRTSPAddressPoolResult:
* @GST_RTSP_ADDRESS_POOL_OK: no error
* @GST_RTSP_ADDRESS_POOL_EINVAL:invalid arguments were provided to a function
* @GST_RTSP_ADDRESS_POOL_ERESERVED: the addres has already been reserved
* @GST_RTSP_ADDRESS_POOL_ERANGE: the address is not in the pool
* @GST_RTSP_ADDRESS_POOL_ELAST: last error
*
* Result codes from RTSP address pool functions.
*/
typedef enum {
GST_RTSP_ADDRESS_POOL_OK = 0,
/* errors */
GST_RTSP_ADDRESS_POOL_EINVAL = -1,
GST_RTSP_ADDRESS_POOL_ERESERVED = -2,
GST_RTSP_ADDRESS_POOL_ERANGE = -3,
GST_RTSP_ADDRESS_POOL_ELAST = -4,
} GstRTSPAddressPoolResult;
typedef struct _GstRTSPAddress GstRTSPAddress;
typedef struct _GstRTSPAddressPool GstRTSPAddressPool;
@ -143,11 +164,12 @@ GstRTSPAddress * gst_rtsp_address_pool_acquire_address (GstRTSPAddressPool
GstRTSPAddressFlags flags,
gint n_ports);
GstRTSPAddress * gst_rtsp_address_pool_reserve_address (GstRTSPAddressPool * pool,
const gchar *address,
GstRTSPAddressPoolResult gst_rtsp_address_pool_reserve_address (GstRTSPAddressPool * pool,
const gchar *ip_address,
guint port,
guint n_ports,
guint ttl);
guint ttl,
GstRTSPAddress ** address);
gboolean gst_rtsp_address_pool_has_unicast_addresses (GstRTSPAddressPool * pool);

View file

@ -730,12 +730,14 @@ gst_rtsp_stream_reserve_address (GstRTSPStream * stream,
g_mutex_lock (&priv->lock);
if (*addrp == NULL) {
GstRTSPAddressPoolResult res;
if (priv->pool == NULL)
goto no_pool;
*addrp = gst_rtsp_address_pool_reserve_address (priv->pool, address,
port, n_ports, ttl);
if (*addrp == NULL)
res = gst_rtsp_address_pool_reserve_address (priv->pool, address,
port, n_ports, ttl, addrp);
if (res != GST_RTSP_ADDRESS_POOL_OK)
goto no_address;
} else {
if (strcmp ((*addrp)->address, address) ||

View file

@ -25,6 +25,7 @@ GST_START_TEST (test_pool)
{
GstRTSPAddressPool *pool;
GstRTSPAddress *addr, *addr2, *addr3;
GstRTSPAddressPoolResult res;
pool = gst_rtsp_address_pool_new ();
@ -126,47 +127,61 @@ GST_START_TEST (test_pool)
fail_unless (gst_rtsp_address_pool_add_range (pool,
"233.252.1.1", "233.252.1.1", 5000, 5001, 1));
addr = gst_rtsp_address_pool_reserve_address (pool, "233.252.1.1", 5000, 3,
1);
res = gst_rtsp_address_pool_reserve_address (pool, "233.252.1.1", 5000, 3,
1, &addr);
fail_unless (res == GST_RTSP_ADDRESS_POOL_ERANGE);
fail_unless (addr == NULL);
addr = gst_rtsp_address_pool_reserve_address (pool, "233.252.1.2", 5000, 2,
1);
res = gst_rtsp_address_pool_reserve_address (pool, "233.252.1.2", 5000, 2,
1, &addr);
fail_unless (res == GST_RTSP_ADDRESS_POOL_ERANGE);
fail_unless (addr == NULL);
addr = gst_rtsp_address_pool_reserve_address (pool, "233.252.1.1", 500, 2, 1);
res = gst_rtsp_address_pool_reserve_address (pool, "233.252.1.1", 500, 2, 1,
&addr);
fail_unless (res == GST_RTSP_ADDRESS_POOL_ERANGE);
fail_unless (addr == NULL);
addr = gst_rtsp_address_pool_reserve_address (pool, "233.252.1.1", 5000, 2,
2);
res = gst_rtsp_address_pool_reserve_address (pool, "233.252.1.1", 5000, 2,
2, &addr);
fail_unless (res == GST_RTSP_ADDRESS_POOL_ERANGE);
fail_unless (addr == NULL);
addr = gst_rtsp_address_pool_reserve_address (pool, "2000::1", 5000, 2, 2);
res = gst_rtsp_address_pool_reserve_address (pool, "2000::1", 5000, 2, 2,
&addr);
fail_unless (res == GST_RTSP_ADDRESS_POOL_EINVAL);
fail_unless (addr == NULL);
addr = gst_rtsp_address_pool_reserve_address (pool, "1.1", 5000, 2, 2);
res = gst_rtsp_address_pool_reserve_address (pool, "1.1", 5000, 2, 2, &addr);
fail_unless (res == GST_RTSP_ADDRESS_POOL_EINVAL);
fail_unless (addr == NULL);
addr = gst_rtsp_address_pool_reserve_address (pool, "233.252.1.1", 5000, 2,
1);
res = gst_rtsp_address_pool_reserve_address (pool, "233.252.1.1", 5000, 2,
1, &addr);
fail_unless (res == GST_RTSP_ADDRESS_POOL_OK);
fail_unless (addr != NULL);
fail_unless (addr->port == 5000);
fail_unless (!strcmp (addr->address, "233.252.1.1"));
res = gst_rtsp_address_pool_reserve_address (pool, "233.252.1.1", 5000, 2,
1, &addr2);
fail_unless (res == GST_RTSP_ADDRESS_POOL_ERESERVED);
fail_unless (addr2 == NULL);
gst_rtsp_address_free (addr);
gst_rtsp_address_pool_clear (pool);
fail_unless (gst_rtsp_address_pool_add_range (pool,
"233.252.1.1", "233.252.1.3", 5000, 5001, 1));
addr = gst_rtsp_address_pool_reserve_address (pool, "233.252.1.1", 5000, 2,
1);
res = gst_rtsp_address_pool_reserve_address (pool, "233.252.1.1", 5000, 2,
1, &addr);
fail_unless (addr != NULL);
fail_unless (addr->port == 5000);
fail_unless (!strcmp (addr->address, "233.252.1.1"));
addr2 = gst_rtsp_address_pool_reserve_address (pool, "233.252.1.3", 5000, 2,
1);
res = gst_rtsp_address_pool_reserve_address (pool, "233.252.1.3", 5000, 2,
1, &addr2);
fail_unless (addr2 != NULL);
fail_unless (addr2->port == 5000);
fail_unless (!strcmp (addr2->address, "233.252.1.3"));