~ubuntu-branches/debian/wheezy/libnice/wheezy

« back to all changes in this revision

Viewing changes to stun/usages/bind.c

  • Committer: Bazaar Package Importer
  • Author(s): Sjoerd Simons, Laurent Bigonville, Sjoerd Simons
  • Date: 2009-03-06 16:34:10 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20090306163410-f3zw3f2ow31nsj5r
Tags: 0.0.5-1
[ Laurent Bigonville ]
* debian/watch: Fix URL

[ Sjoerd Simons ]
* New Upstream Version
* Updates symbol and ship the stun header files

Show diffs side-by-side

added added

removed removed

Lines of Context:
39
39
 
40
40
#ifdef _WIN32
41
41
#include <winsock2.h>
 
42
#include <ws2tcpip.h>
42
43
#include "win32_common.h"
 
44
#define close closesocket
43
45
#else
44
46
#include <sys/types.h>
45
47
#include <sys/socket.h>
 
48
#include <netinet/in.h>
 
49
#include <stdint.h>
46
50
#include <stdbool.h>
47
51
#include <unistd.h>
 
52
#include <errno.h>
48
53
#include <sys/time.h>
49
54
#endif
50
55
 
 
56
 
 
57
#ifdef HAVE_POLL
 
58
# include <poll.h>
 
59
#endif
 
60
 
 
61
 
51
62
#include "bind.h"
52
63
#include "stun/stunagent.h"
53
64
 
58
69
#include <errno.h>
59
70
#include <fcntl.h>
60
71
#include "timer.h"
61
 
#include "trans.h"
 
72
 
 
73
 
62
74
 
63
75
 
64
76
/** Non-blocking mode STUN binding discovery */
75
87
    struct sockaddr *addr, socklen_t *addrlen,
76
88
    struct sockaddr *alternate_server, socklen_t *alternate_server_len)
77
89
{
78
 
  int val, code = -1;
 
90
  int code = -1;
 
91
  StunMessageReturn val;
79
92
 
80
93
  if (stun_message_get_method (msg) != STUN_BINDING)
81
 
    return STUN_USAGE_BIND_RETURN_RETRY;
 
94
    return STUN_USAGE_BIND_RETURN_INVALID;
82
95
 
83
96
  switch (stun_message_get_class (msg))
84
97
  {
85
98
    case STUN_REQUEST:
86
99
    case STUN_INDICATION:
87
 
      return STUN_USAGE_BIND_RETURN_RETRY;
 
100
      return STUN_USAGE_BIND_RETURN_INVALID;
88
101
 
89
102
    case STUN_RESPONSE:
90
103
      break;
91
104
 
92
105
    case STUN_ERROR:
93
 
      if (stun_message_find_error (msg, &code) != 0) {
 
106
      if (stun_message_find_error (msg, &code) != STUN_MESSAGE_RETURN_SUCCESS) {
94
107
        /* missing ERROR-CODE: ignore message */
95
 
        return STUN_USAGE_BIND_RETURN_RETRY;
 
108
        return STUN_USAGE_BIND_RETURN_INVALID;
96
109
      }
97
110
 
98
111
      /* NOTE: currently we ignore unauthenticated messages if the context
103
116
      if ((code / 100) == 3) {
104
117
        if (alternate_server && alternate_server_len) {
105
118
          if (stun_message_find_addr (msg, STUN_ATTRIBUTE_ALTERNATE_SERVER,
106
 
                  alternate_server, alternate_server_len)) {
 
119
                  alternate_server,
 
120
                  alternate_server_len) != STUN_MESSAGE_RETURN_SUCCESS) {
107
121
            stun_debug (" Unexpectedly missing ALTERNATE-SERVER attribute\n");
108
122
            return STUN_USAGE_BIND_RETURN_ERROR;
109
123
          }
125
139
 
126
140
  val = stun_message_find_xor_addr (msg,
127
141
      STUN_ATTRIBUTE_XOR_MAPPED_ADDRESS, addr, addrlen);
128
 
  if (val)
 
142
  if (val != STUN_MESSAGE_RETURN_SUCCESS)
129
143
  {
130
 
    stun_debug (" No XOR-MAPPED-ADDRESS: %s\n", strerror (val));
 
144
    stun_debug (" No XOR-MAPPED-ADDRESS: %d\n", val);
131
145
    val = stun_message_find_addr (msg,
132
146
        STUN_ATTRIBUTE_MAPPED_ADDRESS, addr, addrlen);
133
 
    if (val)
 
147
    if (val != STUN_MESSAGE_RETURN_SUCCESS)
134
148
    {
135
 
      stun_debug (" No MAPPED-ADDRESS: %s\n", strerror (val));
 
149
      stun_debug (" No MAPPED-ADDRESS: %d\n", val);
136
150
      return STUN_USAGE_BIND_RETURN_ERROR;
137
151
    }
138
152
  }
155
169
  return stun_agent_finish_message (agent, msg, NULL, 0);
156
170
}
157
171
 
 
172
 
 
173
 
 
174
typedef struct stun_trans_s
 
175
{
 
176
 
 
177
  int fd;
 
178
  int own_fd;
 
179
  socklen_t dstlen;
 
180
  struct sockaddr_storage dst;
 
181
} StunTransport;
 
182
 
 
183
 
 
184
typedef enum {
 
185
  STUN_USAGE_TRANS_RETURN_SUCCESS,
 
186
  STUN_USAGE_TRANS_RETURN_ERROR,
 
187
  STUN_USAGE_TRANS_RETURN_RETRY,
 
188
  STUN_USAGE_TRANS_RETURN_INVALID_ADDRESS,
 
189
  STUN_USAGE_TRANS_RETURN_UNSUPPORTED,
 
190
} StunUsageTransReturn;
 
191
 
 
192
 
 
193
 
 
194
 
 
195
static StunUsageTransReturn
 
196
stun_trans_init (StunTransport *tr, int fd,
 
197
    const struct sockaddr *srv, socklen_t srvlen)
 
198
{
 
199
  assert (fd != -1);
 
200
 
 
201
  if ((size_t) srvlen > sizeof (tr->dst))
 
202
    return STUN_USAGE_TRANS_RETURN_INVALID_ADDRESS;
 
203
 
 
204
  tr->own_fd = -1;
 
205
  tr->fd = fd;
 
206
 
 
207
  tr->dstlen = srvlen;
 
208
  memcpy (&tr->dst, srv, srvlen);
 
209
 
 
210
  return STUN_USAGE_TRANS_RETURN_SUCCESS;
 
211
}
 
212
 
 
213
 
 
214
/*
 
215
 * Creates and connects a socket. This is useful when a socket is to be used
 
216
 * for multiple consecutive transactions (e.g. TURN).
 
217
 */
 
218
static int stun_socket (int family, int type, int proto)
 
219
{
 
220
  int fd = socket (family, type, proto);
 
221
  if (fd == -1)
 
222
    return -1;
 
223
 
 
224
#ifdef FD_CLOEXEC
 
225
  fcntl (fd, F_SETFD, fcntl (fd, F_GETFD) | FD_CLOEXEC);
 
226
#endif
 
227
#ifdef O_NONBLOCK
 
228
  fcntl (fd, F_SETFL, fcntl (fd, F_GETFL) | O_NONBLOCK);
 
229
#endif
 
230
 
 
231
#ifdef MSG_ERRQUEUE
 
232
  if (type == SOCK_DGRAM)
 
233
  {
 
234
    /* Linux specifics for ICMP errors on non-connected sockets */
 
235
    int yes = 1;
 
236
    switch (family)
 
237
    {
 
238
      case AF_INET:
 
239
        setsockopt (fd, SOL_IP, IP_RECVERR, &yes, sizeof (yes));
 
240
        break;
 
241
      case AF_INET6:
 
242
        setsockopt (fd, SOL_IPV6, IPV6_RECVERR, &yes, sizeof (yes));
 
243
        break;
 
244
    }
 
245
  }
 
246
#endif
 
247
 
 
248
  return fd;
 
249
}
 
250
 
 
251
 
 
252
static StunUsageTransReturn
 
253
stun_trans_create (StunTransport *tr, int type, int proto,
 
254
    const struct sockaddr *srv, socklen_t srvlen)
 
255
{
 
256
  StunUsageTransReturn val = STUN_USAGE_TRANS_RETURN_ERROR;
 
257
  int fd;
 
258
 
 
259
  if ((size_t) srvlen < sizeof(*srv))
 
260
    return STUN_USAGE_TRANS_RETURN_INVALID_ADDRESS;
 
261
 
 
262
  fd = stun_socket (srv->sa_family, type, proto);
 
263
  if (fd == -1)
 
264
    return STUN_USAGE_TRANS_RETURN_ERROR;
 
265
 
 
266
  if (connect (fd, srv, srvlen) &&
 
267
#ifdef _WIN32
 
268
      (WSAGetLastError () != WSAEINPROGRESS)) {
 
269
#else
 
270
    (errno != EINPROGRESS)) {
 
271
#endif
 
272
    goto error;
 
273
  }
 
274
 
 
275
  val = stun_trans_init (tr, fd, NULL, 0);
 
276
  if (val)
 
277
    goto error;
 
278
 
 
279
  tr->own_fd = tr->fd;
 
280
  return STUN_USAGE_TRANS_RETURN_SUCCESS;
 
281
 
 
282
error:
 
283
  close (fd);
 
284
  return val;
 
285
}
 
286
 
 
287
 
 
288
static void stun_trans_deinit (StunTransport *tr)
 
289
{
 
290
  int saved = errno;
 
291
 
 
292
  assert (tr->fd != -1);
 
293
 
 
294
  if (tr->own_fd != -1)
 
295
    close (tr->own_fd);
 
296
 
 
297
  tr->own_fd = -1;
 
298
  tr->fd = -1;
 
299
 
 
300
  errno = saved;
 
301
}
 
302
 
 
303
 
 
304
#ifndef MSG_DONTWAIT
 
305
# define MSG_DONTWAIT 0
 
306
#endif
 
307
#ifndef MSG_NOSIGNAL
 
308
# define MSG_NOSIGNAL 0
 
309
#endif
 
310
 
 
311
 
 
312
static int stun_err_dequeue (int fd)
 
313
{
 
314
#ifdef MSG_ERRQUEUE
 
315
  struct msghdr hdr;
 
316
  int saved_errno = errno, ret;
 
317
 
 
318
  memset (&hdr, 0, sizeof (hdr));
 
319
  ret = (recvmsg (fd, &hdr, MSG_ERRQUEUE) >= 0);
 
320
  errno = saved_errno;
 
321
  return ret;
 
322
#else
 
323
  return 0;
 
324
#endif
 
325
}
 
326
 
 
327
 
 
328
static ssize_t
 
329
stun_trans_sendto (StunTransport *tr, const uint8_t *buf, size_t len,
 
330
                     const struct sockaddr *dst, socklen_t dstlen)
 
331
{
 
332
  static const int flags = MSG_DONTWAIT | MSG_NOSIGNAL;
 
333
  ssize_t val;
 
334
 
 
335
  do
 
336
  {
 
337
    if (dstlen > 0)
 
338
      val = sendto (tr->fd, (void *)buf, len, flags, dst, dstlen);
 
339
    else
 
340
      val = send (tr->fd, (void *)buf, len, flags);
 
341
  }
 
342
  while ((val == -1) && stun_err_dequeue (tr->fd));
 
343
 
 
344
  return val;
 
345
}
 
346
 
 
347
 
 
348
static ssize_t
 
349
stun_trans_recvfrom (StunTransport *tr, uint8_t *buf, size_t maxlen,
 
350
                       struct sockaddr * dst,
 
351
                       socklen_t * dstlen)
 
352
{
 
353
  static const int flags = MSG_DONTWAIT | MSG_NOSIGNAL;
 
354
  ssize_t val;
 
355
 
 
356
  if (dstlen != NULL)
 
357
    val = recvfrom (tr->fd, (void *)buf, maxlen, flags, dst, dstlen);
 
358
  else
 
359
    val = recv (tr->fd, (void *)buf, maxlen, flags);
 
360
 
 
361
  if (val == -1)
 
362
    stun_err_dequeue (tr->fd);
 
363
 
 
364
  return val;
 
365
}
 
366
 
 
367
 
 
368
static ssize_t
 
369
stun_trans_send (StunTransport *tr, const uint8_t *buf, size_t len)
 
370
{
 
371
  return stun_trans_sendto (tr, buf, len,
 
372
      (struct sockaddr *)&tr->dst, tr->dstlen);
 
373
}
 
374
 
 
375
static ssize_t
 
376
stun_trans_recv (StunTransport *tr, uint8_t *buf, size_t maxlen)
 
377
{
 
378
  return stun_trans_recvfrom (tr, buf, maxlen, NULL, NULL);
 
379
}
 
380
 
 
381
 
 
382
static int stun_trans_fd (const StunTransport *tr)
 
383
{
 
384
  assert (tr != NULL);
 
385
  return tr->fd;
 
386
}
 
387
 
 
388
 
 
389
/**
 
390
 * Waits for a response or timeout to occur.
 
391
 *
 
392
 * @return ETIMEDOUT if the transaction has timed out, or 0 if an incoming
 
393
 * message needs to be processed.
 
394
 */
 
395
static StunUsageTransReturn
 
396
stun_trans_poll (StunTransport *tr, unsigned int delay)
 
397
{
 
398
#ifdef HAVE_POLL
 
399
  struct pollfd ufd;
 
400
 
 
401
  memset (&ufd, 0, sizeof (ufd));
 
402
  ufd.fd = stun_trans_fd (tr);
 
403
 
 
404
  ufd.events |= POLLIN;
 
405
 
 
406
  if (poll (&ufd, 1, delay) <= 0) {
 
407
    return STUN_USAGE_TRANS_RETURN_RETRY;
 
408
  }
 
409
 
 
410
  return STUN_USAGE_TRANS_RETURN_SUCCESS;
 
411
#else
 
412
  (void)tr;
 
413
  return STUN_USAGE_TRANS_RETURN_UNSUPPORTED;
 
414
#endif
 
415
}
 
416
 
 
417
 
 
418
 
158
419
/** Blocking mode STUN binding discovery */
159
420
StunUsageBindReturn stun_usage_bind_run (const struct sockaddr *srv,
160
421
    socklen_t srvlen, struct sockaddr *addr, socklen_t *addrlen)
161
422
{
162
 
  stun_timer_t timer;
163
 
  stun_trans_t trans;
 
423
  StunTimer timer;
 
424
  StunTransport trans;
164
425
  StunAgent agent;
165
426
  StunMessage req;
166
427
  uint8_t req_buf[STUN_MAX_MESSAGE_SIZE];
168
429
  uint8_t buf[STUN_MAX_MESSAGE_SIZE];
169
430
  StunValidationStatus valid;
170
431
  size_t len;
171
 
  ssize_t ret;
 
432
  StunUsageTransReturn ret;
172
433
  int val;
173
434
  struct sockaddr_storage alternate_server;
174
435
  socklen_t alternate_server_len = sizeof (alternate_server);
180
441
  len = stun_usage_bind_create (&agent, &req, req_buf, sizeof(req_buf));
181
442
 
182
443
  ret = stun_trans_create (&trans, SOCK_DGRAM, 0, srv, srvlen);
183
 
  if (ret) {
184
 
    errno = ret;
 
444
  if (ret != STUN_USAGE_TRANS_RETURN_SUCCESS) {
185
445
    stun_debug ("STUN transaction failed: couldn't create transport.\n");
186
446
    return STUN_USAGE_BIND_RETURN_ERROR;
187
447
  }
201
461
    for (;;) {
202
462
      unsigned delay = stun_timer_remainder (&timer);
203
463
      ret = stun_trans_poll (&trans, delay);
204
 
      if (ret == EAGAIN) {
 
464
      if (ret == STUN_USAGE_TRANS_RETURN_RETRY) {
205
465
        switch (stun_timer_refresh (&timer)) {
206
 
          case -1:
 
466
          case STUN_USAGE_TIMER_RETURN_TIMEOUT:
207
467
            stun_debug ("STUN transaction failed: time out.\n");
208
468
            return STUN_USAGE_BIND_RETURN_TIMEOUT; // fatal error!
209
 
          case 0:
 
469
          case STUN_USAGE_TIMER_RETURN_RETRANSMIT:
210
470
            stun_debug ("STUN transaction retransmitted (timeout %dms).\n",
211
471
                stun_timer_remainder (&timer));
212
472
            val = stun_trans_send (&trans, req_buf, len);
214
474
              stun_debug ("STUN transaction failed: couldn't resend request.\n");
215
475
              return STUN_USAGE_BIND_RETURN_ERROR;
216
476
            }
217
 
            ret = EAGAIN;
218
477
            continue;
 
478
          case STUN_USAGE_TIMER_RETURN_SUCCESS:
 
479
            break;
219
480
        }
220
481
      }
221
482
      val = stun_trans_recv (&trans, buf, sizeof (buf));
229
490
      return STUN_USAGE_BIND_RETURN_ERROR;
230
491
 
231
492
    if (valid != STUN_VALIDATION_SUCCESS) {
232
 
      ret = EAGAIN;
 
493
      ret = STUN_USAGE_TRANS_RETURN_RETRY;
233
494
    } else {
234
495
      bind_ret = stun_usage_bind_process (&msg, addr, addrlen,
235
496
          (struct sockaddr *) &alternate_server, &alternate_server_len);
239
500
        ret = stun_trans_create (&trans, SOCK_DGRAM, 0,
240
501
            (struct sockaddr *) &alternate_server, alternate_server_len);
241
502
 
242
 
        if (ret) {
243
 
          errno = ret;
 
503
        if (ret != STUN_USAGE_TRANS_RETURN_SUCCESS) {
244
504
          return STUN_USAGE_BIND_RETURN_ERROR;
245
505
        }
246
506
 
249
509
          return STUN_USAGE_BIND_RETURN_ERROR;
250
510
 
251
511
        stun_timer_start (&timer);
252
 
        ret = EAGAIN;
253
 
      } else if (bind_ret ==  STUN_USAGE_BIND_RETURN_RETRY) {
254
 
        ret = EAGAIN;
 
512
        ret = STUN_USAGE_TRANS_RETURN_RETRY;
 
513
      } else if (bind_ret ==  STUN_USAGE_BIND_RETURN_INVALID) {
 
514
        ret = STUN_USAGE_TRANS_RETURN_RETRY;
255
515
      } else {
256
516
        return bind_ret;
257
517
      }
258
518
    }
259
519
  }
260
 
  while (ret == EAGAIN);
 
520
  while (ret == STUN_USAGE_TRANS_RETURN_RETRY);
261
521
 
262
522
  return STUN_USAGE_BIND_RETURN_SUCCESS;
263
523
}