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