summaryrefslogtreecommitdiffstats
path: root/gst/udp
diff options
context:
space:
mode:
authorJarkko Palviainen <jarkko.palviainen at sesca.com>2009-08-31 12:13:07 +0200
committerWim Taymans <wim.taymans@collabora.co.uk>2009-08-31 12:13:07 +0200
commite2518fedbe8f6eb9cf1cf456381a5e350e2c4001 (patch)
treeaf41603f10b6a07b6581378598f1e44558c1fcfa /gst/udp
parent6a53d0a2c983bfeac2f02c9ef9cd3ff155f4e4fd (diff)
udp: split out TTL and loop options
Split setting the TTL and loop parameters in 2 methods as they are not related. Fix setting the TTL correctly for multicast streams. See #588245
Diffstat (limited to 'gst/udp')
-rw-r--r--gst/udp/gstmultiudpsink.c43
-rw-r--r--gst/udp/gstudpnetutils.c69
-rw-r--r--gst/udp/gstudpnetutils.h3
3 files changed, 96 insertions, 19 deletions
diff --git a/gst/udp/gstmultiudpsink.c b/gst/udp/gstmultiudpsink.c
index a6afc9ae..6b5ca4d4 100644
--- a/gst/udp/gstmultiudpsink.c
+++ b/gst/udp/gstmultiudpsink.c
@@ -723,14 +723,26 @@ gst_multiudpsink_init_send (GstMultiUDPSink * sink)
sink->bytes_to_serve = 0;
sink->bytes_served = 0;
- gst_udp_set_loop_ttl (sink->sock, sink->loop, sink->ttl);
gst_multiudpsink_setup_qos_dscp (sink);
- /* look for multicast clients and join multicast groups appropriately */
+ /* look for multicast clients and join multicast groups appropriately
+ set also ttl and multicast loopback delivery appropriately */
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, NULL);
+ if (gst_udp_is_multicast (&client->theiraddr)) {
+ if (sink->auto_multicast) {
+ if (gst_udp_join_group (*(client->sock), &client->theiraddr, NULL)
+ != 0)
+ goto join_group_failed;
+ }
+ if (gst_udp_set_loop (sink->sock, sink->loop) != 0)
+ goto loop_failed;
+ if (gst_udp_set_ttl (sink->sock, sink->ttl, TRUE) != 0)
+ goto ttl_failed;
+ } else {
+ if (gst_udp_set_ttl (sink->sock, sink->ttl, FALSE) != 0)
+ goto ttl_failed;
+ }
}
return TRUE;
@@ -749,6 +761,29 @@ no_broadcast:
g_strerror (errno)));
return FALSE;
}
+join_group_failed:
+ {
+ CLOSE_IF_REQUESTED (sink);
+ GST_ELEMENT_ERROR (sink, RESOURCE, SETTINGS, (NULL),
+ ("Could not join multicast group (%d): %s", errno, g_strerror (errno)));
+ return FALSE;
+ }
+ttl_failed:
+ {
+ CLOSE_IF_REQUESTED (sink);
+ GST_ELEMENT_ERROR (sink, RESOURCE, SETTINGS, (NULL),
+ ("Could not set TTL socket option (%d): %s", errno,
+ g_strerror (errno)));
+ return FALSE;
+ }
+loop_failed:
+ {
+ CLOSE_IF_REQUESTED (sink);
+ GST_ELEMENT_ERROR (sink, RESOURCE, SETTINGS, (NULL),
+ ("Could not set loopback socket option (%d): %s", errno,
+ g_strerror (errno)));
+ return FALSE;
+ }
}
static void
diff --git a/gst/udp/gstudpnetutils.c b/gst/udp/gstudpnetutils.c
index 2ed65e68..322351a8 100644
--- a/gst/udp/gstudpnetutils.c
+++ b/gst/udp/gstudpnetutils.c
@@ -113,7 +113,7 @@ beach:
}
int
-gst_udp_set_loop_ttl (int sockfd, gboolean loop, int ttl)
+gst_udp_set_loop (int sockfd, gboolean loop)
{
socklen_t socklen;
struct sockaddr_storage addr;
@@ -128,29 +128,70 @@ gst_udp_set_loop_ttl (int sockfd, gboolean loop, int ttl)
switch (addr.ss_family) {
case AF_INET:
{
- if ((ret =
- setsockopt (sockfd, IPPROTO_IP, IP_MULTICAST_LOOP, &l,
- sizeof (l))) < 0)
+ ret = setsockopt (sockfd, IPPROTO_IP, IP_MULTICAST_LOOP, &l, sizeof (l));
+ if (ret < 0)
return ret;
- if ((ret =
- setsockopt (sockfd, IPPROTO_IP, IP_MULTICAST_TTL, &ttl,
- sizeof (ttl))) < 0)
- return ret;
break;
}
case AF_INET6:
{
- if ((ret =
- setsockopt (sockfd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &l,
- sizeof (l))) < 0)
+ ret =
+ setsockopt (sockfd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &l,
+ sizeof (l));
+ if (ret < 0)
return ret;
- if ((ret =
- setsockopt (sockfd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &ttl,
- sizeof (ttl))) < 0)
+ break;
+ }
+ default:
+#ifdef G_OS_WIN32
+ WSASetLastError (WSAEAFNOSUPPORT);
+#else
+ errno = EAFNOSUPPORT;
+#endif
+ }
+
+ return ret;
+}
+
+int
+gst_udp_set_ttl (int sockfd, int ttl, gboolean is_multicast)
+{
+ socklen_t socklen;
+ struct sockaddr_storage addr;
+ int optname = -1;
+ int ret = -1;
+
+ socklen = sizeof (addr);
+ if ((ret = getsockname (sockfd, (struct sockaddr *) &addr, &socklen)) < 0) {
+ return ret;
+ }
+
+ switch (addr.ss_family) {
+ case AF_INET:
+ {
+ optname = (is_multicast == TRUE) ? IP_MULTICAST_TTL : IP_TTL;
+ ret = setsockopt (sockfd, IPPROTO_IP, optname, &ttl, sizeof (ttl));
+ if (ret < 0)
+ return ret;
+ break;
+ }
+ case AF_INET6:
+ {
+ optname =
+ (is_multicast == TRUE) ? IPV6_MULTICAST_HOPS : IPV6_UNICAST_HOPS;
+ ret = setsockopt (sockfd, IPPROTO_IPV6, optname, &ttl, sizeof (ttl));
+ if (ret < 0)
return ret;
+ /* When using IPV4 address with IPV6 socket, both TTL values
+ must be set in order to actually use the given value.
+ Has no effect when IPV6 address is used. */
+ optname = (is_multicast == TRUE) ? IP_MULTICAST_TTL : IP_TTL;
+ ret = setsockopt (sockfd, IPPROTO_IP, optname, &ttl, sizeof (ttl));
+ if (ret < 0)
+ return ret;
break;
}
default:
diff --git a/gst/udp/gstudpnetutils.h b/gst/udp/gstudpnetutils.h
index b8f49a73..faaece90 100644
--- a/gst/udp/gstudpnetutils.h
+++ b/gst/udp/gstudpnetutils.h
@@ -80,7 +80,8 @@ int gst_udp_get_sockaddr_length(struct sockaddr_storage *addr);
int gst_udp_get_addr (const char *hostname, int port, struct sockaddr_storage *addr);
int gst_udp_is_multicast (struct sockaddr_storage *addr);
-int gst_udp_set_loop_ttl (int sockfd, gboolean loop, int ttl);
+int gst_udp_set_loop (int sockfd, gboolean loop);
+int gst_udp_set_ttl (int sockfd, int ttl, gboolean is_multicast);
int gst_udp_join_group (int sockfd, struct sockaddr_storage *addr,
gchar *iface);