From 45b6693b39b44f8f29d51dc008f4efacff697247 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 15 Nov 2012 13:25:14 +0100 Subject: [PATCH] rtsp: make address-pool return an address object 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 | 93 +++++++++++++++++++------ gst/rtsp-server/rtsp-address-pool.h | 27 +++++-- gst/rtsp-server/rtsp-client.c | 31 +++++---- gst/rtsp-server/rtsp-session-media.c | 7 +- gst/rtsp-server/rtsp-session-media.h | 3 +- gst/rtsp-server/rtsp-stream-transport.c | 17 +++-- gst/rtsp-server/rtsp-stream-transport.h | 9 ++- tests/check/gst/addresspool.c | 26 +++---- 8 files changed, 143 insertions(+), 70 deletions(-) diff --git a/gst/rtsp-server/rtsp-address-pool.c b/gst/rtsp-server/rtsp-address-pool.c index 194e29094a..45a969b497 100644 --- a/gst/rtsp-server/rtsp-address-pool.c +++ b/gst/rtsp-server/rtsp-address-pool.c @@ -22,6 +22,43 @@ #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; + 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", *address, *port, *ttl); + 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; } diff --git a/gst/rtsp-server/rtsp-address-pool.h b/gst/rtsp-server/rtsp-address-pool.h index d29e1e0170..b8937907e9 100644 --- a/gst/rtsp-server/rtsp-address-pool.h +++ b/gst/rtsp-server/rtsp-address-pool.h @@ -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__ */ diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 7dbddce77b..a9582e0594 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -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, diff --git a/gst/rtsp-server/rtsp-session-media.c b/gst/rtsp-server/rtsp-session-media.c index e8eda2bc98..4d365f03fd 100644 --- a/gst/rtsp-server/rtsp-session-media.c +++ b/gst/rtsp-server/rtsp-session-media.c @@ -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); } diff --git a/gst/rtsp-server/rtsp-session-media.h b/gst/rtsp-server/rtsp-session-media.h index 2156f303ba..2ccfc0ed35 100644 --- a/gst/rtsp-server/rtsp-session-media.h +++ b/gst/rtsp-server/rtsp-session-media.h @@ -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); diff --git a/gst/rtsp-server/rtsp-stream-transport.c b/gst/rtsp-server/rtsp-stream-transport.c index c81a1495de..5101f46679 100644 --- a/gst/rtsp-server/rtsp-stream-transport.c +++ b/gst/rtsp-server/rtsp-stream-transport.c @@ -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; } /** diff --git a/gst/rtsp-server/rtsp-stream-transport.h b/gst/rtsp-server/rtsp-stream-transport.h index 96bf7b67c4..44a3237dfa 100644 --- a/gst/rtsp-server/rtsp-stream-transport.h +++ b/gst/rtsp-server/rtsp-stream-transport.h @@ -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, diff --git a/tests/check/gst/addresspool.c b/tests/check/gst/addresspool.c index 7e25f7a694..b05e973b4f 100644 --- a/tests/check/gst/addresspool.c +++ b/tests/check/gst/addresspool.c @@ -23,11 +23,8 @@ 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); }