udpsrc: Bind to multicast addresses on non-Windows systems

On Windows it's not possible to bind to a multicast address
but the OS will make sure to filter out all packets that
arrive not for the multicast address the socket joined.

On Linux and others it is necessary to bind to a multicast
address to let the OS filter out all packets that are received
on the same port but for different addresses than the multicast
address

And deprecate the multicast-group property and replace it with the
address property.

https://bugzilla.gnome.org/show_bug.cgi?id=707042
This commit is contained in:
Sebastian Dröge 2013-09-03 11:23:24 +02:00
parent 73751dbbe7
commit 7f59436979
2 changed files with 39 additions and 32 deletions

View File

@ -173,7 +173,7 @@ enum
PROP_USED_SOCKET, PROP_USED_SOCKET,
PROP_AUTO_MULTICAST, PROP_AUTO_MULTICAST,
PROP_REUSE, PROP_REUSE,
PROP_BIND_ADDRESS, PROP_ADDRESS,
PROP_LAST PROP_LAST
}; };
@ -226,9 +226,11 @@ gst_udpsrc_class_init (GstUDPSrcClass * klass)
g_param_spec_int ("port", "Port", g_param_spec_int ("port", "Port",
"The port to receive the packets from, 0=allocate", 0, G_MAXUINT16, "The port to receive the packets from, 0=allocate", 0, G_MAXUINT16,
UDP_DEFAULT_PORT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); UDP_DEFAULT_PORT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
/* FIXME 2.0: Remove multicast-group property */
g_object_class_install_property (gobject_class, PROP_MULTICAST_GROUP, g_object_class_install_property (gobject_class, PROP_MULTICAST_GROUP,
g_param_spec_string ("multicast-group", "Multicast Group", g_param_spec_string ("multicast-group", "Multicast Group",
"The Address of multicast group to join", UDP_DEFAULT_MULTICAST_GROUP, "The Address of multicast group to join. DEPRECATED: "
"Use address property instead", UDP_DEFAULT_MULTICAST_GROUP,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_MULTICAST_IFACE, g_object_class_install_property (gobject_class, PROP_MULTICAST_IFACE,
g_param_spec_string ("multicast-iface", "Multicast Interface", g_param_spec_string ("multicast-iface", "Multicast Interface",
@ -278,16 +280,10 @@ gst_udpsrc_class_init (GstUDPSrcClass * klass)
g_object_class_install_property (gobject_class, PROP_REUSE, g_object_class_install_property (gobject_class, PROP_REUSE,
g_param_spec_boolean ("reuse", "Reuse", "Enable reuse of the port", g_param_spec_boolean ("reuse", "Reuse", "Enable reuse of the port",
UDP_DEFAULT_REUSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); UDP_DEFAULT_REUSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_ADDRESS,
/* FIXME 2.0: multicast-group and bind-address should g_param_spec_string ("address", "Address",
* be separated, the former only being the multicast group and "Address to receive packets for. This is equivalent to the "
* the latter always being the address the socket is bound too, "multicast-group property for now", UDP_DEFAULT_MULTICAST_GROUP,
* even if a multicast group is given.
*/
g_object_class_install_property (gobject_class, PROP_BIND_ADDRESS,
g_param_spec_string ("bind-address", "Bind Address",
"Address to bind the socket to. This is equivalent to the "
"multicast-group property", UDP_DEFAULT_MULTICAST_GROUP,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
gst_element_class_add_pad_template (gstelement_class, gst_element_class_add_pad_template (gstelement_class,
@ -315,7 +311,7 @@ gst_udpsrc_init (GstUDPSrc * udpsrc)
g_strdup_printf ("udp://%s:%u", UDP_DEFAULT_MULTICAST_GROUP, g_strdup_printf ("udp://%s:%u", UDP_DEFAULT_MULTICAST_GROUP,
UDP_DEFAULT_PORT); UDP_DEFAULT_PORT);
udpsrc->multi_group = g_strdup (UDP_DEFAULT_MULTICAST_GROUP); udpsrc->address = g_strdup (UDP_DEFAULT_MULTICAST_GROUP);
udpsrc->port = UDP_DEFAULT_PORT; udpsrc->port = UDP_DEFAULT_PORT;
udpsrc->socket = UDP_DEFAULT_SOCKET; udpsrc->socket = UDP_DEFAULT_SOCKET;
udpsrc->multi_iface = g_strdup (UDP_DEFAULT_MULTICAST_IFACE); udpsrc->multi_iface = g_strdup (UDP_DEFAULT_MULTICAST_IFACE);
@ -356,8 +352,8 @@ gst_udpsrc_finalize (GObject * object)
g_free (udpsrc->uri); g_free (udpsrc->uri);
udpsrc->uri = NULL; udpsrc->uri = NULL;
g_free (udpsrc->multi_group); g_free (udpsrc->address);
udpsrc->multi_group = NULL; udpsrc->address = NULL;
if (udpsrc->socket) if (udpsrc->socket)
g_object_unref (udpsrc->socket); g_object_unref (udpsrc->socket);
@ -587,17 +583,17 @@ skip_error:
static gboolean static gboolean
gst_udpsrc_set_uri (GstUDPSrc * src, const gchar * uri, GError ** error) gst_udpsrc_set_uri (GstUDPSrc * src, const gchar * uri, GError ** error)
{ {
gchar *multi_group; gchar *address;
guint16 port; guint16 port;
if (!gst_udp_parse_uri (uri, &multi_group, &port)) if (!gst_udp_parse_uri (uri, &address, &port))
goto wrong_uri; goto wrong_uri;
if (port == (guint16) - 1) if (port == (guint16) - 1)
port = UDP_DEFAULT_PORT; port = UDP_DEFAULT_PORT;
g_free (src->multi_group); g_free (src->address);
src->multi_group = multi_group; src->address = address;
src->port = port; src->port = port;
g_free (src->uri); g_free (src->uri);
@ -630,22 +626,22 @@ gst_udpsrc_set_property (GObject * object, guint prop_id, const GValue * value,
udpsrc->port = g_value_get_int (value); udpsrc->port = g_value_get_int (value);
g_free (udpsrc->uri); g_free (udpsrc->uri);
udpsrc->uri = udpsrc->uri =
g_strdup_printf ("udp://%s:%u", udpsrc->multi_group, udpsrc->port); g_strdup_printf ("udp://%s:%u", udpsrc->address, udpsrc->port);
break; break;
case PROP_MULTICAST_GROUP: case PROP_MULTICAST_GROUP:
case PROP_BIND_ADDRESS: case PROP_ADDRESS:
{ {
const gchar *group; const gchar *group;
g_free (udpsrc->multi_group); g_free (udpsrc->address);
if ((group = g_value_get_string (value))) if ((group = g_value_get_string (value)))
udpsrc->multi_group = g_strdup (group); udpsrc->address = g_strdup (group);
else else
udpsrc->multi_group = g_strdup (UDP_DEFAULT_MULTICAST_GROUP); udpsrc->address = g_strdup (UDP_DEFAULT_MULTICAST_GROUP);
g_free (udpsrc->uri); g_free (udpsrc->uri);
udpsrc->uri = udpsrc->uri =
g_strdup_printf ("udp://%s:%u", udpsrc->multi_group, udpsrc->port); g_strdup_printf ("udp://%s:%u", udpsrc->address, udpsrc->port);
break; break;
} }
case PROP_MULTICAST_IFACE: case PROP_MULTICAST_IFACE:
@ -730,8 +726,8 @@ gst_udpsrc_get_property (GObject * object, guint prop_id, GValue * value,
g_value_set_int (value, udpsrc->port); g_value_set_int (value, udpsrc->port);
break; break;
case PROP_MULTICAST_GROUP: case PROP_MULTICAST_GROUP:
case PROP_BIND_ADDRESS: case PROP_ADDRESS:
g_value_set_string (value, udpsrc->multi_group); g_value_set_string (value, udpsrc->address);
break; break;
case PROP_MULTICAST_IFACE: case PROP_MULTICAST_IFACE:
g_value_set_string (value, udpsrc->multi_iface); g_value_set_string (value, udpsrc->multi_iface);
@ -824,10 +820,10 @@ gst_udpsrc_start (GstBaseSrc * bsrc)
if (src->socket == NULL) { if (src->socket == NULL) {
/* need to allocate a socket */ /* need to allocate a socket */
GST_DEBUG_OBJECT (src, "allocating socket for %s:%d", src->multi_group, GST_DEBUG_OBJECT (src, "allocating socket for %s:%d", src->address,
src->port); src->port);
addr = gst_udpsrc_resolve (src, src->multi_group); addr = gst_udpsrc_resolve (src, src->address);
if (!addr) if (!addr)
goto name_resolve; goto name_resolve;
@ -847,9 +843,20 @@ gst_udpsrc_start (GstBaseSrc * bsrc)
GST_DEBUG_OBJECT (src, "binding on port %d", src->port); GST_DEBUG_OBJECT (src, "binding on port %d", src->port);
/* On Windows it's not possible to bind to a multicast address
* but the OS will make sure to filter out all packets that
* arrive not for the multicast address the socket joined.
*
* On Linux and others it is necessary to bind to a multicast
* address to let the OS filter out all packets that are received
* on the same port but for different addresses than the multicast
* address
*/
#if G_OS_WIN32
if (g_inet_address_get_is_multicast (addr)) if (g_inet_address_get_is_multicast (addr))
bind_addr = g_inet_address_new_any (g_inet_address_get_family (addr)); bind_addr = g_inet_address_new_any (g_inet_address_get_family (addr));
else else
#endif
bind_addr = G_INET_ADDRESS (g_object_ref (addr)); bind_addr = G_INET_ADDRESS (g_object_ref (addr));
g_object_unref (addr); g_object_unref (addr);
@ -955,7 +962,7 @@ gst_udpsrc_start (GstBaseSrc * bsrc)
&& &&
g_inet_address_get_is_multicast (g_inet_socket_address_get_address g_inet_address_get_is_multicast (g_inet_socket_address_get_address
(src->addr))) { (src->addr))) {
GST_DEBUG_OBJECT (src, "joining multicast group %s", src->multi_group); GST_DEBUG_OBJECT (src, "joining multicast group %s", src->address);
if (!g_socket_join_multicast_group (src->used_socket, if (!g_socket_join_multicast_group (src->used_socket,
g_inet_socket_address_get_address (src->addr), g_inet_socket_address_get_address (src->addr),
FALSE, src->multi_iface, &err)) FALSE, src->multi_iface, &err))
@ -1068,7 +1075,7 @@ gst_udpsrc_stop (GstBaseSrc * bsrc)
(src->addr))) { (src->addr))) {
GError *err = NULL; GError *err = NULL;
GST_DEBUG_OBJECT (src, "leaving multicast group %s", src->multi_group); GST_DEBUG_OBJECT (src, "leaving multicast group %s", src->address);
if (!g_socket_leave_multicast_group (src->used_socket, if (!g_socket_leave_multicast_group (src->used_socket,
g_inet_socket_address_get_address (src->addr), FALSE, g_inet_socket_address_get_address (src->addr), FALSE,

View File

@ -48,7 +48,7 @@ struct _GstUDPSrc {
GstPushSrc parent; GstPushSrc parent;
/* properties */ /* properties */
gchar *multi_group; gchar *address;
gint port; gint port;
gchar *multi_iface; gchar *multi_iface;
gint ttl; gint ttl;