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