mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-02-17 11:45:25 +00:00
gst/udp/gstudpnetutils.*: Provide a bunch of helper methods to deal with IPv4 and IPv6 transparently.
Original commit message from CVS: Patch by: Bruno Santos <brunof at ua dot pt> * gst/udp/gstudpnetutils.c: (gst_udp_get_addr), (gst_udp_join_group), (gst_udp_leave_group), (gst_udp_is_multicast): * gst/udp/gstudpnetutils.h: Provide a bunch of helper methods to deal with IPv4 and IPv6 transparently. * gst/udp/gstmultiudpsink.c: (gst_multiudpsink_class_init), (gst_multiudpsink_init), (gst_multiudpsink_set_property), (gst_multiudpsink_get_property), (join_multicast), (gst_multiudpsink_init_send), (gst_multiudpsink_add_internal), (gst_multiudpsink_remove): * gst/udp/gstmultiudpsink.h: Add multicast TTL and loopback properties. Use the helper methods to implement ip4 and ip6. * gst/udp/gstudpsrc.c: (gst_udpsrc_create), (gst_udpsrc_start): * gst/udp/gstudpsrc.h: Use the helper methods to implement ip4 and ip6. Fixes #515962.
This commit is contained in:
parent
94fb1d9870
commit
570718c2fe
7 changed files with 301 additions and 105 deletions
25
ChangeLog
25
ChangeLog
|
@ -1,3 +1,28 @@
|
||||||
|
2008-05-21 Wim Taymans <wim.taymans@collabora.co.uk>
|
||||||
|
|
||||||
|
Patch by: Bruno Santos <brunof at ua dot pt>
|
||||||
|
|
||||||
|
* gst/udp/gstudpnetutils.c: (gst_udp_get_addr),
|
||||||
|
(gst_udp_join_group), (gst_udp_leave_group),
|
||||||
|
(gst_udp_is_multicast):
|
||||||
|
* gst/udp/gstudpnetutils.h:
|
||||||
|
Provide a bunch of helper methods to deal with IPv4 and IPv6
|
||||||
|
transparently.
|
||||||
|
|
||||||
|
* gst/udp/gstmultiudpsink.c: (gst_multiudpsink_class_init),
|
||||||
|
(gst_multiudpsink_init), (gst_multiudpsink_set_property),
|
||||||
|
(gst_multiudpsink_get_property), (join_multicast),
|
||||||
|
(gst_multiudpsink_init_send), (gst_multiudpsink_add_internal),
|
||||||
|
(gst_multiudpsink_remove):
|
||||||
|
* gst/udp/gstmultiudpsink.h:
|
||||||
|
Add multicast TTL and loopback properties.
|
||||||
|
Use the helper methods to implement ip4 and ip6.
|
||||||
|
|
||||||
|
* gst/udp/gstudpsrc.c: (gst_udpsrc_create), (gst_udpsrc_start):
|
||||||
|
* gst/udp/gstudpsrc.h:
|
||||||
|
Use the helper methods to implement ip4 and ip6.
|
||||||
|
Fixes #515962.
|
||||||
|
|
||||||
2008-05-21 Wim Taymans <wim.taymans@collabora.co.uk>
|
2008-05-21 Wim Taymans <wim.taymans@collabora.co.uk>
|
||||||
|
|
||||||
Patch by: Patrick Radizi <patrick dot radizi at axis dot com>
|
Patch by: Patrick Radizi <patrick dot radizi at axis dot com>
|
||||||
|
|
|
@ -81,6 +81,8 @@ enum
|
||||||
#define DEFAULT_SOCK -1
|
#define DEFAULT_SOCK -1
|
||||||
#define DEFAULT_CLIENTS NULL
|
#define DEFAULT_CLIENTS NULL
|
||||||
#define DEFAULT_AUTO_MULTICAST TRUE
|
#define DEFAULT_AUTO_MULTICAST TRUE
|
||||||
|
#define DEFAULT_TTL 64
|
||||||
|
#define DEFAULT_LOOP TRUE
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
|
@ -91,7 +93,9 @@ enum
|
||||||
PROP_CLOSEFD,
|
PROP_CLOSEFD,
|
||||||
PROP_SOCK,
|
PROP_SOCK,
|
||||||
PROP_CLIENTS,
|
PROP_CLIENTS,
|
||||||
PROP_AUTO_MULTICAST
|
PROP_AUTO_MULTICAST,
|
||||||
|
PROP_TTL,
|
||||||
|
PROP_LOOP
|
||||||
/* FILL ME */
|
/* FILL ME */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -292,6 +296,14 @@ gst_multiudpsink_class_init (GstMultiUDPSinkClass * klass)
|
||||||
"Automatically join/leave multicast groups",
|
"Automatically join/leave multicast groups",
|
||||||
"Automatically join/leave the multicast groups, FALSE means user"
|
"Automatically join/leave the multicast groups, FALSE means user"
|
||||||
" has to do it himself", DEFAULT_AUTO_MULTICAST, G_PARAM_READWRITE));
|
" has to do it himself", DEFAULT_AUTO_MULTICAST, G_PARAM_READWRITE));
|
||||||
|
g_object_class_install_property (gobject_class, PROP_TTL,
|
||||||
|
g_param_spec_int ("ttl", "Multicast TTL",
|
||||||
|
"Used for setting the multicast TTL parameter",
|
||||||
|
0, 255, DEFAULT_TTL, G_PARAM_READWRITE));
|
||||||
|
g_object_class_install_property (gobject_class, PROP_LOOP,
|
||||||
|
g_param_spec_boolean ("loop", "Multicast Loopback",
|
||||||
|
"Used for setting the multicast loop parameter. TRUE = enable,"
|
||||||
|
" FALSE = disable", DEFAULT_LOOP, G_PARAM_READWRITE));
|
||||||
|
|
||||||
gstelement_class->change_state = gst_multiudpsink_change_state;
|
gstelement_class->change_state = gst_multiudpsink_change_state;
|
||||||
|
|
||||||
|
@ -316,6 +328,8 @@ gst_multiudpsink_init (GstMultiUDPSink * sink)
|
||||||
sink->closefd = DEFAULT_CLOSEFD;
|
sink->closefd = DEFAULT_CLOSEFD;
|
||||||
sink->externalfd = (sink->sockfd != -1);
|
sink->externalfd = (sink->sockfd != -1);
|
||||||
sink->auto_multicast = DEFAULT_AUTO_MULTICAST;
|
sink->auto_multicast = DEFAULT_AUTO_MULTICAST;
|
||||||
|
sink->ttl = DEFAULT_TTL;
|
||||||
|
sink->loop = DEFAULT_LOOP;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -473,6 +487,12 @@ gst_multiudpsink_set_property (GObject * object, guint prop_id,
|
||||||
case PROP_AUTO_MULTICAST:
|
case PROP_AUTO_MULTICAST:
|
||||||
udpsink->auto_multicast = g_value_get_boolean (value);
|
udpsink->auto_multicast = g_value_get_boolean (value);
|
||||||
break;
|
break;
|
||||||
|
case PROP_TTL:
|
||||||
|
udpsink->ttl = g_value_get_int (value);
|
||||||
|
break;
|
||||||
|
case PROP_LOOP:
|
||||||
|
udpsink->loop = g_value_get_boolean (value);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||||
break;
|
break;
|
||||||
|
@ -510,6 +530,12 @@ gst_multiudpsink_get_property (GObject * object, guint prop_id, GValue * value,
|
||||||
case PROP_AUTO_MULTICAST:
|
case PROP_AUTO_MULTICAST:
|
||||||
g_value_set_boolean (value, udpsink->auto_multicast);
|
g_value_set_boolean (value, udpsink->auto_multicast);
|
||||||
break;
|
break;
|
||||||
|
case PROP_TTL:
|
||||||
|
g_value_set_int (value, udpsink->ttl);
|
||||||
|
break;
|
||||||
|
case PROP_LOOP:
|
||||||
|
g_value_set_boolean (value, udpsink->loop);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||||
break;
|
break;
|
||||||
|
@ -517,33 +543,13 @@ gst_multiudpsink_get_property (GObject * object, guint prop_id, GValue * value,
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
join_multicast (GstUDPClient * client)
|
join_multicast (GstUDPClient * client, gboolean loop, int ttl)
|
||||||
{
|
{
|
||||||
unsigned char ttl = 64;
|
|
||||||
unsigned char loop = 1;
|
|
||||||
|
|
||||||
/* Joining the multicast group */
|
/* Joining the multicast group */
|
||||||
/* FIXME, can we use multicast and unicast over the same
|
/* FIXME, can we use multicast and unicast over the same
|
||||||
* socket? if not, search for socket of this multicast group or
|
* socket? if not, search for socket of this multicast group or
|
||||||
* create a new one. */
|
* create a new one. */
|
||||||
if (setsockopt (*(client->sock), IPPROTO_IP, IP_ADD_MEMBERSHIP,
|
gst_udp_join_group (*(client->sock), loop, ttl, &client->theiraddr);
|
||||||
&(client->multi_addr), sizeof (client->multi_addr)) < 0)
|
|
||||||
perror ("setsockopt IP_ADD_MEMBERSHIP\n");
|
|
||||||
if (setsockopt (*(client->sock), IPPROTO_IP, IP_MULTICAST_TTL, &ttl,
|
|
||||||
sizeof (ttl)) < 0)
|
|
||||||
perror ("setsockopt IP_MULTICAST_TTL\n");
|
|
||||||
if (setsockopt (*(client->sock), IPPROTO_IP, IP_MULTICAST_LOOP, &loop,
|
|
||||||
sizeof (loop)) < 0)
|
|
||||||
perror ("setsockopt IP_MULTICAST_LOOP\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
leave_multicast (GstUDPClient * client)
|
|
||||||
{
|
|
||||||
if (setsockopt (*(client->sock), IPPROTO_IP, IP_DROP_MEMBERSHIP,
|
|
||||||
&(client->multi_addr), sizeof (client->multi_addr)) < 0)
|
|
||||||
GST_WARNING ("setsockopt IP_DROP_MEMBERSHIP failed '%s'",
|
|
||||||
g_strerror (errno));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* create a socket for sending to remote machine */
|
/* create a socket for sending to remote machine */
|
||||||
|
@ -557,8 +563,9 @@ gst_multiudpsink_init_send (GstMultiUDPSink * sink)
|
||||||
|
|
||||||
if (sink->sockfd == -1) {
|
if (sink->sockfd == -1) {
|
||||||
/* create sender socket */
|
/* create sender socket */
|
||||||
if ((sink->sock = socket (AF_INET, SOCK_DGRAM, 0)) == -1)
|
if ((sink->sock = socket (AF_INET6, SOCK_DGRAM, 0)) == -1)
|
||||||
goto no_socket;
|
if ((sink->sock = socket (AF_INET, SOCK_DGRAM, 0)) == -1)
|
||||||
|
goto no_socket;
|
||||||
|
|
||||||
sink->externalfd = FALSE;
|
sink->externalfd = FALSE;
|
||||||
} else {
|
} else {
|
||||||
|
@ -580,8 +587,8 @@ gst_multiudpsink_init_send (GstMultiUDPSink * sink)
|
||||||
|
|
||||||
for (clients = sink->clients; clients; clients = g_list_next (clients)) {
|
for (clients = sink->clients; clients; clients = g_list_next (clients)) {
|
||||||
client = (GstUDPClient *) clients->data;
|
client = (GstUDPClient *) clients->data;
|
||||||
if (client->multi_addr.imr_multiaddr.s_addr && sink->auto_multicast)
|
if (gst_udp_is_multicast (&client->theiraddr) && sink->auto_multicast)
|
||||||
join_multicast (client);
|
join_multicast (client, sink->loop, sink->ttl);
|
||||||
}
|
}
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
||||||
|
@ -612,8 +619,6 @@ static void
|
||||||
gst_multiudpsink_add_internal (GstMultiUDPSink * sink, const gchar * host,
|
gst_multiudpsink_add_internal (GstMultiUDPSink * sink, const gchar * host,
|
||||||
gint port, gboolean lock)
|
gint port, gboolean lock)
|
||||||
{
|
{
|
||||||
struct hostent *he;
|
|
||||||
struct in_addr addr;
|
|
||||||
GstUDPClient *client;
|
GstUDPClient *client;
|
||||||
GTimeVal now;
|
GTimeVal now;
|
||||||
|
|
||||||
|
@ -623,42 +628,19 @@ gst_multiudpsink_add_internal (GstMultiUDPSink * sink, const gchar * host,
|
||||||
client->port = port;
|
client->port = port;
|
||||||
client->sock = &sink->sock;
|
client->sock = &sink->sock;
|
||||||
|
|
||||||
memset (&client->theiraddr, 0, sizeof (client->theiraddr));
|
if (gst_udp_get_addr (host, port, &client->theiraddr) < 0)
|
||||||
memset (&client->multi_addr, 0, sizeof (client->multi_addr));
|
goto getaddrinfo_error;
|
||||||
client->theiraddr.sin_family = AF_INET; /* host byte order */
|
|
||||||
client->theiraddr.sin_port = g_htons (port); /* short, network byte order */
|
|
||||||
|
|
||||||
g_get_current_time (&now);
|
g_get_current_time (&now);
|
||||||
client->connect_time = GST_TIMEVAL_TO_TIME (now);
|
client->connect_time = GST_TIMEVAL_TO_TIME (now);
|
||||||
|
|
||||||
/* if its an IP address */
|
/* check if its a multicast address */
|
||||||
if (inet_aton (host, &addr)) {
|
if (*client->sock > 0 && gst_udp_is_multicast (&client->theiraddr) &&
|
||||||
/* check if its a multicast address */
|
sink->auto_multicast) {
|
||||||
if ((g_ntohl (addr.s_addr) & 0xf0000000) == 0xe0000000) {
|
GST_DEBUG_OBJECT (sink, "multicast address detected");
|
||||||
GST_DEBUG_OBJECT (sink, "multicast address detected");
|
join_multicast (client, sink->loop, sink->ttl);
|
||||||
client->multi_addr.imr_multiaddr.s_addr = addr.s_addr;
|
|
||||||
client->multi_addr.imr_interface.s_addr = INADDR_ANY;
|
|
||||||
|
|
||||||
client->theiraddr.sin_addr = client->multi_addr.imr_multiaddr;
|
|
||||||
|
|
||||||
} else {
|
|
||||||
GST_DEBUG_OBJECT (sink, "normal address detected");
|
|
||||||
client->theiraddr.sin_addr = *((struct in_addr *) &addr);
|
|
||||||
}
|
|
||||||
/* if init_send has already been called, set sockopts for multicast */
|
|
||||||
if (*client->sock > 0 && client->multi_addr.imr_multiaddr.s_addr &&
|
|
||||||
sink->auto_multicast)
|
|
||||||
join_multicast (client);
|
|
||||||
}
|
|
||||||
/* we dont need to lookup for localhost */
|
|
||||||
else if (strcmp (host, "localhost") == 0 && inet_aton ("127.0.0.1", &addr)) {
|
|
||||||
client->theiraddr.sin_addr = *((struct in_addr *) &addr);
|
|
||||||
}
|
|
||||||
/* if its a hostname */
|
|
||||||
else if ((he = gethostbyname (host))) {
|
|
||||||
client->theiraddr.sin_addr = *((struct in_addr *) he->h_addr);
|
|
||||||
} else {
|
} else {
|
||||||
goto host_error;
|
GST_DEBUG_OBJECT (sink, "normal address detected");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lock)
|
if (lock)
|
||||||
|
@ -673,9 +655,9 @@ gst_multiudpsink_add_internal (GstMultiUDPSink * sink, const gchar * host,
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* ERRORS */
|
/* ERRORS */
|
||||||
host_error:
|
getaddrinfo_error:
|
||||||
{
|
{
|
||||||
GST_WARNING_OBJECT (sink, "hostname lookup error?");
|
GST_WARNING_OBJECT (sink, "getaddrinfo lookup error?");
|
||||||
g_free (client->host);
|
g_free (client->host);
|
||||||
g_free (client);
|
g_free (client);
|
||||||
return;
|
return;
|
||||||
|
@ -728,9 +710,9 @@ gst_multiudpsink_remove (GstMultiUDPSink * sink, const gchar * host, gint port)
|
||||||
g_get_current_time (&now);
|
g_get_current_time (&now);
|
||||||
client->disconnect_time = GST_TIMEVAL_TO_TIME (now);
|
client->disconnect_time = GST_TIMEVAL_TO_TIME (now);
|
||||||
|
|
||||||
if (*(client->sock) != -1 && client->multi_addr.imr_multiaddr.s_addr
|
if (*(client->sock) != -1 && gst_udp_is_multicast (&client->theiraddr)
|
||||||
&& sink->auto_multicast)
|
&& sink->auto_multicast)
|
||||||
leave_multicast (client);
|
gst_udp_leave_group (*(client->sock), &client->theiraddr);
|
||||||
|
|
||||||
/* Unlock to emit signal before we delete the actual client */
|
/* Unlock to emit signal before we delete the actual client */
|
||||||
g_mutex_unlock (sink->client_lock);
|
g_mutex_unlock (sink->client_lock);
|
||||||
|
|
|
@ -40,8 +40,7 @@ typedef struct _GstMultiUDPSinkClass GstMultiUDPSinkClass;
|
||||||
typedef struct {
|
typedef struct {
|
||||||
int *sock;
|
int *sock;
|
||||||
|
|
||||||
struct sockaddr_in theiraddr;
|
struct sockaddr_storage theiraddr;
|
||||||
struct ip_mreq multi_addr;
|
|
||||||
|
|
||||||
gchar *host;
|
gchar *host;
|
||||||
gint port;
|
gint port;
|
||||||
|
@ -72,6 +71,8 @@ struct _GstMultiUDPSink {
|
||||||
gboolean externalfd;
|
gboolean externalfd;
|
||||||
|
|
||||||
gboolean auto_multicast;
|
gboolean auto_multicast;
|
||||||
|
gint ttl;
|
||||||
|
gboolean loop;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct _GstMultiUDPSinkClass {
|
struct _GstMultiUDPSinkClass {
|
||||||
|
|
|
@ -22,21 +22,14 @@
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <memory.h>
|
||||||
|
|
||||||
#include "gstudpnetutils.h"
|
#include "gstudpnetutils.h"
|
||||||
|
|
||||||
#ifdef G_OS_WIN32
|
#ifdef G_OS_WIN32
|
||||||
|
|
||||||
int
|
|
||||||
gst_udp_net_utils_win32_inet_aton (const char *c, struct in_addr *paddr)
|
|
||||||
{
|
|
||||||
paddr->s_addr = inet_addr (c);
|
|
||||||
|
|
||||||
if (paddr->s_addr == INADDR_NONE)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
gboolean
|
gboolean
|
||||||
gst_udp_net_utils_win32_wsa_startup (GstObject * obj)
|
gst_udp_net_utils_win32_wsa_startup (GstObject * obj)
|
||||||
{
|
{
|
||||||
|
@ -60,3 +53,178 @@ gst_udp_net_utils_win32_wsa_startup (GstObject * obj)
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
int
|
||||||
|
gst_udp_get_addr (const char *hostname, int port, struct sockaddr_storage *addr)
|
||||||
|
{
|
||||||
|
struct addrinfo hints, *res, *nres;
|
||||||
|
char service[NI_MAXSERV];
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
memset (&hints, 0, sizeof (hints));
|
||||||
|
hints.ai_family = AF_UNSPEC;
|
||||||
|
hints.ai_socktype = SOCK_DGRAM;
|
||||||
|
snprintf (service, sizeof (service) - 1, "%d", port);
|
||||||
|
service[sizeof (service) - 1] = '\0';
|
||||||
|
|
||||||
|
if ((ret = getaddrinfo (hostname, (port == -1) ? NULL : service, &hints,
|
||||||
|
&res)) < 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
nres = res;
|
||||||
|
while (nres) {
|
||||||
|
if (nres->ai_family == AF_INET || nres->ai_family == AF_INET6)
|
||||||
|
break;
|
||||||
|
nres = nres->ai_next;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nres) {
|
||||||
|
memcpy (addr, nres->ai_addr, nres->ai_addrlen);
|
||||||
|
} else {
|
||||||
|
errno = EAI_ADDRFAMILY;
|
||||||
|
ret = -1;
|
||||||
|
}
|
||||||
|
freeaddrinfo (res);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
gst_udp_join_group (int sockfd, gboolean loop, int ttl,
|
||||||
|
struct sockaddr_storage *addr)
|
||||||
|
{
|
||||||
|
int ret = -1;
|
||||||
|
int l = (loop == FALSE) ? 0 : 1;
|
||||||
|
|
||||||
|
switch (addr->ss_family) {
|
||||||
|
case AF_INET:
|
||||||
|
{
|
||||||
|
struct ip_mreq mreq4;
|
||||||
|
|
||||||
|
mreq4.imr_multiaddr.s_addr =
|
||||||
|
((struct sockaddr_in *) addr)->sin_addr.s_addr;
|
||||||
|
mreq4.imr_interface.s_addr = INADDR_ANY;
|
||||||
|
|
||||||
|
if ((ret =
|
||||||
|
setsockopt (sockfd, IPPROTO_IP, IP_MULTICAST_LOOP, &l,
|
||||||
|
sizeof (l))) < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
if ((ret =
|
||||||
|
setsockopt (sockfd, IPPROTO_IP, IP_MULTICAST_TTL, &ttl,
|
||||||
|
sizeof (ttl))) < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
if ((ret =
|
||||||
|
setsockopt (sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
|
||||||
|
(const void *) &mreq4, sizeof (mreq4))) < 0)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case AF_INET6:
|
||||||
|
{
|
||||||
|
struct ipv6_mreq mreq6;
|
||||||
|
|
||||||
|
memcpy (&mreq6.ipv6mr_multiaddr,
|
||||||
|
&(((struct sockaddr_in6 *) addr)->sin6_addr),
|
||||||
|
sizeof (struct in6_addr));
|
||||||
|
mreq6.ipv6mr_interface = 0;
|
||||||
|
|
||||||
|
if ((ret =
|
||||||
|
setsockopt (sockfd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &l,
|
||||||
|
sizeof (l))) < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
if ((ret =
|
||||||
|
setsockopt (sockfd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &ttl,
|
||||||
|
sizeof (ttl))) < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
if ((ret =
|
||||||
|
setsockopt (sockfd, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP,
|
||||||
|
(const void *) &mreq6, sizeof (mreq6))) < 0)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
errno = EAFNOSUPPORT;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
gst_udp_leave_group (int sockfd, struct sockaddr_storage *addr)
|
||||||
|
{
|
||||||
|
int ret = -1;
|
||||||
|
|
||||||
|
switch (addr->ss_family) {
|
||||||
|
case AF_INET:
|
||||||
|
{
|
||||||
|
struct ip_mreq mreq4;
|
||||||
|
|
||||||
|
mreq4.imr_multiaddr.s_addr =
|
||||||
|
((struct sockaddr_in *) addr)->sin_addr.s_addr;
|
||||||
|
mreq4.imr_interface.s_addr = INADDR_ANY;
|
||||||
|
|
||||||
|
if ((ret =
|
||||||
|
setsockopt (sockfd, IPPROTO_IP, IP_DROP_MEMBERSHIP,
|
||||||
|
(const void *) &mreq4, sizeof (mreq4))) < 0)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case AF_INET6:
|
||||||
|
{
|
||||||
|
struct ipv6_mreq mreq6;
|
||||||
|
|
||||||
|
memcpy (&mreq6.ipv6mr_multiaddr,
|
||||||
|
&(((struct sockaddr_in6 *) addr)->sin6_addr),
|
||||||
|
sizeof (struct in6_addr));
|
||||||
|
mreq6.ipv6mr_interface = 0;
|
||||||
|
|
||||||
|
if ((ret =
|
||||||
|
setsockopt (sockfd, IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP,
|
||||||
|
(const void *) &mreq6, sizeof (mreq6))) < 0)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
errno = EAFNOSUPPORT;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
gst_udp_is_multicast (struct sockaddr_storage *addr)
|
||||||
|
{
|
||||||
|
int ret = -1;
|
||||||
|
|
||||||
|
switch (addr->ss_family) {
|
||||||
|
case AF_INET:
|
||||||
|
{
|
||||||
|
struct sockaddr_in *addr4 = (struct sockaddr_in *) addr;
|
||||||
|
|
||||||
|
ret = IN_MULTICAST (ntohl (addr4->sin_addr.s_addr));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case AF_INET6:
|
||||||
|
{
|
||||||
|
struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *) addr;
|
||||||
|
|
||||||
|
ret = IN6_IS_ADDR_MULTICAST (&addr6->sin6_addr);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
errno = EAFNOSUPPORT;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
|
@ -52,7 +52,6 @@
|
||||||
#define IOCTL_SOCKET ioctlsocket
|
#define IOCTL_SOCKET ioctlsocket
|
||||||
#define CLOSE_SOCKET(sock) closesocket(sock)
|
#define CLOSE_SOCKET(sock) closesocket(sock)
|
||||||
#define setsockopt(sock,l,opt,val,len) setsockopt(sock,l,opt,(char *)(val),len)
|
#define setsockopt(sock,l,opt,val,len) setsockopt(sock,l,opt,(char *)(val),len)
|
||||||
#define inet_aton(c,addr) gst_udp_net_utils_win32_inet_aton ((c),(addr))
|
|
||||||
#define WSA_STARTUP(obj) gst_udp_net_utils_win32_wsa_startup(GST_OBJECT(obj))
|
#define WSA_STARTUP(obj) gst_udp_net_utils_win32_wsa_startup(GST_OBJECT(obj))
|
||||||
#define WSA_CLEANUP(obj) WSACleanup ()
|
#define WSA_CLEANUP(obj) WSACleanup ()
|
||||||
|
|
||||||
|
@ -68,10 +67,15 @@
|
||||||
|
|
||||||
#ifdef G_OS_WIN32
|
#ifdef G_OS_WIN32
|
||||||
|
|
||||||
int gst_udp_net_utils_win32_inet_aton (const char *c, struct in_addr * addr);
|
|
||||||
gboolean gst_udp_net_utils_win32_wsa_startup (GstObject * obj);
|
gboolean gst_udp_net_utils_win32_wsa_startup (GstObject * obj);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
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_join_group (int sockfd, gboolean loop, int ttl, struct sockaddr_storage *addr);
|
||||||
|
int gst_udp_leave_group (int sockfd, struct sockaddr_storage *addr);
|
||||||
|
|
||||||
#endif /* __GST_UDP_NET_UTILS_H__*/
|
#endif /* __GST_UDP_NET_UTILS_H__*/
|
||||||
|
|
||||||
|
|
|
@ -349,7 +349,7 @@ gst_udpsrc_create (GstPushSrc * psrc, GstBuffer ** buf)
|
||||||
{
|
{
|
||||||
GstUDPSrc *udpsrc;
|
GstUDPSrc *udpsrc;
|
||||||
GstNetBuffer *outbuf;
|
GstNetBuffer *outbuf;
|
||||||
struct sockaddr_in tmpaddr;
|
struct sockaddr_storage tmpaddr;
|
||||||
socklen_t len;
|
socklen_t len;
|
||||||
guint8 *pktdata;
|
guint8 *pktdata;
|
||||||
gint pktsize;
|
gint pktsize;
|
||||||
|
@ -468,8 +468,28 @@ no_select:
|
||||||
GST_BUFFER_DATA (outbuf) = pktdata;
|
GST_BUFFER_DATA (outbuf) = pktdata;
|
||||||
GST_BUFFER_SIZE (outbuf) = ret;
|
GST_BUFFER_SIZE (outbuf) = ret;
|
||||||
|
|
||||||
gst_netaddress_set_ip4_address (&outbuf->from, tmpaddr.sin_addr.s_addr,
|
switch (tmpaddr.ss_family) {
|
||||||
tmpaddr.sin_port);
|
case AF_INET:
|
||||||
|
{
|
||||||
|
gst_netaddress_set_ip4_address (&outbuf->from,
|
||||||
|
((struct sockaddr_in *) &tmpaddr)->sin_addr.s_addr,
|
||||||
|
((struct sockaddr_in *) &tmpaddr)->sin_port);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case AF_INET6:
|
||||||
|
{
|
||||||
|
guint8 ip6[16];
|
||||||
|
|
||||||
|
memcpy (ip6, &((struct sockaddr_in6 *) &tmpaddr)->sin6_addr,
|
||||||
|
sizeof (ip6));
|
||||||
|
gst_netaddress_set_ip6_address (&outbuf->from, ip6,
|
||||||
|
((struct sockaddr_in *) &tmpaddr)->sin_port);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
errno = EAFNOSUPPORT;
|
||||||
|
goto receive_error;
|
||||||
|
}
|
||||||
|
|
||||||
gst_buffer_set_caps (GST_BUFFER_CAST (outbuf), udpsrc->caps);
|
gst_buffer_set_caps (GST_BUFFER_CAST (outbuf), udpsrc->caps);
|
||||||
|
|
||||||
|
@ -681,7 +701,7 @@ gst_udpsrc_start (GstBaseSrc * bsrc)
|
||||||
{
|
{
|
||||||
guint bc_val;
|
guint bc_val;
|
||||||
gint reuse;
|
gint reuse;
|
||||||
struct sockaddr_in my_addr;
|
struct sockaddr_storage my_addr;
|
||||||
guint len;
|
guint len;
|
||||||
int port;
|
int port;
|
||||||
GstUDPSrc *src;
|
GstUDPSrc *src;
|
||||||
|
@ -690,12 +710,12 @@ gst_udpsrc_start (GstBaseSrc * bsrc)
|
||||||
|
|
||||||
src = GST_UDPSRC (bsrc);
|
src = GST_UDPSRC (bsrc);
|
||||||
|
|
||||||
if (!inet_aton (src->multi_group, &(src->multi_addr.imr_multiaddr)))
|
|
||||||
src->multi_addr.imr_multiaddr.s_addr = 0;
|
|
||||||
|
|
||||||
if (src->sockfd == -1) {
|
if (src->sockfd == -1) {
|
||||||
/* need to allocate a socket */
|
/* need to allocate a socket */
|
||||||
if ((ret = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
|
if ((ret =
|
||||||
|
gst_udp_get_addr (src->multi_group, src->port, &src->myaddr)) < 0)
|
||||||
|
goto getaddrinfo_error;
|
||||||
|
if ((ret = socket (src->myaddr.ss_family, SOCK_DGRAM, IPPROTO_UDP)) < 0)
|
||||||
goto no_socket;
|
goto no_socket;
|
||||||
|
|
||||||
src->sock.fd = ret;
|
src->sock.fd = ret;
|
||||||
|
@ -707,15 +727,6 @@ gst_udpsrc_start (GstBaseSrc * bsrc)
|
||||||
sizeof (reuse))) < 0)
|
sizeof (reuse))) < 0)
|
||||||
goto setsockopt_error;
|
goto setsockopt_error;
|
||||||
|
|
||||||
memset (&src->myaddr, 0, sizeof (src->myaddr));
|
|
||||||
src->myaddr.sin_family = AF_INET; /* host byte order */
|
|
||||||
src->myaddr.sin_port = g_htons (src->port); /* short, network byte order */
|
|
||||||
|
|
||||||
if (src->multi_addr.imr_multiaddr.s_addr)
|
|
||||||
src->myaddr.sin_addr.s_addr = src->multi_addr.imr_multiaddr.s_addr;
|
|
||||||
else
|
|
||||||
src->myaddr.sin_addr.s_addr = INADDR_ANY;
|
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (src, "binding on port %d", src->port);
|
GST_DEBUG_OBJECT (src, "binding on port %d", src->port);
|
||||||
if ((ret = bind (src->sock.fd, (struct sockaddr *) &src->myaddr,
|
if ((ret = bind (src->sock.fd, (struct sockaddr *) &src->myaddr,
|
||||||
sizeof (src->myaddr))) < 0)
|
sizeof (src->myaddr))) < 0)
|
||||||
|
@ -726,11 +737,9 @@ gst_udpsrc_start (GstBaseSrc * bsrc)
|
||||||
src->externalfd = TRUE;
|
src->externalfd = TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (src->multi_addr.imr_multiaddr.s_addr) {
|
if (gst_udp_is_multicast (&src->myaddr)) {
|
||||||
src->multi_addr.imr_interface.s_addr = INADDR_ANY;
|
ret = gst_udp_join_group (src->sock.fd, TRUE, src->ttl, &src->myaddr);
|
||||||
if ((ret =
|
if (ret < 0)
|
||||||
setsockopt (src->sock.fd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
|
|
||||||
&src->multi_addr, sizeof (src->multi_addr))) < 0)
|
|
||||||
goto membership;
|
goto membership;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -769,7 +778,9 @@ gst_udpsrc_start (GstBaseSrc * bsrc)
|
||||||
sizeof (bc_val))) < 0)
|
sizeof (bc_val))) < 0)
|
||||||
goto no_broadcast;
|
goto no_broadcast;
|
||||||
|
|
||||||
port = g_ntohs (my_addr.sin_port);
|
/* NOTE: sockaddr_in.sin_port works for ipv4 and ipv6 because sin_port
|
||||||
|
* follows ss_family on both */
|
||||||
|
port = ntohs (((struct sockaddr_in *) &my_addr)->sin_port);
|
||||||
GST_DEBUG_OBJECT (src, "bound, on port %d", port);
|
GST_DEBUG_OBJECT (src, "bound, on port %d", port);
|
||||||
if (port != src->port) {
|
if (port != src->port) {
|
||||||
src->port = port;
|
src->port = port;
|
||||||
|
@ -777,7 +788,7 @@ gst_udpsrc_start (GstBaseSrc * bsrc)
|
||||||
g_object_notify (G_OBJECT (src), "port");
|
g_object_notify (G_OBJECT (src), "port");
|
||||||
}
|
}
|
||||||
|
|
||||||
src->myaddr.sin_port = g_htons (src->port + 1);
|
((struct sockaddr_in *) &src->myaddr)->sin_port = htons (src->port + 1);
|
||||||
|
|
||||||
if ((src->fdset = gst_poll_new (TRUE)) == NULL)
|
if ((src->fdset = gst_poll_new (TRUE)) == NULL)
|
||||||
goto no_fdset;
|
goto no_fdset;
|
||||||
|
@ -788,6 +799,12 @@ gst_udpsrc_start (GstBaseSrc * bsrc)
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
||||||
/* ERRORS */
|
/* ERRORS */
|
||||||
|
getaddrinfo_error:
|
||||||
|
{
|
||||||
|
GST_ELEMENT_ERROR (src, RESOURCE, SETTINGS, (NULL),
|
||||||
|
("getaddrinfo failed %d: %s (%d)", ret, g_strerror (errno), errno));
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
no_socket:
|
no_socket:
|
||||||
{
|
{
|
||||||
GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, (NULL),
|
GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, (NULL),
|
||||||
|
|
|
@ -68,8 +68,7 @@ struct _GstUDPSrc {
|
||||||
GstPoll *fdset;
|
GstPoll *fdset;
|
||||||
gboolean externalfd;
|
gboolean externalfd;
|
||||||
|
|
||||||
struct sockaddr_in myaddr;
|
struct sockaddr_storage myaddr;
|
||||||
struct ip_mreq multi_addr;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct _GstUDPSrcClass {
|
struct _GstUDPSrcClass {
|
||||||
|
|
Loading…
Reference in a new issue