[glib: 10/12] gio: tests AF_UNIX socket credentials on win32




commit e796124b31aa6cf07ba0b34de5626fd20ea3fa58
Author: Marc-André Lureau <marcandre lureau redhat com>
Date:   Wed Jan 19 20:39:59 2022 +0400

    gio: tests AF_UNIX socket credentials on win32
    
    Signed-off-by: Marc-André Lureau <marcandre lureau redhat com>

 gio/tests/socket.c | 122 ++++++++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 117 insertions(+), 5 deletions(-)
---
diff --git a/gio/tests/socket.c b/gio/tests/socket.c
index 6f6553d6d..250ec648a 100644
--- a/gio/tests/socket.c
+++ b/gio/tests/socket.c
@@ -2102,7 +2102,118 @@ client_setup_thread (gpointer user_data)
   return NULL;
 }
 
-#ifdef G_OS_UNIX
+#ifdef G_OS_WIN32
+/*
+ * _g_win32_socketpair:
+ *
+ * Create a pair of connected sockets, similar to POSIX/BSD socketpair().
+ *
+ * Windows does not (yet) provide a socketpair() function. However, since the
+ * introduction of AF_UNIX sockets, it is possible to implement a fairly close
+ * function.
+ */
+static gint
+_g_win32_socketpair (gint            domain,
+                     gint            type,
+                     gint            protocol,
+                     gint            sv[2])
+{
+  struct sockaddr_un addr = { 0, };
+  socklen_t socklen;
+  SOCKET listener = INVALID_SOCKET;
+  SOCKET client = INVALID_SOCKET;
+  SOCKET server = INVALID_SOCKET;
+  gchar *path = NULL;
+  int tmpfd, rv = -1;
+  u_long arg, br;
+
+  g_return_val_if_fail (sv != NULL, -1);
+
+  addr.sun_family = AF_UNIX;
+  socklen = sizeof (addr);
+
+  tmpfd = g_file_open_tmp (NULL, &path, NULL);
+  if (tmpfd == -1)
+    {
+      WSASetLastError (WSAEACCES);
+      goto out;
+    }
+
+  g_close (tmpfd, NULL);
+
+  if (strlen (path) >= sizeof (addr.sun_path))
+    {
+      WSASetLastError (WSAEACCES);
+      goto out;
+    }
+
+  strncpy (addr.sun_path, path, sizeof (addr.sun_path) - 1);
+
+  listener = socket (domain, type, protocol);
+  if (listener == INVALID_SOCKET)
+    goto out;
+
+  if (DeleteFile (path) == 0)
+    {
+      if (GetLastError () != ERROR_FILE_NOT_FOUND)
+        goto out;
+    }
+
+  if (bind (listener, (struct sockaddr *) &addr, socklen) == SOCKET_ERROR)
+    goto out;
+
+  if (listen (listener, 1) == SOCKET_ERROR)
+    goto out;
+
+  client = socket (domain, type, protocol);
+  if (client == INVALID_SOCKET)
+    goto out;
+
+  arg = 1;
+  if (ioctlsocket (client, FIONBIO, &arg) == SOCKET_ERROR)
+    goto out;
+
+  if (connect (client, (struct sockaddr *) &addr, socklen) == SOCKET_ERROR &&
+      WSAGetLastError () != WSAEWOULDBLOCK)
+    goto out;
+
+  server = accept (listener, NULL, NULL);
+  if (server == INVALID_SOCKET)
+    goto out;
+
+  arg = 0;
+  if (ioctlsocket (client, FIONBIO, &arg) == SOCKET_ERROR)
+    goto out;
+
+  if (WSAIoctl (server, SIO_AF_UNIX_GETPEERPID,
+                NULL, 0U,
+                &arg, sizeof (arg), &br,
+                NULL, NULL) == SOCKET_ERROR || arg != GetCurrentProcessId ())
+    {
+      WSASetLastError (WSAEACCES);
+      goto out;
+    }
+
+  sv[0] = server;
+  server = INVALID_SOCKET;
+  sv[1] = client;
+  client = INVALID_SOCKET;
+  rv = 0;
+
+ out:
+  if (listener != INVALID_SOCKET)
+    closesocket (listener);
+  if (client != INVALID_SOCKET)
+    closesocket (client);
+  if (server != INVALID_SOCKET)
+    closesocket (server);
+
+  DeleteFile (path);
+  g_free (path);
+  return rv;
+}
+#endif /* G_OS_WIN32 */
+
 static void
 test_credentials_unix_socketpair (void)
 {
@@ -2112,7 +2223,11 @@ test_credentials_unix_socketpair (void)
   GError *error = NULL;
   GCredentials *creds;
 
+#ifdef G_OS_WIN32
+  status = _g_win32_socketpair (PF_UNIX, SOCK_STREAM, 0, fds);
+#else
   status = socketpair (PF_UNIX, SOCK_STREAM, 0, fds);
+#endif
   g_assert_cmpint (status, ==, 0);
 
   sock = g_socket_new_from_fd (fds[0], &error);
@@ -2133,10 +2248,9 @@ test_credentials_unix_socketpair (void)
     }
 
   g_object_unref (sock);
-  close (fds[1]);
+  g_close (fds[1], NULL);
 }
 #endif
-#endif
 
 int
 main (int   argc,
@@ -2199,9 +2313,7 @@ main (int   argc,
 #if G_CREDENTIALS_SUPPORTED
   g_test_add_func ("/socket/credentials/tcp_client", test_credentials_tcp_client);
   g_test_add_func ("/socket/credentials/tcp_server", test_credentials_tcp_server);
-#ifdef G_OS_UNIX
   g_test_add_func ("/socket/credentials/unix_socketpair", test_credentials_unix_socketpair);
-#endif
 #endif
 
   return g_test_run();


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