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>
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 * Boston, MA 02111-1307, USA.
29 #include "gstudpnetutils.h"
31 /* EAI_ADDRFAMILY was obsoleted in BSD at some point */
32 #ifndef EAI_ADDRFAMILY
33 #define EAI_ADDRFAMILY 1
39 gst_udp_net_utils_win32_wsa_startup (GstObject * obj)
44 error = WSAStartup (0x0202, &w);
47 GST_WARNING_OBJECT (obj, "WSAStartup error: %d", error);
51 if (w.wVersion != 0x0202) {
53 GST_WARNING_OBJECT (obj, "Winsock version wrong : 0x%x", w.wVersion);
63 gst_udp_get_sockaddr_length (struct sockaddr_storage *addr)
65 /* MacOS is picky about passing precisely the correct length,
66 * so we calculate it here for the given socket type.
68 switch (addr->ss_family) {
70 return sizeof (struct sockaddr_in);
72 return sizeof (struct sockaddr_in6);
74 /* don't know, Screw MacOS and use the full length */
75 return sizeof (*addr);
80 gst_udp_get_addr (const char *hostname, int port, struct sockaddr_storage *addr)
82 struct addrinfo hints, *res = NULL, *nres;
83 char service[NI_MAXSERV];
86 memset (&hints, 0, sizeof (hints));
87 hints.ai_family = AF_UNSPEC;
88 hints.ai_socktype = SOCK_DGRAM;
89 g_snprintf (service, sizeof (service) - 1, "%d", port);
90 service[sizeof (service) - 1] = '\0';
92 if ((ret = getaddrinfo (hostname, (port == -1) ? NULL : service, &hints,
99 if (nres->ai_family == AF_INET || nres->ai_family == AF_INET6)
101 nres = nres->ai_next;
105 memcpy (addr, nres->ai_addr, nres->ai_addrlen);
107 ret = EAI_ADDRFAMILY;
116 gst_udp_set_loop (int sockfd, gboolean loop)
119 struct sockaddr_storage addr;
121 int l = (loop == FALSE) ? 0 : 1;
123 socklen = sizeof (addr);
124 if ((ret = getsockname (sockfd, (struct sockaddr *) &addr, &socklen)) < 0) {
128 switch (addr.ss_family) {
131 ret = setsockopt (sockfd, IPPROTO_IP, IP_MULTICAST_LOOP, &l, sizeof (l));
140 setsockopt (sockfd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &l,
149 WSASetLastError (WSAEAFNOSUPPORT);
151 errno = EAFNOSUPPORT;
159 gst_udp_set_ttl (int sockfd, int ttl, gboolean is_multicast)
162 struct sockaddr_storage addr;
166 socklen = sizeof (addr);
167 if ((ret = getsockname (sockfd, (struct sockaddr *) &addr, &socklen)) < 0) {
171 switch (addr.ss_family) {
174 optname = (is_multicast == TRUE) ? IP_MULTICAST_TTL : IP_TTL;
175 ret = setsockopt (sockfd, IPPROTO_IP, optname, &ttl, sizeof (ttl));
183 (is_multicast == TRUE) ? IPV6_MULTICAST_HOPS : IPV6_UNICAST_HOPS;
184 ret = setsockopt (sockfd, IPPROTO_IPV6, optname, &ttl, sizeof (ttl));
188 /* When using IPV4 address with IPV6 socket, both TTL values
189 must be set in order to actually use the given value.
190 Has no effect when IPV6 address is used. */
191 optname = (is_multicast == TRUE) ? IP_MULTICAST_TTL : IP_TTL;
192 ret = setsockopt (sockfd, IPPROTO_IP, optname, &ttl, sizeof (ttl));
199 WSASetLastError (WSAEAFNOSUPPORT);
201 errno = EAFNOSUPPORT;
207 /* FIXME: Add interface selection for windows hosts. */
209 gst_udp_join_group (int sockfd, struct sockaddr_storage *addr, gchar * iface)
213 switch (addr->ss_family) {
217 struct ip_mreqn mreq4;
219 struct ip_mreq mreq4;
222 memset (&mreq4, 0, sizeof (mreq4));
223 mreq4.imr_multiaddr.s_addr =
224 ((struct sockaddr_in *) addr)->sin_addr.s_addr;
227 mreq4.imr_ifindex = if_nametoindex (iface);
229 mreq4.imr_ifindex = 0; /* Pick any. */
231 mreq4.imr_interface.s_addr = INADDR_ANY;
235 setsockopt (sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
236 (const void *) &mreq4, sizeof (mreq4))) < 0)
243 struct ipv6_mreq mreq6;
245 memset (&mreq6, 0, sizeof (mreq6));
246 memcpy (&mreq6.ipv6mr_multiaddr,
247 &(((struct sockaddr_in6 *) addr)->sin6_addr),
248 sizeof (struct in6_addr));
249 mreq6.ipv6mr_interface = 0;
250 #if !defined(G_OS_WIN32)
252 mreq6.ipv6mr_interface = if_nametoindex (iface);
256 setsockopt (sockfd, IPPROTO_IPV6, IPV6_JOIN_GROUP,
257 (const void *) &mreq6, sizeof (mreq6))) < 0)
264 WSASetLastError (WSAEAFNOSUPPORT);
266 errno = EAFNOSUPPORT;
273 gst_udp_leave_group (int sockfd, struct sockaddr_storage *addr)
277 switch (addr->ss_family) {
280 struct ip_mreq mreq4;
282 memset (&mreq4, 0, sizeof (mreq4));
283 mreq4.imr_multiaddr.s_addr =
284 ((struct sockaddr_in *) addr)->sin_addr.s_addr;
285 mreq4.imr_interface.s_addr = INADDR_ANY;
288 setsockopt (sockfd, IPPROTO_IP, IP_DROP_MEMBERSHIP,
289 (const void *) &mreq4, sizeof (mreq4))) < 0)
296 struct ipv6_mreq mreq6;
298 memset (&mreq6, 0, sizeof (mreq6));
299 memcpy (&mreq6.ipv6mr_multiaddr,
300 &(((struct sockaddr_in6 *) addr)->sin6_addr),
301 sizeof (struct in6_addr));
302 mreq6.ipv6mr_interface = 0;
305 setsockopt (sockfd, IPPROTO_IPV6, IPV6_LEAVE_GROUP,
306 (const void *) &mreq6, sizeof (mreq6))) < 0)
313 WSASetLastError (WSAEAFNOSUPPORT);
315 errno = EAFNOSUPPORT;
323 gst_udp_is_multicast (struct sockaddr_storage *addr)
327 switch (addr->ss_family) {
330 struct sockaddr_in *addr4 = (struct sockaddr_in *) addr;
332 ret = IN_MULTICAST (g_ntohl (addr4->sin_addr.s_addr));
338 struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *) addr;
340 ret = IN6_IS_ADDR_MULTICAST (&addr6->sin6_addr);
346 WSASetLastError (WSAEAFNOSUPPORT);
348 errno = EAFNOSUPPORT;