ServiceBuffer: PChar; ServiceBufferSize: cuint32; Flags: cint): cint; stdcall;
external 'ws2_32.dll' name 'getnameinfo';
- function ResolveHost(HostName: ansistring): TGAIResult;
+ function ResolveHost(HostName: ansistring; Family: cint): TGAIResult;
procedure FreeHost(var GAIResult: TGAIResult);
- function ResolveIP(SockAddr: PSockAddr): ansistring;
+ function ResolveIP(AddrInfo: PAddrInfo): ansistring;
+ function IPToStr(SockAddr: PSockAddr): ansistring;
implementation
-function ResolveHost(HostName: ansistring): TGAIResult;
+function ResolveHost(HostName: ansistring; Family: cint): TGAIResult;
var hint: TAddrInfo;
begin
FillByte(hint, SizeOf(hint), 0);
with hint do begin
- ai_family:= AF_INET;
+ ai_family:= Family;
ai_socktype:= SOCK_STREAM;
ai_protocol:= IPPROTO_TCP;
end;
begin
if GAIResult.AddrInfo <> nil then begin
freeaddrinfo(GAIResult.AddrInfo);
- GAIResult.AddrInfo:= nil;
+ GAIResult.AddrInfo:= nil;
end;
end;
-function ResolveIP(SockAddr: PSockAddr): ansistring;
+function ResolveIP(AddrInfo: PAddrInfo): ansistring;
var
r: integer;
NodeBuffer: array[0..255] of char;
begin
NodeBuffer[0]:= #0;
- r:= getnameinfo(SockAddr, SizeOf(TSockAddr), @NodeBuffer, SizeOf(NodeBuffer), nil, 0, 0);
+ r:= getnameinfo(AddrInfo^.ai_addr, AddrInfo^.ai_addrlen, @NodeBuffer, SizeOf(NodeBuffer), nil, 0, 0);
if r = 0 then ResolveIP:= PChar(@NodeBuffer)
- else ResolveIP:= NetAddrToStr(SockAddr^.sin_addr);
+ else ResolveIP:= IPToStr(AddrInfo^.ai_addr);
end;
+function IPToStr(SockAddr: PSockAddr): ansistring;
+begin
+ if SockAddr^.sa_family = AF_INET then
+ IPToStr:= NetAddrToStr(SockAddr^.sin_addr)
+ else if SockAddr^.sa_family = AF_INET6 then
+ IPToStr:= NetAddrToStr6(PSockAddr6(SockAddr)^.sin6_addr)
+ else
+ IPToStr:= 'unknown';
+end;
end.
TTCPConnection = class
constructor Create; overload;
constructor Create(const HostName: string; Port: word); overload;
- constructor Create(Socket: socket; const Addr: TSockAddr); overload;
+ constructor Create(Socket: socket; const Addr: TSockAddr6); overload;
destructor Destroy; override;
private
FConnected: boolean;
FSocket: socket;
FHostIP: TIPNamePair;
FSockTimeOut: DWord;
- SockAddr: TSockAddr;
+ SockAddr: TSockAddr6;
public
function Connect(const HostName: string; Port: word): boolean;
procedure Disconnect;
end;
TTCPListener = class(TThread)
- constructor Create(const Address: string; Port: word; FeatureRequest: word);
+ constructor Create(const Address: string; Port: word; Family: word; FeatureRequest: word);
{destructor Destroy; override;}
private
FFeatureRequest: word;
+ FFamily: word;
FListenAddress: string;
FListenPort: word;
FListenSocket: socket;
- SockAddr: TSockAddr;
+ SockAddr: TSockAddr6;
protected
procedure HandleClient(Connection: TTCPConnection); virtual; abstract;
procedure Execute; override;
Connect(HostName, Port);
end;
-constructor TTCPConnection.Create(Socket: socket; const Addr: TSockAddr);
+constructor TTCPConnection.Create(Socket: socket; const Addr: TSockAddr6);
{ Use an already connected socket. }
begin
inherited Create;
FSocket:= Socket;
SockAddr:= Addr;
- FHostIP:= TIPNamePair.Create('', NetAddrToStr(Addr.sin_addr));
+ FHostIP:= TIPNamePair.Create('', IPToStr(@Addr));
FConnected:= true;
end;
end;
-constructor TTCPListener.Create(const Address: string; Port: word; FeatureRequest: word);
+constructor TTCPListener.Create(const Address: string; Port: word; Family: word; FeatureRequest: word);
begin
+ FFamily:= Family;
FListenAddress:= Address;
FListenPort:= Port;
FFeatureRequest:= FeatureRequest;
begin
FSocket:= fpSocket(af_inet, sock_stream, 0);
if (FSocket <> -1) then begin
- GAIResult:= ResolveHost(HostName);
- if GAIResult.GAIError = 0 then begin
- SockAddr:= GAIResult.AddrInfo^.ai_addr^;
- SockAddr.sin_port:= htons(Port);
+ GAIResult:= ResolveHost(HostName, AF_UNSPEC);
+ if GAIResult.GAIError = 0 then begin
+ Move(GAIResult.AddrInfo^.ai_addr^, SockAddr, GAIResult.AddrInfo^.ai_addrlen);
+ SockAddr.sin6_port:= htons(Port);
- if SockAddr.sin_addr.s_addr <> 0 then
- { Try to initiate connection. }
- FConnected:= fpConnect(FSocket, @SockAddr, SizeOf(SockAddr)) <> -1;
+ { Try to initiate connection. }
+ FConnected:= fpConnect(FSocket, @SockAddr, GAIResult.AddrInfo^.ai_addrlen) <> -1;
if FConnected then begin
- FHostIP:= TIPNamePair.Create(HostName, NetAddrToStr(SockAddr.sin_addr));
+ FHostIP:= TIPNamePair.Create(HostName, IPToStr(@SockAddr));
SetSockTimeOut(FSockTimeOut);
end
else
var GAIResult: TGAIResult; ai: PAddrInfo;
begin
Result:= false;
- GAIResult:= ResolveHost(HostIP.Name);
+ GAIResult:= ResolveHost(HostIP.Name, AF_UNSPEC);
if GAIResult.GAIError = 0 then begin
ai:= GAIResult.AddrInfo;
- { One of the addresses must match. }
- while (ai <> nil) and not Result do begin
- Result:= NetAddrToStr(ai^.ai_addr^.sin_addr) = HostIP.IP;
- ai:= ai^.ai_next;
+ { One of the addresses must match. }
+ while (ai <> nil) and not Result do begin
+ Result:= IPToStr(ai^.ai_addr) = HostIP.IP;
+ ai:= ai^.ai_next;
end;
end;
end;
function TTCPListener.StartListen: boolean;
var GAIResult: TGAIResult;
begin
- FListenSocket:= fpSocket(af_inet, sock_stream, 0);
+ FListenSocket:= fpSocket(FFamily, SOCK_STREAM, 0);
if FListenSocket <> -1 then begin
- GAIResult:= ResolveHost(FListenAddress);
- if GAIResult.GAIError = 0 then begin
- SockAddr:= GAIResult.AddrInfo^.ai_addr^;
- SockAddr.sin_port:= htons(FListenPort);
+ GAIResult:= ResolveHost(FListenAddress, FFamily);
+ if GAIResult.GAIError = 0 then begin
+ Move(GAIResult.AddrInfo^.ai_addr^, SockAddr, GAIResult.AddrInfo^.ai_addrlen);
+ SockAddr.sin6_port:= htons(FListenPort);
- if fpBind(FListenSocket, @SockAddr, SizeOf(SockAddr)) <> -1 then begin
+ if fpBind(FListenSocket, @SockAddr, GAIResult.AddrInfo^.ai_addrlen) <> -1 then begin
{ It seems the maximum connection value isn't enforced by the
Free Pascal library, so this 512 is a constant, dummy value. }
if fpListen(FListenSocket, 512) <> -1 then begin