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