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>
26 G_DEFINE_TYPE (SoupSocket, soup_socket, G_TYPE_OBJECT)
37 static guint signals[LAST_SIGNAL] = { 0 };
53 SoupAddress *local_addr, *remote_addr;
54 GIOChannel *iochannel;
63 guint read_tag, write_tag, error_tag;
66 GMutex *iolock, *addrlock;
68 #define SOUP_SOCKET_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), SOUP_TYPE_SOCKET, SoupSocketPrivate))
71 #define soup_sockaddr_max sockaddr_in6
73 #define soup_sockaddr_max sockaddr_in
76 static void set_property (GObject *object, guint prop_id,
77 const GValue *value, GParamSpec *pspec);
78 static void get_property (GObject *object, guint prop_id,
79 GValue *value, GParamSpec *pspec);
82 #define SOUP_CLOSE_SOCKET(socket) closesocket (socket)
83 #define SOUP_IS_SOCKET_ERROR(status) ((status) == SOCKET_ERROR)
84 #define SOUP_IS_INVALID_SOCKET(socket) ((socket) == INVALID_SOCKET)
85 #define SOUP_IS_CONNECT_STATUS_INPROGRESS() (WSAGetLastError () == WSAEWOULDBLOCK)
87 #define SOUP_CLOSE_SOCKET(socket) close (socket)
88 #define SOUP_IS_SOCKET_ERROR(status) ((status) == -1)
89 #define SOUP_IS_INVALID_SOCKET(socket) ((socket) < 0)
90 #define SOUP_IS_CONNECT_STATUS_INPROGRESS() (errno == EINPROGRESS)
94 soup_socket_init (SoupSocket *sock)
96 SoupSocketPrivate *priv = SOUP_SOCKET_GET_PRIVATE (sock);
99 priv->non_blocking = priv->nodelay = TRUE;
100 priv->reuseaddr = TRUE;
101 priv->addrlock = g_mutex_new ();
102 priv->iolock = g_mutex_new ();
106 disconnect_internal (SoupSocketPrivate *priv)
108 g_io_channel_unref (priv->iochannel);
109 priv->iochannel = NULL;
112 if (priv->read_tag) {
113 g_source_remove (priv->read_tag);
116 if (priv->write_tag) {
117 g_source_remove (priv->write_tag);
120 if (priv->error_tag) {
121 g_source_remove (priv->error_tag);
127 finalize (GObject *object)
129 SoupSocketPrivate *priv = SOUP_SOCKET_GET_PRIVATE (object);
132 disconnect_internal (priv);
134 if (priv->local_addr)
135 g_object_unref (priv->local_addr);
136 if (priv->remote_addr)
137 g_object_unref (priv->remote_addr);
140 g_source_remove (priv->watch);
142 g_mutex_free (priv->addrlock);
143 g_mutex_free (priv->iolock);
145 G_OBJECT_CLASS (soup_socket_parent_class)->finalize (object);
149 soup_socket_class_init (SoupSocketClass *socket_class)
151 GObjectClass *object_class = G_OBJECT_CLASS (socket_class);
153 g_type_class_add_private (socket_class, sizeof (SoupSocketPrivate));
155 /* virtual method override */
156 object_class->finalize = finalize;
157 object_class->set_property = set_property;
158 object_class->get_property = get_property;
161 signals[CONNECT_RESULT] =
162 g_signal_new ("connect_result",
163 G_OBJECT_CLASS_TYPE (object_class),
165 G_STRUCT_OFFSET (SoupSocketClass, connect_result),
167 soup_marshal_NONE__INT,
171 g_signal_new ("readable",
172 G_OBJECT_CLASS_TYPE (object_class),
174 G_STRUCT_OFFSET (SoupSocketClass, readable),
176 soup_marshal_NONE__NONE,
179 g_signal_new ("writable",
180 G_OBJECT_CLASS_TYPE (object_class),
182 G_STRUCT_OFFSET (SoupSocketClass, writable),
184 soup_marshal_NONE__NONE,
186 signals[DISCONNECTED] =
187 g_signal_new ("disconnected",
188 G_OBJECT_CLASS_TYPE (object_class),
190 G_STRUCT_OFFSET (SoupSocketClass, disconnected),
192 soup_marshal_NONE__NONE,
194 signals[NEW_CONNECTION] =
195 g_signal_new ("new_connection",
196 G_OBJECT_CLASS_TYPE (object_class),
198 G_STRUCT_OFFSET (SoupSocketClass, new_connection),
200 soup_marshal_NONE__OBJECT,
205 g_object_class_install_property (
206 object_class, PROP_NON_BLOCKING,
207 g_param_spec_boolean (SOUP_SOCKET_FLAG_NONBLOCKING,
209 "Whether or not the socket uses non-blocking I/O",
212 g_object_class_install_property (
213 object_class, PROP_NODELAY,
214 g_param_spec_boolean (SOUP_SOCKET_FLAG_NODELAY,
216 "Whether or not the socket uses TCP NODELAY",
219 g_object_class_install_property (
220 object_class, PROP_REUSEADDR,
221 g_param_spec_boolean (SOUP_SOCKET_FLAG_REUSEADDR,
223 "Whether or not the socket uses the TCP REUSEADDR flag",
226 g_object_class_install_property (
227 object_class, PROP_IS_SERVER,
228 g_param_spec_boolean (SOUP_SOCKET_IS_SERVER,
230 "Whether or not the socket is a server socket",
233 g_object_class_install_property (
234 object_class, PROP_SSL_CREDENTIALS,
235 g_param_spec_pointer (SOUP_SOCKET_SSL_CREDENTIALS,
237 "SSL credential information, passed from the session to the SSL implementation",
241 /* Make sure WSAStartup() gets called. */
242 soup_address_get_type ();
248 update_fdflags (SoupSocketPrivate *priv)
255 if (priv->sockfd == -1)
259 flags = fcntl (priv->sockfd, F_GETFL, 0);
261 if (priv->non_blocking)
264 flags &= ~O_NONBLOCK;
265 fcntl (priv->sockfd, F_SETFL, flags);
268 if (priv->non_blocking) {
270 ioctlsocket (priv->sockfd, FIONBIO, &val);
273 ioctlsocket (priv->sockfd, FIONBIO, &val);
277 opt = (priv->nodelay != 0);
278 setsockopt (priv->sockfd, IPPROTO_TCP,
279 TCP_NODELAY, (void *) &opt, sizeof (opt));
281 opt = (priv->reuseaddr != 0);
282 setsockopt (priv->sockfd, SOL_SOCKET,
283 SO_REUSEADDR, (void *) &opt, sizeof (opt));
287 set_property (GObject *object, guint prop_id,
288 const GValue *value, GParamSpec *pspec)
290 SoupSocketPrivate *priv = SOUP_SOCKET_GET_PRIVATE (object);
293 case PROP_NON_BLOCKING:
294 priv->non_blocking = g_value_get_boolean (value);
295 update_fdflags (priv);
298 priv->nodelay = g_value_get_boolean (value);
299 update_fdflags (priv);
302 priv->reuseaddr = g_value_get_boolean (value);
303 update_fdflags (priv);
305 case PROP_SSL_CREDENTIALS:
306 priv->ssl_creds = g_value_get_pointer (value);
314 get_property (GObject *object, guint prop_id,
315 GValue *value, GParamSpec *pspec)
317 SoupSocketPrivate *priv = SOUP_SOCKET_GET_PRIVATE (object);
320 case PROP_NON_BLOCKING:
321 g_value_set_boolean (value, priv->non_blocking);
324 g_value_set_boolean (value, priv->nodelay);
327 g_value_set_boolean (value, priv->reuseaddr);
330 g_value_set_boolean (value, priv->is_server);
332 case PROP_SSL_CREDENTIALS:
333 g_value_set_pointer (value, priv->ssl_creds);
343 * @optname1: name of first property to set (or %NULL)
344 * @...: value of @optname1, followed by additional property/value pairs
346 * Creates a new (disconnected) socket
348 * Return value: the new socket
351 soup_socket_new (const char *optname1, ...)
356 va_start (ap, optname1);
357 sock = (SoupSocket *)g_object_new_valist (SOUP_TYPE_SOCKET,
365 get_iochannel (SoupSocketPrivate *priv)
367 g_mutex_lock (priv->iolock);
368 if (!priv->iochannel) {
371 g_io_channel_unix_new (priv->sockfd);
374 g_io_channel_win32_new_socket (priv->sockfd);
376 g_io_channel_set_close_on_unref (priv->iochannel, TRUE);
377 g_io_channel_set_encoding (priv->iochannel, NULL, NULL);
378 g_io_channel_set_buffered (priv->iochannel, FALSE);
380 g_mutex_unlock (priv->iolock);
381 return priv->iochannel;
385 idle_connect_result (gpointer user_data)
387 SoupSocket *sock = user_data;
388 SoupSocketPrivate *priv = SOUP_SOCKET_GET_PRIVATE (sock);
392 g_signal_emit (sock, signals[CONNECT_RESULT], 0,
393 priv->sockfd != -1 ? SOUP_STATUS_OK : SOUP_STATUS_CANT_CONNECT);
398 connect_watch (GIOChannel* iochannel, GIOCondition condition, gpointer data)
400 SoupSocket *sock = data;
401 SoupSocketPrivate *priv = SOUP_SOCKET_GET_PRIVATE (sock);
403 int len = sizeof (error);
405 /* Remove the watch now in case we don't return immediately */
406 g_source_remove (priv->watch);
409 if (condition & ~(G_IO_IN | G_IO_OUT))
412 if (getsockopt (priv->sockfd, SOL_SOCKET, SO_ERROR,
413 (void *) &error, &len) != 0)
418 return idle_connect_result (sock);
421 g_signal_emit (sock, signals[CONNECT_RESULT], 0, SOUP_STATUS_CANT_CONNECT);
426 got_address (SoupAddress *addr, guint status, gpointer user_data)
428 SoupSocket *sock = user_data;
429 SoupSocketPrivate *priv = SOUP_SOCKET_GET_PRIVATE (sock);
431 if (!SOUP_STATUS_IS_SUCCESSFUL (status)) {
432 g_signal_emit (sock, signals[CONNECT_RESULT], 0, status);
433 g_object_unref (sock);
437 soup_socket_connect (sock, priv->remote_addr);
438 /* soup_socket_connect re-reffed addr */
439 g_object_unref (addr);
441 g_object_unref (sock);
445 * soup_socket_connect:
446 * @sock: a client #SoupSocket (which must not already be connected)
447 * @remote_addr: address to connect to
449 * If %SOUP_SOCKET_FLAG_NONBLOCKING has been set on the socket, this
450 * begins asynchronously connecting to the given address. The socket
451 * will emit %connect_result when it succeeds or fails (but not before
452 * returning from this function).
454 * If %SOUP_SOCKET_FLAG_NONBLOCKING has not been set, this will
455 * attempt to synchronously connect.
457 * Return value: %SOUP_STATUS_CONTINUE if connecting asynchronously,
458 * otherwise a success or failure code.
461 soup_socket_connect (SoupSocket *sock, SoupAddress *remote_addr)
463 SoupSocketPrivate *priv;
467 g_return_val_if_fail (SOUP_IS_SOCKET (sock), SOUP_STATUS_MALFORMED);
468 priv = SOUP_SOCKET_GET_PRIVATE (sock);
469 g_return_val_if_fail (!priv->is_server, SOUP_STATUS_MALFORMED);
470 g_return_val_if_fail (priv->sockfd == -1, SOUP_STATUS_MALFORMED);
471 g_return_val_if_fail (SOUP_IS_ADDRESS (remote_addr), SOUP_STATUS_MALFORMED);
473 priv->remote_addr = g_object_ref (remote_addr);
474 if (!priv->non_blocking) {
475 status = soup_address_resolve_sync (remote_addr);
476 if (!SOUP_STATUS_IS_SUCCESSFUL (status))
480 sa = soup_address_get_sockaddr (priv->remote_addr, &len);
482 if (!priv->non_blocking)
483 return SOUP_STATUS_CANT_RESOLVE;
486 soup_address_resolve_async (remote_addr, got_address, sock);
487 return SOUP_STATUS_CONTINUE;
490 priv->sockfd = socket (sa->sa_family, SOCK_STREAM, 0);
491 if (SOUP_IS_INVALID_SOCKET (priv->sockfd)) {
494 update_fdflags (priv);
496 status = connect (priv->sockfd, sa, len);
498 if (SOUP_IS_SOCKET_ERROR (status)) {
499 if (SOUP_IS_CONNECT_STATUS_INPROGRESS ()) {
500 /* Wait for connect to succeed or fail */
502 g_io_add_watch (get_iochannel (priv),
504 G_IO_PRI | G_IO_ERR |
505 G_IO_HUP | G_IO_NVAL,
506 connect_watch, sock);
507 return SOUP_STATUS_CONTINUE;
509 SOUP_CLOSE_SOCKET (priv->sockfd);
515 if (priv->non_blocking) {
516 priv->watch = g_idle_add (idle_connect_result, sock);
517 return SOUP_STATUS_CONTINUE;
518 } else if (SOUP_IS_INVALID_SOCKET (priv->sockfd))
519 return SOUP_STATUS_CANT_CONNECT;
521 get_iochannel (priv);
522 return SOUP_STATUS_OK;
527 listen_watch (GIOChannel* iochannel, GIOCondition condition, gpointer data)
529 SoupSocket *sock = data, *new;
530 SoupSocketPrivate *priv = SOUP_SOCKET_GET_PRIVATE (sock), *new_priv;
531 struct soup_sockaddr_max sa;
534 if (condition & (G_IO_HUP | G_IO_ERR)) {
535 g_source_remove (priv->watch);
540 sa_len = sizeof (sa);
541 sockfd = accept (priv->sockfd, (struct sockaddr *)&sa, &sa_len);
542 if (SOUP_IS_INVALID_SOCKET (sockfd))
545 new = g_object_new (SOUP_TYPE_SOCKET, NULL);
546 new_priv = SOUP_SOCKET_GET_PRIVATE (new);
547 new_priv->sockfd = sockfd;
548 new_priv->non_blocking = priv->non_blocking;
549 new_priv->nodelay = priv->nodelay;
550 new_priv->is_server = TRUE;
551 new_priv->ssl_creds = priv->ssl_creds;
552 update_fdflags (new_priv);
554 new_priv->remote_addr = soup_address_new_from_sockaddr ((struct sockaddr *)&sa, sa_len);
556 if (new_priv->ssl_creds) {
557 if (!soup_socket_start_ssl (new)) {
558 g_object_unref (new);
562 get_iochannel (new_priv);
564 g_signal_emit (sock, signals[NEW_CONNECTION], 0, new);
565 g_object_unref (new);
571 * soup_socket_listen:
572 * @sock: a server #SoupSocket (which must not already be connected or
574 * @local_addr: Local address to bind to.
576 * Makes @sock start listening on the given interface and port. When
577 * connections come in, @sock will emit %new_connection.
579 * Return value: whether or not @sock is now listening.
582 soup_socket_listen (SoupSocket *sock, SoupAddress *local_addr)
584 SoupSocketPrivate *priv;
588 g_return_val_if_fail (SOUP_IS_SOCKET (sock), FALSE);
589 priv = SOUP_SOCKET_GET_PRIVATE (sock);
590 g_return_val_if_fail (priv->is_server, FALSE);
591 g_return_val_if_fail (priv->sockfd == -1, FALSE);
592 g_return_val_if_fail (SOUP_IS_ADDRESS (local_addr), FALSE);
594 /* @local_addr may have its port set to 0. So we intentionally
595 * don't store it in priv->local_addr, so that if the
596 * caller calls soup_socket_get_local_address() later, we'll
597 * have to make a new addr by calling getsockname(), which
598 * will have the right port number.
600 sa = soup_address_get_sockaddr (local_addr, &sa_len);
601 g_return_val_if_fail (sa != NULL, FALSE);
603 priv->sockfd = socket (sa->sa_family, SOCK_STREAM, 0);
604 if (SOUP_IS_INVALID_SOCKET (priv->sockfd))
606 update_fdflags (priv);
609 if (bind (priv->sockfd, sa, sa_len) != 0)
613 if (listen (priv->sockfd, 10) != 0)
616 priv->watch = g_io_add_watch (get_iochannel (priv),
617 G_IO_IN | G_IO_ERR | G_IO_HUP,
622 if (priv->sockfd != -1) {
623 SOUP_CLOSE_SOCKET (priv->sockfd);
631 * soup_socket_start_ssl:
634 * Starts using SSL on @socket.
636 * Return value: success or failure
639 soup_socket_start_ssl (SoupSocket *sock)
641 SoupSocketPrivate *priv = SOUP_SOCKET_GET_PRIVATE (sock);
643 return soup_socket_start_proxy_ssl (sock, soup_address_get_name (priv->remote_addr));
647 * soup_socket_start_proxy_ssl:
649 * @ssl_host: hostname of the SSL server
651 * Starts using SSL on @socket, expecting to find a host named
654 * Return value: success or failure
657 soup_socket_start_proxy_ssl (SoupSocket *sock, const char *ssl_host)
659 SoupSocketPrivate *priv = SOUP_SOCKET_GET_PRIVATE (sock);
660 GIOChannel *ssl_chan;
662 get_iochannel (priv);
663 ssl_chan = soup_ssl_wrap_iochannel (
664 priv->iochannel, priv->is_server ?
665 SOUP_SSL_TYPE_SERVER : SOUP_SSL_TYPE_CLIENT,
666 ssl_host, priv->ssl_creds);
671 priv->iochannel = ssl_chan;
677 * soup_socket_client_new_async:
678 * @hostname: remote machine to connect to
679 * @port: remote port to connect to
680 * @ssl_creds: SSL credentials structure, or %NULL if not SSL
681 * @callback: callback to call when the socket is connected
682 * @user_data: data for @callback
684 * Creates a connection to @hostname and @port. @callback will be
685 * called when the connection completes (or fails).
687 * Return value: the new socket (not yet ready for use).
690 soup_socket_client_new_async (const char *hostname, guint port,
692 SoupSocketCallback callback, gpointer user_data)
696 g_return_val_if_fail (hostname != NULL, NULL);
698 sock = g_object_new (SOUP_TYPE_SOCKET,
699 SOUP_SOCKET_SSL_CREDENTIALS, ssl_creds,
701 soup_socket_connect (sock, soup_address_new (hostname, port));
704 soup_signal_connect_once (sock, "connect_result",
705 G_CALLBACK (callback), user_data);
711 * soup_socket_client_new_sync:
712 * @hostname: remote machine to connect to
713 * @port: remote port to connect to
714 * @ssl_creds: SSL credentials structure, or %NULL if not SSL
715 * @status_ret: pointer to return the soup status in
717 * Creates a connection to @hostname and @port. If @status_ret is not
718 * %NULL, it will contain a status code on return.
720 * Return value: the new socket, or %NULL if it could not connect.
723 soup_socket_client_new_sync (const char *hostname, guint port,
724 gpointer ssl_creds, guint *status_ret)
727 SoupSocketPrivate *priv;
730 g_return_val_if_fail (hostname != NULL, NULL);
732 sock = g_object_new (SOUP_TYPE_SOCKET,
733 SOUP_SOCKET_SSL_CREDENTIALS, ssl_creds,
735 priv = SOUP_SOCKET_GET_PRIVATE (sock);
736 priv->non_blocking = FALSE;
737 status = soup_socket_connect (sock, soup_address_new (hostname, port));
739 if (!SOUP_STATUS_IS_SUCCESSFUL (status)) {
740 g_object_unref (sock);
745 *status_ret = status;
750 * soup_socket_server_new:
751 * @local_addr: Local address to bind to. (Use soup_address_any_new() to
752 * accept connections on any local address)
753 * @ssl_creds: SSL credentials, or %NULL if this is not an SSL server
754 * @callback: Callback to call when a client connects
755 * @user_data: data to pass to @callback.
757 * Create and open a new #SoupSocket listening on the specified
758 * address. @callback will be called each time a client connects,
759 * with a new #SoupSocket.
761 * Returns: a new #SoupSocket, or NULL if there was a failure.
764 soup_socket_server_new (SoupAddress *local_addr, gpointer ssl_creds,
765 SoupSocketListenerCallback callback,
769 SoupSocketPrivate *priv;
771 g_return_val_if_fail (SOUP_IS_ADDRESS (local_addr), NULL);
773 sock = g_object_new (SOUP_TYPE_SOCKET,
774 SOUP_SOCKET_SSL_CREDENTIALS, ssl_creds,
776 priv = SOUP_SOCKET_GET_PRIVATE (sock);
777 priv->is_server = TRUE;
778 if (!soup_socket_listen (sock, local_addr)) {
779 g_object_unref (sock);
784 g_signal_connect (sock, "new_connection",
785 G_CALLBACK (callback), user_data);
793 * soup_socket_disconnect:
794 * @sock: a #SoupSocket
796 * Disconnects @sock. Any further read or write attempts on it will
800 soup_socket_disconnect (SoupSocket *sock)
802 SoupSocketPrivate *priv;
803 gboolean already_disconnected = FALSE;
805 g_return_if_fail (SOUP_IS_SOCKET (sock));
806 priv = SOUP_SOCKET_GET_PRIVATE (sock);
808 if (g_mutex_trylock (priv->iolock)) {
810 disconnect_internal (priv);
812 already_disconnected = TRUE;
813 g_mutex_unlock (priv->iolock);
817 /* Another thread is currently doing IO, so
818 * we can't close the iochannel. So just kick
819 * the file descriptor out from under it.
822 sockfd = priv->sockfd;
825 already_disconnected = TRUE;
827 g_io_channel_set_close_on_unref (priv->iochannel,
829 SOUP_CLOSE_SOCKET (sockfd);
833 if (already_disconnected)
836 /* Give all readers a chance to notice the connection close */
837 g_signal_emit (sock, signals[READABLE], 0);
839 /* FIXME: can't disconnect until all data is read */
841 /* Then let everyone know we're disconnected */
842 g_signal_emit (sock, signals[DISCONNECTED], 0);
846 * soup_socket_is_connected:
847 * @sock: a #SoupSocket
849 * Tests if @sock is connected to another host
851 * Return value: %TRUE or %FALSE.
854 soup_socket_is_connected (SoupSocket *sock)
856 SoupSocketPrivate *priv;
858 g_return_val_if_fail (SOUP_IS_SOCKET (sock), FALSE);
859 priv = SOUP_SOCKET_GET_PRIVATE (sock);
861 return priv->iochannel != NULL;
865 * soup_socket_get_local_address:
866 * @sock: a #SoupSocket
868 * Returns the #SoupAddress corresponding to the local end of @sock.
870 * Return value: the #SoupAddress
873 soup_socket_get_local_address (SoupSocket *sock)
875 SoupSocketPrivate *priv;
877 g_return_val_if_fail (SOUP_IS_SOCKET (sock), NULL);
878 priv = SOUP_SOCKET_GET_PRIVATE (sock);
880 g_mutex_lock (priv->addrlock);
881 if (!priv->local_addr) {
882 struct soup_sockaddr_max bound_sa;
885 sa_len = sizeof (bound_sa);
886 getsockname (priv->sockfd, (struct sockaddr *)&bound_sa, &sa_len);
887 priv->local_addr = soup_address_new_from_sockaddr ((struct sockaddr *)&bound_sa, sa_len);
889 g_mutex_unlock (priv->addrlock);
891 return priv->local_addr;
895 * soup_socket_get_remote_address:
896 * @sock: a #SoupSocket
898 * Returns the #SoupAddress corresponding to the remote end of @sock.
900 * Return value: the #SoupAddress
903 soup_socket_get_remote_address (SoupSocket *sock)
905 SoupSocketPrivate *priv;
907 g_return_val_if_fail (SOUP_IS_SOCKET (sock), NULL);
908 priv = SOUP_SOCKET_GET_PRIVATE (sock);
910 g_mutex_lock (priv->addrlock);
911 if (!priv->remote_addr) {
912 struct soup_sockaddr_max bound_sa;
915 sa_len = sizeof (bound_sa);
916 getpeername (priv->sockfd, (struct sockaddr *)&bound_sa, &sa_len);
917 priv->remote_addr = soup_address_new_from_sockaddr ((struct sockaddr *)&bound_sa, sa_len);
919 g_mutex_unlock (priv->addrlock);
921 return priv->remote_addr;
928 socket_read_watch (GIOChannel *chan, GIOCondition cond, gpointer user_data)
930 SoupSocket *sock = user_data;
931 SoupSocketPrivate *priv = SOUP_SOCKET_GET_PRIVATE (sock);
934 g_signal_emit (sock, signals[READABLE], 0);
939 static SoupSocketIOStatus
940 read_from_network (SoupSocket *sock, gpointer buffer, gsize len, gsize *nread)
942 SoupSocketPrivate *priv = SOUP_SOCKET_GET_PRIVATE (sock);
944 GIOCondition cond = G_IO_IN;
947 if (!priv->iochannel)
948 return SOUP_SOCKET_EOF;
950 status = g_io_channel_read_chars (priv->iochannel,
951 buffer, len, nread, &err);
953 if (err->domain == SOUP_SSL_ERROR &&
954 err->code == SOUP_SSL_ERROR_HANDSHAKE_NEEDS_WRITE)
956 g_object_set_data_full (G_OBJECT (sock),
957 "SoupSocket-last_error",
958 err, (GDestroyNotify)g_error_free);
960 g_object_set_data (G_OBJECT (sock),
961 "SoupSocket-last_error",
966 case G_IO_STATUS_NORMAL:
967 case G_IO_STATUS_AGAIN:
969 return SOUP_SOCKET_OK;
971 if (!priv->read_tag) {
973 g_io_add_watch (priv->iochannel, cond,
974 socket_read_watch, sock);
976 return SOUP_SOCKET_WOULD_BLOCK;
978 case G_IO_STATUS_EOF:
979 return SOUP_SOCKET_EOF;
982 return SOUP_SOCKET_ERROR;
986 static SoupSocketIOStatus
987 read_from_buf (SoupSocket *sock, gpointer buffer, gsize len, gsize *nread)
989 SoupSocketPrivate *priv = SOUP_SOCKET_GET_PRIVATE (sock);
990 GByteArray *read_buf = priv->read_buf;
992 *nread = MIN (read_buf->len, len);
993 memcpy (buffer, read_buf->data, *nread);
995 if (*nread == read_buf->len) {
996 g_byte_array_free (read_buf, TRUE);
997 priv->read_buf = NULL;
999 memmove (read_buf->data, read_buf->data + *nread,
1000 read_buf->len - *nread);
1001 g_byte_array_set_size (read_buf, read_buf->len - *nread);
1004 return SOUP_SOCKET_OK;
1010 * @buffer: buffer to read into
1011 * @len: size of @buffer in bytes
1012 * @nread: on return, the number of bytes read into @buffer
1014 * Attempts to read up to @len bytes from @sock into @buffer. If some
1015 * data is successfully read, soup_socket_read() will return
1016 * %SOUP_SOCKET_OK, and *@nread will contain the number of bytes
1019 * If @sock is non-blocking, and no data is available, the return
1020 * value will be %SOUP_SOCKET_WOULD_BLOCK. In this case, the caller
1021 * can connect to the %readable signal to know when there is more data
1022 * to read. (NB: You MUST read all available data off the socket
1023 * first. The %readable signal will only be emitted after
1024 * soup_socket_read() has returned %SOUP_SOCKET_WOULD_BLOCK.)
1026 * Return value: a #SoupSocketIOStatus, as described above (or
1027 * %SOUP_SOCKET_EOF if the socket is no longer connected, or
1028 * %SOUP_SOCKET_ERROR on any other error).
1031 soup_socket_read (SoupSocket *sock, gpointer buffer, gsize len, gsize *nread)
1033 SoupSocketPrivate *priv;
1034 SoupSocketIOStatus status;
1036 g_return_val_if_fail (SOUP_IS_SOCKET (sock), SOUP_SOCKET_ERROR);
1037 priv = SOUP_SOCKET_GET_PRIVATE (sock);
1039 g_mutex_lock (priv->iolock);
1041 status = read_from_buf (sock, buffer, len, nread);
1043 status = read_from_network (sock, buffer, len, nread);
1044 g_mutex_unlock (priv->iolock);
1050 * soup_socket_read_until:
1052 * @buffer: buffer to read into
1053 * @len: size of @buffer in bytes
1054 * @boundary: boundary to read until
1055 * @boundary_len: length of @boundary in bytes
1056 * @nread: on return, the number of bytes read into @buffer
1057 * @got_boundary: on return, whether or not the data in @buffer
1058 * ends with the boundary string
1060 * Like soup_socket_read(), but reads no further than the first
1061 * occurrence of @boundary. (If the boundary is found, it will be
1062 * included in the returned data, and *@got_boundary will be set to
1063 * %TRUE.) Any data after the boundary will returned in future reads.
1065 * Return value: as for soup_socket_read()
1068 soup_socket_read_until (SoupSocket *sock, gpointer buffer, gsize len,
1069 gconstpointer boundary, gsize boundary_len,
1070 gsize *nread, gboolean *got_boundary)
1072 SoupSocketPrivate *priv;
1073 SoupSocketIOStatus status;
1074 GByteArray *read_buf;
1075 guint match_len, prev_len;
1078 g_return_val_if_fail (SOUP_IS_SOCKET (sock), SOUP_SOCKET_ERROR);
1079 priv = SOUP_SOCKET_GET_PRIVATE (sock);
1080 g_return_val_if_fail (len >= boundary_len, SOUP_SOCKET_ERROR);
1082 g_mutex_lock (priv->iolock);
1084 *got_boundary = FALSE;
1086 if (!priv->read_buf)
1087 priv->read_buf = g_byte_array_new ();
1088 read_buf = priv->read_buf;
1090 if (read_buf->len < boundary_len) {
1091 prev_len = read_buf->len;
1092 g_byte_array_set_size (read_buf, len);
1093 status = read_from_network (sock,
1094 read_buf->data + prev_len,
1095 len - prev_len, nread);
1096 read_buf->len = prev_len + *nread;
1098 if (status != SOUP_SOCKET_OK) {
1099 g_mutex_unlock (priv->iolock);
1104 /* Scan for the boundary */
1105 end = read_buf->data + read_buf->len;
1106 for (p = read_buf->data; p <= end - boundary_len; p++) {
1107 if (!memcmp (p, boundary, boundary_len)) {
1109 *got_boundary = TRUE;
1114 /* Return everything up to 'p' (which is either just after the
1115 * boundary, or @boundary_len - 1 bytes before the end of the
1118 match_len = p - read_buf->data;
1119 status = read_from_buf (sock, buffer, MIN (len, match_len), nread);
1121 g_mutex_unlock (priv->iolock);
1126 socket_write_watch (GIOChannel *chan, GIOCondition condition, gpointer user_data)
1128 SoupSocket *sock = user_data;
1129 SoupSocketPrivate *priv = SOUP_SOCKET_GET_PRIVATE (sock);
1131 priv->write_tag = 0;
1132 g_signal_emit (sock, signals[WRITABLE], 0);
1138 * soup_socket_write:
1140 * @buffer: data to write
1141 * @len: size of @buffer, in bytes
1142 * @nwrote: on return, number of bytes written
1144 * Attempts to write @len bytes from @buffer to @sock. If some data is
1145 * successfully written, the resturn status will be
1146 * %SOUP_SOCKET_SUCCESS, and *@nwrote will contain the number of bytes
1149 * If @sock is non-blocking, and no data could be written right away,
1150 * the return value will be %SOUP_SOCKET_WOULD_BLOCK. In this case,
1151 * the caller can connect to the %writable signal to know when more
1152 * data can be written. (NB: %writable is only emitted after a
1153 * %SOUP_SOCKET_WOULD_BLOCK.)
1155 * Return value: a #SoupSocketIOStatus, as described above (or
1156 * %SOUP_SOCKET_EOF or %SOUP_SOCKET_ERROR).
1159 soup_socket_write (SoupSocket *sock, gconstpointer buffer,
1160 gsize len, gsize *nwrote)
1162 SoupSocketPrivate *priv;
1165 gpointer pipe_handler;
1167 GIOCondition cond = G_IO_OUT;
1170 g_return_val_if_fail (SOUP_IS_SOCKET (sock), SOUP_SOCKET_ERROR);
1171 priv = SOUP_SOCKET_GET_PRIVATE (sock);
1173 g_mutex_lock (priv->iolock);
1175 if (!priv->iochannel) {
1176 g_mutex_unlock (priv->iolock);
1177 return SOUP_SOCKET_EOF;
1179 if (priv->write_tag) {
1180 g_mutex_unlock (priv->iolock);
1181 return SOUP_SOCKET_WOULD_BLOCK;
1185 pipe_handler = signal (SIGPIPE, SIG_IGN);
1187 status = g_io_channel_write_chars (priv->iochannel,
1188 buffer, len, nwrote, &err);
1190 signal (SIGPIPE, pipe_handler);
1193 if (err->domain == SOUP_SSL_ERROR &&
1194 err->code == SOUP_SSL_ERROR_HANDSHAKE_NEEDS_READ)
1196 g_object_set_data_full (G_OBJECT (sock),
1197 "SoupSocket-last_error",
1198 err, (GDestroyNotify)g_error_free);
1200 g_object_set_data (G_OBJECT (sock),
1201 "SoupSocket-last_error",
1205 if (status != G_IO_STATUS_NORMAL && status != G_IO_STATUS_AGAIN) {
1206 g_mutex_unlock (priv->iolock);
1207 return SOUP_SOCKET_ERROR;
1211 g_mutex_unlock (priv->iolock);
1212 return SOUP_SOCKET_OK;
1216 g_io_add_watch (priv->iochannel, cond,
1217 socket_write_watch, sock);
1218 g_mutex_unlock (priv->iolock);
1219 return SOUP_SOCKET_WOULD_BLOCK;