Change all stun_XXX_t enums/structs into StunXxx to have a common naming convention
[sipe-libnice.git] / stun / usages / bind.c
blobe1dd109a7b1b8e91dfd0677deabc23bef03cf969
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 #ifdef _WIN32
41 #include <winsock2.h>
42 #include "win32_common.h"
43 #else
44 #include <sys/types.h>
45 #include <sys/socket.h>
46 #include <stdbool.h>
47 #include <unistd.h>
48 #include <sys/time.h>
49 #endif
51 #include "bind.h"
52 #include "stun/stunagent.h"
54 #include <assert.h>
55 #include <string.h>
56 #include <stdlib.h>
57 #include <time.h>
58 #include <errno.h>
59 #include <fcntl.h>
60 #include "timer.h"
61 #include "trans.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)
78 int code = -1;
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))
86 case STUN_REQUEST:
87 case STUN_INDICATION:
88 return STUN_USAGE_BIND_RETURN_RETRY;
90 case STUN_RESPONSE:
91 break;
93 case STUN_ERROR:
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,
107 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;
112 } else {
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!) */
150 size_t
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)
164 StunTimer timer;
165 StunTransport trans;
166 StunAgent agent;
167 StunMessage req;
168 uint8_t req_buf[STUN_MAX_MESSAGE_SIZE];
169 StunMessage msg;
170 uint8_t buf[STUN_MAX_MESSAGE_SIZE];
171 StunValidationStatus valid;
172 size_t len;
173 StunUsageTransReturn ret;
174 int val;
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);
191 if (val < -1) {
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));
202 for (;;) {
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);
214 if (val < -1) {
215 stun_debug ("STUN transaction failed: couldn't resend request.\n");
216 return STUN_USAGE_BIND_RETURN_ERROR;
218 continue;
219 case STUN_USAGE_TIMER_RETURN_SUCCESS:
220 break;
223 val = stun_trans_recv (&trans, buf, sizeof (buf));
224 if (val >= 0) {
225 break;
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;
235 } else {
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);
249 if (val < -1)
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;
256 } else {
257 return bind_ret;
261 while (ret == STUN_USAGE_TRANS_RETURN_RETRY);
263 return STUN_USAGE_BIND_RETURN_SUCCESS;