2 * Copyright (C) 2012 Wim Taymans <wim.taymans at gmail.com>
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
23 #include "rtsp-address-pool.h"
26 gst_rtsp_address_copy (GstRTSPAddress * addr)
30 g_return_val_if_fail (addr != NULL, NULL);
32 copy = g_slice_dup (GstRTSPAddress, addr);
33 /* only release to the pool when the original is freed. It's a bit
34 * weird but this will do for now as it avoid us to use refcounting. */
36 copy->address = g_strdup (copy->address);
41 static void gst_rtsp_address_pool_release_address (GstRTSPAddressPool * pool,
42 GstRTSPAddress * addr);
45 gst_rtsp_address_free (GstRTSPAddress * addr)
47 g_return_if_fail (addr != NULL);
50 /* unrefs the pool and sets it to NULL */
51 gst_rtsp_address_pool_release_address (addr->pool, addr);
53 g_free (addr->address);
54 g_slice_free (GstRTSPAddress, addr);
58 G_DEFINE_BOXED_TYPE (GstRTSPAddress, gst_rtsp_address,
59 (GBoxedCopyFunc) gst_rtsp_address_copy,
60 (GBoxedFreeFunc) gst_rtsp_address_free);
62 GST_DEBUG_CATEGORY_STATIC (rtsp_address_pool_debug);
63 #define GST_CAT_DEFAULT rtsp_address_pool_debug
65 #define GST_RTSP_ADDRESS_POOL_GET_PRIVATE(obj) \
66 (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_RTSP_ADDRESS_POOL, GstRTSPAddressPoolPrivate))
68 struct _GstRTSPAddressPoolPrivate
75 #define ADDR_IS_IPV4(a) ((a)->size == 4)
76 #define ADDR_IS_IPV6(a) ((a)->size == 16)
77 #define ADDR_IS_EVEN_PORT(a) (((a)->port & 1) == 0)
93 #define RANGE_IS_SINGLE(r) (memcmp ((r)->min.bytes, (r)->max.bytes, (r)->min.size) == 0)
95 #define gst_rtsp_address_pool_parent_class parent_class
96 G_DEFINE_TYPE (GstRTSPAddressPool, gst_rtsp_address_pool, G_TYPE_OBJECT);
98 static void gst_rtsp_address_pool_finalize (GObject * obj);
101 gst_rtsp_address_pool_class_init (GstRTSPAddressPoolClass * klass)
103 GObjectClass *gobject_class;
105 gobject_class = G_OBJECT_CLASS (klass);
107 gobject_class->finalize = gst_rtsp_address_pool_finalize;
109 g_type_class_add_private (klass, sizeof (GstRTSPAddressPoolPrivate));
111 GST_DEBUG_CATEGORY_INIT (rtsp_address_pool_debug, "rtspaddresspool", 0,
112 "GstRTSPAddressPool");
116 gst_rtsp_address_pool_init (GstRTSPAddressPool * pool)
118 pool->priv = GST_RTSP_ADDRESS_POOL_GET_PRIVATE (pool);
120 g_mutex_init (&pool->priv->lock);
124 free_range (AddrRange * range)
126 g_slice_free (AddrRange, range);
130 gst_rtsp_address_pool_finalize (GObject * obj)
132 GstRTSPAddressPool *pool;
134 pool = GST_RTSP_ADDRESS_POOL (obj);
136 g_list_free_full (pool->priv->addresses, (GDestroyNotify) free_range);
137 g_list_free_full (pool->priv->allocated, (GDestroyNotify) free_range);
138 g_mutex_clear (&pool->priv->lock);
140 G_OBJECT_CLASS (parent_class)->finalize (obj);
144 * gst_rtsp_address_pool_new:
146 * Make a new #GstRTSPAddressPool.
148 * Returns: a new #GstRTSPAddressPool
151 gst_rtsp_address_pool_new (void)
153 GstRTSPAddressPool *pool;
155 pool = g_object_new (GST_TYPE_RTSP_ADDRESS_POOL, NULL);
161 * gst_rtsp_address_pool_clear:
162 * @pool: a #GstRTSPAddressPool
164 * Clear all addresses in @pool. There should be no outstanding
168 gst_rtsp_address_pool_clear (GstRTSPAddressPool * pool)
170 GstRTSPAddressPoolPrivate *priv;
172 g_return_if_fail (GST_IS_RTSP_ADDRESS_POOL (pool));
173 g_return_if_fail (pool->priv->allocated == NULL);
177 g_mutex_lock (&priv->lock);
178 g_list_free_full (priv->addresses, (GDestroyNotify) free_range);
179 priv->addresses = NULL;
180 g_mutex_unlock (&priv->lock);
184 fill_address (const gchar * address, guint16 port, Addr * addr)
188 inet = g_inet_address_new_from_string (address);
192 addr->size = g_inet_address_get_native_size (inet);
193 memcpy (addr->bytes, g_inet_address_to_bytes (inet), addr->size);
194 g_object_unref (inet);
201 get_address_string (Addr * addr)
206 inet = g_inet_address_new_from_bytes (addr->bytes,
207 addr->size == 4 ? G_SOCKET_FAMILY_IPV4 : G_SOCKET_FAMILY_IPV6);
208 res = g_inet_address_to_string (inet);
209 g_object_unref (inet);
215 * gst_rtsp_address_pool_add_range:
216 * @pool: a #GstRTSPAddressPool
217 * @min_address: a minimum address to add
218 * @max_address: a maximum address to add
219 * @min_port: the minimum port
220 * @max_port: the maximum port
223 * Adds the multicast addresses from @min_addess to @max_address (inclusive)
224 * to @pool. The valid port range for the addresses will be from @min_port to
225 * @max_port inclusive.
227 * Returns: %TRUE if the addresses could be added.
230 gst_rtsp_address_pool_add_range (GstRTSPAddressPool * pool,
231 const gchar * min_address, const gchar * max_address,
232 guint16 min_port, guint16 max_port, guint8 ttl)
235 GstRTSPAddressPoolPrivate *priv;
237 g_return_val_if_fail (GST_IS_RTSP_ADDRESS_POOL (pool), FALSE);
238 g_return_val_if_fail (min_port <= max_port, FALSE);
242 range = g_slice_new0 (AddrRange);
244 if (!fill_address (min_address, min_port, &range->min))
246 if (!fill_address (max_address, max_port, &range->max))
249 if (range->min.size != range->max.size)
251 if (memcmp (range->min.bytes, range->max.bytes, range->min.size) > 0)
256 GST_DEBUG_OBJECT (pool, "adding %s-%s:%u-%u ttl %u", min_address, max_address,
257 min_port, max_port, ttl);
259 g_mutex_lock (&priv->lock);
260 priv->addresses = g_list_prepend (priv->addresses, range);
261 g_mutex_unlock (&priv->lock);
268 GST_ERROR_OBJECT (pool, "invalid address range %s-%s", min_address,
270 g_slice_free (AddrRange, range);
276 inc_address (GstRTSPAddressPool * pool, Addr * addr)
282 for (i = addr->size - 1; i >= 0 && carry > 0; i--) {
283 carry += addr->bytes[i];
284 addr->bytes[i] = carry & 0xff;
290 split_range (GstRTSPAddressPool * pool, AddrRange * range, gint skip,
293 GstRTSPAddressPoolPrivate *priv = pool->priv;
296 if (!RANGE_IS_SINGLE (range)) {
297 /* min and max are not the same, we have more than one address. */
298 temp = g_slice_dup (AddrRange, range);
299 /* increment the range min address */
300 inc_address (pool, &temp->min);
301 /* and store back in pool */
302 priv->addresses = g_list_prepend (priv->addresses, temp);
304 /* adjust range with only the first address */
305 memcpy (range->max.bytes, range->min.bytes, range->min.size);
308 /* range now contains only one single address */
310 /* make a range with the skipped ports */
311 temp = g_slice_dup (AddrRange, range);
312 temp->max.port = temp->min.port + skip;
313 /* and store back in pool */
314 priv->addresses = g_list_prepend (priv->addresses, temp);
316 /* increment range port */
317 range->min.port += skip;
319 /* range now contains single address with desired port number */
320 if (range->max.port - range->min.port + 1 > n_ports) {
321 /* make a range with the remaining ports */
322 temp = g_slice_dup (AddrRange, range);
323 temp->min.port += n_ports;
324 /* and store back in pool */
325 priv->addresses = g_list_prepend (priv->addresses, temp);
327 /* and truncate port */
328 range->max.port = range->min.port + n_ports - 1;
334 * gst_rtsp_address_pool_acquire_address:
335 * @pool: a #GstRTSPAddressPool
337 * @n_ports: the amount of ports
339 * Take an address and ports from @pool. @flags can be used to control the
340 * allocation. @n_ports consecutive ports will be allocated of which the first
341 * one can be found in @port.
343 * Returns: a #GstRTSPAddress that should be freed with gst_rtsp_address_free
344 * after use or %NULL when no address could be acquired.
347 gst_rtsp_address_pool_acquire_address (GstRTSPAddressPool * pool,
348 GstRTSPAddressFlags flags, gint n_ports)
350 GstRTSPAddressPoolPrivate *priv;
353 GstRTSPAddress *addr;
355 g_return_val_if_fail (GST_IS_RTSP_ADDRESS_POOL (pool), NULL);
356 g_return_val_if_fail (n_ports > 0, NULL);
362 g_mutex_lock (&priv->lock);
363 /* go over available ranges */
364 for (walk = priv->addresses; walk; walk = next) {
371 /* check address type when given */
372 if (flags & GST_RTSP_ADDRESS_FLAG_IPV4 && !ADDR_IS_IPV4 (&range->min))
374 if (flags & GST_RTSP_ADDRESS_FLAG_IPV6 && !ADDR_IS_IPV6 (&range->min))
377 /* check for enough ports */
378 ports = range->max.port - range->min.port + 1;
379 if (flags & GST_RTSP_ADDRESS_FLAG_EVEN_PORT
380 && !ADDR_IS_EVEN_PORT (&range->min))
384 if (ports - skip < n_ports)
387 /* we found a range, remove from the list */
388 priv->addresses = g_list_delete_link (priv->addresses, walk);
389 /* now split and exit our loop */
390 result = split_range (pool, range, skip, n_ports);
391 priv->allocated = g_list_prepend (priv->allocated, result);
394 g_mutex_unlock (&priv->lock);
397 addr = g_slice_new0 (GstRTSPAddress);
398 addr->pool = g_object_ref (pool);
399 addr->address = get_address_string (&result->min);
400 addr->n_ports = n_ports;
401 addr->port = result->min.port;
402 addr->ttl = result->ttl;
405 GST_DEBUG_OBJECT (pool, "got address %s:%u ttl %u", addr->address,
406 addr->port, addr->ttl);
413 * gst_rtsp_address_pool_release_address:
414 * @pool: a #GstRTSPAddressPool
417 * Release a previously acquired address (with
418 * gst_rtsp_address_pool_acquire_address()) back into @pool.
421 gst_rtsp_address_pool_release_address (GstRTSPAddressPool * pool,
422 GstRTSPAddress * addr)
424 GstRTSPAddressPoolPrivate *priv;
428 g_return_if_fail (GST_IS_RTSP_ADDRESS_POOL (pool));
429 g_return_if_fail (addr != NULL);
430 g_return_if_fail (addr->pool == pool);
435 /* we don't want to free twice */
439 g_mutex_lock (&priv->lock);
440 find = g_list_find (priv->allocated, range);
444 priv->allocated = g_list_delete_link (priv->allocated, find);
446 /* FIXME, merge and do something clever */
447 priv->addresses = g_list_prepend (priv->addresses, range);
448 g_mutex_unlock (&priv->lock);
450 g_object_unref (pool);
457 g_warning ("Released unknown address %p", addr);
458 g_mutex_unlock (&priv->lock);
464 dump_range (AddrRange * range, GstRTSPAddressPool * pool)
466 gchar *addr1, *addr2;
468 addr1 = get_address_string (&range->min);
469 addr2 = get_address_string (&range->max);
470 g_print (" address %s-%s, port %u-%u, ttl %u\n", addr1, addr2,
471 range->min.port, range->max.port, range->ttl);
477 * gst_rtsp_address_pool_dump:
478 * @pool: a #GstRTSPAddressPool
480 * Dump the free and allocated addresses to stdout.
483 gst_rtsp_address_pool_dump (GstRTSPAddressPool * pool)
485 GstRTSPAddressPoolPrivate *priv;
487 g_return_if_fail (GST_IS_RTSP_ADDRESS_POOL (pool));
491 g_mutex_lock (&priv->lock);
493 g_list_foreach (priv->addresses, (GFunc) dump_range, pool);
494 g_print ("allocated:\n");
495 g_list_foreach (priv->allocated, (GFunc) dump_range, pool);
496 g_mutex_unlock (&priv->lock);