fpc/fcl/inc/resolve.pp
2004-02-02 14:42:00 +00:00

980 lines
21 KiB
ObjectPascal

{$MODE OBJFPC}
{$H+}
Unit resolve;
{$ifndef win32}
// Here till BSD supports the netbsd unit.
// MvdV: NetBSD unit? Where?
{$ifdef Unix}
// Undefine this to use the C library resolve routines.
// Don't use under win32, netdb does not work on Win32 (yet) !!
{$define usenetdb}
{$endif Unix}
{$endif}
{ --------------------------------------------------------------------
Unit for internet domain calls.
Copyright (C) 2003 Michael Van Canneyt
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 1, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
------------------------------------------------------------------- }
interface
uses
Classes,UriParser;
Type
THostAddr = array[1..4] of byte;
PHostAddr = ^THostAddr;
TNetAddr = THostAddr;
PNetAddr = ^TNetAddr;
Const
NoAddress : THostAddr = (0,0,0,0);
NoNet : TNetAddr = (0,0,0,0);
{ ---------------------------------------------------------------------
Axuliary routines
---------------------------------------------------------------------}
function HostAddrToStr (Entry : THostAddr) : String;
function StrToHostAddr (IP : String) : THostAddr;
function NetAddrToStr (Entry : TNetAddr) : String;
function StrToNetAddr (IP : String) : TNetAddr;
Function HostToNet (Host : ThostAddr) : ThostAddr;
Function HostToNet (Host : Longint) : Longint;
Function NetToHost (Net : Longint) : Longint;
Function NetToHost (Net : TNetAddr) : TNetAddr;
Function ShortHostToNet (Host : Word) : Word;
Function ShortNetToHost (Net : Word) : Word;
Type
{ ---------------------------------------------------------------------
TResolver
---------------------------------------------------------------------}
TResolver = Class (TComponent)
Private
FName : String;
FAliases : TStringList;
FRaiseOnError : Boolean;
FLastError: Integer;
Function GetAlias(Index : Integer) : STring;
Function GetAliasCount : Integer;
Function GetAliasSorted : Boolean;
Procedure SetAliasSorted (Value : Boolean);
Protected
Procedure CheckOperation(Msg : String);
Function NameLookup(Const S : String) : Boolean; virtual;
Procedure SaveAliases(P : PPChar);
Public
Constructor Create(AOwner : TComponent); override;
Destructor Destroy; override;
Procedure ClearData; virtual;
Property ResolvedName : String Read FName;
Property Aliases [Index : integer ] : string Read GetAlias;
Property AliasCount : Integer read GetAliasCount;
Property SortAliases : Boolean Read GetAliasSorted Write SetAliasSorted;
Property RaiseOnError : Boolean Read FRaiseOnError Write FRAiseOnError;
Property LastError : Integer Read FlastError;
end;
{ ---------------------------------------------------------------------
THostResolver
---------------------------------------------------------------------}
THostResolver = Class(TResolver)
Private
FHostAddress : THostAddr;
FAddressCount : Integer;
FAddresses : PHostAddr;
Function GetAddress (Index : Integer) : THostAddr;
Function GetNetAddress (Index : Integer) : THostAddr;
Function GetNetHostAddress : THostAddr;
Function GetAsString : String;
Procedure SaveHostEntry (Entry : Pointer);
Public
Procedure ClearData; Override;
Function NameLookup(Const S : String) : Boolean; override;
Function AddressLookup(Const S : String) : Boolean; virtual;
Function AddressLookup(Const Address : THostAddr) : Boolean; virtual;
Property HostAddress : THostAddr Read FHostAddress;
Property NetHostAddress : THostAddr Read GetNetHostAddress;
Property AddressAsString : String Read GetAsString;
Property AddressCount : Integer Read FAddressCount ;
Property Addresses [Index : Integer] : ThostAddr Read GetAddress;
Property NetAddresses [Index : Integer] : ThostAddr Read GetNetAddress;
end;
{ ---------------------------------------------------------------------
TNetResolver
---------------------------------------------------------------------}
TNetResolver = Class(TResolver)
Private
FNetAddress : TNetAddr;
FAddrType : Integer;
Function GetAsString : String;
Procedure SaveNetEntry(Entry : Pointer);
Function GetNetAddress : TNetAddr;
Public
Procedure ClearData; override;
Function NameLookup(Const S : String) : boolean; override;
Function AddressLookup(Const S : String) : Boolean; virtual;
Function AddressLookup(Const Address : TNetAddr) : Boolean; virtual;
Property NetAddress : TNetAddr Read FNetAddress;
Property NetNetAddress : TNetAddr Read GetNetAddress;
Property AddressAsString : String Read GetAsString;
Property AddressType : Integer Read FAddrType;
end;
{ ---------------------------------------------------------------------
TServiceResolver
---------------------------------------------------------------------}
TServiceResolver = Class(TResolver)
private
FProtocol : String;
FPort : Integer;
Procedure SaveServiceEntry(Entry : Pointer);
Function GetNetPort : Integer ;
public
Procedure ClearData; override;
Function NameLookup (Const S : String) : boolean; override;
Function NameLookup (Const S,Proto : String) : Boolean;
Function PortLookup (APort : Longint; Proto: string) : Boolean;
Property Protocol : String Read FProtocol;
Property Port : Integer Read FPort;
Property NetPort : Integer Read GetNetPort;
end;
TURIParser = Class(TComponent)
Private
FActive : Boolean;
FProtocol: String;
FUsername: String;
FPassword: String;
FHost: String;
FPort: Word;
FPath: String;
FDocument: String;
FParams: String;
FBookmark: String;
FURI : String;
Protected
Procedure SetElement (Index : Integer; Value : String);Virtual;
Function GetElement(Index : Integer) : String;
Procedure SetPort(Value : Word);
Procedure SetURI(Value : String);
Public
Procedure Clear;
Procedure ParseUri(AURI : String);
Function ComposeURI : String;
Published
Property Port: Word Read FPort Write SetPort;
Property Protocol: String Index 0 Read GetElement Write SetElement;
Property Username: String Index 1 Read GetElement Write SetElement;
Property Password: String Index 2 Read GetElement Write SetElement;
Property Host: String Index 3 Read GetElement Write SetElement;
Property Path: String index 4 Read GetElement Write SetElement;
Property Document: String index 5 read GetElement Write SetElement;
Property Params: String Index 6 read GetElement Write SetElement;
Property Bookmark: String Index 7 Read GetElement Write SetElement;
Property URI : String Read FURI write SetURI;
Property Active : Boolean Read FActive Write FActive;
end;
Resourcestring
SErrHostByName = 'Host by name';
SErrHostByAddr = 'Host by address';
SErrNetByName = 'Net by name';
SErrServByName = 'Service by name';
SErrServByPort = 'Service by port';
Implementation
{ ---------------------------------------------------------------------
Include system dependent stuff.
---------------------------------------------------------------------}
{$ifdef usenetdb}
uses netdb;
{$else}
{$i resolve.inc}
{$endif}
function HostAddrToStr (Entry : THostAddr) : String;
Var Dummy : String[4];
I : Longint;
begin
HostAddrToStr:='';
For I:=1 to 4 do
begin
Str(Entry[I],Dummy);
HostAddrToStr:=HostAddrToStr+Dummy;
If I<4 Then
HostAddrToStr:=HostAddrToStr+'.';
end;
end;
function StrToHostAddr(IP : String) : THostAddr ;
Var
Dummy : String;
I : Longint;
J : Integer;
Temp : THostAddr;
begin
Result:=NoAddress;
For I:=1 to 4 do
begin
If I<4 Then
begin
J:=Pos('.',IP);
If J=0 then
exit;
Dummy:=Copy(IP,1,J-1);
Delete (IP,1,J);
end
else
Dummy:=IP;
Val (Dummy,Temp[I],J);
If J<>0 then Exit;
end;
Result:=Temp;
end;
function NetAddrToStr (Entry : TNetAddr) : String;
Var Dummy : String[4];
I : Longint;
begin
NetAddrToStr:='';
For I:=4 downto 1 do
begin
Str(Entry[I],Dummy);
NetAddrToStr:=NetAddrToStr+Dummy;
If I>1 Then
NetAddrToStr:=NetAddrToStr+'.';
end;
end;
function StrToNetAddr(IP : String) : TNetAddr;
begin
StrToNetAddr:=TNetAddr(StrToHostAddr(IP));
end;
Function HostToNet (Host : ThostAddr) : THostAddr;
begin
Result[1]:=Host[4];
Result[2]:=Host[3];
Result[3]:=Host[2];
Result[4]:=Host[1];
end;
Function NetToHost (Net : TNetAddr) : TNetAddr;
begin
Result[1]:=Net[4];
Result[2]:=Net[3];
Result[3]:=Net[2];
Result[4]:=Net[1];
end;
Function HostToNet (Host : Longint) : Longint;
begin
Result:=Longint(HostToNet(THostAddr(host)));
end;
Function NetToHost (Net : Longint) : Longint;
begin
Result:=Longint(NetToHost(TNetAddr(Net)));
end;
Function ShortHostToNet (Host : Word) : Word;
begin
ShortHostToNet:=lo(host)*256+Hi(Host);
end;
Function ShortNetToHost (Net : Word) : Word;
begin
ShortNetToHost:=lo(Net)*256+Hi(Net);
end;
{ ---------------------------------------------------------------------
TResolver
---------------------------------------------------------------------}
Constructor TResolver.Create(AOwner : TComponent);
begin
Inherited;
FAliases:=TstringList.Create;
end;
Destructor TResolver.Destroy;
begin
ClearData;
FAliases.Free;
end;
Procedure TResolver.ClearData;
begin
FName:='';
FAliases.Clear;
end;
Function TResolver.GetAlias(Index : Integer) : STring;
begin
Result:=FAliases[Index];
end;
Function TResolver.GetAliasCount : Integer;
begin
Result:=FAliases.Count;
end;
Function TResolver.GetAliasSorted : Boolean;
begin
Result:=FAliases.Sorted;
end;
Procedure TResolver.SetAliasSorted (Value : Boolean);
begin
FAliases.Sorted:=Value;
end;
Procedure TResolver.CheckOperation(Msg : String);
begin
end;
Function TResolver.NameLookup(Const S : String) : Boolean;
begin
ClearData;
FName:=S;
Result:=True;
end;
Procedure TResolver.SaveAliases(P : PPChar);
Var
I : Integer;
begin
If (P<>Nil) then
begin
I:=0;
While P[I]<>Nil do
begin
FAliases.Add(StrPas(P[I]));
Inc(I);
end;
end;
end;
{ ---------------------------------------------------------------------
THostResolver
---------------------------------------------------------------------}
Function THostResolver.GetAddress (Index : Integer) : THostAddr;
begin
If (Index>=0) and (Index<FAddressCount) then
Result:=FAddresses[Index];
end;
Function THostResolver.GetAsString : String;
begin
Result:=HostAddrToStr(FHostAddress);
end;
Procedure THostResolver.ClearData;
begin
Inherited;
FHostAddress:=NoAddress;
If FAddressCount<>0 Then
FreeMem(FAddresses);
FAddressCount:=0;
FAddresses:=Nil;
end;
Function THostResolver.AddressLookup(Const S : String) : Boolean;
begin
Result:=AddressLookup(StrToHostAddr(S));
end;
{$ifdef usenetdb}
Function THostResolver.NameLookup (Const S : String) : Boolean;
Var
H : THostEntry;
begin
Result:=Inherited NameLookup(S);
If Result then
begin
Result:=GetHostByName(S,H);
if not Result then
Result:=ResolveHostByName(S,H);
If Result then
SaveHostEntry(@H);
end;
end;
Function THostResolver.AddressLookup (Const Address: THostAddr) : Boolean;
Var
H : THostEntry;
begin
ClearData;
Result:=ResolveHostByAddr(Address,H);
If Result then
SaveHostEntry(@H);
end;
Procedure THostResolver.SaveHostEntry(Entry : Pointer);
Var
PH : ^THostEntry;
I : Integer;
begin
PH:=ENtry;
FName:=PH^.Name;
FHostAddress:=PH^.Addr;
FAddressCount:=1;
GetMem(FAddresses,SizeOf(THostAddr));
FAddresses[0]:=PH^.Addr;
FAliases.CommaText:=PH^.Aliases;
end;
{$else}
Function THostResolver.NameLookup (Const S : String) : Boolean;
Var
FHostEntry : PHostEntry;
begin
Result:=Inherited NameLookup(S);
If Result then
begin
FHostEntry:=ResolveHostByName(pchar(FName));
Result:=FHostEntry<>Nil;
If Result then
SaveHostEntry(FHostEntry)
else
begin
FLastError:=GetDNSError;
CheckOperation(SErrHostByName);
end;
end;
end;
Procedure THostResolver.SaveHostEntry(Entry : Pointer);
Var
P : Pointer;
I,Count : Integer;
begin
With PHostEntry(Entry)^ do
begin
FName:=StrPas(H_Name);
FAddressCount:=0;
While H_Addr[FAddressCount]<>Nil do
Inc(FAddressCount);
If FAddressCount>0 then
begin
GetMem(FAddresses,FAddressCount*SizeOf(THostAddr));
For I:=0 to FAddressCount-1 do
FAddresses[I]:=PHostAddr(H_Addr[I])^;
FHostAddress:=FAddresses[0];
end;
SaveAliases(H_Aliases);
end;
end;
Function THostResolver.AddressLookup (Const Address: THostAddr) : Boolean;
Var
FHostEntry : PHostEntry;
begin
ClearData;
FHostEntry:=ResolveHostByAddr(Pchar(@Address),SizeOf(Address),AF_INET);
Result:=FHostEntry<>Nil;
If Result then
SaveHostEntry(FHostEntry)
else
begin
FLastError:=GetDNSError;
CheckOperation(SErrHostByAddr);
end;
end;
{$endif}
Function THostResolver.GetNetAddress (Index : Integer) : THostAddr;
begin
Result:=HostToNet(Addresses[Index]);
end;
Function THostResolver.GetNetHostAddress : THostAddr;
begin
Result:=HostToNet(FHostAddress);
end;
{ ---------------------------------------------------------------------
TNetResolver
---------------------------------------------------------------------}
{$ifdef usenetdb}
Function TNetResolver.AddressLookup (Const Address: TNetAddr) : boolean;
Var
N : TNetworkEntry;
begin
ClearData;
Result:=GetNetworkByAddr(Address,N);
If Result then
SaveNetEntry(@N);
end;
Function TNetResolver.NameLookup (Const S : String) : Boolean;
Var
N : TNetworkEntry;
begin
Result:=Inherited NameLookup(S);
If Result then
begin
Result:=GetNetworkByName(S,N);
If Result then
SaveNetEntry(@N);
end;
end;
Procedure TNetResolver.SaveNetEntry(Entry : Pointer);
Var
PN : ^TNetworkEntry;
begin
PN:=ENtry;
FName:=PN^.Name;
FNetAddress:=PN^.Addr;
FAliases.CommaText:=PN^.Aliases;
end;
{$else}
Function TNetResolver.NameLookup (Const S : String) : Boolean;
Var
FNetEntry : PNetEntry;
begin
Result:=Inherited NameLookup(S);
If Result then
begin
FNetEntry:=GetNetByName(pchar(S));
Result:=FNetEntry<>Nil;
If Result then
SaveNetEntry(FNetEntry)
else
begin
FLastError:=GetDNSError;
Checkoperation(SErrNetByName);
end;
end;
end;
Procedure TNetResolver.SaveNetEntry(Entry : Pointer);
begin
With PNetEntry(Entry)^ do
begin
FName:=StrPas(N_Name);
FAddrType:=N_addrtype;
FNetAddress:=NetToHost(TNetAddr(N_net));
SaveAliases(N_Aliases);
end;
end;
Function TNetResolver.AddressLookup (Const Address: TNetAddr) : boolean;
Var
FNetEntry : PNetEntry;
begin
ClearData;
{$ifndef win32}
FNetEntry:=GetNetByAddr(Longint(HostToNet(Address)),AF_INET);
{$else}
FNetEntry:=Nil;
{$endif}
Result:=FNetEntry<>Nil;
If Result then
SaveNetEntry(FNetEntry)
else
begin
FLastError:=GetDNSError;
CheckOperation(SErrNetByName);
end;
end;
{$endif}
Function TNetResolver.AddressLookup(Const S : String) : Boolean;
begin
Result:=AddressLookup(StrToNetAddr(S));
end;
Function TNetResolver.GetAsString : String;
begin
Result:=HostAddrToStr(FNetAddress);
end;
Function TNetResolver.GetNetAddress : TNetAddr;
begin
Result:=HostToNet(FNetAddress);
end;
Procedure TNetResolver.ClearData;
begin
Inherited;
FNetAddress:=NoAddress;
FAddrType:=0;
end;
{ ---------------------------------------------------------------------
TServiceResolver
---------------------------------------------------------------------}
Function TServiceResolver.NameLookup (Const S : String) : Boolean;
begin
Result:=NameLookup(S,'');
end;
{$ifdef usenetdb}
Function TServiceResolver.NameLookup (Const S,Proto : String) : Boolean;
Var
E : TServiceEntry;
begin
ClearData;
Result:=GetServiceByName(S,Proto,E);
If Result then
SaveServiceEntry(@E);
end;
Function TServiceResolver.PortLookup (APort: Longint; Proto : String) : Boolean;
Var
E : TServiceEntry;
begin
ClearData;
Result:=GetServiceByPort(APort,Proto,E);
If Result then
SaveServiceEntry(@E);
end;
Procedure TServiceResolver.SaveServiceEntry(Entry : Pointer);
Var
PE : ^TServiceEntry;
begin
PE:=Entry;
FName:=PE^.Name;
FPort:=PE^.Port;
FProtocol:=PE^.Protocol;
FAliases.CommaText:=PE^.Aliases;
end;
{$else}
Function TServiceResolver.NameLookup (Const S,Proto : String) : Boolean;
Var
FServiceEntry : PServEntry;
begin
ClearData;
FName:=S;
FProtocol:=Proto;
If (proto='') then
FServiceEntry:=GetServByName(pchar(S),Nil)
else
FServiceEntry:=GetServByName(pchar(S),PChar(FProtocol));
Result:=FServiceEntry<>Nil;
If Result then
SaveServiceEntry(FServiceEntry)
else
begin
FLastError:=GetDNSError;
CheckOperation(SErrServByName);
end;
end;
Function TServiceResolver.PortLookup (APort: Longint; Proto : String) : Boolean;
Var
FServiceEntry : PServEntry;
begin
ClearData;
APort:=ShortHostToNet(APort);
FProtoCol:=Proto;
If (Proto='') then
FServiceEntry:=GetServByPort(APort,Nil)
else
FServiceEntry:=GetServByPort(APort,pchar(Proto));
Result:=FServiceEntry<>Nil;
If Result then
SaveServiceEntry(FServiceEntry)
else
begin
FLastError:=GetDNSError;
CheckOperation(SErrServByPort);
end;
end;
Procedure TServiceResolver.SaveServiceEntry(Entry : Pointer);
begin
With PServEntry(Entry)^ do
begin
FName:=strpas(s_name);
FPort:=ShortHostToNet(S_port);
FProtocol:=strpas(s_proto);
SaveAliases(S_aliases);
end;
end;
{$endif}
Procedure TServiceResolver.ClearData;
begin
Inherited;
FProtocol:='';
FPort:=0;
end;
Function TServiceResolver.GetNetPort : Integer;
begin
Result:=ShortHostToNet(FPort);
end;
{ ---------------------------------------------------------------------
TURIParser
---------------------------------------------------------------------}
Procedure TURIParser.SetElement (Index : Integer; Value : String);
begin
Case index of
0 : FProtocol := Value;
1 : FUsername := Value;
2 : FPassword := Value;
3 : FHost := Value;
4 : FPath := Value;
5 : FDocument := Value;
6 : FParams := Value;
7 : FBookmark := Value;
else
end;
If FActive and not (csLoading in ComponentState) then
FURI:=ComposeURI;
end;
Function TURIParser.GetElement(Index : Integer) : String;
begin
Case Index of
0 : Result := FProtocol;
1 : Result := FUsername;
2 : Result := FPassword;
3 : Result := FHost ;
4 : Result := FPath ;
5 : Result := FDocument;
6 : Result := FParams ;
7 : Result := FBookmark;
else
Result:='';
end;
end;
Procedure TURIParser.SetPort(Value : Word);
begin
FPort:=Value;
If FActive and not (csLoading in ComponentState) then
FURI:=ComposeURI;
end;
Procedure TURIParser.SetURI(Value : String);
begin
If Active and not (csLoading in ComponentState) then
begin
Clear;
ParseUri(Value);
end;
FURI:=Value;
end;
Procedure TURIParser.Clear;
begin
FProtocol :='';
FUsername :='';
FPassword :='';
FHost :='';
FPort :=0;
FPath :='';
FDocument :='';
FParams :='';
FBookmark :='';
FURI :='';
end;
Procedure TURIParser.ParseUri(AURI : String);
Var
U : TURI;
begin
U:=UriParser.ParseURI(AUri);
FProtocol := u.Protocol;
FUsername := u.Username;
FPassword := u.Password;
FHost := u.Host ;
FPort := u.Port ;
FPath := u.Path ;
FDocument := u.Document;
FParams := u.Params ;
FBookmark := u.Bookmark;
end;
Function TURIParser.ComposeURI : String;
var
U : TURI;
begin
U.Protocol := FProtocol;
U.Username := FUsername;
U.Password := FPassword;
U.Host := FHost ;
U.Port := FPort ;
U.Path := FPath ;
U.Document := FDocument;
U.Params := FParams ;
U.Bookmark := FBookmark;
Result:=EncodeUri(U);
end;
{$ifdef usenetdb}
Procedure InitResolve;
begin
end;
Procedure FinalResolve;
begin
end;
{$endif}
Initialization
InitResolve;
Finalization
FinalResolve;
end.
{
$Log$
Revision 1.8 2004-02-02 14:42:00 marco
* more small fixes
Revision 1.7 2004/01/31 19:02:50 sg
* Tries to first resolve names locally before contacting the DNS server
Revision 1.6 2003/12/11 09:23:50 marco
* patch from peter
Revision 1.5 2003/12/10 15:50:50 marco
* fpgetcerrno introduction
Revision 1.4 2003/05/17 21:52:37 michael
+ Added TURIParser class
Revision 1.3 2003/03/07 20:33:33 michael
Use native pascal netdb on Linux
Revision 1.2 2003/02/03 10:14:12 michael
+ Added init/final routines to initialize winsock library
Revision 1.1 2003/02/01 16:50:38 michael
+ Added resolve unit for WIndows/unix
}