udpsrc: Add network interface selection

Add network interface selection when joining multicast groups.
Useful when using the udpsrc on multihomed hosts.
Fixes #575234.

API: GstUDPSrc::multicast-iface
This commit is contained in:
Edgar E. Iglesias 2009-03-13 18:28:59 +01:00 committed by Wim Taymans
parent a32581abee
commit 469aced581
5 changed files with 43 additions and 5 deletions

View file

@ -635,7 +635,7 @@ gst_multiudpsink_init_send (GstMultiUDPSink * sink)
for (clients = sink->clients; clients; clients = g_list_next (clients)) {
client = (GstUDPClient *) clients->data;
if (sink->auto_multicast && gst_udp_is_multicast (&client->theiraddr))
gst_udp_join_group (*(client->sock), &client->theiraddr);
gst_udp_join_group (*(client->sock), &client->theiraddr, NULL);
}
return TRUE;
@ -687,7 +687,7 @@ gst_multiudpsink_add_internal (GstMultiUDPSink * sink, const gchar * host,
GST_DEBUG_OBJECT (sink, "multicast address detected");
if (sink->auto_multicast) {
GST_DEBUG_OBJECT (sink, "joining multicast group");
gst_udp_join_group (*(client->sock), &client->theiraddr);
gst_udp_join_group (*(client->sock), &client->theiraddr, NULL);
}
} else {
GST_DEBUG_OBJECT (sink, "normal address detected");

View file

@ -163,19 +163,31 @@ gst_udp_set_loop_ttl (int sockfd, gboolean loop, int ttl)
return ret;
}
/* FIXME: Add interface selection for windows hosts. */
int
gst_udp_join_group (int sockfd, struct sockaddr_storage *addr)
gst_udp_join_group (int sockfd, struct sockaddr_storage *addr, gchar * iface)
{
int ret = -1;
switch (addr->ss_family) {
case AF_INET:
{
#ifdef G_OS_WIN32
struct ip_mreq mreq4;
#else
struct ip_mreqn mreq4;
#endif
mreq4.imr_multiaddr.s_addr =
((struct sockaddr_in *) addr)->sin_addr.s_addr;
#ifdef G_OS_WIN32
mreq4.imr_interface.s_addr = INADDR_ANY;
#else
if (iface)
mreq4.imr_ifindex = if_nametoindex (iface);
else
mreq4.imr_ifindex = 0; /* Pick any. */
#endif
if ((ret =
setsockopt (sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
@ -192,6 +204,10 @@ gst_udp_join_group (int sockfd, struct sockaddr_storage *addr)
&(((struct sockaddr_in6 *) addr)->sin6_addr),
sizeof (struct in6_addr));
mreq6.ipv6mr_interface = 0;
#if !defined(G_OS_WIN32)
if (iface)
mreq6.ipv6mr_interface = if_nametoindex (iface);
#endif
if ((ret =
setsockopt (sockfd, IPPROTO_IPV6, IPV6_JOIN_GROUP,

View file

@ -40,6 +40,7 @@
#else
#include <sys/time.h>
#include <netinet/in.h>
#include <net/if.h>
#include <netdb.h>
#include <sys/socket.h>
#include <sys/wait.h>
@ -81,7 +82,8 @@ int gst_udp_is_multicast (struct sockaddr_storage *addr);
int gst_udp_set_loop_ttl (int sockfd, gboolean loop, int ttl);
int gst_udp_join_group (int sockfd, struct sockaddr_storage *addr);
int gst_udp_join_group (int sockfd, struct sockaddr_storage *addr,
gchar *iface);
int gst_udp_leave_group (int sockfd, struct sockaddr_storage *addr);
#endif /* __GST_UDP_NET_UTILS_H__*/

View file

@ -142,6 +142,7 @@ GST_ELEMENT_DETAILS ("UDP packet receiver",
#define UDP_DEFAULT_PORT 4951
#define UDP_DEFAULT_MULTICAST_GROUP "0.0.0.0"
#define UDP_DEFAULT_MULTICAST_IFACE NULL
#define UDP_DEFAULT_URI "udp://"UDP_DEFAULT_MULTICAST_GROUP":"G_STRINGIFY(UDP_DEFAULT_PORT)
#define UDP_DEFAULT_CAPS NULL
#define UDP_DEFAULT_SOCKFD -1
@ -158,6 +159,7 @@ enum
PROP_PORT,
PROP_MULTICAST_GROUP,
PROP_MULTICAST_IFACE,
PROP_URI,
PROP_CAPS,
PROP_SOCKFD,
@ -253,6 +255,10 @@ gst_udpsrc_class_init (GstUDPSrcClass * klass)
g_param_spec_string ("multicast_group", "Multicast Group",
"The Address of multicast group to join", UDP_DEFAULT_MULTICAST_GROUP,
G_PARAM_READWRITE));
g_object_class_install_property (gobject_class, PROP_MULTICAST_IFACE,
g_param_spec_string ("multicast_iface", "Multicast Interface",
"The network interface on which to join the multicast group",
UDP_DEFAULT_MULTICAST_IFACE, G_PARAM_READWRITE));
g_object_class_install_property (gobject_class, PROP_URI,
g_param_spec_string ("uri", "URI",
"URI in the form of udp://multicast_group:port", UDP_DEFAULT_URI,
@ -306,6 +312,7 @@ gst_udpsrc_init (GstUDPSrc * udpsrc, GstUDPSrcClass * g_class)
udpsrc->port = UDP_DEFAULT_PORT;
udpsrc->sockfd = UDP_DEFAULT_SOCKFD;
udpsrc->multi_group = g_strdup (UDP_DEFAULT_MULTICAST_GROUP);
udpsrc->multi_iface = g_strdup (UDP_DEFAULT_MULTICAST_IFACE);
udpsrc->uri = g_strdup (UDP_DEFAULT_URI);
udpsrc->buffer_size = UDP_DEFAULT_BUFFER_SIZE;
udpsrc->timeout = UDP_DEFAULT_TIMEOUT;
@ -334,6 +341,7 @@ gst_udpsrc_finalize (GObject * object)
if (udpsrc->caps)
gst_caps_unref (udpsrc->caps);
g_free (udpsrc->multi_group);
g_free (udpsrc->multi_iface);
g_free (udpsrc->uri);
if (udpsrc->sockfd >= 0 && udpsrc->closefd)
@ -667,6 +675,14 @@ gst_udpsrc_set_property (GObject * object, guint prop_id, const GValue * value,
udpsrc->multi_group = g_value_dup_string (value);
gst_udpsrc_update_uri (udpsrc);
break;
case PROP_MULTICAST_IFACE:
g_free (udpsrc->multi_iface);
if (g_value_get_string (value) == NULL)
udpsrc->multi_iface = g_strdup (UDP_DEFAULT_MULTICAST_IFACE);
else
udpsrc->multi_iface = g_value_dup_string (value);
break;
case PROP_URI:
gst_udpsrc_set_uri (udpsrc, g_value_get_string (value));
break;
@ -731,6 +747,9 @@ gst_udpsrc_get_property (GObject * object, guint prop_id, GValue * value,
case PROP_MULTICAST_GROUP:
g_value_set_string (value, udpsrc->multi_group);
break;
case PROP_MULTICAST_IFACE:
g_value_set_string (value, udpsrc->multi_iface);
break;
case PROP_URI:
g_value_set_string (value, udpsrc->uri);
break;
@ -871,7 +890,7 @@ gst_udpsrc_start (GstBaseSrc * bsrc)
if (src->auto_multicast && gst_udp_is_multicast (&src->myaddr)) {
GST_DEBUG_OBJECT (src, "joining multicast group %s", src->multi_group);
ret = gst_udp_join_group (src->sock.fd, &src->myaddr);
ret = gst_udp_join_group (src->sock.fd, &src->myaddr, src->multi_iface);
if (ret < 0)
goto membership;
}

View file

@ -56,6 +56,7 @@ struct _GstUDPSrc {
gchar *uri;
int port;
gchar *multi_group;
gchar *multi_iface;
gint ttl;
GstCaps *caps;
gint buffer_size;