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