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>
27 G_DEFINE_TYPE (SoupSocket, soup_socket, G_TYPE_OBJECT)
38 static guint signals[LAST_SIGNAL] = { 0 };
57 SoupAddress *local_addr, *remote_addr;
58 GIOChannel *iochannel;
67 GMainContext *async_context;
69 GSource *read_src, *write_src;
72 GMutex *iolock, *addrlock;
75 #define SOUP_SOCKET_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), SOUP_TYPE_SOCKET, SoupSocketPrivate))
78 #define soup_sockaddr_max sockaddr_in6
80 #define soup_sockaddr_max sockaddr_in
83 static void set_property (GObject *object, guint prop_id,
84 const GValue *value, GParamSpec *pspec);
85 static void get_property (GObject *object, guint prop_id,
86 GValue *value, GParamSpec *pspec);
89 #define SOUP_CLOSE_SOCKET(socket) closesocket (socket)
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)
94 #define SOUP_CLOSE_SOCKET(socket) close (socket)
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 = priv->nodelay = TRUE;
107 priv->reuseaddr = TRUE;
108 priv->cloexec = FALSE;
109 priv->addrlock = g_mutex_new ();
110 priv->iolock = g_mutex_new ();
115 disconnect_internal (SoupSocketPrivate *priv)
117 g_io_channel_unref (priv->iochannel);
118 priv->iochannel = NULL;
121 if (priv->read_src) {
122 g_source_destroy (priv->read_src);
123 priv->read_src = NULL;
125 if (priv->write_src) {
126 g_source_destroy (priv->write_src);
127 priv->write_src = NULL;
132 finalize (GObject *object)
134 SoupSocketPrivate *priv = SOUP_SOCKET_GET_PRIVATE (object);
137 disconnect_internal (priv);
139 if (priv->local_addr)
140 g_object_unref (priv->local_addr);
141 if (priv->remote_addr)
142 g_object_unref (priv->remote_addr);
145 g_source_destroy (priv->watch_src);
146 if (priv->async_context)
147 g_main_context_unref (priv->async_context);
150 g_byte_array_free (priv->read_buf, TRUE);
152 g_mutex_free (priv->addrlock);
153 g_mutex_free (priv->iolock);
155 G_OBJECT_CLASS (soup_socket_parent_class)->finalize (object);
159 soup_socket_class_init (SoupSocketClass *socket_class)
161 GObjectClass *object_class = G_OBJECT_CLASS (socket_class);
163 g_type_class_add_private (socket_class, sizeof (SoupSocketPrivate));
165 /* virtual method override */
166 object_class->finalize = finalize;
167 object_class->set_property = set_property;
168 object_class->get_property = get_property;
173 * SoupSocket::connect-result:
175 * @status: the status
177 * Emitted when a connection attempt succeeds or fails. This
178 * is used internally by soup_socket_client_new_async().
180 signals[CONNECT_RESULT] =
181 g_signal_new ("connect_result",
182 G_OBJECT_CLASS_TYPE (object_class),
184 G_STRUCT_OFFSET (SoupSocketClass, connect_result),
186 soup_marshal_NONE__INT,
191 * SoupSocket::readable:
194 * Emitted when an async socket is readable. See
195 * soup_socket_read() and soup_socket_read_until().
198 g_signal_new ("readable",
199 G_OBJECT_CLASS_TYPE (object_class),
201 G_STRUCT_OFFSET (SoupSocketClass, readable),
203 soup_marshal_NONE__NONE,
207 * SoupSocket::writable:
210 * Emitted when an async socket is writable. See
211 * soup_socket_write().
214 g_signal_new ("writable",
215 G_OBJECT_CLASS_TYPE (object_class),
217 G_STRUCT_OFFSET (SoupSocketClass, writable),
219 soup_marshal_NONE__NONE,
223 * SoupSocket::disconnected:
226 * Emitted when the socket is disconnected, for whatever
229 signals[DISCONNECTED] =
230 g_signal_new ("disconnected",
231 G_OBJECT_CLASS_TYPE (object_class),
233 G_STRUCT_OFFSET (SoupSocketClass, disconnected),
235 soup_marshal_NONE__NONE,
239 * SoupSocket::new-connection:
241 * @new: the new socket
243 * Emitted when a listening socket (set up with
244 * soup_socket_listen() or soup_socket_server_new()) receives a
247 signals[NEW_CONNECTION] =
248 g_signal_new ("new_connection",
249 G_OBJECT_CLASS_TYPE (object_class),
251 G_STRUCT_OFFSET (SoupSocketClass, new_connection),
253 soup_marshal_NONE__OBJECT,
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_NODELAY,
267 g_param_spec_boolean (SOUP_SOCKET_FLAG_NODELAY,
269 "Whether or not the socket uses TCP NODELAY",
272 g_object_class_install_property (
273 object_class, PROP_REUSEADDR,
274 g_param_spec_boolean (SOUP_SOCKET_FLAG_REUSEADDR,
276 "Whether or not the socket uses the TCP REUSEADDR flag",
279 g_object_class_install_property (
280 object_class, PROP_CLOEXEC,
281 g_param_spec_boolean (SOUP_SOCKET_FLAG_CLOEXEC,
283 "Whether or not the socket will be closed automatically on exec()",
286 g_object_class_install_property (
287 object_class, PROP_IS_SERVER,
288 g_param_spec_boolean (SOUP_SOCKET_IS_SERVER,
290 "Whether or not the socket is a server socket",
293 g_object_class_install_property (
294 object_class, PROP_SSL_CREDENTIALS,
295 g_param_spec_pointer (SOUP_SOCKET_SSL_CREDENTIALS,
297 "SSL credential information, passed from the session to the SSL implementation",
299 g_object_class_install_property (
300 object_class, PROP_ASYNC_CONTEXT,
301 g_param_spec_pointer (SOUP_SOCKET_ASYNC_CONTEXT,
302 "Async GMainContext",
303 "The GMainContext to dispatch this socket's async I/O in",
304 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
306 g_object_class_install_property (
307 object_class, PROP_TIMEOUT,
308 g_param_spec_uint (SOUP_SOCKET_TIMEOUT,
310 "Value in seconds to timeout a blocking I/O",
315 /* Make sure WSAStartup() gets called. */
316 soup_address_get_type ();
322 update_fdflags (SoupSocketPrivate *priv)
325 struct timeval timeout;
330 if (priv->sockfd == -1)
334 flags = fcntl (priv->sockfd, F_GETFL, 0);
336 if (priv->non_blocking)
339 flags &= ~O_NONBLOCK;
340 fcntl (priv->sockfd, F_SETFL, flags);
342 flags = fcntl (priv->sockfd, F_GETFD, 0);
347 flags &= ~FD_CLOEXEC;
348 fcntl (priv->sockfd, F_SETFD, flags);
352 if (priv->non_blocking) {
354 ioctlsocket (priv->sockfd, FIONBIO, &val);
357 ioctlsocket (priv->sockfd, FIONBIO, &val);
361 opt = (priv->nodelay != 0);
362 setsockopt (priv->sockfd, IPPROTO_TCP,
363 TCP_NODELAY, (void *) &opt, sizeof (opt));
365 timeout.tv_sec = priv->timeout;
367 setsockopt (priv->sockfd, SOL_SOCKET,
368 SO_RCVTIMEO, (void *) &timeout, sizeof (timeout));
370 timeout.tv_sec = priv->timeout;
372 setsockopt (priv->sockfd, SOL_SOCKET,
373 SO_SNDTIMEO, (void *) &timeout, sizeof (timeout));
375 opt = (priv->reuseaddr != 0);
376 setsockopt (priv->sockfd, SOL_SOCKET,
377 SO_REUSEADDR, (void *) &opt, sizeof (opt));
381 set_property (GObject *object, guint prop_id,
382 const GValue *value, GParamSpec *pspec)
384 SoupSocketPrivate *priv = SOUP_SOCKET_GET_PRIVATE (object);
387 case PROP_NON_BLOCKING:
388 priv->non_blocking = g_value_get_boolean (value);
389 update_fdflags (priv);
392 priv->nodelay = g_value_get_boolean (value);
393 update_fdflags (priv);
396 priv->reuseaddr = g_value_get_boolean (value);
397 update_fdflags (priv);
400 priv->cloexec = g_value_get_boolean (value);
401 update_fdflags (priv);
403 case PROP_SSL_CREDENTIALS:
404 priv->ssl_creds = g_value_get_pointer (value);
406 case PROP_ASYNC_CONTEXT:
407 priv->async_context = g_value_get_pointer (value);
408 if (priv->async_context)
409 g_main_context_ref (priv->async_context);
412 priv->timeout = g_value_get_uint (value);
420 get_property (GObject *object, guint prop_id,
421 GValue *value, GParamSpec *pspec)
423 SoupSocketPrivate *priv = SOUP_SOCKET_GET_PRIVATE (object);
426 case PROP_NON_BLOCKING:
427 g_value_set_boolean (value, priv->non_blocking);
430 g_value_set_boolean (value, priv->nodelay);
433 g_value_set_boolean (value, priv->reuseaddr);
436 g_value_set_boolean (value, priv->cloexec);
439 g_value_set_boolean (value, priv->is_server);
441 case PROP_SSL_CREDENTIALS:
442 g_value_set_pointer (value, priv->ssl_creds);
444 case PROP_ASYNC_CONTEXT:
445 g_value_set_pointer (value, priv->async_context ? g_main_context_ref (priv->async_context) : NULL);
448 g_value_set_uint (value, priv->timeout);
458 * @optname1: name of first property to set (or %NULL)
459 * @...: value of @optname1, followed by additional property/value pairs
461 * Creates a new (disconnected) socket
463 * Return value: the new socket
466 soup_socket_new (const char *optname1, ...)
471 va_start (ap, optname1);
472 sock = (SoupSocket *)g_object_new_valist (SOUP_TYPE_SOCKET,
480 get_iochannel (SoupSocketPrivate *priv)
482 g_mutex_lock (priv->iolock);
483 if (!priv->iochannel) {
486 g_io_channel_unix_new (priv->sockfd);
489 g_io_channel_win32_new_socket (priv->sockfd);
491 g_io_channel_set_close_on_unref (priv->iochannel, TRUE);
492 g_io_channel_set_encoding (priv->iochannel, NULL, NULL);
493 g_io_channel_set_buffered (priv->iochannel, FALSE);
495 g_mutex_unlock (priv->iolock);
496 return priv->iochannel;
500 idle_connect_result (gpointer user_data)
502 SoupSocket *sock = user_data;
503 SoupSocketPrivate *priv = SOUP_SOCKET_GET_PRIVATE (sock);
505 priv->watch_src = NULL;
507 g_signal_emit (sock, signals[CONNECT_RESULT], 0,
508 priv->sockfd != -1 ? SOUP_STATUS_OK : SOUP_STATUS_CANT_CONNECT);
513 connect_watch (GIOChannel* iochannel, GIOCondition condition, gpointer data)
515 SoupSocket *sock = data;
516 SoupSocketPrivate *priv = SOUP_SOCKET_GET_PRIVATE (sock);
518 int len = sizeof (error);
520 /* Remove the watch now in case we don't return immediately */
521 g_source_destroy (priv->watch_src);
522 priv->watch_src = NULL;
524 if (condition & ~(G_IO_IN | G_IO_OUT))
527 if (getsockopt (priv->sockfd, SOL_SOCKET, SO_ERROR,
528 (void *)&error, (void *)&len) != 0)
533 return idle_connect_result (sock);
536 g_signal_emit (sock, signals[CONNECT_RESULT], 0, SOUP_STATUS_CANT_CONNECT);
541 got_address (SoupAddress *addr, guint status, gpointer user_data)
543 SoupSocket *sock = user_data;
544 SoupSocketPrivate *priv = SOUP_SOCKET_GET_PRIVATE (sock);
546 if (!SOUP_STATUS_IS_SUCCESSFUL (status)) {
547 g_signal_emit (sock, signals[CONNECT_RESULT], 0, status);
548 g_object_unref (sock);
552 soup_socket_connect (sock, priv->remote_addr);
553 /* soup_socket_connect re-reffed addr */
554 g_object_unref (addr);
556 g_object_unref (sock);
560 * soup_socket_connect:
561 * @sock: a client #SoupSocket (which must not already be connected)
562 * @remote_addr: address to connect to
564 * If %SOUP_SOCKET_FLAG_NONBLOCKING has been set on the socket, this
565 * begins asynchronously connecting to the given address. The socket
566 * will emit %connect_result when it succeeds or fails (but not before
567 * returning from this function).
569 * If %SOUP_SOCKET_FLAG_NONBLOCKING has not been set, this will
570 * attempt to synchronously connect.
572 * Return value: %SOUP_STATUS_CONTINUE if connecting asynchronously,
573 * otherwise a success or failure code.
576 soup_socket_connect (SoupSocket *sock, SoupAddress *remote_addr)
578 SoupSocketPrivate *priv;
582 g_return_val_if_fail (SOUP_IS_SOCKET (sock), SOUP_STATUS_MALFORMED);
583 priv = SOUP_SOCKET_GET_PRIVATE (sock);
584 g_return_val_if_fail (!priv->is_server, SOUP_STATUS_MALFORMED);
585 g_return_val_if_fail (priv->sockfd == -1, SOUP_STATUS_MALFORMED);
586 g_return_val_if_fail (SOUP_IS_ADDRESS (remote_addr), SOUP_STATUS_MALFORMED);
588 priv->remote_addr = g_object_ref (remote_addr);
589 if (!priv->non_blocking) {
590 status = soup_address_resolve_sync (remote_addr);
591 if (!SOUP_STATUS_IS_SUCCESSFUL (status))
595 sa = soup_address_get_sockaddr (priv->remote_addr, &len);
597 if (!priv->non_blocking)
598 return SOUP_STATUS_CANT_RESOLVE;
601 soup_address_resolve_async_full (remote_addr, priv->async_context,
603 return SOUP_STATUS_CONTINUE;
606 priv->sockfd = socket (sa->sa_family, SOCK_STREAM, 0);
607 if (SOUP_IS_INVALID_SOCKET (priv->sockfd)) {
610 update_fdflags (priv);
612 status = connect (priv->sockfd, sa, len);
614 if (SOUP_IS_SOCKET_ERROR (status)) {
615 if (SOUP_IS_CONNECT_STATUS_INPROGRESS ()) {
616 /* Wait for connect to succeed or fail */
618 soup_add_io_watch (priv->async_context,
619 get_iochannel (priv),
621 G_IO_PRI | G_IO_ERR |
622 G_IO_HUP | G_IO_NVAL,
623 connect_watch, sock);
624 return SOUP_STATUS_CONTINUE;
626 SOUP_CLOSE_SOCKET (priv->sockfd);
630 get_iochannel (priv);
633 if (priv->non_blocking) {
634 priv->watch_src = soup_add_idle (priv->async_context,
635 idle_connect_result, sock);
636 return SOUP_STATUS_CONTINUE;
637 } else if (SOUP_IS_INVALID_SOCKET (priv->sockfd))
638 return SOUP_STATUS_CANT_CONNECT;
640 return SOUP_STATUS_OK;
644 listen_watch (GIOChannel* iochannel, GIOCondition condition, gpointer data)
646 SoupSocket *sock = data, *new;
647 SoupSocketPrivate *priv = SOUP_SOCKET_GET_PRIVATE (sock), *new_priv;
648 struct soup_sockaddr_max sa;
651 if (condition & (G_IO_HUP | G_IO_ERR)) {
652 g_source_destroy (priv->watch_src);
653 priv->watch_src = NULL;
657 sa_len = sizeof (sa);
658 sockfd = accept (priv->sockfd, (struct sockaddr *)&sa, (void *)&sa_len);
659 if (SOUP_IS_INVALID_SOCKET (sockfd))
662 new = g_object_new (SOUP_TYPE_SOCKET, NULL);
663 new_priv = SOUP_SOCKET_GET_PRIVATE (new);
664 new_priv->sockfd = sockfd;
665 if (priv->async_context)
666 new_priv->async_context = g_main_context_ref (priv->async_context);
667 new_priv->non_blocking = priv->non_blocking;
668 new_priv->nodelay = priv->nodelay;
669 new_priv->is_server = TRUE;
670 new_priv->ssl_creds = priv->ssl_creds;
671 update_fdflags (new_priv);
673 new_priv->remote_addr = soup_address_new_from_sockaddr ((struct sockaddr *)&sa, sa_len);
675 if (new_priv->ssl_creds) {
676 if (!soup_socket_start_ssl (new)) {
677 g_object_unref (new);
681 get_iochannel (new_priv);
683 g_signal_emit (sock, signals[NEW_CONNECTION], 0, new);
684 g_object_unref (new);
690 * soup_socket_listen:
691 * @sock: a server #SoupSocket (which must not already be connected or
693 * @local_addr: Local address to bind to.
695 * Makes @sock start listening on the given interface and port. When
696 * connections come in, @sock will emit %new_connection.
698 * Return value: whether or not @sock is now listening.
701 soup_socket_listen (SoupSocket *sock, SoupAddress *local_addr)
703 SoupSocketPrivate *priv;
707 g_return_val_if_fail (SOUP_IS_SOCKET (sock), FALSE);
708 priv = SOUP_SOCKET_GET_PRIVATE (sock);
709 g_return_val_if_fail (priv->sockfd == -1, FALSE);
710 g_return_val_if_fail (SOUP_IS_ADDRESS (local_addr), FALSE);
712 priv->is_server = TRUE;
714 /* @local_addr may have its port set to 0. So we intentionally
715 * don't store it in priv->local_addr, so that if the
716 * caller calls soup_socket_get_local_address() later, we'll
717 * have to make a new addr by calling getsockname(), which
718 * will have the right port number.
720 sa = soup_address_get_sockaddr (local_addr, &sa_len);
721 g_return_val_if_fail (sa != NULL, FALSE);
723 priv->sockfd = socket (sa->sa_family, SOCK_STREAM, 0);
724 if (SOUP_IS_INVALID_SOCKET (priv->sockfd))
726 update_fdflags (priv);
729 if (bind (priv->sockfd, sa, sa_len) != 0)
733 if (listen (priv->sockfd, 10) != 0)
736 priv->watch_src = soup_add_io_watch (priv->async_context,
737 get_iochannel (priv),
738 G_IO_IN | G_IO_ERR | G_IO_HUP,
743 if (priv->sockfd != -1) {
744 SOUP_CLOSE_SOCKET (priv->sockfd);
752 * soup_socket_start_ssl:
755 * Starts using SSL on @socket.
757 * Return value: success or failure
760 soup_socket_start_ssl (SoupSocket *sock)
762 SoupSocketPrivate *priv = SOUP_SOCKET_GET_PRIVATE (sock);
764 return soup_socket_start_proxy_ssl (sock, soup_address_get_name (priv->remote_addr));
768 * soup_socket_start_proxy_ssl:
770 * @ssl_host: hostname of the SSL server
772 * Starts using SSL on @socket, expecting to find a host named
775 * Return value: success or failure
778 soup_socket_start_proxy_ssl (SoupSocket *sock, const char *ssl_host)
780 SoupSocketPrivate *priv = SOUP_SOCKET_GET_PRIVATE (sock);
781 GIOChannel *ssl_chan;
782 GIOChannel *real_chan;
784 real_chan = get_iochannel (priv);
785 ssl_chan = soup_ssl_wrap_iochannel (
786 real_chan, priv->is_server ?
787 SOUP_SSL_TYPE_SERVER : SOUP_SSL_TYPE_CLIENT,
788 ssl_host, priv->ssl_creds);
793 priv->iochannel = ssl_chan;
794 g_io_channel_unref (real_chan);
801 * soup_socket_client_new_async:
802 * @hostname: remote machine to connect to
803 * @port: remote port to connect to
804 * @ssl_creds: SSL credentials structure, or %NULL if not SSL
805 * @callback: callback to call when the socket is connected
806 * @user_data: data for @callback
808 * Creates a connection to @hostname and @port. @callback will be
809 * called when the connection completes (or fails).
811 * Uses the default #GMainContext. If you need to use an alternate
812 * context, use soup_socket_new() and soup_socket_connect() directly.
814 * Return value: the new socket (not yet ready for use).
817 soup_socket_client_new_async (const char *hostname, guint port,
819 SoupSocketCallback callback, gpointer user_data)
824 g_return_val_if_fail (hostname != NULL, NULL);
826 sock = g_object_new (SOUP_TYPE_SOCKET,
827 SOUP_SOCKET_SSL_CREDENTIALS, ssl_creds,
829 addr = soup_address_new (hostname, port);
830 soup_socket_connect (sock, addr);
831 g_object_unref (addr);
834 soup_signal_connect_once (sock, "connect_result",
835 G_CALLBACK (callback), user_data);
841 * soup_socket_client_new_sync:
842 * @hostname: remote machine to connect to
843 * @port: remote port to connect to
844 * @ssl_creds: SSL credentials structure, or %NULL if not SSL
845 * @status_ret: pointer to return the soup status in
847 * Creates a connection to @hostname and @port. If @status_ret is not
848 * %NULL, it will contain a status code on return.
850 * Return value: the new socket, or %NULL if it could not connect.
853 soup_socket_client_new_sync (const char *hostname, guint port,
854 gpointer ssl_creds, guint *status_ret)
857 SoupSocketPrivate *priv;
861 g_return_val_if_fail (hostname != NULL, NULL);
863 sock = g_object_new (SOUP_TYPE_SOCKET,
864 SOUP_SOCKET_SSL_CREDENTIALS, ssl_creds,
866 priv = SOUP_SOCKET_GET_PRIVATE (sock);
867 priv->non_blocking = FALSE;
868 addr = soup_address_new (hostname, port);
869 status = soup_socket_connect (sock, addr);
870 g_object_unref (addr);
872 if (!SOUP_STATUS_IS_SUCCESSFUL (status)) {
873 g_object_unref (sock);
878 *status_ret = status;
883 * soup_socket_server_new:
884 * @local_addr: Local address to bind to. (Use soup_address_any_new() to
885 * accept connections on any local address)
886 * @ssl_creds: SSL credentials, or %NULL if this is not an SSL server
887 * @callback: Callback to call when a client connects
888 * @user_data: data to pass to @callback.
890 * Create and open a new #SoupSocket listening on the specified
891 * address. @callback will be called each time a client connects,
892 * with a new #SoupSocket.
894 * Uses the default #GMainContext. If you need to use an alternate
895 * context, use soup_socket_new() and soup_socket_listen() directly.
897 * Returns: a new #SoupSocket, or NULL if there was a failure.
900 soup_socket_server_new (SoupAddress *local_addr, gpointer ssl_creds,
901 SoupSocketListenerCallback callback,
905 SoupSocketPrivate *priv;
907 g_return_val_if_fail (SOUP_IS_ADDRESS (local_addr), NULL);
909 sock = g_object_new (SOUP_TYPE_SOCKET,
910 SOUP_SOCKET_SSL_CREDENTIALS, ssl_creds,
912 priv = SOUP_SOCKET_GET_PRIVATE (sock);
913 if (!soup_socket_listen (sock, local_addr)) {
914 g_object_unref (sock);
919 g_signal_connect (sock, "new_connection",
920 G_CALLBACK (callback), user_data);
928 * soup_socket_disconnect:
929 * @sock: a #SoupSocket
931 * Disconnects @sock. Any further read or write attempts on it will
935 soup_socket_disconnect (SoupSocket *sock)
937 SoupSocketPrivate *priv;
938 gboolean already_disconnected = FALSE;
940 g_return_if_fail (SOUP_IS_SOCKET (sock));
941 priv = SOUP_SOCKET_GET_PRIVATE (sock);
943 if (g_mutex_trylock (priv->iolock)) {
945 disconnect_internal (priv);
947 already_disconnected = TRUE;
948 g_mutex_unlock (priv->iolock);
952 /* Another thread is currently doing IO, so
953 * we can't close the iochannel. So just kick
954 * the file descriptor out from under it.
957 sockfd = priv->sockfd;
960 already_disconnected = TRUE;
962 g_io_channel_set_close_on_unref (priv->iochannel,
964 SOUP_CLOSE_SOCKET (sockfd);
968 if (already_disconnected)
971 /* Give all readers a chance to notice the connection close */
972 g_signal_emit (sock, signals[READABLE], 0);
974 /* FIXME: can't disconnect until all data is read */
976 /* Then let everyone know we're disconnected */
977 g_signal_emit (sock, signals[DISCONNECTED], 0);
981 * soup_socket_is_connected:
982 * @sock: a #SoupSocket
984 * Tests if @sock is connected to another host
986 * Return value: %TRUE or %FALSE.
989 soup_socket_is_connected (SoupSocket *sock)
991 SoupSocketPrivate *priv;
993 g_return_val_if_fail (SOUP_IS_SOCKET (sock), FALSE);
994 priv = SOUP_SOCKET_GET_PRIVATE (sock);
996 return priv->iochannel != NULL;
1000 * soup_socket_get_local_address:
1001 * @sock: a #SoupSocket
1003 * Returns the #SoupAddress corresponding to the local end of @sock.
1005 * Return value: the #SoupAddress
1008 soup_socket_get_local_address (SoupSocket *sock)
1010 SoupSocketPrivate *priv;
1012 g_return_val_if_fail (SOUP_IS_SOCKET (sock), NULL);
1013 priv = SOUP_SOCKET_GET_PRIVATE (sock);
1015 g_mutex_lock (priv->addrlock);
1016 if (!priv->local_addr) {
1017 struct soup_sockaddr_max bound_sa;
1020 sa_len = sizeof (bound_sa);
1021 getsockname (priv->sockfd, (struct sockaddr *)&bound_sa, (void *)&sa_len);
1022 priv->local_addr = soup_address_new_from_sockaddr ((struct sockaddr *)&bound_sa, sa_len);
1024 g_mutex_unlock (priv->addrlock);
1026 return priv->local_addr;
1030 * soup_socket_get_remote_address:
1031 * @sock: a #SoupSocket
1033 * Returns the #SoupAddress corresponding to the remote end of @sock.
1035 * Return value: the #SoupAddress
1038 soup_socket_get_remote_address (SoupSocket *sock)
1040 SoupSocketPrivate *priv;
1042 g_return_val_if_fail (SOUP_IS_SOCKET (sock), NULL);
1043 priv = SOUP_SOCKET_GET_PRIVATE (sock);
1045 g_mutex_lock (priv->addrlock);
1046 if (!priv->remote_addr) {
1047 struct soup_sockaddr_max bound_sa;
1050 sa_len = sizeof (bound_sa);
1051 getpeername (priv->sockfd, (struct sockaddr *)&bound_sa, (void *)&sa_len);
1052 priv->remote_addr = soup_address_new_from_sockaddr ((struct sockaddr *)&bound_sa, sa_len);
1054 g_mutex_unlock (priv->addrlock);
1056 return priv->remote_addr;
1063 socket_read_watch (GIOChannel *chan, GIOCondition cond, gpointer user_data)
1065 SoupSocket *sock = user_data;
1066 SoupSocketPrivate *priv = SOUP_SOCKET_GET_PRIVATE (sock);
1068 priv->read_src = NULL;
1070 if (cond & (G_IO_ERR | G_IO_HUP))
1071 soup_socket_disconnect (sock);
1073 g_signal_emit (sock, signals[READABLE], 0);
1078 static SoupSocketIOStatus
1079 read_from_network (SoupSocket *sock, gpointer buffer, gsize len, gsize *nread)
1081 SoupSocketPrivate *priv = SOUP_SOCKET_GET_PRIVATE (sock);
1083 GIOCondition cond = G_IO_IN;
1086 if (!priv->iochannel)
1087 return SOUP_SOCKET_EOF;
1089 status = g_io_channel_read_chars (priv->iochannel,
1090 buffer, len, nread, &err);
1092 if (err->domain == SOUP_SSL_ERROR &&
1093 err->code == SOUP_SSL_ERROR_HANDSHAKE_NEEDS_WRITE)
1095 g_object_set_data_full (G_OBJECT (sock),
1096 "SoupSocket-last_error",
1097 err, (GDestroyNotify)g_error_free);
1099 g_object_set_data (G_OBJECT (sock),
1100 "SoupSocket-last_error",
1105 case G_IO_STATUS_NORMAL:
1106 case G_IO_STATUS_AGAIN:
1108 return SOUP_SOCKET_OK;
1110 /* If the connection/session is sync and we get
1111 EAGAIN or EWOULDBLOCK, then it will be socket timeout
1112 and should be treated as an error condition.
1114 if (!priv->non_blocking)
1115 return SOUP_SOCKET_ERROR;
1117 if (!priv->read_src) {
1119 soup_add_io_watch (priv->async_context,
1121 cond | G_IO_HUP | G_IO_ERR,
1122 socket_read_watch, sock);
1124 return SOUP_SOCKET_WOULD_BLOCK;
1126 case G_IO_STATUS_EOF:
1127 return SOUP_SOCKET_EOF;
1130 return SOUP_SOCKET_ERROR;
1134 static SoupSocketIOStatus
1135 read_from_buf (SoupSocket *sock, gpointer buffer, gsize len, gsize *nread)
1137 SoupSocketPrivate *priv = SOUP_SOCKET_GET_PRIVATE (sock);
1138 GByteArray *read_buf = priv->read_buf;
1140 *nread = MIN (read_buf->len, len);
1141 memcpy (buffer, read_buf->data, *nread);
1143 if (*nread == read_buf->len) {
1144 g_byte_array_free (read_buf, TRUE);
1145 priv->read_buf = NULL;
1147 memmove (read_buf->data, read_buf->data + *nread,
1148 read_buf->len - *nread);
1149 g_byte_array_set_size (read_buf, read_buf->len - *nread);
1152 return SOUP_SOCKET_OK;
1158 * @buffer: buffer to read into
1159 * @len: size of @buffer in bytes
1160 * @nread: on return, the number of bytes read into @buffer
1162 * Attempts to read up to @len bytes from @sock into @buffer. If some
1163 * data is successfully read, soup_socket_read() will return
1164 * %SOUP_SOCKET_OK, and *@nread will contain the number of bytes
1167 * If @sock is non-blocking, and no data is available, the return
1168 * value will be %SOUP_SOCKET_WOULD_BLOCK. In this case, the caller
1169 * can connect to the %readable signal to know when there is more data
1170 * to read. (NB: You MUST read all available data off the socket
1171 * first. The %readable signal will only be emitted after
1172 * soup_socket_read() has returned %SOUP_SOCKET_WOULD_BLOCK.)
1174 * Return value: a #SoupSocketIOStatus, as described above (or
1175 * %SOUP_SOCKET_EOF if the socket is no longer connected, or
1176 * %SOUP_SOCKET_ERROR on any other error).
1179 soup_socket_read (SoupSocket *sock, gpointer buffer, gsize len, gsize *nread)
1181 SoupSocketPrivate *priv;
1182 SoupSocketIOStatus status;
1184 g_return_val_if_fail (SOUP_IS_SOCKET (sock), SOUP_SOCKET_ERROR);
1185 priv = SOUP_SOCKET_GET_PRIVATE (sock);
1187 g_mutex_lock (priv->iolock);
1189 status = read_from_buf (sock, buffer, len, nread);
1191 status = read_from_network (sock, buffer, len, nread);
1192 g_mutex_unlock (priv->iolock);
1198 * soup_socket_read_until:
1200 * @buffer: buffer to read into
1201 * @len: size of @buffer in bytes
1202 * @boundary: boundary to read until
1203 * @boundary_len: length of @boundary in bytes
1204 * @nread: on return, the number of bytes read into @buffer
1205 * @got_boundary: on return, whether or not the data in @buffer
1206 * ends with the boundary string
1208 * Like soup_socket_read(), but reads no further than the first
1209 * occurrence of @boundary. (If the boundary is found, it will be
1210 * included in the returned data, and *@got_boundary will be set to
1211 * %TRUE.) Any data after the boundary will returned in future reads.
1213 * Return value: as for soup_socket_read()
1216 soup_socket_read_until (SoupSocket *sock, gpointer buffer, gsize len,
1217 gconstpointer boundary, gsize boundary_len,
1218 gsize *nread, gboolean *got_boundary)
1220 SoupSocketPrivate *priv;
1221 SoupSocketIOStatus status;
1222 GByteArray *read_buf;
1223 guint match_len, prev_len;
1226 g_return_val_if_fail (SOUP_IS_SOCKET (sock), SOUP_SOCKET_ERROR);
1227 priv = SOUP_SOCKET_GET_PRIVATE (sock);
1228 g_return_val_if_fail (len >= boundary_len, SOUP_SOCKET_ERROR);
1230 g_mutex_lock (priv->iolock);
1232 *got_boundary = FALSE;
1234 if (!priv->read_buf)
1235 priv->read_buf = g_byte_array_new ();
1236 read_buf = priv->read_buf;
1238 if (read_buf->len < boundary_len) {
1239 prev_len = read_buf->len;
1240 g_byte_array_set_size (read_buf, len);
1241 status = read_from_network (sock,
1242 read_buf->data + prev_len,
1243 len - prev_len, nread);
1244 read_buf->len = prev_len + *nread;
1246 if (status != SOUP_SOCKET_OK) {
1247 g_mutex_unlock (priv->iolock);
1252 /* Scan for the boundary */
1253 end = read_buf->data + read_buf->len;
1254 for (p = read_buf->data; p <= end - boundary_len; p++) {
1255 if (!memcmp (p, boundary, boundary_len)) {
1257 *got_boundary = TRUE;
1262 /* Return everything up to 'p' (which is either just after the
1263 * boundary, or @boundary_len - 1 bytes before the end of the
1266 match_len = p - read_buf->data;
1267 status = read_from_buf (sock, buffer, MIN (len, match_len), nread);
1269 g_mutex_unlock (priv->iolock);
1274 socket_write_watch (GIOChannel *chan, GIOCondition cond, gpointer user_data)
1276 SoupSocket *sock = user_data;
1277 SoupSocketPrivate *priv = SOUP_SOCKET_GET_PRIVATE (sock);
1279 priv->write_src = NULL;
1281 if (cond & (G_IO_ERR | G_IO_HUP))
1282 soup_socket_disconnect (sock);
1284 g_signal_emit (sock, signals[WRITABLE], 0);
1290 * soup_socket_write:
1292 * @buffer: data to write
1293 * @len: size of @buffer, in bytes
1294 * @nwrote: on return, number of bytes written
1296 * Attempts to write @len bytes from @buffer to @sock. If some data is
1297 * successfully written, the resturn status will be
1298 * %SOUP_SOCKET_SUCCESS, and *@nwrote will contain the number of bytes
1301 * If @sock is non-blocking, and no data could be written right away,
1302 * the return value will be %SOUP_SOCKET_WOULD_BLOCK. In this case,
1303 * the caller can connect to the %writable signal to know when more
1304 * data can be written. (NB: %writable is only emitted after a
1305 * %SOUP_SOCKET_WOULD_BLOCK.)
1307 * Return value: a #SoupSocketIOStatus, as described above (or
1308 * %SOUP_SOCKET_EOF or %SOUP_SOCKET_ERROR).
1311 soup_socket_write (SoupSocket *sock, gconstpointer buffer,
1312 gsize len, gsize *nwrote)
1314 SoupSocketPrivate *priv;
1317 gpointer pipe_handler;
1319 GIOCondition cond = G_IO_OUT;
1322 g_return_val_if_fail (SOUP_IS_SOCKET (sock), SOUP_SOCKET_ERROR);
1323 priv = SOUP_SOCKET_GET_PRIVATE (sock);
1325 g_mutex_lock (priv->iolock);
1327 if (!priv->iochannel) {
1328 g_mutex_unlock (priv->iolock);
1329 return SOUP_SOCKET_EOF;
1331 if (priv->write_src) {
1332 g_mutex_unlock (priv->iolock);
1333 return SOUP_SOCKET_WOULD_BLOCK;
1337 pipe_handler = signal (SIGPIPE, SIG_IGN);
1339 status = g_io_channel_write_chars (priv->iochannel,
1340 buffer, len, nwrote, &err);
1342 signal (SIGPIPE, pipe_handler);
1345 if (err->domain == SOUP_SSL_ERROR &&
1346 err->code == SOUP_SSL_ERROR_HANDSHAKE_NEEDS_READ)
1348 g_object_set_data_full (G_OBJECT (sock),
1349 "SoupSocket-last_error",
1350 err, (GDestroyNotify)g_error_free);
1352 g_object_set_data (G_OBJECT (sock),
1353 "SoupSocket-last_error",
1357 /* If the connection/session is sync and we get
1358 EAGAIN or EWOULDBLOCK, then it will be socket timeout
1359 and should be treated as an error condition.
1361 if (!priv->non_blocking && status == G_IO_STATUS_AGAIN) {
1362 g_mutex_unlock (priv->iolock);
1363 return SOUP_SOCKET_ERROR;
1366 if (status != G_IO_STATUS_NORMAL && status != G_IO_STATUS_AGAIN) {
1367 g_mutex_unlock (priv->iolock);
1368 return SOUP_SOCKET_ERROR;
1372 g_mutex_unlock (priv->iolock);
1373 return SOUP_SOCKET_OK;
1377 soup_add_io_watch (priv->async_context,
1379 cond | G_IO_HUP | G_IO_ERR,
1380 socket_write_watch, sock);
1381 g_mutex_unlock (priv->iolock);
1382 return SOUP_SOCKET_WOULD_BLOCK;