Use G_OBJECT_WARN_INVALID_PROPERTY_ID in all get/set_property functions.
[platform/upstream/libsoup.git] / libsoup / soup-socket.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3  * soup-socket.c: Socket networking code.
4  *
5  * Copyright (C) 2000-2003, Ximian, Inc.
6  */
7
8 #ifdef HAVE_CONFIG_H
9 #include <config.h>
10 #endif
11
12 #include <errno.h>
13 #include <fcntl.h>
14 #include <signal.h>
15 #include <string.h>
16 #include <unistd.h>
17
18 #include "soup-address.h"
19 #include "soup-socket.h"
20 #include "soup-marshal.h"
21 #include "soup-misc.h"
22 #include "soup-ssl.h"
23
24 #include <sys/time.h>
25 #include <sys/types.h>
26
27 /**
28  * SECTION:soup-socket
29  * @short_description: A network socket
30  *
31  * #SoupSocket is libsoup's TCP socket type. While it is primarily
32  * intended for internal use, #SoupSocket<!-- -->s are exposed in the
33  * API in various places, and some of their methods (eg,
34  * soup_socket_get_remote_address()) may be useful to applications.
35  **/
36
37 G_DEFINE_TYPE (SoupSocket, soup_socket, G_TYPE_OBJECT)
38
39 enum {
40         READABLE,
41         WRITABLE,
42         DISCONNECTED,
43         NEW_CONNECTION,
44         LAST_SIGNAL
45 };
46
47 static guint signals[LAST_SIGNAL] = { 0 };
48
49 enum {
50         PROP_0,
51
52         PROP_LOCAL_ADDRESS,
53         PROP_REMOTE_ADDRESS,
54         PROP_NON_BLOCKING,
55         PROP_IS_SERVER,
56         PROP_SSL_CREDENTIALS,
57         PROP_ASYNC_CONTEXT,
58         PROP_TIMEOUT,
59
60         LAST_PROP
61 };
62
63 typedef struct {
64         int sockfd;
65         SoupAddress *local_addr, *remote_addr;
66         GIOChannel *iochannel;
67
68         guint non_blocking:1;
69         guint is_server:1;
70         gpointer ssl_creds;
71
72         GMainContext   *async_context;
73         GSource        *watch_src;
74         GSource        *read_src, *write_src;
75         GByteArray     *read_buf;
76
77         GMutex *iolock, *addrlock;
78         guint timeout;
79 } SoupSocketPrivate;
80 #define SOUP_SOCKET_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), SOUP_TYPE_SOCKET, SoupSocketPrivate))
81
82 #ifdef HAVE_IPV6
83 #define soup_sockaddr_max sockaddr_in6
84 #else
85 #define soup_sockaddr_max sockaddr_in
86 #endif
87
88 static void set_property (GObject *object, guint prop_id,
89                           const GValue *value, GParamSpec *pspec);
90 static void get_property (GObject *object, guint prop_id,
91                           GValue *value, GParamSpec *pspec);
92
93 #ifdef G_OS_WIN32
94 #define SOUP_IS_SOCKET_ERROR(status) ((status) == SOCKET_ERROR)
95 #define SOUP_IS_INVALID_SOCKET(socket) ((socket) == INVALID_SOCKET)
96 #define SOUP_IS_CONNECT_STATUS_INPROGRESS() (WSAGetLastError () == WSAEWOULDBLOCK)
97 #define SHUT_RDWR SD_BOTH
98 #else
99 #define SOUP_IS_SOCKET_ERROR(status) ((status) == -1)
100 #define SOUP_IS_INVALID_SOCKET(socket) ((socket) < 0)
101 #define SOUP_IS_CONNECT_STATUS_INPROGRESS() (errno == EINPROGRESS)
102 #endif
103
104 static void
105 soup_socket_init (SoupSocket *sock)
106 {
107         SoupSocketPrivate *priv = SOUP_SOCKET_GET_PRIVATE (sock);
108
109         priv->sockfd = -1;
110         priv->non_blocking = TRUE;
111         priv->addrlock = g_mutex_new ();
112         priv->iolock = g_mutex_new ();
113         priv->timeout = 0;
114 }
115
116 static void
117 disconnect_internal (SoupSocketPrivate *priv)
118 {
119         g_io_channel_unref (priv->iochannel);
120         priv->iochannel = NULL;
121         priv->sockfd = -1;
122
123         if (priv->read_src) {
124                 g_source_destroy (priv->read_src);
125                 priv->read_src = NULL;
126         }
127         if (priv->write_src) {
128                 g_source_destroy (priv->write_src);
129                 priv->write_src = NULL;
130         }
131 }
132
133 static void
134 finalize (GObject *object)
135 {
136         SoupSocketPrivate *priv = SOUP_SOCKET_GET_PRIVATE (object);
137
138         if (priv->iochannel)
139                 disconnect_internal (priv);
140
141         if (priv->local_addr)
142                 g_object_unref (priv->local_addr);
143         if (priv->remote_addr)
144                 g_object_unref (priv->remote_addr);
145
146         if (priv->watch_src)
147                 g_source_destroy (priv->watch_src);
148         if (priv->async_context)
149                 g_main_context_unref (priv->async_context);
150
151         if (priv->read_buf)
152                 g_byte_array_free (priv->read_buf, TRUE);
153
154         g_mutex_free (priv->addrlock);
155         g_mutex_free (priv->iolock);
156
157         G_OBJECT_CLASS (soup_socket_parent_class)->finalize (object);
158 }
159
160 static void
161 soup_socket_class_init (SoupSocketClass *socket_class)
162 {
163         GObjectClass *object_class = G_OBJECT_CLASS (socket_class);
164
165         g_type_class_add_private (socket_class, sizeof (SoupSocketPrivate));
166
167         /* virtual method override */
168         object_class->finalize = finalize;
169         object_class->set_property = set_property;
170         object_class->get_property = get_property;
171
172         /* signals */
173
174         /**
175          * SoupSocket::readable:
176          * @sock: the socket
177          *
178          * Emitted when an async socket is readable. See
179          * soup_socket_read() and soup_socket_read_until().
180          **/
181         signals[READABLE] =
182                 g_signal_new ("readable",
183                               G_OBJECT_CLASS_TYPE (object_class),
184                               G_SIGNAL_RUN_LAST,
185                               G_STRUCT_OFFSET (SoupSocketClass, readable),
186                               NULL, NULL,
187                               soup_marshal_NONE__NONE,
188                               G_TYPE_NONE, 0);
189
190         /**
191          * SoupSocket::writable:
192          * @sock: the socket
193          *
194          * Emitted when an async socket is writable. See
195          * soup_socket_write().
196          **/
197         signals[WRITABLE] =
198                 g_signal_new ("writable",
199                               G_OBJECT_CLASS_TYPE (object_class),
200                               G_SIGNAL_RUN_LAST,
201                               G_STRUCT_OFFSET (SoupSocketClass, writable),
202                               NULL, NULL,
203                               soup_marshal_NONE__NONE,
204                               G_TYPE_NONE, 0);
205
206         /**
207          * SoupSocket::disconnected:
208          * @sock: the socket
209          *
210          * Emitted when the socket is disconnected, for whatever
211          * reason.
212          **/
213         signals[DISCONNECTED] =
214                 g_signal_new ("disconnected",
215                               G_OBJECT_CLASS_TYPE (object_class),
216                               G_SIGNAL_RUN_LAST,
217                               G_STRUCT_OFFSET (SoupSocketClass, disconnected),
218                               NULL, NULL,
219                               soup_marshal_NONE__NONE,
220                               G_TYPE_NONE, 0);
221
222         /**
223          * SoupSocket::new-connection:
224          * @sock: the socket
225          * @new: the new socket
226          *
227          * Emitted when a listening socket (set up with
228          * soup_socket_listen()) receives a new connection.
229          *
230          * You must ref the @new if you want to keep it; otherwise it
231          * will be destroyed after the signal is emitted.
232          **/
233         signals[NEW_CONNECTION] =
234                 g_signal_new ("new_connection",
235                               G_OBJECT_CLASS_TYPE (object_class),
236                               G_SIGNAL_RUN_FIRST,
237                               G_STRUCT_OFFSET (SoupSocketClass, new_connection),
238                               NULL, NULL,
239                               soup_marshal_NONE__OBJECT,
240                               G_TYPE_NONE, 1,
241                               SOUP_TYPE_SOCKET);
242
243         /* properties */
244         g_object_class_install_property (
245                 object_class, PROP_LOCAL_ADDRESS,
246                 g_param_spec_object (SOUP_SOCKET_LOCAL_ADDRESS,
247                                      "Local address",
248                                      "Address of local end of socket",
249                                      SOUP_TYPE_ADDRESS,
250                                      G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
251         g_object_class_install_property (
252                 object_class, PROP_REMOTE_ADDRESS,
253                 g_param_spec_object (SOUP_SOCKET_REMOTE_ADDRESS,
254                                      "Remote address",
255                                      "Address of remote end of socket",
256                                      SOUP_TYPE_ADDRESS,
257                                      G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
258         g_object_class_install_property (
259                 object_class, PROP_NON_BLOCKING,
260                 g_param_spec_boolean (SOUP_SOCKET_FLAG_NONBLOCKING,
261                                       "Non-blocking",
262                                       "Whether or not the socket uses non-blocking I/O",
263                                       TRUE,
264                                       G_PARAM_READWRITE));
265         g_object_class_install_property (
266                 object_class, PROP_IS_SERVER,
267                 g_param_spec_boolean (SOUP_SOCKET_IS_SERVER,
268                                       "Server",
269                                       "Whether or not the socket is a server socket",
270                                       FALSE,
271                                       G_PARAM_READABLE));
272         g_object_class_install_property (
273                 object_class, PROP_SSL_CREDENTIALS,
274                 g_param_spec_pointer (SOUP_SOCKET_SSL_CREDENTIALS,
275                                       "SSL credentials",
276                                       "SSL credential information, passed from the session to the SSL implementation",
277                                       G_PARAM_READWRITE));
278         g_object_class_install_property (
279                 object_class, PROP_ASYNC_CONTEXT,
280                 g_param_spec_pointer (SOUP_SOCKET_ASYNC_CONTEXT,
281                                       "Async GMainContext",
282                                       "The GMainContext to dispatch this socket's async I/O in",
283                                       G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
284
285         g_object_class_install_property (
286                 object_class, PROP_TIMEOUT,
287                 g_param_spec_uint (SOUP_SOCKET_TIMEOUT,
288                                    "Timeout value",
289                                    "Value in seconds to timeout a blocking I/O",
290                                    0, G_MAXUINT, 0,
291                                    G_PARAM_READWRITE));
292
293 #ifdef G_OS_WIN32
294         /* Make sure WSAStartup() gets called. */
295         soup_address_get_type ();
296 #endif
297 }
298
299
300 static void
301 set_nonblocking (SoupSocketPrivate *priv)
302 {
303 #ifndef G_OS_WIN32
304         int flags;
305 #else
306         u_long val;
307 #endif
308
309         if (priv->sockfd == -1)
310                 return;
311
312 #ifndef G_OS_WIN32
313         flags = fcntl (priv->sockfd, F_GETFL, 0);
314         if (flags != -1) {
315                 if (priv->non_blocking)
316                         flags |= O_NONBLOCK;
317                 else
318                         flags &= ~O_NONBLOCK;
319                 fcntl (priv->sockfd, F_SETFL, flags);
320         }
321 #else
322         val = priv->non_blocking ? 1 : 0;
323         ioctlsocket (priv->sockfd, FIONBIO, &val);
324 #endif
325 }
326
327 static void
328 set_fdflags (SoupSocketPrivate *priv)
329 {
330         int opt;
331         struct timeval timeout;
332 #ifndef G_OS_WIN32
333         int flags;
334 #endif
335
336         if (priv->sockfd == -1)
337                 return;
338
339         set_nonblocking (priv);
340
341 #ifndef G_OS_WIN32
342         flags = fcntl (priv->sockfd, F_GETFD, 0);
343         if (flags != -1) {
344                 flags |= FD_CLOEXEC;
345                 fcntl (priv->sockfd, F_SETFD, flags);
346         }
347 #endif
348
349         opt = 1;
350         setsockopt (priv->sockfd, IPPROTO_TCP,
351                     TCP_NODELAY, (void *) &opt, sizeof (opt));
352         setsockopt (priv->sockfd, SOL_SOCKET,
353                     SO_REUSEADDR, (void *) &opt, sizeof (opt));
354
355         timeout.tv_sec = priv->timeout;
356         timeout.tv_usec = 0;
357         setsockopt (priv->sockfd, SOL_SOCKET,
358                     SO_RCVTIMEO, (void *) &timeout, sizeof (timeout));
359
360         timeout.tv_sec = priv->timeout;
361         timeout.tv_usec = 0;
362         setsockopt (priv->sockfd, SOL_SOCKET,
363                     SO_SNDTIMEO, (void *) &timeout, sizeof (timeout));
364
365 #ifndef G_OS_WIN32
366         priv->iochannel =
367                 g_io_channel_unix_new (priv->sockfd);
368 #else
369         priv->iochannel =
370                 g_io_channel_win32_new_socket (priv->sockfd);
371 #endif
372         g_io_channel_set_close_on_unref (priv->iochannel, TRUE);
373         g_io_channel_set_encoding (priv->iochannel, NULL, NULL);
374         g_io_channel_set_buffered (priv->iochannel, FALSE);
375 }
376
377 static void
378 set_property (GObject *object, guint prop_id,
379               const GValue *value, GParamSpec *pspec)
380 {
381         SoupSocketPrivate *priv = SOUP_SOCKET_GET_PRIVATE (object);
382
383         switch (prop_id) {
384         case PROP_LOCAL_ADDRESS:
385                 priv->local_addr = (SoupAddress *)g_value_dup_object (value);
386                 break;
387         case PROP_REMOTE_ADDRESS:
388                 priv->remote_addr = (SoupAddress *)g_value_dup_object (value);
389                 break;
390         case PROP_NON_BLOCKING:
391                 priv->non_blocking = g_value_get_boolean (value);
392                 set_nonblocking (priv);
393                 break;
394         case PROP_SSL_CREDENTIALS:
395                 priv->ssl_creds = g_value_get_pointer (value);
396                 break;
397         case PROP_ASYNC_CONTEXT:
398                 priv->async_context = g_value_get_pointer (value);
399                 if (priv->async_context)
400                         g_main_context_ref (priv->async_context);
401                 break;
402         case PROP_TIMEOUT:
403                 priv->timeout = g_value_get_uint (value);
404                 break;
405         default:
406                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
407                 break;
408         }
409 }
410
411 static void
412 get_property (GObject *object, guint prop_id,
413               GValue *value, GParamSpec *pspec)
414 {
415         SoupSocketPrivate *priv = SOUP_SOCKET_GET_PRIVATE (object);
416
417         switch (prop_id) {
418         case PROP_LOCAL_ADDRESS:
419                 g_value_set_object (value, soup_socket_get_local_address (SOUP_SOCKET (object)));
420                 break;
421         case PROP_REMOTE_ADDRESS:
422                 g_value_set_object (value, soup_socket_get_remote_address (SOUP_SOCKET (object)));
423                 break;
424         case PROP_NON_BLOCKING:
425                 g_value_set_boolean (value, priv->non_blocking);
426                 break;
427         case PROP_IS_SERVER:
428                 g_value_set_boolean (value, priv->is_server);
429                 break;
430         case PROP_SSL_CREDENTIALS:
431                 g_value_set_pointer (value, priv->ssl_creds);
432                 break;
433         case PROP_ASYNC_CONTEXT:
434                 g_value_set_pointer (value, priv->async_context ? g_main_context_ref (priv->async_context) : NULL);
435                 break;
436         case PROP_TIMEOUT:
437                 g_value_set_uint (value, priv->timeout);
438                 break;
439         default:
440                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
441                 break;
442         }
443 }
444
445
446 /**
447  * soup_socket_new:
448  * @optname1: name of first property to set (or %NULL)
449  * @...: value of @optname1, followed by additional property/value pairs
450  *
451  * Creates a new (disconnected) socket
452  *
453  * Return value: the new socket
454  **/
455 SoupSocket *
456 soup_socket_new (const char *optname1, ...)
457 {
458         SoupSocket *sock;
459         va_list ap;
460
461         va_start (ap, optname1);
462         sock = (SoupSocket *)g_object_new_valist (SOUP_TYPE_SOCKET,
463                                                   optname1, ap);
464         va_end (ap);
465
466         return sock;
467 }
468
469 typedef struct {
470         SoupSocket *sock;
471         GCancellable *cancellable;
472         guint cancel_id;
473         SoupSocketCallback callback;
474         gpointer user_data;
475 } SoupSocketAsyncConnectData;
476
477 static gboolean
478 idle_connect_result (gpointer user_data)
479 {
480         SoupSocketAsyncConnectData *sacd = user_data;
481         SoupSocketPrivate *priv = SOUP_SOCKET_GET_PRIVATE (sacd->sock);
482         guint status;
483
484         priv->watch_src = NULL;
485         if (sacd->cancel_id)
486                 g_signal_handler_disconnect (sacd->cancellable, sacd->cancel_id);
487
488         if (priv->sockfd == -1) {
489                 if (g_cancellable_is_cancelled (sacd->cancellable))
490                         status = SOUP_STATUS_CANCELLED;
491                 else
492                         status = SOUP_STATUS_CANT_CONNECT;
493         } else
494                 status = SOUP_STATUS_OK;
495
496         sacd->callback (sacd->sock, status, sacd->user_data);
497         g_slice_free (SoupSocketAsyncConnectData, sacd);
498         return FALSE;
499 }
500
501 static gboolean
502 connect_watch (GIOChannel* iochannel, GIOCondition condition, gpointer data)
503 {
504         SoupSocketAsyncConnectData *sacd = data;
505         SoupSocketPrivate *priv = SOUP_SOCKET_GET_PRIVATE (sacd->sock);
506         int error = 0;
507         int len = sizeof (error);
508
509         /* Remove the watch now in case we don't return immediately */
510         g_source_destroy (priv->watch_src);
511         priv->watch_src = NULL;
512
513         if ((condition & ~(G_IO_IN | G_IO_OUT)) ||
514             (getsockopt (priv->sockfd, SOL_SOCKET, SO_ERROR,
515                          (void *)&error, (void *)&len) != 0) ||
516             error)
517                 disconnect_internal (priv);
518
519         return idle_connect_result (sacd);
520 }
521
522 static void
523 got_address (SoupAddress *addr, guint status, gpointer user_data)
524 {
525         SoupSocketAsyncConnectData *sacd = user_data;
526
527         if (!SOUP_STATUS_IS_SUCCESSFUL (status)) {
528                 sacd->callback (sacd->sock, status, sacd->user_data);
529                 g_slice_free (SoupSocketAsyncConnectData, sacd);
530                 return;
531         }
532
533         soup_socket_connect_async (sacd->sock, sacd->cancellable,
534                                    sacd->callback, sacd->user_data);
535         g_slice_free (SoupSocketAsyncConnectData, sacd);
536 }
537
538 static void
539 async_cancel (GCancellable *cancellable, gpointer user_data)
540 {
541         SoupSocketAsyncConnectData *sacd = user_data;
542         SoupSocketPrivate *priv = SOUP_SOCKET_GET_PRIVATE (sacd->sock);
543
544         if (priv->watch_src)
545                 g_source_destroy (priv->watch_src);
546         disconnect_internal (priv);
547         priv->watch_src = soup_add_idle (priv->async_context,
548                                          idle_connect_result, sacd);
549 }
550
551 static guint
552 socket_connect_internal (SoupSocket *sock)
553 {
554         SoupSocketPrivate *priv = SOUP_SOCKET_GET_PRIVATE (sock);
555         struct sockaddr *sa;
556         int len, status;
557
558         sa = soup_address_get_sockaddr (priv->remote_addr, &len);
559         if (!sa)
560                 return SOUP_STATUS_CANT_RESOLVE;
561
562         priv->sockfd = socket (sa->sa_family, SOCK_STREAM, 0);
563         if (SOUP_IS_INVALID_SOCKET (priv->sockfd))
564                 return SOUP_STATUS_CANT_CONNECT;
565         set_fdflags (priv);
566
567         status = connect (priv->sockfd, sa, len);
568
569         if (SOUP_IS_SOCKET_ERROR (status)) {
570                 if (SOUP_IS_CONNECT_STATUS_INPROGRESS ())
571                         return SOUP_STATUS_CONTINUE;
572
573                 disconnect_internal (priv);
574                 return SOUP_STATUS_CANT_CONNECT;
575         } else
576                 return SOUP_STATUS_OK;
577 }
578
579 /**
580  * SoupSocketCallback:
581  * @sock: the #SoupSocket
582  * @status: an HTTP status code indicating success or failure
583  * @user_data: the data passed to soup_socket_connect_async()
584  *
585  * The callback function passed to soup_socket_connect_async().
586  **/
587
588 /**
589  * soup_socket_connect_async:
590  * @sock: a client #SoupSocket (which must not already be connected)
591  * @cancellable: a #GCancellable, or %NULL
592  * @callback: callback to call after connecting
593  * @user_data: data to pass to @callback
594  *
595  * Begins asynchronously connecting to @sock's remote address. The
596  * socket will call @callback when it succeeds or fails (but not
597  * before returning from this function).
598  *
599  * If @cancellable is non-%NULL, it can be used to cancel the
600  * connection. @callback will still be invoked in this case, with a
601  * status of %SOUP_STATUS_CANCELLED.
602  **/
603 void
604 soup_socket_connect_async (SoupSocket *sock, GCancellable *cancellable,
605                            SoupSocketCallback callback, gpointer user_data)
606 {
607         SoupSocketPrivate *priv;
608         SoupSocketAsyncConnectData *sacd;
609         guint status;
610
611         g_return_if_fail (SOUP_IS_SOCKET (sock));
612         priv = SOUP_SOCKET_GET_PRIVATE (sock);
613         g_return_if_fail (priv->remote_addr != NULL);
614
615         sacd = g_slice_new0 (SoupSocketAsyncConnectData);
616         sacd->sock = sock;
617         sacd->cancellable = cancellable;
618         sacd->callback = callback;
619         sacd->user_data = user_data;
620
621         if (!soup_address_get_sockaddr (priv->remote_addr, NULL)) {
622                 soup_address_resolve_async (priv->remote_addr,
623                                             priv->async_context,
624                                             cancellable,
625                                             got_address, sacd);
626                 return;
627         }
628
629         status = socket_connect_internal (sock);
630         if (status == SOUP_STATUS_CONTINUE) {
631                 /* Wait for connect to succeed or fail */
632                 priv->watch_src =
633                         soup_add_io_watch (priv->async_context,
634                                            priv->iochannel,
635                                            G_IO_IN | G_IO_OUT |
636                                            G_IO_PRI | G_IO_ERR |
637                                            G_IO_HUP | G_IO_NVAL,
638                                            connect_watch, sacd);
639                 if (cancellable) {
640                         sacd->cancel_id =
641                                 g_signal_connect (cancellable, "cancelled",
642                                                   G_CALLBACK (async_cancel),
643                                                   sacd);
644                 }
645         } else {
646                 priv->watch_src = soup_add_idle (priv->async_context,
647                                                  idle_connect_result, sacd);
648         }
649 }
650
651 static void
652 sync_cancel (GCancellable *cancellable, gpointer sock)
653 {
654         SoupSocketPrivate *priv = SOUP_SOCKET_GET_PRIVATE (sock);
655
656         shutdown (priv->sockfd, SHUT_RDWR);
657 }
658
659 /**
660  * soup_socket_connect_sync:
661  * @sock: a client #SoupSocket (which must not already be connected)
662  * @cancellable: a #GCancellable, or %NULL
663  *
664  * Attempt to synchronously connect @sock to its remote address.
665  *
666  * If @cancellable is non-%NULL, it can be used to cancel the
667  * connection, in which case soup_socket_connect_sync() will return
668  * %SOUP_STATUS_CANCELLED.
669  *
670  * Return value: a success or failure code.
671  **/
672 guint
673 soup_socket_connect_sync (SoupSocket *sock, GCancellable *cancellable)
674 {
675         SoupSocketPrivate *priv;
676         guint status, cancel_id;
677
678         g_return_val_if_fail (SOUP_IS_SOCKET (sock), SOUP_STATUS_MALFORMED);
679         priv = SOUP_SOCKET_GET_PRIVATE (sock);
680         g_return_val_if_fail (!priv->is_server, SOUP_STATUS_MALFORMED);
681         g_return_val_if_fail (priv->sockfd == -1, SOUP_STATUS_MALFORMED);
682         g_return_val_if_fail (priv->remote_addr != NULL, SOUP_STATUS_MALFORMED);
683
684         if (!soup_address_get_sockaddr (priv->remote_addr, NULL)) {
685                 status = soup_address_resolve_sync (priv->remote_addr,
686                                                     cancellable);
687                 if (!SOUP_STATUS_IS_SUCCESSFUL (status))
688                         return status;
689         }
690
691         if (cancellable) {
692                 cancel_id = g_signal_connect (cancellable, "cancelled",
693                                               G_CALLBACK (sync_cancel), sock);
694         }
695
696         status = socket_connect_internal (sock);
697
698         if (cancellable) {
699                 if (status != SOUP_STATUS_OK &&
700                     g_cancellable_is_cancelled (cancellable)) {
701                         status = SOUP_STATUS_CANCELLED;
702                         disconnect_internal (priv);
703                 }
704                 g_signal_handler_disconnect (cancellable, cancel_id);
705         }
706
707         return status;
708 }
709
710 static gboolean
711 listen_watch (GIOChannel* iochannel, GIOCondition condition, gpointer data)
712 {
713         SoupSocket *sock = data, *new;
714         SoupSocketPrivate *priv = SOUP_SOCKET_GET_PRIVATE (sock), *new_priv;
715         struct soup_sockaddr_max sa;
716         int sa_len, sockfd;
717
718         if (condition & (G_IO_HUP | G_IO_ERR)) {
719                 g_source_destroy (priv->watch_src);
720                 priv->watch_src = NULL;
721                 return FALSE;
722         }
723
724         sa_len = sizeof (sa);
725         sockfd = accept (priv->sockfd, (struct sockaddr *)&sa, (void *)&sa_len);
726         if (SOUP_IS_INVALID_SOCKET (sockfd))
727                 return TRUE;
728
729         new = g_object_new (SOUP_TYPE_SOCKET, NULL);
730         new_priv = SOUP_SOCKET_GET_PRIVATE (new);
731         new_priv->sockfd = sockfd;
732         if (priv->async_context)
733                 new_priv->async_context = g_main_context_ref (priv->async_context);
734         new_priv->non_blocking = priv->non_blocking;
735         new_priv->is_server = TRUE;
736         new_priv->ssl_creds = priv->ssl_creds;
737         set_fdflags (new_priv);
738
739         new_priv->remote_addr = soup_address_new_from_sockaddr ((struct sockaddr *)&sa, sa_len);
740
741         if (new_priv->ssl_creds) {
742                 if (!soup_socket_start_ssl (new, NULL)) {
743                         g_object_unref (new);
744                         return TRUE;
745                 }
746         }
747
748         g_signal_emit (sock, signals[NEW_CONNECTION], 0, new);
749         g_object_unref (new);
750
751         return TRUE;
752 }
753
754 /**
755  * soup_socket_listen:
756  * @sock: a server #SoupSocket (which must not already be connected or
757  * listening)
758  *
759  * Makes @sock start listening on its local address. When connections
760  * come in, @sock will emit %new_connection.
761  *
762  * Return value: whether or not @sock is now listening.
763  **/
764 gboolean
765 soup_socket_listen (SoupSocket *sock)
766
767 {
768         SoupSocketPrivate *priv;
769         struct sockaddr *sa;
770         int sa_len;
771
772         g_return_val_if_fail (SOUP_IS_SOCKET (sock), FALSE);
773         priv = SOUP_SOCKET_GET_PRIVATE (sock);
774         g_return_val_if_fail (priv->sockfd == -1, FALSE);
775         g_return_val_if_fail (priv->local_addr != NULL, FALSE);
776
777         priv->is_server = TRUE;
778
779         /* @local_addr may have its port set to 0. So we intentionally
780          * don't store it in priv->local_addr, so that if the
781          * caller calls soup_socket_get_local_address() later, we'll
782          * have to make a new addr by calling getsockname(), which
783          * will have the right port number.
784          */
785         sa = soup_address_get_sockaddr (priv->local_addr, &sa_len);
786         g_return_val_if_fail (sa != NULL, FALSE);
787
788         priv->sockfd = socket (sa->sa_family, SOCK_STREAM, 0);
789         if (SOUP_IS_INVALID_SOCKET (priv->sockfd))
790                 goto cant_listen;
791         set_fdflags (priv);
792
793         /* Bind */
794         if (bind (priv->sockfd, sa, sa_len) != 0)
795                 goto cant_listen;
796         /* Force local_addr to be re-resolved now */
797         g_object_unref (priv->local_addr);
798         priv->local_addr = NULL;
799
800         /* Listen */
801         if (listen (priv->sockfd, 10) != 0)
802                 goto cant_listen;
803
804         priv->watch_src = soup_add_io_watch (priv->async_context,
805                                              priv->iochannel,
806                                              G_IO_IN | G_IO_ERR | G_IO_HUP,
807                                              listen_watch, sock);
808         return TRUE;
809
810  cant_listen:
811         if (priv->iochannel)
812                 disconnect_internal (priv);
813
814         return FALSE;
815 }
816
817 /**
818  * soup_socket_start_ssl:
819  * @sock: the socket
820  * @cancellable: a #GCancellable
821  *
822  * Starts using SSL on @socket.
823  *
824  * Return value: success or failure
825  **/
826 gboolean
827 soup_socket_start_ssl (SoupSocket *sock, GCancellable *cancellable)
828 {
829         SoupSocketPrivate *priv = SOUP_SOCKET_GET_PRIVATE (sock);
830
831         return soup_socket_start_proxy_ssl (sock, soup_address_get_name (priv->remote_addr), cancellable);
832 }
833         
834 /**
835  * soup_socket_start_proxy_ssl:
836  * @sock: the socket
837  * @ssl_host: hostname of the SSL server
838  * @cancellable: a #GCancellable
839  *
840  * Starts using SSL on @socket, expecting to find a host named
841  * @ssl_host.
842  *
843  * Return value: success or failure
844  **/
845 gboolean
846 soup_socket_start_proxy_ssl (SoupSocket *sock, const char *ssl_host,
847                              GCancellable *cancellable)
848 {
849         SoupSocketPrivate *priv = SOUP_SOCKET_GET_PRIVATE (sock);
850         GIOChannel *ssl_chan;
851         GIOChannel *real_chan;
852
853         real_chan = priv->iochannel;
854         ssl_chan = soup_ssl_wrap_iochannel (
855                 real_chan, priv->is_server ?
856                 SOUP_SSL_TYPE_SERVER : SOUP_SSL_TYPE_CLIENT,
857                 ssl_host, priv->ssl_creds);
858
859         if (!ssl_chan)
860                 return FALSE;
861
862         priv->iochannel = ssl_chan;
863         g_io_channel_unref (real_chan);
864
865         return TRUE;
866 }
867         
868 /**
869  * soup_socket_is_ssl:
870  * @sock: a #SoupSocket
871  *
872  * Tests if @sock is set up to do SSL. Note that this simply means
873  * that the %SOUP_SOCKET_SSL_CREDENTIALS property has been set; it
874  * does not mean that soup_socket_start_ssl() has been called.
875  *
876  * Return value: %TRUE if @sock has SSL credentials set
877  **/
878 gboolean
879 soup_socket_is_ssl (SoupSocket *sock)
880 {
881         SoupSocketPrivate *priv = SOUP_SOCKET_GET_PRIVATE (sock);
882
883         return priv->ssl_creds != NULL;
884 }
885
886 /**
887  * soup_socket_disconnect:
888  * @sock: a #SoupSocket
889  *
890  * Disconnects @sock. Any further read or write attempts on it will
891  * fail.
892  **/
893 void
894 soup_socket_disconnect (SoupSocket *sock)
895 {
896         SoupSocketPrivate *priv;
897         gboolean already_disconnected = FALSE;
898
899         g_return_if_fail (SOUP_IS_SOCKET (sock));
900         priv = SOUP_SOCKET_GET_PRIVATE (sock);
901
902         if (g_mutex_trylock (priv->iolock)) {
903                 if (priv->iochannel)
904                         disconnect_internal (priv);
905                 else
906                         already_disconnected = TRUE;
907                 g_mutex_unlock (priv->iolock);
908         } else {
909                 int sockfd;
910
911                 /* Another thread is currently doing IO, so
912                  * we can't close the iochannel. So just shutdown
913                  * the file descriptor to force the I/O to fail.
914                  * (It will actually be closed when the socket is
915                  * destroyed.)
916                  */
917                 sockfd = priv->sockfd;
918                 priv->sockfd = -1;
919
920                 if (sockfd == -1)
921                         already_disconnected = TRUE;
922                 else
923                         shutdown (sockfd, SHUT_RDWR);
924         }
925
926         if (already_disconnected)
927                 return;
928
929         /* Give all readers a chance to notice the connection close */
930         g_signal_emit (sock, signals[READABLE], 0);
931
932         /* FIXME: can't disconnect until all data is read */
933
934         /* Then let everyone know we're disconnected */
935         g_signal_emit (sock, signals[DISCONNECTED], 0);
936 }
937
938 /**
939  * soup_socket_is_connected:
940  * @sock: a #SoupSocket
941  *
942  * Tests if @sock is connected to another host
943  *
944  * Return value: %TRUE or %FALSE.
945  **/
946 gboolean
947 soup_socket_is_connected (SoupSocket *sock)
948 {
949         SoupSocketPrivate *priv;
950
951         g_return_val_if_fail (SOUP_IS_SOCKET (sock), FALSE);
952         priv = SOUP_SOCKET_GET_PRIVATE (sock);
953
954         return priv->iochannel != NULL;
955 }
956
957 /**
958  * soup_socket_get_local_address:
959  * @sock: a #SoupSocket
960  *
961  * Returns the #SoupAddress corresponding to the local end of @sock.
962  *
963  * Return value: the #SoupAddress
964  **/
965 SoupAddress *
966 soup_socket_get_local_address (SoupSocket *sock)
967 {
968         SoupSocketPrivate *priv;
969
970         g_return_val_if_fail (SOUP_IS_SOCKET (sock), NULL);
971         priv = SOUP_SOCKET_GET_PRIVATE (sock);
972
973         g_mutex_lock (priv->addrlock);
974         if (!priv->local_addr) {
975                 struct soup_sockaddr_max bound_sa;
976                 int sa_len;
977
978                 sa_len = sizeof (bound_sa);
979                 getsockname (priv->sockfd, (struct sockaddr *)&bound_sa, (void *)&sa_len);
980                 priv->local_addr = soup_address_new_from_sockaddr ((struct sockaddr *)&bound_sa, sa_len);
981         }
982         g_mutex_unlock (priv->addrlock);
983
984         return priv->local_addr;
985 }
986
987 /**
988  * soup_socket_get_remote_address:
989  * @sock: a #SoupSocket
990  *
991  * Returns the #SoupAddress corresponding to the remote end of @sock.
992  *
993  * Return value: the #SoupAddress
994  **/
995 SoupAddress *
996 soup_socket_get_remote_address (SoupSocket *sock)
997 {
998         SoupSocketPrivate *priv;
999
1000         g_return_val_if_fail (SOUP_IS_SOCKET (sock), NULL);
1001         priv = SOUP_SOCKET_GET_PRIVATE (sock);
1002
1003         g_mutex_lock (priv->addrlock);
1004         if (!priv->remote_addr) {
1005                 struct soup_sockaddr_max bound_sa;
1006                 int sa_len;
1007
1008                 sa_len = sizeof (bound_sa);
1009                 getpeername (priv->sockfd, (struct sockaddr *)&bound_sa, (void *)&sa_len);
1010                 priv->remote_addr = soup_address_new_from_sockaddr ((struct sockaddr *)&bound_sa, sa_len);
1011         }
1012         g_mutex_unlock (priv->addrlock);
1013
1014         return priv->remote_addr;
1015 }
1016
1017
1018
1019
1020 static gboolean
1021 socket_read_watch (GIOChannel *chan, GIOCondition cond, gpointer user_data)
1022 {
1023         SoupSocket *sock = user_data;
1024         SoupSocketPrivate *priv = SOUP_SOCKET_GET_PRIVATE (sock);
1025
1026         priv->read_src = NULL;
1027
1028         if (cond & (G_IO_ERR | G_IO_HUP))
1029                 soup_socket_disconnect (sock);
1030         else
1031                 g_signal_emit (sock, signals[READABLE], 0);
1032
1033         return FALSE;
1034 }
1035
1036 static SoupSocketIOStatus
1037 read_from_network (SoupSocket *sock, gpointer buffer, gsize len,
1038                    gsize *nread, GError **error)
1039 {
1040         SoupSocketPrivate *priv = SOUP_SOCKET_GET_PRIVATE (sock);
1041         GIOStatus status;
1042         GIOCondition cond = G_IO_IN;
1043         GError *my_err = NULL;
1044
1045         *nread = 0;
1046
1047         if (!priv->iochannel)
1048                 return SOUP_SOCKET_EOF;
1049
1050         status = g_io_channel_read_chars (priv->iochannel,
1051                                           buffer, len, nread, &my_err);
1052         if (my_err) {
1053                 if (my_err->domain == SOUP_SSL_ERROR &&
1054                     my_err->code == SOUP_SSL_ERROR_HANDSHAKE_NEEDS_WRITE)
1055                         cond = G_IO_OUT;
1056                 g_propagate_error (error, my_err);
1057         }
1058
1059         switch (status) {
1060         case G_IO_STATUS_NORMAL:
1061         case G_IO_STATUS_AGAIN:
1062                 if (*nread > 0) {
1063                         g_clear_error (error);
1064                         return SOUP_SOCKET_OK;
1065                 }
1066
1067                 /* If the socket is sync and we get EAGAIN, then it is
1068                  * a socket timeout and should be treated as an error
1069                  * condition.
1070                  */
1071                 if (!priv->non_blocking)
1072                         return SOUP_SOCKET_ERROR;
1073
1074                 if (!priv->read_src) {
1075                         priv->read_src =
1076                                 soup_add_io_watch (priv->async_context,
1077                                                    priv->iochannel,
1078                                                    cond | G_IO_HUP | G_IO_ERR,
1079                                                    socket_read_watch, sock);
1080                 }
1081                 g_clear_error (error);
1082                 return SOUP_SOCKET_WOULD_BLOCK;
1083
1084         case G_IO_STATUS_EOF:
1085                 g_clear_error (error);
1086                 return SOUP_SOCKET_EOF;
1087
1088         default:
1089                 return SOUP_SOCKET_ERROR;
1090         }
1091 }
1092
1093 static SoupSocketIOStatus
1094 read_from_buf (SoupSocket *sock, gpointer buffer, gsize len, gsize *nread)
1095 {
1096         SoupSocketPrivate *priv = SOUP_SOCKET_GET_PRIVATE (sock);
1097         GByteArray *read_buf = priv->read_buf;
1098
1099         *nread = MIN (read_buf->len, len);
1100         memcpy (buffer, read_buf->data, *nread);
1101
1102         if (*nread == read_buf->len) {
1103                 g_byte_array_free (read_buf, TRUE);
1104                 priv->read_buf = NULL;
1105         } else {
1106                 memmove (read_buf->data, read_buf->data + *nread, 
1107                          read_buf->len - *nread);
1108                 g_byte_array_set_size (read_buf, read_buf->len - *nread);
1109         }
1110
1111         return SOUP_SOCKET_OK;
1112 }
1113
1114 /**
1115  * SoupSocketIOStatus:
1116  * @SOUP_SOCKET_OK: Success
1117  * @SOUP_SOCKET_WOULD_BLOCK: Cannot read/write any more at this time
1118  * @SOUP_SOCKET_EOF: End of file
1119  * @SOUP_SOCKET_ERROR: Other error
1120  *
1121  * Return value from the #SoupSocket IO methods.
1122  **/
1123
1124 /**
1125  * soup_socket_read:
1126  * @sock: the socket
1127  * @buffer: buffer to read into
1128  * @len: size of @buffer in bytes
1129  * @nread: on return, the number of bytes read into @buffer
1130  * @cancellable: a #GCancellable, or %NULL
1131  * @error: error pointer
1132  *
1133  * Attempts to read up to @len bytes from @sock into @buffer. If some
1134  * data is successfully read, soup_socket_read() will return
1135  * %SOUP_SOCKET_OK, and *@nread will contain the number of bytes
1136  * actually read.
1137  *
1138  * If @sock is non-blocking, and no data is available, the return
1139  * value will be %SOUP_SOCKET_WOULD_BLOCK. In this case, the caller
1140  * can connect to the %readable signal to know when there is more data
1141  * to read. (NB: You MUST read all available data off the socket
1142  * first. The %readable signal will only be emitted after
1143  * soup_socket_read() has returned %SOUP_SOCKET_WOULD_BLOCK.)
1144  *
1145  * Return value: a #SoupSocketIOStatus, as described above (or
1146  * %SOUP_SOCKET_EOF if the socket is no longer connected, or
1147  * %SOUP_SOCKET_ERROR on any other error, in which case @error will
1148  * also be set).
1149  **/
1150 SoupSocketIOStatus
1151 soup_socket_read (SoupSocket *sock, gpointer buffer, gsize len,
1152                   gsize *nread, GCancellable *cancellable, GError **error)
1153 {
1154         SoupSocketPrivate *priv;
1155         SoupSocketIOStatus status;
1156
1157         g_return_val_if_fail (SOUP_IS_SOCKET (sock), SOUP_SOCKET_ERROR);
1158         g_return_val_if_fail (nread != NULL, SOUP_SOCKET_ERROR);
1159
1160         priv = SOUP_SOCKET_GET_PRIVATE (sock);
1161
1162         g_mutex_lock (priv->iolock);
1163         if (priv->read_buf)
1164                 status = read_from_buf (sock, buffer, len, nread);
1165         else
1166                 status = read_from_network (sock, buffer, len, nread, error);
1167         g_mutex_unlock (priv->iolock);
1168
1169         return status;
1170 }
1171
1172 /**
1173  * soup_socket_read_until:
1174  * @sock: the socket
1175  * @buffer: buffer to read into
1176  * @len: size of @buffer in bytes
1177  * @boundary: boundary to read until
1178  * @boundary_len: length of @boundary in bytes
1179  * @nread: on return, the number of bytes read into @buffer
1180  * @got_boundary: on return, whether or not the data in @buffer
1181  * ends with the boundary string
1182  * @cancellable: a #GCancellable, or %NULL
1183  * @error: error pointer
1184  *
1185  * Like soup_socket_read(), but reads no further than the first
1186  * occurrence of @boundary. (If the boundary is found, it will be
1187  * included in the returned data, and *@got_boundary will be set to
1188  * %TRUE.) Any data after the boundary will returned in future reads.
1189  *
1190  * Return value: as for soup_socket_read()
1191  **/
1192 SoupSocketIOStatus
1193 soup_socket_read_until (SoupSocket *sock, gpointer buffer, gsize len,
1194                         gconstpointer boundary, gsize boundary_len,
1195                         gsize *nread, gboolean *got_boundary,
1196                         GCancellable *cancellable, GError **error)
1197 {
1198         SoupSocketPrivate *priv;
1199         SoupSocketIOStatus status;
1200         GByteArray *read_buf;
1201         guint match_len, prev_len;
1202         guint8 *p, *end;
1203
1204         g_return_val_if_fail (SOUP_IS_SOCKET (sock), SOUP_SOCKET_ERROR);
1205         g_return_val_if_fail (nread != NULL, SOUP_SOCKET_ERROR);
1206         g_return_val_if_fail (len >= boundary_len, SOUP_SOCKET_ERROR);
1207
1208         priv = SOUP_SOCKET_GET_PRIVATE (sock);
1209
1210         g_mutex_lock (priv->iolock);
1211
1212         *got_boundary = FALSE;
1213
1214         if (!priv->read_buf)
1215                 priv->read_buf = g_byte_array_new ();
1216         read_buf = priv->read_buf;
1217
1218         if (read_buf->len < boundary_len) {
1219                 prev_len = read_buf->len;
1220                 g_byte_array_set_size (read_buf, len);
1221                 status = read_from_network (sock,
1222                                             read_buf->data + prev_len,
1223                                             len - prev_len, nread, error);
1224                 read_buf->len = prev_len + *nread;
1225
1226                 if (status != SOUP_SOCKET_OK) {
1227                         g_mutex_unlock (priv->iolock);
1228                         return status;
1229                 }
1230         }
1231
1232         /* Scan for the boundary */
1233         end = read_buf->data + read_buf->len;
1234         for (p = read_buf->data; p <= end - boundary_len; p++) {
1235                 if (!memcmp (p, boundary, boundary_len)) {
1236                         p += boundary_len;
1237                         *got_boundary = TRUE;
1238                         break;
1239                 }
1240         }
1241
1242         /* Return everything up to 'p' (which is either just after the
1243          * boundary, or @boundary_len - 1 bytes before the end of the
1244          * buffer).
1245          */
1246         match_len = p - read_buf->data;
1247         status = read_from_buf (sock, buffer, MIN (len, match_len), nread);
1248
1249         g_mutex_unlock (priv->iolock);
1250         return status;
1251 }
1252
1253 static gboolean
1254 socket_write_watch (GIOChannel *chan, GIOCondition cond, gpointer user_data)
1255 {
1256         SoupSocket *sock = user_data;
1257         SoupSocketPrivate *priv = SOUP_SOCKET_GET_PRIVATE (sock);
1258
1259         priv->write_src = NULL;
1260
1261         if (cond & (G_IO_ERR | G_IO_HUP))
1262                 soup_socket_disconnect (sock);
1263         else
1264                 g_signal_emit (sock, signals[WRITABLE], 0);
1265
1266         return FALSE;
1267 }
1268
1269 /**
1270  * soup_socket_write:
1271  * @sock: the socket
1272  * @buffer: data to write
1273  * @len: size of @buffer, in bytes
1274  * @nwrote: on return, number of bytes written
1275  * @cancellable: a #GCancellable, or %NULL
1276  * @error: error pointer
1277  *
1278  * Attempts to write @len bytes from @buffer to @sock. If some data is
1279  * successfully written, the resturn status will be
1280  * %SOUP_SOCKET_OK, and *@nwrote will contain the number of bytes
1281  * actually written.
1282  *
1283  * If @sock is non-blocking, and no data could be written right away,
1284  * the return value will be %SOUP_SOCKET_WOULD_BLOCK. In this case,
1285  * the caller can connect to the %writable signal to know when more
1286  * data can be written. (NB: %writable is only emitted after a
1287  * %SOUP_SOCKET_WOULD_BLOCK.)
1288  *
1289  * Return value: a #SoupSocketIOStatus, as described above (or
1290  * %SOUP_SOCKET_EOF or %SOUP_SOCKET_ERROR. @error will be set if the
1291  * return value is %SOUP_SOCKET_ERROR.)
1292  **/
1293 SoupSocketIOStatus
1294 soup_socket_write (SoupSocket *sock, gconstpointer buffer,
1295                    gsize len, gsize *nwrote,
1296                    GCancellable *cancellable, GError **error)
1297 {
1298         SoupSocketPrivate *priv;
1299         GIOStatus status;
1300 #ifdef SIGPIPE
1301         gpointer pipe_handler;
1302 #endif
1303         GIOCondition cond = G_IO_OUT;
1304         GError *my_err = NULL;
1305
1306         g_return_val_if_fail (SOUP_IS_SOCKET (sock), SOUP_SOCKET_ERROR);
1307         g_return_val_if_fail (nwrote != NULL, SOUP_SOCKET_ERROR);
1308
1309         priv = SOUP_SOCKET_GET_PRIVATE (sock);
1310
1311         g_mutex_lock (priv->iolock);
1312
1313         if (!priv->iochannel) {
1314                 g_mutex_unlock (priv->iolock);
1315                 return SOUP_SOCKET_EOF;
1316         }
1317         if (priv->write_src) {
1318                 g_mutex_unlock (priv->iolock);
1319                 return SOUP_SOCKET_WOULD_BLOCK;
1320         }
1321
1322 #ifdef SIGPIPE
1323         pipe_handler = signal (SIGPIPE, SIG_IGN);
1324 #endif
1325         status = g_io_channel_write_chars (priv->iochannel,
1326                                            buffer, len, nwrote, &my_err);
1327 #ifdef SIGPIPE
1328         signal (SIGPIPE, pipe_handler);
1329 #endif
1330         if (my_err) {
1331                 if (my_err->domain == SOUP_SSL_ERROR &&
1332                     my_err->code == SOUP_SSL_ERROR_HANDSHAKE_NEEDS_READ)
1333                         cond = G_IO_IN;
1334                 g_propagate_error (error, my_err);
1335         }
1336
1337         /* If the socket is sync and we get EAGAIN, then it is a
1338          * socket timeout and should be treated as an error condition.
1339          */
1340         if (!priv->non_blocking && status == G_IO_STATUS_AGAIN) {
1341                 g_mutex_unlock (priv->iolock);
1342                 return SOUP_SOCKET_ERROR;
1343         }
1344
1345         if (status != G_IO_STATUS_NORMAL && status != G_IO_STATUS_AGAIN) {
1346                 g_mutex_unlock (priv->iolock);
1347                 return SOUP_SOCKET_ERROR;
1348         }
1349
1350         g_clear_error (error);
1351
1352         if (*nwrote) {
1353                 g_mutex_unlock (priv->iolock);
1354                 return SOUP_SOCKET_OK;
1355         }
1356
1357         priv->write_src =
1358                 soup_add_io_watch (priv->async_context,
1359                                    priv->iochannel,
1360                                    cond | G_IO_HUP | G_IO_ERR, 
1361                                    socket_write_watch, sock);
1362         g_mutex_unlock (priv->iolock);
1363         return SOUP_SOCKET_WOULD_BLOCK;
1364 }