rtsp: make address-pool return an address object
authorWim Taymans <wim.taymans@collabora.co.uk>
Thu, 15 Nov 2012 12:25:14 +0000 (13:25 +0100)
committerWim Taymans <wim.taymans@collabora.co.uk>
Thu, 15 Nov 2012 12:25:14 +0000 (13:25 +0100)
Return a boxed GstRTSPAddress from the GstRTSPAddressPool. This allows us to
store more info in the structure and allows us to more easily return the address
to the right pool when no longer needed.
Pass the address to the StreamTransport so that we can return it to the pool
when the stream transport is freed or changed.

gst/rtsp-server/rtsp-address-pool.c
gst/rtsp-server/rtsp-address-pool.h
gst/rtsp-server/rtsp-client.c
gst/rtsp-server/rtsp-session-media.c
gst/rtsp-server/rtsp-session-media.h
gst/rtsp-server/rtsp-stream-transport.c
gst/rtsp-server/rtsp-stream-transport.h
tests/check/gst/addresspool.c

index 194e290..45a969b 100644 (file)
 
 #include "rtsp-address-pool.h"
 
+GstRTSPAddress *
+gst_rtsp_address_copy (GstRTSPAddress * addr)
+{
+  GstRTSPAddress *copy;
+
+  g_return_val_if_fail (addr != NULL, NULL);
+
+  copy = g_slice_dup (GstRTSPAddress, addr);
+  /* only release to the pool when the original is freed. It's a bit
+   * weird but this will do for now as it avoid us to use refcounting. */
+  copy->pool = NULL;
+  copy->address = g_strdup (copy->address);
+
+  return copy;
+}
+
+static void gst_rtsp_address_pool_release_address (GstRTSPAddressPool * pool,
+    GstRTSPAddress * addr);
+
+void
+gst_rtsp_address_free (GstRTSPAddress * addr)
+{
+  g_return_if_fail (addr != NULL);
+
+  if (addr->pool) {
+    /* unrefs the pool and sets it to NULL */
+    gst_rtsp_address_pool_release_address (addr->pool, addr);
+  }
+  g_free (addr->address);
+  g_slice_free (GstRTSPAddress, addr);
+}
+
+
+G_DEFINE_BOXED_TYPE (GstRTSPAddress, gst_rtsp_address,
+    (GBoxedCopyFunc) gst_rtsp_address_copy,
+    (GBoxedFreeFunc) gst_rtsp_address_free);
+
 GST_DEBUG_CATEGORY_STATIC (rtsp_address_pool_debug);
 #define GST_CAT_DEFAULT rtsp_address_pool_debug
 
@@ -298,35 +335,29 @@ split_range (GstRTSPAddressPool * pool, AddrRange * range, gint skip,
  * @pool: a #GstRTSPAddressPool
  * @flags: flags
  * @n_ports: the amount of ports
- * @address: result address
- * @port: result port
- * @ttl: result TTL
  *
  * Take an address and ports from @pool. @flags can be used to control the
  * allocation. @n_ports consecutive ports will be allocated of which the first
  * one can be found in @port.
  *
- * Returns: a pointer that should be used to release the address with
- *   gst_rtsp_address_pool_release_address() after usage or %NULL when no
- *   address could be acquired.
+ * Returns: a #GstRTSPAddress that should be freed with gst_rtsp_address_free
+ *   after use or %NULL when no address could be acquired.
  */
-gpointer
+GstRTSPAddress *
 gst_rtsp_address_pool_acquire_address (GstRTSPAddressPool * pool,
-    GstRTSPAddressFlags flags, gint n_ports, gchar ** address,
-    guint16 * port, guint8 * ttl)
+    GstRTSPAddressFlags flags, gint n_ports)
 {
   GstRTSPAddressPoolPrivate *priv;
   GList *walk, *next;
   AddrRange *result;
+  GstRTSPAddress *addr;
 
   g_return_val_if_fail (GST_IS_RTSP_ADDRESS_POOL (pool), NULL);
   g_return_val_if_fail (n_ports > 0, NULL);
-  g_return_val_if_fail (address != NULL, NULL);
-  g_return_val_if_fail (port != NULL, NULL);
-  g_return_val_if_fail (ttl != NULL, NULL);
 
   priv = pool->priv;
   result = NULL;
+  addr = NULL;
 
   g_mutex_lock (&priv->lock);
   /* go over available ranges */
@@ -363,13 +394,19 @@ gst_rtsp_address_pool_acquire_address (GstRTSPAddressPool * pool,
   g_mutex_unlock (&priv->lock);
 
   if (result) {
-    *address = get_address_string (&result->min);
-    *port = result->min.port;
-    *ttl = result->ttl;
-
-    GST_DEBUG_OBJECT (pool, "got address %s:%u ttl %u", *address, *port, *ttl);
+    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, "got address %s:%u ttl %u", addr->address,
+        addr->port, addr->ttl);
   }
-  return result;
+
+  return addr;
 }
 
 /**
@@ -380,34 +417,44 @@ gst_rtsp_address_pool_acquire_address (GstRTSPAddressPool * pool,
  * Release a previously acquired address (with
  * gst_rtsp_address_pool_acquire_address()) back into @pool.
  */
-void
-gst_rtsp_address_pool_release_address (GstRTSPAddressPool * pool, gpointer id)
+static void
+gst_rtsp_address_pool_release_address (GstRTSPAddressPool * pool,
+    GstRTSPAddress * addr)
 {
   GstRTSPAddressPoolPrivate *priv;
   GList *find;
+  AddrRange *range;
 
   g_return_if_fail (GST_IS_RTSP_ADDRESS_POOL (pool));
-  g_return_if_fail (id != NULL);
+  g_return_if_fail (addr != NULL);
+  g_return_if_fail (addr->pool == pool);
 
   priv = pool->priv;
+  range = addr->priv;
+
+  /* we don't want to free twice */
+  addr->priv = NULL;
+  addr->pool = NULL;
 
   g_mutex_lock (&priv->lock);
-  find = g_list_find (priv->allocated, id);
+  find = g_list_find (priv->allocated, range);
   if (find == NULL)
     goto not_found;
 
   priv->allocated = g_list_delete_link (priv->allocated, find);
 
   /* FIXME, merge and do something clever */
-  priv->addresses = g_list_prepend (priv->addresses, id);
+  priv->addresses = g_list_prepend (priv->addresses, range);
   g_mutex_unlock (&priv->lock);
 
+  g_object_unref (pool);
+
   return;
 
   /* ERRORS */
 not_found:
   {
-    g_warning ("Released unknown id %p", id);
+    g_warning ("Released unknown address %p", addr);
     g_mutex_unlock (&priv->lock);
     return;
   }
index d29e1e0..b893790 100644 (file)
@@ -33,10 +33,29 @@ G_BEGIN_DECLS
 #define GST_RTSP_ADDRESS_POOL_CAST(obj)         ((GstRTSPAddressPool*)(obj))
 #define GST_RTSP_ADDRESS_POOL_CLASS_CAST(klass) ((GstRTSPAddressPoolClass*)(klass))
 
+typedef struct _GstRTSPAddress GstRTSPAddress;
+typedef struct _GstRTSPAddressClass GstRTSPAddressClass;
+
 typedef struct _GstRTSPAddressPool GstRTSPAddressPool;
 typedef struct _GstRTSPAddressPoolClass GstRTSPAddressPoolClass;
 typedef struct _GstRTSPAddressPoolPrivate GstRTSPAddressPoolPrivate;
 
+struct _GstRTSPAddress {
+  GstRTSPAddressPool *pool;
+
+  gchar *address;
+  guint16 port;
+  gint n_ports;
+  guint8 ttl;
+
+  gpointer priv;
+};
+
+GType gst_rtsp_address_get_type        (void);
+
+GstRTSPAddress * gst_rtsp_address_copy (GstRTSPAddress *addr);
+void             gst_rtsp_address_free (GstRTSPAddress *addr);
+
 typedef enum {
   GST_RTSP_ADDRESS_FLAG_NONE      = 0,
   GST_RTSP_ADDRESS_FLAG_IPV4      = (1 << 0),
@@ -74,13 +93,9 @@ gboolean               gst_rtsp_address_pool_add_range       (GstRTSPAddressPool
                                                               guint16 max_port,
                                                               guint8 ttl);
 
-gpointer               gst_rtsp_address_pool_acquire_address (GstRTSPAddressPool * pool,
+GstRTSPAddress *       gst_rtsp_address_pool_acquire_address (GstRTSPAddressPool * pool,
                                                               GstRTSPAddressFlags flags,
-                                                              gint n_ports,
-                                                              gchar **address,
-                                                              guint16 *port, guint8 *ttl);
-void                   gst_rtsp_address_pool_release_address (GstRTSPAddressPool * pool,
-                                                              gpointer);
+                                                              gint n_ports);
 G_END_DECLS
 
 #endif /* __GST_RTSP_ADDRESS_POOL_H__ */
index 7dbddce..a9582e0 100644 (file)
@@ -973,31 +973,30 @@ handle_blocksize (GstRTSPMedia * media, GstRTSPMessage * request)
 
 static gboolean
 configure_client_transport (GstRTSPClient * client, GstRTSPClientState * state,
-    GstRTSPTransport * ct)
+    GstRTSPTransport * ct, GstRTSPAddress ** addr)
 {
   /* we have a valid transport now, set the destination of the client. */
   if (ct->lower_transport == GST_RTSP_LOWER_TRANS_UDP_MCAST) {
     if (ct->destination == NULL || !client->use_client_settings) {
       GstRTSPAddressPool *pool;
-      gchar *address;
-      guint16 port;
-      guint8 ttl;
-      gpointer id;
+      GstRTSPAddress *ad;
 
       pool = gst_rtsp_media_get_address_pool (state->media);
       if (pool == NULL)
         goto no_pool;
 
-      id = gst_rtsp_address_pool_acquire_address (pool,
-          GST_RTSP_ADDRESS_FLAG_EVEN_PORT, 2, &address, &port, &ttl);
-      if (id == NULL)
+      ad = gst_rtsp_address_pool_acquire_address (pool,
+          GST_RTSP_ADDRESS_FLAG_EVEN_PORT, 2);
+      if (ad == NULL)
         goto no_address;
 
       g_free (ct->destination);
-      ct->destination = address;
-      ct->port.min = port;
-      ct->port.max = port + 1;
-      ct->ttl = ttl;
+      ct->destination = g_strdup (ad->address);
+      ct->port.min = ad->port;
+      ct->port.max = ad->port + 1;
+      ct->ttl = ad->ttl;
+
+      *addr = ad;
     }
   } else {
     GstRTSPUrl *url;
@@ -1019,10 +1018,12 @@ configure_client_transport (GstRTSPClient * client, GstRTSPClientState * state,
   /* ERRORS */
 no_pool:
   {
+    GST_ERROR_OBJECT (client, "no address pool specified");
     return FALSE;
   }
 no_address:
   {
+    GST_ERROR_OBJECT (client, "failed to acquire address from pool");
     return FALSE;
   }
 }
@@ -1078,6 +1079,7 @@ handle_setup_request (GstRTSPClient * client, GstRTSPClientState * state)
   GstRTSPSessionMedia *sessmedia;
   GstRTSPMedia *media;
   GstRTSPStream *stream;
+  GstRTSPAddress *addr;
 
   uri = state->uri;
 
@@ -1166,11 +1168,12 @@ handle_setup_request (GstRTSPClient * client, GstRTSPClientState * state)
     goto invalid_blocksize;
 
   /* update the client transport */
-  if (!configure_client_transport (client, state, ct))
+  addr = NULL;
+  if (!configure_client_transport (client, state, ct, &addr))
     goto unsupported_client_transport;
 
   /* set in the session media transport */
-  trans = gst_rtsp_session_media_set_transport (sessmedia, stream, ct);
+  trans = gst_rtsp_session_media_set_transport (sessmedia, stream, ct, addr);
 
   /* configure keepalive for this transport */
   gst_rtsp_stream_transport_set_keepalive (trans,
index e8eda2b..4d365f0 100644 (file)
@@ -123,6 +123,7 @@ gst_rtsp_session_media_new (const GstRTSPUrl * url, GstRTSPMedia * media)
  * @media: a #GstRTSPSessionMedia
  * @stream: a #GstRTSPStream
  * @tr: a #GstRTSPTransport
+ * @addr: (transfer full) (allow none): an optional #GstRTSPAddress
  *
  * Configure the transport for @stream to @tr in @media.
  *
@@ -130,7 +131,7 @@ gst_rtsp_session_media_new (const GstRTSPUrl * url, GstRTSPMedia * media)
  */
 GstRTSPStreamTransport *
 gst_rtsp_session_media_set_transport (GstRTSPSessionMedia * media,
-    GstRTSPStream * stream, GstRTSPTransport * tr)
+    GstRTSPStream * stream, GstRTSPTransport * tr, GstRTSPAddress * addr)
 {
   GstRTSPStreamTransport *result;
 
@@ -141,11 +142,11 @@ gst_rtsp_session_media_set_transport (GstRTSPSessionMedia * media,
   g_mutex_lock (&media->lock);
   result = g_ptr_array_index (media->transports, stream->idx);
   if (result == NULL) {
-    result = gst_rtsp_stream_transport_new (stream, tr);
+    result = gst_rtsp_stream_transport_new (stream, tr, addr);
     g_ptr_array_index (media->transports, stream->idx) = result;
     g_mutex_unlock (&media->lock);
   } else {
-    gst_rtsp_stream_transport_set_transport (result, tr);
+    gst_rtsp_stream_transport_set_transport (result, tr, addr);
     g_mutex_unlock (&media->lock);
   }
 
index 2156f30..2ccfc0e 100644 (file)
@@ -78,7 +78,8 @@ gboolean                 gst_rtsp_session_media_set_state      (GstRTSPSessionMe
 /* get stream transport config */
 GstRTSPStreamTransport * gst_rtsp_session_media_set_transport  (GstRTSPSessionMedia *media,
                                                                 GstRTSPStream *stream,
-                                                                GstRTSPTransport *tr);
+                                                                GstRTSPTransport *tr,
+                                                                GstRTSPAddress *addr);
 GstRTSPStreamTransport * gst_rtsp_session_media_get_transport  (GstRTSPSessionMedia *media,
                                                                 guint idx);
 
index c81a149..5101f46 100644 (file)
@@ -70,6 +70,8 @@ gst_rtsp_stream_transport_finalize (GObject * obj)
 
   if (trans->transport)
     gst_rtsp_transport_free (trans->transport);
+  if (trans->addr)
+    gst_rtsp_address_free (trans->addr);
 
 #if 0
   if (trans->rtpsource)
@@ -83,6 +85,7 @@ gst_rtsp_stream_transport_finalize (GObject * obj)
  * gst_rtsp_stream_transport_new:
  * @stream: a #GstRTSPStream
  * @tr: (transfer full): a GstRTSPTransport
+ * @addr: (transfer full) (allow none): an optional GstRTSPAddress
  *
  * Create a new #GstRTSPStreamTransport that can be used to manage
  * @stream with transport @tr.
@@ -90,7 +93,8 @@ gst_rtsp_stream_transport_finalize (GObject * obj)
  * Returns: a new #GstRTSPStreamTransport
  */
 GstRTSPStreamTransport *
-gst_rtsp_stream_transport_new (GstRTSPStream * stream, GstRTSPTransport * tr)
+gst_rtsp_stream_transport_new (GstRTSPStream * stream, GstRTSPTransport * tr,
+    GstRTSPAddress * addr)
 {
   GstRTSPStreamTransport *trans;
 
@@ -100,6 +104,7 @@ gst_rtsp_stream_transport_new (GstRTSPStream * stream, GstRTSPTransport * tr)
   trans = g_object_new (GST_TYPE_RTSP_STREAM_TRANSPORT, NULL);
   trans->stream = stream;
   trans->transport = tr;
+  trans->addr = addr;
 
   return trans;
 }
@@ -154,13 +159,14 @@ gst_rtsp_stream_transport_set_keepalive (GstRTSPStreamTransport * trans,
  * gst_rtsp_stream_transport_set_transport:
  * @trans: a #GstRTSPStreamTransport
  * @tr: (transfer full): a client #GstRTSPTransport
+ * @addr: (transfer full) (allow none): a ##GstRTSPAddress
  *
- * Set @ct as the client transport. This function takes ownership of
- * the passed @tr.
+ * Set @tr and the optional @addr as the client transport. This function
+ * takes ownership of the passed @tr and @addr.
  */
 void
 gst_rtsp_stream_transport_set_transport (GstRTSPStreamTransport * trans,
-    GstRTSPTransport * tr)
+    GstRTSPTransport * tr, GstRTSPAddress * addr)
 {
   g_return_if_fail (GST_IS_RTSP_STREAM_TRANSPORT (trans));
   g_return_if_fail (tr != NULL);
@@ -169,6 +175,9 @@ gst_rtsp_stream_transport_set_transport (GstRTSPStreamTransport * trans,
   if (trans->transport)
     gst_rtsp_transport_free (trans->transport);
   trans->transport = tr;
+  if (trans->addr)
+    gst_rtsp_address_free (trans->addr);
+  trans->addr = addr;
 }
 
 /**
index 96bf7b6..44a3237 100644 (file)
@@ -40,6 +40,7 @@ typedef struct _GstRTSPStreamTransport GstRTSPStreamTransport;
 typedef struct _GstRTSPStreamTransportClass GstRTSPStreamTransportClass;
 
 #include "rtsp-stream.h"
+#include "rtsp-address-pool.h"
 
 typedef gboolean (*GstRTSPSendFunc)      (GstBuffer *buffer, guint8 channel, gpointer user_data);
 typedef void     (*GstRTSPKeepAliveFunc) (gpointer user_data);
@@ -58,6 +59,7 @@ typedef void     (*GstRTSPKeepAliveFunc) (gpointer user_data);
  * @active: if we are actively sending
  * @timeout: if we timed out
  * @transport: a transport description
+ * @addr: an optional address
  * @rtpsource: the receiver rtp source object
  *
  * A Transport description for stream @idx
@@ -79,6 +81,7 @@ struct _GstRTSPStreamTransport {
   gboolean             timeout;
 
   GstRTSPTransport    *transport;
+  GstRTSPAddress      *addr;
 
   GObject             *rtpsource;
 };
@@ -90,10 +93,12 @@ struct _GstRTSPStreamTransportClass {
 GType                    gst_rtsp_stream_transport_get_type (void);
 
 GstRTSPStreamTransport * gst_rtsp_stream_transport_new           (GstRTSPStream *stream,
-                                                                  GstRTSPTransport *tr);
+                                                                  GstRTSPTransport *tr,
+                                                                  GstRTSPAddress *addr);
 
 void                     gst_rtsp_stream_transport_set_transport (GstRTSPStreamTransport *trans,
-                                                                  GstRTSPTransport * tr);
+                                                                  GstRTSPTransport * tr,
+                                                                  GstRTSPAddress *addr);
 
 void                     gst_rtsp_stream_transport_set_callbacks (GstRTSPStreamTransport *trans,
                                                                   GstRTSPSendFunc send_rtp,
index 7e25f7a..b05e973 100644 (file)
 
 GST_START_TEST (test_pool)
 {
-  gpointer id;
   GstRTSPAddressPool *pool;
-  gchar *address;
-  guint16 port;
-  guint8 ttl;
+  GstRTSPAddress *addr;
 
   pool = gst_rtsp_address_pool_new ();
 
@@ -44,23 +41,18 @@ GST_START_TEST (test_pool)
           "233.255.0.0", "233.255.0.0", 5020, 5020, 1));
 
   /* should fail, we can't allocate a block of 256 ports */
-  id = gst_rtsp_address_pool_acquire_address (pool,
-      0, 256, &address, &port, &ttl);
-  fail_unless (id == NULL);
+  addr = gst_rtsp_address_pool_acquire_address (pool, 0, 256);
+  fail_unless (addr == NULL);
 
-  id = gst_rtsp_address_pool_acquire_address (pool,
-      0, 2, &address, &port, &ttl);
-  fail_unless (id != NULL);
+  addr = gst_rtsp_address_pool_acquire_address (pool, 0, 2);
+  fail_unless (addr != NULL);
 
-  gst_rtsp_address_pool_release_address (pool, id);
-  g_free (address);
+  gst_rtsp_address_free (addr);
 
-  id = gst_rtsp_address_pool_acquire_address (pool,
-      0, 4, &address, &port, &ttl);
-  fail_unless (id != NULL);
+  addr = gst_rtsp_address_pool_acquire_address (pool, 0, 4);
+  fail_unless (addr != NULL);
 
-  gst_rtsp_address_pool_release_address (pool, id);
-  g_free (address);
+  gst_rtsp_address_free (addr);
 
   g_object_unref (pool);
 }