Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Windows socket duplication implementation #183

Merged
merged 6 commits into from
Apr 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions dub.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
"money": "~>3.0.2"
},
"targetType": "sourceLibrary",
"libs-windows": ["ws2_32"],
"-ddoxTool": "scod",
"configurations": [
{
Expand Down
102 changes: 91 additions & 11 deletions src/dpq2/connection.d
Original file line number Diff line number Diff line change
Expand Up @@ -207,27 +207,55 @@ 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 posixSocketDuplicate()
{
import core.stdc.stdlib: malloc, free;
import core.sys.windows.winbase: GetCurrentProcessId;

auto protocolInfo = cast(WSAPROTOCOL_INFOW*) malloc(WSAPROTOCOL_INFOW.sizeof);
scope(failure) free(protocolInfo);

int dupStatus = WSADuplicateSocketW(posixSocket, GetCurrentProcessId, protocolInfo);

if(dupStatus)
throw new ConnectionException("WSADuplicateSocketW error, code "~WSAGetLastError().to!string);

SOCKET s = 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()
{
return new Socket(posixSocketDuplicate, AddressFamily.UNSPEC);
version(Windows) static assert(SOCKET.sizeof == socket_t.sizeof);

return new Socket(cast(socket_t) posixSocketDuplicate, AddressFamily.UNSPEC);
}

/// Returns the error message most recently generated by an operation on the connection
Expand Down Expand Up @@ -401,6 +429,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
Expand Down
4 changes: 3 additions & 1 deletion src/dpq2/conv/native_tests.d
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,9 @@ 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'");
// 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;
params.resultFormat = ValueFormat.BINARY;
Expand Down