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 static void socket_close (NiceSocket
*sock
);
77 static gint
socket_recv (NiceSocket
*sock
, NiceAddress
*from
,
78 guint len
, gchar
*buf
);
79 static gboolean
socket_send (NiceSocket
*sock
, const NiceAddress
*to
,
80 guint len
, const gchar
*buf
);
81 static gboolean
socket_is_reliable (NiceSocket
*sock
);
84 static void add_to_be_sent (NiceSocket
*sock
, const gchar
*buf
, guint len
,
86 static void free_to_be_sent (struct to_be_sent
*tbs
);
87 static gboolean
socket_send_more (GIOChannel
*source
, GIOCondition condition
,
91 nice_tcp_bsd_socket_new (NiceAgent
*agent
, GMainContext
*ctx
, NiceAddress
*addr
)
95 struct sockaddr_storage name
;
96 guint name_len
= sizeof (name
);
97 NiceSocket
*sock
= g_slice_new0 (NiceSocket
);
101 nice_address_copy_to_sockaddr(addr
, (struct sockaddr
*)&name
);
103 memset (&name
, 0, sizeof (name
));
104 name
.ss_family
= AF_UNSPEC
;
107 if ((sockfd
== -1) &&
108 ((name
.ss_family
== AF_UNSPEC
) ||
109 (name
.ss_family
== AF_INET
))) {
110 sockfd
= socket (PF_INET
, SOCK_STREAM
, 0);
111 name
.ss_family
= AF_INET
;
113 name
.ss_len
= sizeof (struct sockaddr_in
);
118 g_slice_free (NiceSocket
, sock
);
123 fcntl (sockfd
, F_SETFD
, fcntl (sockfd
, F_GETFD
) | FD_CLOEXEC
);
126 fcntl (sockfd
, F_SETFL
, fcntl (sockfd
, F_GETFL
) | O_NONBLOCK
);
129 name_len
= name
.ss_family
== AF_INET
? sizeof (struct sockaddr_in
) :
130 sizeof(struct sockaddr_in6
);
131 ret
= connect (sockfd
, (const struct sockaddr
*)&name
, name_len
);
134 if (ret
< 0 && WSAGetLastError () != WSAEINPROGRESS
) {
135 closesocket (sockfd
);
137 if (ret
< 0 && errno
!= EINPROGRESS
) {
140 g_slice_free (NiceSocket
, sock
);
144 name_len
= name
.ss_family
== AF_INET
? sizeof (struct sockaddr_in
) :
145 sizeof(struct sockaddr_in6
);
146 if (getsockname (sockfd
, (struct sockaddr
*) &name
, &name_len
) < 0) {
147 g_slice_free (NiceSocket
, sock
);
156 nice_address_set_from_sockaddr (&sock
->addr
, (struct sockaddr
*)&name
);
158 sock
->priv
= priv
= g_slice_new0 (TcpPriv
);
162 priv
->server_addr
= *addr
;
164 sock
->fileno
= sockfd
;
165 sock
->send
= socket_send
;
166 sock
->recv
= socket_recv
;
167 sock
->is_reliable
= socket_is_reliable
;
168 sock
->close
= socket_close
;
175 socket_close (NiceSocket
*sock
)
177 TcpPriv
*priv
= sock
->priv
;
180 closesocket(sock
->fileno
);
182 close (sock
->fileno
);
184 if (priv
->io_source
) {
185 g_source_destroy (priv
->io_source
);
186 g_source_unref (priv
->io_source
);
188 if (priv
->io_channel
)
189 g_io_channel_unref (priv
->io_channel
);
190 g_queue_foreach (&priv
->send_queue
, (GFunc
) free_to_be_sent
, NULL
);
191 g_queue_clear (&priv
->send_queue
);
193 g_slice_free(TcpPriv
, sock
->priv
);
197 socket_recv (NiceSocket
*sock
, NiceAddress
*from
, guint len
, gchar
*buf
)
199 TcpPriv
*priv
= sock
->priv
;
202 ret
= recv (sock
->fileno
, buf
, len
, 0);
204 /* recv returns 0 when the peer performed a shutdown.. we must return -1 here
205 * so that the agent destroys the g_source */
211 if (WSAGetLastError () == WSAEWOULDBLOCK
)
221 *from
= priv
->server_addr
;
227 socket_send (NiceSocket
*sock
, const NiceAddress
*to
,
228 guint len
, const gchar
*buf
)
230 TcpPriv
*priv
= sock
->priv
;
233 /* First try to send the data, don't send it later if it can be sent now
234 this way we avoid allocating memory on every send */
235 if (g_queue_is_empty (&priv
->send_queue
)) {
236 ret
= send (sock
->fileno
, buf
, len
, 0);
240 if (WSAGetLastError () == WSAEWOULDBLOCK
) {
242 if (errno
== EAGAIN
) {
244 add_to_be_sent (sock
, buf
, len
, FALSE
);
249 } else if ((guint
)ret
< len
) {
250 add_to_be_sent (sock
, buf
+ ret
, len
- ret
, FALSE
);
254 add_to_be_sent (sock
, buf
, len
, FALSE
);
261 socket_is_reliable (NiceSocket
*sock
)
270 * 0 = have more to send
271 * 1 = sent everything
277 GIOCondition condition
,
280 NiceSocket
*sock
= (NiceSocket
*) data
;
281 TcpPriv
*priv
= sock
->priv
;
282 struct to_be_sent
*tbs
= NULL
;
284 g_static_rec_mutex_lock (&priv
->agent
->mutex
);
286 while ((tbs
= g_queue_pop_head (&priv
->send_queue
))) {
289 ret
= send (sock
->fileno
, tbs
->buf
, tbs
->length
, 0);
293 if (WSAGetLastError () == WSAEWOULDBLOCK
) {
295 if (errno
== EAGAIN
) {
297 add_to_be_sent (sock
, tbs
->buf
, tbs
->length
, TRUE
);
299 g_slice_free (struct to_be_sent
, tbs
);
302 } else if (ret
< (int) tbs
->length
) {
303 add_to_be_sent (sock
, tbs
->buf
+ ret
, tbs
->length
- ret
, TRUE
);
305 g_slice_free (struct to_be_sent
, tbs
);
310 g_slice_free (struct to_be_sent
, tbs
);
313 if (g_queue_is_empty (&priv
->send_queue
)) {
314 g_io_channel_unref (priv
->io_channel
);
315 priv
->io_channel
= NULL
;
316 g_source_destroy (priv
->io_source
);
317 g_source_unref (priv
->io_source
);
318 priv
->io_source
= NULL
;
320 g_static_rec_mutex_unlock (&priv
->agent
->mutex
);
324 g_static_rec_mutex_unlock (&priv
->agent
->mutex
);
330 add_to_be_sent (NiceSocket
*sock
, const gchar
*buf
, guint len
, gboolean head
)
332 TcpPriv
*priv
= sock
->priv
;
333 struct to_be_sent
*tbs
= NULL
;
338 tbs
= g_slice_new0 (struct to_be_sent
);
339 tbs
->buf
= g_memdup (buf
, len
);
342 g_queue_push_head (&priv
->send_queue
, tbs
);
344 g_queue_push_tail (&priv
->send_queue
, tbs
);
346 if (priv
->io_channel
== NULL
) {
347 priv
->io_channel
= g_io_channel_unix_new (sock
->fileno
);
348 priv
->io_source
= g_io_create_watch (priv
->io_channel
, G_IO_OUT
);
349 g_source_set_callback (priv
->io_source
, (GSourceFunc
) socket_send_more
,
351 g_source_attach (priv
->io_source
, priv
->context
);
358 free_to_be_sent (struct to_be_sent
*tbs
)
361 g_slice_free (struct to_be_sent
, tbs
);