Add win32 directory to EXTRA_DIST
[sipe-libnice.git] / stun / tools / stund.c
blobd340d194a15f20617f18ca483d50696c30c0bdf8
1 /*
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
17 * License.
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.
24 * Contributors:
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.
39 #ifdef HAVE_CONFIG_H
40 # include <config.h>
41 #endif
43 #ifdef __sun
44 #define _XPG4_2 1
45 #endif
47 #ifndef _WIN32
49 #include <stdio.h>
50 #include <stdint.h>
51 #include <string.h>
52 #include <stdlib.h>
53 #include <signal.h>
55 #include <sys/types.h>
58 #include <sys/socket.h>
59 #include <netdb.h>
60 #include <netinet/in.h>
62 #include <unistd.h>
63 #include <errno.h>
64 #include <limits.h>
66 #ifndef SOL_IP
67 # define SOL_IP IPPROTO_IP
68 #endif
70 #ifndef SOL_IPV6
71 # define SOL_IPV6 IPPROTO_IPV6
72 #endif
75 #ifndef IPV6_RECVPKTINFO
76 # define IPV6_RECVPKTINFO IPV6_PKTINFO
77 #endif
79 /** Default port for STUN binding discovery */
80 #define IPPORT_STUN 3478
82 #include "stun/stunagent.h"
83 #include "stund.h"
85 static const uint16_t known_attributes[] = {
90 * Creates a listening socket
92 int listen_socket (int fam, int type, int proto, unsigned int port)
94 int yes = 1;
95 int fd = socket (fam, type, proto);
96 union {
97 struct sockaddr addr;
98 struct sockaddr_in in;
99 struct sockaddr_in6 in6;
100 struct sockaddr_storage storage;
101 } addr;
102 if (fd == -1)
104 perror ("Error opening IP port");
105 return -1;
107 if (fd < 3)
108 goto error;
110 memset (&addr, 0, sizeof (addr));
111 addr.storage.ss_family = fam;
112 #ifdef HAVE_SA_LEN
113 addr.storage.ss_len = sizeof (addr);
114 #endif
116 switch (fam)
118 case AF_INET:
119 addr.in.sin_port = htons (port);
120 break;
122 case AF_INET6:
123 #ifdef IPV6_V6ONLY
124 setsockopt (fd, SOL_IPV6, IPV6_V6ONLY, &yes, sizeof (yes));
125 #endif
126 addr.in6.sin6_port = htons (port);
127 break;
130 if (bind (fd, (struct sockaddr *)&addr, sizeof (struct sockaddr)))
132 perror ("Error opening IP port");
133 goto error;
136 if ((type == SOCK_DGRAM) || (type == SOCK_RAW))
138 switch (fam)
140 case AF_INET:
141 #ifdef IP_RECVERR
142 setsockopt (fd, SOL_IP, IP_RECVERR, &yes, sizeof (yes));
143 #endif
144 break;
146 case AF_INET6:
147 #ifdef IPV6_RECVERR
148 setsockopt (fd, SOL_IPV6, IPV6_RECVERR, &yes, sizeof (yes));
149 #endif
150 break;
153 else
155 if (listen (fd, INT_MAX))
157 perror ("Error opening IP port");
158 goto error;
162 return fd;
164 error:
165 close (fd);
166 return -1;
169 static int dgram_process (int sock, StunAgent *oldagent, StunAgent *newagent)
171 struct sockaddr_storage addr;
172 socklen_t addr_len;
173 uint8_t buf[STUN_MAX_MESSAGE_SIZE];
174 size_t buf_len = 0;
175 size_t len = 0;
176 StunMessage request;
177 StunMessage response;
178 StunValidationStatus validation;
179 StunAgent *agent = NULL;
181 addr_len = sizeof (struct sockaddr_in);
182 len = recvfrom (sock, buf, sizeof(buf), 0,
183 (struct sockaddr *)&addr, &addr_len);
184 if (len == (size_t)-1)
185 return -1;
187 validation = stun_agent_validate (newagent, &request, buf, len, NULL, 0);
189 if (validation == STUN_VALIDATION_SUCCESS) {
190 agent = newagent;
192 else {
193 validation = stun_agent_validate (oldagent, &request, buf, len, NULL, 0);
194 agent = oldagent;
197 /* Unknown attributes */
198 if (validation == STUN_VALIDATION_UNKNOWN_REQUEST_ATTRIBUTE)
200 buf_len = stun_agent_build_unknown_attributes_error (agent, &response, buf,
201 sizeof (buf), &request);
202 goto send_buf;
205 /* Mal-formatted packets */
206 if (validation != STUN_VALIDATION_SUCCESS ||
207 stun_message_get_class (&request) != STUN_REQUEST) {
208 return -1;
211 switch (stun_message_get_method (&request))
213 case STUN_BINDING:
214 stun_agent_init_response (agent, &response, buf, sizeof (buf), &request);
215 if (stun_message_has_cookie (&request))
216 stun_message_append_xor_addr (&response,
217 STUN_ATTRIBUTE_XOR_MAPPED_ADDRESS,
218 (struct sockaddr *)&addr, addr_len);
219 else
220 stun_message_append_addr (&response, STUN_ATTRIBUTE_MAPPED_ADDRESS,
221 (struct sockaddr *)&addr, addr_len);
222 break;
224 default:
225 if (!stun_agent_init_error (agent, &response, buf, sizeof (buf),
226 &request, STUN_ERROR_BAD_REQUEST))
227 return -1;
230 buf_len = stun_agent_finish_message (agent, &response, NULL, 0);
231 send_buf:
232 len = sendto (sock, buf, buf_len, 0,
233 (struct sockaddr *)&addr, addr_len);
234 return (len < buf_len) ? -1 : 0;
238 static int run (int family, int protocol, unsigned port)
240 StunAgent oldagent;
241 StunAgent newagent;
242 int sock = listen_socket (family, SOCK_DGRAM, protocol, port);
243 if (sock == -1)
244 return -1;
246 stun_agent_init (&oldagent, known_attributes,
247 STUN_COMPATIBILITY_RFC3489, 0);
248 stun_agent_init (&newagent, known_attributes,
249 STUN_COMPATIBILITY_RFC5389, STUN_AGENT_USAGE_USE_FINGERPRINT);
251 for (;;)
252 dgram_process (sock, &oldagent, &newagent);
256 /* Pretty useless dummy signal handler...
257 * But calling exit() is needed for gcov to work properly. */
258 static void exit_handler (int signum)
260 (void)signum;
261 exit (0);
265 int main (int argc, char *argv[])
267 int family = AF_INET;
268 unsigned port = IPPORT_STUN;
270 for (;;)
272 int c = getopt (argc, argv, "46");
273 if (c == EOF)
274 break;
276 switch (c)
278 case '4':
279 family = AF_INET;
280 break;
282 case '6':
283 family = AF_INET6;
284 break;
288 if (optind < argc)
289 port = atoi (argv[optind++]);
291 signal (SIGINT, exit_handler);
292 signal (SIGTERM, exit_handler);
293 return run (family, IPPROTO_UDP, port) ? EXIT_FAILURE : EXIT_SUCCESS;
296 #else
297 int main (int argc, char **argv) {
298 return 0;
300 #endif