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.)
46 #include "agent-priv.h"
58 NiceAddress server_addr
;
60 GMainContext
*context
;
61 GIOChannel
*io_channel
;
71 #define MAX_QUEUE_LENGTH 20
73 static void socket_close (NiceSocket
*sock
);
74 static gint
socket_recv (NiceSocket
*sock
, NiceAddress
*from
,
75 guint len
, gchar
*buf
);
76 static gboolean
socket_send (NiceSocket
*sock
, const NiceAddress
*to
,
77 guint len
, const gchar
*buf
);
78 static gboolean
socket_is_reliable (NiceSocket
*sock
);
81 static void add_to_be_sent (NiceSocket
*sock
, const gchar
*buf
, guint len
,
83 static void free_to_be_sent (struct to_be_sent
*tbs
);
84 static gboolean
socket_send_more (GIOChannel
*source
, GIOCondition condition
,
88 nice_tcp_bsd_socket_new (NiceAgent
*agent
, GMainContext
*ctx
, NiceAddress
*addr
)
92 struct sockaddr_storage name
;
93 guint name_len
= sizeof (name
);
98 /* We can't connect a tcp socket with no destination address */
102 sock
= g_slice_new0 (NiceSocket
);
104 nice_address_copy_to_sockaddr(addr
, (struct sockaddr
*)&name
);
107 if (name
.ss_family
== AF_UNSPEC
|| name
.ss_family
== AF_INET
) {
108 sockfd
= socket (PF_INET
, SOCK_STREAM
, 0);
109 name
.ss_family
= AF_INET
;
111 name
.ss_len
= sizeof (struct sockaddr_in
);
113 } else if (name
.ss_family
== AF_INET6
) {
114 sockfd
= socket (PF_INET6
, SOCK_STREAM
, 0);
115 name
.ss_family
= AF_INET6
;
117 name
.ss_len
= sizeof (struct sockaddr_in6
);
123 g_slice_free (NiceSocket
, sock
);
128 fcntl (sockfd
, F_SETFD
, fcntl (sockfd
, F_GETFD
) | FD_CLOEXEC
);
131 fcntl (sockfd
, F_SETFL
, fcntl (sockfd
, F_GETFL
) | O_NONBLOCK
);
134 name_len
= name
.ss_family
== AF_INET
? sizeof (struct sockaddr_in
) :
135 sizeof(struct sockaddr_in6
);
136 ret
= connect (sockfd
, (const struct sockaddr
*)&name
, name_len
);
139 if (ret
< 0 && WSAGetLastError () != WSAEINPROGRESS
) {
140 closesocket (sockfd
);
142 if (ret
< 0 && errno
!= EINPROGRESS
) {
145 g_slice_free (NiceSocket
, sock
);
149 name_len
= name
.ss_family
== AF_INET
? sizeof (struct sockaddr_in
) :
150 sizeof(struct sockaddr_in6
);
151 if (getsockname (sockfd
, (struct sockaddr
*) &name
, &name_len
) < 0) {
152 g_slice_free (NiceSocket
, sock
);
161 nice_address_set_from_sockaddr (&sock
->addr
, (struct sockaddr
*)&name
);
163 sock
->priv
= priv
= g_slice_new0 (TcpPriv
);
167 priv
->server_addr
= *addr
;
169 sock
->fileno
= sockfd
;
170 sock
->send
= socket_send
;
171 sock
->recv
= socket_recv
;
172 sock
->is_reliable
= socket_is_reliable
;
173 sock
->close
= socket_close
;
180 socket_close (NiceSocket
*sock
)
182 TcpPriv
*priv
= sock
->priv
;
185 closesocket(sock
->fileno
);
187 close (sock
->fileno
);
189 if (priv
->io_source
) {
190 g_source_destroy (priv
->io_source
);
191 g_source_unref (priv
->io_source
);
193 if (priv
->io_channel
)
194 g_io_channel_unref (priv
->io_channel
);
195 g_queue_foreach (&priv
->send_queue
, (GFunc
) free_to_be_sent
, NULL
);
196 g_queue_clear (&priv
->send_queue
);
198 g_slice_free(TcpPriv
, sock
->priv
);
202 socket_recv (NiceSocket
*sock
, NiceAddress
*from
, guint len
, gchar
*buf
)
204 TcpPriv
*priv
= sock
->priv
;
207 ret
= recv (sock
->fileno
, buf
, len
, 0);
209 /* recv returns 0 when the peer performed a shutdown.. we must return -1 here
210 * so that the agent destroys the g_source */
216 if (WSAGetLastError () == WSAEWOULDBLOCK
)
226 *from
= priv
->server_addr
;
230 /* Data sent to this function must be a single entity because buffers can be
231 * dropped if the bandwidth isn't fast enough. So do not send a message in
232 * multiple chunks. */
234 socket_send (NiceSocket
*sock
, const NiceAddress
*to
,
235 guint len
, const gchar
*buf
)
237 TcpPriv
*priv
= sock
->priv
;
240 /* First try to send the data, don't send it later if it can be sent now
241 this way we avoid allocating memory on every send */
242 if (g_queue_is_empty (&priv
->send_queue
)) {
243 ret
= send (sock
->fileno
, buf
, len
, 0);
247 if (WSAGetLastError () == WSAEWOULDBLOCK
) {
249 if (errno
== EAGAIN
) {
251 add_to_be_sent (sock
, buf
, len
, FALSE
);
256 } else if ((guint
)ret
< len
) {
257 add_to_be_sent (sock
, buf
+ ret
, len
- ret
, TRUE
);
261 if (g_queue_get_length(&priv
->send_queue
) >= MAX_QUEUE_LENGTH
) {
263 struct to_be_sent
*tbs
= NULL
;
264 while ((tbs
= g_queue_peek_nth (&priv
->send_queue
, peek_idx
)) != NULL
) {
266 tbs
= g_queue_pop_nth (&priv
->send_queue
, peek_idx
);
268 g_slice_free (struct to_be_sent
, tbs
);
275 add_to_be_sent (sock
, buf
, len
, FALSE
);
282 socket_is_reliable (NiceSocket
*sock
)
291 * 0 = have more to send
292 * 1 = sent everything
298 GIOCondition condition
,
301 NiceSocket
*sock
= (NiceSocket
*) data
;
302 TcpPriv
*priv
= sock
->priv
;
303 struct to_be_sent
*tbs
= NULL
;
307 if (g_source_is_destroyed (g_main_current_source ())) {
308 nice_debug ("Source was destroyed. "
309 "Avoided race condition in tcp-bsd.c:socket_send_more");
314 while ((tbs
= g_queue_pop_head (&priv
->send_queue
)) != NULL
) {
317 ret
= send (sock
->fileno
, tbs
->buf
, tbs
->length
, 0);
321 if (WSAGetLastError () == WSAEWOULDBLOCK
) {
323 if (errno
== EAGAIN
) {
325 add_to_be_sent (sock
, tbs
->buf
, tbs
->length
, TRUE
);
327 g_slice_free (struct to_be_sent
, tbs
);
330 } else if (ret
< (int) tbs
->length
) {
331 add_to_be_sent (sock
, tbs
->buf
+ ret
, tbs
->length
- ret
, TRUE
);
333 g_slice_free (struct to_be_sent
, tbs
);
338 g_slice_free (struct to_be_sent
, tbs
);
341 if (g_queue_is_empty (&priv
->send_queue
)) {
342 g_io_channel_unref (priv
->io_channel
);
343 priv
->io_channel
= NULL
;
344 g_source_destroy (priv
->io_source
);
345 g_source_unref (priv
->io_source
);
346 priv
->io_source
= NULL
;
358 add_to_be_sent (NiceSocket
*sock
, const gchar
*buf
, guint len
, gboolean head
)
360 TcpPriv
*priv
= sock
->priv
;
361 struct to_be_sent
*tbs
= NULL
;
366 tbs
= g_slice_new0 (struct to_be_sent
);
367 tbs
->buf
= g_memdup (buf
, len
);
369 tbs
->can_drop
= !head
;
371 g_queue_push_head (&priv
->send_queue
, tbs
);
373 g_queue_push_tail (&priv
->send_queue
, tbs
);
375 if (priv
->io_channel
== NULL
) {
376 priv
->io_channel
= g_io_channel_unix_new (sock
->fileno
);
377 priv
->io_source
= g_io_create_watch (priv
->io_channel
, G_IO_OUT
);
378 g_source_set_callback (priv
->io_source
, (GSourceFunc
) socket_send_more
,
380 g_source_attach (priv
->io_source
, priv
->context
);
387 free_to_be_sent (struct to_be_sent
*tbs
)
390 g_slice_free (struct to_be_sent
, tbs
);