2 * This file is part of the Nice GLib ICE library.
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
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/
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
20 * The Original Code is the Nice GLib ICE library.
22 * The Initial Developers of the Original Code are Collabora Ltd and Nokia
23 * Corporation. All Rights Reserved.
26 * Dafydd Harries, Collabora Ltd.
27 * Olivier Crete, Collabora Ltd.
28 * RĂ©mi Denis-Courmont, Nokia
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.
43 * Implementation of TCP relay socket interface using TCP Berkeley sockets. (See
44 * http://en.wikipedia.org/wiki/Berkeley_sockets.)
51 #include "agent-priv.h"
63 NiceAddress server_addr
;
65 GMainContext
*context
;
66 GIOChannel
*io_channel
;
76 #define MAX_QUEUE_LENGTH 20
78 static void socket_close (NiceSocket
*sock
);
79 static gint
socket_recv (NiceSocket
*sock
, NiceAddress
*from
,
80 guint len
, gchar
*buf
);
81 static gboolean
socket_send (NiceSocket
*sock
, const NiceAddress
*to
,
82 guint len
, const gchar
*buf
);
83 static gboolean
socket_is_reliable (NiceSocket
*sock
);
86 static void add_to_be_sent (NiceSocket
*sock
, const gchar
*buf
, guint len
,
88 static void free_to_be_sent (struct to_be_sent
*tbs
);
89 static gboolean
socket_send_more (GIOChannel
*source
, GIOCondition condition
,
93 nice_tcp_bsd_socket_new (NiceAgent
*agent
, GMainContext
*ctx
, NiceAddress
*addr
)
97 struct sockaddr_storage name
;
98 guint name_len
= sizeof (name
);
99 NiceSocket
*sock
= g_slice_new0 (NiceSocket
);
103 nice_address_copy_to_sockaddr(addr
, (struct sockaddr
*)&name
);
105 memset (&name
, 0, sizeof (name
));
106 name
.ss_family
= AF_UNSPEC
;
109 if ((sockfd
== -1) &&
110 ((name
.ss_family
== AF_UNSPEC
) ||
111 (name
.ss_family
== AF_INET
))) {
112 sockfd
= socket (PF_INET
, SOCK_STREAM
, 0);
113 name
.ss_family
= AF_INET
;
115 name
.ss_len
= sizeof (struct sockaddr_in
);
120 g_slice_free (NiceSocket
, sock
);
125 fcntl (sockfd
, F_SETFD
, fcntl (sockfd
, F_GETFD
) | FD_CLOEXEC
);
128 fcntl (sockfd
, F_SETFL
, fcntl (sockfd
, F_GETFL
) | O_NONBLOCK
);
131 name_len
= name
.ss_family
== AF_INET
? sizeof (struct sockaddr_in
) :
132 sizeof(struct sockaddr_in6
);
133 ret
= connect (sockfd
, (const struct sockaddr
*)&name
, name_len
);
136 if (ret
< 0 && WSAGetLastError () != WSAEINPROGRESS
) {
137 closesocket (sockfd
);
139 if (ret
< 0 && errno
!= EINPROGRESS
) {
142 g_slice_free (NiceSocket
, sock
);
146 name_len
= name
.ss_family
== AF_INET
? sizeof (struct sockaddr_in
) :
147 sizeof(struct sockaddr_in6
);
148 if (getsockname (sockfd
, (struct sockaddr
*) &name
, &name_len
) < 0) {
149 g_slice_free (NiceSocket
, sock
);
158 nice_address_set_from_sockaddr (&sock
->addr
, (struct sockaddr
*)&name
);
160 sock
->priv
= priv
= g_slice_new0 (TcpPriv
);
164 priv
->server_addr
= *addr
;
166 sock
->fileno
= sockfd
;
167 sock
->send
= socket_send
;
168 sock
->recv
= socket_recv
;
169 sock
->is_reliable
= socket_is_reliable
;
170 sock
->close
= socket_close
;
177 socket_close (NiceSocket
*sock
)
179 TcpPriv
*priv
= sock
->priv
;
182 closesocket(sock
->fileno
);
184 close (sock
->fileno
);
186 if (priv
->io_source
) {
187 g_source_destroy (priv
->io_source
);
188 g_source_unref (priv
->io_source
);
190 if (priv
->io_channel
)
191 g_io_channel_unref (priv
->io_channel
);
192 g_queue_foreach (&priv
->send_queue
, (GFunc
) free_to_be_sent
, NULL
);
193 g_queue_clear (&priv
->send_queue
);
195 g_slice_free(TcpPriv
, sock
->priv
);
199 socket_recv (NiceSocket
*sock
, NiceAddress
*from
, guint len
, gchar
*buf
)
201 TcpPriv
*priv
= sock
->priv
;
204 ret
= recv (sock
->fileno
, buf
, len
, 0);
206 /* recv returns 0 when the peer performed a shutdown.. we must return -1 here
207 * so that the agent destroys the g_source */
213 if (WSAGetLastError () == WSAEWOULDBLOCK
)
223 *from
= priv
->server_addr
;
227 /* Data sent to this function must be a single entity because buffers can be
228 * dropped if the bandwidth isn't fast enough. So do not send a message in
229 * multiple chunks. */
231 socket_send (NiceSocket
*sock
, const NiceAddress
*to
,
232 guint len
, const gchar
*buf
)
234 TcpPriv
*priv
= sock
->priv
;
237 /* First try to send the data, don't send it later if it can be sent now
238 this way we avoid allocating memory on every send */
239 if (g_queue_is_empty (&priv
->send_queue
)) {
240 ret
= send (sock
->fileno
, buf
, len
, 0);
244 if (WSAGetLastError () == WSAEWOULDBLOCK
) {
246 if (errno
== EAGAIN
) {
248 add_to_be_sent (sock
, buf
, len
, FALSE
);
253 } else if ((guint
)ret
< len
) {
254 add_to_be_sent (sock
, buf
+ ret
, len
- ret
, TRUE
);
258 if (g_queue_get_length(&priv
->send_queue
) >= MAX_QUEUE_LENGTH
) {
260 struct to_be_sent
*tbs
= NULL
;
261 while ((tbs
= g_queue_peek_nth (&priv
->send_queue
, peek_idx
)) != NULL
) {
263 tbs
= g_queue_pop_nth (&priv
->send_queue
, peek_idx
);
265 g_slice_free (struct to_be_sent
, tbs
);
272 add_to_be_sent (sock
, buf
, len
, FALSE
);
279 socket_is_reliable (NiceSocket
*sock
)
288 * 0 = have more to send
289 * 1 = sent everything
295 GIOCondition condition
,
298 NiceSocket
*sock
= (NiceSocket
*) data
;
299 TcpPriv
*priv
= sock
->priv
;
300 struct to_be_sent
*tbs
= NULL
;
304 if (g_source_is_destroyed (g_main_current_source ())) {
305 nice_debug ("Source was destroyed. "
306 "Avoided race condition in tcp-bsd.c:socket_send_more");
311 while ((tbs
= g_queue_pop_head (&priv
->send_queue
)) != NULL
) {
314 ret
= send (sock
->fileno
, tbs
->buf
, tbs
->length
, 0);
318 if (WSAGetLastError () == WSAEWOULDBLOCK
) {
320 if (errno
== EAGAIN
) {
322 add_to_be_sent (sock
, tbs
->buf
, tbs
->length
, TRUE
);
324 g_slice_free (struct to_be_sent
, tbs
);
327 } else if (ret
< (int) tbs
->length
) {
328 add_to_be_sent (sock
, tbs
->buf
+ ret
, tbs
->length
- ret
, TRUE
);
330 g_slice_free (struct to_be_sent
, tbs
);
335 g_slice_free (struct to_be_sent
, tbs
);
338 if (g_queue_is_empty (&priv
->send_queue
)) {
339 g_io_channel_unref (priv
->io_channel
);
340 priv
->io_channel
= NULL
;
341 g_source_destroy (priv
->io_source
);
342 g_source_unref (priv
->io_source
);
343 priv
->io_source
= NULL
;
355 add_to_be_sent (NiceSocket
*sock
, const gchar
*buf
, guint len
, gboolean head
)
357 TcpPriv
*priv
= sock
->priv
;
358 struct to_be_sent
*tbs
= NULL
;
363 tbs
= g_slice_new0 (struct to_be_sent
);
364 tbs
->buf
= g_memdup (buf
, len
);
366 tbs
->can_drop
= !head
;
368 g_queue_push_head (&priv
->send_queue
, tbs
);
370 g_queue_push_tail (&priv
->send_queue
, tbs
);
372 if (priv
->io_channel
== NULL
) {
373 priv
->io_channel
= g_io_channel_unix_new (sock
->fileno
);
374 priv
->io_source
= g_io_create_watch (priv
->io_channel
, G_IO_OUT
);
375 g_source_set_callback (priv
->io_source
, (GSourceFunc
) socket_send_more
,
377 g_source_attach (priv
->io_source
, priv
->context
);
384 free_to_be_sent (struct to_be_sent
*tbs
)
387 g_slice_free (struct to_be_sent
, tbs
);