tcp-turn.c 11.2 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
/*
 * This file is part of the Nice GLib ICE library.
 *
 * (C) 2006-2008 Collabora Ltd.
 *  Contact: Dafydd Harries
 *  Contact: Olivier Crete
 * (C) 2006, 2007 Nokia Corporation. All rights reserved.
 *  Contact: Kai Vehmanen
 *
 * 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:
 *   Dafydd Harries, Collabora Ltd.
 *   Olivier Crete, Collabora Ltd.
 *   Rémi Denis-Courmont, Nokia
 *   Kai Vehmanen
 *
 * 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.
 */

/*
43
 * Implementation of TCP relay socket interface using TCP Berkeley sockets. (See
44 45 46 47 48 49
 * http://en.wikipedia.org/wiki/Berkeley_sockets.)
 */
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

50 51
#include "tcp-turn.h"

52 53 54 55
#include <string.h>
#include <errno.h>
#include <fcntl.h>

56 57 58
#ifndef G_OS_WIN32
#include <unistd.h>
#endif
59 60 61 62 63 64 65

typedef struct {
  NiceUdpTurnSocketCompatibility compatibility;
  GQueue send_queue;
  gchar recv_buf[65536];
  guint recv_buf_len;
  guint expecting_len;
66
  NiceAddress server_addr;
67 68 69
  GMainContext *context;
  GIOChannel *io_channel;
  GSource *io_source;
70 71 72 73 74 75 76
} TurnTcpPriv;

struct to_be_sent {
  guint length;
  gchar *buf;
};

77
/*** NiceSocket ***/
78 79 80

static gint
socket_recv (
81
  NiceSocket *sock,
82 83 84 85 86 87
  NiceAddress *from,
  guint len,
  gchar *buf)
{
  TurnTcpPriv *priv = sock->priv;
  int ret;
88
  guint padlen;
89 90

  if (priv->expecting_len == 0) {
91
    guint headerlen = 0;
92 93 94 95 96 97 98 99

    if (priv->compatibility == NICE_UDP_TURN_SOCKET_COMPATIBILITY_DRAFT9)
      headerlen = 4;
    else if (priv->compatibility == NICE_UDP_TURN_SOCKET_COMPATIBILITY_GOOGLE)
      headerlen = 2;
    else
      g_assert_not_reached();

100 101
    ret = recv (sock->fileno, priv->recv_buf + priv->recv_buf_len,
        headerlen - priv->recv_buf_len, 0);
102
    if (ret < 0) {
103 104 105
#ifdef G_OS_WIN32
      if (WSAGetLastError () == WSAEWOULDBLOCK)
#else
106
      if (errno == EAGAIN)
107
#endif
108 109 110 111 112 113 114
        return 0;
      else
        return ret;
    }

    priv->recv_buf_len += ret;

115
    if (priv->recv_buf_len < headerlen)
116 117 118 119 120 121
      return 0;

    if (priv->compatibility == NICE_UDP_TURN_SOCKET_COMPATIBILITY_DRAFT9) {
      guint16 magic = ntohs (*(guint16*)priv->recv_buf);
      guint16 packetlen = ntohs (*(guint16*)(priv->recv_buf + 2));

122 123
      if (magic < 0x4000) {
        /* Its STUN */
124
        priv->expecting_len = 20 + packetlen;
125 126
      } else {
        /* Channel data */
127 128 129 130 131 132 133 134 135 136
        priv->expecting_len = 4 + packetlen;
      }
    }
    else if (priv->compatibility == NICE_UDP_TURN_SOCKET_COMPATIBILITY_GOOGLE) {
      guint len = ntohs (*(guint16*)priv->recv_buf);
      priv->expecting_len = len;
      priv->recv_buf_len = 0;
    }
  }

137 138 139 140
  if (priv->compatibility == NICE_UDP_TURN_SOCKET_COMPATIBILITY_DRAFT9)
    padlen = (priv->expecting_len % 4) ?  4 - (priv->expecting_len % 4) : 0;
  else
    padlen = 0;
141

142 143
  ret = recv (sock->fileno, priv->recv_buf + priv->recv_buf_len,
      priv->expecting_len + padlen - priv->recv_buf_len, 0);
144
  if (ret < 0) {
145 146 147
#ifdef G_OS_WIN32
    if (WSAGetLastError () == WSAEWOULDBLOCK)
#else
148
    if (errno == EAGAIN)
149
#endif
150 151 152 153 154 155 156 157 158 159 160 161
      return 0;
    else
      return ret;
  }

  priv->recv_buf_len += ret;

  if (priv->recv_buf_len == priv->expecting_len + padlen) {
    guint copy_len = MIN (len, priv->recv_buf_len);
    memcpy (buf, priv->recv_buf, copy_len);
    priv->expecting_len = 0;
    priv->recv_buf_len = 0;
162 163
    if (from)
      *from = priv->server_addr;
164 165 166 167 168 169
    return copy_len;
  }

  return 0;
}
static void
170
add_to_be_sent (NiceSocket *sock, const gchar *buf, guint len, gboolean head);
171 172 173 174 175 176 177 178 179 180



/*
 * Returns:
 * -1 = error
 * 0 = have more to send
 * 1 = sent everything
 */

181 182 183 184 185 186
static gboolean
socket_send_more (
  GIOChannel *source,
  G_GNUC_UNUSED
  GIOCondition condition,
  gpointer data)
187
{
188
  NiceSocket *sock = (NiceSocket *) data;
189 190 191 192 193 194
  TurnTcpPriv *priv = sock->priv;
  struct to_be_sent *tbs = NULL;

  while ((tbs = g_queue_pop_head (&priv->send_queue))) {
    int ret;

195
    ret = send (sock->fileno, tbs->buf, tbs->length, 0);
196

197
    if (ret < 0) {
198 199 200
#ifdef G_OS_WIN32
      if (WSAGetLastError () == WSAEWOULDBLOCK) {
#else
201
      if (errno == EAGAIN) {
202
#endif
203
        add_to_be_sent (sock, tbs->buf, tbs->length, TRUE);
204 205 206
        g_free (tbs->buf);
        g_slice_free (struct to_be_sent, tbs);
        break;
207 208 209
      }
    } else if (ret < (int) tbs->length) {
      add_to_be_sent (sock, tbs->buf + ret, tbs->length - ret, TRUE);
210 211 212
      g_free (tbs->buf);
      g_slice_free (struct to_be_sent, tbs);
      break;
213 214
    }

215
    g_free (tbs->buf);
216 217 218
    g_slice_free (struct to_be_sent, tbs);
  }

219 220 221 222 223 224 225 226 227 228
  if (g_queue_is_empty (&priv->send_queue)) {
    g_io_channel_unref (priv->io_channel);
    priv->io_channel = NULL;
    g_source_destroy (priv->io_source);
    g_source_unref (priv->io_source);
    priv->io_source = NULL;
    return FALSE;
  }

  return TRUE;
229 230
}

231 232 233 234 235 236 237

static void
add_to_be_sent (NiceSocket *sock, const gchar *buf, guint len, gboolean head)
{
  TurnTcpPriv *priv = sock->priv;
  struct to_be_sent *tbs = g_slice_new (struct to_be_sent);

238 239 240
  if (len <= 0)
    return;

241 242 243 244 245 246 247
  tbs->buf = g_memdup (buf, len);
  tbs->length = len;
  if (head)
    g_queue_push_head (&priv->send_queue, tbs);
  else
    g_queue_push_tail (&priv->send_queue, tbs);

248 249 250 251 252 253 254
  if (priv->io_channel == NULL) {
    priv->io_channel = g_io_channel_unix_new (sock->fileno);
    priv->io_source = g_io_create_watch (priv->io_channel, G_IO_OUT);
    g_source_set_callback (priv->io_source, (GSourceFunc) socket_send_more,
        sock, NULL);
    g_source_attach (priv->io_source, priv->context);
  }
255 256 257
}


258 259
static gboolean
socket_send (
260
  NiceSocket *sock,
261 262 263 264 265 266
  const NiceAddress *to,
  guint len,
  const gchar *buf)
{
  int ret;
  TurnTcpPriv *priv = sock->priv;
267 268 269 270 271
  gchar padbuf[3] = {0, 0, 0};
  int padlen = (len%4) ? 4 - (len%4) : 0;

  if (priv->compatibility != NICE_UDP_TURN_SOCKET_COMPATIBILITY_DRAFT9)
    padlen = 0;
272

273 274
  /* First try to send the data, don't send it later if it can be sent now
     this way we avoid allocating memory on every send */
275 276 277
  if (g_queue_is_empty (&priv->send_queue)) {
    if (priv->compatibility == NICE_UDP_TURN_SOCKET_COMPATIBILITY_GOOGLE) {
      guint16 tmpbuf = htons (len);
278
      ret = send (sock->fileno, (void *) &tmpbuf, sizeof(guint16), 0);
279 280

      if (ret < 0) {
281 282 283
#ifdef G_OS_WIN32
        if (WSAGetLastError () == WSAEWOULDBLOCK) {
#else
284
        if (errno == EAGAIN) {
285 286
#endif
          add_to_be_sent (sock, (gchar *) &tmpbuf, sizeof(guint16), FALSE);
287 288 289 290 291 292
          add_to_be_sent (sock, buf, len, FALSE);
          return TRUE;
        } else {
          return FALSE;
        }
      } else if ((guint)ret < sizeof(guint16)) {
293
        add_to_be_sent (sock, ((gchar *) &tmpbuf) + ret,
294
            sizeof(guint16) - ret, FALSE);
295
        add_to_be_sent (sock, buf, len, FALSE);
296 297 298 299
        return TRUE;
      }
    }

300
    ret = send (sock->fileno, buf, len, 0);
301

302
    if (ret < 0) {
303 304 305
#ifdef G_OS_WIN32
      if (WSAGetLastError () == WSAEWOULDBLOCK) {
#else
306
      if (errno == EAGAIN) {
307
#endif
308
        add_to_be_sent (sock, buf, len, FALSE);
309
        add_to_be_sent (sock, padbuf, padlen, FALSE);
310 311 312 313
        return TRUE;
      } else {
        return FALSE;
      }
314 315
    } else if ((guint)ret < len) {
      add_to_be_sent (sock, buf + ret, len - ret, FALSE);
316
      add_to_be_sent (sock, padbuf, padlen, FALSE);
317
      return TRUE;
318
    }
319 320 321 322

    if (priv->compatibility == NICE_UDP_TURN_SOCKET_COMPATIBILITY_DRAFT9 &&
        len % 4) {

323
      ret = send (sock->fileno, padbuf, padlen, 0);
324 325

      if (ret < 0) {
326 327 328
#ifdef G_OS_WIN32
        if (WSAGetLastError () == WSAEWOULDBLOCK) {
#else
329
        if (errno == EAGAIN) {
330
#endif
331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346
          add_to_be_sent (sock, padbuf, padlen, FALSE);
          return TRUE;
        } else {
          return FALSE;
        }
      } else if (ret < padlen) {
        add_to_be_sent (sock, padbuf, padlen - ret, FALSE);
        return TRUE;
      }
    }
  } else {
    if (priv->compatibility == NICE_UDP_TURN_SOCKET_COMPATIBILITY_GOOGLE) {
      guint16 tmpbuf = htons (len);
      add_to_be_sent (sock, (gchar*) &tmpbuf, sizeof(guint16), FALSE);
    }
    add_to_be_sent (sock, buf, len, FALSE);
347
    add_to_be_sent (sock, padbuf, padlen, FALSE);
348 349 350 351 352 353 354 355 356 357 358 359 360
  }

  return TRUE;
}

static void
free_to_be_sent (struct to_be_sent *tbs)
{
  g_free (tbs->buf);
  g_slice_free (struct to_be_sent, tbs);
}

static void
361
socket_close (NiceSocket *sock)
362 363 364 365 366
{
  TurnTcpPriv *priv = sock->priv;
  close (sock->fileno);
  g_queue_foreach (&priv->send_queue, (GFunc) free_to_be_sent, NULL);
  g_queue_clear (&priv->send_queue);
367 368 369
  g_io_channel_unref (priv->io_channel);
  g_source_destroy (priv->io_source);
  g_source_unref (priv->io_source);
370 371 372
  g_slice_free(TurnTcpPriv, sock->priv);
}

373 374 375 376 377 378
static gboolean
socket_is_reliable (NiceSocket *sock)
{
  return TRUE;
}

379

380 381 382
NiceSocket *
nice_tcp_turn_socket_new (
    NiceAgent *agent,
383
    GMainContext *ctx,
384 385
    NiceAddress *addr,
    NiceUdpTurnSocketCompatibility compatibility)
386 387
{
  int sockfd = -1;
388
  int ret;
389 390
  struct sockaddr_storage name;
  guint name_len = sizeof (name);
391
  NiceSocket *sock = g_slice_new0 (NiceSocket);
392 393
  TurnTcpPriv *priv;

394 395 396 397 398 399
  if (addr != NULL) {
    nice_address_copy_to_sockaddr(addr, (struct sockaddr *)&name);
  } else {
    memset (&name, 0, sizeof (name));
    name.ss_family = AF_UNSPEC;
  }
400

401 402 403 404 405
  if ((sockfd == -1) &&
      ((name.ss_family == AF_UNSPEC) ||
          (name.ss_family == AF_INET))) {
    sockfd = socket (PF_INET, SOCK_STREAM, 0);
    name.ss_family = AF_INET;
406
#ifdef HAVE_SA_LEN
407
    name.ss_len = sizeof (struct sockaddr_in);
408
#endif
409
  }
410

411 412 413 414
  if (sockfd == -1) {
    g_slice_free (NiceSocket, sock);
    return NULL;
  }
415 416 417 418 419 420 421 422 423

#ifdef FD_CLOEXEC
  fcntl (sockfd, F_SETFD, fcntl (sockfd, F_GETFD) | FD_CLOEXEC);
#endif
#ifdef O_NONBLOCK
  fcntl (sockfd, F_SETFL, fcntl (sockfd, F_GETFL) | O_NONBLOCK);
#endif


424
  ret = connect (sockfd, (const struct sockaddr *)&name, name_len);
425

426 427 428
#ifdef G_OS_WIN32
  if (ret < 0 && WSAGetLastError () != WSAEINPROGRESS) {
#else
429
  if (ret < 0 && errno != EINPROGRESS) {
430
#endif
431
    close (sockfd);
432 433
    g_slice_free (NiceSocket, sock);
    return NULL;
434 435 436 437 438
  }

  sock->priv = priv = g_slice_new0 (TurnTcpPriv);

  priv->compatibility = compatibility;
439
  priv->server_addr = *addr;
440
  priv->context = ctx;
441 442 443 444

  sock->fileno = sockfd;
  sock->send = socket_send;
  sock->recv = socket_recv;
445
  sock->is_reliable = socket_is_reliable;
446 447
  sock->close = socket_close;

448
  return sock;
449
}