1 /* GStreamer UDP network utility functions
2 * Copyright (C) 2006 Tim-Philipp Müller <tim centricular net>
3 * Copyright (C) 2006 Joni Valtanen <joni.valtanen@movial.fi>
4 * Copyright (C) 2009 Jarkko Palviainen <jarkko.palviainen@sesca.com>
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
16 * You should have received a copy of the GNU Library General Public
17 * License along with this library; if not, write to the
18 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 * Boston, MA 02111-1307, USA.
33 #include "gstudpnetutils.h"
35 /* EAI_ADDRFAMILY was obsoleted in BSD at some point */
36 #ifndef EAI_ADDRFAMILY
37 #define EAI_ADDRFAMILY 1
43 gst_udp_net_utils_win32_wsa_startup (GstObject * obj)
48 error = WSAStartup (0x0202, &w);
51 GST_WARNING_OBJECT (obj, "WSAStartup error: %d", error);
55 if (w.wVersion != 0x0202) {
57 GST_WARNING_OBJECT (obj, "Winsock version wrong : 0x%x", w.wVersion);
67 gst_udp_get_sockaddr_length (struct sockaddr_storage *addr)
69 /* MacOS is picky about passing precisely the correct length,
70 * so we calculate it here for the given socket type.
72 switch (addr->ss_family) {
74 return sizeof (struct sockaddr_in);
76 return sizeof (struct sockaddr_in6);
78 /* don't know, Screw MacOS and use the full length */
79 return sizeof (*addr);
84 gst_udp_get_addr (const char *hostname, int port, struct sockaddr_storage *addr)
86 struct addrinfo hints, *res = NULL, *nres;
87 char service[NI_MAXSERV];
90 memset (&hints, 0, sizeof (hints));
91 hints.ai_family = AF_UNSPEC;
92 hints.ai_socktype = SOCK_DGRAM;
93 g_snprintf (service, sizeof (service) - 1, "%d", port);
94 service[sizeof (service) - 1] = '\0';
96 if ((ret = getaddrinfo (hostname, (port == -1) ? NULL : service, &hints,
103 if (nres->ai_family == AF_INET || nres->ai_family == AF_INET6)
105 nres = nres->ai_next;
109 memcpy (addr, nres->ai_addr, nres->ai_addrlen);
111 ret = EAI_ADDRFAMILY;
120 gst_udp_set_loop (int sockfd, gboolean loop)
123 struct sockaddr_storage addr;
125 int l = (loop == FALSE) ? 0 : 1;
127 socklen = sizeof (addr);
128 if ((ret = getsockname (sockfd, (struct sockaddr *) &addr, &socklen)) < 0) {
132 switch (addr.ss_family) {
135 ret = setsockopt (sockfd, IPPROTO_IP, IP_MULTICAST_LOOP, &l, sizeof (l));
144 setsockopt (sockfd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &l,
153 WSASetLastError (WSAEAFNOSUPPORT);
155 errno = EAFNOSUPPORT;
163 gst_udp_set_ttl (int sockfd, int ttl, gboolean is_multicast)
166 struct sockaddr_storage addr;
170 socklen = sizeof (addr);
171 if ((ret = getsockname (sockfd, (struct sockaddr *) &addr, &socklen)) < 0) {
175 switch (addr.ss_family) {
178 optname = (is_multicast == TRUE) ? IP_MULTICAST_TTL : IP_TTL;
179 ret = setsockopt (sockfd, IPPROTO_IP, optname, &ttl, sizeof (ttl));
187 (is_multicast == TRUE) ? IPV6_MULTICAST_HOPS : IPV6_UNICAST_HOPS;
188 ret = setsockopt (sockfd, IPPROTO_IPV6, optname, &ttl, sizeof (ttl));
192 /* When using IPV4 address with IPV6 socket, both TTL values
193 must be set in order to actually use the given value.
194 Has no effect when IPV6 address is used. */
195 optname = (is_multicast == TRUE) ? IP_MULTICAST_TTL : IP_TTL;
196 ret = setsockopt (sockfd, IPPROTO_IP, optname, &ttl, sizeof (ttl));
203 WSASetLastError (WSAEAFNOSUPPORT);
205 errno = EAFNOSUPPORT;
211 /* FIXME: Add interface selection for windows hosts. */
213 gst_udp_join_group (int sockfd, struct sockaddr_storage *addr, gchar * iface)
217 switch (addr->ss_family) {
221 struct ip_mreqn mreq4;
223 struct ip_mreq mreq4;
226 memset (&mreq4, 0, sizeof (mreq4));
227 mreq4.imr_multiaddr.s_addr =
228 ((struct sockaddr_in *) addr)->sin_addr.s_addr;
231 mreq4.imr_ifindex = if_nametoindex (iface);
233 mreq4.imr_ifindex = 0; /* Pick any. */
235 mreq4.imr_interface.s_addr = INADDR_ANY;
239 setsockopt (sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
240 (const void *) &mreq4, sizeof (mreq4))) < 0)
247 struct ipv6_mreq mreq6;
249 memset (&mreq6, 0, sizeof (mreq6));
250 memcpy (&mreq6.ipv6mr_multiaddr,
251 &(((struct sockaddr_in6 *) addr)->sin6_addr),
252 sizeof (struct in6_addr));
253 mreq6.ipv6mr_interface = 0;
254 #if !defined(G_OS_WIN32)
256 mreq6.ipv6mr_interface = if_nametoindex (iface);
260 setsockopt (sockfd, IPPROTO_IPV6, IPV6_JOIN_GROUP,
261 (const void *) &mreq6, sizeof (mreq6))) < 0)
268 WSASetLastError (WSAEAFNOSUPPORT);
270 errno = EAFNOSUPPORT;
277 gst_udp_leave_group (int sockfd, struct sockaddr_storage *addr)
281 switch (addr->ss_family) {
284 struct ip_mreq mreq4;
286 memset (&mreq4, 0, sizeof (mreq4));
287 mreq4.imr_multiaddr.s_addr =
288 ((struct sockaddr_in *) addr)->sin_addr.s_addr;
289 mreq4.imr_interface.s_addr = INADDR_ANY;
292 setsockopt (sockfd, IPPROTO_IP, IP_DROP_MEMBERSHIP,
293 (const void *) &mreq4, sizeof (mreq4))) < 0)
300 struct ipv6_mreq mreq6;
302 memset (&mreq6, 0, sizeof (mreq6));
303 memcpy (&mreq6.ipv6mr_multiaddr,
304 &(((struct sockaddr_in6 *) addr)->sin6_addr),
305 sizeof (struct in6_addr));
306 mreq6.ipv6mr_interface = 0;
309 setsockopt (sockfd, IPPROTO_IPV6, IPV6_LEAVE_GROUP,
310 (const void *) &mreq6, sizeof (mreq6))) < 0)
317 WSASetLastError (WSAEAFNOSUPPORT);
319 errno = EAFNOSUPPORT;
327 gst_udp_is_multicast (struct sockaddr_storage *addr)
331 switch (addr->ss_family) {
334 struct sockaddr_in *addr4 = (struct sockaddr_in *) addr;
336 ret = IN_MULTICAST (g_ntohl (addr4->sin_addr.s_addr));
342 struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *) addr;
344 ret = IN6_IS_ADDR_MULTICAST (&addr6->sin6_addr);
350 WSASetLastError (WSAEAFNOSUPPORT);
352 errno = EAFNOSUPPORT;
360 gst_udp_uri_init (GstUDPUri * uri, const gchar * host, gint port)
364 gst_udp_uri_update (uri, host, port);
368 gst_udp_uri_update (GstUDPUri * uri, const gchar * host, gint port)
372 uri->host = g_strdup (host);
373 if (strchr (host, ':'))
376 uri->is_ipv6 = FALSE;
385 gst_udp_parse_uri (const gchar * uristr, GstUDPUri * uri)
388 gchar *location, *location_end;
391 protocol = gst_uri_get_protocol (uristr);
392 if (strcmp (protocol, "udp") != 0)
396 location = gst_uri_get_location (uristr);
400 GST_DEBUG ("got location '%s'", location);
402 if (location[0] == '[') {
403 GST_DEBUG ("parse IPV6 address '%s'", location);
404 location_end = strchr (location, ']');
405 if (location_end == NULL)
410 uri->host = g_strndup (location + 1, location_end - location - 1);
411 colptr = strrchr (location_end, ':');
413 GST_DEBUG ("parse IPV4 address '%s'", location);
414 uri->is_ipv6 = FALSE;
415 colptr = strrchr (location, ':');
418 if (colptr != NULL) {
419 uri->host = g_strndup (location, colptr - location);
421 uri->host = g_strdup (location);
424 GST_DEBUG ("host set to '%s'", uri->host);
426 if (colptr != NULL) {
427 uri->port = atoi (colptr + 1);
436 GST_ERROR ("error parsing uri %s: wrong protocol (%s != udp)", uristr,
443 GST_ERROR ("error parsing uri %s", uristr);
450 gst_udp_uri_string (GstUDPUri * uri)
455 result = g_strdup_printf ("udp://[%s]:%d", uri->host, uri->port);
457 result = g_strdup_printf ("udp://%s:%d", uri->host, uri->port);
463 gst_udp_uri_free (GstUDPUri * uri)