1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 * soup-socket.c: Socket networking code.
5 * Copyright (C) 2000-2003, Ximian, Inc.
18 #include "soup-address.h"
19 #include "soup-socket.h"
20 #include "soup-marshal.h"
21 #include "soup-misc.h"
24 #include <sys/types.h>
25 #include <sys/socket.h>
26 #include <netinet/in.h>
27 #include <netinet/tcp.h>
29 #define PARENT_TYPE G_TYPE_OBJECT
30 static GObjectClass *parent_class;
41 static guint signals[LAST_SIGNAL] = { 0 };
55 struct SoupSocketPrivate {
57 SoupAddress *local_addr, *remote_addr;
58 GIOChannel *iochannel;
67 guint read_tag, write_tag, error_tag;
70 GMutex *iolock, *addrlock;
74 #define soup_sockaddr_max sockaddr_in6
76 #define soup_sockaddr_max sockaddr_in
79 static void set_property (GObject *object, guint prop_id,
80 const GValue *value, GParamSpec *pspec);
81 static void get_property (GObject *object, guint prop_id,
82 GValue *value, GParamSpec *pspec);
85 init (GObject *object)
87 SoupSocket *sock = SOUP_SOCKET (object);
89 sock->priv = g_new0 (SoupSocketPrivate, 1);
90 sock->priv->sockfd = -1;
91 sock->priv->non_blocking = sock->priv->nodelay = TRUE;
92 sock->priv->reuseaddr = TRUE;
93 sock->priv->addrlock = g_mutex_new ();
94 sock->priv->iolock = g_mutex_new ();
98 disconnect_internal (SoupSocket *sock)
100 g_io_channel_unref (sock->priv->iochannel);
101 sock->priv->iochannel = NULL;
102 sock->priv->sockfd = -1;
104 if (sock->priv->read_tag) {
105 g_source_remove (sock->priv->read_tag);
106 sock->priv->read_tag = 0;
108 if (sock->priv->write_tag) {
109 g_source_remove (sock->priv->write_tag);
110 sock->priv->write_tag = 0;
112 if (sock->priv->error_tag) {
113 g_source_remove (sock->priv->error_tag);
114 sock->priv->error_tag = 0;
119 finalize (GObject *object)
121 SoupSocket *sock = SOUP_SOCKET (object);
123 if (sock->priv->iochannel)
124 disconnect_internal (sock);
126 if (sock->priv->local_addr)
127 g_object_unref (sock->priv->local_addr);
128 if (sock->priv->remote_addr)
129 g_object_unref (sock->priv->remote_addr);
131 if (sock->priv->watch)
132 g_source_remove (sock->priv->watch);
134 g_mutex_free (sock->priv->addrlock);
135 g_mutex_free (sock->priv->iolock);
139 G_OBJECT_CLASS (parent_class)->finalize (object);
143 class_init (GObjectClass *object_class)
145 parent_class = g_type_class_ref (PARENT_TYPE);
147 /* virtual method override */
148 object_class->finalize = finalize;
149 object_class->set_property = set_property;
150 object_class->get_property = get_property;
153 signals[CONNECT_RESULT] =
154 g_signal_new ("connect_result",
155 G_OBJECT_CLASS_TYPE (object_class),
157 G_STRUCT_OFFSET (SoupSocketClass, connect_result),
159 soup_marshal_NONE__INT,
163 g_signal_new ("readable",
164 G_OBJECT_CLASS_TYPE (object_class),
166 G_STRUCT_OFFSET (SoupSocketClass, readable),
168 soup_marshal_NONE__NONE,
171 g_signal_new ("writable",
172 G_OBJECT_CLASS_TYPE (object_class),
174 G_STRUCT_OFFSET (SoupSocketClass, writable),
176 soup_marshal_NONE__NONE,
178 signals[DISCONNECTED] =
179 g_signal_new ("disconnected",
180 G_OBJECT_CLASS_TYPE (object_class),
182 G_STRUCT_OFFSET (SoupSocketClass, disconnected),
184 soup_marshal_NONE__NONE,
186 signals[NEW_CONNECTION] =
187 g_signal_new ("new_connection",
188 G_OBJECT_CLASS_TYPE (object_class),
190 G_STRUCT_OFFSET (SoupSocketClass, new_connection),
192 soup_marshal_NONE__OBJECT,
197 g_object_class_install_property (
198 object_class, PROP_NON_BLOCKING,
199 g_param_spec_boolean (SOUP_SOCKET_FLAG_NONBLOCKING,
201 "Whether or not the socket uses non-blocking I/O",
204 g_object_class_install_property (
205 object_class, PROP_NODELAY,
206 g_param_spec_boolean (SOUP_SOCKET_FLAG_NODELAY,
208 "Whether or not the socket uses TCP NODELAY",
211 g_object_class_install_property (
212 object_class, PROP_REUSEADDR,
213 g_param_spec_boolean (SOUP_SOCKET_FLAG_REUSEADDR,
215 "Whether or not the socket uses the TCP REUSEADDR flag",
218 g_object_class_install_property (
219 object_class, PROP_IS_SERVER,
220 g_param_spec_boolean (SOUP_SOCKET_IS_SERVER,
222 "Whether or not the socket is a server socket",
225 g_object_class_install_property (
226 object_class, PROP_SSL_CREDENTIALS,
227 g_param_spec_pointer (SOUP_SOCKET_SSL_CREDENTIALS,
229 "SSL credential information, passed from the session to the SSL implementation",
233 SOUP_MAKE_TYPE (soup_socket, SoupSocket, class_init, init, PARENT_TYPE)
237 update_fdflags (SoupSocket *sock)
241 if (sock->priv->sockfd == -1)
244 flags = fcntl (sock->priv->sockfd, F_GETFL, 0);
246 if (sock->priv->non_blocking)
249 flags &= ~O_NONBLOCK;
250 fcntl (sock->priv->sockfd, F_SETFL, flags);
253 opt = (sock->priv->nodelay != 0);
254 setsockopt (sock->priv->sockfd, IPPROTO_TCP,
255 TCP_NODELAY, &opt, sizeof (opt));
257 opt = (sock->priv->reuseaddr != 0);
258 setsockopt (sock->priv->sockfd, SOL_SOCKET,
259 SO_REUSEADDR, &opt, sizeof (opt));
263 set_property (GObject *object, guint prop_id,
264 const GValue *value, GParamSpec *pspec)
266 SoupSocket *sock = SOUP_SOCKET (object);
269 case PROP_NON_BLOCKING:
270 sock->priv->non_blocking = g_value_get_boolean (value);
271 update_fdflags (sock);
274 sock->priv->nodelay = g_value_get_boolean (value);
275 update_fdflags (sock);
278 sock->priv->reuseaddr = g_value_get_boolean (value);
279 update_fdflags (sock);
281 case PROP_SSL_CREDENTIALS:
282 sock->priv->ssl_creds = g_value_get_pointer (value);
290 get_property (GObject *object, guint prop_id,
291 GValue *value, GParamSpec *pspec)
293 SoupSocket *sock = SOUP_SOCKET (object);
296 case PROP_NON_BLOCKING:
297 g_value_set_boolean (value, sock->priv->non_blocking);
300 g_value_set_boolean (value, sock->priv->nodelay);
303 g_value_set_boolean (value, sock->priv->reuseaddr);
306 g_value_set_boolean (value, sock->priv->is_server);
308 case PROP_SSL_CREDENTIALS:
309 g_value_set_pointer (value, sock->priv->ssl_creds);
319 * @optname1: name of first property to set (or %NULL)
320 * @...: value of @optname1, followed by additional property/value pairs
322 * Creates a new (disconnected) socket
324 * Return value: the new socket
327 soup_socket_new (const char *optname1, ...)
332 va_start (ap, optname1);
333 sock = (SoupSocket *)g_object_new_valist (SOUP_TYPE_SOCKET,
341 get_iochannel (SoupSocket *sock)
343 g_mutex_lock (sock->priv->iolock);
344 if (!sock->priv->iochannel) {
345 sock->priv->iochannel =
346 g_io_channel_unix_new (sock->priv->sockfd);
347 g_io_channel_set_close_on_unref (sock->priv->iochannel, TRUE);
348 g_io_channel_set_encoding (sock->priv->iochannel, NULL, NULL);
349 g_io_channel_set_buffered (sock->priv->iochannel, FALSE);
351 g_mutex_unlock (sock->priv->iolock);
352 return sock->priv->iochannel;
356 idle_connect_result (gpointer user_data)
358 SoupSocket *sock = user_data;
360 sock->priv->watch = 0;
362 g_signal_emit (sock, signals[CONNECT_RESULT], 0,
363 sock->priv->sockfd != -1 ? SOUP_STATUS_OK : SOUP_STATUS_CANT_CONNECT);
368 connect_watch (GIOChannel* iochannel, GIOCondition condition, gpointer data)
370 SoupSocket *sock = data;
372 int len = sizeof (error);
374 /* Remove the watch now in case we don't return immediately */
375 g_source_remove (sock->priv->watch);
376 sock->priv->watch = 0;
378 if (condition & ~(G_IO_IN | G_IO_OUT))
381 if (getsockopt (sock->priv->sockfd, SOL_SOCKET, SO_ERROR,
387 return idle_connect_result (sock);
390 g_signal_emit (sock, signals[CONNECT_RESULT], 0, SOUP_STATUS_CANT_CONNECT);
395 got_address (SoupAddress *addr, guint status, gpointer user_data)
397 SoupSocket *sock = user_data;
399 if (!SOUP_STATUS_IS_SUCCESSFUL (status)) {
400 g_signal_emit (sock, signals[CONNECT_RESULT], 0, status);
401 g_object_unref (sock);
405 soup_socket_connect (sock, sock->priv->remote_addr);
406 /* soup_socket_connect re-reffed addr */
407 g_object_unref (addr);
409 g_object_unref (sock);
413 * soup_socket_connect:
414 * @sock: a client #SoupSocket (which must not already be connected)
415 * @remote_addr: address to connect to
417 * If %SOUP_SOCKET_FLAG_NONBLOCKING has been set on the socket, this
418 * begins asynchronously connecting to the given address. The socket
419 * will emit %connect_result when it succeeds or fails (but not before
420 * returning from this function).
422 * If %SOUP_SOCKET_FLAG_NONBLOCKING has not been set, this will
423 * attempt to synchronously connect.
425 * Return value: %SOUP_STATUS_CONTINUE if connecting asynchronously,
426 * otherwise a success or failure code.
429 soup_socket_connect (SoupSocket *sock, SoupAddress *remote_addr)
434 g_return_val_if_fail (SOUP_IS_SOCKET (sock), SOUP_STATUS_MALFORMED);
435 g_return_val_if_fail (!sock->priv->is_server, SOUP_STATUS_MALFORMED);
436 g_return_val_if_fail (sock->priv->sockfd == -1, SOUP_STATUS_MALFORMED);
437 g_return_val_if_fail (SOUP_IS_ADDRESS (remote_addr), SOUP_STATUS_MALFORMED);
439 sock->priv->remote_addr = g_object_ref (remote_addr);
440 if (!sock->priv->non_blocking) {
441 status = soup_address_resolve_sync (remote_addr);
442 if (!SOUP_STATUS_IS_SUCCESSFUL (status))
446 sa = soup_address_get_sockaddr (sock->priv->remote_addr, &len);
448 if (!sock->priv->non_blocking)
449 return SOUP_STATUS_CANT_RESOLVE;
452 soup_address_resolve_async (remote_addr, got_address, sock);
453 return SOUP_STATUS_CONTINUE;
456 sock->priv->sockfd = socket (sa->sa_family, SOCK_STREAM, 0);
457 if (sock->priv->sockfd == -1) {
460 update_fdflags (sock);
462 status = connect (sock->priv->sockfd, sa, len);
465 if (errno == EINPROGRESS) {
466 /* Wait for connect to succeed or fail */
468 g_io_add_watch (get_iochannel (sock),
470 G_IO_PRI | G_IO_ERR |
471 G_IO_HUP | G_IO_NVAL,
472 connect_watch, sock);
473 return SOUP_STATUS_CONTINUE;
475 close (sock->priv->sockfd);
476 sock->priv->sockfd = -1;
481 if (sock->priv->non_blocking) {
482 sock->priv->watch = g_idle_add (idle_connect_result, sock);
483 return SOUP_STATUS_CONTINUE;
484 } else if (sock->priv->sockfd == -1)
485 return SOUP_STATUS_CANT_CONNECT;
487 get_iochannel (sock);
488 return SOUP_STATUS_OK;
493 listen_watch (GIOChannel* iochannel, GIOCondition condition, gpointer data)
495 SoupSocket *sock = data, *new;
496 struct soup_sockaddr_max sa;
499 if (condition & (G_IO_HUP | G_IO_ERR)) {
500 g_source_remove (sock->priv->watch);
501 sock->priv->watch = 0;
505 sa_len = sizeof (sa);
506 sockfd = accept (sock->priv->sockfd, (struct sockaddr *)&sa, &sa_len);
510 new = g_object_new (SOUP_TYPE_SOCKET, NULL);
511 new->priv->sockfd = sockfd;
512 new->priv->non_blocking = sock->priv->non_blocking;
513 new->priv->nodelay = sock->priv->nodelay;
514 new->priv->is_server = TRUE;
515 new->priv->ssl_creds = sock->priv->ssl_creds;
516 update_fdflags (new);
518 new->priv->remote_addr = soup_address_new_from_sockaddr ((struct sockaddr *)&sa, sa_len);
520 if (new->priv->ssl_creds) {
521 if (!soup_socket_start_ssl (new)) {
522 g_object_unref (new);
528 g_signal_emit (sock, signals[NEW_CONNECTION], 0, new);
529 g_object_unref (new);
535 * soup_socket_listen:
536 * @sock: a server #SoupSocket (which must not already be connected or
538 * @local_addr: Local address to bind to.
540 * Makes @sock start listening on the given interface and port. When
541 * connections come in, @sock will emit %new_connection.
543 * Return value: whether or not @sock is now listening.
546 soup_socket_listen (SoupSocket *sock, SoupAddress *local_addr)
551 g_return_val_if_fail (SOUP_IS_SOCKET (sock), FALSE);
552 g_return_val_if_fail (sock->priv->is_server, FALSE);
553 g_return_val_if_fail (sock->priv->sockfd == -1, FALSE);
554 g_return_val_if_fail (SOUP_IS_ADDRESS (local_addr), FALSE);
556 /* @local_addr may have its port set to 0. So we intentionally
557 * don't store it in sock->priv->local_addr, so that if the
558 * caller calls soup_socket_get_local_address() later, we'll
559 * have to make a new addr by calling getsockname(), which
560 * will have the right port number.
562 sa = soup_address_get_sockaddr (local_addr, &sa_len);
563 g_return_val_if_fail (sa != NULL, FALSE);
565 sock->priv->sockfd = socket (sa->sa_family, SOCK_STREAM, 0);
566 if (sock->priv->sockfd < 0)
568 update_fdflags (sock);
571 if (bind (sock->priv->sockfd, sa, sa_len) != 0)
575 if (listen (sock->priv->sockfd, 10) != 0)
578 sock->priv->watch = g_io_add_watch (get_iochannel (sock),
579 G_IO_IN | G_IO_ERR | G_IO_HUP,
584 if (sock->priv->sockfd != -1) {
585 close (sock->priv->sockfd);
586 sock->priv->sockfd = -1;
593 * soup_socket_start_ssl:
596 * Starts using SSL on @socket.
598 * Return value: success or failure
601 soup_socket_start_ssl (SoupSocket *sock)
603 return soup_socket_start_proxy_ssl (sock, soup_address_get_name (sock->priv->remote_addr));
607 * soup_socket_start_proxy_ssl:
609 * @ssl_host: hostname of the SSL server
611 * Starts using SSL on @socket, expecting to find a host named
614 * Return value: success or failure
617 soup_socket_start_proxy_ssl (SoupSocket *sock, const char *ssl_host)
619 GIOChannel *ssl_chan;
621 get_iochannel (sock);
622 ssl_chan = soup_ssl_wrap_iochannel (
623 sock->priv->iochannel, sock->priv->is_server ?
624 SOUP_SSL_TYPE_SERVER : SOUP_SSL_TYPE_CLIENT,
625 ssl_host, sock->priv->ssl_creds);
630 sock->priv->iochannel = ssl_chan;
636 * soup_socket_client_new_async:
637 * @hostname: remote machine to connect to
638 * @port: remote port to connect to
639 * @ssl_creds: SSL credentials structure, or %NULL if not SSL
640 * @callback: callback to call when the socket is connected
641 * @user_data: data for @callback
643 * Creates a connection to @hostname and @port. @callback will be
644 * called when the connection completes (or fails).
646 * Return value: the new socket (not yet ready for use).
649 soup_socket_client_new_async (const char *hostname, guint port,
651 SoupSocketCallback callback, gpointer user_data)
655 g_return_val_if_fail (hostname != NULL, NULL);
657 sock = g_object_new (SOUP_TYPE_SOCKET,
658 SOUP_SOCKET_SSL_CREDENTIALS, ssl_creds,
660 soup_socket_connect (sock, soup_address_new (hostname, port));
663 soup_signal_connect_once (sock, "connect_result",
664 G_CALLBACK (callback), user_data);
670 * soup_socket_client_new_sync:
671 * @hostname: remote machine to connect to
672 * @port: remote port to connect to
673 * @ssl_creds: SSL credentials structure, or %NULL if not SSL
674 * @status_ret: pointer to return the soup status in
676 * Creates a connection to @hostname and @port. If @status_ret is not
677 * %NULL, it will contain a status code on return.
679 * Return value: the new socket, or %NULL if it could not connect.
682 soup_socket_client_new_sync (const char *hostname, guint port,
683 gpointer ssl_creds, guint *status_ret)
688 g_return_val_if_fail (hostname != NULL, NULL);
690 sock = g_object_new (SOUP_TYPE_SOCKET,
691 SOUP_SOCKET_SSL_CREDENTIALS, ssl_creds,
693 sock->priv->non_blocking = FALSE;
694 status = soup_socket_connect (sock, soup_address_new (hostname, port));
696 if (!SOUP_STATUS_IS_SUCCESSFUL (status)) {
697 g_object_unref (sock);
702 *status_ret = status;
707 * soup_socket_server_new:
708 * @local_addr: Local address to bind to. (Use soup_address_any_new() to
709 * accept connections on any local address)
710 * @ssl_creds: SSL credentials, or %NULL if this is not an SSL server
711 * @callback: Callback to call when a client connects
712 * @user_data: data to pass to @callback.
714 * Create and open a new #SoupSocket listening on the specified
715 * address. @callback will be called each time a client connects,
716 * with a new #SoupSocket.
718 * Returns: a new #SoupSocket, or NULL if there was a failure.
721 soup_socket_server_new (SoupAddress *local_addr, gpointer ssl_creds,
722 SoupSocketListenerCallback callback,
727 g_return_val_if_fail (SOUP_IS_ADDRESS (local_addr), NULL);
729 sock = g_object_new (SOUP_TYPE_SOCKET,
730 SOUP_SOCKET_SSL_CREDENTIALS, ssl_creds,
732 sock->priv->is_server = TRUE;
733 if (!soup_socket_listen (sock, local_addr)) {
734 g_object_unref (sock);
739 g_signal_connect (sock, "new_connection",
740 G_CALLBACK (callback), user_data);
748 * soup_socket_disconnect:
749 * @sock: a #SoupSocket
751 * Disconnects @sock. Any further read or write attempts on it will
755 soup_socket_disconnect (SoupSocket *sock)
757 gboolean already_disconnected = FALSE;
759 g_return_if_fail (SOUP_IS_SOCKET (sock));
761 if (g_mutex_trylock (sock->priv->iolock)) {
762 if (sock->priv->iochannel)
763 disconnect_internal (sock);
765 already_disconnected = TRUE;
766 g_mutex_unlock (sock->priv->iolock);
770 /* Another thread is currently doing IO, so
771 * we can't close the iochannel. So just kick
772 * the file descriptor out from under it.
775 sockfd = sock->priv->sockfd;
776 sock->priv->sockfd = -1;
778 already_disconnected = TRUE;
780 g_io_channel_set_close_on_unref (sock->priv->iochannel,
786 if (already_disconnected)
789 /* Give all readers a chance to notice the connection close */
790 g_signal_emit (sock, signals[READABLE], 0);
792 /* FIXME: can't disconnect until all data is read */
794 /* Then let everyone know we're disconnected */
795 g_signal_emit (sock, signals[DISCONNECTED], 0);
799 * soup_socket_is_connected:
800 * @sock: a #SoupSocket
802 * Tests if @sock is connected to another host
804 * Return value: %TRUE or %FALSE.
807 soup_socket_is_connected (SoupSocket *sock)
809 g_return_val_if_fail (SOUP_IS_SOCKET (sock), FALSE);
811 return sock->priv->iochannel != NULL;
815 * soup_socket_get_local_address:
816 * @sock: a #SoupSocket
818 * Returns the #SoupAddress corresponding to the local end of @sock.
820 * Return value: the #SoupAddress
823 soup_socket_get_local_address (SoupSocket *sock)
825 g_return_val_if_fail (SOUP_IS_SOCKET (sock), NULL);
827 g_mutex_lock (sock->priv->addrlock);
828 if (!sock->priv->local_addr) {
829 struct soup_sockaddr_max bound_sa;
832 sa_len = sizeof (bound_sa);
833 getsockname (sock->priv->sockfd, (struct sockaddr *)&bound_sa, &sa_len);
834 sock->priv->local_addr = soup_address_new_from_sockaddr ((struct sockaddr *)&bound_sa, sa_len);
836 g_mutex_unlock (sock->priv->addrlock);
838 return sock->priv->local_addr;
842 * soup_socket_get_remote_address:
843 * @sock: a #SoupSocket
845 * Returns the #SoupAddress corresponding to the remote end of @sock.
847 * Return value: the #SoupAddress
850 soup_socket_get_remote_address (SoupSocket *sock)
852 g_return_val_if_fail (SOUP_IS_SOCKET (sock), NULL);
854 g_mutex_lock (sock->priv->addrlock);
855 if (!sock->priv->remote_addr) {
856 struct soup_sockaddr_max bound_sa;
859 sa_len = sizeof (bound_sa);
860 getpeername (sock->priv->sockfd, (struct sockaddr *)&bound_sa, &sa_len);
861 sock->priv->remote_addr = soup_address_new_from_sockaddr ((struct sockaddr *)&bound_sa, sa_len);
863 g_mutex_unlock (sock->priv->addrlock);
865 return sock->priv->remote_addr;
872 socket_read_watch (GIOChannel *chan, GIOCondition cond, gpointer user_data)
874 SoupSocket *sock = user_data;
876 sock->priv->read_tag = 0;
877 g_signal_emit (sock, signals[READABLE], 0);
882 static SoupSocketIOStatus
883 read_from_network (SoupSocket *sock, gpointer buffer, gsize len, gsize *nread)
886 GIOCondition cond = G_IO_IN;
889 if (!sock->priv->iochannel)
890 return SOUP_SOCKET_EOF;
892 status = g_io_channel_read_chars (sock->priv->iochannel,
893 buffer, len, nread, &err);
895 if (err->domain == SOUP_SSL_ERROR &&
896 err->code == SOUP_SSL_ERROR_HANDSHAKE_NEEDS_WRITE)
898 g_object_set_data_full (G_OBJECT (sock),
899 "SoupSocket-last_error",
900 err, (GDestroyNotify)g_error_free);
902 g_object_set_data (G_OBJECT (sock),
903 "SoupSocket-last_error",
908 case G_IO_STATUS_NORMAL:
909 case G_IO_STATUS_AGAIN:
911 return SOUP_SOCKET_OK;
913 if (!sock->priv->read_tag) {
914 sock->priv->read_tag =
915 g_io_add_watch (sock->priv->iochannel, cond,
916 socket_read_watch, sock);
918 return SOUP_SOCKET_WOULD_BLOCK;
920 case G_IO_STATUS_EOF:
921 return SOUP_SOCKET_EOF;
924 return SOUP_SOCKET_ERROR;
928 static SoupSocketIOStatus
929 read_from_buf (SoupSocket *sock, gpointer buffer, gsize len, gsize *nread)
931 GByteArray *read_buf = sock->priv->read_buf;
933 *nread = MIN (read_buf->len, len);
934 memcpy (buffer, read_buf->data, *nread);
936 if (*nread == read_buf->len) {
937 g_byte_array_free (read_buf, TRUE);
938 sock->priv->read_buf = NULL;
940 memmove (read_buf->data, read_buf->data + *nread,
941 read_buf->len - *nread);
942 g_byte_array_set_size (read_buf, read_buf->len - *nread);
945 return SOUP_SOCKET_OK;
951 * @buffer: buffer to read into
952 * @len: size of @buffer in bytes
953 * @nread: on return, the number of bytes read into @buffer
955 * Attempts to read up to @len bytes from @sock into @buffer. If some
956 * data is successfully read, soup_socket_read() will return
957 * %SOUP_SOCKET_OK, and *@nread will contain the number of bytes
960 * If @sock is non-blocking, and no data is available, the return
961 * value will be %SOUP_SOCKET_WOULD_BLOCK. In this case, the caller
962 * can connect to the %readable signal to know when there is more data
963 * to read. (NB: You MUST read all available data off the socket
964 * first. The %readable signal will only be emitted after
965 * soup_socket_read() has returned %SOUP_SOCKET_WOULD_BLOCK.)
967 * Return value: a #SoupSocketIOStatus, as described above (or
968 * %SOUP_SOCKET_EOF if the socket is no longer connected, or
969 * %SOUP_SOCKET_ERROR on any other error).
972 soup_socket_read (SoupSocket *sock, gpointer buffer, gsize len, gsize *nread)
974 SoupSocketIOStatus status;
976 g_return_val_if_fail (SOUP_IS_SOCKET (sock), SOUP_SOCKET_ERROR);
978 g_mutex_lock (sock->priv->iolock);
979 if (sock->priv->read_buf)
980 status = read_from_buf (sock, buffer, len, nread);
982 status = read_from_network (sock, buffer, len, nread);
983 g_mutex_unlock (sock->priv->iolock);
989 * soup_socket_read_until:
991 * @buffer: buffer to read into
992 * @len: size of @buffer in bytes
993 * @boundary: boundary to read until
994 * @boundary_len: length of @boundary in bytes
995 * @nread: on return, the number of bytes read into @buffer
996 * @got_boundary: on return, whether or not the data in @buffer
997 * ends with the boundary string
999 * Like soup_socket_read(), but reads no further than the first
1000 * occurrence of @boundary. (If the boundary is found, it will be
1001 * included in the returned data, and *@got_boundary will be set to
1002 * %TRUE.) Any data after the boundary will returned in future reads.
1004 * Return value: as for soup_socket_read()
1007 soup_socket_read_until (SoupSocket *sock, gpointer buffer, gsize len,
1008 gconstpointer boundary, gsize boundary_len,
1009 gsize *nread, gboolean *got_boundary)
1011 SoupSocketIOStatus status;
1012 GByteArray *read_buf;
1013 guint match_len, prev_len;
1016 g_return_val_if_fail (SOUP_IS_SOCKET (sock), SOUP_SOCKET_ERROR);
1017 g_return_val_if_fail (len >= boundary_len, SOUP_SOCKET_ERROR);
1019 g_mutex_lock (sock->priv->iolock);
1021 *got_boundary = FALSE;
1023 if (!sock->priv->read_buf)
1024 sock->priv->read_buf = g_byte_array_new ();
1025 read_buf = sock->priv->read_buf;
1027 if (read_buf->len < boundary_len) {
1028 prev_len = read_buf->len;
1029 g_byte_array_set_size (read_buf, len);
1030 status = read_from_network (sock,
1031 read_buf->data + prev_len,
1032 len - prev_len, nread);
1033 read_buf->len = prev_len + *nread;
1035 if (status != SOUP_SOCKET_OK) {
1036 g_mutex_unlock (sock->priv->iolock);
1041 /* Scan for the boundary */
1042 end = read_buf->data + read_buf->len;
1043 for (p = read_buf->data; p <= end - boundary_len; p++) {
1044 if (!memcmp (p, boundary, boundary_len)) {
1046 *got_boundary = TRUE;
1051 /* Return everything up to 'p' (which is either just after the
1052 * boundary, or @boundary_len - 1 bytes before the end of the
1055 match_len = p - read_buf->data;
1056 status = read_from_buf (sock, buffer, MIN (len, match_len), nread);
1058 g_mutex_unlock (sock->priv->iolock);
1063 socket_write_watch (GIOChannel *chan, GIOCondition condition, gpointer user_data)
1065 SoupSocket *sock = user_data;
1067 sock->priv->write_tag = 0;
1068 g_signal_emit (sock, signals[WRITABLE], 0);
1074 * soup_socket_write:
1076 * @buffer: data to write
1077 * @len: size of @buffer, in bytes
1078 * @nwrote: on return, number of bytes written
1080 * Attempts to write @len bytes from @buffer to @sock. If some data is
1081 * successfully written, the resturn status will be
1082 * %SOUP_SOCKET_SUCCESS, and *@nwrote will contain the number of bytes
1085 * If @sock is non-blocking, and no data could be written right away,
1086 * the return value will be %SOUP_SOCKET_WOULD_BLOCK. In this case,
1087 * the caller can connect to the %writable signal to know when more
1088 * data can be written. (NB: %writable is only emitted after a
1089 * %SOUP_SOCKET_WOULD_BLOCK.)
1091 * Return value: a #SoupSocketIOStatus, as described above (or
1092 * %SOUP_SOCKET_EOF or %SOUP_SOCKET_ERROR).
1095 soup_socket_write (SoupSocket *sock, gconstpointer buffer,
1096 gsize len, gsize *nwrote)
1099 gpointer pipe_handler;
1100 GIOCondition cond = G_IO_OUT;
1103 g_return_val_if_fail (SOUP_IS_SOCKET (sock), SOUP_SOCKET_ERROR);
1105 g_mutex_lock (sock->priv->iolock);
1107 if (!sock->priv->iochannel) {
1108 g_mutex_unlock (sock->priv->iolock);
1109 return SOUP_SOCKET_EOF;
1111 if (sock->priv->write_tag) {
1112 g_mutex_unlock (sock->priv->iolock);
1113 return SOUP_SOCKET_WOULD_BLOCK;
1116 pipe_handler = signal (SIGPIPE, SIG_IGN);
1117 status = g_io_channel_write_chars (sock->priv->iochannel,
1118 buffer, len, nwrote, &err);
1119 signal (SIGPIPE, pipe_handler);
1121 if (err->domain == SOUP_SSL_ERROR &&
1122 err->code == SOUP_SSL_ERROR_HANDSHAKE_NEEDS_READ)
1124 g_object_set_data_full (G_OBJECT (sock),
1125 "SoupSocket-last_error",
1126 err, (GDestroyNotify)g_error_free);
1128 g_object_set_data (G_OBJECT (sock),
1129 "SoupSocket-last_error",
1133 if (status != G_IO_STATUS_NORMAL && status != G_IO_STATUS_AGAIN) {
1134 g_mutex_unlock (sock->priv->iolock);
1135 return SOUP_SOCKET_ERROR;
1139 g_mutex_unlock (sock->priv->iolock);
1140 return SOUP_SOCKET_OK;
1143 sock->priv->write_tag =
1144 g_io_add_watch (sock->priv->iochannel, cond,
1145 socket_write_watch, sock);
1146 g_mutex_unlock (sock->priv->iolock);
1147 return SOUP_SOCKET_WOULD_BLOCK;