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, guint16 ss_family, gboolean loop)
123 int l = (loop == FALSE) ? 0 : 1;
128 ret = setsockopt (sockfd, IPPROTO_IP, IP_MULTICAST_LOOP, &l, sizeof (l));
137 setsockopt (sockfd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &l,
146 WSASetLastError (WSAEAFNOSUPPORT);
148 errno = EAFNOSUPPORT;
156 gst_udp_set_ttl (int sockfd, guint16 ss_family, int ttl, gboolean is_multicast)
164 optname = (is_multicast == TRUE) ? IP_MULTICAST_TTL : IP_TTL;
165 ret = setsockopt (sockfd, IPPROTO_IP, optname, &ttl, sizeof (ttl));
173 (is_multicast == TRUE) ? IPV6_MULTICAST_HOPS : IPV6_UNICAST_HOPS;
174 ret = setsockopt (sockfd, IPPROTO_IPV6, optname, &ttl, sizeof (ttl));
178 /* When using IPV4 address with IPV6 socket, both TTL values
179 must be set in order to actually use the given value.
180 Has no effect when IPV6 address is used. */
181 optname = (is_multicast == TRUE) ? IP_MULTICAST_TTL : IP_TTL;
182 ret = setsockopt (sockfd, IPPROTO_IP, optname, &ttl, sizeof (ttl));
189 WSASetLastError (WSAEAFNOSUPPORT);
191 errno = EAFNOSUPPORT;
197 /* FIXME: Add interface selection for windows hosts. */
199 gst_udp_join_group (int sockfd, struct sockaddr_storage *addr, gchar * iface)
203 switch (addr->ss_family) {
207 struct ip_mreqn mreq4;
209 struct ip_mreq mreq4;
212 memset (&mreq4, 0, sizeof (mreq4));
213 mreq4.imr_multiaddr.s_addr =
214 ((struct sockaddr_in *) addr)->sin_addr.s_addr;
217 mreq4.imr_ifindex = if_nametoindex (iface);
219 mreq4.imr_ifindex = 0; /* Pick any. */
221 mreq4.imr_interface.s_addr = INADDR_ANY;
225 setsockopt (sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
226 (const void *) &mreq4, sizeof (mreq4))) < 0)
233 struct ipv6_mreq mreq6;
235 memset (&mreq6, 0, sizeof (mreq6));
236 memcpy (&mreq6.ipv6mr_multiaddr,
237 &(((struct sockaddr_in6 *) addr)->sin6_addr),
238 sizeof (struct in6_addr));
239 mreq6.ipv6mr_interface = 0;
240 #if !defined(G_OS_WIN32)
242 mreq6.ipv6mr_interface = if_nametoindex (iface);
246 setsockopt (sockfd, IPPROTO_IPV6, IPV6_JOIN_GROUP,
247 (const void *) &mreq6, sizeof (mreq6))) < 0)
254 WSASetLastError (WSAEAFNOSUPPORT);
256 errno = EAFNOSUPPORT;
263 gst_udp_leave_group (int sockfd, struct sockaddr_storage *addr)
267 switch (addr->ss_family) {
270 struct ip_mreq mreq4;
272 memset (&mreq4, 0, sizeof (mreq4));
273 mreq4.imr_multiaddr.s_addr =
274 ((struct sockaddr_in *) addr)->sin_addr.s_addr;
275 mreq4.imr_interface.s_addr = INADDR_ANY;
278 setsockopt (sockfd, IPPROTO_IP, IP_DROP_MEMBERSHIP,
279 (const void *) &mreq4, sizeof (mreq4))) < 0)
286 struct ipv6_mreq mreq6;
288 memset (&mreq6, 0, sizeof (mreq6));
289 memcpy (&mreq6.ipv6mr_multiaddr,
290 &(((struct sockaddr_in6 *) addr)->sin6_addr),
291 sizeof (struct in6_addr));
292 mreq6.ipv6mr_interface = 0;
295 setsockopt (sockfd, IPPROTO_IPV6, IPV6_LEAVE_GROUP,
296 (const void *) &mreq6, sizeof (mreq6))) < 0)
303 WSASetLastError (WSAEAFNOSUPPORT);
305 errno = EAFNOSUPPORT;
313 gst_udp_is_multicast (struct sockaddr_storage *addr)
317 switch (addr->ss_family) {
320 struct sockaddr_in *addr4 = (struct sockaddr_in *) addr;
322 ret = IN_MULTICAST (g_ntohl (addr4->sin_addr.s_addr));
328 struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *) addr;
330 ret = IN6_IS_ADDR_MULTICAST (&addr6->sin6_addr);
336 WSASetLastError (WSAEAFNOSUPPORT);
338 errno = EAFNOSUPPORT;
346 gst_udp_uri_init (GstUDPUri * uri, const gchar * host, gint port)
350 gst_udp_uri_update (uri, host, port);
354 gst_udp_uri_update (GstUDPUri * uri, const gchar * host, gint port)
358 uri->host = g_strdup (host);
359 if (strchr (host, ':'))
362 uri->is_ipv6 = FALSE;
371 gst_udp_parse_uri (const gchar * uristr, gchar ** host, guint16 * port)
373 gchar *protocol, *location_start;
374 gchar *location, *location_end;
377 /* consider no protocol to be udp:// */
378 protocol = gst_uri_get_protocol (uristr);
381 if (strcmp (protocol, "udp") != 0)
385 location_start = gst_uri_get_location (uristr);
389 GST_DEBUG ("got location '%s'", location_start);
391 /* VLC compatibility, strip everything before the @ sign. VLC uses that as the
393 location = g_strstr_len (location_start, -1, "@");
394 if (location == NULL)
395 location = location_start;
399 if (location[0] == '[') {
400 GST_DEBUG ("parse IPV6 address '%s'", location);
401 location_end = strchr (location, ']');
402 if (location_end == NULL)
405 *host = g_strndup (location + 1, location_end - location - 1);
406 colptr = strrchr (location_end, ':');
408 GST_DEBUG ("parse IPV4 address '%s'", location);
409 colptr = strrchr (location, ':');
411 if (colptr != NULL) {
412 *host = g_strndup (location, colptr - location);
414 *host = g_strdup (location);
417 GST_DEBUG ("host set to '%s'", *host);
419 if (colptr != NULL) {
420 *port = atoi (colptr + 1);
422 g_free (location_start);
429 GST_ERROR ("error parsing uri %s: no protocol", uristr);
434 GST_ERROR ("error parsing uri %s: wrong protocol (%s != udp)", uristr,
441 GST_ERROR ("error parsing uri %s", uristr);
448 gst_udp_uri_string (GstUDPUri * uri)
453 result = g_strdup_printf ("udp://[%s]:%d", uri->host, uri->port);
455 result = g_strdup_printf ("udp://%s:%d", uri->host, uri->port);
461 gst_udp_uri_free (GstUDPUri * uri)