~ubuntu-branches/debian/squeeze/libnice/squeeze

« back to all changes in this revision

Viewing changes to socket/tcp-turn.c

  • Committer: Bazaar Package Importer
  • Author(s): Laurent Bigonville
  • Date: 2009-01-04 17:45:34 UTC
  • Revision ID: james.westby@ubuntu.com-20090104174534-dh5u1pfonumqa99c
Tags: upstream-0.0.4
Import upstream version 0.0.4

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * This file is part of the Nice GLib ICE library.
 
3
 *
 
4
 * (C) 2006-2008 Collabora Ltd.
 
5
 *  Contact: Dafydd Harries
 
6
 *  Contact: Olivier Crete
 
7
 * (C) 2006, 2007 Nokia Corporation. All rights reserved.
 
8
 *  Contact: Kai Vehmanen
 
9
 *
 
10
 * The contents of this file are subject to the Mozilla Public License Version
 
11
 * 1.1 (the "License"); you may not use this file except in compliance with
 
12
 * the License. You may obtain a copy of the License at
 
13
 * http://www.mozilla.org/MPL/
 
14
 *
 
15
 * Software distributed under the License is distributed on an "AS IS" basis,
 
16
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 
17
 * for the specific language governing rights and limitations under the
 
18
 * License.
 
19
 *
 
20
 * The Original Code is the Nice GLib ICE library.
 
21
 *
 
22
 * The Initial Developers of the Original Code are Collabora Ltd and Nokia
 
23
 * Corporation. All Rights Reserved.
 
24
 *
 
25
 * Contributors:
 
26
 *   Dafydd Harries, Collabora Ltd.
 
27
 *   Olivier Crete, Collabora Ltd.
 
28
 *   Rémi Denis-Courmont, Nokia
 
29
 *   Kai Vehmanen
 
30
 *
 
31
 * Alternatively, the contents of this file may be used under the terms of the
 
32
 * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which
 
33
 * case the provisions of LGPL are applicable instead of those above. If you
 
34
 * wish to allow use of your version of this file only under the terms of the
 
35
 * LGPL and not to allow others to use your version of this file under the
 
36
 * MPL, indicate your decision by deleting the provisions above and replace
 
37
 * them with the notice and other provisions required by the LGPL. If you do
 
38
 * not delete the provisions above, a recipient may use your version of this
 
39
 * file under either the MPL or the LGPL.
 
40
 */
 
41
 
 
42
/*
 
43
 * Implementation of TCP relay socket interface using TCP Berkeley sockets. (See
 
44
 * http://en.wikipedia.org/wiki/Berkeley_sockets.)
 
45
 */
 
46
#ifdef HAVE_CONFIG_H
 
47
# include "config.h"
 
48
#endif
 
49
 
 
50
#include "tcp-turn.h"
 
51
 
 
52
#include <string.h>
 
53
#include <errno.h>
 
54
#include <fcntl.h>
 
55
 
 
56
#ifndef G_OS_WIN32
 
57
#include <unistd.h>
 
58
#endif
 
59
 
 
60
typedef struct {
 
61
  NiceTurnSocketCompatibility compatibility;
 
62
  gchar recv_buf[65536];
 
63
  guint recv_buf_len;
 
64
  guint expecting_len;
 
65
  NiceSocket *base_socket;
 
66
} TurnTcpPriv;
 
67
 
 
68
 
 
69
static void socket_close (NiceSocket *sock);
 
70
static gint socket_recv (NiceSocket *sock, NiceAddress *from,
 
71
    guint len, gchar *buf);
 
72
static gboolean socket_send (NiceSocket *sock, const NiceAddress *to,
 
73
    guint len, const gchar *buf);
 
74
static gboolean socket_is_reliable (NiceSocket *sock);
 
75
 
 
76
NiceSocket *
 
77
nice_tcp_turn_socket_new (NiceAgent *agent, NiceSocket *base_socket,
 
78
    NiceTurnSocketCompatibility compatibility)
 
79
{
 
80
  TurnTcpPriv *priv;
 
81
  NiceSocket *sock = g_slice_new0 (NiceSocket);
 
82
  sock->priv = priv = g_slice_new0 (TurnTcpPriv);
 
83
 
 
84
  priv->compatibility = compatibility;
 
85
  priv->base_socket = base_socket;
 
86
 
 
87
  sock->fileno = priv->base_socket->fileno;
 
88
  sock->addr = priv->base_socket->addr;
 
89
  sock->send = socket_send;
 
90
  sock->recv = socket_recv;
 
91
  sock->is_reliable = socket_is_reliable;
 
92
  sock->close = socket_close;
 
93
 
 
94
  return sock;
 
95
}
 
96
 
 
97
 
 
98
static void
 
99
socket_close (NiceSocket *sock)
 
100
{
 
101
  TurnTcpPriv *priv = sock->priv;
 
102
 
 
103
  if (priv->base_socket)
 
104
    nice_socket_free (priv->base_socket);
 
105
 
 
106
  g_slice_free(TurnTcpPriv, sock->priv);
 
107
}
 
108
 
 
109
 
 
110
static gint
 
111
socket_recv (NiceSocket *sock, NiceAddress *from, guint len, gchar *buf)
 
112
{
 
113
  TurnTcpPriv *priv = sock->priv;
 
114
  int ret;
 
115
  guint padlen;
 
116
 
 
117
  if (priv->expecting_len == 0) {
 
118
    guint headerlen = 0;
 
119
 
 
120
    if (priv->compatibility == NICE_TURN_SOCKET_COMPATIBILITY_DRAFT9)
 
121
      headerlen = 4;
 
122
    else if (priv->compatibility == NICE_TURN_SOCKET_COMPATIBILITY_GOOGLE)
 
123
      headerlen = 2;
 
124
    else
 
125
      return -1;
 
126
 
 
127
    ret = nice_socket_recv (priv->base_socket, from,
 
128
        headerlen - priv->recv_buf_len, priv->recv_buf + priv->recv_buf_len);
 
129
    if (ret < 0)
 
130
        return ret;
 
131
 
 
132
    priv->recv_buf_len += ret;
 
133
 
 
134
    if (priv->recv_buf_len < headerlen)
 
135
      return 0;
 
136
 
 
137
    if (priv->compatibility == NICE_TURN_SOCKET_COMPATIBILITY_DRAFT9) {
 
138
      guint16 magic = ntohs (*(guint16*)priv->recv_buf);
 
139
      guint16 packetlen = ntohs (*(guint16*)(priv->recv_buf + 2));
 
140
 
 
141
      if (magic < 0x4000) {
 
142
        /* Its STUN */
 
143
        priv->expecting_len = 20 + packetlen;
 
144
      } else {
 
145
        /* Channel data */
 
146
        priv->expecting_len = 4 + packetlen;
 
147
      }
 
148
    }
 
149
    else if (priv->compatibility == NICE_TURN_SOCKET_COMPATIBILITY_GOOGLE) {
 
150
      guint len = ntohs (*(guint16*)priv->recv_buf);
 
151
      priv->expecting_len = len;
 
152
      priv->recv_buf_len = 0;
 
153
    }
 
154
  }
 
155
 
 
156
  if (priv->compatibility == NICE_TURN_SOCKET_COMPATIBILITY_DRAFT9)
 
157
    padlen = (priv->expecting_len % 4) ?  4 - (priv->expecting_len % 4) : 0;
 
158
  else
 
159
    padlen = 0;
 
160
 
 
161
  ret = nice_socket_recv (priv->base_socket, from,
 
162
      priv->expecting_len + padlen - priv->recv_buf_len,
 
163
      priv->recv_buf + priv->recv_buf_len);
 
164
 
 
165
  if (ret < 0)
 
166
      return ret;
 
167
 
 
168
  priv->recv_buf_len += ret;
 
169
 
 
170
  if (priv->recv_buf_len == priv->expecting_len + padlen) {
 
171
    guint copy_len = MIN (len, priv->recv_buf_len);
 
172
    memcpy (buf, priv->recv_buf, copy_len);
 
173
    priv->expecting_len = 0;
 
174
    priv->recv_buf_len = 0;
 
175
 
 
176
    return copy_len;
 
177
  }
 
178
 
 
179
  return 0;
 
180
}
 
181
 
 
182
static gboolean
 
183
socket_send (NiceSocket *sock, const NiceAddress *to,
 
184
    guint len, const gchar *buf)
 
185
{
 
186
  gboolean ret = TRUE;
 
187
  TurnTcpPriv *priv = sock->priv;
 
188
  gchar padbuf[3] = {0, 0, 0};
 
189
  int padlen = (len%4) ? 4 - (len%4) : 0;
 
190
 
 
191
  if (priv->compatibility != NICE_TURN_SOCKET_COMPATIBILITY_DRAFT9)
 
192
    padlen = 0;
 
193
 
 
194
  if (priv->compatibility == NICE_TURN_SOCKET_COMPATIBILITY_GOOGLE) {
 
195
    guint16 tmpbuf = htons (len);
 
196
    ret = nice_socket_send (priv->base_socket, to,
 
197
        sizeof(guint16), (gchar *)&tmpbuf);
 
198
 
 
199
    if (!ret)
 
200
      return ret;
 
201
  }
 
202
 
 
203
  ret = nice_socket_send (priv->base_socket, to, len, buf);
 
204
 
 
205
  if (!ret)
 
206
    return ret;
 
207
 
 
208
  if (priv->compatibility == NICE_TURN_SOCKET_COMPATIBILITY_DRAFT9)
 
209
    ret = nice_socket_send (priv->base_socket, to, padlen, padbuf);
 
210
 
 
211
  return ret;
 
212
}
 
213
 
 
214
 
 
215
static gboolean
 
216
socket_is_reliable (NiceSocket *sock)
 
217
{
 
218
  return TRUE;
 
219
}
 
220