Initial release including wifi display based on gst-rtsp-server-1.4.1
[platform/upstream/gstreamer.git] / gst / rtsp-server / rtsp-address-pool.c
1 /* GStreamer
2  * Copyright (C) 2012 Wim Taymans <wim.taymans at gmail.com>
3  *
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.
8  *
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.
13  *
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.
18  */
19 /**
20  * SECTION:rtsp-address-pool
21  * @short_description: A pool of network addresses
22  * @see_also: #GstRTSPStream, #GstRTSPStreamTransport
23  *
24  * The #GstRTSPAddressPool is an object that maintains a collection of network
25  * addresses. It is used to allocate server ports and server multicast addresses
26  * but also to reserve client provided destination addresses.
27  *
28  * A range of addresses can be added with gst_rtsp_address_pool_add_range().
29  * Both multicast and unicast addresses can be added.
30  *
31  * With gst_rtsp_address_pool_acquire_address() an unused address and port range
32  * can be acquired from the pool. With gst_rtsp_address_pool_reserve_address() a
33  * specific address can be retrieved. Both methods return a boxed
34  * #GstRTSPAddress that should be freed with gst_rtsp_address_free() after
35  * usage, which brings the address back into the pool.
36  *
37  * Last reviewed on 2013-07-16 (1.0.0)
38  */
39
40 #include <string.h>
41 #include <gio/gio.h>
42
43 #include "rtsp-address-pool.h"
44
45 /**
46  * gst_rtsp_address_copy:
47  * @addr: a #GstRTSPAddress
48  *
49  * Make a copy of @addr.
50  *
51  * Returns: a copy of @addr.
52  */
53 GstRTSPAddress *
54 gst_rtsp_address_copy (GstRTSPAddress * addr)
55 {
56   GstRTSPAddress *copy;
57
58   g_return_val_if_fail (addr != NULL, NULL);
59
60   copy = g_slice_dup (GstRTSPAddress, addr);
61   /* only release to the pool when the original is freed. It's a bit
62    * weird but this will do for now as it avoid us to use refcounting. */
63   copy->pool = NULL;
64   copy->address = g_strdup (copy->address);
65
66   return copy;
67 }
68
69 static void gst_rtsp_address_pool_release_address (GstRTSPAddressPool * pool,
70     GstRTSPAddress * addr);
71
72 /**
73  * gst_rtsp_address_free:
74  * @addr: a #GstRTSPAddress
75  *
76  * Free @addr and releasing it back into the pool when owned by a
77  * pool.
78  */
79 void
80 gst_rtsp_address_free (GstRTSPAddress * addr)
81 {
82   g_return_if_fail (addr != NULL);
83
84   if (addr->pool) {
85     /* unrefs the pool and sets it to NULL */
86     gst_rtsp_address_pool_release_address (addr->pool, addr);
87   }
88   g_free (addr->address);
89   g_slice_free (GstRTSPAddress, addr);
90 }
91
92 G_DEFINE_BOXED_TYPE (GstRTSPAddress, gst_rtsp_address,
93     (GBoxedCopyFunc) gst_rtsp_address_copy,
94     (GBoxedFreeFunc) gst_rtsp_address_free);
95
96 GST_DEBUG_CATEGORY_STATIC (rtsp_address_pool_debug);
97 #define GST_CAT_DEFAULT rtsp_address_pool_debug
98
99 #define GST_RTSP_ADDRESS_POOL_GET_PRIVATE(obj)  \
100      (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_RTSP_ADDRESS_POOL, GstRTSPAddressPoolPrivate))
101
102 struct _GstRTSPAddressPoolPrivate
103 {
104   GMutex lock;                  /* protects everything in this struct */
105   GList *addresses;
106   GList *allocated;
107
108   gboolean has_unicast_addresses;
109 };
110
111 #define ADDR_IS_IPV4(a)      ((a)->size == 4)
112 #define ADDR_IS_IPV6(a)      ((a)->size == 16)
113 #define ADDR_IS_EVEN_PORT(a) (((a)->port & 1) == 0)
114
115 typedef struct
116 {
117   guint8 bytes[16];
118   gsize size;
119   guint16 port;
120 } Addr;
121
122 typedef struct
123 {
124   Addr min;
125   Addr max;
126   guint8 ttl;
127 } AddrRange;
128
129 #define RANGE_IS_SINGLE(r) (memcmp ((r)->min.bytes, (r)->max.bytes, (r)->min.size) == 0)
130
131 #define gst_rtsp_address_pool_parent_class parent_class
132 G_DEFINE_TYPE (GstRTSPAddressPool, gst_rtsp_address_pool, G_TYPE_OBJECT);
133
134 static void gst_rtsp_address_pool_finalize (GObject * obj);
135
136 static void
137 gst_rtsp_address_pool_class_init (GstRTSPAddressPoolClass * klass)
138 {
139   GObjectClass *gobject_class;
140
141   gobject_class = G_OBJECT_CLASS (klass);
142
143   gobject_class->finalize = gst_rtsp_address_pool_finalize;
144
145   g_type_class_add_private (klass, sizeof (GstRTSPAddressPoolPrivate));
146
147   GST_DEBUG_CATEGORY_INIT (rtsp_address_pool_debug, "rtspaddresspool", 0,
148       "GstRTSPAddressPool");
149 }
150
151 static void
152 gst_rtsp_address_pool_init (GstRTSPAddressPool * pool)
153 {
154   pool->priv = GST_RTSP_ADDRESS_POOL_GET_PRIVATE (pool);
155
156   g_mutex_init (&pool->priv->lock);
157 }
158
159 static void
160 free_range (AddrRange * range)
161 {
162   g_slice_free (AddrRange, range);
163 }
164
165 static void
166 gst_rtsp_address_pool_finalize (GObject * obj)
167 {
168   GstRTSPAddressPool *pool;
169
170   pool = GST_RTSP_ADDRESS_POOL (obj);
171
172   g_list_free_full (pool->priv->addresses, (GDestroyNotify) free_range);
173   g_list_free_full (pool->priv->allocated, (GDestroyNotify) free_range);
174   g_mutex_clear (&pool->priv->lock);
175
176   G_OBJECT_CLASS (parent_class)->finalize (obj);
177 }
178
179 /**
180  * gst_rtsp_address_pool_new:
181  *
182  * Make a new #GstRTSPAddressPool.
183  *
184  * Returns: (transfer full): a new #GstRTSPAddressPool
185  */
186 GstRTSPAddressPool *
187 gst_rtsp_address_pool_new (void)
188 {
189   GstRTSPAddressPool *pool;
190
191   pool = g_object_new (GST_TYPE_RTSP_ADDRESS_POOL, NULL);
192
193   return pool;
194 }
195
196 /**
197  * gst_rtsp_address_pool_clear:
198  * @pool: a #GstRTSPAddressPool
199  *
200  * Clear all addresses in @pool. There should be no outstanding
201  * allocations.
202  */
203 void
204 gst_rtsp_address_pool_clear (GstRTSPAddressPool * pool)
205 {
206   GstRTSPAddressPoolPrivate *priv;
207
208   g_return_if_fail (GST_IS_RTSP_ADDRESS_POOL (pool));
209   g_return_if_fail (pool->priv->allocated == NULL);
210
211   priv = pool->priv;
212
213   g_mutex_lock (&priv->lock);
214   g_list_free_full (priv->addresses, (GDestroyNotify) free_range);
215   priv->addresses = NULL;
216   g_mutex_unlock (&priv->lock);
217 }
218
219 static gboolean
220 fill_address (const gchar * address, guint16 port, Addr * addr,
221     gboolean is_multicast)
222 {
223   GInetAddress *inet;
224
225   inet = g_inet_address_new_from_string (address);
226   if (inet == NULL)
227     return FALSE;
228
229   if (is_multicast != g_inet_address_get_is_multicast (inet)) {
230     g_object_unref (inet);
231     return FALSE;
232   }
233
234   addr->size = g_inet_address_get_native_size (inet);
235   memcpy (addr->bytes, g_inet_address_to_bytes (inet), addr->size);
236   g_object_unref (inet);
237   addr->port = port;
238
239   return TRUE;
240 }
241
242 static gchar *
243 get_address_string (Addr * addr)
244 {
245   gchar *res;
246   GInetAddress *inet;
247
248   inet = g_inet_address_new_from_bytes (addr->bytes,
249       addr->size == 4 ? G_SOCKET_FAMILY_IPV4 : G_SOCKET_FAMILY_IPV6);
250   res = g_inet_address_to_string (inet);
251   g_object_unref (inet);
252
253   return res;
254 }
255
256 /**
257  * gst_rtsp_address_pool_add_range:
258  * @pool: a #GstRTSPAddressPool
259  * @min_address: a minimum address to add
260  * @max_address: a maximum address to add
261  * @min_port: the minimum port
262  * @max_port: the maximum port
263  * @ttl: a TTL or 0 for unicast addresses
264  *
265  * Adds the addresses from @min_addess to @max_address (inclusive)
266  * to @pool. The valid port range for the addresses will be from @min_port to
267  * @max_port inclusive.
268  *
269  * When @ttl is 0, @min_address and @max_address should be unicast addresses.
270  * @min_address and @max_address can be set to
271  * #GST_RTSP_ADDRESS_POOL_ANY_IPV4 or #GST_RTSP_ADDRESS_POOL_ANY_IPV6 to bind
272  * to all available IPv4 or IPv6 addresses.
273  *
274  * When @ttl > 0, @min_address and @max_address should be multicast addresses.
275  *
276  * Returns: %TRUE if the addresses could be added.
277  */
278 gboolean
279 gst_rtsp_address_pool_add_range (GstRTSPAddressPool * pool,
280     const gchar * min_address, const gchar * max_address,
281     guint16 min_port, guint16 max_port, guint8 ttl)
282 {
283   AddrRange *range;
284   GstRTSPAddressPoolPrivate *priv;
285   gboolean is_multicast;
286
287   g_return_val_if_fail (GST_IS_RTSP_ADDRESS_POOL (pool), FALSE);
288   g_return_val_if_fail (min_port <= max_port, FALSE);
289
290   priv = pool->priv;
291
292   is_multicast = ttl != 0;
293
294   range = g_slice_new0 (AddrRange);
295
296   if (!fill_address (min_address, min_port, &range->min, is_multicast))
297     goto invalid;
298   if (!fill_address (max_address, max_port, &range->max, is_multicast))
299     goto invalid;
300
301   if (range->min.size != range->max.size)
302     goto invalid;
303   if (memcmp (range->min.bytes, range->max.bytes, range->min.size) > 0)
304     goto invalid;
305
306   range->ttl = ttl;
307
308   GST_DEBUG_OBJECT (pool, "adding %s-%s:%u-%u ttl %u", min_address, max_address,
309       min_port, max_port, ttl);
310
311   g_mutex_lock (&priv->lock);
312   priv->addresses = g_list_prepend (priv->addresses, range);
313
314   if (!is_multicast)
315     priv->has_unicast_addresses = TRUE;
316   g_mutex_unlock (&priv->lock);
317
318   return TRUE;
319
320   /* ERRORS */
321 invalid:
322   {
323     GST_ERROR_OBJECT (pool, "invalid address range %s-%s", min_address,
324         max_address);
325     g_slice_free (AddrRange, range);
326     return FALSE;
327   }
328 }
329
330 static void
331 inc_address (Addr * addr, guint count)
332 {
333   gint i;
334   guint carry;
335
336   carry = count;
337   for (i = addr->size - 1; i >= 0 && carry > 0; i--) {
338     carry += addr->bytes[i];
339     addr->bytes[i] = carry & 0xff;
340     carry >>= 8;
341   }
342 }
343
344 /* tells us the number of addresses between min_addr and max_addr */
345 static guint
346 diff_address (Addr * max_addr, Addr * min_addr)
347 {
348   gint i;
349   guint result = 0;
350
351   g_return_val_if_fail (min_addr->size == max_addr->size, 0);
352
353   for (i = 0; i < min_addr->size; i++) {
354     g_return_val_if_fail (result < (1 << 24), result);
355
356     result <<= 8;
357     result += max_addr->bytes[i] - min_addr->bytes[i];
358   }
359
360   return result;
361 }
362
363 static AddrRange *
364 split_range (GstRTSPAddressPool * pool, AddrRange * range, guint skip_addr,
365     guint skip_port, gint n_ports)
366 {
367   GstRTSPAddressPoolPrivate *priv = pool->priv;
368   AddrRange *temp;
369
370   if (skip_addr) {
371     temp = g_slice_dup (AddrRange, range);
372     memcpy (temp->max.bytes, temp->min.bytes, temp->min.size);
373     inc_address (&temp->max, skip_addr - 1);
374     priv->addresses = g_list_prepend (priv->addresses, temp);
375
376     inc_address (&range->min, skip_addr);
377   }
378
379   if (!RANGE_IS_SINGLE (range)) {
380     /* min and max are not the same, we have more than one address. */
381     temp = g_slice_dup (AddrRange, range);
382     /* increment the range min address */
383     inc_address (&temp->min, 1);
384     /* and store back in pool */
385     priv->addresses = g_list_prepend (priv->addresses, temp);
386
387     /* adjust range with only the first address */
388     memcpy (range->max.bytes, range->min.bytes, range->min.size);
389   }
390
391   /* range now contains only one single address */
392   if (skip_port > 0) {
393     /* make a range with the skipped ports */
394     temp = g_slice_dup (AddrRange, range);
395     temp->max.port = temp->min.port + skip_port - 1;
396     /* and store back in pool */
397     priv->addresses = g_list_prepend (priv->addresses, temp);
398
399     /* increment range port */
400     range->min.port += skip_port;
401   }
402   /* range now contains single address with desired port number */
403   if (range->max.port - range->min.port + 1 > n_ports) {
404     /* make a range with the remaining ports */
405     temp = g_slice_dup (AddrRange, range);
406     temp->min.port += n_ports;
407     /* and store back in pool */
408     priv->addresses = g_list_prepend (priv->addresses, temp);
409
410     /* and truncate port */
411     range->max.port = range->min.port + n_ports - 1;
412   }
413   return range;
414 }
415
416 /**
417  * gst_rtsp_address_pool_acquire_address:
418  * @pool: a #GstRTSPAddressPool
419  * @flags: flags
420  * @n_ports: the amount of ports
421  *
422  * Take an address and ports from @pool. @flags can be used to control the
423  * allocation. @n_ports consecutive ports will be allocated of which the first
424  * one can be found in @port.
425  *
426  * Returns: (nullable): a #GstRTSPAddress that should be freed with
427  * gst_rtsp_address_free after use or %NULL when no address could be
428  * acquired.
429  */
430 GstRTSPAddress *
431 gst_rtsp_address_pool_acquire_address (GstRTSPAddressPool * pool,
432     GstRTSPAddressFlags flags, gint n_ports)
433 {
434   GstRTSPAddressPoolPrivate *priv;
435   GList *walk, *next;
436   AddrRange *result;
437   GstRTSPAddress *addr;
438
439   g_return_val_if_fail (GST_IS_RTSP_ADDRESS_POOL (pool), NULL);
440   g_return_val_if_fail (n_ports > 0, NULL);
441
442   priv = pool->priv;
443   result = NULL;
444   addr = NULL;
445
446   g_mutex_lock (&priv->lock);
447   /* go over available ranges */
448   for (walk = priv->addresses; walk; walk = next) {
449     AddrRange *range;
450     gint ports, skip;
451
452     range = walk->data;
453     next = walk->next;
454
455     /* check address type when given */
456     if (flags & GST_RTSP_ADDRESS_FLAG_IPV4 && !ADDR_IS_IPV4 (&range->min))
457       continue;
458     if (flags & GST_RTSP_ADDRESS_FLAG_IPV6 && !ADDR_IS_IPV6 (&range->min))
459       continue;
460     if (flags & GST_RTSP_ADDRESS_FLAG_MULTICAST && range->ttl == 0)
461       continue;
462     if (flags & GST_RTSP_ADDRESS_FLAG_UNICAST && range->ttl != 0)
463       continue;
464
465     /* check for enough ports */
466     ports = range->max.port - range->min.port + 1;
467     if (flags & GST_RTSP_ADDRESS_FLAG_EVEN_PORT
468         && !ADDR_IS_EVEN_PORT (&range->min))
469       skip = 1;
470     else
471       skip = 0;
472     if (ports - skip < n_ports)
473       continue;
474
475     /* we found a range, remove from the list */
476     priv->addresses = g_list_delete_link (priv->addresses, walk);
477     /* now split and exit our loop */
478     result = split_range (pool, range, 0, skip, n_ports);
479     priv->allocated = g_list_prepend (priv->allocated, result);
480     break;
481   }
482   g_mutex_unlock (&priv->lock);
483
484   if (result) {
485     addr = g_slice_new0 (GstRTSPAddress);
486     addr->pool = g_object_ref (pool);
487     addr->address = get_address_string (&result->min);
488     addr->n_ports = n_ports;
489     addr->port = result->min.port;
490     addr->ttl = result->ttl;
491     addr->priv = result;
492
493     GST_DEBUG_OBJECT (pool, "got address %s:%u ttl %u", addr->address,
494         addr->port, addr->ttl);
495   }
496
497   return addr;
498 }
499
500 /**
501  * gst_rtsp_address_pool_release_address:
502  * @pool: a #GstRTSPAddressPool
503  * @id: an address id
504  *
505  * Release a previously acquired address (with
506  * gst_rtsp_address_pool_acquire_address()) back into @pool.
507  */
508 static void
509 gst_rtsp_address_pool_release_address (GstRTSPAddressPool * pool,
510     GstRTSPAddress * addr)
511 {
512   GstRTSPAddressPoolPrivate *priv;
513   GList *find;
514   AddrRange *range;
515
516   g_return_if_fail (GST_IS_RTSP_ADDRESS_POOL (pool));
517   g_return_if_fail (addr != NULL);
518   g_return_if_fail (addr->pool == pool);
519
520   priv = pool->priv;
521   range = addr->priv;
522
523   /* we don't want to free twice */
524   addr->priv = NULL;
525   addr->pool = NULL;
526
527   g_mutex_lock (&priv->lock);
528   find = g_list_find (priv->allocated, range);
529   if (find == NULL)
530     goto not_found;
531
532   priv->allocated = g_list_delete_link (priv->allocated, find);
533
534   /* FIXME, merge and do something clever */
535   priv->addresses = g_list_prepend (priv->addresses, range);
536   g_mutex_unlock (&priv->lock);
537
538   g_object_unref (pool);
539
540   return;
541
542   /* ERRORS */
543 not_found:
544   {
545     g_warning ("Released unknown address %p", addr);
546     g_mutex_unlock (&priv->lock);
547     return;
548   }
549 }
550
551 static void
552 dump_range (AddrRange * range, GstRTSPAddressPool * pool)
553 {
554   gchar *addr1, *addr2;
555
556   addr1 = get_address_string (&range->min);
557   addr2 = get_address_string (&range->max);
558   g_print ("  address %s-%s, port %u-%u, ttl %u\n", addr1, addr2,
559       range->min.port, range->max.port, range->ttl);
560   g_free (addr1);
561   g_free (addr2);
562 }
563
564 /**
565  * gst_rtsp_address_pool_dump:
566  * @pool: a #GstRTSPAddressPool
567  *
568  * Dump the free and allocated addresses to stdout.
569  */
570 void
571 gst_rtsp_address_pool_dump (GstRTSPAddressPool * pool)
572 {
573   GstRTSPAddressPoolPrivate *priv;
574
575   g_return_if_fail (GST_IS_RTSP_ADDRESS_POOL (pool));
576
577   priv = pool->priv;
578
579   g_mutex_lock (&priv->lock);
580   g_print ("free:\n");
581   g_list_foreach (priv->addresses, (GFunc) dump_range, pool);
582   g_print ("allocated:\n");
583   g_list_foreach (priv->allocated, (GFunc) dump_range, pool);
584   g_mutex_unlock (&priv->lock);
585 }
586
587 static GList *
588 find_address_in_ranges (GList * addresses, Addr * addr, guint port,
589     guint n_ports, guint ttl)
590 {
591   GList *walk, *next;
592
593   /* go over available ranges */
594   for (walk = addresses; walk; walk = next) {
595     AddrRange *range;
596
597     range = walk->data;
598     next = walk->next;
599
600     /* Not the right type of address */
601     if (range->min.size != addr->size)
602       continue;
603
604     /* Check that the address is in the interval */
605     if (memcmp (range->min.bytes, addr->bytes, addr->size) > 0 ||
606         memcmp (range->max.bytes, addr->bytes, addr->size) < 0)
607       continue;
608
609     /* Make sure the requested ports are inside the range */
610     if (port < range->min.port || port + n_ports - 1 > range->max.port)
611       continue;
612
613     if (ttl != range->ttl)
614       continue;
615
616     break;
617   }
618
619   return walk;
620 }
621
622 /**
623  * gst_rtsp_address_pool_reserve_address:
624  * @pool: a #GstRTSPAddressPool
625  * @ip_address: The IP address to reserve
626  * @port: The first port to reserve
627  * @n_ports: The number of ports
628  * @ttl: The requested ttl
629  * @address: (out): storage for a #GstRTSPAddress
630  *
631  * Take a specific address and ports from @pool. @n_ports consecutive
632  * ports will be allocated of which the first one can be found in
633  * @port.
634  *
635  * If @ttl is 0, @address should be a unicast address. If @ttl > 0, @address
636  * should be a valid multicast address.
637  *
638  * Returns: #GST_RTSP_ADDRESS_POOL_OK if an address was reserved. The address
639  * is returned in @address and should be freed with gst_rtsp_address_free
640  * after use.
641  */
642 GstRTSPAddressPoolResult
643 gst_rtsp_address_pool_reserve_address (GstRTSPAddressPool * pool,
644     const gchar * ip_address, guint port, guint n_ports, guint ttl,
645     GstRTSPAddress ** address)
646 {
647   GstRTSPAddressPoolPrivate *priv;
648   Addr input_addr;
649   GList *list;
650   AddrRange *addr_range;
651   GstRTSPAddress *addr;
652   gboolean is_multicast;
653   GstRTSPAddressPoolResult result;
654
655   g_return_val_if_fail (GST_IS_RTSP_ADDRESS_POOL (pool),
656       GST_RTSP_ADDRESS_POOL_EINVAL);
657   g_return_val_if_fail (ip_address != NULL, GST_RTSP_ADDRESS_POOL_EINVAL);
658   g_return_val_if_fail (port > 0, GST_RTSP_ADDRESS_POOL_EINVAL);
659   g_return_val_if_fail (n_ports > 0, GST_RTSP_ADDRESS_POOL_EINVAL);
660   g_return_val_if_fail (address != NULL, GST_RTSP_ADDRESS_POOL_EINVAL);
661
662   priv = pool->priv;
663   addr_range = NULL;
664   addr = NULL;
665   is_multicast = ttl != 0;
666
667   if (!fill_address (ip_address, port, &input_addr, is_multicast))
668     goto invalid;
669
670   g_mutex_lock (&priv->lock);
671   list = find_address_in_ranges (priv->addresses, &input_addr, port, n_ports,
672       ttl);
673   if (list != NULL) {
674     AddrRange *range = list->data;
675     guint skip_port, skip_addr;
676
677     skip_addr = diff_address (&input_addr, &range->min);
678     skip_port = port - range->min.port;
679
680     GST_DEBUG_OBJECT (pool, "diff 0x%08x/%u", skip_addr, skip_port);
681
682     /* we found a range, remove from the list */
683     priv->addresses = g_list_delete_link (priv->addresses, list);
684     /* now split and exit our loop */
685     addr_range = split_range (pool, range, skip_addr, skip_port, n_ports);
686     priv->allocated = g_list_prepend (priv->allocated, addr_range);
687   }
688
689   if (addr_range) {
690     addr = g_slice_new0 (GstRTSPAddress);
691     addr->pool = g_object_ref (pool);
692     addr->address = get_address_string (&addr_range->min);
693     addr->n_ports = n_ports;
694     addr->port = addr_range->min.port;
695     addr->ttl = addr_range->ttl;
696     addr->priv = addr_range;
697
698     result = GST_RTSP_ADDRESS_POOL_OK;
699     GST_DEBUG_OBJECT (pool, "reserved address %s:%u ttl %u", addr->address,
700         addr->port, addr->ttl);
701   } else {
702     /* We failed to reserve the address. Check if it was because the address
703      * was already in use or if it wasn't in the pool to begin with */
704     list = find_address_in_ranges (priv->allocated, &input_addr, port, n_ports,
705         ttl);
706     if (list != NULL) {
707       result = GST_RTSP_ADDRESS_POOL_ERESERVED;
708     } else {
709       result = GST_RTSP_ADDRESS_POOL_ERANGE;
710     }
711   }
712   g_mutex_unlock (&priv->lock);
713
714   *address = addr;
715   return result;
716
717   /* ERRORS */
718 invalid:
719   {
720     GST_ERROR_OBJECT (pool, "invalid address %s:%u/%u/%u", ip_address,
721         port, n_ports, ttl);
722     *address = NULL;
723     return GST_RTSP_ADDRESS_POOL_EINVAL;
724   }
725 }
726
727 /**
728  * gst_rtsp_address_pool_has_unicast_addresses:
729  * @pool: a #GstRTSPAddressPool
730  *
731  * Used to know if the pool includes any unicast addresses.
732  *
733  * Returns: %TRUE if the pool includes any unicast addresses, %FALSE otherwise
734  */
735
736 gboolean
737 gst_rtsp_address_pool_has_unicast_addresses (GstRTSPAddressPool * pool)
738 {
739   GstRTSPAddressPoolPrivate *priv;
740   gboolean has_unicast_addresses;
741
742   g_return_val_if_fail (GST_IS_RTSP_ADDRESS_POOL (pool), FALSE);
743
744   priv = pool->priv;
745
746   g_mutex_lock (&priv->lock);
747   has_unicast_addresses = priv->has_unicast_addresses;
748   g_mutex_unlock (&priv->lock);
749
750   return has_unicast_addresses;
751 }