Change all stun_XXX_t enums/structs into StunXxx to have a common naming convention
[sipe-libnice.git] / stun / usages / ice.c
blob524900188ec394e60438087aebcf2e9230448fba
1 /*
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
15 * License.
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.
22 * Contributors:
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.
36 #ifdef HAVE_CONFIG_H
37 # include <config.h>
38 #endif
40 #include <string.h>
41 #include <assert.h>
43 #ifdef _WIN32
44 #include <winsock2.h>
45 #else
46 #include <sys/types.h>
47 #include <sys/socket.h>
48 #include <arpa/inet.h>
49 #endif
52 #include "stunagent.h"
54 /** ICE connectivity checks **/
55 #include "ice.h"
58 size_t
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) {
71 if (cand_use)
73 val = stun_message_append_flag (msg, STUN_ATTRIBUTE_USE_CANDIDATE);
74 if (val != STUN_MESSAGE_RETURN_SUCCESS)
75 return 0;
78 val = stun_message_append32 (msg, STUN_ATTRIBUTE_PRIORITY, priority);
79 if (val != STUN_MESSAGE_RETURN_SUCCESS)
80 return 0;
82 if (controlling)
83 val = stun_message_append64 (msg, STUN_ATTRIBUTE_ICE_CONTROLLING, tie);
84 else
85 val = stun_message_append64 (msg, STUN_ATTRIBUTE_ICE_CONTROLLED, tie);
86 if (val != STUN_MESSAGE_RETURN_SUCCESS)
87 return 0;
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)
94 return 0;
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)
106 int code = -1;
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))
114 case STUN_REQUEST:
115 case STUN_INDICATION:
116 return STUN_USAGE_ICE_RETURN_RETRY;
118 case STUN_RESPONSE:
119 break;
121 case STUN_ERROR:
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));
147 } else {
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;
167 static int
168 stun_bind_error (StunAgent *agent, StunMessage *msg,
169 uint8_t *buf, size_t *plen, const StunMessage *req,
170 StunError code)
172 size_t len = *plen;
173 int val;
175 *plen = 0;
176 stun_debug ("STUN Error Reply (buffer size: %u)...\n", (unsigned)len);
178 val = stun_agent_init_error (agent, msg, buf, len, req, code);
179 if (!val)
180 return val;
182 len = stun_agent_finish_message (agent, msg, NULL, 0);
183 if (len == 0)
184 return 0;
186 *plen = len;
187 stun_debug (" Error response (%u) of %u bytes\n", (unsigned)code,
188 (unsigned)*plen);
189 return 1;
192 StunUsageIceReturn
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;
201 size_t len = *plen;
202 uint64_t q;
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); \
209 *plen = len
211 *plen = 0;
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");
236 if (tie < q)
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;
243 else
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;
250 } else {
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");
256 goto failure;
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,
268 src, srclen);
269 } else {
270 val = stun_message_append_addr (msg, STUN_ATTRIBUTE_MAPPED_ADDRESS,
271 src, srclen);
274 if (val != STUN_MESSAGE_RETURN_SUCCESS) {
275 stun_debug (" Mapped address problem: %d\n", val);
276 goto failure;
279 username = (const char *)stun_message_find (req,
280 STUN_ATTRIBUTE_USERNAME, &username_len);
281 if (username) {
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);
288 goto failure;
293 /* the stun agent will automatically use the password of the request */
294 len = stun_agent_finish_message (agent, msg, NULL, 0);
295 if (len == 0)
296 goto failure;
298 *plen = len;
299 stun_debug (" All done (response size: %u)\n", (unsigned)len);
300 return ret;
302 failure:
303 assert (*plen == 0);
304 stun_debug (" Fatal error formatting Response: %d\n", val);
306 switch (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;
313 default:
314 return STUN_USAGE_ICE_RETURN_ERROR;
317 #undef err
320 uint32_t stun_usage_ice_conncheck_priority (const StunMessage *msg)
322 uint32_t value;
324 if (stun_message_find32 (msg, STUN_ATTRIBUTE_PRIORITY, &value)
325 != STUN_MESSAGE_RETURN_SUCCESS)
326 return 0;
327 return value;
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);