2 * This file is part of the Nice GLib ICE library.
4 * (C) 2008-2009 Collabora Ltd.
5 * Contact: Youness Alaoui
6 * (C) 2007-2009 Nokia Corporation. All rights reserved.
7 * Contact: Rémi Denis-Courmont
9 * The contents of this file are subject to the Mozilla Public License Version
10 * 1.1 (the "License"); you may not use this file except in compliance with
11 * the License. You may obtain a copy of the License at
12 * http://www.mozilla.org/MPL/
14 * Software distributed under the License is distributed on an "AS IS" basis,
15 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
16 * for the specific language governing rights and limitations under the
19 * The Original Code is the Nice GLib ICE library.
21 * The Initial Developers of the Original Code are Collabora Ltd and Nokia
22 * Corporation. All Rights Reserved.
25 * Youness Alaoui, Collabora Ltd.
26 * Rémi Denis-Courmont, Nokia
28 * Alternatively, the contents of this file may be used under the terms of the
29 * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which
30 * case the provisions of LGPL are applicable instead of those above. If you
31 * wish to allow use of your version of this file only under the terms of the
32 * LGPL and not to allow others to use your version of this file under the
33 * MPL, indicate your decision by deleting the provisions above and replace
34 * them with the notice and other provisions required by the LGPL. If you do
35 * not delete the provisions above, a recipient may use your version of this
36 * file under either the MPL or the LGPL.
54 #include <sys/types.h>
59 #include <sys/socket.h>
61 #include <netinet/in.h>
67 # define close(fd) _close(fd)
75 # define SOL_IP IPPROTO_IP
79 # define SOL_IPV6 IPPROTO_IPV6
83 #ifndef IPV6_RECVPKTINFO
84 # define IPV6_RECVPKTINFO IPV6_PKTINFO
87 /** Default port for STUN binding discovery */
88 #define IPPORT_STUN 3478
90 #include "stun/stunagent.h"
93 static const uint16_t known_attributes[] = {
98 * Creates a listening socket
100 int listen_socket (int fam, int type, int proto, unsigned int port)
103 int fd = socket (fam, type, proto);
105 struct sockaddr addr;
106 struct sockaddr_in in;
107 struct sockaddr_in6 in6;
108 struct sockaddr_storage storage;
113 perror ("Error opening IP port");
117 memset (&addr, 0, sizeof (addr));
118 addr.storage.ss_family = fam;
120 addr.storage.ss_len = sizeof (addr);
126 addr.in.sin_port = htons (port);
131 setsockopt (fd, SOL_IPV6, IPV6_V6ONLY, (const char *) &yes, sizeof (yes));
133 addr.in6.sin6_port = htons (port);
137 assert (0); /* should never be reached */
140 if (bind (fd, &addr.addr, sizeof (struct sockaddr_storage)))
142 perror ("Error opening IP port");
146 if ((type == SOCK_DGRAM) || (type == SOCK_RAW))
152 setsockopt (fd, SOL_IP, IP_RECVERR, (const char*) &yes, sizeof (yes));
158 setsockopt (fd, SOL_IPV6, IPV6_RECVERR, (const char*) &yes, sizeof (yes));
163 assert (0); /* should never be reached */
168 if (listen (fd, INT_MAX))
170 perror ("Error opening IP port");
182 static int dgram_process (int sock, StunAgent *oldagent, StunAgent *newagent)
185 struct sockaddr_storage storage;
186 struct sockaddr addr;
189 uint8_t buf[STUN_MAX_MESSAGE_SIZE];
193 StunMessage response;
194 StunValidationStatus validation;
195 StunAgent *agent = NULL;
197 addr_len = sizeof (struct sockaddr_storage);
198 len = recvfrom (sock, buf, sizeof(buf), 0, &addr.addr, &addr_len);
199 if (len == (size_t)-1)
202 validation = stun_agent_validate (newagent, &request, buf, len, NULL, 0);
204 if (validation == STUN_VALIDATION_SUCCESS) {
208 validation = stun_agent_validate (oldagent, &request, buf, len, NULL, 0);
212 /* Unknown attributes */
213 if (validation == STUN_VALIDATION_UNKNOWN_REQUEST_ATTRIBUTE)
215 buf_len = stun_agent_build_unknown_attributes_error (agent, &response, buf,
216 sizeof (buf), &request);
220 /* Mal-formatted packets */
221 if (validation != STUN_VALIDATION_SUCCESS ||
222 stun_message_get_class (&request) != STUN_REQUEST) {
226 switch (stun_message_get_method (&request))
229 stun_agent_init_response (agent, &response, buf, sizeof (buf), &request);
230 if (stun_message_has_cookie (&request))
231 stun_message_append_xor_addr (&response,
232 STUN_ATTRIBUTE_XOR_MAPPED_ADDRESS, &addr.storage, addr_len);
234 stun_message_append_addr (&response, STUN_ATTRIBUTE_MAPPED_ADDRESS,
235 &addr.addr, addr_len);
238 case STUN_SHARED_SECRET:
244 case STUN_CREATEPERMISSION:
245 case STUN_CHANNELBIND:
247 if (!stun_agent_init_error (agent, &response, buf, sizeof (buf),
248 &request, STUN_ERROR_BAD_REQUEST))
252 buf_len = stun_agent_finish_message (agent, &response, NULL, 0);
254 len = sendto (sock, buf, buf_len, 0, &addr.addr, addr_len);
255 return (len < buf_len) ? -1 : 0;
259 static int run (int family, int protocol, unsigned port)
263 int sock = listen_socket (family, SOCK_DGRAM, protocol, port);
267 stun_agent_init (&oldagent, known_attributes,
268 STUN_COMPATIBILITY_RFC3489, 0);
269 stun_agent_init (&newagent, known_attributes,
270 STUN_COMPATIBILITY_RFC5389, STUN_AGENT_USAGE_USE_FINGERPRINT);
273 dgram_process (sock, &oldagent, &newagent);
277 /* Pretty useless dummy signal handler...
278 * But calling exit() is needed for gcov to work properly. */
279 static void exit_handler (int signum)
286 int main (int argc, char *argv[])
288 int family = AF_INET;
289 unsigned port = IPPORT_STUN;
296 if (WSAStartup(MAKEWORD(2, 0), &wsadata) != 0) {
297 fprintf(stderr, "Could not start Winsock2");
304 for (i = 1; i < argc; ++i)
306 const char *arg = argv[i];
308 if (strcmp (arg, "-4") == 0)
312 else if (strcmp (arg, "-6") == 0)
316 else if (arg[0] < '0' || arg[0] > '9')
318 fprintf (stderr, "Unexpected command line argument '%s'", arg);
327 signal (SIGINT, exit_handler);
328 signal (SIGTERM, exit_handler);
329 return run (family, IPPROTO_UDP, port) ? EXIT_FAILURE : EXIT_SUCCESS;