Use getaddrinfo & getnameinfo
[mgsmtp.git] / Network.pas
index 10a95f991d3898060489ecfdc31d252c242b81d7..d5b458da2d5919570e2805ae5416b63eac408752 100644 (file)
@@ -61,7 +61,7 @@ type
       FSocket: socket;
       FHostIP: TIPNamePair;
       FSockTimeOut: DWord;
       FSocket: socket;
       FHostIP: TIPNamePair;
       FSockTimeOut: DWord;
-      sAddr: TSockAddr;
+      SockAddr: TSockAddr;
    public
       function Connect(const HostName: string; Port: word): boolean;
       procedure Disconnect;
    public
       function Connect(const HostName: string; Port: word): boolean;
       procedure Disconnect;
@@ -106,7 +106,7 @@ type
       FListenAddress: string;
       FListenPort: word;
       FListenSocket: socket;
       FListenAddress: string;
       FListenPort: word;
       FListenSocket: socket;
-      sAddr: TSockAddr;
+      SockAddr: TSockAddr;
    protected
       procedure HandleClient(Connection: TTCPConnection); virtual; abstract;
       procedure Execute; override;
    protected
       procedure HandleClient(Connection: TTCPConnection); virtual; abstract;
       procedure Execute; override;
@@ -133,7 +133,7 @@ end;
 constructor TTCPConnection.Create(const HostName: string; Port: word);
 { Connect to the given port on the given hostname. }
 begin
 constructor TTCPConnection.Create(const HostName: string; Port: word);
 { Connect to the given port on the given hostname. }
 begin
-   inherited Create;
+   Create;
    Connect(HostName, Port);
 end;
 
    Connect(HostName, Port);
 end;
 
@@ -142,7 +142,7 @@ constructor TTCPConnection.Create(Socket: socket; const Addr: TSockAddr);
 begin
    inherited Create;
    FSocket:= Socket;
 begin
    inherited Create;
    FSocket:= Socket;
-   sAddr:= Addr;
+   SockAddr:= Addr;
    FHostIP:= TIPNamePair.Create('', NetAddrToStr(Addr.sin_addr));
    FConnected:= true;
 end;
    FHostIP:= TIPNamePair.Create('', NetAddrToStr(Addr.sin_addr));
    FConnected:= true;
 end;
@@ -170,32 +170,35 @@ begin
    FListenPort:= Port;
    FFeatureRequest:= FeatureRequest;
    FreeOnTerminate:= false;
    FListenPort:= Port;
    FFeatureRequest:= FeatureRequest;
    FreeOnTerminate:= false;
+   FillChar(SockAddr, SizeOf(SockAddr), 0);
    inherited Create(true);
 end;
 
 
 function TTCPConnection.Connect(const HostName: string; Port: word): boolean;
 { Resolves the given hostname, and tries to connect it on the given port. }
    inherited Create(true);
 end;
 
 
 function TTCPConnection.Connect(const HostName: string; Port: word): boolean;
 { Resolves the given hostname, and tries to connect it on the given port. }
+var GAIResult: TGAIResult;
 begin
    FSocket:= fpSocket(af_inet, sock_stream, 0);
    if (FSocket <> -1) then begin
 begin
    FSocket:= fpSocket(af_inet, sock_stream, 0);
    if (FSocket <> -1) then begin
-      with sAddr do begin
-         sin_family:= af_inet;
-         sin_port:= htons(Port);
-         { Resolve hostname to IP address. }
-         sin_addr:= ResolveHost(HostName);
+      GAIResult:= ResolveHost(HostName);
+         if GAIResult.GAIError = 0 then begin
+            SockAddr:= GAIResult.AddrInfo^.ai_addr^;
+                SockAddr.sin_port:= htons(Port);
+
+                if SockAddr.sin_addr.s_addr <> 0 then
+                   { Try to initiate connection. }
+                   FConnected:= fpConnect(FSocket, @SockAddr, SizeOf(SockAddr)) <> -1;
+
+                if FConnected then begin
+                   FHostIP:= TIPNamePair.Create(HostName, NetAddrToStr(SockAddr.sin_addr));
+                   SetSockTimeOut(FSockTimeOut);
+                end
+                else
+                   CloseSocket(FSocket);
+
+         FreeHost(GAIResult);
       end;
       end;
-
-      if sAddr.sin_addr.s_addr <> 0 then
-         { Try to initiate connection. }
-         FConnected:= fpConnect(FSocket, @sAddr, SizeOf(sAddr)) <> -1;
-
-      if FConnected then begin
-         FHostIP:= TIPNamePair.Create(HostName, NetAddrToStr(sAddr.sin_addr));
-         SetSockTimeOut(FSockTimeOut);
-      end
-      else
-         CloseSocket(FSocket);
    end;
    Result:= FConnected;
 end;
    end;
    Result:= FConnected;
 end;
@@ -214,15 +217,25 @@ procedure TTCPConnection.ReverseDNSLookup;
 var NHostIP: TIPNamePair;
 begin
    if FConnected then begin
 var NHostIP: TIPNamePair;
 begin
    if FConnected then begin
-      NHostIP:= TIPNamePair.Create(ResolveIP(sAddr.sin_addr), FHostIP.IP);
+      NHostIP:= TIPNamePair.Create(ResolveIP(@SockAddr), FHostIP.IP);
       FHostIP.Free;
       FHostIP:= NHostIP;
    end;
 end;
 
 function TTCPConnection.VerifyFCrDNS: boolean;
       FHostIP.Free;
       FHostIP:= NHostIP;
    end;
 end;
 
 function TTCPConnection.VerifyFCrDNS: boolean;
+var GAIResult: TGAIResult; ai: PAddrInfo;
 begin
 begin
-   Result:= NetAddrToStr(ResolveHost(HostIP.Name)) = HostIP.IP;
+   Result:= false;
+   GAIResult:= ResolveHost(HostIP.Name);
+   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;
+      end;
+   end;
 end;
 
 procedure TTCPConnection.SetSockTimeOut(TimeOut: DWord);
 end;
 
 procedure TTCPConnection.SetSockTimeOut(TimeOut: DWord);
@@ -288,24 +301,29 @@ end;
 
 
 function TTCPListener.StartListen: boolean;
 
 
 function TTCPListener.StartListen: boolean;
+var GAIResult: TGAIResult;
 begin
    FListenSocket:= fpSocket(af_inet, sock_stream, 0);
    if FListenSocket <> -1 then begin
 begin
    FListenSocket:= fpSocket(af_inet, sock_stream, 0);
    if FListenSocket <> -1 then begin
-      with sAddr do begin
-         sin_family:= af_inet;
-         sin_port:= htons(FListenPort);
-         sin_addr:= ResolveHost(FListenAddress);
-      end;
-      if fpBind(FListenSocket, @sAddr, sizeof(sAddr)) <> -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
-            Result:= true;
-            Start;
+      GAIResult:= ResolveHost(FListenAddress);
+         if GAIResult.GAIError = 0 then begin
+            SockAddr:= GAIResult.AddrInfo^.ai_addr^;
+                SockAddr.sin_port:= htons(FListenPort);
+
+         if fpBind(FListenSocket, @SockAddr, SizeOf(SockAddr)) <> -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
+               Result:= true;
+               Start;
+            end
+            else Result:= false;
          end
          else Result:= false;
          end
          else Result:= false;
+
+         FreeHost(GAIResult);
       end
       end
-      else Result:= false;
+         else Result:= false;
    end
    else Result:= false;
 end;
    end
    else Result:= false;
 end;
@@ -323,8 +341,8 @@ begin
    { Now, accept connections. }
    AcceptFailCount:= 0;
    while not Terminated do begin
    { Now, accept connections. }
    AcceptFailCount:= 0;
    while not Terminated do begin
-      Len:= SizeOf(sAddr);
-      ClientSocket:= fpAccept(FListenSocket, @sAddr, @Len);
+      Len:= SizeOf(SockAddr);
+      ClientSocket:= fpAccept(FListenSocket, @SockAddr, @Len);
       if ClientSocket <> -1 then begin
          AcceptFailCount:= 0;
 
       if ClientSocket <> -1 then begin
          AcceptFailCount:= 0;
 
@@ -332,9 +350,9 @@ begin
            connection. }
          case FFeatureRequest of
          NET_TCP_BASIC:
            connection. }
          case FFeatureRequest of
          NET_TCP_BASIC:
-            TCPConnection:= TTCPConnection.Create(ClientSocket, sAddr);
+            TCPConnection:= TTCPConnection.Create(ClientSocket, SockAddr);
          NET_TCP_RFCSUPPORT:
          NET_TCP_RFCSUPPORT:
-            TCPConnection:= TTCPRFCConnection.Create(ClientSocket, sAddr);
+            TCPConnection:= TTCPRFCConnection.Create(ClientSocket, SockAddr);
          end;
 
          { Then start a new thread with the connection handler. }
          end;
 
          { Then start a new thread with the connection handler. }