Beginnings of improved synchronous API support
[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-private.h"
20 #include "soup-socket.h"
21 #include "soup-marshal.h"
22 #include "soup-ssl.h"
23
24 #include <sys/types.h>
25 #include <sys/socket.h>
26 #include <netinet/in.h>
27 #include <netinet/tcp.h>
28
29 #define PARENT_TYPE G_TYPE_OBJECT
30 static GObjectClass *parent_class;
31
32 enum {
33         CONNECT_RESULT,
34         READABLE,
35         WRITABLE,
36         DISCONNECTED,
37         NEW_CONNECTION,
38         LAST_SIGNAL
39 };
40
41 static guint signals[LAST_SIGNAL] = { 0 };
42
43 struct SoupSocketPrivate {
44         int sockfd;
45         SoupAddress *local_addr, *remote_addr;
46         GIOChannel *iochannel;
47
48         guint watch;
49         guint flags;
50
51         guint           read_tag, write_tag, error_tag;
52         GByteArray     *read_buf;
53 };
54
55 #define SOUP_SOCKET_FLAG_SSL    (1<<8)
56
57 #define SOUP_SOCKET_SET_FLAG(sock, flag) (sock)->priv->flags |= (flag)
58 #define SOUP_SOCKET_CLEAR_FLAG(sock, flag) (sock)->priv->flags &= ~(flag)
59 #define SOUP_SOCKET_CHECK_FLAG(sock, flag) ((sock)->priv->flags & (flag))
60
61 static void
62 init (GObject *object)
63 {
64         SoupSocket *sock = SOUP_SOCKET (object);
65
66         sock->priv = g_new0 (SoupSocketPrivate, 1);
67         sock->priv->sockfd = -1;
68 }
69
70 static void
71 disconnect_internal (SoupSocket *sock)
72 {
73         g_io_channel_unref (sock->priv->iochannel);
74         sock->priv->iochannel = NULL;
75
76         if (sock->priv->read_tag) {
77                 g_source_remove (sock->priv->read_tag);
78                 sock->priv->read_tag = 0;
79         }
80         if (sock->priv->write_tag) {
81                 g_source_remove (sock->priv->write_tag);
82                 sock->priv->write_tag = 0;
83         }
84         if (sock->priv->error_tag) {
85                 g_source_remove (sock->priv->error_tag);
86                 sock->priv->error_tag = 0;
87         }
88 }
89
90 static void
91 finalize (GObject *object)
92 {
93         SoupSocket *sock = SOUP_SOCKET (object);
94
95         if (sock->priv->iochannel)
96                 disconnect_internal (sock);
97
98         if (sock->priv->local_addr)
99                 g_object_unref (sock->priv->local_addr);
100         if (sock->priv->remote_addr)
101                 g_object_unref (sock->priv->remote_addr);
102
103         if (sock->priv->watch)
104                 g_source_remove (sock->priv->watch);
105
106         g_free (sock->priv);
107
108         G_OBJECT_CLASS (parent_class)->finalize (object);
109 }
110
111 static void
112 class_init (GObjectClass *object_class)
113 {
114         parent_class = g_type_class_ref (PARENT_TYPE);
115
116         /* virtual method override */
117         object_class->finalize = finalize;
118
119         /* signals */
120         signals[CONNECT_RESULT] =
121                 g_signal_new ("connect_result",
122                               G_OBJECT_CLASS_TYPE (object_class),
123                               G_SIGNAL_RUN_FIRST,
124                               G_STRUCT_OFFSET (SoupSocketClass, connect_result),
125                               NULL, NULL,
126                               soup_marshal_NONE__INT,
127                               G_TYPE_NONE, 1,
128                               G_TYPE_INT);
129         signals[READABLE] =
130                 g_signal_new ("readable",
131                               G_OBJECT_CLASS_TYPE (object_class),
132                               G_SIGNAL_RUN_LAST,
133                               G_STRUCT_OFFSET (SoupSocketClass, readable),
134                               NULL, NULL,
135                               soup_marshal_NONE__NONE,
136                               G_TYPE_NONE, 0);
137         signals[WRITABLE] =
138                 g_signal_new ("writable",
139                               G_OBJECT_CLASS_TYPE (object_class),
140                               G_SIGNAL_RUN_LAST,
141                               G_STRUCT_OFFSET (SoupSocketClass, writable),
142                               NULL, NULL,
143                               soup_marshal_NONE__NONE,
144                               G_TYPE_NONE, 0);
145         signals[DISCONNECTED] =
146                 g_signal_new ("disconnected",
147                               G_OBJECT_CLASS_TYPE (object_class),
148                               G_SIGNAL_RUN_LAST,
149                               G_STRUCT_OFFSET (SoupSocketClass, disconnected),
150                               NULL, NULL,
151                               soup_marshal_NONE__NONE,
152                               G_TYPE_NONE, 0);
153         signals[NEW_CONNECTION] =
154                 g_signal_new ("new_connection",
155                               G_OBJECT_CLASS_TYPE (object_class),
156                               G_SIGNAL_RUN_FIRST,
157                               G_STRUCT_OFFSET (SoupSocketClass, new_connection),
158                               NULL, NULL,
159                               soup_marshal_NONE__OBJECT,
160                               G_TYPE_NONE, 1,
161                               SOUP_TYPE_SOCKET);
162 }
163
164 SOUP_MAKE_TYPE (soup_socket, SoupSocket, class_init, init, PARENT_TYPE)
165
166
167 /**
168  * soup_socket_new:
169  *
170  * Return value: a new (disconnected) socket
171  **/
172 SoupSocket *
173 soup_socket_new (void)
174 {
175         return g_object_new (SOUP_TYPE_SOCKET, NULL);
176 }
177
178 static void
179 update_fdflags (SoupSocket *sock, guint mask)
180 {
181         int flags, opt;
182
183         if (mask & SOUP_SOCKET_FLAG_NONBLOCKING) {
184                 flags = fcntl (sock->priv->sockfd, F_GETFL, 0);
185                 g_return_if_fail (flags != -1);
186
187                 if (sock->priv->flags & SOUP_SOCKET_FLAG_NONBLOCKING)
188                         flags |= O_NONBLOCK;
189                 else
190                         flags &= ~O_NONBLOCK;
191                 fcntl (sock->priv->sockfd, F_SETFL, flags);
192         }
193         if (mask & SOUP_SOCKET_FLAG_NODELAY) {
194                 opt = (sock->priv->flags & SOUP_SOCKET_FLAG_NODELAY) != 0;
195                 setsockopt (sock->priv->sockfd, IPPROTO_TCP,
196                             TCP_NODELAY, &opt, sizeof (opt));
197         }
198         if (mask & SOUP_SOCKET_FLAG_REUSEADDR) {
199                 opt = (sock->priv->flags & SOUP_SOCKET_FLAG_REUSEADDR) != 0;
200                 setsockopt (sock->priv->sockfd, SOL_SOCKET,
201                             SO_REUSEADDR, &opt, sizeof (opt));
202         }
203 }
204
205 void
206 soup_socket_set_flags (SoupSocket *sock, guint mask, guint flags)
207 {
208         g_return_if_fail (SOUP_IS_SOCKET (sock));
209
210         sock->priv->flags |= mask & flags;
211         sock->priv->flags &= ~(mask & ~flags);
212
213         if (sock->priv->sockfd)
214                 update_fdflags (sock, mask);
215 }
216
217 static GIOChannel *
218 get_iochannel (SoupSocket *sock)
219 {
220         if (!sock->priv->iochannel) {
221                 sock->priv->iochannel =
222                         g_io_channel_unix_new (sock->priv->sockfd);
223                 g_io_channel_set_close_on_unref (sock->priv->iochannel, TRUE);
224                 g_io_channel_set_encoding (sock->priv->iochannel, NULL, NULL);
225                 g_io_channel_set_buffered (sock->priv->iochannel, FALSE);
226         }
227         return sock->priv->iochannel;
228 }
229
230 static gboolean
231 connect_watch (GIOChannel* iochannel, GIOCondition condition, gpointer data)
232 {
233         SoupSocket *sock = data;
234         int error = 0;
235         int len = sizeof (error);
236
237         /* Remove the watch now in case we don't return immediately */
238         g_source_remove (sock->priv->watch);
239         sock->priv->watch = 0;
240
241         if (condition & ~(G_IO_IN | G_IO_OUT))
242                 goto cant_connect;
243
244         if (getsockopt (sock->priv->sockfd, SOL_SOCKET, SO_ERROR,
245                         &error, &len) != 0)
246                 goto cant_connect;
247         if (error)
248                 goto cant_connect;
249
250         if (SOUP_SOCKET_CHECK_FLAG (sock, SOUP_SOCKET_FLAG_SSL))
251                 soup_socket_start_ssl (sock);
252
253         g_signal_emit (sock, signals[CONNECT_RESULT], 0, SOUP_STATUS_OK);
254         return FALSE;
255
256  cant_connect:
257         g_signal_emit (sock, signals[CONNECT_RESULT], 0, SOUP_STATUS_CANT_CONNECT);
258         return FALSE;
259 }
260
261 static gboolean
262 idle_connect_result (gpointer user_data)
263 {
264         SoupSocket *sock = user_data;
265
266         sock->priv->watch = 0;
267
268         g_signal_emit (sock, signals[CONNECT_RESULT], 0,
269                        sock->priv->sockfd != -1 ? SOUP_STATUS_OK : SOUP_STATUS_CANT_CONNECT);
270         return FALSE;
271 }
272
273 static void
274 got_address (SoupAddress *addr, guint status, gpointer user_data)
275 {
276         SoupSocket *sock = user_data;
277
278         if (!SOUP_STATUS_IS_SUCCESSFUL (status)) {
279                 g_signal_emit (sock, signals[CONNECT_RESULT], 0, status);
280                 return;
281         }
282
283         soup_socket_connect (sock, sock->priv->remote_addr);
284         /* soup_socket_connect re-reffed addr */
285         g_object_unref (addr);
286 }
287
288 /**
289  * soup_socket_connect:
290  * @sock: a client #SoupSocket (which must not already be connected)
291  * @remote_addr: address to connect to
292  *
293  * If %SOUP_SOCKET_FLAG_NONBLOCKING has been set on the socket, this
294  * begins asynchronously connecting to the given address. The socket
295  * will emit %connect_result when it succeeds or fails (but not before
296  * returning from this function).
297  *
298  * If %SOUP_SOCKET_FLAG_NONBLOCKING has not been set, this will
299  * attempt to synchronously connect.
300  *
301  * Return value: %SOUP_STATUS_CONTINUE if connecting asynchronously,
302  * otherwise a success or failure code.
303  **/
304 guint
305 soup_socket_connect (SoupSocket *sock, SoupAddress *remote_addr)
306 {
307         struct sockaddr *sa;
308         int len, status;
309         gboolean sync;
310
311         g_return_val_if_fail (SOUP_IS_SOCKET (sock), SOUP_STATUS_MALFORMED);
312         g_return_val_if_fail (!SOUP_SOCKET_CHECK_FLAG (sock, SOUP_SOCKET_FLAG_SERVER), FALSE);
313         g_return_val_if_fail (sock->priv->sockfd == -1, SOUP_STATUS_MALFORMED);
314         g_return_val_if_fail (SOUP_IS_ADDRESS (remote_addr), SOUP_STATUS_MALFORMED);
315
316         sync = !(sock->priv->flags & SOUP_SOCKET_FLAG_NONBLOCKING);
317
318         sock->priv->remote_addr = g_object_ref (remote_addr);
319         if (sync) {
320                 status = soup_address_resolve_sync (remote_addr);
321                 if (!SOUP_STATUS_IS_SUCCESSFUL (status))
322                         return status;
323         }
324
325         sa = soup_address_get_sockaddr (sock->priv->remote_addr, &len);
326         if (!sa) {
327                 if (sync)
328                         return SOUP_STATUS_CANT_RESOLVE;
329
330                 soup_address_resolve_async (remote_addr, got_address, sock);
331                 return SOUP_STATUS_CONTINUE;
332         }
333
334         sock->priv->sockfd = socket (sa->sa_family, SOCK_STREAM, 0);
335         if (sock->priv->sockfd == -1) {
336                 g_free (sa);
337                 goto done;
338         }
339         update_fdflags (sock, SOUP_SOCKET_FLAG_ALL);
340
341         status = connect (sock->priv->sockfd, sa, len);
342         g_free (sa);
343
344         if (status == -1) {
345                 if (errno == EINPROGRESS) {
346                         /* Wait for connect to succeed or fail */
347                         sock->priv->watch =
348                                 g_io_add_watch (get_iochannel (sock),
349                                                 G_IO_IN | G_IO_OUT |
350                                                 G_IO_PRI | G_IO_ERR |
351                                                 G_IO_HUP | G_IO_NVAL,
352                                                 connect_watch, sock);
353                         return SOUP_STATUS_CONTINUE;
354                 } else {
355                         close (sock->priv->sockfd);
356                         sock->priv->sockfd = -1;
357                 }
358         }
359
360  done:
361         if (sync) {
362                 return sock->priv->sockfd != -1 ?
363                         SOUP_STATUS_OK : SOUP_STATUS_CANT_CONNECT;
364         } else {
365                 sock->priv->watch = g_idle_add (idle_connect_result, sock);
366                 return SOUP_STATUS_CONTINUE;
367         }
368 }
369
370 static gboolean
371 listen_watch (GIOChannel* iochannel, GIOCondition condition, gpointer data)
372 {
373         SoupSocket *sock = data, *new;
374         struct soup_sockaddr_max sa;
375         int sa_len, sockfd;
376
377         if (condition & (G_IO_HUP | G_IO_ERR)) {
378                 g_source_remove (sock->priv->watch);
379                 sock->priv->watch = 0;
380                 return FALSE;
381         }
382
383         sa_len = sizeof (sa);
384         sockfd = accept (sock->priv->sockfd, (struct sockaddr *)&sa, &sa_len);
385         if (sockfd == -1)
386                 return TRUE;
387
388         new = soup_socket_new ();
389         new->priv->sockfd = sockfd;
390         new->priv->flags = (SOUP_SOCKET_FLAG_NONBLOCKING |
391                             SOUP_SOCKET_FLAG_NODELAY |
392                             SOUP_SOCKET_FLAG_SERVER |
393                             (sock->priv->flags & SOUP_SOCKET_FLAG_SSL));
394         update_fdflags (new, SOUP_SOCKET_FLAG_ALL);
395
396         new->priv->remote_addr = soup_address_new_from_sockaddr ((struct sockaddr *)&sa, sa_len);
397
398         if (SOUP_SOCKET_CHECK_FLAG (new, SOUP_SOCKET_FLAG_SSL))
399                 soup_socket_start_ssl (new);
400         else
401                 get_iochannel (new);
402
403         g_signal_emit (sock, signals[NEW_CONNECTION], 0, new);
404         g_object_unref (new);
405
406         return TRUE;
407 }
408
409 /**
410  * soup_socket_listen:
411  * @sock: a server #SoupSocket (which must not already be connected or
412  * listening)
413  * @local_addr: Local address to bind to.
414  *
415  * Makes @sock start listening on the given interface and port. When
416  * connections come in, @sock will emit %new_connection.
417  *
418  * Return value: whether or not @sock is now listening.
419  **/
420 gboolean
421 soup_socket_listen (SoupSocket *sock, SoupAddress *local_addr)
422 {
423         struct sockaddr *sa;
424         int sa_len;
425
426         g_return_val_if_fail (SOUP_IS_SOCKET (sock), FALSE);
427         g_return_val_if_fail (SOUP_SOCKET_CHECK_FLAG (sock, SOUP_SOCKET_FLAG_SERVER), FALSE);
428         g_return_val_if_fail (sock->priv->sockfd == -1, FALSE);
429         g_return_val_if_fail (SOUP_IS_ADDRESS (local_addr), FALSE);
430
431         /* @local_addr may have its port set to 0. So we intentionally
432          * don't store it in sock->priv->local_addr, so that if the
433          * caller calls soup_socket_get_local_address() later, we'll
434          * have to make a new addr by calling getsockname(), which
435          * will have the right port number.
436          */
437         sa = soup_address_get_sockaddr (local_addr, &sa_len);
438         g_return_val_if_fail (sa != NULL, FALSE);
439
440         sock->priv->sockfd = socket (sa->sa_family, SOCK_STREAM, 0);
441         if (sock->priv->sockfd < 0)
442                 goto cant_listen;
443         update_fdflags (sock, SOUP_SOCKET_FLAG_ALL);
444
445         /* Bind */
446         if (bind (sock->priv->sockfd, sa, sa_len) != 0)
447                 goto cant_listen;
448
449         /* Listen */
450         if (listen (sock->priv->sockfd, 10) != 0)
451                 goto cant_listen;
452
453         sock->priv->watch = g_io_add_watch (get_iochannel (sock),
454                                             G_IO_IN | G_IO_ERR | G_IO_HUP,
455                                             listen_watch, sock);
456         return TRUE;
457
458  cant_listen:
459         if (sock->priv->sockfd != -1) {
460                 close (sock->priv->sockfd);
461                 sock->priv->sockfd = -1;
462         }
463         if (sa)
464                 g_free (sa);
465         return FALSE;
466 }
467
468 /**
469  * soup_socket_start_ssl:
470  * @socket: the socket
471  *
472  * Starts using SSL on @socket.
473  **/
474 void
475 soup_socket_start_ssl (SoupSocket *sock)
476 {
477         GIOChannel *chan;
478
479         chan = get_iochannel (sock);
480         sock->priv->iochannel =
481                 SOUP_SOCKET_CHECK_FLAG (sock, SOUP_SOCKET_FLAG_SERVER) ?
482                 soup_ssl_get_server_iochannel (chan) :
483                 soup_ssl_get_iochannel (chan);
484         SOUP_SOCKET_SET_FLAG (sock, SOUP_SOCKET_FLAG_SSL);
485 }
486         
487
488 /**
489  * soup_socket_client_new_async:
490  * @hostname: remote machine to connect to
491  * @port: remote port to connect to
492  * @ssl: whether or not to use SSL
493  * @callback: callback to call when the socket is connected
494  * @user_data: data for @callback
495  *
496  * Creates a connection to @hostname and @port. @callback will be
497  * called when the connection completes (or fails).
498  *
499  * Return value: the new socket (not yet ready for use).
500  **/
501 SoupSocket *
502 soup_socket_client_new_async (const char *hostname, guint port, gboolean ssl, 
503                               SoupSocketCallback callback, gpointer user_data)
504 {
505         SoupSocket *sock;
506
507         g_return_val_if_fail (hostname != NULL, NULL);
508
509         sock = soup_socket_new ();
510         sock->priv->flags = (SOUP_SOCKET_FLAG_NONBLOCKING |
511                              (ssl ? SOUP_SOCKET_FLAG_SSL : 0));
512         soup_socket_connect (sock, soup_address_new (hostname, port));
513
514         if (callback) {
515                 soup_signal_connect_once (sock, "connect_result",
516                                           G_CALLBACK (callback), user_data);
517         }
518         return sock;
519 }
520
521 /**
522  * soup_socket_client_new_sync:
523  * @hostname: remote machine to connect to
524  * @port: remote port to connect to
525  * @ssl: whether or not to use SSL
526  * @status_ret: pointer to return the soup status in
527  *
528  * Creates a connection to @hostname and @port. If @status_ret is not
529  * %NULL, it will contain a status code on return.
530  *
531  * Return value: the new socket, or %NULL if it could not connect.
532  **/
533 SoupSocket *
534 soup_socket_client_new_sync (const char *hostname, guint port, gboolean ssl,
535                              guint *status_ret)
536 {
537         SoupSocket *sock;
538         guint status;
539
540         g_return_val_if_fail (hostname != NULL, NULL);
541
542         sock = soup_socket_new ();
543         sock->priv->flags = ssl ? SOUP_SOCKET_FLAG_SSL : 0;
544         status = soup_socket_connect (sock, soup_address_new (hostname, port));
545
546         if (!SOUP_STATUS_IS_SUCCESSFUL (status)) {
547                 g_object_unref (sock);
548                 sock = NULL;
549         }
550
551         if (status_ret)
552                 *status_ret = status;
553         return sock;
554 }
555
556 /**
557  * soup_socket_server_new:
558  * @local_addr: Local address to bind to. (Use soup_address_any_new() to
559  * accept connections on any local address)
560  * @ssl: Whether or not this is an SSL server.
561  * @callback: Callback to call when a client connects
562  * @user_data: data to pass to @callback.
563  *
564  * Create and open a new #SoupSocket listening on the specified
565  * address. @callback will be called each time a client connects,
566  * with a new #SoupSocket.
567  *
568  * Returns: a new #SoupSocket, or NULL if there was a failure.
569  **/
570 SoupSocket *
571 soup_socket_server_new (SoupAddress *local_addr, gboolean ssl,
572                         SoupSocketListenerCallback callback,
573                         gpointer user_data)
574 {
575         SoupSocket *sock;
576
577         g_return_val_if_fail (SOUP_IS_ADDRESS (local_addr), NULL);
578
579         sock = soup_socket_new ();
580         sock->priv->flags = (SOUP_SOCKET_FLAG_SERVER |
581                              SOUP_SOCKET_FLAG_NONBLOCKING |
582                              (ssl ? SOUP_SOCKET_FLAG_SSL : 0));
583         if (!soup_socket_listen (sock, local_addr)) {
584                 g_object_unref (sock);
585                 return NULL;
586         }
587
588         if (callback) {
589                 g_signal_connect (sock, "new_connection",
590                                   G_CALLBACK (callback), user_data);
591         }
592
593         return sock;
594 }
595
596
597 void
598 soup_socket_disconnect (SoupSocket *sock)
599 {
600         g_return_if_fail (SOUP_IS_SOCKET (sock));
601
602         if (!sock->priv->iochannel)
603                 return;
604
605         disconnect_internal (sock);
606
607         /* Give all readers a chance to notice the connection close */
608         g_signal_emit (sock, signals[READABLE], 0);
609
610         /* FIXME: can't disconnect until all data is read */
611
612         /* Then let everyone know we're disconnected */
613         g_signal_emit (sock, signals[DISCONNECTED], 0);
614 }
615
616 gboolean
617 soup_socket_is_connected (SoupSocket *sock)
618 {
619         g_return_val_if_fail (SOUP_IS_SOCKET (sock), FALSE);
620
621         return sock->priv->iochannel != NULL;
622 }
623
624
625 SoupAddress *
626 soup_socket_get_local_address (SoupSocket *sock)
627 {
628         g_return_val_if_fail (SOUP_IS_SOCKET (sock), NULL);
629
630         if (!sock->priv->local_addr) {
631                 struct soup_sockaddr_max bound_sa;
632                 int sa_len;
633
634                 sa_len = sizeof (bound_sa);
635                 getsockname (sock->priv->sockfd, (struct sockaddr *)&bound_sa, &sa_len);
636                 sock->priv->local_addr = soup_address_new_from_sockaddr ((struct sockaddr *)&bound_sa, sa_len);
637         }
638
639         return sock->priv->local_addr;
640 }
641
642 SoupAddress *
643 soup_socket_get_remote_address (SoupSocket *sock)
644 {
645         g_return_val_if_fail (SOUP_IS_SOCKET (sock), NULL);
646
647         if (!sock->priv->local_addr) {
648                 struct soup_sockaddr_max bound_sa;
649                 int sa_len;
650
651                 sa_len = sizeof (bound_sa);
652                 getpeername (sock->priv->sockfd, (struct sockaddr *)&bound_sa, &sa_len);
653                 sock->priv->remote_addr = soup_address_new_from_sockaddr ((struct sockaddr *)&bound_sa, sa_len);
654         }
655
656         return sock->priv->remote_addr;
657 }
658
659
660
661
662 static gboolean
663 socket_read_watch (GIOChannel *chan, GIOCondition cond, gpointer user_data)
664 {
665         SoupSocket *sock = user_data;
666
667         sock->priv->read_tag = 0;
668         g_signal_emit (sock, signals[READABLE], 0);
669
670         return FALSE;
671 }
672
673 static SoupSocketIOStatus
674 read_from_network (SoupSocket *sock, gpointer buffer, gsize len, gsize *nread)
675 {
676         GIOStatus status;
677
678         if (!sock->priv->iochannel)
679                 return SOUP_SOCKET_EOF;
680
681         status = g_io_channel_read_chars (sock->priv->iochannel,
682                                           buffer, len, nread, NULL);
683         switch (status) {
684         case G_IO_STATUS_NORMAL:
685         case G_IO_STATUS_AGAIN:
686                 if (*nread > 0)
687                         return SOUP_SOCKET_OK;
688
689                 if (!sock->priv->read_tag) {
690                         sock->priv->read_tag =
691                                 g_io_add_watch (sock->priv->iochannel, G_IO_IN,
692                                                 socket_read_watch, sock);
693                 }
694                 return SOUP_SOCKET_WOULD_BLOCK;
695
696         case G_IO_STATUS_EOF:
697                 return SOUP_SOCKET_EOF;
698
699         default:
700                 return SOUP_SOCKET_ERROR;
701         }
702 }
703
704 static SoupSocketIOStatus
705 read_from_buf (SoupSocket *sock, gpointer buffer, gsize len, gsize *nread)
706 {
707         GByteArray *read_buf = sock->priv->read_buf;
708
709         *nread = MIN (read_buf->len, len);
710         memcpy (buffer, read_buf->data, *nread);
711
712         if (*nread == read_buf->len) {
713                 g_byte_array_free (read_buf, TRUE);
714                 sock->priv->read_buf = NULL;
715         } else {
716                 memcpy (read_buf->data, read_buf->data + *nread, 
717                         read_buf->len - *nread);
718                 g_byte_array_set_size (read_buf, read_buf->len - *nread);
719         }
720
721         return SOUP_SOCKET_OK;
722 }
723
724 /**
725  * soup_socket_read:
726  * @sock: the socket
727  * @buffer: buffer to read into
728  * @len: size of @buffer in bytes
729  * @nread: on return, the number of bytes read into @buffer
730  *
731  * Attempts to read up to @len bytes from @sock into @buffer. If some
732  * data is successfully read, soup_socket_read() will return
733  * %SOUP_SOCKET_OK, and *@nread will contain the number of bytes
734  * actually read.
735  *
736  * If @sock is non-blocking, and no data is available, the return
737  * value will be %SOUP_SOCKET_WOULD_BLOCK. In this case, the caller
738  * can connect to the %readable signal to know when there is more data
739  * to read. (NB: You MUST read all available data off the socket
740  * first. The %readable signal will only be emitted after
741  * soup_socket_read() has returned %SOUP_SOCKET_WOULD_BLOCK.)
742  *
743  * Return value: a #SoupSocketIOStatus, as described above (or
744  * %SOUP_SOCKET_EOF if the socket is no longer connected, or
745  * %SOUP_SOCKET_ERROR on any other error).
746  **/
747 SoupSocketIOStatus
748 soup_socket_read (SoupSocket *sock, gpointer buffer, gsize len, gsize *nread)
749 {
750         g_return_val_if_fail (SOUP_IS_SOCKET (sock), SOUP_SOCKET_ERROR);
751
752         if (sock->priv->read_buf)
753                 return read_from_buf (sock, buffer, len, nread);
754         else
755                 return read_from_network (sock, buffer, len, nread);
756 }
757
758 /**
759  * soup_socket_read_until:
760  * @sock: the socket
761  * @buffer: buffer to read into
762  * @len: size of @buffer in bytes
763  * @boundary: boundary to read until
764  * @boundary_len: length of @boundary in bytes
765  * @nread: on return, the number of bytes read into @buffer
766  * @got_boundary: on return, whether or not the data in @buffer
767  * ends with the boundary string
768  *
769  * Like soup_socket_read(), but reads no further than the first
770  * occurrence of @boundary. (If the boundary is found, it will be
771  * included in the returned data, and *@got_boundary will be set to
772  * %TRUE.) Any data after the boundary will returned in future reads.
773  *
774  * Return value: as for soup_socket_read()
775  **/
776 SoupSocketIOStatus
777 soup_socket_read_until (SoupSocket *sock, gpointer buffer, gsize len,
778                         gconstpointer boundary, gsize boundary_len,
779                         gsize *nread, gboolean *got_boundary)
780 {
781         SoupSocketIOStatus status;
782         GByteArray *read_buf;
783         guint match_len, prev_len;
784         guint8 *p, *end;
785
786         g_return_val_if_fail (SOUP_IS_SOCKET (sock), SOUP_SOCKET_ERROR);
787         g_return_val_if_fail (len >= boundary_len, SOUP_SOCKET_ERROR);
788
789         *got_boundary = FALSE;
790
791         if (!sock->priv->read_buf)
792                 sock->priv->read_buf = g_byte_array_new ();
793         read_buf = sock->priv->read_buf;
794
795         if (read_buf->len < boundary_len) {
796                 prev_len = read_buf->len;
797                 g_byte_array_set_size (read_buf, len);
798                 status = read_from_network (sock,
799                                             read_buf->data + prev_len,
800                                             len - prev_len, nread);
801                 read_buf->len = prev_len + *nread;
802
803                 if (status != SOUP_SOCKET_OK)
804                         return status;
805         }
806
807         /* Scan for the boundary */
808         end = read_buf->data + read_buf->len;
809         for (p = read_buf->data; p <= end - boundary_len; p++) {
810                 if (!memcmp (p, boundary, boundary_len)) {
811                         p += boundary_len;
812                         *got_boundary = TRUE;
813                         break;
814                 }
815         }
816
817         /* Return everything up to 'p' (which is either just after the
818          * boundary, or @boundary_len - 1 bytes before the end of the
819          * buffer).
820          */
821         match_len = p - read_buf->data;
822         return read_from_buf (sock, buffer, MIN (len, match_len), nread);
823 }
824
825 static gboolean
826 socket_write_watch (GIOChannel *chan, GIOCondition condition, gpointer user_data)
827 {
828         SoupSocket *sock = user_data;
829
830         sock->priv->write_tag = 0;
831         g_signal_emit (sock, signals[WRITABLE], 0);
832
833         return FALSE;
834 }
835
836 /**
837  * soup_socket_write:
838  * @sock: the socket
839  * @buffer: data to write
840  * @len: size of @buffer, in bytes
841  * @nwrite: on return, number of bytes written
842  *
843  * Attempts to write @len bytes from @buffer to @sock. If some data is
844  * successfully written, the resturn status will be
845  * %SOUP_SOCKET_SUCCESS, and *@nwrote will contain the number of bytes
846  * actually written.
847  *
848  * If @sock is non-blocking, and no data could be written right away,
849  * the return value will be %SOUP_SOCKET_WOULD_BLOCK. In this case,
850  * the caller can connect to the %writable signal to know when more
851  * data can be written. (NB: %writable is only emitted after a
852  * %SOUP_SOCKET_WOULD_BLOCK.)
853  *
854  * Return value: a #SoupSocketIOStatus, as described above (or
855  * %SOUP_SOCKET_EOF or %SOUP_SOCKET_ERROR).
856  **/
857 SoupSocketIOStatus
858 soup_socket_write (SoupSocket *sock, gconstpointer buffer,
859                    gsize len, gsize *nwrote)
860 {
861         GIOStatus status;
862         gpointer pipe_handler;
863
864         g_return_val_if_fail (SOUP_IS_SOCKET (sock), SOUP_SOCKET_ERROR);
865
866         if (!sock->priv->iochannel)
867                 return SOUP_SOCKET_EOF;
868         if (sock->priv->write_tag)
869                 return SOUP_SOCKET_WOULD_BLOCK;
870
871         pipe_handler = signal (SIGPIPE, SIG_IGN);
872         status = g_io_channel_write_chars (sock->priv->iochannel,
873                                            buffer, len, nwrote, NULL);
874         signal (SIGPIPE, pipe_handler);
875         if (status != G_IO_STATUS_NORMAL && status != G_IO_STATUS_AGAIN)
876                 return SOUP_SOCKET_ERROR;
877
878         if (*nwrote)
879                 return SOUP_SOCKET_OK;
880
881         sock->priv->write_tag =
882                 g_io_add_watch (sock->priv->iochannel, G_IO_OUT,
883                                 socket_write_watch, sock);
884         return SOUP_SOCKET_WOULD_BLOCK;
885 }