Switch to using GstStaticPadTemplate.
[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     errno = EAI_ADDRFAMILY;
108     ret = -1;
109   }
110
111 beach:
112   freeaddrinfo (res);
113   return ret;
114 }
115
116 int
117 gst_udp_set_loop_ttl (int sockfd, gboolean loop, int ttl)
118 {
119   int ret = -1;
120
121 #if 0
122   int l = (loop == FALSE) ? 0 : 1;
123
124   switch (addr->ss_family) {
125     case AF_INET:
126     {
127       if ((ret =
128               setsockopt (sockfd, IPPROTO_IP, IP_MULTICAST_LOOP, &l,
129                   sizeof (l))) < 0)
130         return ret;
131
132       if ((ret =
133               setsockopt (sockfd, IPPROTO_IP, IP_MULTICAST_TTL, &ttl,
134                   sizeof (ttl))) < 0)
135         return ret;
136       break;
137     }
138     case AF_INET6:
139     {
140       if ((ret =
141               setsockopt (sockfd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &l,
142                   sizeof (l))) < 0)
143         return ret;
144
145       if ((ret =
146               setsockopt (sockfd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &ttl,
147                   sizeof (ttl))) < 0)
148         return ret;
149
150       break;
151     }
152     default:
153       errno = EAFNOSUPPORT;
154   }
155 #endif
156   return ret;
157 }
158
159 int
160 gst_udp_join_group (int sockfd, struct sockaddr_storage *addr)
161 {
162   int ret = -1;
163
164   switch (addr->ss_family) {
165     case AF_INET:
166     {
167       struct ip_mreq mreq4;
168
169       mreq4.imr_multiaddr.s_addr =
170           ((struct sockaddr_in *) addr)->sin_addr.s_addr;
171       mreq4.imr_interface.s_addr = INADDR_ANY;
172
173       if ((ret =
174               setsockopt (sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
175                   (const void *) &mreq4, sizeof (mreq4))) < 0)
176         return ret;
177
178       break;
179     }
180     case AF_INET6:
181     {
182       struct ipv6_mreq mreq6;
183
184       memcpy (&mreq6.ipv6mr_multiaddr,
185           &(((struct sockaddr_in6 *) addr)->sin6_addr),
186           sizeof (struct in6_addr));
187       mreq6.ipv6mr_interface = 0;
188
189       if ((ret =
190               setsockopt (sockfd, IPPROTO_IPV6, IPV6_JOIN_GROUP,
191                   (const void *) &mreq6, sizeof (mreq6))) < 0)
192         return ret;
193
194       break;
195     }
196     default:
197 #ifdef G_OS_WIN32
198       WSASetLastError (WSAEAFNOSUPPORT);
199 #else
200       errno = EAFNOSUPPORT;
201 #endif
202   }
203   return ret;
204 }
205
206 int
207 gst_udp_leave_group (int sockfd, struct sockaddr_storage *addr)
208 {
209   int ret = -1;
210
211   switch (addr->ss_family) {
212     case AF_INET:
213     {
214       struct ip_mreq mreq4;
215
216       mreq4.imr_multiaddr.s_addr =
217           ((struct sockaddr_in *) addr)->sin_addr.s_addr;
218       mreq4.imr_interface.s_addr = INADDR_ANY;
219
220       if ((ret =
221               setsockopt (sockfd, IPPROTO_IP, IP_DROP_MEMBERSHIP,
222                   (const void *) &mreq4, sizeof (mreq4))) < 0)
223         return ret;
224     }
225       break;
226
227     case AF_INET6:
228     {
229       struct ipv6_mreq mreq6;
230
231       memcpy (&mreq6.ipv6mr_multiaddr,
232           &(((struct sockaddr_in6 *) addr)->sin6_addr),
233           sizeof (struct in6_addr));
234       mreq6.ipv6mr_interface = 0;
235
236       if ((ret =
237               setsockopt (sockfd, IPPROTO_IPV6, IPV6_LEAVE_GROUP,
238                   (const void *) &mreq6, sizeof (mreq6))) < 0)
239         return ret;
240     }
241       break;
242
243     default:
244 #ifdef G_OS_WIN32
245       WSASetLastError (WSAEAFNOSUPPORT);
246 #else
247       errno = EAFNOSUPPORT;
248 #endif
249   }
250
251   return ret;
252 }
253
254 int
255 gst_udp_is_multicast (struct sockaddr_storage *addr)
256 {
257   int ret = -1;
258
259   switch (addr->ss_family) {
260     case AF_INET:
261     {
262       struct sockaddr_in *addr4 = (struct sockaddr_in *) addr;
263
264       ret = IN_MULTICAST (g_ntohl (addr4->sin_addr.s_addr));
265     }
266       break;
267
268     case AF_INET6:
269     {
270       struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *) addr;
271
272       ret = IN6_IS_ADDR_MULTICAST (&addr6->sin6_addr);
273     }
274       break;
275
276     default:
277 #ifdef G_OS_WIN32
278       WSASetLastError (WSAEAFNOSUPPORT);
279 #else
280       errno = EAFNOSUPPORT;
281 #endif
282   }
283
284   return ret;
285 }