2 * This file is part of the Nice GLib ICE library.
4 * (C) 2007 Nokia Corporation. All rights reserved.
5 * Contact: Rémi Denis-Courmont
7 * The contents of this file are subject to the Mozilla Public License Version
8 * 1.1 (the "License"); you may not use this file except in compliance with
9 * the License. You may obtain a copy of the License at
10 * http://www.mozilla.org/MPL/
12 * Software distributed under the License is distributed on an "AS IS" basis,
13 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
14 * for the specific language governing rights and limitations under the
17 * The Original Code is the Nice GLib ICE library.
19 * The Initial Developers of the Original Code are Collabora Ltd and Nokia
20 * Corporation. All Rights Reserved.
23 * Rémi Denis-Courmont, Nokia
25 * Alternatively, the contents of this file may be used under the terms of the
26 * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which
27 * case the provisions of LGPL are applicable instead of those above. If you
28 * wish to allow use of your version of this file only under the terms of the
29 * LGPL and not to allow others to use your version of this file under the
30 * MPL, indicate your decision by deleting the provisions above and replace
31 * them with the notice and other provisions required by the LGPL. If you do
32 * not delete the provisions above, a recipient may use your version of this
33 * file under either the MPL or the LGPL.
42 #include "win32_common.h"
44 #include <sys/types.h>
45 #include <sys/socket.h>
52 #include "stun/stunagent.h"
64 /** Non-blocking mode STUN binding discovery */
66 size_t stun_usage_bind_create (StunAgent
*agent
, StunMessage
*msg
,
67 uint8_t *buffer
, size_t buffer_len
)
69 stun_agent_init_request (agent
, msg
, buffer
, buffer_len
, STUN_BINDING
);
71 return stun_agent_finish_message (agent
, msg
, NULL
, 0);
74 StunUsageBindReturn
stun_usage_bind_process (StunMessage
*msg
,
75 struct sockaddr
*addr
, socklen_t
*addrlen
,
76 struct sockaddr
*alternate_server
, socklen_t
*alternate_server_len
)
79 StunMessageReturn val
;
81 if (stun_message_get_method (msg
) != STUN_BINDING
)
82 return STUN_USAGE_BIND_RETURN_RETRY
;
84 switch (stun_message_get_class (msg
))
88 return STUN_USAGE_BIND_RETURN_RETRY
;
94 if (stun_message_find_error (msg
, &code
) != STUN_MESSAGE_RETURN_SUCCESS
) {
95 /* missing ERROR-CODE: ignore message */
96 return STUN_USAGE_BIND_RETURN_RETRY
;
99 /* NOTE: currently we ignore unauthenticated messages if the context
100 * is authenticated, for security reasons. */
101 stun_debug (" STUN error message received (code: %d)\n", code
);
103 /* ALTERNATE-SERVER mechanism */
104 if ((code
/ 100) == 3) {
105 if (alternate_server
&& alternate_server_len
) {
106 if (stun_message_find_addr (msg
, STUN_ATTRIBUTE_ALTERNATE_SERVER
,
108 alternate_server_len
) != STUN_MESSAGE_RETURN_SUCCESS
) {
109 stun_debug (" Unexpectedly missing ALTERNATE-SERVER attribute\n");
110 return STUN_USAGE_BIND_RETURN_ERROR
;
113 if (!stun_message_has_attribute (msg
, STUN_ATTRIBUTE_ALTERNATE_SERVER
)) {
114 stun_debug (" Unexpectedly missing ALTERNATE-SERVER attribute\n");
115 return STUN_USAGE_BIND_RETURN_ERROR
;
119 stun_debug ("Found alternate server\n");
120 return STUN_USAGE_BIND_RETURN_ALTERNATE_SERVER
;
123 return STUN_USAGE_BIND_RETURN_ERROR
;
126 stun_debug ("Received %u-bytes STUN message\n", stun_message_length (msg
));
128 val
= stun_message_find_xor_addr (msg
,
129 STUN_ATTRIBUTE_XOR_MAPPED_ADDRESS
, addr
, addrlen
);
130 if (val
!= STUN_MESSAGE_RETURN_SUCCESS
)
132 stun_debug (" No XOR-MAPPED-ADDRESS: %d\n", val
);
133 val
= stun_message_find_addr (msg
,
134 STUN_ATTRIBUTE_MAPPED_ADDRESS
, addr
, addrlen
);
135 if (val
!= STUN_MESSAGE_RETURN_SUCCESS
)
137 stun_debug (" No MAPPED-ADDRESS: %d\n", val
);
138 return STUN_USAGE_BIND_RETURN_ERROR
;
142 stun_debug (" Mapped address found!\n");
143 return STUN_USAGE_BIND_RETURN_SUCCESS
;
148 /** Binding keep-alive (Binding discovery indication!) */
151 stun_usage_bind_keepalive (StunAgent
*agent
, StunMessage
*msg
,
152 uint8_t *buf
, size_t len
)
155 stun_agent_init_indication (agent
, msg
,
156 buf
, len
, STUN_BINDING
);
157 return stun_agent_finish_message (agent
, msg
, NULL
, 0);
160 /** Blocking mode STUN binding discovery */
161 StunUsageBindReturn
stun_usage_bind_run (const struct sockaddr
*srv
,
162 socklen_t srvlen
, struct sockaddr
*addr
, socklen_t
*addrlen
)
168 uint8_t req_buf
[STUN_MAX_MESSAGE_SIZE
];
170 uint8_t buf
[STUN_MAX_MESSAGE_SIZE
];
171 StunValidationStatus valid
;
173 StunUsageTransReturn ret
;
175 struct sockaddr_storage alternate_server
;
176 socklen_t alternate_server_len
= sizeof (alternate_server
);
177 StunUsageBindReturn bind_ret
;
179 stun_agent_init (&agent
, STUN_ALL_KNOWN_ATTRIBUTES
,
180 STUN_COMPATIBILITY_RFC3489
, 0);
182 len
= stun_usage_bind_create (&agent
, &req
, req_buf
, sizeof(req_buf
));
184 ret
= stun_trans_create (&trans
, SOCK_DGRAM
, 0, srv
, srvlen
);
185 if (ret
!= STUN_USAGE_TRANS_RETURN_SUCCESS
) {
186 stun_debug ("STUN transaction failed: couldn't create transport.\n");
187 return STUN_USAGE_BIND_RETURN_ERROR
;
190 val
= stun_trans_send (&trans
, req_buf
, len
);
192 stun_debug ("STUN transaction failed: couldn't send request.\n");
193 return STUN_USAGE_BIND_RETURN_ERROR
;
196 stun_timer_start (&timer
);
197 stun_debug ("STUN transaction started (timeout %dms).\n",
198 stun_timer_remainder (&timer
));
203 unsigned delay
= stun_timer_remainder (&timer
);
204 ret
= stun_trans_poll (&trans
, delay
);
205 if (ret
== STUN_USAGE_TRANS_RETURN_RETRY
) {
206 switch (stun_timer_refresh (&timer
)) {
207 case STUN_USAGE_TIMER_RETURN_TIMEOUT
:
208 stun_debug ("STUN transaction failed: time out.\n");
209 return STUN_USAGE_BIND_RETURN_TIMEOUT
; // fatal error!
210 case STUN_USAGE_TIMER_RETURN_RETRANSMIT
:
211 stun_debug ("STUN transaction retransmitted (timeout %dms).\n",
212 stun_timer_remainder (&timer
));
213 val
= stun_trans_send (&trans
, req_buf
, len
);
215 stun_debug ("STUN transaction failed: couldn't resend request.\n");
216 return STUN_USAGE_BIND_RETURN_ERROR
;
219 case STUN_USAGE_TIMER_RETURN_SUCCESS
:
223 val
= stun_trans_recv (&trans
, buf
, sizeof (buf
));
229 valid
= stun_agent_validate (&agent
, &msg
, buf
, val
, NULL
, NULL
);
230 if (valid
== STUN_VALIDATION_UNKNOWN_ATTRIBUTE
)
231 return STUN_USAGE_BIND_RETURN_ERROR
;
233 if (valid
!= STUN_VALIDATION_SUCCESS
) {
234 ret
= STUN_USAGE_TRANS_RETURN_RETRY
;
236 bind_ret
= stun_usage_bind_process (&msg
, addr
, addrlen
,
237 (struct sockaddr
*) &alternate_server
, &alternate_server_len
);
238 if (bind_ret
== STUN_USAGE_BIND_RETURN_ALTERNATE_SERVER
) {
239 stun_trans_deinit (&trans
);
241 ret
= stun_trans_create (&trans
, SOCK_DGRAM
, 0,
242 (struct sockaddr
*) &alternate_server
, alternate_server_len
);
244 if (ret
!= STUN_USAGE_TRANS_RETURN_SUCCESS
) {
245 return STUN_USAGE_BIND_RETURN_ERROR
;
248 val
= stun_trans_send (&trans
, req_buf
, len
);
250 return STUN_USAGE_BIND_RETURN_ERROR
;
252 stun_timer_start (&timer
);
253 ret
= STUN_USAGE_TRANS_RETURN_RETRY
;
254 } else if (bind_ret
== STUN_USAGE_BIND_RETURN_RETRY
) {
255 ret
= STUN_USAGE_TRANS_RETURN_RETRY
;
261 while (ret
== STUN_USAGE_TRANS_RETURN_RETRY
);
263 return STUN_USAGE_BIND_RETURN_SUCCESS
;