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.
30 #include "gstudpnetutils.h"
32 /* EAI_ADDRFAMILY was obsoleted in BSD at some point */
33 #ifndef EAI_ADDRFAMILY
34 #define EAI_ADDRFAMILY 1
40 gst_udp_net_utils_win32_wsa_startup (GstObject * obj)
45 error = WSAStartup (0x0202, &w);
48 GST_WARNING_OBJECT (obj, "WSAStartup error: %d", error);
52 if (w.wVersion != 0x0202) {
54 GST_WARNING_OBJECT (obj, "Winsock version wrong : 0x%x", w.wVersion);
64 gst_udp_get_sockaddr_length (struct sockaddr_storage *addr)
66 /* MacOS is picky about passing precisely the correct length,
67 * so we calculate it here for the given socket type.
69 switch (addr->ss_family) {
71 return sizeof (struct sockaddr_in);
73 return sizeof (struct sockaddr_in6);
75 /* don't know, Screw MacOS and use the full length */
76 return sizeof (*addr);
81 gst_udp_get_addr (const char *hostname, int port, struct sockaddr_storage *addr)
83 struct addrinfo hints, *res = NULL, *nres;
84 char service[NI_MAXSERV];
87 memset (&hints, 0, sizeof (hints));
88 hints.ai_family = AF_UNSPEC;
89 hints.ai_socktype = SOCK_DGRAM;
90 g_snprintf (service, sizeof (service) - 1, "%d", port);
91 service[sizeof (service) - 1] = '\0';
93 if ((ret = getaddrinfo (hostname, (port == -1) ? NULL : service, &hints,
100 if (nres->ai_family == AF_INET || nres->ai_family == AF_INET6)
102 nres = nres->ai_next;
106 memcpy (addr, nres->ai_addr, nres->ai_addrlen);
108 ret = EAI_ADDRFAMILY;
117 gst_udp_set_loop (int sockfd, gboolean loop)
120 struct sockaddr_storage addr;
122 int l = (loop == FALSE) ? 0 : 1;
124 socklen = sizeof (addr);
125 if ((ret = getsockname (sockfd, (struct sockaddr *) &addr, &socklen)) < 0) {
129 switch (addr.ss_family) {
132 ret = setsockopt (sockfd, IPPROTO_IP, IP_MULTICAST_LOOP, &l, sizeof (l));
141 setsockopt (sockfd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &l,
150 WSASetLastError (WSAEAFNOSUPPORT);
152 errno = EAFNOSUPPORT;
160 gst_udp_set_ttl (int sockfd, int ttl, gboolean is_multicast)
163 struct sockaddr_storage addr;
167 socklen = sizeof (addr);
168 if ((ret = getsockname (sockfd, (struct sockaddr *) &addr, &socklen)) < 0) {
172 switch (addr.ss_family) {
175 optname = (is_multicast == TRUE) ? IP_MULTICAST_TTL : IP_TTL;
176 ret = setsockopt (sockfd, IPPROTO_IP, optname, &ttl, sizeof (ttl));
184 (is_multicast == TRUE) ? IPV6_MULTICAST_HOPS : IPV6_UNICAST_HOPS;
185 ret = setsockopt (sockfd, IPPROTO_IPV6, optname, &ttl, sizeof (ttl));
189 /* When using IPV4 address with IPV6 socket, both TTL values
190 must be set in order to actually use the given value.
191 Has no effect when IPV6 address is used. */
192 optname = (is_multicast == TRUE) ? IP_MULTICAST_TTL : IP_TTL;
193 ret = setsockopt (sockfd, IPPROTO_IP, optname, &ttl, sizeof (ttl));
200 WSASetLastError (WSAEAFNOSUPPORT);
202 errno = EAFNOSUPPORT;
208 /* FIXME: Add interface selection for windows hosts. */
210 gst_udp_join_group (int sockfd, struct sockaddr_storage *addr, gchar * iface)
214 switch (addr->ss_family) {
218 struct ip_mreqn mreq4;
220 struct ip_mreq mreq4;
223 memset (&mreq4, 0, sizeof (mreq4));
224 mreq4.imr_multiaddr.s_addr =
225 ((struct sockaddr_in *) addr)->sin_addr.s_addr;
228 mreq4.imr_ifindex = if_nametoindex (iface);
230 mreq4.imr_ifindex = 0; /* Pick any. */
232 mreq4.imr_interface.s_addr = INADDR_ANY;
236 setsockopt (sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
237 (const void *) &mreq4, sizeof (mreq4))) < 0)
244 struct ipv6_mreq mreq6;
246 memset (&mreq6, 0, sizeof (mreq6));
247 memcpy (&mreq6.ipv6mr_multiaddr,
248 &(((struct sockaddr_in6 *) addr)->sin6_addr),
249 sizeof (struct in6_addr));
250 mreq6.ipv6mr_interface = 0;
251 #if !defined(G_OS_WIN32)
253 mreq6.ipv6mr_interface = if_nametoindex (iface);
257 setsockopt (sockfd, IPPROTO_IPV6, IPV6_JOIN_GROUP,
258 (const void *) &mreq6, sizeof (mreq6))) < 0)
265 WSASetLastError (WSAEAFNOSUPPORT);
267 errno = EAFNOSUPPORT;
274 gst_udp_leave_group (int sockfd, struct sockaddr_storage *addr)
278 switch (addr->ss_family) {
281 struct ip_mreq mreq4;
283 memset (&mreq4, 0, sizeof (mreq4));
284 mreq4.imr_multiaddr.s_addr =
285 ((struct sockaddr_in *) addr)->sin_addr.s_addr;
286 mreq4.imr_interface.s_addr = INADDR_ANY;
289 setsockopt (sockfd, IPPROTO_IP, IP_DROP_MEMBERSHIP,
290 (const void *) &mreq4, sizeof (mreq4))) < 0)
297 struct ipv6_mreq mreq6;
299 memset (&mreq6, 0, sizeof (mreq6));
300 memcpy (&mreq6.ipv6mr_multiaddr,
301 &(((struct sockaddr_in6 *) addr)->sin6_addr),
302 sizeof (struct in6_addr));
303 mreq6.ipv6mr_interface = 0;
306 setsockopt (sockfd, IPPROTO_IPV6, IPV6_LEAVE_GROUP,
307 (const void *) &mreq6, sizeof (mreq6))) < 0)
314 WSASetLastError (WSAEAFNOSUPPORT);
316 errno = EAFNOSUPPORT;
324 gst_udp_is_multicast (struct sockaddr_storage *addr)
328 switch (addr->ss_family) {
331 struct sockaddr_in *addr4 = (struct sockaddr_in *) addr;
333 ret = IN_MULTICAST (g_ntohl (addr4->sin_addr.s_addr));
339 struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *) addr;
341 ret = IN6_IS_ADDR_MULTICAST (&addr6->sin6_addr);
347 WSASetLastError (WSAEAFNOSUPPORT);
349 errno = EAFNOSUPPORT;