Find and document every message attribute/error code and from which RFC/Draft they...
[sipe-libnice.git] / socket / tcp-bsd.c
blob2c41d75fb6aeecb5e8fe729c27d0825b92ed5dfa
1 /*
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
18 * License.
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.
25 * Contributors:
26 * Dafydd Harries, Collabora Ltd.
27 * Olivier Crete, Collabora Ltd.
28 * RĂ©mi Denis-Courmont, Nokia
29 * Kai Vehmanen
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.)
46 #ifdef HAVE_CONFIG_H
47 # include "config.h"
48 #endif
50 #include "tcp-bsd.h"
51 #include "agent-priv.h"
53 #include <string.h>
54 #include <errno.h>
55 #include <fcntl.h>
57 #ifndef G_OS_WIN32
58 #include <unistd.h>
59 #endif
61 typedef struct {
62 NiceAgent *agent;
63 NiceAddress server_addr;
64 GQueue send_queue;
65 GMainContext *context;
66 GIOChannel *io_channel;
67 GSource *io_source;
68 } TcpPriv;
70 struct to_be_sent {
71 guint length;
72 gchar *buf;
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,
85 gboolean head);
86 static void free_to_be_sent (struct to_be_sent *tbs);
87 static gboolean socket_send_more (GIOChannel *source, GIOCondition condition,
88 gpointer data);
90 NiceSocket *
91 nice_tcp_bsd_socket_new (NiceAgent *agent, GMainContext *ctx, NiceAddress *addr)
93 int sockfd = -1;
94 int ret;
95 struct sockaddr_storage name;
96 guint name_len = sizeof (name);
97 NiceSocket *sock = g_slice_new0 (NiceSocket);
98 TcpPriv *priv;
100 if (addr != NULL) {
101 nice_address_copy_to_sockaddr(addr, (struct sockaddr *)&name);
102 } else {
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;
112 #ifdef HAVE_SA_LEN
113 name.ss_len = sizeof (struct sockaddr_in);
114 #endif
117 if (sockfd == -1) {
118 g_slice_free (NiceSocket, sock);
119 return NULL;
122 #ifdef FD_CLOEXEC
123 fcntl (sockfd, F_SETFD, fcntl (sockfd, F_GETFD) | FD_CLOEXEC);
124 #endif
125 #ifdef O_NONBLOCK
126 fcntl (sockfd, F_SETFL, fcntl (sockfd, F_GETFL) | O_NONBLOCK);
127 #endif
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);
133 #ifdef G_OS_WIN32
134 if (ret < 0 && WSAGetLastError () != WSAEINPROGRESS) {
135 closesocket (sockfd);
136 #else
137 if (ret < 0 && errno != EINPROGRESS) {
138 close (sockfd);
139 #endif
140 g_slice_free (NiceSocket, sock);
141 return NULL;
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);
148 #ifdef G_OS_WIN32
149 closesocket(sockfd);
150 #else
151 close (sockfd);
152 #endif
153 return NULL;
156 nice_address_set_from_sockaddr (&sock->addr, (struct sockaddr *)&name);
158 sock->priv = priv = g_slice_new0 (TcpPriv);
160 priv->agent = agent;
161 priv->context = ctx;
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;
170 return sock;
174 static void
175 socket_close (NiceSocket *sock)
177 TcpPriv *priv = sock->priv;
179 #ifdef G_OS_WIN32
180 closesocket(sock->fileno);
181 #else
182 close (sock->fileno);
183 #endif
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);
196 static gint
197 socket_recv (NiceSocket *sock, NiceAddress *from, guint len, gchar *buf)
199 TcpPriv *priv = sock->priv;
200 int ret;
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 */
206 if (ret == 0)
207 return -1;
209 if (ret < 0) {
210 #ifdef G_OS_WIN32
211 if (WSAGetLastError () == WSAEWOULDBLOCK)
212 #else
213 if (errno == EAGAIN)
214 #endif
215 return 0;
216 else
217 return ret;
220 if (from)
221 *from = priv->server_addr;
222 return ret;
226 static gboolean
227 socket_send (NiceSocket *sock, const NiceAddress *to,
228 guint len, const gchar *buf)
230 TcpPriv *priv = sock->priv;
231 int ret;
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);
238 if (ret < 0) {
239 #ifdef G_OS_WIN32
240 if (WSAGetLastError () == WSAEWOULDBLOCK) {
241 #else
242 if (errno == EAGAIN) {
243 #endif
244 add_to_be_sent (sock, buf, len, FALSE);
245 return TRUE;
246 } else {
247 return FALSE;
249 } else if ((guint)ret < len) {
250 add_to_be_sent (sock, buf + ret, len - ret, FALSE);
251 return TRUE;
253 } else {
254 add_to_be_sent (sock, buf, len, FALSE);
257 return TRUE;
260 static gboolean
261 socket_is_reliable (NiceSocket *sock)
263 return TRUE;
268 * Returns:
269 * -1 = error
270 * 0 = have more to send
271 * 1 = sent everything
274 static gboolean
275 socket_send_more (
276 GIOChannel *source,
277 GIOCondition condition,
278 gpointer data)
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))) {
287 int ret;
289 ret = send (sock->fileno, tbs->buf, tbs->length, 0);
291 if (ret < 0) {
292 #ifdef G_OS_WIN32
293 if (WSAGetLastError () == WSAEWOULDBLOCK) {
294 #else
295 if (errno == EAGAIN) {
296 #endif
297 add_to_be_sent (sock, tbs->buf, tbs->length, TRUE);
298 g_free (tbs->buf);
299 g_slice_free (struct to_be_sent, tbs);
300 break;
302 } else if (ret < (int) tbs->length) {
303 add_to_be_sent (sock, tbs->buf + ret, tbs->length - ret, TRUE);
304 g_free (tbs->buf);
305 g_slice_free (struct to_be_sent, tbs);
306 break;
309 g_free (tbs->buf);
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);
321 return FALSE;
324 g_static_rec_mutex_unlock (&priv->agent->mutex);
325 return TRUE;
329 static void
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;
335 if (len <= 0)
336 return;
338 tbs = g_slice_new0 (struct to_be_sent);
339 tbs->buf = g_memdup (buf, len);
340 tbs->length = len;
341 if (head)
342 g_queue_push_head (&priv->send_queue, tbs);
343 else
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,
350 sock, NULL);
351 g_source_attach (priv->io_source, priv->context);
357 static void
358 free_to_be_sent (struct to_be_sent *tbs)
360 g_free (tbs->buf);
361 g_slice_free (struct to_be_sent, tbs);