Version 0.1.0
[sipe-libnice.git] / socket / tcp-turn.c
blob97778497a693d79ef6d97c5aa2d25ce48319d9fb
1 /*
2 * This file is part of the Nice GLib ICE library.
4 * (C) 2008-2009 Collabora Ltd.
5 * Contact: Youness Alaoui
6 * (C) 2008-2009 Nokia Corporation. All rights reserved.
8 * The contents of this file are subject to the Mozilla Public License Version
9 * 1.1 (the "License"); you may not use this file except in compliance with
10 * the License. You may obtain a copy of the License at
11 * http://www.mozilla.org/MPL/
13 * Software distributed under the License is distributed on an "AS IS" basis,
14 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
15 * for the specific language governing rights and limitations under the
16 * License.
18 * The Original Code is the Nice GLib ICE library.
20 * The Initial Developers of the Original Code are Collabora Ltd and Nokia
21 * Corporation. All Rights Reserved.
23 * Contributors:
24 * Youness Alaoui, Collabora Ltd.
26 * Alternatively, the contents of this file may be used under the terms of the
27 * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which
28 * case the provisions of LGPL are applicable instead of those above. If you
29 * wish to allow use of your version of this file only under the terms of the
30 * LGPL and not to allow others to use your version of this file under the
31 * MPL, indicate your decision by deleting the provisions above and replace
32 * them with the notice and other provisions required by the LGPL. If you do
33 * not delete the provisions above, a recipient may use your version of this
34 * file under either the MPL or the LGPL.
38 * Implementation of TCP relay socket interface using TCP Berkeley sockets. (See
39 * http://en.wikipedia.org/wiki/Berkeley_sockets.)
41 #ifdef HAVE_CONFIG_H
42 # include "config.h"
43 #endif
45 #include "tcp-turn.h"
47 #include <string.h>
48 #include <errno.h>
49 #include <fcntl.h>
51 #ifndef G_OS_WIN32
52 #include <unistd.h>
53 #endif
55 typedef struct {
56 NiceTurnSocketCompatibility compatibility;
57 gchar recv_buf[65536];
58 guint recv_buf_len;
59 guint expecting_len;
60 NiceSocket *base_socket;
61 } TurnTcpPriv;
63 #define MAX_UDP_MESSAGE_SIZE 65535
65 static void socket_close (NiceSocket *sock);
66 static gint socket_recv (NiceSocket *sock, NiceAddress *from,
67 guint len, gchar *buf);
68 static gboolean socket_send (NiceSocket *sock, const NiceAddress *to,
69 guint len, const gchar *buf);
70 static gboolean socket_is_reliable (NiceSocket *sock);
72 NiceSocket *
73 nice_tcp_turn_socket_new (NiceAgent *agent, NiceSocket *base_socket,
74 NiceTurnSocketCompatibility compatibility)
76 TurnTcpPriv *priv;
77 NiceSocket *sock = g_slice_new0 (NiceSocket);
78 sock->priv = priv = g_slice_new0 (TurnTcpPriv);
80 priv->compatibility = compatibility;
81 priv->base_socket = base_socket;
83 sock->fileno = priv->base_socket->fileno;
84 sock->addr = priv->base_socket->addr;
85 sock->send = socket_send;
86 sock->recv = socket_recv;
87 sock->is_reliable = socket_is_reliable;
88 sock->close = socket_close;
90 return sock;
94 static void
95 socket_close (NiceSocket *sock)
97 TurnTcpPriv *priv = sock->priv;
99 if (priv->base_socket)
100 nice_socket_free (priv->base_socket);
102 g_slice_free(TurnTcpPriv, sock->priv);
106 static gint
107 socket_recv (NiceSocket *sock, NiceAddress *from, guint len, gchar *buf)
109 TurnTcpPriv *priv = sock->priv;
110 int ret;
111 guint padlen;
113 if (priv->expecting_len == 0) {
114 guint headerlen = 0;
116 if (priv->compatibility == NICE_TURN_SOCKET_COMPATIBILITY_DRAFT9 ||
117 priv->compatibility == NICE_TURN_SOCKET_COMPATIBILITY_RFC5766)
118 headerlen = 4;
119 else if (priv->compatibility == NICE_TURN_SOCKET_COMPATIBILITY_GOOGLE)
120 headerlen = 2;
121 else
122 return -1;
124 ret = nice_socket_recv (priv->base_socket, from,
125 headerlen - priv->recv_buf_len, priv->recv_buf + priv->recv_buf_len);
126 if (ret < 0)
127 return ret;
129 priv->recv_buf_len += ret;
131 if (priv->recv_buf_len < headerlen)
132 return 0;
134 if (priv->compatibility == NICE_TURN_SOCKET_COMPATIBILITY_DRAFT9 ||
135 priv->compatibility == NICE_TURN_SOCKET_COMPATIBILITY_RFC5766) {
136 guint16 magic = ntohs (*(guint16*)priv->recv_buf);
137 guint16 packetlen = ntohs (*(guint16*)(priv->recv_buf + 2));
139 if (magic < 0x4000) {
140 /* Its STUN */
141 priv->expecting_len = 20 + packetlen;
142 } else {
143 /* Channel data */
144 priv->expecting_len = 4 + packetlen;
147 else if (priv->compatibility == NICE_TURN_SOCKET_COMPATIBILITY_GOOGLE) {
148 guint len = ntohs (*(guint16*)priv->recv_buf);
149 priv->expecting_len = len;
150 priv->recv_buf_len = 0;
154 if (priv->compatibility == NICE_TURN_SOCKET_COMPATIBILITY_DRAFT9 ||
155 priv->compatibility == NICE_TURN_SOCKET_COMPATIBILITY_RFC5766)
156 padlen = (priv->expecting_len % 4) ? 4 - (priv->expecting_len % 4) : 0;
157 else
158 padlen = 0;
160 ret = nice_socket_recv (priv->base_socket, from,
161 priv->expecting_len + padlen - priv->recv_buf_len,
162 priv->recv_buf + priv->recv_buf_len);
164 if (ret < 0)
165 return ret;
167 priv->recv_buf_len += ret;
169 if (priv->recv_buf_len == priv->expecting_len + padlen) {
170 guint copy_len = MIN (len, priv->recv_buf_len);
171 memcpy (buf, priv->recv_buf, copy_len);
172 priv->expecting_len = 0;
173 priv->recv_buf_len = 0;
175 return copy_len;
178 return 0;
181 static gboolean
182 socket_send (NiceSocket *sock, const NiceAddress *to,
183 guint len, const gchar *buf)
185 TurnTcpPriv *priv = sock->priv;
186 gchar padbuf[3] = {0, 0, 0};
187 int padlen = (len%4) ? 4 - (len%4) : 0;
188 gchar buffer[MAX_UDP_MESSAGE_SIZE + sizeof(guint16) + sizeof(padbuf)];
189 guint buffer_len = 0;
191 if (priv->compatibility != NICE_TURN_SOCKET_COMPATIBILITY_DRAFT9 ||
192 priv->compatibility == NICE_TURN_SOCKET_COMPATIBILITY_RFC5766)
193 padlen = 0;
195 if (priv->compatibility == NICE_TURN_SOCKET_COMPATIBILITY_GOOGLE) {
196 guint16 tmpbuf = htons (len);
197 memcpy (buffer + buffer_len, (gchar *)&tmpbuf, sizeof(guint16));
198 buffer_len += sizeof(guint16);
201 memcpy (buffer + buffer_len, buf, len);
202 buffer_len += len;
204 if (priv->compatibility == NICE_TURN_SOCKET_COMPATIBILITY_DRAFT9 ||
205 priv->compatibility == NICE_TURN_SOCKET_COMPATIBILITY_RFC5766) {
206 memcpy (buffer + buffer_len, padbuf, padlen);
207 buffer_len += padlen;
209 return nice_socket_send (priv->base_socket, to, buffer_len, buffer);
214 static gboolean
215 socket_is_reliable (NiceSocket *sock)
217 return TRUE;