udp-turn-over-tcp.c 13.2 KB
Newer Older
1 2 3
/*
 * This file is part of the Nice GLib ICE library.
 *
4 5 6
 * (C) 2008-2009 Collabora Ltd.
 *  Contact: Youness Alaoui
 * (C) 2008-2009 Nokia Corporation. All rights reserved.
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (the "License"); you may not use this file except in compliance with
 * the License. You may obtain a copy of the License at
 * http://www.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * The Original Code is the Nice GLib ICE library.
 *
 * The Initial Developers of the Original Code are Collabora Ltd and Nokia
 * Corporation. All Rights Reserved.
 *
 * Contributors:
24
 *   Youness Alaoui, Collabora Ltd.
25 26 27 28 29 30 31 32 33 34 35 36 37
 *
 * Alternatively, the contents of this file may be used under the terms of the
 * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which
 * case the provisions of LGPL are applicable instead of those above. If you
 * wish to allow use of your version of this file only under the terms of the
 * LGPL and not to allow others to use your version of this file under the
 * MPL, indicate your decision by deleting the provisions above and replace
 * them with the notice and other provisions required by the LGPL. If you do
 * not delete the provisions above, a recipient may use your version of this
 * file under either the MPL or the LGPL.
 */

/*
38
 * Implementation of TCP relay socket interface using TCP Berkeley sockets. (See
39 40 41 42 43 44
 * http://en.wikipedia.org/wiki/Berkeley_sockets.)
 */
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

45
#include "udp-turn-over-tcp.h"
46
#include "agent-priv.h"
47

48 49 50 51
#include <string.h>
#include <errno.h>
#include <fcntl.h>

52 53 54
#ifndef G_OS_WIN32
#include <unistd.h>
#endif
55 56

typedef struct {
57
  NiceTurnSocketCompatibility compatibility;
58 59 60 61 62
  union {
    guint8 u8[65536];
    guint16 u16[32768];
  } recv_buf;
  gsize recv_buf_len;  /* in bytes */
63
  guint expecting_len;
64
  NiceSocket *base_socket;
65 66
} TurnTcpPriv;

67 68 69 70 71
typedef enum {
  MS_TURN_CONTROL_MESSAGE = 2,
  MS_TURN_END_TO_END_DATA = 3
} MsTurnPayloadType;

72
#define MAX_UDP_MESSAGE_SIZE 65535
73

74
#define MAGIC_COOKIE_OFFSET \
75 76
  STUN_MESSAGE_HEADER_LENGTH + STUN_MESSAGE_TYPE_LEN + \
  STUN_MESSAGE_LENGTH_LEN + sizeof(guint16)
77

78
static void socket_close (NiceSocket *sock);
79 80
static gint socket_recv_messages (NiceSocket *sock,
    NiceInputMessage *recv_messages, guint n_recv_messages);
81
static gint socket_send_messages (NiceSocket *sock, const NiceAddress *to,
82
    const NiceOutputMessage *messages, guint n_messages);
83 84
static gint socket_send_messages_reliable (NiceSocket *sock,
    const NiceAddress *to, const NiceOutputMessage *messages, guint n_messages);
85
static gboolean socket_is_reliable (NiceSocket *sock);
86 87 88
static gboolean socket_can_send (NiceSocket *sock, NiceAddress *addr);
static void socket_set_writable_callback (NiceSocket *sock,
    NiceSocketWritableCb callback, gpointer user_data);
89
static gboolean socket_is_based_on (NiceSocket *sock, NiceSocket *other);
90 91

NiceSocket *
92
nice_udp_turn_over_tcp_socket_new (NiceSocket *base_socket,
93 94 95 96 97 98 99 100 101
    NiceTurnSocketCompatibility compatibility)
{
  TurnTcpPriv *priv;
  NiceSocket *sock = g_slice_new0 (NiceSocket);
  sock->priv = priv = g_slice_new0 (TurnTcpPriv);

  priv->compatibility = compatibility;
  priv->base_socket = base_socket;

102
  sock->type = NICE_SOCKET_TYPE_UDP_TURN_OVER_TCP;
103 104
  sock->fileno = priv->base_socket->fileno;
  sock->addr = priv->base_socket->addr;
105
  sock->send_messages = socket_send_messages;
106
  sock->send_messages_reliable = socket_send_messages_reliable;
107
  sock->recv_messages = socket_recv_messages;
108
  sock->is_reliable = socket_is_reliable;
109 110
  sock->can_send = socket_can_send;
  sock->set_writable_callback = socket_set_writable_callback;
111
  sock->is_based_on = socket_is_based_on;
112 113 114 115 116 117 118 119 120 121 122 123 124 125 126
  sock->close = socket_close;

  return sock;
}


static void
socket_close (NiceSocket *sock)
{
  TurnTcpPriv *priv = sock->priv;

  if (priv->base_socket)
    nice_socket_free (priv->base_socket);

  g_slice_free(TurnTcpPriv, sock->priv);
127
  sock->priv = NULL;
128 129
}

130 131
static gssize
socket_recv_message (NiceSocket *sock, NiceInputMessage *recv_message)
132 133
{
  TurnTcpPriv *priv = sock->priv;
134
  gssize ret;
135
  guint padlen;
136 137
  GInputVector local_recv_buf;
  NiceInputMessage local_recv_message;
138

139 140
  /* Make sure socket has not been freed: */
  g_assert (sock->priv != NULL);
141

142
  if (priv->expecting_len == 0) {
143
    guint headerlen = 0;
144

145
    if (priv->compatibility == NICE_TURN_SOCKET_COMPATIBILITY_DRAFT9 ||
146 147
        priv->compatibility == NICE_TURN_SOCKET_COMPATIBILITY_RFC5766 ||
        priv->compatibility == NICE_TURN_SOCKET_COMPATIBILITY_OC2007)
148
      headerlen = 4;
149
    else if (priv->compatibility == NICE_TURN_SOCKET_COMPATIBILITY_GOOGLE)
150 151
      headerlen = 2;
    else
152 153
      return -1;

154 155 156 157 158 159 160 161
    local_recv_buf.buffer = priv->recv_buf.u8 + priv->recv_buf_len;
    local_recv_buf.size = headerlen - priv->recv_buf_len;
    local_recv_message.buffers = &local_recv_buf;
    local_recv_message.n_buffers = 1;
    local_recv_message.from = recv_message->from;
    local_recv_message.length = 0;

    ret = nice_socket_recv_messages (priv->base_socket, &local_recv_message, 1);
162
    if (ret < 0)
163 164
        return ret;

165
    priv->recv_buf_len += local_recv_message.length;
166

167
    if (priv->recv_buf_len < headerlen)
168 169
      return 0;

170 171
    if (priv->compatibility == NICE_TURN_SOCKET_COMPATIBILITY_DRAFT9 ||
        priv->compatibility == NICE_TURN_SOCKET_COMPATIBILITY_RFC5766) {
172 173
      guint16 magic = ntohs (*priv->recv_buf.u16);
      guint16 packetlen = ntohs (*(priv->recv_buf.u16 + 1));
174

175 176
      if (magic < 0x4000) {
        /* Its STUN */
177
        priv->expecting_len = 20 + packetlen;
178 179
      } else {
        /* Channel data */
180 181 182
        priv->expecting_len = 4 + packetlen;
      }
    }
183
    else if (priv->compatibility == NICE_TURN_SOCKET_COMPATIBILITY_GOOGLE) {
184 185
      guint compat_len = ntohs (*priv->recv_buf.u16);
      priv->expecting_len = compat_len;
186 187
      priv->recv_buf_len = 0;
    }
188 189 190 191 192 193 194 195 196
    else if (priv->compatibility == NICE_TURN_SOCKET_COMPATIBILITY_OC2007) {
      guint8 pt = *priv->recv_buf.u8;
      guint16 packetlen = ntohs (priv->recv_buf.u16[1]);

      if (pt != MS_TURN_CONTROL_MESSAGE &&
          pt != MS_TURN_END_TO_END_DATA) {
        /* Unexpected data, error in stream */
        return -1;
      }
197 198 199 200 201

      /* Keep the RFC4571 framing for the NiceAgent to unframe */
      priv->expecting_len = packetlen + sizeof(guint16);
      priv->recv_buf_len = sizeof(guint16);
      priv->recv_buf.u16[0] = priv->recv_buf.u16[1];
202
    }
203 204
  }

205
  if (priv->compatibility == NICE_TURN_SOCKET_COMPATIBILITY_DRAFT9 ||
206
      priv->compatibility == NICE_TURN_SOCKET_COMPATIBILITY_RFC5766)
207 208 209
    padlen = (priv->expecting_len % 4) ?  4 - (priv->expecting_len % 4) : 0;
  else
    padlen = 0;
210

211 212 213 214 215 216
  local_recv_buf.buffer = priv->recv_buf.u8 + priv->recv_buf_len;
  local_recv_buf.size = priv->expecting_len + padlen - priv->recv_buf_len;
  local_recv_message.buffers = &local_recv_buf;
  local_recv_message.n_buffers = 1;
  local_recv_message.from = recv_message->from;
  local_recv_message.length = 0;
217

218
  ret = nice_socket_recv_messages (priv->base_socket, &local_recv_message, 1);
219
  if (ret < 0)
220 221
      return ret;

222
  priv->recv_buf_len += local_recv_message.length;
223 224

  if (priv->recv_buf_len == priv->expecting_len + padlen) {
225 226 227 228
    /* FIXME: Eliminate this memcpy(). */
    ret = memcpy_buffer_to_input_message (recv_message,
        priv->recv_buf.u8, priv->recv_buf_len);

229 230
    priv->expecting_len = 0;
    priv->recv_buf_len = 0;
231

232
    return ret;
233 234 235 236 237
  }

  return 0;
}

238
static gint
239
socket_recv_messages (NiceSocket *nicesock,
240 241 242 243 244
    NiceInputMessage *recv_messages, guint n_recv_messages)
{
  guint i;
  gboolean error = FALSE;

245 246
  /* Make sure socket has not been freed: */
  g_assert (nicesock->priv != NULL);
247

248 249 250
  for (i = 0; i < n_recv_messages; i++) {
    gssize len;

251
    len = socket_recv_message (nicesock, &recv_messages[i]);
252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267
    recv_messages[i].length = MAX (len, 0);

    if (len < 0)
      error = TRUE;

    if (len <= 0)
      break;
  }

  /* Was there an error processing the first message? */
  if (error && i == 0)
    return -1;

  return i;
}

268
static gssize
269
socket_send_message (NiceSocket *sock, const NiceAddress *to,
270
    const NiceOutputMessage *message, gboolean reliable)
271
{
272
  TurnTcpPriv *priv = sock->priv;
273 274 275 276 277 278
  guint8 padbuf[3] = {0, 0, 0};
  GOutputVector *local_bufs;
  NiceOutputMessage local_message;
  guint j;
  gint ret;
  guint n_bufs;
279 280 281 282 283 284 285
  union {
    guint16 google_len;
    struct {
      guint8 pt;
      guint8 zero;
    } msoc;
  } header_buf;
286
  guint offset = 0;
287

288 289
  /* Make sure socket has not been freed: */
  g_assert (sock->priv != NULL);
290

291 292 293 294 295 296 297 298 299
  /* Count the number of buffers. */
  if (message->n_buffers == -1) {
    n_bufs = 0;

    for (j = 0; message->buffers[j].buffer != NULL; j++)
      n_bufs++;
  } else {
    n_bufs = message->n_buffers;
  }
300

301 302
  /* Allocate a new array of buffers, covering all the buffers in the input
   * @message, but with an additional one for a header and one for a footer. */
303
  local_bufs = g_alloca ((n_bufs + 1) * sizeof (GOutputVector));
304
  local_message.buffers = local_bufs;
305
  local_message.n_buffers = n_bufs + 1;
306

307
  if (priv->compatibility == NICE_TURN_SOCKET_COMPATIBILITY_GOOGLE) {
308
    header_buf.google_len = htons (output_message_get_size (message));
309
    local_bufs[0].buffer = &header_buf;
310
    local_bufs[0].size = sizeof (guint16);
311 312
    offset = 1;
  } else if (priv->compatibility == NICE_TURN_SOCKET_COMPATIBILITY_DRAFT9 ||
313
      priv->compatibility == NICE_TURN_SOCKET_COMPATIBILITY_RFC5766) {
314 315
    gsize message_len = output_message_get_size (message);
    gsize padlen = (message_len % 4) ? 4 - (message_len % 4) : 0;
316 317 318

    local_bufs[n_bufs].buffer = &padbuf;
    local_bufs[n_bufs].size = padlen;
319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356
  } else if (priv->compatibility == NICE_TURN_SOCKET_COMPATIBILITY_OC2007) {
    union {
      guint32 u32;
      guint8 u8[4];
    } cookie;
    guint16 len = output_message_get_size (message);

    /* Copy the cookie from possibly split messages */
    cookie.u32 = 0;
    if (len > sizeof (TURN_MAGIC_COOKIE) + MAGIC_COOKIE_OFFSET) {
      guint16 buf_offset = 0;
      guint i;

      for (i = 0; i < n_bufs; i++) {
        if (message->buffers[i].size >
            (gsize) (MAGIC_COOKIE_OFFSET - buf_offset)) {
          /* If the cookie is split, we assume it's data */
          if (message->buffers[i].size > sizeof (TURN_MAGIC_COOKIE) +
              MAGIC_COOKIE_OFFSET - buf_offset) {
            const guint8 *buf = message->buffers[i].buffer;
            memcpy (&cookie.u8, buf + MAGIC_COOKIE_OFFSET - buf_offset,
                sizeof (TURN_MAGIC_COOKIE));
          }
          break;
        } else {
          buf_offset += message->buffers[i].size;
        }
      }
    }

    cookie.u32 = ntohl(cookie.u32);
    header_buf.msoc.zero = 0;
    if (cookie.u32 == TURN_MAGIC_COOKIE)
      header_buf.msoc.pt = MS_TURN_CONTROL_MESSAGE;
    else
      header_buf.msoc.pt = MS_TURN_END_TO_END_DATA;

    local_bufs[0].buffer = &header_buf;
357
    local_bufs[0].size = sizeof(header_buf.msoc);
358
    offset = 1;
359
  } else {
360
    local_message.n_buffers = n_bufs;
361 362
  }

363 364 365 366 367 368 369
  /* Copy the existing buffers across. */
  for (j = 0; j < n_bufs; j++) {
    local_bufs[j + offset].buffer = message->buffers[j].buffer;
    local_bufs[j + offset].size = message->buffers[j].size;
  }


370 371 372 373 374
  if (reliable)
    ret = nice_socket_send_messages_reliable (priv->base_socket, to,
        &local_message, 1);
  else
    ret = nice_socket_send_messages (priv->base_socket, to, &local_message, 1);
375

376 377 378
  if (ret == 1)
    ret = output_message_get_size (&local_message);

379 380 381 382
  return ret;
}

static gint
383 384
socket_send_messages (NiceSocket *sock, const NiceAddress *to,
    const NiceOutputMessage *messages, guint n_messages)
385 386 387
{
  guint i;

388 389
  /* Make sure socket has not been freed: */
  g_assert (sock->priv != NULL);
390

391 392 393 394
  for (i = 0; i < n_messages; i++) {
    const NiceOutputMessage *message = &messages[i];
    gssize len;

395
    len = socket_send_message (sock, to, message, FALSE);
396 397 398

    if (len < 0) {
      /* Error. */
399 400
      if (i > 0)
        break;
401 402 403 404 405
      return len;
    } else if (len == 0) {
      /* EWOULDBLOCK. */
      break;
    }
406
  }
407

408
  return i;
409 410
}

411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431
static gint
socket_send_messages_reliable (NiceSocket *sock, const NiceAddress *to,
    const NiceOutputMessage *messages, guint n_messages)
{
  guint i;

  for (i = 0; i < n_messages; i++) {
    const NiceOutputMessage *message = &messages[i];
    gssize len;

    len = socket_send_message (sock, to, message, TRUE);

    if (len < 0) {
      /* Error. */
      return len;
    }
  }

  return i;
}

432

433 434 435
static gboolean
socket_is_reliable (NiceSocket *sock)
{
436 437 438
  TurnTcpPriv *priv = sock->priv;

  return nice_socket_is_reliable (priv->base_socket);
439 440
}

441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456
static gboolean
socket_can_send (NiceSocket *sock, NiceAddress *addr)
{
  TurnTcpPriv *priv = sock->priv;

  return nice_socket_can_send (priv->base_socket, addr);
}

static void
socket_set_writable_callback (NiceSocket *sock,
    NiceSocketWritableCb callback, gpointer user_data)
{
  TurnTcpPriv *priv = sock->priv;

  nice_socket_set_writable_callback (priv->base_socket, callback, user_data);
}
457 458

static gboolean
459
socket_is_based_on (NiceSocket *sock, NiceSocket *other)
460
{
461
  TurnTcpPriv *priv = sock->priv;
462

463 464
  return (sock == other) ||
      (priv && nice_socket_is_based_on (priv->base_socket, other));
465
}