gst/udp/gstudpnetutils.*: Provide a bunch of helper methods to deal with IPv4 and...
[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 #include "gstudpnetutils.h"
30
31 #ifdef G_OS_WIN32
32
33 gboolean
34 gst_udp_net_utils_win32_wsa_startup (GstObject * obj)
35 {
36   WSADATA w;
37   int error;
38
39   error = WSAStartup (0x0202, &w);
40
41   if (error) {
42     GST_WARNING_OBJECT (obj, "WSAStartup error: %d", error);
43     return FALSE;
44   }
45
46   if (w.wVersion != 0x0202) {
47     WSACleanup ();
48     GST_WARNING_OBJECT (obj, "Winsock version wrong : 0x%x", w.wVersion);
49     return FALSE;
50   }
51
52   return TRUE;
53 }
54
55 #endif
56
57 int
58 gst_udp_get_addr (const char *hostname, int port, struct sockaddr_storage *addr)
59 {
60   struct addrinfo hints, *res, *nres;
61   char service[NI_MAXSERV];
62   int ret;
63
64   memset (&hints, 0, sizeof (hints));
65   hints.ai_family = AF_UNSPEC;
66   hints.ai_socktype = SOCK_DGRAM;
67   snprintf (service, sizeof (service) - 1, "%d", port);
68   service[sizeof (service) - 1] = '\0';
69
70   if ((ret = getaddrinfo (hostname, (port == -1) ? NULL : service, &hints,
71               &res)) < 0) {
72     return ret;
73   }
74
75   nres = res;
76   while (nres) {
77     if (nres->ai_family == AF_INET || nres->ai_family == AF_INET6)
78       break;
79     nres = nres->ai_next;
80   }
81
82   if (nres) {
83     memcpy (addr, nres->ai_addr, nres->ai_addrlen);
84   } else {
85     errno = EAI_ADDRFAMILY;
86     ret = -1;
87   }
88   freeaddrinfo (res);
89
90   return ret;
91 }
92
93 int
94 gst_udp_join_group (int sockfd, gboolean loop, int ttl,
95     struct sockaddr_storage *addr)
96 {
97   int ret = -1;
98   int l = (loop == FALSE) ? 0 : 1;
99
100   switch (addr->ss_family) {
101     case AF_INET:
102     {
103       struct ip_mreq mreq4;
104
105       mreq4.imr_multiaddr.s_addr =
106           ((struct sockaddr_in *) addr)->sin_addr.s_addr;
107       mreq4.imr_interface.s_addr = INADDR_ANY;
108
109       if ((ret =
110               setsockopt (sockfd, IPPROTO_IP, IP_MULTICAST_LOOP, &l,
111                   sizeof (l))) < 0)
112         return ret;
113
114       if ((ret =
115               setsockopt (sockfd, IPPROTO_IP, IP_MULTICAST_TTL, &ttl,
116                   sizeof (ttl))) < 0)
117         return ret;
118
119       if ((ret =
120               setsockopt (sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
121                   (const void *) &mreq4, sizeof (mreq4))) < 0)
122         return ret;
123     }
124       break;
125
126     case AF_INET6:
127     {
128       struct ipv6_mreq mreq6;
129
130       memcpy (&mreq6.ipv6mr_multiaddr,
131           &(((struct sockaddr_in6 *) addr)->sin6_addr),
132           sizeof (struct in6_addr));
133       mreq6.ipv6mr_interface = 0;
134
135       if ((ret =
136               setsockopt (sockfd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &l,
137                   sizeof (l))) < 0)
138         return ret;
139
140       if ((ret =
141               setsockopt (sockfd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &ttl,
142                   sizeof (ttl))) < 0)
143         return ret;
144
145       if ((ret =
146               setsockopt (sockfd, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP,
147                   (const void *) &mreq6, sizeof (mreq6))) < 0)
148         return ret;
149     }
150       break;
151
152     default:
153       errno = EAFNOSUPPORT;
154   }
155
156   return ret;
157 }
158
159 int
160 gst_udp_leave_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_DROP_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_DROP_MEMBERSHIP,
191                   (const void *) &mreq6, sizeof (mreq6))) < 0)
192         return ret;
193     }
194       break;
195
196     default:
197       errno = EAFNOSUPPORT;
198   }
199
200   return ret;
201 }
202
203 int
204 gst_udp_is_multicast (struct sockaddr_storage *addr)
205 {
206   int ret = -1;
207
208   switch (addr->ss_family) {
209     case AF_INET:
210     {
211       struct sockaddr_in *addr4 = (struct sockaddr_in *) addr;
212
213       ret = IN_MULTICAST (ntohl (addr4->sin_addr.s_addr));
214     }
215       break;
216
217     case AF_INET6:
218     {
219       struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *) addr;
220
221       ret = IN6_IS_ADDR_MULTICAST (&addr6->sin6_addr);
222     }
223       break;
224
225     default:
226       errno = EAFNOSUPPORT;
227   }
228
229   return ret;
230 }