[libsoup/server-api: 3/6] SoupSocket: add properties to create a SoupSocket from an fd or GSocket



commit a263acd1ae99632915f4ebe05265a3a98e62de97
Author: Dan Winship <danw gnome org>
Date:   Tue Mar 11 09:01:57 2014 -0400

    SoupSocket: add properties to create a SoupSocket from an fd or GSocket
    
    FIXME bug number

 libsoup/soup-socket-private.h |    7 +-
 libsoup/soup-socket.c         |  160 +++++++++++++++++++++++++---
 po/POTFILES.in                |    1 +
 tests/socket-test.c           |  231 +++++++++++++++++++++++++++++++++++++++++
 4 files changed, 381 insertions(+), 18 deletions(-)
---
diff --git a/libsoup/soup-socket-private.h b/libsoup/soup-socket-private.h
index f602077..f661cc5 100644
--- a/libsoup/soup-socket-private.h
+++ b/libsoup/soup-socket-private.h
@@ -8,8 +8,11 @@
 
 #include "soup-socket.h"
 
-#define SOUP_SOCKET_CLEAN_DISPOSE  "clean-dispose"
-#define SOUP_SOCKET_PROXY_RESOLVER "proxy-resolver"
+#define SOUP_SOCKET_CLEAN_DISPOSE    "clean-dispose"
+#define SOUP_SOCKET_PROXY_RESOLVER   "proxy-resolver"
+#define SOUP_SOCKET_CLOSE_ON_DISPOSE "close-on-dispose"
+#define SOUP_SOCKET_FD               "fd"
+#define SOUP_SOCKET_GSOCKET          "gsocket"
 
 gboolean   soup_socket_connect_sync_internal   (SoupSocket           *sock,
                                                GCancellable         *cancellable,
diff --git a/libsoup/soup-socket.c b/libsoup/soup-socket.c
index c1d503f..df40efc 100644
--- a/libsoup/soup-socket.c
+++ b/libsoup/soup-socket.c
@@ -11,6 +11,7 @@
 
 #include <string.h>
 
+#include <glib/gi18n-lib.h>
 #include <gio/gnetworking.h>
 
 #include "soup-socket.h"
@@ -29,7 +30,11 @@
  * soup_socket_get_remote_address()) may be useful to applications.
  **/
 
-G_DEFINE_TYPE (SoupSocket, soup_socket, G_TYPE_OBJECT)
+static void soup_socket_initable_interface_init (GInitableIface *initable_interface);
+
+G_DEFINE_TYPE_WITH_CODE (SoupSocket, soup_socket, G_TYPE_OBJECT,
+                        G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,
+                                               soup_socket_initable_interface_init))
 
 enum {
        READABLE,
@@ -45,6 +50,8 @@ static guint signals[LAST_SIGNAL] = { 0 };
 enum {
        PROP_0,
 
+       PROP_FD,
+       PROP_GSOCKET,
        PROP_LOCAL_ADDRESS,
        PROP_REMOTE_ADDRESS,
        PROP_NON_BLOCKING,
@@ -60,6 +67,7 @@ enum {
        PROP_TLS_CERTIFICATE,
        PROP_TLS_ERRORS,
        PROP_PROXY_RESOLVER,
+       PROP_CLOSE_ON_DISPOSE,
 
        LAST_PROP
 };
@@ -79,6 +87,7 @@ typedef struct {
        guint ssl_strict:1;
        guint ssl_fallback:1;
        guint clean_dispose:1;
+       guint close_on_dispose:1;
        guint use_thread_context:1;
        gpointer ssl_creds;
 
@@ -90,12 +99,15 @@ typedef struct {
        guint timeout;
 
        GCancellable *connect_cancel;
+       int fd;
 } SoupSocketPrivate;
 #define SOUP_SOCKET_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), SOUP_TYPE_SOCKET, SoupSocketPrivate))
 
 static void soup_socket_peer_certificate_changed (GObject *conn,
                                                  GParamSpec *pspec,
                                                  gpointer user_data);
+static void finish_socket_setup (SoupSocket *sock);
+static void finish_listener_setup (SoupSocket *sock);
 
 static void
 soup_socket_init (SoupSocket *sock)
@@ -103,10 +115,63 @@ soup_socket_init (SoupSocket *sock)
        SoupSocketPrivate *priv = SOUP_SOCKET_GET_PRIVATE (sock);
 
        priv->non_blocking = TRUE;
+       priv->fd = -1;
        g_mutex_init (&priv->addrlock);
        g_mutex_init (&priv->iolock);
 }
 
+static gboolean
+soup_socket_initable_init (GInitable     *initable,
+                          GCancellable  *cancellable,
+                          GError       **error)
+{
+       SoupSocket *sock = SOUP_SOCKET (initable);
+       SoupSocketPrivate *priv = SOUP_SOCKET_GET_PRIVATE (sock);
+
+       if (priv->fd != -1) {
+               guint type, len = sizeof (type);
+
+               g_warn_if_fail (priv->gsock == NULL);
+
+               /* GSocket will g_error() this, so we have to check ourselves. */
+               if (getsockopt (priv->fd, SOL_SOCKET, SO_TYPE,
+                               (gpointer)&type, (gpointer)&len) == -1) {
+                       g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+                                            "Can't import non-socket as SoupSocket");
+                       return FALSE;
+               }
+
+               priv->gsock = g_socket_new_from_fd (priv->fd, error);
+               if (!priv->gsock)
+                       return FALSE;
+       }
+
+       if (priv->gsock != NULL) {
+               int listening;
+
+               g_warn_if_fail (priv->local_addr == NULL);
+               g_warn_if_fail (priv->remote_addr == NULL);
+
+               if (!g_socket_get_option (priv->gsock,
+                                         SOL_SOCKET, SO_ACCEPTCONN,
+                                         &listening, error)) {
+                       g_prefix_error (error, _("Could not import existing socket: "));
+                       return FALSE;
+               }
+
+               finish_socket_setup (sock);
+               if (listening)
+                       finish_listener_setup (sock);
+               else if (!g_socket_is_connected (priv->gsock)) {
+                       g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+                                            _("Can't import unconnected socket"));
+                       return FALSE;
+               }
+       }
+
+       return TRUE;
+}
+
 static void
 disconnect_internal (SoupSocket *sock, gboolean close)
 {
@@ -136,7 +201,7 @@ soup_socket_finalize (GObject *object)
                        g_warning ("Disposing socket %p during connect", object);
                g_object_unref (priv->connect_cancel);
        }
-       if (priv->gsock) {
+       if (priv->gsock && priv->close_on_dispose) {
                if (priv->clean_dispose)
                        g_warning ("Disposing socket %p while still connected", object);
                disconnect_internal (SOUP_SOCKET (object), TRUE);
@@ -165,10 +230,11 @@ soup_socket_finalize (GObject *object)
        G_OBJECT_CLASS (soup_socket_parent_class)->finalize (object);
 }
 
-
 static void
-finish_socket_setup (SoupSocketPrivate *priv)
+finish_socket_setup (SoupSocket *sock)
 {
+       SoupSocketPrivate *priv = SOUP_SOCKET_GET_PRIVATE (sock);
+
        if (!priv->gsock)
                return;
 
@@ -192,11 +258,17 @@ soup_socket_set_property (GObject *object, guint prop_id,
        SoupSocketPrivate *priv = SOUP_SOCKET_GET_PRIVATE (object);
 
        switch (prop_id) {
+       case PROP_FD:
+               priv->fd = g_value_get_int (value);
+               break;
+       case PROP_GSOCKET:
+               priv->gsock = g_value_dup_object (value);
+               break;
        case PROP_LOCAL_ADDRESS:
-               priv->local_addr = (SoupAddress *)g_value_dup_object (value);
+               priv->local_addr = g_value_dup_object (value);
                break;
        case PROP_REMOTE_ADDRESS:
-               priv->remote_addr = (SoupAddress *)g_value_dup_object (value);
+               priv->remote_addr = g_value_dup_object (value);
                break;
        case PROP_NON_BLOCKING:
                priv->non_blocking = g_value_get_boolean (value);
@@ -229,6 +301,9 @@ soup_socket_set_property (GObject *object, guint prop_id,
        case PROP_CLEAN_DISPOSE:
                priv->clean_dispose = g_value_get_boolean (value);
                break;
+       case PROP_CLOSE_ON_DISPOSE:
+               priv->close_on_dispose = g_value_get_boolean (value);
+               break;
        default:
                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
                break;
@@ -242,6 +317,9 @@ soup_socket_get_property (GObject *object, guint prop_id,
        SoupSocketPrivate *priv = SOUP_SOCKET_GET_PRIVATE (object);
 
        switch (prop_id) {
+       case PROP_FD:
+               g_value_set_int (value, priv->fd);
+               break;
        case PROP_LOCAL_ADDRESS:
                g_value_set_object (value, soup_socket_get_local_address (SOUP_SOCKET (object)));
                break;
@@ -287,6 +365,9 @@ soup_socket_get_property (GObject *object, guint prop_id,
        case PROP_PROXY_RESOLVER:
                g_value_set_object (value, priv->proxy_resolver);
                break;
+       case PROP_CLOSE_ON_DISPOSE:
+               g_value_set_boolean (value, priv->close_on_dispose);
+               break;
        default:
                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
                break;
@@ -400,6 +481,21 @@ soup_socket_class_init (SoupSocketClass *socket_class)
 
 
        /* properties */
+       g_object_class_install_property (
+                object_class, PROP_FD,
+                g_param_spec_int (SOUP_SOCKET_FD,
+                                  "FD",
+                                  "The socket's file descriptor",
+                                  -1, G_MAXINT, -1,
+                                  G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+       g_object_class_install_property (
+                object_class, PROP_GSOCKET,
+                g_param_spec_object (SOUP_SOCKET_GSOCKET,
+                                     "GSocket",
+                                     "The socket's underlying GSocket",
+                                     G_TYPE_SOCKET,
+                                     G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
+
        /**
         * SOUP_SOCKET_LOCAL_ADDRESS:
         *
@@ -466,8 +562,18 @@ soup_socket_class_init (SoupSocketClass *socket_class)
        /**
         * SOUP_SOCKET_IS_SERVER:
         *
-        * Alias for the #SoupSocket:is-server property. (Whether or
-        * not the socket is a server socket.)
+        * Alias for the #SoupSocket:is-server property, qv.
+        **/
+       /**
+        * SoupSocket:is-server:
+        *
+        * Whether or not the socket is a server socket.
+        *
+        * Note that for "ordinary" #SoupSockets this will be set for
+        * both listening sockets and the sockets emitted by
+        * #SoupSocket::new-connection, but for sockets created by
+        * setting #SoupSocket:fd, it will only be set for listening
+        * sockets.
         **/
        g_object_class_install_property (
                object_class, PROP_IS_SERVER,
@@ -628,6 +734,20 @@ soup_socket_class_init (SoupSocketClass *socket_class)
                                     "GProxyResolver to use",
                                     G_TYPE_PROXY_RESOLVER,
                                     G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+
+       g_object_class_install_property (
+               object_class, PROP_CLOSE_ON_DISPOSE,
+               g_param_spec_boolean (SOUP_SOCKET_CLOSE_ON_DISPOSE,
+                                     "Close socket on disposal",
+                                     "Whether the socket is closed on disposal",
+                                     TRUE,
+                                     G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+}
+
+static void
+soup_socket_initable_interface_init (GInitableIface *initable_interface)
+{
+       initable_interface->init = soup_socket_initable_init;
 }
 
 
@@ -677,7 +797,7 @@ socket_connect_finish (SoupSocket *sock, GSocketConnection *conn)
        if (conn) {
                priv->conn = (GIOStream *)conn;
                priv->gsock = g_object_ref (g_socket_connection_get_socket (conn));
-               finish_socket_setup (priv);
+               finish_socket_setup (sock);
                return TRUE;
        } else
                return FALSE;
@@ -996,11 +1116,12 @@ listen_watch (GObject *pollable, gpointer data)
                new_priv->async_context = g_main_context_ref (priv->async_context);
        new_priv->use_thread_context = priv->use_thread_context;
        new_priv->non_blocking = priv->non_blocking;
+       new_priv->clean_dispose = priv->clean_dispose;
        new_priv->is_server = TRUE;
        new_priv->ssl = priv->ssl;
        if (priv->ssl_creds)
                new_priv->ssl_creds = priv->ssl_creds;
-       finish_socket_setup (new_priv);
+       finish_socket_setup (new);
 
        if (new_priv->ssl_creds) {
                if (!soup_socket_start_proxy_ssl (new, NULL, NULL)) {
@@ -1015,6 +1136,17 @@ listen_watch (GObject *pollable, gpointer data)
        return TRUE;
 }
 
+static void
+finish_listener_setup (SoupSocket *sock)
+{
+       SoupSocketPrivate *priv = SOUP_SOCKET_GET_PRIVATE (sock);
+
+       priv->is_server = TRUE;
+       priv->watch_src = soup_socket_create_watch (priv, G_IO_IN,
+                                                   listen_watch, sock,
+                                                   NULL);
+}
+
 /**
  * soup_socket_listen:
  * @sock: a server #SoupSocket (which must not already be connected or
@@ -1037,8 +1169,6 @@ soup_socket_listen (SoupSocket *sock)
        g_return_val_if_fail (priv->gsock == NULL, FALSE);
        g_return_val_if_fail (priv->local_addr != NULL, FALSE);
 
-       priv->is_server = TRUE;
-
        /* @local_addr may have its port set to 0. So we intentionally
         * don't store it in priv->local_addr, so that if the
         * caller calls soup_socket_get_local_address() later, we'll
@@ -1054,7 +1184,7 @@ soup_socket_listen (SoupSocket *sock)
                                    NULL);
        if (!priv->gsock)
                goto cant_listen;
-       finish_socket_setup (priv);
+       finish_socket_setup (sock);
 
        /* Bind */
        if (!g_socket_bind (priv->gsock, addr, TRUE, NULL))
@@ -1066,10 +1196,8 @@ soup_socket_listen (SoupSocket *sock)
        /* Listen */
        if (!g_socket_listen (priv->gsock, NULL))
                goto cant_listen;
+       finish_listener_setup (sock);
 
-       priv->watch_src = soup_socket_create_watch (priv, G_IO_IN,
-                                                   listen_watch, sock,
-                                                   NULL);
        g_object_unref (addr);
        return TRUE;
 
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 21c70d4..23a19a5 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -6,4 +6,5 @@ libsoup/soup-message-io.c
 libsoup/soup-message-server-io.c
 libsoup/soup-request.c
 libsoup/soup-session.c
+libsoup/soup-socket.c
 libsoup/soup-tld.c
diff --git a/tests/socket-test.c b/tests/socket-test.c
index 5bcc3b0..821b1a2 100644
--- a/tests/socket-test.c
+++ b/tests/socket-test.c
@@ -5,7 +5,9 @@
  */
 
 #include "test-utils.h"
+#include "libsoup/soup-socket-private.h"
 
+#include <fcntl.h>
 #include <gio/gnetworking.h>
 
 static void
@@ -108,6 +110,232 @@ do_unconnected_socket_test (void)
        g_object_unref (sock);
 }
 
+static void
+do_socket_from_fd_client_test (void)
+{
+       SoupServer *server;
+       GSocket *gsock;
+       SoupSocket *sock;
+       SoupAddress *local, *remote;
+       GSocketAddress *gaddr;
+       gboolean is_server;
+       int type;
+       GError *error = NULL;
+
+       server = soup_test_server_new (FALSE);
+
+       gsock = g_socket_new (G_SOCKET_FAMILY_IPV4,
+                             G_SOCKET_TYPE_STREAM,
+                             G_SOCKET_PROTOCOL_DEFAULT,
+                             &error);
+       g_assert_no_error (error);
+
+       gaddr = g_inet_socket_address_new_from_string ("127.0.0.1", soup_server_get_port (server));
+       g_socket_connect (gsock, gaddr, NULL, &error);
+       g_object_unref (gaddr);
+       g_assert_no_error (error);
+       g_assert_true (g_socket_is_connected (gsock));
+
+       gaddr = g_socket_get_local_address (gsock, &error);
+       g_assert_no_error (error);
+
+       sock = g_initable_new (SOUP_TYPE_SOCKET, NULL, &error,
+                              SOUP_SOCKET_FD, g_socket_get_fd (gsock),
+                              SOUP_SOCKET_CLOSE_ON_DISPOSE, FALSE,
+                              NULL);
+       g_assert_no_error (error);
+       g_assert_nonnull (sock);
+
+       g_object_get (G_OBJECT (sock),
+                     SOUP_SOCKET_LOCAL_ADDRESS, &local,
+                     SOUP_SOCKET_REMOTE_ADDRESS, &remote,
+                     SOUP_SOCKET_IS_SERVER, &is_server,
+                     NULL);
+       g_assert_cmpint (soup_socket_get_fd (sock), ==, g_socket_get_fd (gsock));
+       g_assert_false (is_server);
+       g_assert_true (soup_socket_is_connected (sock));
+
+       g_assert_cmpstr (soup_address_get_physical (local), ==, "127.0.0.1");
+       g_assert_cmpint (soup_address_get_port (local), ==, g_inet_socket_address_get_port 
(G_INET_SOCKET_ADDRESS (gaddr)));
+       g_assert_cmpstr (soup_address_get_physical (remote), ==, "127.0.0.1");
+       g_assert_cmpint (soup_address_get_port (remote), ==, soup_server_get_port (server));
+
+       g_object_unref (local);
+       g_object_unref (remote);
+       g_object_unref (gaddr);
+
+       g_object_unref (sock);
+       /* We specified close-on-dispose=FALSE */
+       g_socket_get_option (gsock, SOL_SOCKET, SO_TYPE, &type, &error);
+       g_assert_no_error (error);
+
+       g_object_unref (gsock);
+
+       g_object_unref (server);
+}
+
+static void
+do_socket_from_fd_server_test (void)
+{
+       GSocket *gsock;
+       SoupSocket *sock;
+       SoupAddress *local;
+       GSocketAddress *gaddr;
+       gboolean is_server;
+       GError *error = NULL;
+
+       gsock = g_socket_new (G_SOCKET_FAMILY_IPV4,
+                             G_SOCKET_TYPE_STREAM,
+                             G_SOCKET_PROTOCOL_DEFAULT,
+                             &error);
+       g_assert_no_error (error);
+
+       gaddr = g_inet_socket_address_new_from_string ("127.0.0.1", 0);
+       g_socket_bind (gsock, gaddr, TRUE, &error);
+       g_object_unref (gaddr);
+       g_assert_no_error (error);
+       g_socket_listen (gsock, &error);
+       g_assert_no_error (error);
+       g_assert_false (g_socket_is_connected (gsock));
+
+       gaddr = g_socket_get_local_address (gsock, &error);
+       g_assert_no_error (error);
+
+       sock = g_initable_new (SOUP_TYPE_SOCKET, NULL, &error,
+                              SOUP_SOCKET_GSOCKET, gsock,
+                              NULL);
+       g_assert_no_error (error);
+       g_assert_nonnull (sock);
+
+       g_object_get (G_OBJECT (sock),
+                     SOUP_SOCKET_LOCAL_ADDRESS, &local,
+                     SOUP_SOCKET_IS_SERVER, &is_server,
+                     NULL);
+       g_assert_cmpint (soup_socket_get_fd (sock), ==, g_socket_get_fd (gsock));
+       g_assert_true (is_server);
+       g_assert_true (soup_socket_is_connected (sock));
+
+       g_assert_cmpstr (soup_address_get_physical (local), ==, "127.0.0.1");
+       g_assert_cmpint (soup_address_get_port (local), ==, g_inet_socket_address_get_port 
(G_INET_SOCKET_ADDRESS (gaddr)));
+       g_object_unref (local);
+
+       g_object_unref (sock);
+
+       /* Closing the SoupSocket should have closed the GSocket */
+       g_assert_true (g_socket_is_closed (gsock));
+
+       g_object_unref (gsock);
+}
+
+static void
+do_socket_from_fd_bad_test (void)
+{
+       GSocket *gsock, *gsock2, *gsockcli;
+       SoupSocket *sock, *sock2;
+       SoupAddress *local, *remote;
+       GSocketAddress *gaddr;
+       gboolean is_server;
+       int fd;
+       GError *error = NULL;
+
+       /* Importing a non-socket fd gives an error */
+       fd = open (g_test_get_filename (G_TEST_DIST, "test-cert.pem", NULL), O_RDONLY);
+       g_assert_cmpint (fd, !=, -1);
+
+       sock = g_initable_new (SOUP_TYPE_SOCKET, NULL, &error,
+                              SOUP_SOCKET_FD, fd,
+                              NULL);
+       g_assert_error (error, G_IO_ERROR, G_IO_ERROR_FAILED);
+       g_clear_error (&error);
+       g_assert_null (sock);
+       close (fd);
+
+       /* Importing an unconnected socket gives an error */
+       gsock = g_socket_new (G_SOCKET_FAMILY_IPV4,
+                             G_SOCKET_TYPE_STREAM,
+                             G_SOCKET_PROTOCOL_DEFAULT,
+                             &error);
+       g_assert_no_error (error);
+       g_assert_false (g_socket_is_connected (gsock));
+
+       sock = g_initable_new (SOUP_TYPE_SOCKET, NULL, &error,
+                              SOUP_SOCKET_FD, g_socket_get_fd (gsock),
+                              NULL);
+       g_assert_error (error, G_IO_ERROR, G_IO_ERROR_FAILED);
+       g_clear_error (&error);
+       g_assert_null (sock);
+       g_object_unref (gsock);
+
+       /* Importing a non-listening server-side socket works, but
+        * gives the wrong answer for soup_socket_is_server().
+        */
+       gsock = g_socket_new (G_SOCKET_FAMILY_IPV4,
+                             G_SOCKET_TYPE_STREAM,
+                             G_SOCKET_PROTOCOL_DEFAULT,
+                             &error);
+       g_assert_no_error (error);
+
+       gaddr = g_inet_socket_address_new_from_string ("127.0.0.1", 0);
+       g_socket_bind (gsock, gaddr, TRUE, &error);
+       g_object_unref (gaddr);
+       g_assert_no_error (error);
+       g_socket_listen (gsock, &error);
+       g_assert_no_error (error);
+       g_assert_false (g_socket_is_connected (gsock));
+
+       gaddr = g_socket_get_local_address (gsock, &error);
+       g_assert_no_error (error);
+
+       gsockcli = g_socket_new (G_SOCKET_FAMILY_IPV4,
+                                G_SOCKET_TYPE_STREAM,
+                                G_SOCKET_PROTOCOL_DEFAULT,
+                                &error);
+       g_assert_no_error (error);
+
+       g_socket_connect (gsockcli, gaddr, NULL, &error);
+       g_assert_no_error (error);
+       g_assert_true (g_socket_is_connected (gsockcli));
+       
+       gsock2 = g_socket_accept (gsock, NULL, &error);
+       g_assert_no_error (error);
+       g_assert_nonnull (gsock2);
+
+       sock2 = g_initable_new (SOUP_TYPE_SOCKET, NULL, &error,
+                               SOUP_SOCKET_GSOCKET, gsock2,
+                               NULL);
+       g_assert_no_error (error);
+       g_assert_nonnull (sock2);
+
+       g_object_get (G_OBJECT (sock2),
+                     SOUP_SOCKET_LOCAL_ADDRESS, &local,
+                     SOUP_SOCKET_REMOTE_ADDRESS, &remote,
+                     SOUP_SOCKET_IS_SERVER, &is_server,
+                     NULL);
+       g_assert_cmpint (soup_socket_get_fd (sock2), ==, g_socket_get_fd (gsock2));
+       g_assert_true (soup_socket_is_connected (sock2));
+       /* This is wrong, but can't be helped. */
+       g_assert_false (is_server);
+
+       g_assert_cmpstr (soup_address_get_physical (local), ==, "127.0.0.1");
+       g_assert_cmpint (soup_address_get_port (local), ==, g_inet_socket_address_get_port 
(G_INET_SOCKET_ADDRESS (gaddr)));
+       g_object_unref (gaddr);
+
+       gaddr = g_socket_get_local_address (gsockcli, &error);
+       g_assert_no_error (error);
+       g_assert_cmpstr (soup_address_get_physical (remote), ==, "127.0.0.1");
+       g_assert_cmpint (soup_address_get_port (remote), ==, g_inet_socket_address_get_port 
(G_INET_SOCKET_ADDRESS (gaddr)));
+       g_object_unref (gaddr);
+
+       g_object_unref (local);
+       g_object_unref (remote);
+
+       g_object_unref (sock2);
+
+       g_object_unref (gsock);
+       g_object_unref (gsock2);
+       g_object_unref (gsockcli);
+}
+
 int
 main (int argc, char **argv)
 {
@@ -116,6 +344,9 @@ main (int argc, char **argv)
        test_init (argc, argv, NULL);
 
        g_test_add_func ("/sockets/unconnected", do_unconnected_socket_test);
+       g_test_add_func ("/sockets/from-fd/client", do_socket_from_fd_client_test);
+       g_test_add_func ("/sockets/from-fd/server", do_socket_from_fd_server_test);
+       g_test_add_func ("/sockets/from-fd/bad", do_socket_from_fd_bad_test);
 
        ret = g_test_run ();
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]