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
31 * #SoupSocket is libsoup's TCP socket type. While it is primarily
32 * intended for internal use, #SoupSocket<!-- -->s are exposed in the
33 * API in various places, and some of their methods (eg,
34 * soup_socket_get_remote_address()) may be useful to applications.
37 G_DEFINE_TYPE (SoupSocket, soup_socket, G_TYPE_OBJECT)
47 static guint signals[LAST_SIGNAL] = { 0 };
65 SoupAddress *local_addr, *remote_addr;
66 GIOChannel *iochannel;
72 GMainContext *async_context;
74 GSource *read_src, *write_src;
77 GMutex *iolock, *addrlock;
80 #define SOUP_SOCKET_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), SOUP_TYPE_SOCKET, SoupSocketPrivate))
83 #define soup_sockaddr_max sockaddr_in6
85 #define soup_sockaddr_max sockaddr_in
88 static void set_property (GObject *object, guint prop_id,
89 const GValue *value, GParamSpec *pspec);
90 static void get_property (GObject *object, guint prop_id,
91 GValue *value, GParamSpec *pspec);
94 #define SOUP_IS_SOCKET_ERROR(status) ((status) == SOCKET_ERROR)
95 #define SOUP_IS_INVALID_SOCKET(socket) ((socket) == INVALID_SOCKET)
96 #define SOUP_IS_CONNECT_STATUS_INPROGRESS() (WSAGetLastError () == WSAEWOULDBLOCK)
97 #define SHUT_RDWR SD_BOTH
99 #define SOUP_IS_SOCKET_ERROR(status) ((status) == -1)
100 #define SOUP_IS_INVALID_SOCKET(socket) ((socket) < 0)
101 #define SOUP_IS_CONNECT_STATUS_INPROGRESS() (errno == EINPROGRESS)
105 soup_socket_init (SoupSocket *sock)
107 SoupSocketPrivate *priv = SOUP_SOCKET_GET_PRIVATE (sock);
110 priv->non_blocking = TRUE;
111 priv->addrlock = g_mutex_new ();
112 priv->iolock = g_mutex_new ();
117 disconnect_internal (SoupSocketPrivate *priv)
119 g_io_channel_unref (priv->iochannel);
120 priv->iochannel = NULL;
123 if (priv->read_src) {
124 g_source_destroy (priv->read_src);
125 priv->read_src = NULL;
127 if (priv->write_src) {
128 g_source_destroy (priv->write_src);
129 priv->write_src = NULL;
134 finalize (GObject *object)
136 SoupSocketPrivate *priv = SOUP_SOCKET_GET_PRIVATE (object);
139 disconnect_internal (priv);
141 if (priv->local_addr)
142 g_object_unref (priv->local_addr);
143 if (priv->remote_addr)
144 g_object_unref (priv->remote_addr);
147 g_source_destroy (priv->watch_src);
148 if (priv->async_context)
149 g_main_context_unref (priv->async_context);
152 g_byte_array_free (priv->read_buf, TRUE);
154 g_mutex_free (priv->addrlock);
155 g_mutex_free (priv->iolock);
157 G_OBJECT_CLASS (soup_socket_parent_class)->finalize (object);
161 soup_socket_class_init (SoupSocketClass *socket_class)
163 GObjectClass *object_class = G_OBJECT_CLASS (socket_class);
165 g_type_class_add_private (socket_class, sizeof (SoupSocketPrivate));
167 /* virtual method override */
168 object_class->finalize = finalize;
169 object_class->set_property = set_property;
170 object_class->get_property = get_property;
175 * SoupSocket::readable:
178 * Emitted when an async socket is readable. See
179 * soup_socket_read() and soup_socket_read_until().
182 g_signal_new ("readable",
183 G_OBJECT_CLASS_TYPE (object_class),
185 G_STRUCT_OFFSET (SoupSocketClass, readable),
187 soup_marshal_NONE__NONE,
191 * SoupSocket::writable:
194 * Emitted when an async socket is writable. See
195 * soup_socket_write().
198 g_signal_new ("writable",
199 G_OBJECT_CLASS_TYPE (object_class),
201 G_STRUCT_OFFSET (SoupSocketClass, writable),
203 soup_marshal_NONE__NONE,
207 * SoupSocket::disconnected:
210 * Emitted when the socket is disconnected, for whatever
213 signals[DISCONNECTED] =
214 g_signal_new ("disconnected",
215 G_OBJECT_CLASS_TYPE (object_class),
217 G_STRUCT_OFFSET (SoupSocketClass, disconnected),
219 soup_marshal_NONE__NONE,
223 * SoupSocket::new-connection:
225 * @new: the new socket
227 * Emitted when a listening socket (set up with
228 * soup_socket_listen()) receives a new connection.
230 * You must ref the @new if you want to keep it; otherwise it
231 * will be destroyed after the signal is emitted.
233 signals[NEW_CONNECTION] =
234 g_signal_new ("new_connection",
235 G_OBJECT_CLASS_TYPE (object_class),
237 G_STRUCT_OFFSET (SoupSocketClass, new_connection),
239 soup_marshal_NONE__OBJECT,
244 g_object_class_install_property (
245 object_class, PROP_LOCAL_ADDRESS,
246 g_param_spec_object (SOUP_SOCKET_LOCAL_ADDRESS,
248 "Address of local end of socket",
250 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
251 g_object_class_install_property (
252 object_class, PROP_REMOTE_ADDRESS,
253 g_param_spec_object (SOUP_SOCKET_REMOTE_ADDRESS,
255 "Address of remote end of socket",
257 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
258 g_object_class_install_property (
259 object_class, PROP_NON_BLOCKING,
260 g_param_spec_boolean (SOUP_SOCKET_FLAG_NONBLOCKING,
262 "Whether or not the socket uses non-blocking I/O",
265 g_object_class_install_property (
266 object_class, PROP_IS_SERVER,
267 g_param_spec_boolean (SOUP_SOCKET_IS_SERVER,
269 "Whether or not the socket is a server socket",
272 g_object_class_install_property (
273 object_class, PROP_SSL_CREDENTIALS,
274 g_param_spec_pointer (SOUP_SOCKET_SSL_CREDENTIALS,
276 "SSL credential information, passed from the session to the SSL implementation",
278 g_object_class_install_property (
279 object_class, PROP_ASYNC_CONTEXT,
280 g_param_spec_pointer (SOUP_SOCKET_ASYNC_CONTEXT,
281 "Async GMainContext",
282 "The GMainContext to dispatch this socket's async I/O in",
283 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
285 g_object_class_install_property (
286 object_class, PROP_TIMEOUT,
287 g_param_spec_uint (SOUP_SOCKET_TIMEOUT,
289 "Value in seconds to timeout a blocking I/O",
294 /* Make sure WSAStartup() gets called. */
295 soup_address_get_type ();
301 set_nonblocking (SoupSocketPrivate *priv)
309 if (priv->sockfd == -1)
313 flags = fcntl (priv->sockfd, F_GETFL, 0);
315 if (priv->non_blocking)
318 flags &= ~O_NONBLOCK;
319 fcntl (priv->sockfd, F_SETFL, flags);
322 val = priv->non_blocking ? 1 : 0;
323 ioctlsocket (priv->sockfd, FIONBIO, &val);
328 set_fdflags (SoupSocketPrivate *priv)
331 struct timeval timeout;
336 if (priv->sockfd == -1)
339 set_nonblocking (priv);
342 flags = fcntl (priv->sockfd, F_GETFD, 0);
345 fcntl (priv->sockfd, F_SETFD, flags);
350 setsockopt (priv->sockfd, IPPROTO_TCP,
351 TCP_NODELAY, (void *) &opt, sizeof (opt));
352 setsockopt (priv->sockfd, SOL_SOCKET,
353 SO_REUSEADDR, (void *) &opt, sizeof (opt));
355 timeout.tv_sec = priv->timeout;
357 setsockopt (priv->sockfd, SOL_SOCKET,
358 SO_RCVTIMEO, (void *) &timeout, sizeof (timeout));
360 timeout.tv_sec = priv->timeout;
362 setsockopt (priv->sockfd, SOL_SOCKET,
363 SO_SNDTIMEO, (void *) &timeout, sizeof (timeout));
367 g_io_channel_unix_new (priv->sockfd);
370 g_io_channel_win32_new_socket (priv->sockfd);
372 g_io_channel_set_close_on_unref (priv->iochannel, TRUE);
373 g_io_channel_set_encoding (priv->iochannel, NULL, NULL);
374 g_io_channel_set_buffered (priv->iochannel, FALSE);
378 set_property (GObject *object, guint prop_id,
379 const GValue *value, GParamSpec *pspec)
381 SoupSocketPrivate *priv = SOUP_SOCKET_GET_PRIVATE (object);
384 case PROP_LOCAL_ADDRESS:
385 priv->local_addr = (SoupAddress *)g_value_dup_object (value);
387 case PROP_REMOTE_ADDRESS:
388 priv->remote_addr = (SoupAddress *)g_value_dup_object (value);
390 case PROP_NON_BLOCKING:
391 priv->non_blocking = g_value_get_boolean (value);
392 set_nonblocking (priv);
394 case PROP_SSL_CREDENTIALS:
395 priv->ssl_creds = g_value_get_pointer (value);
397 case PROP_ASYNC_CONTEXT:
398 priv->async_context = g_value_get_pointer (value);
399 if (priv->async_context)
400 g_main_context_ref (priv->async_context);
403 priv->timeout = g_value_get_uint (value);
406 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
412 get_property (GObject *object, guint prop_id,
413 GValue *value, GParamSpec *pspec)
415 SoupSocketPrivate *priv = SOUP_SOCKET_GET_PRIVATE (object);
418 case PROP_LOCAL_ADDRESS:
419 g_value_set_object (value, soup_socket_get_local_address (SOUP_SOCKET (object)));
421 case PROP_REMOTE_ADDRESS:
422 g_value_set_object (value, soup_socket_get_remote_address (SOUP_SOCKET (object)));
424 case PROP_NON_BLOCKING:
425 g_value_set_boolean (value, priv->non_blocking);
428 g_value_set_boolean (value, priv->is_server);
430 case PROP_SSL_CREDENTIALS:
431 g_value_set_pointer (value, priv->ssl_creds);
433 case PROP_ASYNC_CONTEXT:
434 g_value_set_pointer (value, priv->async_context ? g_main_context_ref (priv->async_context) : NULL);
437 g_value_set_uint (value, priv->timeout);
440 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
448 * @optname1: name of first property to set (or %NULL)
449 * @...: value of @optname1, followed by additional property/value pairs
451 * Creates a new (disconnected) socket
453 * Return value: the new socket
456 soup_socket_new (const char *optname1, ...)
461 va_start (ap, optname1);
462 sock = (SoupSocket *)g_object_new_valist (SOUP_TYPE_SOCKET,
471 GCancellable *cancellable;
473 SoupSocketCallback callback;
475 } SoupSocketAsyncConnectData;
478 idle_connect_result (gpointer user_data)
480 SoupSocketAsyncConnectData *sacd = user_data;
481 SoupSocketPrivate *priv = SOUP_SOCKET_GET_PRIVATE (sacd->sock);
484 priv->watch_src = NULL;
486 g_signal_handler_disconnect (sacd->cancellable, sacd->cancel_id);
488 if (priv->sockfd == -1) {
489 if (g_cancellable_is_cancelled (sacd->cancellable))
490 status = SOUP_STATUS_CANCELLED;
492 status = SOUP_STATUS_CANT_CONNECT;
494 status = SOUP_STATUS_OK;
496 sacd->callback (sacd->sock, status, sacd->user_data);
497 g_slice_free (SoupSocketAsyncConnectData, sacd);
502 connect_watch (GIOChannel* iochannel, GIOCondition condition, gpointer data)
504 SoupSocketAsyncConnectData *sacd = data;
505 SoupSocketPrivate *priv = SOUP_SOCKET_GET_PRIVATE (sacd->sock);
507 int len = sizeof (error);
509 /* Remove the watch now in case we don't return immediately */
510 g_source_destroy (priv->watch_src);
511 priv->watch_src = NULL;
513 if ((condition & ~(G_IO_IN | G_IO_OUT)) ||
514 (getsockopt (priv->sockfd, SOL_SOCKET, SO_ERROR,
515 (void *)&error, (void *)&len) != 0) ||
517 disconnect_internal (priv);
519 return idle_connect_result (sacd);
523 got_address (SoupAddress *addr, guint status, gpointer user_data)
525 SoupSocketAsyncConnectData *sacd = user_data;
527 if (!SOUP_STATUS_IS_SUCCESSFUL (status)) {
528 sacd->callback (sacd->sock, status, sacd->user_data);
529 g_slice_free (SoupSocketAsyncConnectData, sacd);
533 soup_socket_connect_async (sacd->sock, sacd->cancellable,
534 sacd->callback, sacd->user_data);
535 g_slice_free (SoupSocketAsyncConnectData, sacd);
539 async_cancel (GCancellable *cancellable, gpointer user_data)
541 SoupSocketAsyncConnectData *sacd = user_data;
542 SoupSocketPrivate *priv = SOUP_SOCKET_GET_PRIVATE (sacd->sock);
545 g_source_destroy (priv->watch_src);
546 disconnect_internal (priv);
547 priv->watch_src = soup_add_idle (priv->async_context,
548 idle_connect_result, sacd);
552 socket_connect_internal (SoupSocket *sock)
554 SoupSocketPrivate *priv = SOUP_SOCKET_GET_PRIVATE (sock);
558 sa = soup_address_get_sockaddr (priv->remote_addr, &len);
560 return SOUP_STATUS_CANT_RESOLVE;
562 priv->sockfd = socket (sa->sa_family, SOCK_STREAM, 0);
563 if (SOUP_IS_INVALID_SOCKET (priv->sockfd))
564 return SOUP_STATUS_CANT_CONNECT;
567 status = connect (priv->sockfd, sa, len);
569 if (SOUP_IS_SOCKET_ERROR (status)) {
570 if (SOUP_IS_CONNECT_STATUS_INPROGRESS ())
571 return SOUP_STATUS_CONTINUE;
573 disconnect_internal (priv);
574 return SOUP_STATUS_CANT_CONNECT;
576 return SOUP_STATUS_OK;
580 * SoupSocketCallback:
581 * @sock: the #SoupSocket
582 * @status: an HTTP status code indicating success or failure
583 * @user_data: the data passed to soup_socket_connect_async()
585 * The callback function passed to soup_socket_connect_async().
589 * soup_socket_connect_async:
590 * @sock: a client #SoupSocket (which must not already be connected)
591 * @cancellable: a #GCancellable, or %NULL
592 * @callback: callback to call after connecting
593 * @user_data: data to pass to @callback
595 * Begins asynchronously connecting to @sock's remote address. The
596 * socket will call @callback when it succeeds or fails (but not
597 * before returning from this function).
599 * If @cancellable is non-%NULL, it can be used to cancel the
600 * connection. @callback will still be invoked in this case, with a
601 * status of %SOUP_STATUS_CANCELLED.
604 soup_socket_connect_async (SoupSocket *sock, GCancellable *cancellable,
605 SoupSocketCallback callback, gpointer user_data)
607 SoupSocketPrivate *priv;
608 SoupSocketAsyncConnectData *sacd;
611 g_return_if_fail (SOUP_IS_SOCKET (sock));
612 priv = SOUP_SOCKET_GET_PRIVATE (sock);
613 g_return_if_fail (priv->remote_addr != NULL);
615 sacd = g_slice_new0 (SoupSocketAsyncConnectData);
617 sacd->cancellable = cancellable;
618 sacd->callback = callback;
619 sacd->user_data = user_data;
621 if (!soup_address_get_sockaddr (priv->remote_addr, NULL)) {
622 soup_address_resolve_async (priv->remote_addr,
629 status = socket_connect_internal (sock);
630 if (status == SOUP_STATUS_CONTINUE) {
631 /* Wait for connect to succeed or fail */
633 soup_add_io_watch (priv->async_context,
636 G_IO_PRI | G_IO_ERR |
637 G_IO_HUP | G_IO_NVAL,
638 connect_watch, sacd);
641 g_signal_connect (cancellable, "cancelled",
642 G_CALLBACK (async_cancel),
646 priv->watch_src = soup_add_idle (priv->async_context,
647 idle_connect_result, sacd);
652 sync_cancel (GCancellable *cancellable, gpointer sock)
654 SoupSocketPrivate *priv = SOUP_SOCKET_GET_PRIVATE (sock);
656 shutdown (priv->sockfd, SHUT_RDWR);
660 * soup_socket_connect_sync:
661 * @sock: a client #SoupSocket (which must not already be connected)
662 * @cancellable: a #GCancellable, or %NULL
664 * Attempt to synchronously connect @sock to its remote address.
666 * If @cancellable is non-%NULL, it can be used to cancel the
667 * connection, in which case soup_socket_connect_sync() will return
668 * %SOUP_STATUS_CANCELLED.
670 * Return value: a success or failure code.
673 soup_socket_connect_sync (SoupSocket *sock, GCancellable *cancellable)
675 SoupSocketPrivate *priv;
676 guint status, cancel_id;
678 g_return_val_if_fail (SOUP_IS_SOCKET (sock), SOUP_STATUS_MALFORMED);
679 priv = SOUP_SOCKET_GET_PRIVATE (sock);
680 g_return_val_if_fail (!priv->is_server, SOUP_STATUS_MALFORMED);
681 g_return_val_if_fail (priv->sockfd == -1, SOUP_STATUS_MALFORMED);
682 g_return_val_if_fail (priv->remote_addr != NULL, SOUP_STATUS_MALFORMED);
684 if (!soup_address_get_sockaddr (priv->remote_addr, NULL)) {
685 status = soup_address_resolve_sync (priv->remote_addr,
687 if (!SOUP_STATUS_IS_SUCCESSFUL (status))
692 cancel_id = g_signal_connect (cancellable, "cancelled",
693 G_CALLBACK (sync_cancel), sock);
696 status = socket_connect_internal (sock);
699 if (status != SOUP_STATUS_OK &&
700 g_cancellable_is_cancelled (cancellable)) {
701 status = SOUP_STATUS_CANCELLED;
702 disconnect_internal (priv);
704 g_signal_handler_disconnect (cancellable, cancel_id);
711 listen_watch (GIOChannel* iochannel, GIOCondition condition, gpointer data)
713 SoupSocket *sock = data, *new;
714 SoupSocketPrivate *priv = SOUP_SOCKET_GET_PRIVATE (sock), *new_priv;
715 struct soup_sockaddr_max sa;
718 if (condition & (G_IO_HUP | G_IO_ERR)) {
719 g_source_destroy (priv->watch_src);
720 priv->watch_src = NULL;
724 sa_len = sizeof (sa);
725 sockfd = accept (priv->sockfd, (struct sockaddr *)&sa, (void *)&sa_len);
726 if (SOUP_IS_INVALID_SOCKET (sockfd))
729 new = g_object_new (SOUP_TYPE_SOCKET, NULL);
730 new_priv = SOUP_SOCKET_GET_PRIVATE (new);
731 new_priv->sockfd = sockfd;
732 if (priv->async_context)
733 new_priv->async_context = g_main_context_ref (priv->async_context);
734 new_priv->non_blocking = priv->non_blocking;
735 new_priv->is_server = TRUE;
736 new_priv->ssl_creds = priv->ssl_creds;
737 set_fdflags (new_priv);
739 new_priv->remote_addr = soup_address_new_from_sockaddr ((struct sockaddr *)&sa, sa_len);
741 if (new_priv->ssl_creds) {
742 if (!soup_socket_start_ssl (new, NULL)) {
743 g_object_unref (new);
748 g_signal_emit (sock, signals[NEW_CONNECTION], 0, new);
749 g_object_unref (new);
755 * soup_socket_listen:
756 * @sock: a server #SoupSocket (which must not already be connected or
759 * Makes @sock start listening on its local address. When connections
760 * come in, @sock will emit %new_connection.
762 * Return value: whether or not @sock is now listening.
765 soup_socket_listen (SoupSocket *sock)
768 SoupSocketPrivate *priv;
772 g_return_val_if_fail (SOUP_IS_SOCKET (sock), FALSE);
773 priv = SOUP_SOCKET_GET_PRIVATE (sock);
774 g_return_val_if_fail (priv->sockfd == -1, FALSE);
775 g_return_val_if_fail (priv->local_addr != NULL, FALSE);
777 priv->is_server = TRUE;
779 /* @local_addr may have its port set to 0. So we intentionally
780 * don't store it in priv->local_addr, so that if the
781 * caller calls soup_socket_get_local_address() later, we'll
782 * have to make a new addr by calling getsockname(), which
783 * will have the right port number.
785 sa = soup_address_get_sockaddr (priv->local_addr, &sa_len);
786 g_return_val_if_fail (sa != NULL, FALSE);
788 priv->sockfd = socket (sa->sa_family, SOCK_STREAM, 0);
789 if (SOUP_IS_INVALID_SOCKET (priv->sockfd))
794 if (bind (priv->sockfd, sa, sa_len) != 0)
796 /* Force local_addr to be re-resolved now */
797 g_object_unref (priv->local_addr);
798 priv->local_addr = NULL;
801 if (listen (priv->sockfd, 10) != 0)
804 priv->watch_src = soup_add_io_watch (priv->async_context,
806 G_IO_IN | G_IO_ERR | G_IO_HUP,
812 disconnect_internal (priv);
818 * soup_socket_start_ssl:
820 * @cancellable: a #GCancellable
822 * Starts using SSL on @socket.
824 * Return value: success or failure
827 soup_socket_start_ssl (SoupSocket *sock, GCancellable *cancellable)
829 SoupSocketPrivate *priv = SOUP_SOCKET_GET_PRIVATE (sock);
831 return soup_socket_start_proxy_ssl (sock, soup_address_get_name (priv->remote_addr), cancellable);
835 * soup_socket_start_proxy_ssl:
837 * @ssl_host: hostname of the SSL server
838 * @cancellable: a #GCancellable
840 * Starts using SSL on @socket, expecting to find a host named
843 * Return value: success or failure
846 soup_socket_start_proxy_ssl (SoupSocket *sock, const char *ssl_host,
847 GCancellable *cancellable)
849 SoupSocketPrivate *priv = SOUP_SOCKET_GET_PRIVATE (sock);
850 GIOChannel *ssl_chan;
851 GIOChannel *real_chan;
853 real_chan = priv->iochannel;
854 ssl_chan = soup_ssl_wrap_iochannel (
855 real_chan, priv->is_server ?
856 SOUP_SSL_TYPE_SERVER : SOUP_SSL_TYPE_CLIENT,
857 ssl_host, priv->ssl_creds);
862 priv->iochannel = ssl_chan;
863 g_io_channel_unref (real_chan);
869 * soup_socket_is_ssl:
870 * @sock: a #SoupSocket
872 * Tests if @sock is set up to do SSL. Note that this simply means
873 * that the %SOUP_SOCKET_SSL_CREDENTIALS property has been set; it
874 * does not mean that soup_socket_start_ssl() has been called.
876 * Return value: %TRUE if @sock has SSL credentials set
879 soup_socket_is_ssl (SoupSocket *sock)
881 SoupSocketPrivate *priv = SOUP_SOCKET_GET_PRIVATE (sock);
883 return priv->ssl_creds != NULL;
887 * soup_socket_disconnect:
888 * @sock: a #SoupSocket
890 * Disconnects @sock. Any further read or write attempts on it will
894 soup_socket_disconnect (SoupSocket *sock)
896 SoupSocketPrivate *priv;
897 gboolean already_disconnected = FALSE;
899 g_return_if_fail (SOUP_IS_SOCKET (sock));
900 priv = SOUP_SOCKET_GET_PRIVATE (sock);
902 if (g_mutex_trylock (priv->iolock)) {
904 disconnect_internal (priv);
906 already_disconnected = TRUE;
907 g_mutex_unlock (priv->iolock);
911 /* Another thread is currently doing IO, so
912 * we can't close the iochannel. So just shutdown
913 * the file descriptor to force the I/O to fail.
914 * (It will actually be closed when the socket is
917 sockfd = priv->sockfd;
921 already_disconnected = TRUE;
923 shutdown (sockfd, SHUT_RDWR);
926 if (already_disconnected)
929 /* Give all readers a chance to notice the connection close */
930 g_signal_emit (sock, signals[READABLE], 0);
932 /* FIXME: can't disconnect until all data is read */
934 /* Then let everyone know we're disconnected */
935 g_signal_emit (sock, signals[DISCONNECTED], 0);
939 * soup_socket_is_connected:
940 * @sock: a #SoupSocket
942 * Tests if @sock is connected to another host
944 * Return value: %TRUE or %FALSE.
947 soup_socket_is_connected (SoupSocket *sock)
949 SoupSocketPrivate *priv;
951 g_return_val_if_fail (SOUP_IS_SOCKET (sock), FALSE);
952 priv = SOUP_SOCKET_GET_PRIVATE (sock);
954 return priv->iochannel != NULL;
958 * soup_socket_get_local_address:
959 * @sock: a #SoupSocket
961 * Returns the #SoupAddress corresponding to the local end of @sock.
963 * Return value: the #SoupAddress
966 soup_socket_get_local_address (SoupSocket *sock)
968 SoupSocketPrivate *priv;
970 g_return_val_if_fail (SOUP_IS_SOCKET (sock), NULL);
971 priv = SOUP_SOCKET_GET_PRIVATE (sock);
973 g_mutex_lock (priv->addrlock);
974 if (!priv->local_addr) {
975 struct soup_sockaddr_max bound_sa;
978 sa_len = sizeof (bound_sa);
979 getsockname (priv->sockfd, (struct sockaddr *)&bound_sa, (void *)&sa_len);
980 priv->local_addr = soup_address_new_from_sockaddr ((struct sockaddr *)&bound_sa, sa_len);
982 g_mutex_unlock (priv->addrlock);
984 return priv->local_addr;
988 * soup_socket_get_remote_address:
989 * @sock: a #SoupSocket
991 * Returns the #SoupAddress corresponding to the remote end of @sock.
993 * Return value: the #SoupAddress
996 soup_socket_get_remote_address (SoupSocket *sock)
998 SoupSocketPrivate *priv;
1000 g_return_val_if_fail (SOUP_IS_SOCKET (sock), NULL);
1001 priv = SOUP_SOCKET_GET_PRIVATE (sock);
1003 g_mutex_lock (priv->addrlock);
1004 if (!priv->remote_addr) {
1005 struct soup_sockaddr_max bound_sa;
1008 sa_len = sizeof (bound_sa);
1009 getpeername (priv->sockfd, (struct sockaddr *)&bound_sa, (void *)&sa_len);
1010 priv->remote_addr = soup_address_new_from_sockaddr ((struct sockaddr *)&bound_sa, sa_len);
1012 g_mutex_unlock (priv->addrlock);
1014 return priv->remote_addr;
1021 socket_read_watch (GIOChannel *chan, GIOCondition cond, gpointer user_data)
1023 SoupSocket *sock = user_data;
1024 SoupSocketPrivate *priv = SOUP_SOCKET_GET_PRIVATE (sock);
1026 priv->read_src = NULL;
1028 if (cond & (G_IO_ERR | G_IO_HUP))
1029 soup_socket_disconnect (sock);
1031 g_signal_emit (sock, signals[READABLE], 0);
1036 static SoupSocketIOStatus
1037 read_from_network (SoupSocket *sock, gpointer buffer, gsize len,
1038 gsize *nread, GError **error)
1040 SoupSocketPrivate *priv = SOUP_SOCKET_GET_PRIVATE (sock);
1042 GIOCondition cond = G_IO_IN;
1043 GError *my_err = NULL;
1047 if (!priv->iochannel)
1048 return SOUP_SOCKET_EOF;
1050 status = g_io_channel_read_chars (priv->iochannel,
1051 buffer, len, nread, &my_err);
1053 if (my_err->domain == SOUP_SSL_ERROR &&
1054 my_err->code == SOUP_SSL_ERROR_HANDSHAKE_NEEDS_WRITE)
1056 g_propagate_error (error, my_err);
1060 case G_IO_STATUS_NORMAL:
1061 case G_IO_STATUS_AGAIN:
1063 g_clear_error (error);
1064 return SOUP_SOCKET_OK;
1067 /* If the socket is sync and we get EAGAIN, then it is
1068 * a socket timeout and should be treated as an error
1071 if (!priv->non_blocking)
1072 return SOUP_SOCKET_ERROR;
1074 if (!priv->read_src) {
1076 soup_add_io_watch (priv->async_context,
1078 cond | G_IO_HUP | G_IO_ERR,
1079 socket_read_watch, sock);
1081 g_clear_error (error);
1082 return SOUP_SOCKET_WOULD_BLOCK;
1084 case G_IO_STATUS_EOF:
1085 g_clear_error (error);
1086 return SOUP_SOCKET_EOF;
1089 return SOUP_SOCKET_ERROR;
1093 static SoupSocketIOStatus
1094 read_from_buf (SoupSocket *sock, gpointer buffer, gsize len, gsize *nread)
1096 SoupSocketPrivate *priv = SOUP_SOCKET_GET_PRIVATE (sock);
1097 GByteArray *read_buf = priv->read_buf;
1099 *nread = MIN (read_buf->len, len);
1100 memcpy (buffer, read_buf->data, *nread);
1102 if (*nread == read_buf->len) {
1103 g_byte_array_free (read_buf, TRUE);
1104 priv->read_buf = NULL;
1106 memmove (read_buf->data, read_buf->data + *nread,
1107 read_buf->len - *nread);
1108 g_byte_array_set_size (read_buf, read_buf->len - *nread);
1111 return SOUP_SOCKET_OK;
1115 * SoupSocketIOStatus:
1116 * @SOUP_SOCKET_OK: Success
1117 * @SOUP_SOCKET_WOULD_BLOCK: Cannot read/write any more at this time
1118 * @SOUP_SOCKET_EOF: End of file
1119 * @SOUP_SOCKET_ERROR: Other error
1121 * Return value from the #SoupSocket IO methods.
1127 * @buffer: buffer to read into
1128 * @len: size of @buffer in bytes
1129 * @nread: on return, the number of bytes read into @buffer
1130 * @cancellable: a #GCancellable, or %NULL
1131 * @error: error pointer
1133 * Attempts to read up to @len bytes from @sock into @buffer. If some
1134 * data is successfully read, soup_socket_read() will return
1135 * %SOUP_SOCKET_OK, and *@nread will contain the number of bytes
1138 * If @sock is non-blocking, and no data is available, the return
1139 * value will be %SOUP_SOCKET_WOULD_BLOCK. In this case, the caller
1140 * can connect to the %readable signal to know when there is more data
1141 * to read. (NB: You MUST read all available data off the socket
1142 * first. The %readable signal will only be emitted after
1143 * soup_socket_read() has returned %SOUP_SOCKET_WOULD_BLOCK.)
1145 * Return value: a #SoupSocketIOStatus, as described above (or
1146 * %SOUP_SOCKET_EOF if the socket is no longer connected, or
1147 * %SOUP_SOCKET_ERROR on any other error, in which case @error will
1151 soup_socket_read (SoupSocket *sock, gpointer buffer, gsize len,
1152 gsize *nread, GCancellable *cancellable, GError **error)
1154 SoupSocketPrivate *priv;
1155 SoupSocketIOStatus status;
1157 g_return_val_if_fail (SOUP_IS_SOCKET (sock), SOUP_SOCKET_ERROR);
1158 g_return_val_if_fail (nread != NULL, SOUP_SOCKET_ERROR);
1160 priv = SOUP_SOCKET_GET_PRIVATE (sock);
1162 g_mutex_lock (priv->iolock);
1164 status = read_from_buf (sock, buffer, len, nread);
1166 status = read_from_network (sock, buffer, len, nread, error);
1167 g_mutex_unlock (priv->iolock);
1173 * soup_socket_read_until:
1175 * @buffer: buffer to read into
1176 * @len: size of @buffer in bytes
1177 * @boundary: boundary to read until
1178 * @boundary_len: length of @boundary in bytes
1179 * @nread: on return, the number of bytes read into @buffer
1180 * @got_boundary: on return, whether or not the data in @buffer
1181 * ends with the boundary string
1182 * @cancellable: a #GCancellable, or %NULL
1183 * @error: error pointer
1185 * Like soup_socket_read(), but reads no further than the first
1186 * occurrence of @boundary. (If the boundary is found, it will be
1187 * included in the returned data, and *@got_boundary will be set to
1188 * %TRUE.) Any data after the boundary will returned in future reads.
1190 * Return value: as for soup_socket_read()
1193 soup_socket_read_until (SoupSocket *sock, gpointer buffer, gsize len,
1194 gconstpointer boundary, gsize boundary_len,
1195 gsize *nread, gboolean *got_boundary,
1196 GCancellable *cancellable, GError **error)
1198 SoupSocketPrivate *priv;
1199 SoupSocketIOStatus status;
1200 GByteArray *read_buf;
1201 guint match_len, prev_len;
1204 g_return_val_if_fail (SOUP_IS_SOCKET (sock), SOUP_SOCKET_ERROR);
1205 g_return_val_if_fail (nread != NULL, SOUP_SOCKET_ERROR);
1206 g_return_val_if_fail (len >= boundary_len, SOUP_SOCKET_ERROR);
1208 priv = SOUP_SOCKET_GET_PRIVATE (sock);
1210 g_mutex_lock (priv->iolock);
1212 *got_boundary = FALSE;
1214 if (!priv->read_buf)
1215 priv->read_buf = g_byte_array_new ();
1216 read_buf = priv->read_buf;
1218 if (read_buf->len < boundary_len) {
1219 prev_len = read_buf->len;
1220 g_byte_array_set_size (read_buf, len);
1221 status = read_from_network (sock,
1222 read_buf->data + prev_len,
1223 len - prev_len, nread, error);
1224 read_buf->len = prev_len + *nread;
1226 if (status != SOUP_SOCKET_OK) {
1227 g_mutex_unlock (priv->iolock);
1232 /* Scan for the boundary */
1233 end = read_buf->data + read_buf->len;
1234 for (p = read_buf->data; p <= end - boundary_len; p++) {
1235 if (!memcmp (p, boundary, boundary_len)) {
1237 *got_boundary = TRUE;
1242 /* Return everything up to 'p' (which is either just after the
1243 * boundary, or @boundary_len - 1 bytes before the end of the
1246 match_len = p - read_buf->data;
1247 status = read_from_buf (sock, buffer, MIN (len, match_len), nread);
1249 g_mutex_unlock (priv->iolock);
1254 socket_write_watch (GIOChannel *chan, GIOCondition cond, gpointer user_data)
1256 SoupSocket *sock = user_data;
1257 SoupSocketPrivate *priv = SOUP_SOCKET_GET_PRIVATE (sock);
1259 priv->write_src = NULL;
1261 if (cond & (G_IO_ERR | G_IO_HUP))
1262 soup_socket_disconnect (sock);
1264 g_signal_emit (sock, signals[WRITABLE], 0);
1270 * soup_socket_write:
1272 * @buffer: data to write
1273 * @len: size of @buffer, in bytes
1274 * @nwrote: on return, number of bytes written
1275 * @cancellable: a #GCancellable, or %NULL
1276 * @error: error pointer
1278 * Attempts to write @len bytes from @buffer to @sock. If some data is
1279 * successfully written, the resturn status will be
1280 * %SOUP_SOCKET_OK, and *@nwrote will contain the number of bytes
1283 * If @sock is non-blocking, and no data could be written right away,
1284 * the return value will be %SOUP_SOCKET_WOULD_BLOCK. In this case,
1285 * the caller can connect to the %writable signal to know when more
1286 * data can be written. (NB: %writable is only emitted after a
1287 * %SOUP_SOCKET_WOULD_BLOCK.)
1289 * Return value: a #SoupSocketIOStatus, as described above (or
1290 * %SOUP_SOCKET_EOF or %SOUP_SOCKET_ERROR. @error will be set if the
1291 * return value is %SOUP_SOCKET_ERROR.)
1294 soup_socket_write (SoupSocket *sock, gconstpointer buffer,
1295 gsize len, gsize *nwrote,
1296 GCancellable *cancellable, GError **error)
1298 SoupSocketPrivate *priv;
1301 gpointer pipe_handler;
1303 GIOCondition cond = G_IO_OUT;
1304 GError *my_err = NULL;
1306 g_return_val_if_fail (SOUP_IS_SOCKET (sock), SOUP_SOCKET_ERROR);
1307 g_return_val_if_fail (nwrote != NULL, SOUP_SOCKET_ERROR);
1309 priv = SOUP_SOCKET_GET_PRIVATE (sock);
1311 g_mutex_lock (priv->iolock);
1313 if (!priv->iochannel) {
1314 g_mutex_unlock (priv->iolock);
1315 return SOUP_SOCKET_EOF;
1317 if (priv->write_src) {
1318 g_mutex_unlock (priv->iolock);
1319 return SOUP_SOCKET_WOULD_BLOCK;
1323 pipe_handler = signal (SIGPIPE, SIG_IGN);
1325 status = g_io_channel_write_chars (priv->iochannel,
1326 buffer, len, nwrote, &my_err);
1328 signal (SIGPIPE, pipe_handler);
1331 if (my_err->domain == SOUP_SSL_ERROR &&
1332 my_err->code == SOUP_SSL_ERROR_HANDSHAKE_NEEDS_READ)
1334 g_propagate_error (error, my_err);
1337 /* If the socket is sync and we get EAGAIN, then it is a
1338 * socket timeout and should be treated as an error condition.
1340 if (!priv->non_blocking && status == G_IO_STATUS_AGAIN) {
1341 g_mutex_unlock (priv->iolock);
1342 return SOUP_SOCKET_ERROR;
1345 if (status != G_IO_STATUS_NORMAL && status != G_IO_STATUS_AGAIN) {
1346 g_mutex_unlock (priv->iolock);
1347 return SOUP_SOCKET_ERROR;
1350 g_clear_error (error);
1353 g_mutex_unlock (priv->iolock);
1354 return SOUP_SOCKET_OK;
1358 soup_add_io_watch (priv->async_context,
1360 cond | G_IO_HUP | G_IO_ERR,
1361 socket_write_watch, sock);
1362 g_mutex_unlock (priv->iolock);
1363 return SOUP_SOCKET_WOULD_BLOCK;