504bd89bf7a4cc85a8b1d6e2efaef7415b5b0f3e
[platform/upstream/libnice.git] / stun / usages / bind.c
1 /*
2  * This file is part of the Nice GLib ICE library.
3  *
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
8  *
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/
13  *
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
17  * License.
18  *
19  * The Original Code is the Nice GLib ICE library.
20  *
21  * The Initial Developers of the Original Code are Collabora Ltd and Nokia
22  * Corporation. All Rights Reserved.
23  *
24  * Contributors:
25  *   Youness Alaoui, Collabora Ltd.
26  *   Rémi Denis-Courmont, Nokia
27  *
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.
37  */
38
39 #ifdef HAVE_CONFIG_H
40 # include <config.h>
41 #endif
42
43 #ifdef _WIN32
44 #include <winsock2.h>
45 #include <ws2tcpip.h>
46 #include "win32_common.h"
47 #define close closesocket
48 #else
49 #include <sys/types.h>
50 #include <sys/socket.h>
51 #include <netinet/in.h>
52 #include <stdint.h>
53 #include <stdbool.h>
54 #include <unistd.h>
55 #include <errno.h>
56 #include <sys/time.h>
57 #include <fcntl.h>
58 #endif
59
60
61 #ifdef HAVE_POLL
62 # include <poll.h>
63 #endif
64
65
66 #include "bind.h"
67 #include "stun/stunagent.h"
68
69 #include <assert.h>
70 #include <string.h>
71 #include <stdlib.h>
72 #include <time.h>
73 #include <errno.h>
74 #include "timer.h"
75
76
77 #ifndef SOL_IP
78 # define SOL_IP IPPROTO_IP
79 #endif
80
81 #ifndef SOL_IPV6
82 # define SOL_IPV6 IPPROTO_IPV6
83 #endif
84
85
86 /** Non-blocking mode STUN binding discovery */
87
88 size_t stun_usage_bind_create (StunAgent *agent, StunMessage *msg,
89     uint8_t *buffer, size_t buffer_len)
90 {
91   stun_agent_init_request (agent, msg, buffer, buffer_len, STUN_BINDING);
92
93   return stun_agent_finish_message (agent, msg, NULL, 0);
94 }
95
96 StunUsageBindReturn stun_usage_bind_process (StunMessage *msg,
97     struct sockaddr *addr, socklen_t *addrlen,
98     struct sockaddr *alternate_server, socklen_t *alternate_server_len)
99 {
100   int code = -1;
101   StunMessageReturn val;
102   union {
103     struct sockaddr *sa;
104     struct sockaddr_storage *sas;
105   } sa;
106
107   sa.sa = addr;
108
109   if (stun_message_get_method (msg) != STUN_BINDING)
110     return STUN_USAGE_BIND_RETURN_INVALID;
111
112   switch (stun_message_get_class (msg))
113   {
114     case STUN_REQUEST:
115     case STUN_INDICATION:
116       return STUN_USAGE_BIND_RETURN_INVALID;
117
118     case STUN_RESPONSE:
119       break;
120
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_BIND_RETURN_INVALID;
125       }
126
127       /* NOTE: currently we ignore unauthenticated messages if the context
128        * is authenticated, for security reasons. */
129       stun_debug (" STUN error message received (code: %d)", code);
130
131       /* ALTERNATE-SERVER mechanism */
132       if ((code / 100) == 3) {
133         union {
134           struct sockaddr *sa;
135           struct sockaddr_storage *sas;
136         } alternate_sa;
137
138         alternate_sa.sa = alternate_server;
139         if (alternate_server && alternate_server_len) {
140           if (stun_message_find_addr (msg, STUN_ATTRIBUTE_ALTERNATE_SERVER,
141                   alternate_sa.sas,
142                   alternate_server_len) != STUN_MESSAGE_RETURN_SUCCESS) {
143             stun_debug (" Unexpectedly missing ALTERNATE-SERVER attribute");
144             return STUN_USAGE_BIND_RETURN_ERROR;
145           }
146         } else {
147           if (!stun_message_has_attribute (msg, STUN_ATTRIBUTE_ALTERNATE_SERVER)) {
148             stun_debug (" Unexpectedly missing ALTERNATE-SERVER attribute");
149             return STUN_USAGE_BIND_RETURN_ERROR;
150           }
151         }
152
153         stun_debug ("Found alternate server");
154         return STUN_USAGE_BIND_RETURN_ALTERNATE_SERVER;
155
156       }
157       return STUN_USAGE_BIND_RETURN_ERROR;
158
159     default:
160       /* Fall through. */
161       break;
162   }
163
164   stun_debug ("Received %u-bytes STUN message", stun_message_length (msg));
165
166   val = stun_message_find_xor_addr (msg,
167       STUN_ATTRIBUTE_XOR_MAPPED_ADDRESS, sa.sas,
168       addrlen);
169   if (val != STUN_MESSAGE_RETURN_SUCCESS)
170   {
171     stun_debug (" No XOR-MAPPED-ADDRESS: %d", val);
172     val = stun_message_find_addr (msg,
173         STUN_ATTRIBUTE_MAPPED_ADDRESS, sa.sas,
174         addrlen);
175     if (val != STUN_MESSAGE_RETURN_SUCCESS)
176     {
177       stun_debug (" No MAPPED-ADDRESS: %d", val);
178       return STUN_USAGE_BIND_RETURN_ERROR;
179     }
180   }
181
182   stun_debug (" Mapped address found!");
183   return STUN_USAGE_BIND_RETURN_SUCCESS;
184
185 }
186
187
188 /** Binding keep-alive (Binding discovery indication!) */
189
190 size_t
191 stun_usage_bind_keepalive (StunAgent *agent, StunMessage *msg,
192     uint8_t *buf, size_t len)
193 {
194
195   stun_agent_init_indication (agent, msg,
196       buf, len, STUN_BINDING);
197   return stun_agent_finish_message (agent, msg, NULL, 0);
198 }
199
200
201
202 typedef struct stun_trans_s
203 {
204
205   int fd;
206   int own_fd;
207   socklen_t dstlen;
208   struct sockaddr_storage dst;
209 } StunTransport;
210
211
212 typedef enum {
213   STUN_USAGE_TRANS_RETURN_SUCCESS,
214   STUN_USAGE_TRANS_RETURN_ERROR,
215   STUN_USAGE_TRANS_RETURN_RETRY,
216   STUN_USAGE_TRANS_RETURN_INVALID_ADDRESS,
217   STUN_USAGE_TRANS_RETURN_UNSUPPORTED,
218 } StunUsageTransReturn;
219
220
221
222
223 static StunUsageTransReturn
224 stun_trans_init (StunTransport *tr, int fd,
225     const struct sockaddr *srv, socklen_t srvlen)
226 {
227   assert (fd != -1);
228
229   if ((size_t) srvlen > sizeof (tr->dst))
230     return STUN_USAGE_TRANS_RETURN_INVALID_ADDRESS;
231
232   tr->own_fd = -1;
233   tr->fd = fd;
234
235   tr->dstlen = srvlen;
236   memcpy (&tr->dst, srv, srvlen);
237
238   return STUN_USAGE_TRANS_RETURN_SUCCESS;
239 }
240
241
242 /*
243  * Creates and connects a socket. This is useful when a socket is to be used
244  * for multiple consecutive transactions (e.g. TURN).
245  */
246 static int stun_socket (int family, int type, int proto)
247 {
248 #ifdef _WIN32
249   unsigned long set_nonblock=1;
250 #endif
251
252   int fd = socket (family, type, proto);
253   if (fd == -1)
254     return -1;
255
256 #ifdef FD_CLOEXEC
257   fcntl (fd, F_SETFD, fcntl (fd, F_GETFD) | FD_CLOEXEC);
258 #endif
259 #ifdef O_NONBLOCK
260   fcntl (fd, F_SETFL, fcntl (fd, F_GETFL) | O_NONBLOCK);
261 #elif defined _WIN32
262   ioctlsocket(fd, FIONBIO, &set_nonblock);
263 #endif
264
265 #ifdef MSG_ERRQUEUE
266   if (type == SOCK_DGRAM)
267   {
268     /* Linux specifics for ICMP errors on non-connected sockets */
269     int yes = 1;
270     switch (family)
271     {
272       case AF_INET:
273         setsockopt (fd, SOL_IP, IP_RECVERR, &yes, sizeof (yes));
274         break;
275       case AF_INET6:
276         setsockopt (fd, SOL_IPV6, IPV6_RECVERR, &yes, sizeof (yes));
277         break;
278       default:
279         /* Nothing to do. */
280         break;
281     }
282   }
283 #endif
284
285   return fd;
286 }
287
288
289 static StunUsageTransReturn
290 stun_trans_create (StunTransport *tr, int type, int proto,
291     const struct sockaddr *srv, socklen_t srvlen)
292 {
293   StunUsageTransReturn val = STUN_USAGE_TRANS_RETURN_ERROR;
294   int fd;
295
296   if ((size_t) srvlen < sizeof(*srv))
297     return STUN_USAGE_TRANS_RETURN_INVALID_ADDRESS;
298
299   fd = stun_socket (srv->sa_family, type, proto);
300   if (fd == -1)
301     return STUN_USAGE_TRANS_RETURN_ERROR;
302
303   if (type != SOCK_DGRAM) {
304     if (connect (fd, srv, srvlen) &&
305 #ifdef _WIN32
306         (WSAGetLastError () != WSAEINPROGRESS)) {
307 #else
308       (errno != EINPROGRESS)) {
309 #endif
310       goto error;
311     }
312     val = stun_trans_init (tr, fd, NULL, 0);
313   } else {
314     val = stun_trans_init (tr, fd, srv, srvlen);
315   }
316
317   if (val)
318     goto error;
319
320   tr->own_fd = tr->fd;
321   return STUN_USAGE_TRANS_RETURN_SUCCESS;
322
323 error:
324   close (fd);
325   return val;
326 }
327
328
329 static void stun_trans_deinit (StunTransport *tr)
330 {
331   int saved = errno;
332
333   assert (tr->fd != -1);
334
335   if (tr->own_fd != -1)
336     close (tr->own_fd);
337
338   tr->own_fd = -1;
339   tr->fd = -1;
340
341   errno = saved;
342 }
343
344
345 #ifndef MSG_DONTWAIT
346 # define MSG_DONTWAIT 0
347 #endif
348 #ifndef MSG_NOSIGNAL
349 # define MSG_NOSIGNAL 0
350 #endif
351
352
353 static int stun_err_dequeue (int fd)
354 {
355 #ifdef MSG_ERRQUEUE
356   struct msghdr hdr;
357   int saved_errno = errno, ret;
358
359   memset (&hdr, 0, sizeof (hdr));
360   ret = (recvmsg (fd, &hdr, MSG_ERRQUEUE) >= 0);
361   errno = saved_errno;
362   return ret;
363 #else
364   (void) fd;
365   return 0;
366 #endif
367 }
368
369
370 static ssize_t
371 stun_trans_sendto (StunTransport *tr, const uint8_t *buf, size_t len,
372     const struct sockaddr *dst, socklen_t dstlen)
373 {
374   static const int flags = MSG_DONTWAIT | MSG_NOSIGNAL;
375   ssize_t val;
376
377   do
378   {
379     if (dstlen > 0)
380       val = sendto (tr->fd, (void *)buf, len, flags, dst, dstlen);
381     else
382       val = send (tr->fd, (void *)buf, len, flags);
383   }
384   while ((val == -1) && stun_err_dequeue (tr->fd));
385
386   return val;
387 }
388
389
390 static ssize_t
391 stun_trans_recvfrom (StunTransport *tr, uint8_t *buf, size_t maxlen,
392                        struct sockaddr_storage * dst,
393                        socklen_t * dstlen)
394 {
395   static const int flags = MSG_DONTWAIT | MSG_NOSIGNAL;
396   ssize_t val;
397
398   if (dstlen != NULL)
399     val = recvfrom (tr->fd, (void *)buf, maxlen, flags, (struct sockaddr *) dst,
400         dstlen);
401   else
402     val = recv (tr->fd, (void *)buf, maxlen, flags);
403
404   if (val == -1)
405     stun_err_dequeue (tr->fd);
406
407   return val;
408 }
409
410
411 static ssize_t
412 stun_trans_send (StunTransport *tr, const uint8_t *buf, size_t len)
413 {
414   struct sockaddr *conv;
415
416   conv = (struct sockaddr *) &tr->dst;
417
418   return stun_trans_sendto (tr, buf, len, conv, tr->dstlen);
419 }
420
421 static ssize_t
422 stun_trans_recv (StunTransport *tr, uint8_t *buf, size_t maxlen)
423 {
424   return stun_trans_recvfrom (tr, buf, maxlen, NULL, NULL);
425 }
426
427
428 #ifdef HAVE_POLL
429 static int stun_trans_fd (const StunTransport *tr)
430 {
431   assert (tr != NULL);
432   return tr->fd;
433 }
434 #endif
435
436
437 /*
438  * Waits for a response or timeout to occur.
439  *
440  * @return ETIMEDOUT if the transaction has timed out, or 0 if an incoming
441  * message needs to be processed.
442  */
443 static StunUsageTransReturn
444 stun_trans_poll (StunTransport *tr, unsigned int delay)
445 {
446 #ifdef HAVE_POLL
447   struct pollfd ufd;
448
449   memset (&ufd, 0, sizeof (ufd));
450   ufd.fd = stun_trans_fd (tr);
451
452   ufd.events |= POLLIN;
453
454   if (poll (&ufd, 1, delay) <= 0) {
455     return STUN_USAGE_TRANS_RETURN_RETRY;
456   }
457
458   return STUN_USAGE_TRANS_RETURN_SUCCESS;
459 #else
460   (void)tr;
461   return STUN_USAGE_TRANS_RETURN_UNSUPPORTED;
462 #endif
463 }
464
465
466
467 /** Blocking mode STUN binding discovery */
468 StunUsageBindReturn stun_usage_bind_run (const struct sockaddr *srv,
469     socklen_t srvlen, struct sockaddr_storage *addr, socklen_t *addrlen)
470 {
471   StunTimer timer;
472   StunTransport trans;
473   StunAgent agent;
474   StunMessage req;
475   uint8_t req_buf[STUN_MAX_MESSAGE_SIZE];
476   StunMessage msg;
477   uint8_t buf[STUN_MAX_MESSAGE_SIZE];
478   StunValidationStatus valid;
479   size_t len;
480   StunUsageTransReturn ret;
481   int val;
482   struct sockaddr_storage alternate_server = { AF_UNSPEC } ;
483   socklen_t alternate_server_len = sizeof (alternate_server);
484   StunUsageBindReturn bind_ret;
485
486   trans.fd = -1;
487
488   stun_agent_init (&agent, STUN_ALL_KNOWN_ATTRIBUTES,
489       STUN_COMPATIBILITY_RFC3489, 0);
490
491   len = stun_usage_bind_create (&agent, &req, req_buf, sizeof(req_buf));
492
493   ret = stun_trans_create (&trans, SOCK_DGRAM, 0, srv, srvlen);
494   if (ret != STUN_USAGE_TRANS_RETURN_SUCCESS) {
495     stun_debug ("STUN transaction failed: couldn't create transport.");
496     bind_ret = STUN_USAGE_BIND_RETURN_ERROR;
497     goto done;
498   }
499
500   val = stun_trans_send (&trans, req_buf, len);
501   if (val < -1) {
502     stun_debug ("STUN transaction failed: couldn't send request.");
503     bind_ret = STUN_USAGE_BIND_RETURN_ERROR;
504     goto done;
505   }
506
507   stun_timer_start (&timer, STUN_TIMER_DEFAULT_TIMEOUT,
508       STUN_TIMER_DEFAULT_MAX_RETRANSMISSIONS);
509   stun_debug ("STUN transaction started (timeout %dms).",
510       stun_timer_remainder (&timer));
511
512   do
513   {
514     for (;;) {
515       unsigned delay = stun_timer_remainder (&timer);
516       ret = stun_trans_poll (&trans, delay);
517       if (ret == STUN_USAGE_TRANS_RETURN_RETRY) {
518         switch (stun_timer_refresh (&timer)) {
519           case STUN_USAGE_TIMER_RETURN_TIMEOUT:
520             stun_debug ("STUN transaction failed: time out.");
521             bind_ret = STUN_USAGE_BIND_RETURN_TIMEOUT; // fatal error!
522             goto done;
523           case STUN_USAGE_TIMER_RETURN_RETRANSMIT:
524             stun_debug ("STUN transaction retransmitted (timeout %dms).",
525                 stun_timer_remainder (&timer));
526             val = stun_trans_send (&trans, req_buf, len);
527             if (val <  -1) {
528               stun_debug ("STUN transaction failed: couldn't resend request.");
529               bind_ret = STUN_USAGE_BIND_RETURN_ERROR;
530               goto done;
531             }
532             continue;
533           case STUN_USAGE_TIMER_RETURN_SUCCESS:
534           default:
535             /* Fall through. */
536             break;
537         }
538       }
539       val = stun_trans_recv (&trans, buf, sizeof (buf));
540       if (val >= 0) {
541         break;
542       }
543     }
544
545     valid = stun_agent_validate (&agent, &msg, buf, val, NULL, NULL);
546     if (valid == STUN_VALIDATION_UNKNOWN_ATTRIBUTE)
547     {
548       bind_ret = STUN_USAGE_BIND_RETURN_ERROR;
549       goto done;
550     }
551
552     if (valid != STUN_VALIDATION_SUCCESS) {
553       ret = STUN_USAGE_TRANS_RETURN_RETRY;
554     } else {
555       bind_ret = stun_usage_bind_process (&msg, (struct sockaddr *)  addr,
556           addrlen, (struct sockaddr *) &alternate_server, &alternate_server_len);
557       if (bind_ret == STUN_USAGE_BIND_RETURN_ALTERNATE_SERVER) {
558         stun_trans_deinit (&trans);
559
560         assert (alternate_server.ss_family != AF_UNSPEC);
561
562         ret = stun_trans_create (&trans, SOCK_DGRAM, 0,
563             (struct sockaddr *) &alternate_server, alternate_server_len);
564
565         if (ret != STUN_USAGE_TRANS_RETURN_SUCCESS) {
566           bind_ret = STUN_USAGE_BIND_RETURN_ERROR;
567           goto done;
568         }
569
570         val = stun_trans_send (&trans, req_buf, len);
571         if (val < -1)
572         {
573           bind_ret = STUN_USAGE_BIND_RETURN_ERROR;
574           goto done;
575         }
576
577         stun_timer_start (&timer, STUN_TIMER_DEFAULT_TIMEOUT,
578             STUN_TIMER_DEFAULT_MAX_RETRANSMISSIONS);
579         ret = STUN_USAGE_TRANS_RETURN_RETRY;
580       } else if (bind_ret ==  STUN_USAGE_BIND_RETURN_INVALID) {
581         ret = STUN_USAGE_TRANS_RETURN_RETRY;
582       } else {
583         break;
584       }
585     }
586   }
587   while (ret == STUN_USAGE_TRANS_RETURN_RETRY);
588
589 done:
590   if (trans.fd != -1)
591     stun_trans_deinit (&trans);
592
593   return bind_ret;
594 }