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
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.
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.)
56 NiceTurnSocketCompatibility compatibility
;
57 gchar recv_buf
[65536];
60 NiceSocket
*base_socket
;
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
);
73 nice_tcp_turn_socket_new (NiceAgent
*agent
, NiceSocket
*base_socket
,
74 NiceTurnSocketCompatibility compatibility
)
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
;
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
);
107 socket_recv (NiceSocket
*sock
, NiceAddress
*from
, guint len
, gchar
*buf
)
109 TurnTcpPriv
*priv
= sock
->priv
;
113 if (priv
->expecting_len
== 0) {
116 if (priv
->compatibility
== NICE_TURN_SOCKET_COMPATIBILITY_DRAFT9
||
117 priv
->compatibility
== NICE_TURN_SOCKET_COMPATIBILITY_RFC5766
)
119 else if (priv
->compatibility
== NICE_TURN_SOCKET_COMPATIBILITY_GOOGLE
)
124 ret
= nice_socket_recv (priv
->base_socket
, from
,
125 headerlen
- priv
->recv_buf_len
, priv
->recv_buf
+ priv
->recv_buf_len
);
129 priv
->recv_buf_len
+= ret
;
131 if (priv
->recv_buf_len
< headerlen
)
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) {
141 priv
->expecting_len
= 20 + packetlen
;
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;
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
);
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;
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
)
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
);
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
);
215 socket_is_reliable (NiceSocket
*sock
)