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"
25 #include <sys/types.h>
29 * @short_description: A network socket
33 G_DEFINE_TYPE (SoupSocket, soup_socket, G_TYPE_OBJECT)
43 static guint signals[LAST_SIGNAL] = { 0 };
61 SoupAddress *local_addr, *remote_addr;
62 GIOChannel *iochannel;
68 GMainContext *async_context;
70 GSource *read_src, *write_src;
73 GMutex *iolock, *addrlock;
76 #define SOUP_SOCKET_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), SOUP_TYPE_SOCKET, SoupSocketPrivate))
79 #define soup_sockaddr_max sockaddr_in6
81 #define soup_sockaddr_max sockaddr_in
84 static void set_property (GObject *object, guint prop_id,
85 const GValue *value, GParamSpec *pspec);
86 static void get_property (GObject *object, guint prop_id,
87 GValue *value, GParamSpec *pspec);
90 #define SOUP_IS_SOCKET_ERROR(status) ((status) == SOCKET_ERROR)
91 #define SOUP_IS_INVALID_SOCKET(socket) ((socket) == INVALID_SOCKET)
92 #define SOUP_IS_CONNECT_STATUS_INPROGRESS() (WSAGetLastError () == WSAEWOULDBLOCK)
93 #define SHUT_RDWR SD_BOTH
95 #define SOUP_IS_SOCKET_ERROR(status) ((status) == -1)
96 #define SOUP_IS_INVALID_SOCKET(socket) ((socket) < 0)
97 #define SOUP_IS_CONNECT_STATUS_INPROGRESS() (errno == EINPROGRESS)
101 soup_socket_init (SoupSocket *sock)
103 SoupSocketPrivate *priv = SOUP_SOCKET_GET_PRIVATE (sock);
106 priv->non_blocking = TRUE;
107 priv->addrlock = g_mutex_new ();
108 priv->iolock = g_mutex_new ();
113 disconnect_internal (SoupSocketPrivate *priv)
115 g_io_channel_unref (priv->iochannel);
116 priv->iochannel = NULL;
119 if (priv->read_src) {
120 g_source_destroy (priv->read_src);
121 priv->read_src = NULL;
123 if (priv->write_src) {
124 g_source_destroy (priv->write_src);
125 priv->write_src = NULL;
130 finalize (GObject *object)
132 SoupSocketPrivate *priv = SOUP_SOCKET_GET_PRIVATE (object);
135 disconnect_internal (priv);
137 if (priv->local_addr)
138 g_object_unref (priv->local_addr);
139 if (priv->remote_addr)
140 g_object_unref (priv->remote_addr);
143 g_source_destroy (priv->watch_src);
144 if (priv->async_context)
145 g_main_context_unref (priv->async_context);
148 g_byte_array_free (priv->read_buf, TRUE);
150 g_mutex_free (priv->addrlock);
151 g_mutex_free (priv->iolock);
153 G_OBJECT_CLASS (soup_socket_parent_class)->finalize (object);
157 soup_socket_class_init (SoupSocketClass *socket_class)
159 GObjectClass *object_class = G_OBJECT_CLASS (socket_class);
161 g_type_class_add_private (socket_class, sizeof (SoupSocketPrivate));
163 /* virtual method override */
164 object_class->finalize = finalize;
165 object_class->set_property = set_property;
166 object_class->get_property = get_property;
171 * SoupSocket::readable:
174 * Emitted when an async socket is readable. See
175 * soup_socket_read() and soup_socket_read_until().
178 g_signal_new ("readable",
179 G_OBJECT_CLASS_TYPE (object_class),
181 G_STRUCT_OFFSET (SoupSocketClass, readable),
183 soup_marshal_NONE__NONE,
187 * SoupSocket::writable:
190 * Emitted when an async socket is writable. See
191 * soup_socket_write().
194 g_signal_new ("writable",
195 G_OBJECT_CLASS_TYPE (object_class),
197 G_STRUCT_OFFSET (SoupSocketClass, writable),
199 soup_marshal_NONE__NONE,
203 * SoupSocket::disconnected:
206 * Emitted when the socket is disconnected, for whatever
209 signals[DISCONNECTED] =
210 g_signal_new ("disconnected",
211 G_OBJECT_CLASS_TYPE (object_class),
213 G_STRUCT_OFFSET (SoupSocketClass, disconnected),
215 soup_marshal_NONE__NONE,
219 * SoupSocket::new-connection:
221 * @new: the new socket
223 * Emitted when a listening socket (set up with
224 * soup_socket_listen()) receives a new connection.
226 * You must ref the @new if you want to keep it; otherwise it
227 * will be destroyed after the signal is emitted.
229 signals[NEW_CONNECTION] =
230 g_signal_new ("new_connection",
231 G_OBJECT_CLASS_TYPE (object_class),
233 G_STRUCT_OFFSET (SoupSocketClass, new_connection),
235 soup_marshal_NONE__OBJECT,
240 g_object_class_install_property (
241 object_class, PROP_LOCAL_ADDRESS,
242 g_param_spec_object (SOUP_SOCKET_LOCAL_ADDRESS,
244 "Address of local end of socket",
246 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
247 g_object_class_install_property (
248 object_class, PROP_REMOTE_ADDRESS,
249 g_param_spec_object (SOUP_SOCKET_REMOTE_ADDRESS,
251 "Address of remote end of socket",
253 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
254 g_object_class_install_property (
255 object_class, PROP_NON_BLOCKING,
256 g_param_spec_boolean (SOUP_SOCKET_FLAG_NONBLOCKING,
258 "Whether or not the socket uses non-blocking I/O",
261 g_object_class_install_property (
262 object_class, PROP_IS_SERVER,
263 g_param_spec_boolean (SOUP_SOCKET_IS_SERVER,
265 "Whether or not the socket is a server socket",
268 g_object_class_install_property (
269 object_class, PROP_SSL_CREDENTIALS,
270 g_param_spec_pointer (SOUP_SOCKET_SSL_CREDENTIALS,
272 "SSL credential information, passed from the session to the SSL implementation",
274 g_object_class_install_property (
275 object_class, PROP_ASYNC_CONTEXT,
276 g_param_spec_pointer (SOUP_SOCKET_ASYNC_CONTEXT,
277 "Async GMainContext",
278 "The GMainContext to dispatch this socket's async I/O in",
279 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
281 g_object_class_install_property (
282 object_class, PROP_TIMEOUT,
283 g_param_spec_uint (SOUP_SOCKET_TIMEOUT,
285 "Value in seconds to timeout a blocking I/O",
290 /* Make sure WSAStartup() gets called. */
291 soup_address_get_type ();
297 set_nonblocking (SoupSocketPrivate *priv)
305 if (priv->sockfd == -1)
309 flags = fcntl (priv->sockfd, F_GETFL, 0);
311 if (priv->non_blocking)
314 flags &= ~O_NONBLOCK;
315 fcntl (priv->sockfd, F_SETFL, flags);
318 val = priv->non_blocking ? 1 : 0;
319 ioctlsocket (priv->sockfd, FIONBIO, &val);
324 set_fdflags (SoupSocketPrivate *priv)
327 struct timeval timeout;
332 if (priv->sockfd == -1)
335 set_nonblocking (priv);
338 flags = fcntl (priv->sockfd, F_GETFD, 0);
341 fcntl (priv->sockfd, F_SETFD, flags);
346 setsockopt (priv->sockfd, IPPROTO_TCP,
347 TCP_NODELAY, (void *) &opt, sizeof (opt));
348 setsockopt (priv->sockfd, SOL_SOCKET,
349 SO_REUSEADDR, (void *) &opt, sizeof (opt));
351 timeout.tv_sec = priv->timeout;
353 setsockopt (priv->sockfd, SOL_SOCKET,
354 SO_RCVTIMEO, (void *) &timeout, sizeof (timeout));
356 timeout.tv_sec = priv->timeout;
358 setsockopt (priv->sockfd, SOL_SOCKET,
359 SO_SNDTIMEO, (void *) &timeout, sizeof (timeout));
363 g_io_channel_unix_new (priv->sockfd);
366 g_io_channel_win32_new_socket (priv->sockfd);
368 g_io_channel_set_close_on_unref (priv->iochannel, TRUE);
369 g_io_channel_set_encoding (priv->iochannel, NULL, NULL);
370 g_io_channel_set_buffered (priv->iochannel, FALSE);
374 set_property (GObject *object, guint prop_id,
375 const GValue *value, GParamSpec *pspec)
377 SoupSocketPrivate *priv = SOUP_SOCKET_GET_PRIVATE (object);
380 case PROP_LOCAL_ADDRESS:
381 priv->local_addr = (SoupAddress *)g_value_dup_object (value);
383 case PROP_REMOTE_ADDRESS:
384 priv->remote_addr = (SoupAddress *)g_value_dup_object (value);
386 case PROP_NON_BLOCKING:
387 priv->non_blocking = g_value_get_boolean (value);
388 set_nonblocking (priv);
390 case PROP_SSL_CREDENTIALS:
391 priv->ssl_creds = g_value_get_pointer (value);
393 case PROP_ASYNC_CONTEXT:
394 priv->async_context = g_value_get_pointer (value);
395 if (priv->async_context)
396 g_main_context_ref (priv->async_context);
399 priv->timeout = g_value_get_uint (value);
407 get_property (GObject *object, guint prop_id,
408 GValue *value, GParamSpec *pspec)
410 SoupSocketPrivate *priv = SOUP_SOCKET_GET_PRIVATE (object);
413 case PROP_LOCAL_ADDRESS:
414 g_value_set_object (value, soup_socket_get_local_address (SOUP_SOCKET (object)));
416 case PROP_REMOTE_ADDRESS:
417 g_value_set_object (value, soup_socket_get_remote_address (SOUP_SOCKET (object)));
419 case PROP_NON_BLOCKING:
420 g_value_set_boolean (value, priv->non_blocking);
423 g_value_set_boolean (value, priv->is_server);
425 case PROP_SSL_CREDENTIALS:
426 g_value_set_pointer (value, priv->ssl_creds);
428 case PROP_ASYNC_CONTEXT:
429 g_value_set_pointer (value, priv->async_context ? g_main_context_ref (priv->async_context) : NULL);
432 g_value_set_uint (value, priv->timeout);
442 * @optname1: name of first property to set (or %NULL)
443 * @...: value of @optname1, followed by additional property/value pairs
445 * Creates a new (disconnected) socket
447 * Return value: the new socket
450 soup_socket_new (const char *optname1, ...)
455 va_start (ap, optname1);
456 sock = (SoupSocket *)g_object_new_valist (SOUP_TYPE_SOCKET,
465 GCancellable *cancellable;
467 SoupSocketCallback callback;
469 } SoupSocketAsyncConnectData;
472 idle_connect_result (gpointer user_data)
474 SoupSocketAsyncConnectData *sacd = user_data;
475 SoupSocketPrivate *priv = SOUP_SOCKET_GET_PRIVATE (sacd->sock);
478 priv->watch_src = NULL;
480 g_signal_handler_disconnect (sacd->cancellable, sacd->cancel_id);
482 if (priv->sockfd == -1) {
483 if (g_cancellable_is_cancelled (sacd->cancellable))
484 status = SOUP_STATUS_CANCELLED;
486 status = SOUP_STATUS_CANT_CONNECT;
488 status = SOUP_STATUS_OK;
490 sacd->callback (sacd->sock, status, sacd->user_data);
491 g_slice_free (SoupSocketAsyncConnectData, sacd);
496 connect_watch (GIOChannel* iochannel, GIOCondition condition, gpointer data)
498 SoupSocketAsyncConnectData *sacd = data;
499 SoupSocketPrivate *priv = SOUP_SOCKET_GET_PRIVATE (sacd->sock);
501 int len = sizeof (error);
503 /* Remove the watch now in case we don't return immediately */
504 g_source_destroy (priv->watch_src);
505 priv->watch_src = NULL;
507 if ((condition & ~(G_IO_IN | G_IO_OUT)) ||
508 (getsockopt (priv->sockfd, SOL_SOCKET, SO_ERROR,
509 (void *)&error, (void *)&len) != 0) ||
511 disconnect_internal (priv);
513 return idle_connect_result (sacd);
517 got_address (SoupAddress *addr, guint status, gpointer user_data)
519 SoupSocketAsyncConnectData *sacd = user_data;
521 if (!SOUP_STATUS_IS_SUCCESSFUL (status)) {
522 sacd->callback (sacd->sock, status, sacd->user_data);
523 g_slice_free (SoupSocketAsyncConnectData, sacd);
527 soup_socket_connect_async (sacd->sock, sacd->cancellable,
528 sacd->callback, sacd->user_data);
529 g_slice_free (SoupSocketAsyncConnectData, sacd);
533 async_cancel (GCancellable *cancellable, gpointer user_data)
535 SoupSocketAsyncConnectData *sacd = user_data;
536 SoupSocketPrivate *priv = SOUP_SOCKET_GET_PRIVATE (sacd->sock);
539 g_source_destroy (priv->watch_src);
540 disconnect_internal (priv);
541 priv->watch_src = soup_add_idle (priv->async_context,
542 idle_connect_result, sacd);
546 socket_connect_internal (SoupSocket *sock)
548 SoupSocketPrivate *priv = SOUP_SOCKET_GET_PRIVATE (sock);
552 sa = soup_address_get_sockaddr (priv->remote_addr, &len);
554 return SOUP_STATUS_CANT_RESOLVE;
556 priv->sockfd = socket (sa->sa_family, SOCK_STREAM, 0);
557 if (SOUP_IS_INVALID_SOCKET (priv->sockfd))
558 return SOUP_STATUS_CANT_CONNECT;
561 status = connect (priv->sockfd, sa, len);
563 if (SOUP_IS_SOCKET_ERROR (status)) {
564 if (SOUP_IS_CONNECT_STATUS_INPROGRESS ())
565 return SOUP_STATUS_CONTINUE;
567 disconnect_internal (priv);
568 return SOUP_STATUS_CANT_CONNECT;
570 return SOUP_STATUS_OK;
574 * SoupSocketCallback:
575 * @sock: the #SoupSocket
576 * @status: an HTTP status code indicating success or failure
577 * @user_data: the data passed to soup_socket_connect_async()
579 * The callback function passed to soup_socket_connect_async().
583 * soup_socket_connect_async:
584 * @sock: a client #SoupSocket (which must not already be connected)
585 * @cancellable: a #GCancellable, or %NULL
586 * @callback: callback to call after connecting
587 * @user_data: data to pass to @callback
589 * Begins asynchronously connecting to @sock's remote address. The
590 * socket will call @callback when it succeeds or fails (but not
591 * before returning from this function).
593 * If @cancellable is non-%NULL, it can be used to cancel the
594 * connection. @callback will still be invoked in this case, with a
595 * status of %SOUP_STATUS_CANCELLED.
598 soup_socket_connect_async (SoupSocket *sock, GCancellable *cancellable,
599 SoupSocketCallback callback, gpointer user_data)
601 SoupSocketPrivate *priv;
602 SoupSocketAsyncConnectData *sacd;
605 g_return_if_fail (SOUP_IS_SOCKET (sock));
606 priv = SOUP_SOCKET_GET_PRIVATE (sock);
607 g_return_if_fail (priv->remote_addr != NULL);
609 sacd = g_slice_new0 (SoupSocketAsyncConnectData);
611 sacd->cancellable = cancellable;
612 sacd->callback = callback;
613 sacd->user_data = user_data;
615 if (!soup_address_get_sockaddr (priv->remote_addr, NULL)) {
616 soup_address_resolve_async (priv->remote_addr,
623 status = socket_connect_internal (sock);
624 if (status == SOUP_STATUS_CONTINUE) {
625 /* Wait for connect to succeed or fail */
627 soup_add_io_watch (priv->async_context,
630 G_IO_PRI | G_IO_ERR |
631 G_IO_HUP | G_IO_NVAL,
632 connect_watch, sacd);
635 g_signal_connect (cancellable, "cancelled",
636 G_CALLBACK (async_cancel),
640 priv->watch_src = soup_add_idle (priv->async_context,
641 idle_connect_result, sacd);
646 sync_cancel (GCancellable *cancellable, gpointer sock)
648 SoupSocketPrivate *priv = SOUP_SOCKET_GET_PRIVATE (sock);
650 shutdown (priv->sockfd, SHUT_RDWR);
654 * soup_socket_connect_sync:
655 * @sock: a client #SoupSocket (which must not already be connected)
656 * @cancellable: a #GCancellable, or %NULL
658 * Attempt to synchronously connect @sock to its remote address.
660 * If @cancellable is non-%NULL, it can be used to cancel the
661 * connection, in which case soup_socket_connect_sync() will return
662 * %SOUP_STATUS_CANCELLED.
664 * Return value: a success or failure code.
667 soup_socket_connect_sync (SoupSocket *sock, GCancellable *cancellable)
669 SoupSocketPrivate *priv;
670 guint status, cancel_id;
672 g_return_val_if_fail (SOUP_IS_SOCKET (sock), SOUP_STATUS_MALFORMED);
673 priv = SOUP_SOCKET_GET_PRIVATE (sock);
674 g_return_val_if_fail (!priv->is_server, SOUP_STATUS_MALFORMED);
675 g_return_val_if_fail (priv->sockfd == -1, SOUP_STATUS_MALFORMED);
676 g_return_val_if_fail (priv->remote_addr != NULL, SOUP_STATUS_MALFORMED);
678 if (!soup_address_get_sockaddr (priv->remote_addr, NULL)) {
679 status = soup_address_resolve_sync (priv->remote_addr,
681 if (!SOUP_STATUS_IS_SUCCESSFUL (status))
686 cancel_id = g_signal_connect (cancellable, "cancelled",
687 G_CALLBACK (sync_cancel), sock);
690 status = socket_connect_internal (sock);
693 if (status != SOUP_STATUS_OK &&
694 g_cancellable_is_cancelled (cancellable)) {
695 status = SOUP_STATUS_CANCELLED;
696 disconnect_internal (priv);
698 g_signal_handler_disconnect (cancellable, cancel_id);
705 listen_watch (GIOChannel* iochannel, GIOCondition condition, gpointer data)
707 SoupSocket *sock = data, *new;
708 SoupSocketPrivate *priv = SOUP_SOCKET_GET_PRIVATE (sock), *new_priv;
709 struct soup_sockaddr_max sa;
712 if (condition & (G_IO_HUP | G_IO_ERR)) {
713 g_source_destroy (priv->watch_src);
714 priv->watch_src = NULL;
718 sa_len = sizeof (sa);
719 sockfd = accept (priv->sockfd, (struct sockaddr *)&sa, (void *)&sa_len);
720 if (SOUP_IS_INVALID_SOCKET (sockfd))
723 new = g_object_new (SOUP_TYPE_SOCKET, NULL);
724 new_priv = SOUP_SOCKET_GET_PRIVATE (new);
725 new_priv->sockfd = sockfd;
726 if (priv->async_context)
727 new_priv->async_context = g_main_context_ref (priv->async_context);
728 new_priv->non_blocking = priv->non_blocking;
729 new_priv->is_server = TRUE;
730 new_priv->ssl_creds = priv->ssl_creds;
731 set_fdflags (new_priv);
733 new_priv->remote_addr = soup_address_new_from_sockaddr ((struct sockaddr *)&sa, sa_len);
735 if (new_priv->ssl_creds) {
736 if (!soup_socket_start_ssl (new, NULL)) {
737 g_object_unref (new);
742 g_signal_emit (sock, signals[NEW_CONNECTION], 0, new);
743 g_object_unref (new);
749 * soup_socket_listen:
750 * @sock: a server #SoupSocket (which must not already be connected or
753 * Makes @sock start listening on its local address. When connections
754 * come in, @sock will emit %new_connection.
756 * Return value: whether or not @sock is now listening.
759 soup_socket_listen (SoupSocket *sock)
762 SoupSocketPrivate *priv;
766 g_return_val_if_fail (SOUP_IS_SOCKET (sock), FALSE);
767 priv = SOUP_SOCKET_GET_PRIVATE (sock);
768 g_return_val_if_fail (priv->sockfd == -1, FALSE);
769 g_return_val_if_fail (priv->local_addr != NULL, FALSE);
771 priv->is_server = TRUE;
773 /* @local_addr may have its port set to 0. So we intentionally
774 * don't store it in priv->local_addr, so that if the
775 * caller calls soup_socket_get_local_address() later, we'll
776 * have to make a new addr by calling getsockname(), which
777 * will have the right port number.
779 sa = soup_address_get_sockaddr (priv->local_addr, &sa_len);
780 g_return_val_if_fail (sa != NULL, FALSE);
782 priv->sockfd = socket (sa->sa_family, SOCK_STREAM, 0);
783 if (SOUP_IS_INVALID_SOCKET (priv->sockfd))
788 if (bind (priv->sockfd, sa, sa_len) != 0)
790 /* Force local_addr to be re-resolved now */
791 g_object_unref (priv->local_addr);
792 priv->local_addr = NULL;
795 if (listen (priv->sockfd, 10) != 0)
798 priv->watch_src = soup_add_io_watch (priv->async_context,
800 G_IO_IN | G_IO_ERR | G_IO_HUP,
806 disconnect_internal (priv);
812 * soup_socket_start_ssl:
814 * @cancellable: a #GCancellable
816 * Starts using SSL on @socket.
818 * Return value: success or failure
821 soup_socket_start_ssl (SoupSocket *sock, GCancellable *cancellable)
823 SoupSocketPrivate *priv = SOUP_SOCKET_GET_PRIVATE (sock);
825 return soup_socket_start_proxy_ssl (sock, soup_address_get_name (priv->remote_addr), cancellable);
829 * soup_socket_start_proxy_ssl:
831 * @ssl_host: hostname of the SSL server
832 * @cancellable: a #GCancellable
834 * Starts using SSL on @socket, expecting to find a host named
837 * Return value: success or failure
840 soup_socket_start_proxy_ssl (SoupSocket *sock, const char *ssl_host,
841 GCancellable *cancellable)
843 SoupSocketPrivate *priv = SOUP_SOCKET_GET_PRIVATE (sock);
844 GIOChannel *ssl_chan;
845 GIOChannel *real_chan;
847 real_chan = priv->iochannel;
848 ssl_chan = soup_ssl_wrap_iochannel (
849 real_chan, priv->is_server ?
850 SOUP_SSL_TYPE_SERVER : SOUP_SSL_TYPE_CLIENT,
851 ssl_host, priv->ssl_creds);
856 priv->iochannel = ssl_chan;
857 g_io_channel_unref (real_chan);
863 soup_socket_is_ssl (SoupSocket *sock)
865 SoupSocketPrivate *priv = SOUP_SOCKET_GET_PRIVATE (sock);
867 return priv->ssl_creds != NULL;
871 * soup_socket_disconnect:
872 * @sock: a #SoupSocket
874 * Disconnects @sock. Any further read or write attempts on it will
878 soup_socket_disconnect (SoupSocket *sock)
880 SoupSocketPrivate *priv;
881 gboolean already_disconnected = FALSE;
883 g_return_if_fail (SOUP_IS_SOCKET (sock));
884 priv = SOUP_SOCKET_GET_PRIVATE (sock);
886 if (g_mutex_trylock (priv->iolock)) {
888 disconnect_internal (priv);
890 already_disconnected = TRUE;
891 g_mutex_unlock (priv->iolock);
895 /* Another thread is currently doing IO, so
896 * we can't close the iochannel. So just shutdown
897 * the file descriptor to force the I/O to fail.
898 * (It will actually be closed when the socket is
901 sockfd = priv->sockfd;
905 already_disconnected = TRUE;
907 shutdown (sockfd, SHUT_RDWR);
910 if (already_disconnected)
913 /* Give all readers a chance to notice the connection close */
914 g_signal_emit (sock, signals[READABLE], 0);
916 /* FIXME: can't disconnect until all data is read */
918 /* Then let everyone know we're disconnected */
919 g_signal_emit (sock, signals[DISCONNECTED], 0);
923 * soup_socket_is_connected:
924 * @sock: a #SoupSocket
926 * Tests if @sock is connected to another host
928 * Return value: %TRUE or %FALSE.
931 soup_socket_is_connected (SoupSocket *sock)
933 SoupSocketPrivate *priv;
935 g_return_val_if_fail (SOUP_IS_SOCKET (sock), FALSE);
936 priv = SOUP_SOCKET_GET_PRIVATE (sock);
938 return priv->iochannel != NULL;
942 * soup_socket_get_local_address:
943 * @sock: a #SoupSocket
945 * Returns the #SoupAddress corresponding to the local end of @sock.
947 * Return value: the #SoupAddress
950 soup_socket_get_local_address (SoupSocket *sock)
952 SoupSocketPrivate *priv;
954 g_return_val_if_fail (SOUP_IS_SOCKET (sock), NULL);
955 priv = SOUP_SOCKET_GET_PRIVATE (sock);
957 g_mutex_lock (priv->addrlock);
958 if (!priv->local_addr) {
959 struct soup_sockaddr_max bound_sa;
962 sa_len = sizeof (bound_sa);
963 getsockname (priv->sockfd, (struct sockaddr *)&bound_sa, (void *)&sa_len);
964 priv->local_addr = soup_address_new_from_sockaddr ((struct sockaddr *)&bound_sa, sa_len);
966 g_mutex_unlock (priv->addrlock);
968 return priv->local_addr;
972 * soup_socket_get_remote_address:
973 * @sock: a #SoupSocket
975 * Returns the #SoupAddress corresponding to the remote end of @sock.
977 * Return value: the #SoupAddress
980 soup_socket_get_remote_address (SoupSocket *sock)
982 SoupSocketPrivate *priv;
984 g_return_val_if_fail (SOUP_IS_SOCKET (sock), NULL);
985 priv = SOUP_SOCKET_GET_PRIVATE (sock);
987 g_mutex_lock (priv->addrlock);
988 if (!priv->remote_addr) {
989 struct soup_sockaddr_max bound_sa;
992 sa_len = sizeof (bound_sa);
993 getpeername (priv->sockfd, (struct sockaddr *)&bound_sa, (void *)&sa_len);
994 priv->remote_addr = soup_address_new_from_sockaddr ((struct sockaddr *)&bound_sa, sa_len);
996 g_mutex_unlock (priv->addrlock);
998 return priv->remote_addr;
1005 socket_read_watch (GIOChannel *chan, GIOCondition cond, gpointer user_data)
1007 SoupSocket *sock = user_data;
1008 SoupSocketPrivate *priv = SOUP_SOCKET_GET_PRIVATE (sock);
1010 priv->read_src = NULL;
1012 if (cond & (G_IO_ERR | G_IO_HUP))
1013 soup_socket_disconnect (sock);
1015 g_signal_emit (sock, signals[READABLE], 0);
1020 static SoupSocketIOStatus
1021 read_from_network (SoupSocket *sock, gpointer buffer, gsize len,
1022 gsize *nread, GError **error)
1024 SoupSocketPrivate *priv = SOUP_SOCKET_GET_PRIVATE (sock);
1026 GIOCondition cond = G_IO_IN;
1027 GError *my_err = NULL;
1029 if (!priv->iochannel)
1030 return SOUP_SOCKET_EOF;
1032 status = g_io_channel_read_chars (priv->iochannel,
1033 buffer, len, nread, &my_err);
1035 if (my_err->domain == SOUP_SSL_ERROR &&
1036 my_err->code == SOUP_SSL_ERROR_HANDSHAKE_NEEDS_WRITE)
1038 g_propagate_error (error, my_err);
1042 case G_IO_STATUS_NORMAL:
1043 case G_IO_STATUS_AGAIN:
1045 g_clear_error (error);
1046 return SOUP_SOCKET_OK;
1049 /* If the socket is sync and we get EAGAIN, then it is
1050 * a socket timeout and should be treated as an error
1053 if (!priv->non_blocking)
1054 return SOUP_SOCKET_ERROR;
1056 if (!priv->read_src) {
1058 soup_add_io_watch (priv->async_context,
1060 cond | G_IO_HUP | G_IO_ERR,
1061 socket_read_watch, sock);
1063 g_clear_error (error);
1064 return SOUP_SOCKET_WOULD_BLOCK;
1066 case G_IO_STATUS_EOF:
1067 g_clear_error (error);
1068 return SOUP_SOCKET_EOF;
1071 return SOUP_SOCKET_ERROR;
1075 static SoupSocketIOStatus
1076 read_from_buf (SoupSocket *sock, gpointer buffer, gsize len, gsize *nread)
1078 SoupSocketPrivate *priv = SOUP_SOCKET_GET_PRIVATE (sock);
1079 GByteArray *read_buf = priv->read_buf;
1081 *nread = MIN (read_buf->len, len);
1082 memcpy (buffer, read_buf->data, *nread);
1084 if (*nread == read_buf->len) {
1085 g_byte_array_free (read_buf, TRUE);
1086 priv->read_buf = NULL;
1088 memmove (read_buf->data, read_buf->data + *nread,
1089 read_buf->len - *nread);
1090 g_byte_array_set_size (read_buf, read_buf->len - *nread);
1093 return SOUP_SOCKET_OK;
1097 * SoupSocketIOStatus:
1098 * @SOUP_SOCKET_OK: Success
1099 * @SOUP_SOCKET_WOULD_BLOCK: Cannot read/write any more at this time
1100 * @SOUP_SOCKET_EOF: End of file
1101 * @SOUP_SOCKET_ERROR: Other error
1103 * Return value from the #SoupSocket IO methods.
1109 * @buffer: buffer to read into
1110 * @len: size of @buffer in bytes
1111 * @nread: on return, the number of bytes read into @buffer
1112 * @cancellable: a #GCancellable, or %NULL
1113 * @error: error pointer
1115 * Attempts to read up to @len bytes from @sock into @buffer. If some
1116 * data is successfully read, soup_socket_read() will return
1117 * %SOUP_SOCKET_OK, and *@nread will contain the number of bytes
1120 * If @sock is non-blocking, and no data is available, the return
1121 * value will be %SOUP_SOCKET_WOULD_BLOCK. In this case, the caller
1122 * can connect to the %readable signal to know when there is more data
1123 * to read. (NB: You MUST read all available data off the socket
1124 * first. The %readable signal will only be emitted after
1125 * soup_socket_read() has returned %SOUP_SOCKET_WOULD_BLOCK.)
1127 * Return value: a #SoupSocketIOStatus, as described above (or
1128 * %SOUP_SOCKET_EOF if the socket is no longer connected, or
1129 * %SOUP_SOCKET_ERROR on any other error, in which case @error will
1133 soup_socket_read (SoupSocket *sock, gpointer buffer, gsize len,
1134 gsize *nread, GCancellable *cancellable, GError **error)
1136 SoupSocketPrivate *priv;
1137 SoupSocketIOStatus status;
1139 g_return_val_if_fail (SOUP_IS_SOCKET (sock), SOUP_SOCKET_ERROR);
1140 priv = SOUP_SOCKET_GET_PRIVATE (sock);
1142 g_mutex_lock (priv->iolock);
1144 status = read_from_buf (sock, buffer, len, nread);
1146 status = read_from_network (sock, buffer, len, nread, error);
1147 g_mutex_unlock (priv->iolock);
1153 * soup_socket_read_until:
1155 * @buffer: buffer to read into
1156 * @len: size of @buffer in bytes
1157 * @boundary: boundary to read until
1158 * @boundary_len: length of @boundary in bytes
1159 * @nread: on return, the number of bytes read into @buffer
1160 * @got_boundary: on return, whether or not the data in @buffer
1161 * ends with the boundary string
1162 * @cancellable: a #GCancellable, or %NULL
1163 * @error: error pointer
1165 * Like soup_socket_read(), but reads no further than the first
1166 * occurrence of @boundary. (If the boundary is found, it will be
1167 * included in the returned data, and *@got_boundary will be set to
1168 * %TRUE.) Any data after the boundary will returned in future reads.
1170 * Return value: as for soup_socket_read()
1173 soup_socket_read_until (SoupSocket *sock, gpointer buffer, gsize len,
1174 gconstpointer boundary, gsize boundary_len,
1175 gsize *nread, gboolean *got_boundary,
1176 GCancellable *cancellable, GError **error)
1178 SoupSocketPrivate *priv;
1179 SoupSocketIOStatus status;
1180 GByteArray *read_buf;
1181 guint match_len, prev_len;
1184 g_return_val_if_fail (SOUP_IS_SOCKET (sock), SOUP_SOCKET_ERROR);
1185 priv = SOUP_SOCKET_GET_PRIVATE (sock);
1186 g_return_val_if_fail (len >= boundary_len, SOUP_SOCKET_ERROR);
1188 g_mutex_lock (priv->iolock);
1190 *got_boundary = FALSE;
1192 if (!priv->read_buf)
1193 priv->read_buf = g_byte_array_new ();
1194 read_buf = priv->read_buf;
1196 if (read_buf->len < boundary_len) {
1197 prev_len = read_buf->len;
1198 g_byte_array_set_size (read_buf, len);
1199 status = read_from_network (sock,
1200 read_buf->data + prev_len,
1201 len - prev_len, nread, error);
1202 read_buf->len = prev_len + *nread;
1204 if (status != SOUP_SOCKET_OK) {
1205 g_mutex_unlock (priv->iolock);
1210 /* Scan for the boundary */
1211 end = read_buf->data + read_buf->len;
1212 for (p = read_buf->data; p <= end - boundary_len; p++) {
1213 if (!memcmp (p, boundary, boundary_len)) {
1215 *got_boundary = TRUE;
1220 /* Return everything up to 'p' (which is either just after the
1221 * boundary, or @boundary_len - 1 bytes before the end of the
1224 match_len = p - read_buf->data;
1225 status = read_from_buf (sock, buffer, MIN (len, match_len), nread);
1227 g_mutex_unlock (priv->iolock);
1232 socket_write_watch (GIOChannel *chan, GIOCondition cond, gpointer user_data)
1234 SoupSocket *sock = user_data;
1235 SoupSocketPrivate *priv = SOUP_SOCKET_GET_PRIVATE (sock);
1237 priv->write_src = NULL;
1239 if (cond & (G_IO_ERR | G_IO_HUP))
1240 soup_socket_disconnect (sock);
1242 g_signal_emit (sock, signals[WRITABLE], 0);
1248 * soup_socket_write:
1250 * @buffer: data to write
1251 * @len: size of @buffer, in bytes
1252 * @nwrote: on return, number of bytes written
1253 * @cancellable: a #GCancellable, or %NULL
1254 * @error: error pointer
1256 * Attempts to write @len bytes from @buffer to @sock. If some data is
1257 * successfully written, the resturn status will be
1258 * %SOUP_SOCKET_SUCCESS, and *@nwrote will contain the number of bytes
1261 * If @sock is non-blocking, and no data could be written right away,
1262 * the return value will be %SOUP_SOCKET_WOULD_BLOCK. In this case,
1263 * the caller can connect to the %writable signal to know when more
1264 * data can be written. (NB: %writable is only emitted after a
1265 * %SOUP_SOCKET_WOULD_BLOCK.)
1267 * Return value: a #SoupSocketIOStatus, as described above (or
1268 * %SOUP_SOCKET_EOF or %SOUP_SOCKET_ERROR. @error will be set if the
1269 * return value is %SOUP_SOCKET_ERROR.)
1272 soup_socket_write (SoupSocket *sock, gconstpointer buffer,
1273 gsize len, gsize *nwrote,
1274 GCancellable *cancellable, GError **error)
1276 SoupSocketPrivate *priv;
1279 gpointer pipe_handler;
1281 GIOCondition cond = G_IO_OUT;
1282 GError *my_err = NULL;
1284 g_return_val_if_fail (SOUP_IS_SOCKET (sock), SOUP_SOCKET_ERROR);
1285 priv = SOUP_SOCKET_GET_PRIVATE (sock);
1287 g_mutex_lock (priv->iolock);
1289 if (!priv->iochannel) {
1290 g_mutex_unlock (priv->iolock);
1291 return SOUP_SOCKET_EOF;
1293 if (priv->write_src) {
1294 g_mutex_unlock (priv->iolock);
1295 return SOUP_SOCKET_WOULD_BLOCK;
1299 pipe_handler = signal (SIGPIPE, SIG_IGN);
1301 status = g_io_channel_write_chars (priv->iochannel,
1302 buffer, len, nwrote, &my_err);
1304 signal (SIGPIPE, pipe_handler);
1307 if (my_err->domain == SOUP_SSL_ERROR &&
1308 my_err->code == SOUP_SSL_ERROR_HANDSHAKE_NEEDS_READ)
1310 g_propagate_error (error, my_err);
1313 /* If the socket is sync and we get EAGAIN, then it is a
1314 * socket timeout and should be treated as an error condition.
1316 if (!priv->non_blocking && status == G_IO_STATUS_AGAIN) {
1317 g_mutex_unlock (priv->iolock);
1318 return SOUP_SOCKET_ERROR;
1321 if (status != G_IO_STATUS_NORMAL && status != G_IO_STATUS_AGAIN) {
1322 g_mutex_unlock (priv->iolock);
1323 return SOUP_SOCKET_ERROR;
1326 g_clear_error (error);
1329 g_mutex_unlock (priv->iolock);
1330 return SOUP_SOCKET_OK;
1334 soup_add_io_watch (priv->async_context,
1336 cond | G_IO_HUP | G_IO_ERR,
1337 socket_write_watch, sock);
1338 g_mutex_unlock (priv->iolock);
1339 return SOUP_SOCKET_WOULD_BLOCK;