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.
55 #include <sys/types.h>
58 #include <sys/socket.h>
60 #include <netinet/in.h>
67 # define SOL_IP IPPROTO_IP
71 # define SOL_IPV6 IPPROTO_IPV6
75 #ifndef IPV6_RECVPKTINFO
76 # define IPV6_RECVPKTINFO IPV6_PKTINFO
79 /** Default port for STUN binding discovery */
80 #define IPPORT_STUN 3478
82 #include "stun/stunagent.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
)
95 int fd
= socket (fam
, type
, proto
);
98 struct sockaddr_in in
;
99 struct sockaddr_in6 in6
;
100 struct sockaddr_storage storage
;
104 perror ("Error opening IP port");
110 memset (&addr
, 0, sizeof (addr
));
111 addr
.storage
.ss_family
= fam
;
113 addr
.storage
.ss_len
= sizeof (addr
);
119 addr
.in
.sin_port
= htons (port
);
124 setsockopt (fd
, SOL_IPV6
, IPV6_V6ONLY
, &yes
, sizeof (yes
));
126 addr
.in6
.sin6_port
= htons (port
);
130 if (bind (fd
, (struct sockaddr
*)&addr
, sizeof (struct sockaddr
)))
132 perror ("Error opening IP port");
136 if ((type
== SOCK_DGRAM
) || (type
== SOCK_RAW
))
142 setsockopt (fd
, SOL_IP
, IP_RECVERR
, &yes
, sizeof (yes
));
148 setsockopt (fd
, SOL_IPV6
, IPV6_RECVERR
, &yes
, sizeof (yes
));
155 if (listen (fd
, INT_MAX
))
157 perror ("Error opening IP port");
169 static int dgram_process (int sock
, StunAgent
*oldagent
, StunAgent
*newagent
)
171 struct sockaddr_storage addr
;
173 uint8_t buf
[STUN_MAX_MESSAGE_SIZE
];
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)
187 validation
= stun_agent_validate (newagent
, &request
, buf
, len
, NULL
, 0);
189 if (validation
== STUN_VALIDATION_SUCCESS
) {
193 validation
= stun_agent_validate (oldagent
, &request
, buf
, len
, NULL
, 0);
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
);
205 /* Mal-formatted packets */
206 if (validation
!= STUN_VALIDATION_SUCCESS
||
207 stun_message_get_class (&request
) != STUN_REQUEST
) {
211 switch (stun_message_get_method (&request
))
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
);
220 stun_message_append_addr (&response
, STUN_ATTRIBUTE_MAPPED_ADDRESS
,
221 (struct sockaddr
*)&addr
, addr_len
);
225 if (!stun_agent_init_error (agent
, &response
, buf
, sizeof (buf
),
226 &request
, STUN_ERROR_BAD_REQUEST
))
230 buf_len
= stun_agent_finish_message (agent
, &response
, NULL
, 0);
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
)
242 int sock
= listen_socket (family
, SOCK_DGRAM
, protocol
, port
);
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
);
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
)
265 int main (int argc
, char *argv
[])
267 int family
= AF_INET
;
268 unsigned port
= IPPORT_STUN
;
272 int c
= getopt (argc
, argv
, "46");
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
;
297 int main (int argc
, char **argv
) {