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.
46 #include <sys/types.h>
47 #include <sys/socket.h>
48 #include <arpa/inet.h>
52 #include "stunagent.h"
54 /** ICE connectivity checks **/
59 stun_usage_ice_conncheck_create (StunAgent
*agent
, StunMessage
*msg
,
60 uint8_t *buffer
, size_t buffer_len
,
61 const uint8_t *username
, const size_t username_len
,
62 const uint8_t *password
, const size_t password_len
,
63 bool cand_use
, bool controlling
, uint32_t priority
,
64 uint64_t tie
, StunUsageIceCompatibility compatibility
)
66 StunMessageReturn val
;
68 stun_agent_init_request (agent
, msg
, buffer
, buffer_len
, STUN_BINDING
);
70 if (compatibility
== STUN_USAGE_ICE_COMPATIBILITY_DRAFT19
) {
73 val
= stun_message_append_flag (msg
, STUN_ATTRIBUTE_USE_CANDIDATE
);
74 if (val
!= STUN_MESSAGE_RETURN_SUCCESS
)
78 val
= stun_message_append32 (msg
, STUN_ATTRIBUTE_PRIORITY
, priority
);
79 if (val
!= STUN_MESSAGE_RETURN_SUCCESS
)
83 val
= stun_message_append64 (msg
, STUN_ATTRIBUTE_ICE_CONTROLLING
, tie
);
85 val
= stun_message_append64 (msg
, STUN_ATTRIBUTE_ICE_CONTROLLED
, tie
);
86 if (val
!= STUN_MESSAGE_RETURN_SUCCESS
)
90 if (username
&& username_len
> 0) {
91 val
= stun_message_append_bytes (msg
, STUN_ATTRIBUTE_USERNAME
,
92 username
, username_len
);
93 if (val
!= STUN_MESSAGE_RETURN_SUCCESS
)
97 return stun_agent_finish_message (agent
, msg
, password
, password_len
);
102 StunUsageIceReturn
stun_usage_ice_conncheck_process (StunMessage
*msg
,
103 struct sockaddr
*addr
, socklen_t
*addrlen
,
104 StunUsageIceCompatibility compatibility
)
107 StunMessageReturn val
;
109 if (stun_message_get_method (msg
) != STUN_BINDING
)
110 return STUN_USAGE_ICE_RETURN_RETRY
;
112 switch (stun_message_get_class (msg
))
115 case STUN_INDICATION
:
116 return STUN_USAGE_ICE_RETURN_RETRY
;
122 if (stun_message_find_error (msg
, &code
) != STUN_MESSAGE_RETURN_SUCCESS
) {
123 /* missing ERROR-CODE: ignore message */
124 return STUN_USAGE_ICE_RETURN_RETRY
;
127 if (code
== STUN_ERROR_ROLE_CONFLICT
)
128 return STUN_USAGE_ICE_RETURN_ROLE_CONFLICT
;
130 /* NOTE: currently we ignore unauthenticated messages if the context
131 * is authenticated, for security reasons. */
132 stun_debug (" STUN error message received (code: %d)\n", code
);
134 return STUN_USAGE_ICE_RETURN_ERROR
;
137 stun_debug ("Received %u-bytes STUN message\n", stun_message_length (msg
));
139 if (compatibility
== STUN_USAGE_ICE_COMPATIBILITY_MSN
) {
140 StunTransactionId transid
;
141 uint32_t magic_cookie
;
142 stun_message_id (msg
, transid
);
143 magic_cookie
= *((uint32_t *) transid
);
145 val
= stun_message_find_xor_addr_full (msg
,
146 STUN_ATTRIBUTE_XOR_MAPPED_ADDRESS
, addr
, addrlen
, htonl (magic_cookie
));
148 val
= stun_message_find_xor_addr (msg
,
149 STUN_ATTRIBUTE_XOR_MAPPED_ADDRESS
, addr
, addrlen
);
151 if (val
!= STUN_MESSAGE_RETURN_SUCCESS
)
153 stun_debug (" No XOR-MAPPED-ADDRESS: %d\n", val
);
154 val
= stun_message_find_addr (msg
,
155 STUN_ATTRIBUTE_MAPPED_ADDRESS
, addr
, addrlen
);
156 if (val
!= STUN_MESSAGE_RETURN_SUCCESS
)
158 stun_debug (" No MAPPED-ADDRESS: %d\n", val
);
159 return STUN_USAGE_ICE_RETURN_ERROR
;
163 stun_debug ("Mapped address found!\n");
164 return STUN_USAGE_ICE_RETURN_SUCCESS
;
168 stun_bind_error (StunAgent
*agent
, StunMessage
*msg
,
169 uint8_t *buf
, size_t *plen
, const StunMessage
*req
,
176 stun_debug ("STUN Error Reply (buffer size: %u)...\n", (unsigned)len
);
178 val
= stun_agent_init_error (agent
, msg
, buf
, len
, req
, code
);
182 len
= stun_agent_finish_message (agent
, msg
, NULL
, 0);
187 stun_debug (" Error response (%u) of %u bytes\n", (unsigned)code
,
193 stun_usage_ice_conncheck_create_reply (StunAgent
*agent
, StunMessage
*req
,
194 StunMessage
*msg
, uint8_t *buf
, size_t *plen
,
195 const struct sockaddr
*src
, socklen_t srclen
,
196 bool *control
, uint64_t tie
,
197 StunUsageIceCompatibility compatibility
)
199 const char *username
= NULL
;
200 uint16_t username_len
;
203 StunMessageReturn val
= STUN_MESSAGE_RETURN_SUCCESS
;
204 StunUsageIceReturn ret
= STUN_USAGE_ICE_RETURN_SUCCESS
;
207 #define err( code ) \
208 stun_bind_error (agent, msg, buf, &len, req, code); \
212 stun_debug ("STUN Reply (buffer size = %u)...\n", (unsigned)len
);
214 if (stun_message_get_class (req
) != STUN_REQUEST
)
216 stun_debug (" Unhandled non-request (class %u) message.\n",
217 stun_message_get_class (req
));
218 return STUN_USAGE_ICE_RETURN_INVALID_REQUEST
;
221 if (stun_message_get_method (req
) != STUN_BINDING
)
223 stun_debug (" Bad request (method %u) message.\n",
224 stun_message_get_method (req
));
225 err (STUN_ERROR_BAD_REQUEST
);
226 return STUN_USAGE_ICE_RETURN_INVALID_METHOD
;
229 /* Role conflict handling */
230 assert (control
!= NULL
);
231 if (stun_message_find64 (req
, *control
? STUN_ATTRIBUTE_ICE_CONTROLLING
232 : STUN_ATTRIBUTE_ICE_CONTROLLED
, &q
) == STUN_MESSAGE_RETURN_SUCCESS
)
234 stun_debug ("STUN Role Conflict detected:\n");
238 stun_debug (" switching role from \"controll%s\" to \"controll%s\"\n",
239 *control
? "ing" : "ed", *control
? "ed" : "ing");
240 *control
= !*control
;
241 ret
= STUN_USAGE_ICE_RETURN_ROLE_CONFLICT
;
245 stun_debug (" staying \"controll%s\" (sending error)\n",
246 *control
? "ing" : "ed");
247 err (STUN_ERROR_ROLE_CONFLICT
);
248 return STUN_USAGE_ICE_RETURN_SUCCESS
;
251 stun_debug ("STUN Role not specified by peer!\n");
254 if (stun_agent_init_response (agent
, msg
, buf
, len
, req
) == FALSE
) {
255 stun_debug ("Unable to create response\n");
258 if (compatibility
== STUN_USAGE_ICE_COMPATIBILITY_MSN
) {
259 StunTransactionId transid
;
260 uint32_t magic_cookie
;
261 stun_message_id (msg
, transid
);
262 magic_cookie
= *((uint32_t *) transid
);
264 val
= stun_message_append_xor_addr_full (msg
, STUN_ATTRIBUTE_XOR_MAPPED_ADDRESS
,
265 src
, srclen
, htonl (magic_cookie
));
266 } else if (stun_has_cookie (msg
)) {
267 val
= stun_message_append_xor_addr (msg
, STUN_ATTRIBUTE_XOR_MAPPED_ADDRESS
,
270 val
= stun_message_append_addr (msg
, STUN_ATTRIBUTE_MAPPED_ADDRESS
,
274 if (val
!= STUN_MESSAGE_RETURN_SUCCESS
) {
275 stun_debug (" Mapped address problem: %d\n", val
);
279 username
= (const char *)stun_message_find (req
,
280 STUN_ATTRIBUTE_USERNAME
, &username_len
);
282 val
= stun_message_append_bytes (msg
, STUN_ATTRIBUTE_USERNAME
,
283 username
, username_len
);
286 if (val
!= STUN_MESSAGE_RETURN_SUCCESS
) {
287 stun_debug ("Error appending username: %d\n", val
);
293 /* the stun agent will automatically use the password of the request */
294 len
= stun_agent_finish_message (agent
, msg
, NULL
, 0);
299 stun_debug (" All done (response size: %u)\n", (unsigned)len
);
304 stun_debug (" Fatal error formatting Response: %d\n", val
);
308 case STUN_MESSAGE_RETURN_NOT_ENOUGH_SPACE
:
309 return STUN_USAGE_ICE_RETURN_MEMORY_ERROR
;
310 case STUN_MESSAGE_RETURN_INVALID
:
311 case STUN_MESSAGE_RETURN_UNSUPPORTED_ADDRESS
:
312 return STUN_USAGE_ICE_RETURN_INVALID_ADDRESS
;
314 return STUN_USAGE_ICE_RETURN_ERROR
;
320 uint32_t stun_usage_ice_conncheck_priority (const StunMessage
*msg
)
324 if (stun_message_find32 (msg
, STUN_ATTRIBUTE_PRIORITY
, &value
)
325 != STUN_MESSAGE_RETURN_SUCCESS
)
331 bool stun_usage_ice_conncheck_use_candidate (const StunMessage
*msg
)
333 return (stun_message_find_flag (msg
,
334 STUN_ATTRIBUTE_USE_CANDIDATE
) == STUN_MESSAGE_RETURN_SUCCESS
);