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.
32 #include "gstudpnetutils.h"
34 /* EAI_ADDRFAMILY was obsoleted in BSD at some point */
35 #ifndef EAI_ADDRFAMILY
36 #define EAI_ADDRFAMILY 1
42 gst_udp_net_utils_win32_wsa_startup (GstObject * obj)
47 error = WSAStartup (0x0202, &w);
50 GST_WARNING_OBJECT (obj, "WSAStartup error: %d", error);
54 if (w.wVersion != 0x0202) {
56 GST_WARNING_OBJECT (obj, "Winsock version wrong : 0x%x", w.wVersion);
66 gst_udp_get_sockaddr_length (struct sockaddr_storage *addr)
68 /* MacOS is picky about passing precisely the correct length,
69 * so we calculate it here for the given socket type.
71 switch (addr->ss_family) {
73 return sizeof (struct sockaddr_in);
75 return sizeof (struct sockaddr_in6);
77 /* don't know, Screw MacOS and use the full length */
78 return sizeof (*addr);
83 gst_udp_get_addr (const char *hostname, int port, struct sockaddr_storage *addr)
85 struct addrinfo hints, *res = NULL, *nres;
86 char service[NI_MAXSERV];
89 memset (&hints, 0, sizeof (hints));
90 hints.ai_family = AF_UNSPEC;
91 hints.ai_socktype = SOCK_DGRAM;
92 g_snprintf (service, sizeof (service) - 1, "%d", port);
93 service[sizeof (service) - 1] = '\0';
95 if ((ret = getaddrinfo (hostname, (port == -1) ? NULL : service, &hints,
102 if (nres->ai_family == AF_INET || nres->ai_family == AF_INET6)
104 nres = nres->ai_next;
108 memcpy (addr, nres->ai_addr, nres->ai_addrlen);
110 ret = EAI_ADDRFAMILY;
119 gst_udp_set_loop (int sockfd, gboolean loop)
122 struct sockaddr_storage addr;
124 int l = (loop == FALSE) ? 0 : 1;
126 socklen = sizeof (addr);
127 if ((ret = getsockname (sockfd, (struct sockaddr *) &addr, &socklen)) < 0) {
131 switch (addr.ss_family) {
134 ret = setsockopt (sockfd, IPPROTO_IP, IP_MULTICAST_LOOP, &l, sizeof (l));
143 setsockopt (sockfd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &l,
152 WSASetLastError (WSAEAFNOSUPPORT);
154 errno = EAFNOSUPPORT;
162 gst_udp_set_ttl (int sockfd, int ttl, gboolean is_multicast)
165 struct sockaddr_storage addr;
169 socklen = sizeof (addr);
170 if ((ret = getsockname (sockfd, (struct sockaddr *) &addr, &socklen)) < 0) {
174 switch (addr.ss_family) {
177 optname = (is_multicast == TRUE) ? IP_MULTICAST_TTL : IP_TTL;
178 ret = setsockopt (sockfd, IPPROTO_IP, optname, &ttl, sizeof (ttl));
186 (is_multicast == TRUE) ? IPV6_MULTICAST_HOPS : IPV6_UNICAST_HOPS;
187 ret = setsockopt (sockfd, IPPROTO_IPV6, optname, &ttl, sizeof (ttl));
191 /* When using IPV4 address with IPV6 socket, both TTL values
192 must be set in order to actually use the given value.
193 Has no effect when IPV6 address is used. */
194 optname = (is_multicast == TRUE) ? IP_MULTICAST_TTL : IP_TTL;
195 ret = setsockopt (sockfd, IPPROTO_IP, optname, &ttl, sizeof (ttl));
202 WSASetLastError (WSAEAFNOSUPPORT);
204 errno = EAFNOSUPPORT;
210 /* FIXME: Add interface selection for windows hosts. */
212 gst_udp_join_group (int sockfd, struct sockaddr_storage *addr, gchar * iface)
216 switch (addr->ss_family) {
220 struct ip_mreqn mreq4;
222 struct ip_mreq mreq4;
225 memset (&mreq4, 0, sizeof (mreq4));
226 mreq4.imr_multiaddr.s_addr =
227 ((struct sockaddr_in *) addr)->sin_addr.s_addr;
230 mreq4.imr_ifindex = if_nametoindex (iface);
232 mreq4.imr_ifindex = 0; /* Pick any. */
234 mreq4.imr_interface.s_addr = INADDR_ANY;
238 setsockopt (sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
239 (const void *) &mreq4, sizeof (mreq4))) < 0)
246 struct ipv6_mreq mreq6;
248 memset (&mreq6, 0, sizeof (mreq6));
249 memcpy (&mreq6.ipv6mr_multiaddr,
250 &(((struct sockaddr_in6 *) addr)->sin6_addr),
251 sizeof (struct in6_addr));
252 mreq6.ipv6mr_interface = 0;
253 #if !defined(G_OS_WIN32)
255 mreq6.ipv6mr_interface = if_nametoindex (iface);
259 setsockopt (sockfd, IPPROTO_IPV6, IPV6_JOIN_GROUP,
260 (const void *) &mreq6, sizeof (mreq6))) < 0)
267 WSASetLastError (WSAEAFNOSUPPORT);
269 errno = EAFNOSUPPORT;
276 gst_udp_leave_group (int sockfd, struct sockaddr_storage *addr)
280 switch (addr->ss_family) {
283 struct ip_mreq mreq4;
285 memset (&mreq4, 0, sizeof (mreq4));
286 mreq4.imr_multiaddr.s_addr =
287 ((struct sockaddr_in *) addr)->sin_addr.s_addr;
288 mreq4.imr_interface.s_addr = INADDR_ANY;
291 setsockopt (sockfd, IPPROTO_IP, IP_DROP_MEMBERSHIP,
292 (const void *) &mreq4, sizeof (mreq4))) < 0)
299 struct ipv6_mreq mreq6;
301 memset (&mreq6, 0, sizeof (mreq6));
302 memcpy (&mreq6.ipv6mr_multiaddr,
303 &(((struct sockaddr_in6 *) addr)->sin6_addr),
304 sizeof (struct in6_addr));
305 mreq6.ipv6mr_interface = 0;
308 setsockopt (sockfd, IPPROTO_IPV6, IPV6_LEAVE_GROUP,
309 (const void *) &mreq6, sizeof (mreq6))) < 0)
316 WSASetLastError (WSAEAFNOSUPPORT);
318 errno = EAFNOSUPPORT;
326 gst_udp_is_multicast (struct sockaddr_storage *addr)
330 switch (addr->ss_family) {
333 struct sockaddr_in *addr4 = (struct sockaddr_in *) addr;
335 ret = IN_MULTICAST (g_ntohl (addr4->sin_addr.s_addr));
341 struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *) addr;
343 ret = IN6_IS_ADDR_MULTICAST (&addr6->sin6_addr);
349 WSASetLastError (WSAEAFNOSUPPORT);
351 errno = EAFNOSUPPORT;
359 gst_udp_uri_init (GstUDPUri * uri, const gchar * host, gint port)
363 gst_udp_uri_update (uri, host, port);
367 gst_udp_uri_update (GstUDPUri * uri, const gchar * host, gint port)
371 uri->host = g_strdup (host);
372 if (strchr (host, ':'))
375 uri->is_ipv6 = FALSE;
384 gst_udp_parse_uri (const gchar * uristr, GstUDPUri * uri)
387 gchar *location, *location_end;
390 protocol = gst_uri_get_protocol (uristr);
391 if (strcmp (protocol, "udp") != 0)
395 location = gst_uri_get_location (uristr);
399 GST_DEBUG ("got location '%s'", location);
401 if (location[0] == '[') {
402 GST_DEBUG ("parse IPV6 address '%s'", location);
403 location_end = strchr (location, ']');
404 if (location_end == NULL)
409 uri->host = g_strndup (location + 1, location_end - location - 1);
410 colptr = strrchr (location_end, ':');
412 GST_DEBUG ("parse IPV4 address '%s'", location);
413 uri->is_ipv6 = FALSE;
414 colptr = strrchr (location, ':');
417 if (colptr != NULL) {
418 uri->host = g_strndup (location, colptr - location);
420 uri->host = g_strdup (location);
423 GST_DEBUG ("host set to '%s'", uri->host);
425 if (colptr != NULL) {
426 uri->port = atoi (colptr + 1);
435 GST_ERROR ("error parsing uri %s: wrong protocol (%s != udp)", uristr,
442 GST_ERROR ("error parsing uri %s", uristr);
449 gst_udp_uri_string (GstUDPUri * uri)
454 result = g_strdup_printf ("udp://[%s]:%d", uri->host, uri->port);
456 result = g_strdup_printf ("udp://%s:%d", uri->host, uri->port);
462 gst_udp_uri_free (GstUDPUri * uri)