Add g_output_stream_write_all_async()
[platform/upstream/glib.git] / gio / gsocketconnection.c
index 3033c3a..9f490c8 100644 (file)
@@ -15,9 +15,7 @@
  * Lesser General Public License for more details.
  *
  * You should have received a copy of the GNU Lesser General
- * Public License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
- * Boston, MA 02111-1307, USA.
+ * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
  *
  * Authors: Christian Kellner <gicmo@gnome.org>
  *          Samuel Cormier-Iijima <sciyoshi@gmail.com>
 
 #include "gsocketoutputstream.h"
 #include "gsocketinputstream.h"
+#include "gioprivate.h"
 #include <gio/giostream.h>
-#include <gio/gsimpleasyncresult.h>
+#include <gio/gtask.h>
 #include "gunixconnection.h"
 #include "gtcpconnection.h"
 #include "glibintl.h"
 
-#include "gioalias.h"
 
 /**
  * SECTION:gsocketconnection
  * can be created either by #GSocketClient when connecting to a host,
  * or by #GSocketListener when accepting a new client.
  *
- * The type of the #GSocketConnection object returned from these calls depends
- * on the type of the underlying socket that is in use. For instance, for a
- * TCP/IP connection it will be a #GTcpConnection.
+ * The type of the #GSocketConnection object returned from these calls
+ * depends on the type of the underlying socket that is in use. For
+ * instance, for a TCP/IP connection it will be a #GTcpConnection.
  *
- * Chosing what type of object to construct is done with the socket connection
- * factory, and it is possible for 3rd parties to register custom socket connection
- * types for specific combination of socket family/type/protocol using
- * g_socket_connection_factory_register_type().
+ * Choosing what type of object to construct is done with the socket
+ * connection factory, and it is possible for 3rd parties to register
+ * custom socket connection types for specific combination of socket
+ * family/type/protocol using g_socket_connection_factory_register_type().
+ *
+ * To close a #GSocketConnection, use g_io_stream_close(). Closing both
+ * substreams of the #GIOStream separately will not close the underlying
+ * #GSocket.
  *
  * Since: 2.22
- **/
-
-G_DEFINE_TYPE (GSocketConnection,
-              g_socket_connection, G_TYPE_IO_STREAM);
+ */
 
 enum
 {
@@ -75,6 +74,10 @@ struct _GSocketConnectionPrivate
   GSocket       *socket;
   GInputStream  *input_stream;
   GOutputStream *output_stream;
+
+  GSocketAddress *cached_remote_address;
+
+  gboolean       in_dispose;
 };
 
 static gboolean g_socket_connection_close         (GIOStream            *stream,
@@ -89,6 +92,8 @@ static gboolean g_socket_connection_close_finish  (GIOStream            *stream,
                                                   GAsyncResult         *result,
                                                   GError              **error);
 
+G_DEFINE_TYPE_WITH_PRIVATE (GSocketConnection, g_socket_connection, G_TYPE_IO_STREAM)
+
 static GInputStream *
 g_socket_connection_get_input_stream (GIOStream *io_stream)
 {
@@ -114,17 +119,163 @@ g_socket_connection_get_output_stream (GIOStream *io_stream)
 }
 
 /**
+ * g_socket_connection_is_connected:
+ * @connection: a #GSocketConnection
+ *
+ * Checks if @connection is connected. This is equivalent to calling
+ * g_socket_is_connected() on @connection's underlying #GSocket.
+ *
+ * Returns: whether @connection is connected
+ *
+ * Since: 2.32
+ */
+gboolean
+g_socket_connection_is_connected (GSocketConnection  *connection)
+{
+  return g_socket_is_connected (connection->priv->socket);
+}
+
+/**
+ * g_socket_connection_connect:
+ * @connection: a #GSocketConnection
+ * @address: a #GSocketAddress specifying the remote address.
+ * @cancellable: (allow-none): a %GCancellable or %NULL
+ * @error: #GError for error reporting, or %NULL to ignore.
+ *
+ * Connect @connection to the specified remote address.
+ *
+ * Returns: %TRUE if the connection succeeded, %FALSE on error
+ *
+ * Since: 2.32
+ */
+gboolean
+g_socket_connection_connect (GSocketConnection  *connection,
+                            GSocketAddress     *address,
+                            GCancellable       *cancellable,
+                            GError            **error)
+{
+  g_return_val_if_fail (G_IS_SOCKET_CONNECTION (connection), FALSE);
+  g_return_val_if_fail (G_IS_SOCKET_ADDRESS (address), FALSE);
+
+  return g_socket_connect (connection->priv->socket, address,
+                          cancellable, error);
+}
+
+static gboolean g_socket_connection_connect_callback (GSocket      *socket,
+                                                     GIOCondition  condition,
+                                                     gpointer      user_data);
+
+/**
+ * g_socket_connection_connect_async:
+ * @connection: a #GSocketConnection
+ * @address: a #GSocketAddress specifying the remote address.
+ * @cancellable: (allow-none): a %GCancellable or %NULL
+ * @callback: (scope async): a #GAsyncReadyCallback
+ * @user_data: (closure): user data for the callback
+ *
+ * Asynchronously connect @connection to the specified remote address.
+ *
+ * This clears the #GSocket:blocking flag on @connection's underlying
+ * socket if it is currently set.
+ *
+ * Use g_socket_connection_connect_finish() to retrieve the result.
+ *
+ * Since: 2.32
+ */
+void
+g_socket_connection_connect_async (GSocketConnection   *connection,
+                                  GSocketAddress      *address,
+                                  GCancellable        *cancellable,
+                                  GAsyncReadyCallback  callback,
+                                  gpointer             user_data)
+{
+  GTask *task;
+  GError *tmp_error = NULL;
+
+  g_return_if_fail (G_IS_SOCKET_CONNECTION (connection));
+  g_return_if_fail (G_IS_SOCKET_ADDRESS (address));
+
+  task = g_task_new (connection, cancellable, callback, user_data);
+
+  g_socket_set_blocking (connection->priv->socket, FALSE);
+
+  if (g_socket_connect (connection->priv->socket, address,
+                       cancellable, &tmp_error))
+    {
+      g_task_return_boolean (task, TRUE);
+      g_object_unref (task);
+    }
+  else if (g_error_matches (tmp_error, G_IO_ERROR, G_IO_ERROR_PENDING))
+    {
+      GSource *source;
+
+      g_error_free (tmp_error);
+      source = g_socket_create_source (connection->priv->socket,
+                                      G_IO_OUT, cancellable);
+      g_task_attach_source (task, source,
+                           (GSourceFunc) g_socket_connection_connect_callback);
+      g_source_unref (source);
+    }
+  else
+    {
+      g_task_return_error (task, tmp_error);
+      g_object_unref (task);
+    }
+}
+
+static gboolean
+g_socket_connection_connect_callback (GSocket      *socket,
+                                     GIOCondition  condition,
+                                     gpointer      user_data)
+{
+  GTask *task = user_data;
+  GSocketConnection *connection = g_task_get_source_object (task);
+  GError *error = NULL;
+
+  if (g_socket_check_connect_result (connection->priv->socket, &error))
+    g_task_return_boolean (task, TRUE);
+  else
+    g_task_return_error (task, error);
+
+  g_object_unref (task);
+  return FALSE;
+}
+
+/**
+ * g_socket_connection_connect_finish:
+ * @connection: a #GSocketConnection
+ * @result: the #GAsyncResult
+ * @error: #GError for error reporting, or %NULL to ignore.
+ *
+ * Gets the result of a g_socket_connection_connect_async() call.
+ *
+ * Returns: %TRUE if the connection succeeded, %FALSE on error
+ *
+ * Since: 2.32
+ */
+gboolean
+g_socket_connection_connect_finish (GSocketConnection  *connection,
+                                   GAsyncResult       *result,
+                                   GError            **error)
+{
+  g_return_val_if_fail (G_IS_SOCKET_CONNECTION (connection), FALSE);
+  g_return_val_if_fail (g_task_is_valid (result, connection), FALSE);
+
+  return g_task_propagate_boolean (G_TASK (result), error);
+}
+
+/**
  * g_socket_connection_get_socket:
- * @connection: a #GSocketConnection.
+ * @connection: a #GSocketConnection
  *
  * Gets the underlying #GSocket object of the connection.
  * This can be useful if you want to do something unusual on it
  * not supported by the #GSocketConnection APIs.
  *
- * Returns: a #GSocketAddress or %NULL on error.
+ * Returns: (transfer none): a #GSocketAddress or %NULL on error.
  *
  * Since: 2.22
- **/
+ */
 GSocket *
 g_socket_connection_get_socket (GSocketConnection *connection)
 {
@@ -135,45 +286,72 @@ g_socket_connection_get_socket (GSocketConnection *connection)
 
 /**
  * g_socket_connection_get_local_address:
- * @connection: a #GSocketConnection.
+ * @connection: a #GSocketConnection
  * @error: #GError for error reporting, or %NULL to ignore.
  *
  * Try to get the local address of a socket connection.
  *
- * Returns: a #GSocketAddress or %NULL on error.
+ * Returns: (transfer full): a #GSocketAddress or %NULL on error.
  *     Free the returned object with g_object_unref().
  *
  * Since: 2.22
- **/
+ */
 GSocketAddress *
 g_socket_connection_get_local_address (GSocketConnection  *connection,
-                                      GError  **error)
+                                      GError            **error)
 {
   return g_socket_get_local_address (connection->priv->socket, error);
 }
 
 /**
  * g_socket_connection_get_remote_address:
- * @connection: a #GSocketConnection.
+ * @connection: a #GSocketConnection
  * @error: #GError for error reporting, or %NULL to ignore.
  *
- * Try to get the remove address of a socket connection.
+ * Try to get the remote address of a socket connection.
+ *
+ * Since GLib 2.40, when used with g_socket_client_connect() or
+ * g_socket_client_connect_async(), during emission of
+ * %G_SOCKET_CLIENT_CONNECTING, this function will return the remote
+ * address that will be used for the connection.  This allows
+ * applications to print e.g. "Connecting to example.com
+ * (10.42.77.3)...".
  *
- * Returns: a #GSocketAddress or %NULL on error.
+ * Returns: (transfer full): a #GSocketAddress or %NULL on error.
  *     Free the returned object with g_object_unref().
  *
  * Since: 2.22
- **/
+ */
 GSocketAddress *
 g_socket_connection_get_remote_address (GSocketConnection  *connection,
-                                       GError  **error)
+                                       GError            **error)
 {
+  if (!g_socket_is_connected (connection->priv->socket))
+    {
+      return connection->priv->cached_remote_address ?
+        g_object_ref (connection->priv->cached_remote_address) : NULL;
+    }
   return g_socket_get_remote_address (connection->priv->socket, error);
 }
 
+/* Private API allowing applications to retrieve the resolved address
+ * now, before we start connecting.
+ *
+ * https://bugzilla.gnome.org/show_bug.cgi?id=712547
+ */
+void
+g_socket_connection_set_cached_remote_address (GSocketConnection *connection,
+                                               GSocketAddress    *address)
+{
+  g_clear_object (&connection->priv->cached_remote_address);
+  connection->priv->cached_remote_address = address ? g_object_ref (address) : NULL;
+}
+
 static void
-g_socket_connection_get_property (GObject *object, guint prop_id,
-                                  GValue *value, GParamSpec *pspec)
+g_socket_connection_get_property (GObject    *object,
+                                  guint       prop_id,
+                                  GValue     *value,
+                                  GParamSpec *pspec)
 {
   GSocketConnection *connection = G_SOCKET_CONNECTION (object);
 
@@ -189,8 +367,10 @@ g_socket_connection_get_property (GObject *object, guint prop_id,
 }
 
 static void
-g_socket_connection_set_property (GObject *object, guint prop_id,
-                                  const GValue *value, GParamSpec *pspec)
+g_socket_connection_set_property (GObject      *object,
+                                  guint         prop_id,
+                                  const GValue *value,
+                                  GParamSpec   *pspec)
 {
   GSocketConnection *connection = G_SOCKET_CONNECTION (object);
 
@@ -214,6 +394,21 @@ g_socket_connection_constructed (GObject *object)
 }
 
 static void
+g_socket_connection_dispose (GObject *object)
+{
+  GSocketConnection *connection = G_SOCKET_CONNECTION (object);
+
+  connection->priv->in_dispose = TRUE;
+
+  g_clear_object (&connection->priv->cached_remote_address);
+
+  G_OBJECT_CLASS (g_socket_connection_parent_class)
+    ->dispose (object);
+
+  connection->priv->in_dispose = FALSE;
+}
+
+static void
 g_socket_connection_finalize (GObject *object)
 {
   GSocketConnection *connection = G_SOCKET_CONNECTION (object);
@@ -236,12 +431,11 @@ g_socket_connection_class_init (GSocketConnectionClass *klass)
   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
   GIOStreamClass *stream_class = G_IO_STREAM_CLASS (klass);
 
-  g_type_class_add_private (klass, sizeof (GSocketConnectionPrivate));
-
   gobject_class->set_property = g_socket_connection_set_property;
   gobject_class->get_property = g_socket_connection_get_property;
   gobject_class->constructed = g_socket_connection_constructed;
   gobject_class->finalize = g_socket_connection_finalize;
+  gobject_class->dispose = g_socket_connection_dispose;
 
   stream_class->get_input_stream = g_socket_connection_get_input_stream;
   stream_class->get_output_stream = g_socket_connection_get_output_stream;
@@ -249,26 +443,27 @@ g_socket_connection_class_init (GSocketConnectionClass *klass)
   stream_class->close_async = g_socket_connection_close_async;
   stream_class->close_finish = g_socket_connection_close_finish;
 
-  g_object_class_install_property (gobject_class, PROP_SOCKET,
-    g_param_spec_object ("socket",
-                        P_("Socket"),
-                        P_("The underlying GSocket"),
-                         G_TYPE_SOCKET, G_PARAM_CONSTRUCT_ONLY |
-                         G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class,
+                                   PROP_SOCKET,
+                                   g_param_spec_object ("socket",
+                                                       P_("Socket"),
+                                                       P_("The underlying GSocket"),
+                                                        G_TYPE_SOCKET,
+                                                        G_PARAM_CONSTRUCT_ONLY |
+                                                        G_PARAM_READWRITE |
+                                                        G_PARAM_STATIC_STRINGS));
 }
 
 static void
 g_socket_connection_init (GSocketConnection *connection)
 {
-  connection->priv = G_TYPE_INSTANCE_GET_PRIVATE (connection,
-                                                  G_TYPE_SOCKET_CONNECTION,
-                                                  GSocketConnectionPrivate);
+  connection->priv = g_socket_connection_get_instance_private (connection);
 }
 
 static gboolean
-g_socket_connection_close (GIOStream            *stream,
-                          GCancellable         *cancellable,
-                          GError              **error)
+g_socket_connection_close (GIOStream     *stream,
+                          GCancellable  *cancellable,
+                          GError       **error)
 {
   GSocketConnection *connection = G_SOCKET_CONNECTION (stream);
 
@@ -279,49 +474,51 @@ g_socket_connection_close (GIOStream            *stream,
     g_input_stream_close (connection->priv->input_stream,
                          cancellable, NULL);
 
+  /* Don't close the underlying socket if this is being called
+   * as part of dispose(); when destroying the GSocketConnection,
+   * we only want to close the socket if we're holding the last
+   * reference on it, and in that case it will close itself when
+   * we unref it in finalize().
+   */
+  if (connection->priv->in_dispose)
+    return TRUE;
+
   return g_socket_close (connection->priv->socket, error);
 }
 
 
 static void
-g_socket_connection_close_async (GIOStream        *stream,
-                                int               io_priority,
-                                GCancellable     *cancellable,
-                                GAsyncReadyCallback callback,
-                                gpointer          user_data)
+g_socket_connection_close_async (GIOStream           *stream,
+                                int                  io_priority,
+                                GCancellable        *cancellable,
+                                GAsyncReadyCallback  callback,
+                                gpointer             user_data)
 {
-  GSimpleAsyncResult *res;
+  GTask *task;
   GIOStreamClass *class;
   GError *error;
 
   class = G_IO_STREAM_GET_CLASS (stream);
 
+  task = g_task_new (stream, cancellable, callback, user_data);
+
   /* socket close is not blocked, just do it! */
   error = NULL;
   if (class->close_fn &&
       !class->close_fn (stream, cancellable, &error))
-    {
-      g_simple_async_report_gerror_in_idle (G_OBJECT (stream),
-                                           callback, user_data,
-                                           error);
-      g_error_free (error);
-      return;
-    }
+    g_task_return_error (task, error);
+  else
+    g_task_return_boolean (task, TRUE);
 
-  res = g_simple_async_result_new (G_OBJECT (stream),
-                                  callback,
-                                  user_data,
-                                  g_socket_connection_close_async);
-  g_simple_async_result_complete_in_idle (res);
-  g_object_unref (res);
+  g_object_unref (task);
 }
 
 static gboolean
-g_socket_connection_close_finish (GIOStream  *stream,
+g_socket_connection_close_finish (GIOStream     *stream,
                                  GAsyncResult  *result,
                                  GError       **error)
 {
-  return TRUE;
+  return g_task_propagate_boolean (G_TASK (result), error);
 }
 
 typedef struct {
@@ -369,23 +566,23 @@ G_LOCK_DEFINE_STATIC(connection_factories);
 
 /**
  * g_socket_connection_factory_register_type:
- * @g_type: a #GType, inheriting from G_SOCKET_CONNECTION
- * @family: a #GSocketFamily.
+ * @g_type: a #GType, inheriting from %G_TYPE_SOCKET_CONNECTION
+ * @family: a #GSocketFamily
  * @type: a #GSocketType
  * @protocol: a protocol id
  *
  * Looks up the #GType to be used when creating socket connections on
- * sockets with the specified @family,@type and @protocol.
+ * sockets with the specified @family, @type and @protocol.
  *
  * If no type is registered, the #GSocketConnection base type is returned.
  *
  * Since: 2.22
- **/
+ */
 void
-g_socket_connection_factory_register_type (GType g_type,
+g_socket_connection_factory_register_type (GType         g_type,
                                           GSocketFamily family,
-                                          GSocketType type,
-                                          gint protocol)
+                                          GSocketType   type,
+                                          gint          protocol)
 {
   ConnectionFactory *factory;
 
@@ -414,31 +611,31 @@ g_socket_connection_factory_register_type (GType g_type,
 static void
 init_builtin_types (void)
 {
-  volatile GType a_type;
 #ifndef G_OS_WIN32
-  a_type = g_unix_connection_get_type ();
+  g_type_ensure (G_TYPE_UNIX_CONNECTION);
 #endif
-  a_type = g_tcp_connection_get_type ();
+  g_type_ensure (G_TYPE_TCP_CONNECTION);
 }
 
 /**
  * g_socket_connection_factory_lookup_type:
- * @family: a #GSocketFamily.
+ * @family: a #GSocketFamily
  * @type: a #GSocketType
  * @protocol_id: a protocol id
  *
  * Looks up the #GType to be used when creating socket connections on
- * sockets with the specified @family,@type and @protocol_id.
+ * sockets with the specified @family, @type and @protocol_id.
  *
  * If no type is registered, the #GSocketConnection base type is returned.
  *
  * Returns: a #GType
+ *
  * Since: 2.22
- **/
+ */
 GType
 g_socket_connection_factory_lookup_type (GSocketFamily family,
-                                        GSocketType type,
-                                        gint protocol_id)
+                                        GSocketType   type,
+                                        gint          protocol_id)
 {
   ConnectionFactory *factory, key;
   GType g_type;
@@ -467,15 +664,15 @@ g_socket_connection_factory_lookup_type (GSocketFamily family,
 
 /**
  * g_socket_connection_factory_create_connection:
- * @socket: a #GSocket.
+ * @socket: a #GSocket
  *
  * Creates a #GSocketConnection subclass of the right type for
  * @socket.
  *
- * Returns: a #GSocketConnection
+ * Returns: (transfer full): a #GSocketConnection
  *
  * Since: 2.22
- **/
+ */
 GSocketConnection *
 g_socket_connection_factory_create_connection (GSocket *socket)
 {
@@ -486,6 +683,3 @@ g_socket_connection_factory_create_connection (GSocket *socket)
                                                  g_socket_get_protocol (socket));
   return g_object_new (type, "socket", socket, NULL);
 }
-
-#define __G_SOCKET_CONNECTION_C__
-#include "gioaliasdef.c"