From e52982a17534eeaede7c123b59205e36ed28080f Mon Sep 17 00:00:00 2001 From: Denis Feklushkin Date: Sun, 9 Oct 2022 00:44:59 +0300 Subject: [PATCH 1/6] Windows: implements posixSocketDuplicate --- dub.json | 1 + src/dpq2/connection.d | 98 ++++++++++++++++++++++++++++++++---- src/dpq2/conv/native_tests.d | 2 +- 3 files changed, 90 insertions(+), 11 deletions(-) diff --git a/dub.json b/dub.json index c30fc215..ca5d9347 100644 --- a/dub.json +++ b/dub.json @@ -13,6 +13,7 @@ "money": "~>3.0.2" }, "targetType": "sourceLibrary", + "libs-windows": ["ws2_32"], "-ddoxTool": "scod", "configurations": [ { diff --git a/src/dpq2/connection.d b/src/dpq2/connection.d index ffd0377b..dcaca825 100644 --- a/src/dpq2/connection.d +++ b/src/dpq2/connection.d @@ -207,23 +207,49 @@ class Connection } /// Obtains duplicate file descriptor number of the connection socket to the server + version(Posix) socket_t posixSocketDuplicate() { - version(Windows) - { - assert(false, "FIXME: implement socket duplication"); - } - else // Posix OS - { - import core.sys.posix.unistd: dup; + import core.sys.posix.unistd: dup; - return cast(socket_t) dup(cast(socket_t) posixSocket); - } + static assert(socket_t.sizeof == int.sizeof); + + return cast(socket_t) dup(cast(socket_t) posixSocket); + } + + /// Obtains duplicate file descriptor number of the connection socket to the server + version(Windows) + socket_t posixSocketDuplicate() + { + import std.experimental.allocator.mallocator: Mallocator; + import core.sys.windows.winbase: GetCurrentProcessId; + + static assert(socket_t.sizeof >= SOCKET.sizeof); + + auto protocolInfo = cast(WSAPROTOCOL_INFOW*) Mallocator.instance.allocate(WSAPROTOCOL_INFOW.sizeof); + int dupStatus = WSADuplicateSocketW(posixSocket, GetCurrentProcessId, protocolInfo); + + if(dupStatus) + throw new ConnectionException("WSADuplicateSocketW error, code "~WSAGetLastError().to!string); + + socket_t s = cast(socket_t) WSASocketW( + FROM_PROTOCOL_INFO, + FROM_PROTOCOL_INFO, + FROM_PROTOCOL_INFO, + protocolInfo, + 0, + 0 + ); + + if(s == INVALID_SOCKET) + throw new ConnectionException("WSASocket error, code "~WSAGetLastError().to!string); + + return s; } /// Obtains std.socket.Socket of the connection to the server /// - /// Due to a limitation of Socket actually for the Socket creation + /// Due to a limitation of Dlang Socket actually for the Socket creation /// duplicate of internal posix socket will be used. Socket socket() { @@ -401,6 +427,58 @@ class Connection } } +// Socket duplication stuff for Win32 +version(Windows) +private +{ + import core.sys.windows.windef; + import core.sys.windows.basetyps: GUID; + + alias GROUP = uint; + + enum INVALID_SOCKET = 0; + enum FROM_PROTOCOL_INFO =-1; + enum MAX_PROTOCOL_CHAIN = 7; + enum WSAPROTOCOL_LEN = 255; + + struct WSAPROTOCOLCHAIN + { + int ChainLen; + DWORD[MAX_PROTOCOL_CHAIN] ChainEntries; + } + + struct WSAPROTOCOL_INFOW + { + DWORD dwServiceFlags1; + DWORD dwServiceFlags2; + DWORD dwServiceFlags3; + DWORD dwServiceFlags4; + DWORD dwProviderFlags; + GUID ProviderId; + DWORD dwCatalogEntryId; + WSAPROTOCOLCHAIN ProtocolChain; + int iVersion; + int iAddressFamily; + int iMaxSockAddr; + int iMinSockAddr; + int iSocketType; + int iProtocol; + int iProtocolMaxOffset; + int iNetworkByteOrder; + int iSecurityScheme; + DWORD dwMessageSize; + DWORD dwProviderReserved; + WCHAR[WSAPROTOCOL_LEN+1] szProtocol; + } + + extern(Windows) nothrow @nogc + { + import core.sys.windows.winsock2: WSAGetLastError; + int WSADuplicateSocketW(SOCKET s, DWORD dwProcessId, WSAPROTOCOL_INFOW* lpProtocolInfo); + SOCKET WSASocketW(int af, int type, int protocol, WSAPROTOCOL_INFOW*, GROUP, DWORD dwFlags); + } +} + private auto keyValToPQparamsArrays(in string[string] keyValueParams) { static struct PQparamsArrays diff --git a/src/dpq2/conv/native_tests.d b/src/dpq2/conv/native_tests.d index 83b25ae3..80d56a57 100644 --- a/src/dpq2/conv/native_tests.d +++ b/src/dpq2/conv/native_tests.d @@ -46,7 +46,7 @@ public void _integration_test( string connParam ) @system // to return times in other than UTC time zone but fixed time zone so make the test reproducible in databases with other TZ conn.exec("SET TIMEZONE TO +02"); - conn.exec("SET lc_monetary = 'en_US.UTF-8'"); + conn.exec("SET lc_monetary = 'C'"); QueryParams params; params.resultFormat = ValueFormat.BINARY; From b0af3707274312cdc2dacb71ca9ba078cc95c079 Mon Sep 17 00:00:00 2001 From: Denis Feklushkin Date: Tue, 11 Oct 2022 16:06:06 +0300 Subject: [PATCH 2/6] Forgotten comment --- src/dpq2/conv/native_tests.d | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/dpq2/conv/native_tests.d b/src/dpq2/conv/native_tests.d index 80d56a57..19055305 100644 --- a/src/dpq2/conv/native_tests.d +++ b/src/dpq2/conv/native_tests.d @@ -46,6 +46,8 @@ public void _integration_test( string connParam ) @system // to return times in other than UTC time zone but fixed time zone so make the test reproducible in databases with other TZ conn.exec("SET TIMEZONE TO +02"); + // It is found what Linux and Windows have different approach for monetary + // types formatting at same locales. This line sets equal approach. conn.exec("SET lc_monetary = 'C'"); QueryParams params; From 22ae5c5b9e43ceb52d56347da5573452df24e901 Mon Sep 17 00:00:00 2001 From: Denis Feklushkin Date: Tue, 11 Oct 2022 16:51:53 +0300 Subject: [PATCH 3/6] Mallocator -> malloc, potential memory leak fixed --- src/dpq2/connection.d | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/dpq2/connection.d b/src/dpq2/connection.d index dcaca825..e9e18eee 100644 --- a/src/dpq2/connection.d +++ b/src/dpq2/connection.d @@ -221,12 +221,14 @@ class Connection version(Windows) socket_t posixSocketDuplicate() { - import std.experimental.allocator.mallocator: Mallocator; + import core.stdc.stdlib: malloc, free; import core.sys.windows.winbase: GetCurrentProcessId; static assert(socket_t.sizeof >= SOCKET.sizeof); - auto protocolInfo = cast(WSAPROTOCOL_INFOW*) Mallocator.instance.allocate(WSAPROTOCOL_INFOW.sizeof); + auto protocolInfo = cast(WSAPROTOCOL_INFOW*) malloc(WSAPROTOCOL_INFOW.sizeof); + scope(failure) free(protocolInfo); + int dupStatus = WSADuplicateSocketW(posixSocket, GetCurrentProcessId, protocolInfo); if(dupStatus) From 2e589649eba60fda5ecb3767bf7e0adc58a5e25d Mon Sep 17 00:00:00 2001 From: Denis Feklushkin Date: Thu, 13 Oct 2022 00:00:23 +0300 Subject: [PATCH 4/6] Windows: posixSocketDuplicate returns SOCKET, not socket_t --- src/dpq2/connection.d | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/dpq2/connection.d b/src/dpq2/connection.d index e9e18eee..9f3b8c95 100644 --- a/src/dpq2/connection.d +++ b/src/dpq2/connection.d @@ -219,7 +219,7 @@ class Connection /// Obtains duplicate file descriptor number of the connection socket to the server version(Windows) - socket_t posixSocketDuplicate() + SOCKET posixSocketDuplicate() { import core.stdc.stdlib: malloc, free; import core.sys.windows.winbase: GetCurrentProcessId; @@ -234,7 +234,7 @@ class Connection if(dupStatus) throw new ConnectionException("WSADuplicateSocketW error, code "~WSAGetLastError().to!string); - socket_t s = cast(socket_t) WSASocketW( + SOCKET s = WSASocketW( FROM_PROTOCOL_INFO, FROM_PROTOCOL_INFO, FROM_PROTOCOL_INFO, @@ -255,7 +255,14 @@ class Connection /// duplicate of internal posix socket will be used. Socket socket() { - return new Socket(posixSocketDuplicate, AddressFamily.UNSPEC); + /* + * Especially for Win32: + * Even though sizeof(SOCKET) is 8, it's safe to cast it to int, because + * the value constitutes an index in per-process table of limited size + * and not a real pointer. + */ + + return new Socket(cast(socket_t) posixSocketDuplicate, AddressFamily.UNSPEC); } /// Returns the error message most recently generated by an operation on the connection From ac81db448963253f7ba94a1f744efd9b46a068ec Mon Sep 17 00:00:00 2001 From: Denis Feklushkin Date: Thu, 13 Oct 2022 00:37:23 +0300 Subject: [PATCH 5/6] Windows: unnecessary static assert removed --- src/dpq2/connection.d | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/dpq2/connection.d b/src/dpq2/connection.d index 9f3b8c95..f86a0cd3 100644 --- a/src/dpq2/connection.d +++ b/src/dpq2/connection.d @@ -224,8 +224,6 @@ class Connection import core.stdc.stdlib: malloc, free; import core.sys.windows.winbase: GetCurrentProcessId; - static assert(socket_t.sizeof >= SOCKET.sizeof); - auto protocolInfo = cast(WSAPROTOCOL_INFOW*) malloc(WSAPROTOCOL_INFOW.sizeof); scope(failure) free(protocolInfo); From 16464f19aa872b4776a00b916f0c51ac2cbc7d8d Mon Sep 17 00:00:00 2001 From: Denis Feklushkin Date: Thu, 13 Oct 2022 00:48:51 +0300 Subject: [PATCH 6/6] Windows: sockets sizes are euqal, comment removed --- src/dpq2/connection.d | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/dpq2/connection.d b/src/dpq2/connection.d index f86a0cd3..898834a9 100644 --- a/src/dpq2/connection.d +++ b/src/dpq2/connection.d @@ -253,12 +253,7 @@ class Connection /// duplicate of internal posix socket will be used. Socket socket() { - /* - * Especially for Win32: - * Even though sizeof(SOCKET) is 8, it's safe to cast it to int, because - * the value constitutes an index in per-process table of limited size - * and not a real pointer. - */ + version(Windows) static assert(SOCKET.sizeof == socket_t.sizeof); return new Socket(cast(socket_t) posixSocketDuplicate, AddressFamily.UNSPEC); }