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.
This commit is contained in:
Wim Taymans 2012-11-15 13:25:14 +01:00
parent fde8c01a85
commit 45b6693b39
8 changed files with 143 additions and 70 deletions

View file

@ -22,6 +22,43 @@
#include "rtsp-address-pool.h" #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); GST_DEBUG_CATEGORY_STATIC (rtsp_address_pool_debug);
#define GST_CAT_DEFAULT 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 * @pool: a #GstRTSPAddressPool
* @flags: flags * @flags: flags
* @n_ports: the amount of ports * @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 * 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 * allocation. @n_ports consecutive ports will be allocated of which the first
* one can be found in @port. * one can be found in @port.
* *
* Returns: a pointer that should be used to release the address with * Returns: a #GstRTSPAddress that should be freed with gst_rtsp_address_free
* gst_rtsp_address_pool_release_address() after usage or %NULL when no * after use or %NULL when no address could be acquired.
* address could be acquired.
*/ */
gpointer GstRTSPAddress *
gst_rtsp_address_pool_acquire_address (GstRTSPAddressPool * pool, gst_rtsp_address_pool_acquire_address (GstRTSPAddressPool * pool,
GstRTSPAddressFlags flags, gint n_ports, gchar ** address, GstRTSPAddressFlags flags, gint n_ports)
guint16 * port, guint8 * ttl)
{ {
GstRTSPAddressPoolPrivate *priv; GstRTSPAddressPoolPrivate *priv;
GList *walk, *next; GList *walk, *next;
AddrRange *result; AddrRange *result;
GstRTSPAddress *addr;
g_return_val_if_fail (GST_IS_RTSP_ADDRESS_POOL (pool), NULL); 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 (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; priv = pool->priv;
result = NULL; result = NULL;
addr = NULL;
g_mutex_lock (&priv->lock); g_mutex_lock (&priv->lock);
/* go over available ranges */ /* go over available ranges */
@ -363,13 +394,19 @@ gst_rtsp_address_pool_acquire_address (GstRTSPAddressPool * pool,
g_mutex_unlock (&priv->lock); g_mutex_unlock (&priv->lock);
if (result) { if (result) {
*address = get_address_string (&result->min); addr = g_slice_new0 (GstRTSPAddress);
*port = result->min.port; addr->pool = g_object_ref (pool);
*ttl = result->ttl; 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 * Release a previously acquired address (with
* gst_rtsp_address_pool_acquire_address()) back into @pool. * gst_rtsp_address_pool_acquire_address()) back into @pool.
*/ */
void static void
gst_rtsp_address_pool_release_address (GstRTSPAddressPool * pool, gpointer id) gst_rtsp_address_pool_release_address (GstRTSPAddressPool * pool,
GstRTSPAddress * addr)
{ {
GstRTSPAddressPoolPrivate *priv; GstRTSPAddressPoolPrivate *priv;
GList *find; GList *find;
AddrRange *range;
g_return_if_fail (GST_IS_RTSP_ADDRESS_POOL (pool)); 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; priv = pool->priv;
range = addr->priv;
/* we don't want to free twice */
addr->priv = NULL;
addr->pool = NULL;
g_mutex_lock (&priv->lock); g_mutex_lock (&priv->lock);
find = g_list_find (priv->allocated, id); find = g_list_find (priv->allocated, range);
if (find == NULL) if (find == NULL)
goto not_found; goto not_found;
priv->allocated = g_list_delete_link (priv->allocated, find); priv->allocated = g_list_delete_link (priv->allocated, find);
/* FIXME, merge and do something clever */ /* 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_mutex_unlock (&priv->lock);
g_object_unref (pool);
return; return;
/* ERRORS */ /* ERRORS */
not_found: not_found:
{ {
g_warning ("Released unknown id %p", id); g_warning ("Released unknown address %p", addr);
g_mutex_unlock (&priv->lock); g_mutex_unlock (&priv->lock);
return; return;
} }

View file

@ -33,10 +33,29 @@ G_BEGIN_DECLS
#define GST_RTSP_ADDRESS_POOL_CAST(obj) ((GstRTSPAddressPool*)(obj)) #define GST_RTSP_ADDRESS_POOL_CAST(obj) ((GstRTSPAddressPool*)(obj))
#define GST_RTSP_ADDRESS_POOL_CLASS_CAST(klass) ((GstRTSPAddressPoolClass*)(klass)) #define GST_RTSP_ADDRESS_POOL_CLASS_CAST(klass) ((GstRTSPAddressPoolClass*)(klass))
typedef struct _GstRTSPAddress GstRTSPAddress;
typedef struct _GstRTSPAddressClass GstRTSPAddressClass;
typedef struct _GstRTSPAddressPool GstRTSPAddressPool; typedef struct _GstRTSPAddressPool GstRTSPAddressPool;
typedef struct _GstRTSPAddressPoolClass GstRTSPAddressPoolClass; typedef struct _GstRTSPAddressPoolClass GstRTSPAddressPoolClass;
typedef struct _GstRTSPAddressPoolPrivate GstRTSPAddressPoolPrivate; 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 { typedef enum {
GST_RTSP_ADDRESS_FLAG_NONE = 0, GST_RTSP_ADDRESS_FLAG_NONE = 0,
GST_RTSP_ADDRESS_FLAG_IPV4 = (1 << 0), GST_RTSP_ADDRESS_FLAG_IPV4 = (1 << 0),
@ -74,13 +93,9 @@ gboolean gst_rtsp_address_pool_add_range (GstRTSPAddressPool
guint16 max_port, guint16 max_port,
guint8 ttl); guint8 ttl);
gpointer gst_rtsp_address_pool_acquire_address (GstRTSPAddressPool * pool, GstRTSPAddress * gst_rtsp_address_pool_acquire_address (GstRTSPAddressPool * pool,
GstRTSPAddressFlags flags, GstRTSPAddressFlags flags,
gint n_ports, gint n_ports);
gchar **address,
guint16 *port, guint8 *ttl);
void gst_rtsp_address_pool_release_address (GstRTSPAddressPool * pool,
gpointer);
G_END_DECLS G_END_DECLS
#endif /* __GST_RTSP_ADDRESS_POOL_H__ */ #endif /* __GST_RTSP_ADDRESS_POOL_H__ */

View file

@ -973,31 +973,30 @@ handle_blocksize (GstRTSPMedia * media, GstRTSPMessage * request)
static gboolean static gboolean
configure_client_transport (GstRTSPClient * client, GstRTSPClientState * state, 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. */ /* we have a valid transport now, set the destination of the client. */
if (ct->lower_transport == GST_RTSP_LOWER_TRANS_UDP_MCAST) { if (ct->lower_transport == GST_RTSP_LOWER_TRANS_UDP_MCAST) {
if (ct->destination == NULL || !client->use_client_settings) { if (ct->destination == NULL || !client->use_client_settings) {
GstRTSPAddressPool *pool; GstRTSPAddressPool *pool;
gchar *address; GstRTSPAddress *ad;
guint16 port;
guint8 ttl;
gpointer id;
pool = gst_rtsp_media_get_address_pool (state->media); pool = gst_rtsp_media_get_address_pool (state->media);
if (pool == NULL) if (pool == NULL)
goto no_pool; goto no_pool;
id = gst_rtsp_address_pool_acquire_address (pool, ad = gst_rtsp_address_pool_acquire_address (pool,
GST_RTSP_ADDRESS_FLAG_EVEN_PORT, 2, &address, &port, &ttl); GST_RTSP_ADDRESS_FLAG_EVEN_PORT, 2);
if (id == NULL) if (ad == NULL)
goto no_address; goto no_address;
g_free (ct->destination); g_free (ct->destination);
ct->destination = address; ct->destination = g_strdup (ad->address);
ct->port.min = port; ct->port.min = ad->port;
ct->port.max = port + 1; ct->port.max = ad->port + 1;
ct->ttl = ttl; ct->ttl = ad->ttl;
*addr = ad;
} }
} else { } else {
GstRTSPUrl *url; GstRTSPUrl *url;
@ -1019,10 +1018,12 @@ configure_client_transport (GstRTSPClient * client, GstRTSPClientState * state,
/* ERRORS */ /* ERRORS */
no_pool: no_pool:
{ {
GST_ERROR_OBJECT (client, "no address pool specified");
return FALSE; return FALSE;
} }
no_address: no_address:
{ {
GST_ERROR_OBJECT (client, "failed to acquire address from pool");
return FALSE; return FALSE;
} }
} }
@ -1078,6 +1079,7 @@ handle_setup_request (GstRTSPClient * client, GstRTSPClientState * state)
GstRTSPSessionMedia *sessmedia; GstRTSPSessionMedia *sessmedia;
GstRTSPMedia *media; GstRTSPMedia *media;
GstRTSPStream *stream; GstRTSPStream *stream;
GstRTSPAddress *addr;
uri = state->uri; uri = state->uri;
@ -1166,11 +1168,12 @@ handle_setup_request (GstRTSPClient * client, GstRTSPClientState * state)
goto invalid_blocksize; goto invalid_blocksize;
/* update the client transport */ /* 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; goto unsupported_client_transport;
/* set in the session media 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 */ /* configure keepalive for this transport */
gst_rtsp_stream_transport_set_keepalive (trans, gst_rtsp_stream_transport_set_keepalive (trans,

View file

@ -123,6 +123,7 @@ gst_rtsp_session_media_new (const GstRTSPUrl * url, GstRTSPMedia * media)
* @media: a #GstRTSPSessionMedia * @media: a #GstRTSPSessionMedia
* @stream: a #GstRTSPStream * @stream: a #GstRTSPStream
* @tr: a #GstRTSPTransport * @tr: a #GstRTSPTransport
* @addr: (transfer full) (allow none): an optional #GstRTSPAddress
* *
* Configure the transport for @stream to @tr in @media. * Configure the transport for @stream to @tr in @media.
* *
@ -130,7 +131,7 @@ gst_rtsp_session_media_new (const GstRTSPUrl * url, GstRTSPMedia * media)
*/ */
GstRTSPStreamTransport * GstRTSPStreamTransport *
gst_rtsp_session_media_set_transport (GstRTSPSessionMedia * media, gst_rtsp_session_media_set_transport (GstRTSPSessionMedia * media,
GstRTSPStream * stream, GstRTSPTransport * tr) GstRTSPStream * stream, GstRTSPTransport * tr, GstRTSPAddress * addr)
{ {
GstRTSPStreamTransport *result; GstRTSPStreamTransport *result;
@ -141,11 +142,11 @@ gst_rtsp_session_media_set_transport (GstRTSPSessionMedia * media,
g_mutex_lock (&media->lock); g_mutex_lock (&media->lock);
result = g_ptr_array_index (media->transports, stream->idx); result = g_ptr_array_index (media->transports, stream->idx);
if (result == NULL) { 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_ptr_array_index (media->transports, stream->idx) = result;
g_mutex_unlock (&media->lock); g_mutex_unlock (&media->lock);
} else { } else {
gst_rtsp_stream_transport_set_transport (result, tr); gst_rtsp_stream_transport_set_transport (result, tr, addr);
g_mutex_unlock (&media->lock); g_mutex_unlock (&media->lock);
} }

View file

@ -78,7 +78,8 @@ gboolean gst_rtsp_session_media_set_state (GstRTSPSessionMe
/* get stream transport config */ /* get stream transport config */
GstRTSPStreamTransport * gst_rtsp_session_media_set_transport (GstRTSPSessionMedia *media, GstRTSPStreamTransport * gst_rtsp_session_media_set_transport (GstRTSPSessionMedia *media,
GstRTSPStream *stream, GstRTSPStream *stream,
GstRTSPTransport *tr); GstRTSPTransport *tr,
GstRTSPAddress *addr);
GstRTSPStreamTransport * gst_rtsp_session_media_get_transport (GstRTSPSessionMedia *media, GstRTSPStreamTransport * gst_rtsp_session_media_get_transport (GstRTSPSessionMedia *media,
guint idx); guint idx);

View file

@ -70,6 +70,8 @@ gst_rtsp_stream_transport_finalize (GObject * obj)
if (trans->transport) if (trans->transport)
gst_rtsp_transport_free (trans->transport); gst_rtsp_transport_free (trans->transport);
if (trans->addr)
gst_rtsp_address_free (trans->addr);
#if 0 #if 0
if (trans->rtpsource) if (trans->rtpsource)
@ -83,6 +85,7 @@ gst_rtsp_stream_transport_finalize (GObject * obj)
* gst_rtsp_stream_transport_new: * gst_rtsp_stream_transport_new:
* @stream: a #GstRTSPStream * @stream: a #GstRTSPStream
* @tr: (transfer full): a GstRTSPTransport * @tr: (transfer full): a GstRTSPTransport
* @addr: (transfer full) (allow none): an optional GstRTSPAddress
* *
* Create a new #GstRTSPStreamTransport that can be used to manage * Create a new #GstRTSPStreamTransport that can be used to manage
* @stream with transport @tr. * @stream with transport @tr.
@ -90,7 +93,8 @@ gst_rtsp_stream_transport_finalize (GObject * obj)
* Returns: a new #GstRTSPStreamTransport * Returns: a new #GstRTSPStreamTransport
*/ */
GstRTSPStreamTransport * GstRTSPStreamTransport *
gst_rtsp_stream_transport_new (GstRTSPStream * stream, GstRTSPTransport * tr) gst_rtsp_stream_transport_new (GstRTSPStream * stream, GstRTSPTransport * tr,
GstRTSPAddress * addr)
{ {
GstRTSPStreamTransport *trans; 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 = g_object_new (GST_TYPE_RTSP_STREAM_TRANSPORT, NULL);
trans->stream = stream; trans->stream = stream;
trans->transport = tr; trans->transport = tr;
trans->addr = addr;
return trans; return trans;
} }
@ -154,13 +159,14 @@ gst_rtsp_stream_transport_set_keepalive (GstRTSPStreamTransport * trans,
* gst_rtsp_stream_transport_set_transport: * gst_rtsp_stream_transport_set_transport:
* @trans: a #GstRTSPStreamTransport * @trans: a #GstRTSPStreamTransport
* @tr: (transfer full): a client #GstRTSPTransport * @tr: (transfer full): a client #GstRTSPTransport
* @addr: (transfer full) (allow none): a ##GstRTSPAddress
* *
* Set @ct as the client transport. This function takes ownership of * Set @tr and the optional @addr as the client transport. This function
* the passed @tr. * takes ownership of the passed @tr and @addr.
*/ */
void void
gst_rtsp_stream_transport_set_transport (GstRTSPStreamTransport * trans, 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 (GST_IS_RTSP_STREAM_TRANSPORT (trans));
g_return_if_fail (tr != NULL); g_return_if_fail (tr != NULL);
@ -169,6 +175,9 @@ gst_rtsp_stream_transport_set_transport (GstRTSPStreamTransport * trans,
if (trans->transport) if (trans->transport)
gst_rtsp_transport_free (trans->transport); gst_rtsp_transport_free (trans->transport);
trans->transport = tr; trans->transport = tr;
if (trans->addr)
gst_rtsp_address_free (trans->addr);
trans->addr = addr;
} }
/** /**

View file

@ -40,6 +40,7 @@ typedef struct _GstRTSPStreamTransport GstRTSPStreamTransport;
typedef struct _GstRTSPStreamTransportClass GstRTSPStreamTransportClass; typedef struct _GstRTSPStreamTransportClass GstRTSPStreamTransportClass;
#include "rtsp-stream.h" #include "rtsp-stream.h"
#include "rtsp-address-pool.h"
typedef gboolean (*GstRTSPSendFunc) (GstBuffer *buffer, guint8 channel, gpointer user_data); typedef gboolean (*GstRTSPSendFunc) (GstBuffer *buffer, guint8 channel, gpointer user_data);
typedef void (*GstRTSPKeepAliveFunc) (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 * @active: if we are actively sending
* @timeout: if we timed out * @timeout: if we timed out
* @transport: a transport description * @transport: a transport description
* @addr: an optional address
* @rtpsource: the receiver rtp source object * @rtpsource: the receiver rtp source object
* *
* A Transport description for stream @idx * A Transport description for stream @idx
@ -79,6 +81,7 @@ struct _GstRTSPStreamTransport {
gboolean timeout; gboolean timeout;
GstRTSPTransport *transport; GstRTSPTransport *transport;
GstRTSPAddress *addr;
GObject *rtpsource; GObject *rtpsource;
}; };
@ -90,10 +93,12 @@ struct _GstRTSPStreamTransportClass {
GType gst_rtsp_stream_transport_get_type (void); GType gst_rtsp_stream_transport_get_type (void);
GstRTSPStreamTransport * gst_rtsp_stream_transport_new (GstRTSPStream *stream, GstRTSPStreamTransport * gst_rtsp_stream_transport_new (GstRTSPStream *stream,
GstRTSPTransport *tr); GstRTSPTransport *tr,
GstRTSPAddress *addr);
void gst_rtsp_stream_transport_set_transport (GstRTSPStreamTransport *trans, void gst_rtsp_stream_transport_set_transport (GstRTSPStreamTransport *trans,
GstRTSPTransport * tr); GstRTSPTransport * tr,
GstRTSPAddress *addr);
void gst_rtsp_stream_transport_set_callbacks (GstRTSPStreamTransport *trans, void gst_rtsp_stream_transport_set_callbacks (GstRTSPStreamTransport *trans,
GstRTSPSendFunc send_rtp, GstRTSPSendFunc send_rtp,

View file

@ -23,11 +23,8 @@
GST_START_TEST (test_pool) GST_START_TEST (test_pool)
{ {
gpointer id;
GstRTSPAddressPool *pool; GstRTSPAddressPool *pool;
gchar *address; GstRTSPAddress *addr;
guint16 port;
guint8 ttl;
pool = gst_rtsp_address_pool_new (); 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)); "233.255.0.0", "233.255.0.0", 5020, 5020, 1));
/* should fail, we can't allocate a block of 256 ports */ /* should fail, we can't allocate a block of 256 ports */
id = gst_rtsp_address_pool_acquire_address (pool, addr = gst_rtsp_address_pool_acquire_address (pool, 0, 256);
0, 256, &address, &port, &ttl); fail_unless (addr == NULL);
fail_unless (id == NULL);
id = gst_rtsp_address_pool_acquire_address (pool, addr = gst_rtsp_address_pool_acquire_address (pool, 0, 2);
0, 2, &address, &port, &ttl); fail_unless (addr != NULL);
fail_unless (id != NULL);
gst_rtsp_address_pool_release_address (pool, id); gst_rtsp_address_free (addr);
g_free (address);
id = gst_rtsp_address_pool_acquire_address (pool, addr = gst_rtsp_address_pool_acquire_address (pool, 0, 4);
0, 4, &address, &port, &ttl); fail_unless (addr != NULL);
fail_unless (id != NULL);
gst_rtsp_address_pool_release_address (pool, id); gst_rtsp_address_free (addr);
g_free (address);
g_object_unref (pool); g_object_unref (pool);
} }