Windows 10 [received support](https://devblogs.microsoft.com/commandline/af_unix-comes-to-windows/) for AF_UNIX sockets in Insider Build 17063. This merge request adds basic support for AF_UNIX sockets to ws2_32 and wineserver.
Of particular note is the difficulty in handling `sun_path`. Most of the functions that allow for translating Windows paths to Unix paths are not accessible from ws2_32. I considered the following options: * Pass the Windows path to wineserver and do the conversion there. * This is, as far as I can tell, not possible without major rearchitecting. wineserver does not have functions to translate Windows paths to Unix paths, for obvious reasons. * Obtain the current working directory of the requesting process and temporarily change directories to there. * This only handles relative paths and fails for absolute paths, UNC paths, etc. * Conditionally change directories based on whether the path is relative or not. * This is error-prone and wineserver does not have the requisite functions to do this cleanly.
I ultimately decided to pass the translated Unix path to wineserver, which changes directories to `dirname(path)`. It then provides `bind` and `connect` with `basename(path)`. This is not threadsafe, but wineserver is not (currently) multithreaded.
Abstract sockets are not fully supported by this patch, matching the behavior of Windows.
-- v67: ws2_32/tests: Add test for AF_UNIX sockets. server: Fix getsockname() and accept() on AF_UNIX sockets. server: Introduce error when attempting to create a SOCK_DGRAM AF_UNIX socket. server: Allow for deletion of socket files. ws2_32: Add support for AF_UNIX sockets. ws2_32: Add afunix.h header.
From: Ally Sommers dropbear.sh@gmail.com
This header is needed for support of AF_UNIX sockets. --- include/Makefile.in | 1 + include/afunix.h | 38 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+) create mode 100644 include/afunix.h
diff --git a/include/Makefile.in b/include/Makefile.in index 80c380d993c..540101569d0 100644 --- a/include/Makefile.in +++ b/include/Makefile.in @@ -12,6 +12,7 @@ SOURCES = \ adshlp.h \ advpub.h \ af_irda.h \ + afunix.h \ amaudio.h \ amsi.idl \ amstream.idl \ diff --git a/include/afunix.h b/include/afunix.h new file mode 100644 index 00000000000..8118dda271b --- /dev/null +++ b/include/afunix.h @@ -0,0 +1,38 @@ +/* + * Copyright 2023 Ally Sommers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _WS2AFUNIX_ +#define _WS2AFUNIX_ + +#include "windef.h" +#include "ws2def.h" + +#ifdef USE_WS_PREFIX +# define WS(x) WS_##x +#else +# define WS(x) x +#endif + +#define UNIX_PATH_MAX 108 + +typedef struct WS(sockaddr_un) { + USHORT sun_family; + char sun_path[UNIX_PATH_MAX]; +} SOCKADDR_UN, *PSOCKADDR_UN; + +#endif /* _WS2AFUNIX_ */ \ No newline at end of file
From: Ally Sommers dropbear.sh@gmail.com
This commit additionally modifies wineserver's sock_ioctl to handle the provided pathname by changing directories and then returning after the native call. This is NOT threadsafe, but wineserver is not multithreaded. --- dlls/ntdll/unix/socket.c | 4 + dlls/ws2_32/socket.c | 83 +++++++++++++++++-- dlls/ws2_32/ws2_32_private.h | 13 +++ server/sock.c | 152 ++++++++++++++++++++++++++++++++--- 4 files changed, 238 insertions(+), 14 deletions(-)
diff --git a/dlls/ntdll/unix/socket.c b/dlls/ntdll/unix/socket.c index 65f30759db3..f122e74b143 100644 --- a/dlls/ntdll/unix/socket.c +++ b/dlls/ntdll/unix/socket.c @@ -67,6 +67,8 @@ # define HAS_IRDA #endif
+#include <sys/un.h> + #include "ntstatus.h" #define WIN32_NO_STATUS #include "windef.h" @@ -78,6 +80,7 @@ #include "ws2tcpip.h" #include "wsipx.h" #include "af_irda.h" +#include "afunix.h" #include "wine/afd.h"
#include "unix_private.h" @@ -106,6 +109,7 @@ union unix_sockaddr #ifdef HAS_IRDA struct sockaddr_irda irda; #endif + struct sockaddr_un un; };
struct async_recv_ioctl diff --git a/dlls/ws2_32/socket.c b/dlls/ws2_32/socket.c index eb84558cbac..c2521d7645f 100644 --- a/dlls/ws2_32/socket.c +++ b/dlls/ws2_32/socket.c @@ -167,6 +167,19 @@ static const WSAPROTOCOL_INFOW supported_protocols[] = .dwMessageSize = UINT_MAX, .szProtocol = L"SPX II", }, + { + .dwServiceFlags1 = XP1_GUARANTEED_DELIVERY | XP1_GUARANTEED_ORDER | XP1_IFS_HANDLES, + .dwProviderFlags = PFL_MATCHES_PROTOCOL_ZERO, + .ProviderId = {0xa00943d9, 0x9c2e, 0x4633, {0x9b, 0x59, 0x00, 0x57, 0xa3, 0x16, 0x09, 0x94}}, + .dwCatalogEntryId = 1007, + .ProtocolChain.ChainLen = 1, + .iVersion = 2, + .iAddressFamily = AF_UNIX, + .iMaxSockAddr = sizeof(struct sockaddr_un), + .iMinSockAddr = offsetof(struct sockaddr_un, sun_path), + .iSocketType = SOCK_STREAM, + .szProtocol = L"AF_UNIX", + }, };
DECLARE_CRITICAL_SECTION(cs_socket_list); @@ -226,6 +239,11 @@ const char *debugstr_sockaddr( const struct sockaddr *a ) addr, ((const SOCKADDR_IRDA *)a)->irdaServiceName); } + case AF_UNIX: + { + return wine_dbg_sprintf("{ family AF_UNIX, path %s }", + ((const SOCKADDR_UN *)a)->sun_path); + } default: return wine_dbg_sprintf("{ family %d }", a->sa_family); } @@ -1106,6 +1124,10 @@ int WINAPI bind( SOCKET s, const struct sockaddr *addr, int len ) HANDLE sync_event; NTSTATUS status;
+ const int bind_len = len; + char *unix_path = NULL; + int unix_varargs_size = 0; + TRACE( "socket %#Ix, addr %s\n", s, debugstr_sockaddr(addr) );
if (!addr) @@ -1148,6 +1170,14 @@ int WINAPI bind( SOCKET s, const struct sockaddr *addr, int len ) } break;
+ case AF_UNIX: + if (len < offsetof(struct sockaddr_un, sun_path)) + { + SetLastError( WSAEFAULT ); + return -1; + } + break; + default: FIXME( "unknown protocol %u\n", addr->sa_family ); SetLastError( WSAEAFNOSUPPORT ); @@ -1156,7 +1186,29 @@ int WINAPI bind( SOCKET s, const struct sockaddr *addr, int len )
if (!(sync_event = get_sync_event())) return -1;
- params = malloc( sizeof(int) + len ); + if (addr->sa_family == AF_UNIX && *addr->sa_data) + { + struct sockaddr_un sun = { 0 }; + WCHAR *sun_pathW; + memcpy(&sun, addr, len); + if (strlen( sun.sun_path )) + { + sun_pathW = strdupAtoW( sun.sun_path ); + unix_path = wine_get_unix_file_name( sun_pathW ); + free( sun_pathW ); + if (!unix_path) + return SOCKET_ERROR; + } + else + { + unix_path = malloc(1); + *unix_path = '\0'; + } + len = sizeof(sun); + unix_varargs_size = strlen( unix_path ); + } + + params = malloc( sizeof(int) + len + unix_varargs_size ); ret_addr = malloc( len ); if (!params || !ret_addr) { @@ -1166,10 +1218,14 @@ int WINAPI bind( SOCKET s, const struct sockaddr *addr, int len ) return -1; } params->unknown = 0; - memcpy( ¶ms->addr, addr, len ); + if (addr->sa_family == AF_UNIX) + memset( ¶ms->addr, 0, len ); + memcpy( ¶ms->addr, addr, bind_len ); + if (unix_path) + memcpy( (char *)¶ms->addr + len, unix_path, unix_varargs_size );
status = NtDeviceIoControlFile( (HANDLE)s, sync_event, NULL, NULL, &io, IOCTL_AFD_BIND, - params, sizeof(int) + len, ret_addr, len ); + params, sizeof(int) + len + unix_varargs_size, ret_addr, len ); if (status == STATUS_PENDING) { if (WaitForSingleObject( sync_event, INFINITE ) == WAIT_FAILED) @@ -1182,6 +1238,7 @@ int WINAPI bind( SOCKET s, const struct sockaddr *addr, int len )
free( params ); free( ret_addr ); + free( unix_path );
SetLastError( NtStatusToWSAError( status ) ); return status ? -1 : 0; @@ -1222,11 +1279,24 @@ int WINAPI connect( SOCKET s, const struct sockaddr *addr, int len ) HANDLE sync_event; NTSTATUS status;
+ char *unix_path = NULL; + int unix_varargs_size = 0; + TRACE( "socket %#Ix, addr %s, len %d\n", s, debugstr_sockaddr(addr), len );
if (!(sync_event = get_sync_event())) return -1;
- if (!(params = malloc( sizeof(*params) + len ))) + if (addr->sa_family == AF_UNIX && *addr->sa_data) + { + WCHAR *sun_pathW = strdupAtoW(addr->sa_data); + unix_path = wine_get_unix_file_name(sun_pathW); + free(sun_pathW); + if (!unix_path) + return SOCKET_ERROR; + unix_varargs_size = strlen(unix_path); + } + + if (!(params = malloc( sizeof(*params) + len + unix_varargs_size ))) { SetLastError( ERROR_NOT_ENOUGH_MEMORY ); return -1; @@ -1234,10 +1304,13 @@ int WINAPI connect( SOCKET s, const struct sockaddr *addr, int len ) params->addr_len = len; params->synchronous = TRUE; memcpy( params + 1, addr, len ); + if (unix_path) + memcpy( (char *)(params + 1) + len, unix_path, unix_varargs_size );
status = NtDeviceIoControlFile( (HANDLE)s, sync_event, NULL, NULL, &io, IOCTL_AFD_WINE_CONNECT, - params, sizeof(*params) + len, NULL, 0 ); + params, sizeof(*params) + len + unix_varargs_size, NULL, 0 ); free( params ); + free( unix_path ); if (status == STATUS_PENDING) { if (wait_event_alertable( sync_event ) == WAIT_FAILED) return -1; diff --git a/dlls/ws2_32/ws2_32_private.h b/dlls/ws2_32/ws2_32_private.h index 9e116de814d..5708ae60d91 100644 --- a/dlls/ws2_32/ws2_32_private.h +++ b/dlls/ws2_32/ws2_32_private.h @@ -44,6 +44,7 @@ #include "mstcpip.h" #include "af_irda.h" #include "winnt.h" +#include "afunix.h" #define USE_WC_PREFIX /* For CMSG_DATA */ #include "iphlpapi.h" #include "ip2string.h" @@ -71,6 +72,18 @@ static inline char *strdupWtoA( const WCHAR *str ) return ret; }
+static inline WCHAR *strdupAtoW( const char *str ) +{ + WCHAR *ret = NULL; + if (str) + { + DWORD len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0); + if ((ret = malloc( len * sizeof(WCHAR) ))) + MultiByteToWideChar(CP_ACP, 0, str, -1, ret, len); + } + return ret; +} + static const char magic_loopback_addr[] = {127, 12, 34, 56};
const char *debugstr_sockaddr( const struct sockaddr *addr ); diff --git a/server/sock.c b/server/sock.c index 8a95caded8b..5d7dd2b750e 100644 --- a/server/sock.c +++ b/server/sock.c @@ -84,6 +84,8 @@ # define HAS_IRDA #endif
+#include <sys/un.h> + #include "ntstatus.h" #define WIN32_NO_STATUS #include "windef.h" @@ -94,6 +96,7 @@ #include "ws2tcpip.h" #include "wsipx.h" #include "af_irda.h" +#include "afunix.h" #include "wine/afd.h" #include "wine/rbtree.h"
@@ -117,6 +120,7 @@ union win_sockaddr struct WS_sockaddr_in6 in6; struct WS_sockaddr_ipx ipx; SOCKADDR_IRDA irda; + struct WS_sockaddr_un un; };
union unix_sockaddr @@ -130,6 +134,7 @@ union unix_sockaddr #ifdef HAS_IRDA struct sockaddr_irda irda; #endif + struct sockaddr_un un; };
static struct list poll_list = LIST_INIT( poll_list ); @@ -677,6 +682,9 @@ static socklen_t get_unix_sockaddr_any( union unix_sockaddr *uaddr, int ws_famil uaddr->irda.sir_family = AF_IRDA; return sizeof(uaddr->irda); #endif + case WS_AF_UNIX: + uaddr->un.sun_family = AF_UNIX; + return sizeof(uaddr->un); default: return 0; } @@ -1777,6 +1785,7 @@ static int get_unix_family( int family ) #ifdef AF_IRDA case WS_AF_IRDA: return AF_IRDA; #endif + case WS_AF_UNIX: return AF_UNIX; case WS_AF_UNSPEC: return AF_UNSPEC; default: return -1; } @@ -2573,8 +2582,13 @@ static void sock_ioctl( struct fd *fd, ioctl_code_t code, struct async *async )
if (listen( unix_fd, params->backlog ) < 0) { - set_error( sock_get_ntstatus( errno ) ); - return; + /* Due to the way we handle the Windows AF_UNIX bind edge case, we also need to + * ignore listen's error. */ + if (!(errno == EINVAL && sock->family == WS_AF_UNIX && !*sock->addr.un.sun_path)) + { + set_error( sock_get_ntstatus( errno ) ); + return; + } }
sock->state = SOCK_LISTENING; @@ -2644,7 +2658,55 @@ static void sock_ioctl( struct fd *fd, ioctl_code_t code, struct async *async ) break; }
- unix_len = sockaddr_to_unix( addr, params->addr_len, &unix_addr ); + if (sock->family == WS_AF_UNIX) + { + if (*addr->sa_data) + { + int unix_path_len = get_req_data_size() - sizeof(*params) - params->addr_len; + char *unix_path; + char *base_name; + + if (!(unix_path = mem_alloc( unix_path_len + 1 ))) + return; + + memcpy( unix_path, (char *)(params + 1) + params->addr_len, unix_path_len ); + unix_path[unix_path_len] = '\0'; + + base_name = strrchr(unix_path, '/'); + if (base_name) + { + if (base_name != unix_path) + (++base_name)[-1] = '\0'; + } + else + base_name = unix_path; + + if (chdir( unix_path ) == -1) + { + set_error( sock_get_ntstatus( errno ) ); + free( unix_path ); + return; + } + + send_len -= unix_path_len; + unix_len = sizeof(unix_addr.un); + memset( &unix_addr.un, 0, sizeof(unix_addr.un) ); + unix_addr.un.sun_family = AF_UNIX; + memcpy( unix_addr.un.sun_path, base_name, strlen( base_name ) ); + free( unix_path ); + } + else + { + /* Contrary to documentation, Windows does not currently support abstract Unix + * sockets. connect() throws WSAEINVAL if sun_family is AF_UNIX and sun_path + * begins with '\0', even though bind() will succeed. */ + set_win32_error( WSAEINVAL ); + return; + } + } + else + unix_len = sockaddr_to_unix( addr, params->addr_len, &unix_addr ); + if (!unix_len) { set_error( STATUS_INVALID_ADDRESS ); @@ -2666,6 +2728,9 @@ static void sock_ioctl( struct fd *fd, ioctl_code_t code, struct async *async ) ret = connect( unix_fd, &unix_addr.addr, unix_len ); }
+ if (sock->family == WS_AF_UNIX && *addr->sa_data) + fchdir(server_dir_fd); + if (ret < 0 && errno != EINPROGRESS) { set_error( sock_get_ntstatus( errno ) ); @@ -2921,6 +2986,7 @@ static void sock_ioctl( struct fd *fd, ioctl_code_t code, struct async *async ) data_size_t in_size; socklen_t unix_len; int v6only = 1; + int unix_path_len = 0;
/* the ioctl is METHOD_NEITHER, so ntdll gives us the output buffer as * input */ @@ -2930,8 +2996,10 @@ static void sock_ioctl( struct fd *fd, ioctl_code_t code, struct async *async ) return; } in_size = get_req_data_size() - get_reply_max_size(); + if (params->addr.sa_family == WS_AF_UNIX) + unix_path_len = in_size - sizeof(params->unknown) - sizeof(struct WS_sockaddr_un); if (in_size < offsetof(struct afd_bind_params, addr.sa_data) - || get_reply_max_size() < in_size - sizeof(int)) + || get_reply_max_size() < in_size - sizeof(int) - unix_path_len) { set_error( STATUS_INVALID_PARAMETER ); return; @@ -2943,7 +3011,47 @@ static void sock_ioctl( struct fd *fd, ioctl_code_t code, struct async *async ) return; }
- unix_len = sockaddr_to_unix( ¶ms->addr, in_size - sizeof(int), &unix_addr ); + if (sock->family == WS_AF_UNIX) + { + if (*params->addr.sa_data) + { + char *unix_path; + char *base_name; + + if (!(unix_path = mem_alloc( unix_path_len + 1 ))) + return; + + memcpy( unix_path, (char *)(¶ms->addr) + sizeof(struct WS_sockaddr_un), unix_path_len ); + unix_path[unix_path_len] = '\0'; + + base_name = strrchr(unix_path, '/'); + if (base_name) + { + if (base_name != unix_path) + (++base_name)[-1] = '\0'; + } + else + base_name = unix_path; + + if (chdir( unix_path ) == -1) + { + free( unix_path ); + set_error( sock_get_ntstatus( errno ) ); + return; + } + + memset( &unix_addr.un, 0, sizeof(unix_addr.un) ); + memcpy( unix_addr.un.sun_path, base_name, strlen( base_name ) ); + free( unix_path ); + } + else + memset(unix_addr.un.sun_path, 0, sizeof(unix_addr.un.sun_path)); + unix_addr.un.sun_family = AF_UNIX; + unix_len = sizeof(unix_addr.un); + } + else + unix_len = sockaddr_to_unix( ¶ms->addr, in_size - sizeof(int), &unix_addr ); + if (!unix_len) { set_error( STATUS_INVALID_ADDRESS ); @@ -2987,8 +3095,16 @@ static void sock_ioctl( struct fd *fd, ioctl_code_t code, struct async *async ) if (errno == EADDRINUSE && sock->reuseaddr) errno = EACCES;
- set_error( sock_get_ntstatus( errno ) ); - return; + /* Windows' AF_UNIX implementation has an edge case allowing for a socket to bind to + * an empty path. Linux doesn't, so it throws EINVAL. We check for this situation + * here and avoid early-exiting if it's the case. */ + if (!(errno == EINVAL && sock->family == WS_AF_UNIX && !*params->addr.sa_data)) + { + set_error( sock_get_ntstatus( errno ) ); + if (sock->family == WS_AF_UNIX && *params->addr.sa_data) + fchdir(server_dir_fd); + return; + } }
sock->bound = 1; @@ -3000,13 +3116,23 @@ static void sock_ioctl( struct fd *fd, ioctl_code_t code, struct async *async ) * actual unix address */ if (bind_addr.addr.sa_family == AF_INET) bind_addr.in.sin_addr = unix_addr.in.sin_addr; - sock->addr_len = sockaddr_from_unix( &bind_addr, &sock->addr.addr, sizeof(sock->addr) ); + if (bind_addr.addr.sa_family == AF_UNIX) + { + sock->addr.un.sun_family = WS_AF_UNIX; + memcpy(sock->addr.un.sun_path, params->addr.sa_data, sizeof(sock->addr.un.sun_path)); + sock->addr_len = sizeof(sock->addr.un); + } + else + sock->addr_len = sockaddr_from_unix( &bind_addr, &sock->addr.addr, sizeof(sock->addr) ); }
update_addr_usage( sock, &bind_addr, v6only );
if (get_reply_max_size() >= sock->addr_len) set_reply_data( &sock->addr, sock->addr_len ); + + if (sock->family == WS_AF_UNIX && *params->addr.sa_data) + fchdir(server_dir_fd); return; }
@@ -3023,7 +3149,15 @@ static void sock_ioctl( struct fd *fd, ioctl_code_t code, struct async *async ) return; }
- set_reply_data( &sock->addr, sock->addr_len ); + if (sock->family == WS_AF_UNIX) + { + if (*sock->addr.un.sun_path) + set_reply_data( &sock->addr, sizeof(sock->addr.un.sun_family) + strlen(sock->addr.un.sun_path) + 1 ); + else + set_reply_data( &sock->addr, sizeof(sock->addr.un) ); + } + else + set_reply_data( &sock->addr, sock->addr_len ); return;
case IOCTL_AFD_WINE_GETPEERNAME:
From: Ally Sommers dropbear.sh@gmail.com
Deleting the socket file is a common pattern with AF_UNIX sockets, and is analogous to unbinding. --- server/fd.c | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-)
diff --git a/server/fd.c b/server/fd.c index fc7f7be92b9..dd2238b8eae 100644 --- a/server/fd.c +++ b/server/fd.c @@ -1939,6 +1939,19 @@ struct fd *open_fd( struct fd *root, const char *name, struct unicode_str nt_nam fd->unix_fd = open( name, O_RDONLY | (flags & ~(O_TRUNC | O_CREAT | O_EXCL)), *mode ); }
+ /* POSIX requires that open(2) throws EOPNOTSUPP when `path` is a Unix + * socket. *BSD throws EOPNOTSUPP in this case and the additional case of + * O_SHLOCK or O_EXLOCK being passed when `path` resides on a filesystem + * without lock support. + * + * Contrary to POSIX, Linux returns ENXIO in this case, so we also check + * that error code here. */ + if (errno == EOPNOTSUPP || errno == ENXIO) + { + if (!stat(name, &st) && S_ISSOCK(st.st_mode) && (options & FILE_DELETE_ON_CLOSE)) + goto skip_open_fail; + } + if (fd->unix_fd == -1) { /* check for trailing slash on file path */ @@ -1950,6 +1963,7 @@ struct fd *open_fd( struct fd *root, const char *name, struct unicode_str nt_nam } }
+skip_open_fail: fd->nt_name = dup_nt_name( root, nt_name, &fd->nt_namelen ); fd->unix_name = NULL; if ((path = dup_fd_name( root, name ))) @@ -1961,11 +1975,12 @@ struct fd *open_fd( struct fd *root, const char *name, struct unicode_str nt_nam closed_fd->unix_fd = fd->unix_fd; closed_fd->disp_flags = 0; closed_fd->unix_name = fd->unix_name; - fstat( fd->unix_fd, &st ); + if (fd->unix_fd != -1) + fstat( fd->unix_fd, &st ); *mode = st.st_mode;
- /* only bother with an inode for normal files and directories */ - if (S_ISREG(st.st_mode) || S_ISDIR(st.st_mode)) + /* only bother with an inode for normal files, directories, and socket files */ + if (S_ISREG(st.st_mode) || S_ISDIR(st.st_mode) || S_ISSOCK(st.st_mode)) { unsigned int err; struct inode *inode = get_inode( st.st_dev, st.st_ino, fd->unix_fd );
From: Ally Sommers dropbear.sh@gmail.com
--- server/sock.c | 6 ++++++ 1 file changed, 6 insertions(+)
diff --git a/server/sock.c b/server/sock.c index 5d7dd2b750e..7dd3243dc85 100644 --- a/server/sock.c +++ b/server/sock.c @@ -1878,6 +1878,12 @@ static int init_socket( struct sock *sock, int family, int type, int protocol ) return -1; }
+ if (unix_family == AF_UNIX && unix_type == SOCK_DGRAM) + { + set_win32_error(WSAEAFNOSUPPORT); + return -1; + } + sockfd = socket( unix_family, unix_type, unix_protocol );
#ifdef linux
From: Ally Sommers dropbear.sh@gmail.com
--- server/sock.c | 72 ++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 60 insertions(+), 12 deletions(-)
diff --git a/server/sock.c b/server/sock.c index 7dd3243dc85..35e1962ce8f 100644 --- a/server/sock.c +++ b/server/sock.c @@ -2063,11 +2063,32 @@ static struct sock *accept_socket( struct sock *sock ) unix_len = sizeof(unix_addr); if (!getsockname( acceptfd, &unix_addr.addr, &unix_len )) { - acceptsock->addr_len = sockaddr_from_unix( &unix_addr, &acceptsock->addr.addr, sizeof(acceptsock->addr) ); + if (sock->family == WS_AF_UNIX) + { + acceptsock->addr_len = sock->addr_len; + acceptsock->addr.un = sock->addr.un; + } + else + { + acceptsock->addr_len = sockaddr_from_unix( &unix_addr, + &acceptsock->addr.addr, + sizeof(acceptsock->addr) ); + } + if (!getpeername( acceptfd, &unix_addr.addr, &unix_len )) - acceptsock->peer_addr_len = sockaddr_from_unix( &unix_addr, - &acceptsock->peer_addr.addr, - sizeof(acceptsock->peer_addr) ); + { + if (sock->family == WS_AF_UNIX) + { + acceptsock->peer_addr_len = sizeof( sock->peer_addr.un ); + acceptsock->peer_addr.un = sock->peer_addr.un; + } + else + { + acceptsock->peer_addr_len = sockaddr_from_unix( &unix_addr, + &acceptsock->peer_addr.addr, + sizeof(acceptsock->peer_addr) ); + } + } } }
@@ -2126,11 +2147,31 @@ static int accept_into_socket( struct sock *sock, struct sock *acceptsock ) unix_len = sizeof(unix_addr); if (!getsockname( get_unix_fd( newfd ), &unix_addr.addr, &unix_len )) { - acceptsock->addr_len = sockaddr_from_unix( &unix_addr, &acceptsock->addr.addr, sizeof(acceptsock->addr) ); + if (sock->family == WS_AF_UNIX) + { + acceptsock->addr_len = sock->addr_len; + acceptsock->addr.un = sock->addr.un; + } + else + { + acceptsock->addr_len = sockaddr_from_unix( &unix_addr, + &acceptsock->addr.addr, + sizeof(acceptsock->addr) ); + } if (!getpeername( get_unix_fd( newfd ), &unix_addr.addr, &unix_len )) - acceptsock->peer_addr_len = sockaddr_from_unix( &unix_addr, - &acceptsock->peer_addr.addr, - sizeof(acceptsock->peer_addr) ); + { + if (sock->family == WS_AF_UNIX) + { + acceptsock->peer_addr_len = sizeof( sock->peer_addr.un ); + acceptsock->peer_addr.un = sock->peer_addr.un; + } + else + { + acceptsock->peer_addr_len = sockaddr_from_unix( &unix_addr, + &acceptsock->peer_addr.addr, + sizeof(acceptsock->peer_addr) ); + } + } }
clear_error(); @@ -2747,10 +2788,17 @@ static void sock_ioctl( struct fd *fd, ioctl_code_t code, struct async *async ) allow_fd_caching( sock->fd );
unix_len = sizeof(unix_addr); - getsockname( unix_fd, &unix_addr.addr, &unix_len ); - sock->addr_len = sockaddr_from_unix( &unix_addr, &sock->addr.addr, sizeof(sock->addr) ); - sock->peer_addr_len = sockaddr_from_unix( &peer_addr, &sock->peer_addr.addr, sizeof(sock->peer_addr)); - + if (sock->family == WS_AF_UNIX) + { + sock->peer_addr.un = *(struct WS_sockaddr_un *)addr; + sock->peer_addr_len = sizeof(struct WS_sockaddr_un); + } + else + { + getsockname( unix_fd, &unix_addr.addr, &unix_len ); + sock->addr_len = sockaddr_from_unix( &unix_addr, &sock->addr.addr, sizeof(sock->addr) ); + sock->peer_addr_len = sockaddr_from_unix( &peer_addr, &sock->peer_addr.addr, sizeof(sock->peer_addr)); + } sock->bound = 1;
if (!ret)
From: Ally Sommers dropbear.sh@gmail.com
--- dlls/ws2_32/tests/sock.c | 292 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 292 insertions(+)
diff --git a/dlls/ws2_32/tests/sock.c b/dlls/ws2_32/tests/sock.c index 6954b3e077a..e76b65202f0 100644 --- a/dlls/ws2_32/tests/sock.c +++ b/dlls/ws2_32/tests/sock.c @@ -29,6 +29,7 @@ #include <iphlpapi.h> #include <ws2tcpip.h> #include <wsipx.h> +#include <afunix.h> #include <wsnwlink.h> #include <mswsock.h> #include <mstcpip.h> @@ -14167,6 +14168,296 @@ static void test_select_after_WSAEventSelect(void) closesocket(client); }
+static void test_afunix(void) +{ + SOCKET listener, client, server = 0; + SOCKADDR_UN addr = { AF_UNIX, "test_afunix.sock" }; + char serverBuf[] = "ws2_32/AF_UNIX socket test"; + char clientBuf[sizeof(serverBuf)] = { 0 }; + + char paths[4][sizeof(addr.sun_path)] = { "./tmp.sock", "../tmp.sock" }; + char dosPath[sizeof(addr.sun_path)]; + WCHAR dosWidePath[sizeof(addr.sun_path)]; + UNICODE_STRING ntPath = { 0 }; + SOCKADDR_UN outAddr = { 0 }; + int outAddrSize = sizeof(outAddr); + SOCKADDR_UN truncatedAddr = { 0 }; + ULONG zero = 0; + ULONG one = 1; + int ret; + + /* Test connection and send/recv */ + listener = socket(AF_UNIX, SOCK_STREAM, 0); + if (listener == INVALID_SOCKET && GetLastError() == WSAEAFNOSUPPORT) + { + win_skip("AF_UNIX sockets are unsupported, skipping...\n"); + return; + } + + ok(listener != INVALID_SOCKET, "Could not create Unix socket: %lu\n", + GetLastError()); + + ret = bind(listener, (SOCKADDR *)&addr, 0); + ok(ret && GetLastError() == WSAEFAULT, "Incorrect error: %lu\n", GetLastError()); + ret = bind(listener, (SOCKADDR *)&addr, 2); + ok(!ret, "Could not bind Unix socket: %lu\n", GetLastError()); + ret = listen(listener, 1); + ok(!ret, "Could not listen on Unix socket: %lu\n", GetLastError()); + closesocket(listener); + + listener = socket(AF_UNIX, SOCK_STREAM, 0); + ok(listener != INVALID_SOCKET, "Could not create Unix socket: %lu\n", + GetLastError()); + ret = bind(listener, (SOCKADDR *)&addr, 3); + ok(!ret, "Could not bind Unix socket: %lu\n", GetLastError()); + + memcpy(&truncatedAddr, &addr, 3); + ret = getsockname(listener, (SOCKADDR *)&outAddr, &outAddrSize); + ok(!ret, "Could not get info on Unix socket: %lu\n", GetLastError()); + ok(!memcmp(truncatedAddr.sun_path, outAddr.sun_path, sizeof(addr.sun_path)), + "getsockname returned incorrect path '%s' for provided path '%s'\n", + outAddr.sun_path, + truncatedAddr.sun_path); + ok(outAddrSize == sizeof(outAddr.sun_family) + strlen(outAddr.sun_path) + 1, + "getsockname returned incorrect size '%d' for provided path '%s'\n", + outAddrSize, + truncatedAddr.sun_path); + closesocket(listener); + ret = DeleteFileA(truncatedAddr.sun_path); + ok(ret, "DeleteFileA on socket file failed: %lu\n", GetLastError()); + ok(GetFileAttributesA(truncatedAddr.sun_path) == INVALID_FILE_ATTRIBUTES && + GetLastError() == ERROR_FILE_NOT_FOUND, + "Failed to delete socket file at path '%s'\n", + truncatedAddr.sun_path); + + listener = socket(AF_UNIX, SOCK_STREAM, 0); + ok(listener != INVALID_SOCKET, "Could not create Unix socket: %lu\n", + GetLastError()); + + ret = bind(listener, (SOCKADDR *)&addr, sizeof(SOCKADDR_UN)); + ok(!ret, "Could not bind Unix socket: %lu\n", GetLastError()); + + ret = listen(listener, 1); + ok(!ret, "Could not listen on Unix socket: %lu\n", GetLastError()); + + client = socket(AF_UNIX, SOCK_STREAM, 0); + ok(client != INVALID_SOCKET, "Failed to create second Unix socket: %lu\n", + GetLastError()); + + ret = ioctlsocket(client, FIONBIO, &one); + ok(!ret, "Could not set AF_UNIX socket to nonblocking: %lu; skipping connection\n", GetLastError()); + if (!ret) + { + ret = connect(client, (SOCKADDR *)&addr, sizeof(addr)); + ok(!ret || (ret == SOCKET_ERROR && GetLastError() == WSAEWOULDBLOCK), + "Error when connecting to Unix socket: %lu\n", + GetLastError()); + server = accept(listener, NULL, NULL); + ok(server != INVALID_SOCKET, "Could not accept Unix socket connection: %lu\n", + GetLastError()); + ret = ioctlsocket(client, FIONBIO, &zero); + ok(!ret, "Could not set AF_UNIX socket to blocking: %lu\n", GetLastError()); + } + + ret = send(server, serverBuf, sizeof(serverBuf), 0); + ok(ret == sizeof(serverBuf), "Incorrect return value from send: %d\n", ret); + ret = recv(client, clientBuf, sizeof(serverBuf), 0); + ok(ret == sizeof(serverBuf), "Incorrect return value from recv: %d\n", ret); + ok(!memcmp(serverBuf, clientBuf, sizeof(serverBuf)), "Data mismatch over Unix socket\n"); + + memset(clientBuf, 0, sizeof(clientBuf)); + + ret = sendto(server, serverBuf, sizeof(serverBuf), 0, NULL, 0); + ok(ret == sizeof(serverBuf), "Incorrect return value from sendto: %d\n", ret); + ret = recvfrom(client, clientBuf, sizeof(serverBuf), 0, NULL, 0); + ok(ret == sizeof(serverBuf), "Incorrect return value from recvfrom: %d\n", ret); + ok(!memcmp(serverBuf, clientBuf, sizeof(serverBuf)), "Data mismatch over Unix socket\n"); + + memset(serverBuf, 0, sizeof(serverBuf)); + + ret = send(client, clientBuf, sizeof(clientBuf), 0); + ok(ret == sizeof(clientBuf), "Incorrect return value from send: %d\n", ret); + ret = recv(server, serverBuf, sizeof(clientBuf), 0); + ok(ret == sizeof(serverBuf), "Incorrect return value from recv: %d\n", ret); + ok(!memcmp(serverBuf, clientBuf, sizeof(clientBuf)), "Data mismatch over Unix socket\n"); + + memset(serverBuf, 0, sizeof(serverBuf)); + + ret = sendto(client, clientBuf, sizeof(clientBuf), 0, NULL, 0); + ok(ret == sizeof(clientBuf), "Incorrect return value from sendto: %d\n", ret); + ret = recvfrom(server, serverBuf, sizeof(clientBuf), 0, NULL, 0); + ok(ret == sizeof(serverBuf), "Incorrect return value from recvfrom: %d\n", ret); + ok(!memcmp(serverBuf, clientBuf, sizeof(clientBuf)), "Data mismatch over Unix socket\n"); + + closesocket(listener); + closesocket(client); + closesocket(server); + + /* Test socket file deletion */ + ret = DeleteFileA("test_afunix.sock"); + ok(ret, "DeleteFileA on socket file failed: %lu\n", GetLastError()); + ok(GetFileAttributesA("test_afunix.sock") == INVALID_FILE_ATTRIBUTES && + GetLastError() == ERROR_FILE_NOT_FOUND, + "Failed to delete socket file at path '%s'\n", + addr.sun_path); + + /* Test failure modes */ + listener = socket(AF_UNIX, SOCK_STREAM, 0); + ok(listener != INVALID_SOCKET, "Could not create Unix socket: %lu\n", + GetLastError()); + ret = bind(listener, (SOCKADDR *)&addr, sizeof(SOCKADDR_UN)); + ok(!ret, "Could not bind Unix socket to path '%s': %lu\n", addr.sun_path, GetLastError()); + closesocket(listener); + listener = socket(AF_UNIX, SOCK_STREAM, 0); + ok(listener != INVALID_SOCKET, "Could not create Unix socket: %lu\n", + GetLastError()); + ret = bind(listener, (SOCKADDR *)&addr, sizeof(SOCKADDR_UN)); + ok(ret && GetLastError() == WSAEADDRINUSE, + "Bound Unix socket to path '%s' despite existing socket file: %lu\n", + addr.sun_path, + GetLastError()); + closesocket(listener); + ret = DeleteFileA(addr.sun_path); + ok(ret, "DeleteFileA on socket file failed: %lu\n", GetLastError()); + ok(GetFileAttributesA("test_afunix.sock") == INVALID_FILE_ATTRIBUTES && + GetLastError() == ERROR_FILE_NOT_FOUND, + "Failed to delete socket file at path '%s'\n", + addr.sun_path); + + /* Test different path types (relative, NT, etc.) */ + GetTempPathA(sizeof(paths[0]) - 1, paths[2]); + strcat(paths[2], "tmp.sock"); + MultiByteToWideChar(CP_ACP, 0, paths[2], -1, dosWidePath, sizeof(dosPath)); + RtlDosPathNameToNtPathName_U(dosWidePath, &ntPath, NULL, NULL); + RtlUnicodeToMultiByteN(paths[3], sizeof(addr.sun_path) - 1, NULL, ntPath.Buffer, ntPath.Length); + + for (int i = 0; i < sizeof(paths) / sizeof(paths[0]); i++) + { + memcpy(addr.sun_path, paths[i], sizeof(paths[i])); + + listener = socket(AF_UNIX, SOCK_STREAM, 0); + ok(listener != INVALID_SOCKET, "Could not create Unix socket: %lu\n", + GetLastError()); + + ret = bind(listener, (SOCKADDR *)&addr, sizeof(SOCKADDR_UN)); + ok(!ret, "Could not bind Unix socket to path '%s': %lu\n", addr.sun_path, GetLastError()); + + ret = listen(listener, 1); + ok(!ret, "Could not listen on Unix socket: %lu\n", GetLastError()); + + client = socket(AF_UNIX, SOCK_STREAM, 0); + ok(client != INVALID_SOCKET, "Failed to create second Unix socket: %lu\n", + GetLastError()); + + ret = ioctlsocket(client, FIONBIO, &one); + ok(!ret, "Could not set AF_UNIX socket to nonblocking: %lu; skipping connection\n", GetLastError()); + if (!ret) + { + ret = connect(client, (SOCKADDR *)&addr, sizeof(addr)); + ok(!ret || (ret == SOCKET_ERROR && GetLastError() == WSAEWOULDBLOCK), + "Error when connecting to Unix socket: %lu\n", + GetLastError()); + server = accept(listener, NULL, NULL); + ok(server != INVALID_SOCKET, "Could not accept Unix socket connection: %lu\n", + GetLastError()); + ret = ioctlsocket(client, FIONBIO, &zero); + ok(!ret, "Could not set AF_UNIX socket to blocking: %lu\n", GetLastError()); + } + + memset(&outAddr, 0, sizeof(outAddr)); + outAddrSize = sizeof(outAddr); + ret = getsockname(listener, (SOCKADDR *)&outAddr, &outAddrSize); + ok(!ret, "Could not get info on Unix socket: %lu\n", GetLastError()); + ok(!memcmp(addr.sun_path, outAddr.sun_path, sizeof(addr.sun_path)), + "getsockname returned incorrect path '%s' for provided path '%s'\n", + outAddr.sun_path, + addr.sun_path); + ok(outAddrSize == sizeof(outAddr.sun_family) + strlen(outAddr.sun_path) + 1, + "getsockname returned incorrect size '%d' for provided path '%s'\n", + outAddrSize, + addr.sun_path); + + memset(&outAddr, 0, sizeof(outAddr)); + outAddrSize = sizeof(outAddr); + ret = getsockname(client, (SOCKADDR *)&outAddr, &outAddrSize); + ok(!ret, "Could not get info on Unix socket: %lu\n", GetLastError()); + ok(!memcmp((char[108]){0}, outAddr.sun_path, sizeof(addr.sun_path)), + "getsockname returned incorrect path '%s' for provided path '%s'\n", + outAddr.sun_path, + addr.sun_path); + ok(outAddrSize == sizeof(outAddr), + "getsockname returned incorrect size '%d' for provided path '%s'\n", + outAddrSize, + addr.sun_path); + + memset(&outAddr, 0, sizeof(outAddr)); + outAddrSize = sizeof(outAddr); + ret = getsockname(server, (SOCKADDR *)&outAddr, &outAddrSize); + ok(!ret, "Could not get info on Unix socket: %lu\n", GetLastError()); + ok(!memcmp(addr.sun_path, outAddr.sun_path, sizeof(addr.sun_path)), + "getsockname returned incorrect path '%s' for provided path '%s'\n", + outAddr.sun_path, + addr.sun_path); + ok(outAddrSize == sizeof(outAddr.sun_family) + strlen(outAddr.sun_path) + 1, + "getsockname returned incorrect size '%d' for provided path '%s'\n", + outAddrSize, + addr.sun_path); + + memset(&outAddr, 0, sizeof(outAddr)); + outAddrSize = sizeof(outAddr); + ret = getpeername(listener, (SOCKADDR *)&outAddr, &outAddrSize); + ok(ret == -1, "Got info on Unix socket: %lu\n", GetLastError()); + ok(GetLastError() == WSAENOTCONN, + "Incorrect error returned from getpeername on Unix socket: %ld\n", + GetLastError()); + ok(!memcmp((char[108]){0}, outAddr.sun_path, sizeof(addr.sun_path)), + "getpeername returned incorrect path '%s' for provided path '%s'\n", + outAddr.sun_path, + addr.sun_path); + ok(outAddrSize == sizeof(outAddr), + "getpeername returned incorrect size '%d' for provided path '%s'\n", + outAddrSize, + addr.sun_path); + + memset(&outAddr, 0, sizeof(outAddr)); + outAddrSize = sizeof(outAddr); + ret = getpeername(client, (SOCKADDR *)&outAddr, &outAddrSize); + ok(!ret, "Could not get info on Unix socket: %lu\n", GetLastError()); + ok(!memcmp(addr.sun_path, outAddr.sun_path, sizeof(addr.sun_path)), + "getpeername returned incorrect path '%s' for provided path '%s'\n", + outAddr.sun_path, + addr.sun_path); + ok(outAddrSize == sizeof(outAddr), + "getpeername returned incorrect size '%d' for provided path '%s'\n", + outAddrSize, + addr.sun_path); + + memset(&outAddr, 0, sizeof(outAddr)); + outAddrSize = sizeof(outAddr); + ret = getpeername(server, (SOCKADDR *)&outAddr, &outAddrSize); + ok(!ret, "Could not get info on Unix socket: %lu\n", GetLastError()); + ok(!memcmp((char[108]){0}, outAddr.sun_path, sizeof(addr.sun_path)), + "getpeername returned incorrect path '%s' for provided path '%s'\n", + outAddr.sun_path, + addr.sun_path); + ok(outAddrSize == sizeof(outAddr), + "getpeername returned incorrect size '%d' for provided path '%s'\n", + outAddrSize, + addr.sun_path); + + closesocket(listener); + closesocket(client); + closesocket(server); + + ret = DeleteFileA(addr.sun_path); + ok(ret, "DeleteFileA on socket file failed: %lu\n", GetLastError()); + ok(GetFileAttributesA(addr.sun_path) == INVALID_FILE_ATTRIBUTES && + GetLastError() == ERROR_FILE_NOT_FOUND, + "Failed to delete socket file at path '%s'\n", + addr.sun_path); + } +} + START_TEST( sock ) { int i; @@ -14249,6 +14540,7 @@ START_TEST( sock ) test_icmp(); test_connect_udp(); test_tcp_sendto_recvfrom(); + test_afunix();
/* There is apparently an obscure interaction between this test and * test_WSAGetOverlappedResult().
On Wed Apr 24 22:21:11 2024 +0000, Ally Sommers wrote:
This patch still works on master with all tests passing and the software I use it for still works as expected. I think it would be great for this to be merged, but the deletion code not being up to scratch is an understandable barrier. The first version was even worse. However, at the time I did spend a while looking at ways to get deletion working, and this was the least problematic solution I could come up with. I unfortunately can't really do much more than that unless a more specific criticism than "it's ugly" (which, again, I agree with) is levied. A nominally cleaner solution would probably introduce a lot of extra code just for this one special case, which seems undesired based on feedback for a previous patch of mine, so I'm hesitant to even attempt that. If anyone has any ideas, though, I'm all ears.
@zfigura "be considered ready by the submitter" doesn't means a patch is ready.
I think a lot of good MRs are being submitted and left into dust, a system that allow MRs to be aproved by other developers would allow more MRs to be accepted, like for example, a lot of simple stubs are not being merged and someone passing though MRs found out that https://gitlab.winehq.org/wine/wine/-/merge_requests/5522 code was a containing a duplicate of https://gitlab.winehq.org/wine/wine/-/merge_requests/2374 cause the stub was required to run an installer.
My proposed solution is in no way perfect, but it's still far better than right now, where multiple peoples are developing the same code for wine.
I think a lot of good MRs are being submitted and left into dust, a system that allow MRs to be aproved by other developers would allow more MRs to be accepted, like for example, a lot of simple stubs are not being merged and someone passing though MRs found out that https://gitlab.winehq.org/wine/wine/-/merge_requests/5522 code was a containing a duplicate of https://gitlab.winehq.org/wine/wine/-/merge_requests/2374 cause the stub was required to run an installer.
I don't understand? Merge requests can already be approved by anyone, regardless of whether they're an assigned reviewer or maintainer or not.
As explained in 5522, 2374 was never accepted because it didn't actually help anything.
Would this be useful without deletion part? And if yes maybe we could get the socket part in if the path/fd part is controversial?
Would this be useful without deletion part? And if yes maybe we could get the socket part in if the path/fd part is controversial?
Without support for deletion, creating a Unix domain socket will always leak an on-disk path. This also, I believe, precludes support for having any tests.
Would changing NtDeleteFile implementation to not go through whole open/close be better? as a side note - does windows even allow CreateFile with AF_UNIX socket paths anyway?
Would adding additional flag to server's create_file request be ok? (that will only be set by NtDeleteFile and if set will skip open call and will automatically do open/close on server side). Advantage of that is that it won't expose ability to CreateFile("file.sock") outside of wine internals. I'm not sure how stable wineserver's protocol needs to be though.
`CreateFile` can be used to "create" a Unix socket file in the same way that `mknod` with `S_IFSOCK` "creates" a Unix socket file. It's a file that exists and presents as a socket, but you can't really do anything with it. On Windows, they're reparse points tagged with `IO_REPARSE_TAG_AF_UNIX`. I don't understand reparse points very well at all yet, but from a cursory reading of Microsoft's documentation, it's likely that there are edge cases with Unix socket files that this MR might need to cover.
To me, adding a flag for a single function doesn't seem like a better solution than the one currently implemented in this MR.
On Thu Apr 25 19:50:23 2024 +0000, Elizabeth Figura wrote:
I think a lot of good MRs are being submitted and left into dust, a
system that allow MRs to be aproved by other developers would allow more MRs to be accepted, like for example, a lot of simple stubs are not being merged and someone passing though MRs found out that https://gitlab.winehq.org/wine/wine/-/merge_requests/5522 code was a containing a duplicate of https://gitlab.winehq.org/wine/wine/-/merge_requests/2374 cause the stub was required to run an installer. I don't understand? Merge requests can already be approved by anyone, regardless of whether they're an assigned reviewer or maintainer or not. As explained in 5522, 2374 was never accepted because it didn't actually help anything.
@zfigura I would appreciate it if the "didn't actually help anything" concerns regarding my patches were made in the MR containing them. That would be so that I could have the opportunity to make improvements to them in response to your feedback.
@zfigura I would appreciate it if the "didn't actually help anything" concerns regarding my patches were made in the MR containing them. That would be so that I could have the opportunity to make improvements to them in response to your feedback.
Sure. (Of course, I wasn't the one to make that comment about 2374, and I only commented on 5522 in an attempt to explain the rejection from other contributors.)
On Tue Sep 19 20:13:15 2023 +0000, Ally Sommers wrote:
I do agree that the file deletion code is a bit hacky, but a lot of the file handling code in wineserver depends on having a valid file descriptor, and we can't `open()` the socket file. This was the simplest way I could find to make socket file deletion work.
A year has now passed. Is it possible that this topic has been solved better in wine in the meantime ?
To see how complete this merge request is, I synchronized the status with git master (https://gitlab.winehq.org/rhabacker/wine/-/commits/afunix), which worked quite well, and used it to build wine from the git master branch. The included tests for ws2_32 ran without any problems, as did the test binaries available at https://bugs.winehq.org/show_bug.cgi?id=52568.
Is it possible to merge this changes ?
On Sat Feb 1 17:05:53 2025 +0000, Ralf Habacker wrote:
To see how complete this merge request is, I synchronized the status with git master (https://gitlab.winehq.org/rhabacker/wine/-/commits/afunix), which worked quite well, and used it to build wine from the git master branch. The included tests for ws2_32 ran without any problems, as did the test binaries available at https://bugs.winehq.org/show_bug.cgi?id=52568. Is it possible to merge this changes ?
Well, everything stalled, last time I tried to push for it to get merged, nothing happened.
Maybe making smaller separate MRs would make the merging process easier?
FYI [nbdkit](https://gitlab.com/nbdkit/nbdkit) is another application which can usefully use AF_UNIX sockets on Windows.
Unfortunately, last time I tried to write tests for Unix sockets, I started triggering kernel panics in Windows. Maybe the situation has improved since then?
It has been improved. As part of the provision of AF_UNIX support for DBus on Windows https://gitlab.freedesktop.org/dbus/dbus/-/merge_requests/391 there are corresponding test cases for AF_UNIX, which run without problems on a native Windows.