tags:

views:

108

answers:

1

[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))
    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!

+1  A: 

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.

Serg
Delphi 7.I've adjusted the problem description to code that uses Winsock.pas's definitions. The sin_family field is a different garbage value, but otherwise the problem remains.
David
Thankyou, this worked.
David