addresspool: return reason of failure
authorPatrick Radizi <patrick.radizi at axis.com>
Tue, 24 Sep 2013 15:30:18 +0000 (17:30 +0200)
committerWim Taymans <wim.taymans@collabora.co.uk>
Tue, 24 Sep 2013 15:30:18 +0000 (17:30 +0200)
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

gst/rtsp-server/rtsp-address-pool.c
gst/rtsp-server/rtsp-address-pool.h
gst/rtsp-server/rtsp-stream.c
tests/check/gst/addresspool.c

index 6bb0956..e1e9b91 100644 (file)
@@ -585,13 +585,49 @@ gst_rtsp_address_pool_dump (GstRTSPAddressPool * pool)
   g_mutex_unlock (&priv->lock);
 }
 
+static GList *
+find_address_in_ranges (GList * addresses, Addr * addr, guint port,
+    guint n_ports, guint ttl)
+{
+  GList *walk, *next;
+
+  /* go over available ranges */
+  for (walk = addresses; walk; walk = next) {
+    AddrRange *range;
+
+    range = walk->data;
+    next = walk->next;
+
+    /* Not the right type of address */
+    if (range->min.size != addr->size)
+      continue;
+
+    /* Check that the address is in the interval */
+    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 */
+    if (port < range->min.port || port + n_ports - 1 > range->max.port)
+      continue;
+
+    if (ttl != range->ttl)
+      continue;
+
+    break;
+  }
+
+  return walk;
+}
+
 /**
  * gst_rtsp_address_pool_reserve_address:
  * @pool: a #GstRTSPAddressPool
- * @address: The IP address to reserve
+ * @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
@@ -600,90 +636,90 @@ gst_rtsp_address_pool_dump (GstRTSPAddressPool * pool)
  * 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.
+ * 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.
  */
-GstRTSPAddress *
+GstRTSPAddressPoolResult
 gst_rtsp_address_pool_reserve_address (GstRTSPAddressPool * pool,
-    const gchar * address, guint port, guint n_ports, guint ttl)
+    const gchar * ip_address, guint port, guint n_ports, guint ttl,
+    GstRTSPAddress ** address)
 {
   GstRTSPAddressPoolPrivate *priv;
   Addr input_addr;
-  GList *walk, *next;
-  AddrRange *result;
+  GList *list;
+  AddrRange *addr_range;
   GstRTSPAddress *addr;
   gboolean is_multicast;
+  GstRTSPAddressPoolResult result;
 
-  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);
+  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;
-  result = NULL;
+  addr_range = NULL;
   addr = NULL;
   is_multicast = ttl != 0;
 
-  if (!fill_address (address, port, &input_addr, is_multicast))
+  if (!fill_address (ip_address, port, &input_addr, is_multicast))
     goto invalid;
 
   g_mutex_lock (&priv->lock);
-  /* go over available ranges */
-  for (walk = priv->addresses; walk; walk = next) {
-    AddrRange *range;
+  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;
 
-    range = walk->data;
-    next = walk->next;
-
-    /* Not the right type of address */
-    if (range->min.size != input_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)
-      continue;
-
-    /* Make sure the requested ports are inside the range */
-    if (port < range->min.port || port + n_ports - 1 > range->max.port)
-      continue;
-
-    if (ttl != range->ttl)
-      continue;
-
     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);
   }
-  g_mutex_unlock (&priv->lock);
 
-  if (result) {
+  if (addr_range) {
     addr = g_slice_new0 (GstRTSPAddress);
     addr->pool = g_object_ref (pool);
-    addr->address = get_address_string (&result->min);
+    addr->address = get_address_string (&addr_range->min);
     addr->n_ports = n_ports;
-    addr->port = result->min.port;
-    addr->ttl = result->ttl;
-    addr->priv = result;
+    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;
+    }
   }
-  return addr;
+  g_mutex_unlock (&priv->lock);
+
+  *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;
   }
 }
 
index 1cf908b..8320dd9 100644 (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);
 
index 633ec55..e5576a1 100644 (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) ||
index d862929..f1b62e9 100644 (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"));