Add IPv6 support to Network unit
authorMegaBrutal <code+git@megabrutal.com>
Tue, 30 Oct 2018 00:55:55 +0000 (01:55 +0100)
committerMegaBrutal <code+git@megabrutal.com>
Tue, 30 Oct 2018 00:55:55 +0000 (01:55 +0100)
Made the DNSResolve and Network units IP version agnostic.

modified:   DNSResolve.pas
modified:   Network.pas

DNSResolve.pas
Network.pas

index 2ca6439012e325b974d8c3df13b71bd19d6298fa..fb4b467bd6424946f05825e80f7dde6f2958a09f 100644 (file)
@@ -53,20 +53,21 @@ type
       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;
@@ -77,21 +78,30 @@ procedure FreeHost(var GAIResult: TGAIResult);
 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.
index d5b458da2d5919570e2805ae5416b63eac408752..b19dd7dcbe144741369c301e3dfc71a03f24e8cc 100644 (file)
@@ -54,14 +54,14 @@ type
    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;
@@ -99,14 +99,15 @@ type
    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;
@@ -137,13 +138,13 @@ begin
    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;
 
@@ -164,8 +165,9 @@ begin
 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;
@@ -181,17 +183,16 @@ var GAIResult: TGAIResult;
 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
@@ -227,13 +228,13 @@ function TTCPConnection.VerifyFCrDNS: boolean;
 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;
@@ -303,14 +304,14 @@ 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