GetAcceptExSockaddrs returns garbage! Does anyone know why?
[I've followed the suggestion to use Winsock.pas, but it still writes garbage -- although the sin_family field has changed to a new garbage value.]
Hello, I'm trying to write a quick/dirty echoserver in Delphi, but I notice that GetAcceptExSockaddrs seems to be writing to only the first 4 bytes of the structure I pass it.
program TCPEcho;
{$APPTYPE CONSOLE}
uses Windows, SysUtils, Winsock;
type INT = SmallInt;
const
BufDataSize = 8192;
BufAddrSize = SizeOf (TSockAddrIn) + 16;
var
WSAData : TWSAData;
ListenSock, AcceptSock : TSocket;
Addr, LocalAddr, RemoteAddr : TSockAddrIn;
LocalAddrSize, RemoteAddrSize : Integer;
Ov : OVERLAPPED;
Buf : array[1..BufDataSize + BufAddrSize * 2] of Byte;
BytesReceived : DWORD;
begin
FillChar (WSAData, SizeOf (WSAData), 0);
WSAStartup (2, WSAData);
ListenSock := ValidSocketCheck ('Socket', Socket (AF_INET, SOCK_STREAM, IPPROTO_TCP));
FillChar (Addr, SizeOf (Addr), 0);
Addr.sin_family := AF_INET;
Addr.sin_port := HToNS (1066);
Addr.sin_addr.s_addr := HToNL (INADDR_ANY);
SocketCheck ('bind', bind (ListenSock, Addr, SizeOf (Addr)));
SocketCheck ('Listen', Listen (ListenSock, 3));
FillChar (Ov, SizeOf (Ov), 0);
Ov.hEvent := HandleCheck ('CreateEvent', CreateEvent (nil, False, False, nil));
AcceptSock := ValidSocketCheck ('Socket', Socket (AF_INET, SOCK_STREAM, IPPROTO_TCP));
if AcceptEx (ListenSock, AcceptSock, @Buf, BufDataSize, BufAddrSize, BufAddrSize, BytesReceived, @Ov) then
WinCheck ('SetEvent', SetEvent (Ov.hEvent)开发者_StackOverflow社区)
else
if GetLastError <> ERROR_IO_PENDING then
WinCheck ('AcceptEx', GetLastError);
if WaitForMultipleObjects (1, @Ov.hEvent, False, INFINITE) <> WAIT_OBJECT_0 then
raise Exception.Create ('WFMO');
GetAcceptExSockaddrs (@Buf, BufDataSize, BufAddrSize, BufAddrSize, LocalAddr, LocalAddrSize, RemoteAddr, RemoteAddrSize);
WriteLn (RemoteAddr.sin_family);
end.
So if I run this, connect to it with Telnet (on same computer, connecting to localhost) and then type a key, WaitForMultipleObjects will unblock and GetAcceptExSockaddrs will run. But the result is garbage!
RemoteAddr.sin_family = 51618
RemoteAddr.sin_port = 64
and the rest is zeroes.
What gives? Thanks in advance!
What Delphi version are you using? In any case where is no need to use your own type definitions for GetAcceptExSockaddrs and its arguments, use the definitions from WinSock.pas unit; they differ from yours definitions at least for unicode Delphi versions.
Updated
Looks like the definition of GetAcceptExSockaddrs is wrong. I remember old Delphi versions contained a bug here. The correct prototype (taken from Delphi 2009 WinSock.pas) is
procedure GetAcceptExSockaddrs(lpOutputBuffer: Pointer;
dwReceiveDataLength, dwLocalAddressLength, dwRemoteAddressLength: DWORD;
var LocalSockaddr: PSockAddr; var LocalSockaddrLength: Integer;
var RemoteSockaddr: PSockAddr; var RemoteSockaddrLength: Integer); stdcall;
Note that LocalSockaddr and RemoteSockaddr are not pointers to structures but pointers to pointers to structures.
Same happens if you use the GetAcceptExSockaddrs prototype from mingw. It returns garbage.
Instead resolve the GetAcceptExSockaddrs the same way you resolve AcceptEx and ConnectEx, i.e.:
#define WSAID_GETACCEPTEXSOCKADDRS { 0xb5367df2,0xcbac,0x11cf,{0x95,0xca,0x00,0x80,0x5f,0x48,0xa1,0x92} }
GUID GuidGetAcceptSockAddrs = WSAID_GETACCEPTEXSOCKADDRS;
DWORD dwBytes;
if ( WSAIoctl( activeSock,
SIO_GET_EXTENSION_FUNCTION_POINTER,
&GuidGetAcceptSockAddrs,
sizeof (GuidGetAcceptSockAddrs),
&pfnGetAcceptSockAddrs,
sizeof (pfnGetAcceptSockAddrs),
&dwBytes,
NULL,
NULL ) == SOCKET_ERROR )
{
... error ...
}
精彩评论