udp: Fix a simple typo in the previous commit
[platform/upstream/gst-plugins-good.git] / gst / udp / gstudpnetutils.c
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  *
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.
9  *
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.
14  *
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.
19  */
20
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24
25 #include <errno.h>
26 #include <stdio.h>
27 #include <memory.h>
28
29 /* EAI_ADDRFAMILY was obsoleted in BSD at some point */
30 #ifndef EAI_ADDRFAMILY
31 #define EAI_ADDRFAMILY 1
32 #endif
33
34 #include "gstudpnetutils.h"
35
36 #ifdef G_OS_WIN32
37
38 gboolean
39 gst_udp_net_utils_win32_wsa_startup (GstObject * obj)
40 {
41   WSADATA w;
42   int error;
43
44   error = WSAStartup (0x0202, &w);
45
46   if (error) {
47     GST_WARNING_OBJECT (obj, "WSAStartup error: %d", error);
48     return FALSE;
49   }
50
51   if (w.wVersion != 0x0202) {
52     WSACleanup ();
53     GST_WARNING_OBJECT (obj, "Winsock version wrong : 0x%x", w.wVersion);
54     return FALSE;
55   }
56
57   return TRUE;
58 }
59
60 #endif
61
62 int
63 gst_udp_get_sockaddr_length (struct sockaddr_storage *addr)
64 {
65   /* MacOS is picky about passing precisely the correct length,
66    * so we calculate it here for the given socket type.
67    */
68   switch (addr->ss_family) {
69     case AF_INET:
70       return sizeof (struct sockaddr_in);
71     case AF_INET6:
72       return sizeof (struct sockaddr_in6);
73     default:
74       /* don't know, Screw MacOS and use the full length */
75       return sizeof (*addr);
76   }
77 }
78
79 int
80 gst_udp_get_addr (const char *hostname, int port, struct sockaddr_storage *addr)
81 {
82   struct addrinfo hints, *res, *nres;
83   char service[NI_MAXSERV];
84   int ret;
85
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';
91
92   if ((ret = getaddrinfo (hostname, (port == -1) ? NULL : service, &hints,
93               &res)) < 0) {
94     goto beach;
95   }
96
97   nres = res;
98   while (nres) {
99     if (nres->ai_family == AF_INET || nres->ai_family == AF_INET6)
100       break;
101     nres = nres->ai_next;
102   }
103
104   if (nres) {
105     memcpy (addr, nres->ai_addr, nres->ai_addrlen);
106   } else {
107     ret = EAI_ADDRFAMILY;
108   }
109
110 beach:
111   freeaddrinfo (res);
112   return ret;
113 }
114
115 int
116 gst_udp_set_loop_ttl (int sockfd, gboolean loop, int ttl)
117 {
118   socklen_t socklen;
119   struct sockaddr_storage addr;
120   int ret = -1;
121   int l = (loop == FALSE) ? 0 : 1;
122
123   socklen = sizeof (addr);
124   if ((ret = getsockname (sockfd, (struct sockaddr *) &addr, &socklen)) < 0) {
125     return ret;
126   }
127
128   switch (addr.ss_family) {
129     case AF_INET:
130     {
131       if ((ret =
132               setsockopt (sockfd, IPPROTO_IP, IP_MULTICAST_LOOP, &l,
133                   sizeof (l))) < 0)
134         return ret;
135
136       if ((ret =
137               setsockopt (sockfd, IPPROTO_IP, IP_MULTICAST_TTL, &ttl,
138                   sizeof (ttl))) < 0)
139         return ret;
140       break;
141     }
142     case AF_INET6:
143     {
144       if ((ret =
145               setsockopt (sockfd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &l,
146                   sizeof (l))) < 0)
147         return ret;
148
149       if ((ret =
150               setsockopt (sockfd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &ttl,
151                   sizeof (ttl))) < 0)
152         return ret;
153
154       break;
155     }
156     default:
157 #ifdef G_OS_WIN32
158       WSASetLastError (WSAEAFNOSUPPORT);
159 #else
160       errno = EAFNOSUPPORT;
161 #endif
162   }
163   return ret;
164 }
165
166 /* FIXME: Add interface selection for windows hosts.  */
167 int
168 gst_udp_join_group (int sockfd, struct sockaddr_storage *addr, gchar * iface)
169 {
170   int ret = -1;
171
172   switch (addr->ss_family) {
173     case AF_INET:
174     {
175 #ifdef HAVE_IP_MREQN
176       struct ip_mreqn mreq4;
177 #else
178       struct ip_mreq mreq4;
179 #endif
180
181       mreq4.imr_multiaddr.s_addr =
182           ((struct sockaddr_in *) addr)->sin_addr.s_addr;
183 #ifdef HAVE_IP_MREQN
184       if (iface)
185         mreq4.imr_ifindex = if_nametoindex (iface);
186       else
187         mreq4.imr_ifindex = 0;  /* Pick any.  */
188 #else
189       mreq4.imr_interface.s_addr = INADDR_ANY;
190 #endif
191
192       if ((ret =
193               setsockopt (sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
194                   (const void *) &mreq4, sizeof (mreq4))) < 0)
195         return ret;
196
197       break;
198     }
199     case AF_INET6:
200     {
201       struct ipv6_mreq mreq6;
202
203       memcpy (&mreq6.ipv6mr_multiaddr,
204           &(((struct sockaddr_in6 *) addr)->sin6_addr),
205           sizeof (struct in6_addr));
206       mreq6.ipv6mr_interface = 0;
207 #if !defined(G_OS_WIN32)
208       if (iface)
209         mreq6.ipv6mr_interface = if_nametoindex (iface);
210 #endif
211
212       if ((ret =
213               setsockopt (sockfd, IPPROTO_IPV6, IPV6_JOIN_GROUP,
214                   (const void *) &mreq6, sizeof (mreq6))) < 0)
215         return ret;
216
217       break;
218     }
219     default:
220 #ifdef G_OS_WIN32
221       WSASetLastError (WSAEAFNOSUPPORT);
222 #else
223       errno = EAFNOSUPPORT;
224 #endif
225   }
226   return ret;
227 }
228
229 int
230 gst_udp_leave_group (int sockfd, struct sockaddr_storage *addr)
231 {
232   int ret = -1;
233
234   switch (addr->ss_family) {
235     case AF_INET:
236     {
237       struct ip_mreq mreq4;
238
239       mreq4.imr_multiaddr.s_addr =
240           ((struct sockaddr_in *) addr)->sin_addr.s_addr;
241       mreq4.imr_interface.s_addr = INADDR_ANY;
242
243       if ((ret =
244               setsockopt (sockfd, IPPROTO_IP, IP_DROP_MEMBERSHIP,
245                   (const void *) &mreq4, sizeof (mreq4))) < 0)
246         return ret;
247     }
248       break;
249
250     case AF_INET6:
251     {
252       struct ipv6_mreq mreq6;
253
254       memcpy (&mreq6.ipv6mr_multiaddr,
255           &(((struct sockaddr_in6 *) addr)->sin6_addr),
256           sizeof (struct in6_addr));
257       mreq6.ipv6mr_interface = 0;
258
259       if ((ret =
260               setsockopt (sockfd, IPPROTO_IPV6, IPV6_LEAVE_GROUP,
261                   (const void *) &mreq6, sizeof (mreq6))) < 0)
262         return ret;
263     }
264       break;
265
266     default:
267 #ifdef G_OS_WIN32
268       WSASetLastError (WSAEAFNOSUPPORT);
269 #else
270       errno = EAFNOSUPPORT;
271 #endif
272   }
273
274   return ret;
275 }
276
277 int
278 gst_udp_is_multicast (struct sockaddr_storage *addr)
279 {
280   int ret = -1;
281
282   switch (addr->ss_family) {
283     case AF_INET:
284     {
285       struct sockaddr_in *addr4 = (struct sockaddr_in *) addr;
286
287       ret = IN_MULTICAST (g_ntohl (addr4->sin_addr.s_addr));
288     }
289       break;
290
291     case AF_INET6:
292     {
293       struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *) addr;
294
295       ret = IN6_IS_ADDR_MULTICAST (&addr6->sin6_addr);
296     }
297       break;
298
299     default:
300 #ifdef G_OS_WIN32
301       WSASetLastError (WSAEAFNOSUPPORT);
302 #else
303       errno = EAFNOSUPPORT;
304 #endif
305   }
306
307   return ret;
308 }