restemplate/indy/System/IdWship6.pas

1528 lines
48 KiB
Plaintext

{
$Project$
$Workfile$
$Revision$
$DateUTC$
$Id$
This file is part of the Indy (Internet Direct) project, and is offered
under the dual-licensing agreement described on the Indy website.
(http://www.indyproject.org/)
Copyright:
(c) 1993-2005, Chad Z. Hower and the Indy Pit Crew. All rights reserved.
}
{
$Log$
}
{
Rev 1.0 2004.02.03 3:14:52 PM czhower
Move and updates
Rev 1.2 10/15/2003 9:43:20 PM DSiders
Added localization comments.
Rev 1.1 1-10-2003 19:44:28 BGooijen
fixed leak in CloseLibrary()
Rev 1.0 11/13/2002 09:03:24 AM JPMugaas
}
unit IdWship6;
interface
{$I IdCompilerDefines.inc}
{$IFDEF FPC}
{$IFDEF WIN32}
{$ALIGN OFF}
{$ELSE}
//It turns out that Win64 and WinCE require record alignment
{$PACKRECORDS C}
{$ENDIF}
{$ELSE}
{$IFDEF WIN64}
{$ALIGN ON}
{$MINENUMSIZE 4}
{$ELSE}
{$MINENUMSIZE 4}
{$IFDEF REQUIRES_PROPER_ALIGNMENT}
{$ALIGN ON}
{$ELSE}
{$ALIGN OFF}
{$WRITEABLECONST OFF}
{$ENDIF}
{$ENDIF}
{$ENDIF}
uses
{$IFDEF HAS_TInterlocked}
syncobjs, //here to facilitate inlining with Delphi
{$ENDIF}
{$IFNDEF HAS_SIZE_T}
IdGlobal,
{$ENDIF}
Windows,
IdWinsock2;
const
Wship6_dll = 'Wship6.dll'; {do not localize}
iphlpapi_dll = 'iphlpapi.dll'; {do not localize}
fwpuclnt_dll = 'Fwpuclnt.dll'; {Do not localize}
// Error codes from getaddrinfo().
//JPM
//Note that I am adding a GIA_ prefix on my own because
//some names here share some names defined in IdWinsock2 causing
//an unpredictible problem. The values are not defined the same in IdWinsock2
{$EXTERNALSYM GIA_EAI_ADDRFAMILY}
GIA_EAI_ADDRFAMILY = 1 ; // Address family for nodename not supported.
{$EXTERNALSYM GIA_EAI_AGAIN}
GIA_EAI_AGAIN = 2 ; // Temporary failure in name resolution.
{$EXTERNALSYM GIA_EAI_BADFLAGS}
GIA_EAI_BADFLAGS = 3 ; // Invalid value for ai_flags.
{$EXTERNALSYM GIA_EAI_FAIL}
GIA_EAI_FAIL = 4 ; // Non-recoverable failure in name resolution.
{$EXTERNALSYM GIA_EAI_FAMILY}
GIA_EAI_FAMILY = 5 ; // Address family ai_family not supported.
{$EXTERNALSYM GIA_EAI_MEMORY}
GIA_EAI_MEMORY = 6 ; // Memory allocation failure.
{$EXTERNALSYM GIA_EAI_NODATA}
GIA_EAI_NODATA = 7 ; // No address associated with nodename.
{$EXTERNALSYM GIA_EAI_NONAME}
GIA_EAI_NONAME = 8 ; // Nodename nor servname provided, or not known.
{$EXTERNALSYM GIA_EAI_SERVICE}
GIA_EAI_SERVICE = 9 ; // Servname not supported for ai_socktype.
{$EXTERNALSYM GIA_EAI_SOCKTYPE}
GIA_EAI_SOCKTYPE = 10 ; // Socket type ai_socktype not supported.
{$EXTERNALSYM GIA_EAI_SYSTEM}
GIA_EAI_SYSTEM = 11 ; // System error returned in errno.
{$EXTERNALSYM NI_MAXHOST}
NI_MAXHOST = 1025; // Max size of a fully-qualified domain name.
{$EXTERNALSYM NI_MAXSERV}
NI_MAXSERV = 32; // Max size of a service name.
// Flags for getnameinfo().
{$EXTERNALSYM NI_NOFQDN}
NI_NOFQDN = $1 ; // Only return nodename portion for local hosts.
{$EXTERNALSYM NI_NUMERICHOST}
NI_NUMERICHOST = $2 ; // Return numeric form of the host's address.
{$EXTERNALSYM NI_NAMEREQD}
NI_NAMEREQD = $4 ; // Error if the host's name not in DNS.
{$EXTERNALSYM NI_NUMERICSERV}
NI_NUMERICSERV = $8 ; // Return numeric form of the service (port #).
{$EXTERNALSYM NI_DGRAM}
NI_DGRAM = $10 ; // Service is a datagram service.
//JPM - These may not be supported in WinCE 4.2
{$EXTERNALSYM PROTECTION_LEVEL_RESTRICTED}
PROTECTION_LEVEL_RESTRICTED = 30; //* for Intranet apps /*
{$EXTERNALSYM PROTECTION_LEVEL_DEFAULT}
PROTECTION_LEVEL_DEFAULT = 20; //* default level /*
{$EXTERNALSYM PROTECTION_LEVEL_UNRESTRICTED}
PROTECTION_LEVEL_UNRESTRICTED = 10; //* for peer-to-peer apps /*
{$EXTERNALSYM SOCKET_SETTINGS_GUARANTEE_ENCRYPTION}
SOCKET_SETTINGS_GUARANTEE_ENCRYPTION = $00000001;
{$EXTERNALSYM SOCKET_SETTINGS_ALLOW_INSECURE}
SOCKET_SETTINGS_ALLOW_INSECURE = $00000002;
{$EXTERNALSYM SOCKET_INFO_CONNECTION_SECURED}
SOCKET_INFO_CONNECTION_SECURED = $00000001;
{$EXTERNALSYM SOCKET_INFO_CONNECTION_ENCRYPTED}
SOCKET_INFO_CONNECTION_ENCRYPTED = $00000002;
type
// RLebeau: find a better place for this
{$IFNDEF HAS_UInt64}
{$EXTERNALSYM UINT64}
UINT64 = {$IFDEF HAS_QWord}QWord{$ELSE}Int64{$ENDIF};
{$ENDIF}
{$NODEFINE PPaddrinfo}
PPaddrinfo = ^PAddrInfo;
{$NODEFINE PPaddrinfoW}
PPaddrinfoW = ^PAddrInfoW;
{$IFNDEF WINCE}
{$EXTERNALSYM SOCKET_SECURITY_PROTOCOL}
{$EXTERNALSYM SOCKET_SECURITY_PROTOCOL_DEFAULT}
{$EXTERNALSYM SOCKET_SECURITY_PROTOCOL_IPSEC}
{$EXTERNALSYM SOCKET_SECURITY_PROTOCOL_INVALID}
SOCKET_SECURITY_PROTOCOL = (
SOCKET_SECURITY_PROTOCOL_DEFAULT, SOCKET_SECURITY_PROTOCOL_IPSEC, SOCKET_SECURITY_PROTOCOL_INVALID
);
{$EXTERNALSYM SOCKET_SECURITY_SETTINGS_IPSEC}
SOCKET_SECURITY_SETTINGS_IPSEC = record
SecurityProtocol : SOCKET_SECURITY_PROTOCOL;
SecurityFlags : ULONG;
IpsecFlags : ULONG;
AuthipMMPolicyKey : TGUID;
AuthipQMPolicyKey : TGUID;
Reserved : TGUID;
Reserved2 : UINT64;
UserNameStringLen : ULONG;
DomainNameStringLen : ULONG;
PasswordStringLen : ULONG;
// wchar_t AllStrings[0];
end;
{$EXTERNALSYM PSOCKET_SECURITY_SETTINGS_IPSEC}
PSOCKET_SECURITY_SETTINGS_IPSEC = ^SOCKET_SECURITY_SETTINGS_IPSEC;
{$EXTERNALSYM SOCKET_SECURITY_SETTINGS}
SOCKET_SECURITY_SETTINGS = record
SecurityProtocol : SOCKET_SECURITY_PROTOCOL;
SecurityFlags : ULONG;
end;
{$EXTERNALSYM PSOCKET_SECURITY_SETTINGS}
PSOCKET_SECURITY_SETTINGS = ^SOCKET_SECURITY_SETTINGS;
{$EXTERNALSYM SOCKET_PEER_TARGET_NAME}
SOCKET_PEER_TARGET_NAME = record
SecurityProtocol : SOCKET_SECURITY_PROTOCOL;
PeerAddress : SOCKADDR_STORAGE;
PeerTargetNameStringLen : ULONG;
//wchar_t AllStrings[0];
end;
{$EXTERNALSYM PSOCKET_PEER_TARGET_NAME}
PSOCKET_PEER_TARGET_NAME = ^SOCKET_PEER_TARGET_NAME;
{$EXTERNALSYM SOCKET_SECURITY_QUERY_INFO}
SOCKET_SECURITY_QUERY_INFO = record
SecurityProtocol : SOCKET_SECURITY_PROTOCOL;
Flags : ULONG;
PeerApplicationAccessTokenHandle : UINT64;
PeerMachineAccessTokenHandle : UINT64;
end;
{$EXTERNALSYM PSOCKET_SECURITY_QUERY_INFO}
PSOCKET_SECURITY_QUERY_INFO = ^SOCKET_SECURITY_QUERY_INFO;
{$EXTERNALSYM SOCKET_SECURITY_QUERY_TEMPLATE}
SOCKET_SECURITY_QUERY_TEMPLATE = record
SecurityProtocol : SOCKET_SECURITY_PROTOCOL;
PeerAddress : SOCKADDR_STORAGE;
PeerTokenAccessMask : ULONG;
end;
{$EXTERNALSYM PSOCKET_SECURITY_QUERY_TEMPLATE}
PSOCKET_SECURITY_QUERY_TEMPLATE = ^SOCKET_SECURITY_QUERY_TEMPLATE;
//callback defs
type
{$EXTERNALSYM LPLOOKUPSERVICE_COMPLETION_ROUTINE}
LPLOOKUPSERVICE_COMPLETION_ROUTINE = procedure (const dwError, dwBytes : DWORD; lpOverlapped : LPWSAOVERLAPPED); stdcall;
{$ENDIF}
type
{$EXTERNALSYM LPFN_GETADDRINFO}
LPFN_GETADDRINFO = function(NodeName: PAnsiChar; ServiceName: PAnsiChar; Hints: Paddrinfo; ppResult: PPaddrinfo): Integer; stdcall;
{$EXTERNALSYM LPFN_GETADDRINFOW}
LPFN_GETADDRINFOW = function(NodeName: PWideChar; ServiceName: PWideChar; Hints: PaddrinfoW; ppResult: PPaddrinfoW): Integer; stdcall;
{$EXTERNALSYM LPFN_GETNAMEINFO}
//The IPv6 preview for Win2K defines hostlen and servelen as size_t but do not use them
//for these definitions as the newer SDK's define those as DWORD.
LPFN_GETNAMEINFO = function(sa: psockaddr; salen: u_int; host: PAnsiChar; hostlen: u_int; serv: PAnsiChar; servlen: u_int; flags: Integer): Integer; stdcall;
{$EXTERNALSYM LPFN_GETNAMEINFOW}
LPFN_GETNAMEINFOW = function(sa: psockaddr; salen: u_int; host: PWideChar; hostlen: u_int; serv: PWideChar; servlen: u_int; flags: Integer): Integer; stdcall;
{$EXTERNALSYM LPFN_FREEADDRINFO}
LPFN_FREEADDRINFO = procedure(ai: Paddrinfo); stdcall;
{$EXTERNALSYM LPFN_FREEADDRINFOW}
LPFN_FREEADDRINFOW = procedure(ai: PaddrinfoW); stdcall;
//function GetAdaptersAddresses( Family:ULONG; Flags:ULONG; Reserved:Pointer; pAdapterAddresses: PIP_ADAPTER_ADDRESSES; pOutBufLen:PULONG):ULONG;stdcall; external iphlpapi_dll;
{ the following are not used, nor tested}
{function getipnodebyaddr(const src:pointer; len:integer; af:integer;var error_num:integer) :phostent;stdcall; external Wship6_dll;
procedure freehostent(ptr:phostent);stdcall; external Wship6_dll;
function inet_pton(af:integer; const src:pchar; dst:pointer):integer;stdcall; external Wship6_dll;
function inet_ntop(af:integer; const src:pointer; dst:pchar;size:integer):pchar;stdcall; external Wship6_dll;
}
{$IFNDEF WINCE}
{$EXTERNALSYM LPFN_INET_PTON}
LPFN_INET_PTON = function (af: Integer; const src: PAnsiChar; dst: Pointer): Integer; stdcall;
{$EXTERNALSYM LPFN_INET_PTONW}
LPFN_INET_PTONW = function (af: Integer; const src: PWideChar; dst: Pointer): Integer; stdcall;
{$EXTERNALSYM LPFN_INET_NTOP}
LPFN_INET_NTOP = function (af: Integer; const src: Pointer; dst: PAnsiChar; size: size_t): PAnsiChar; stdcall;
{$EXTERNALSYM LPFN_INET_NTOPW}
LPFN_INET_NTOPW = function (af: Integer; const src: Pointer; dst: PWideChar; size: size_t): PAnsiChar; stdcall;
{ end the following are not used, nor tested}
//These are provided in case we need them later
//Windows Vista
{$EXTERNALSYM LPFN_GETADDRINFOEXA}
LPFN_GETADDRINFOEXA = function(pName : PAnsiChar; pServiceName : PAnsiChar;
const dwNameSpace: DWord; lpNspId : LPGUID; hints : PADDRINFOEXA;
var ppResult : PADDRINFOEXA; timeout : Ptimeval; lpOverlapped : LPWSAOVERLAPPED;
lpCompletionRoutine : LPLOOKUPSERVICE_COMPLETION_ROUTINE;
lpNameHandle : PHandle) : Integer; stdcall;
{$EXTERNALSYM LPFN_GETADDRINFOEXW}
LPFN_GETADDRINFOEXW = function(pName : PWideChar; pServiceName : PWideChar;
const dwNameSpace: DWord; lpNspId : LPGUID;hints : PADDRINFOEXW;
var ppResult : PADDRINFOEXW; timeout : Ptimeval; lpOverlapped : LPWSAOVERLAPPED;
lpCompletionRoutine : LPLOOKUPSERVICE_COMPLETION_ROUTINE;
lpNameHandle : PHandle) : Integer; stdcall;
{$EXTERNALSYM LPFN_SETADDRINFOEXA}
LPFN_SETADDRINFOEXA= function(pName : PAnsiChar; pServiceName : PAnsiChar;
pAddresses : PSOCKET_ADDRESS; const dwAddressCount : DWord; lpBlob : LPBLOB;
const dwFlags : DWord; const dwNameSpace : DWord; lpNspId : LPGUID;
timeout : Ptimeval;
lpOverlapped : LPWSAOVERLAPPED;
lpCompletionRoutine : LPLOOKUPSERVICE_COMPLETION_ROUTINE; lpNameHandle : PHandle) : Integer; stdcall;
{$EXTERNALSYM LPFN_SETADDRINFOEXW}
LPFN_SETADDRINFOEXW= function(pName : PWideChar; pServiceName : PWideChar;
pAddresses : PSOCKET_ADDRESS; const dwAddressCount : DWord; lpBlob : LPBLOB;
const dwFlags : DWord; const dwNameSpace : DWord; lpNspId : LPGUID;
timeout : Ptimeval;
lpOverlapped : LPWSAOVERLAPPED;
lpCompletionRoutine : LPLOOKUPSERVICE_COMPLETION_ROUTINE; lpNameHandle : PHandle) : Integer; stdcall;
{$EXTERNALSYM LPFN_FREEADDRINFOEX}
LPFN_FREEADDRINFOEX = procedure(pAddrInfoEx : PADDRINFOEXA) ; stdcall;
{$EXTERNALSYM LPFN_FREEADDRINFOEXW}
LPFN_FREEADDRINFOEXW = procedure(pAddrInfoEx : PADDRINFOEXW) ; stdcall;
{$EXTERNALSYM LPFN_GETADDRINFOEX}
{$EXTERNALSYM LPFN_SETADDRINFOEX}
{$IFDEF UNICODE}
LPFN_GETADDRINFOEX = LPFN_GETADDRINFOEXW;
LPFN_SETADDRINFOEX = LPFN_SETADDRINFOEXW;
{$ELSE}
LPFN_GETADDRINFOEX = LPFN_GETADDRINFOEXA;
LPFN_SETADDRINFOEX = LPFN_SETADDRINFOEXA;
{$ENDIF}
// Fwpuclnt.dll - API
{$EXTERNALSYM LPFN_WSASetSocketSecurity}
LPFN_WSASetSocketSecurity = function (socket : TSocket;
SecuritySettings : PSOCKET_SECURITY_SETTINGS; const SecuritySettingsLen : ULONG;
OVERLAPPED : LPWSAOVERLAPPED; CompletionRoutine : LPWSAOVERLAPPED_COMPLETION_ROUTINE) : Integer; stdcall;
{$EXTERNALSYM LPFN_WSADELETESOCKETPEERTARGETNAME}
LPFN_WSADELETESOCKETPEERTARGETNAME = function (Socket : TSocket;
PeerAddr : Psockaddr; PeerAddrLen : ULONG;
Overlapped : LPWSAOVERLAPPED; CompletionRoutine : LPWSAOVERLAPPED_COMPLETION_ROUTINE): Integer; stdcall;
{$EXTERNALSYM LPFN_WSASETSOCKETPEERTARGETNAME}
LPFN_WSASETSOCKETPEERTARGETNAME = function (Socket : TSocket;
PeerTargetName : PSOCKET_PEER_TARGET_NAME; PeerTargetNameLen : ULONG;
Overlapped : LPWSAOVERLAPPED; CompletionRoutine : LPWSAOVERLAPPED_COMPLETION_ROUTINE) : Integer; stdcall;
{$EXTERNALSYM LPFN_WSAIMPERSONATESOCKETPEER}
LPFN_WSAIMPERSONATESOCKETPEER = function (Socket : TSocket;
PeerAddress : Psockaddr; peerAddressLen : ULONG) : Integer; stdcall;
{$EXTERNALSYM LPFN_WSAQUERYSOCKETSECURITY}
LPFN_WSAQUERYSOCKETSECURITY = function (Socket : TSocket;
SecurityQueryTemplate : PSOCKET_SECURITY_QUERY_TEMPLATE; const SecurityQueryTemplateLen : ULONG;
SecurityQueryInfo : PSOCKET_SECURITY_QUERY_INFO; var SecurityQueryInfoLen : ULONG;
Overlapped : LPWSAOVERLAPPED; CompletionRoutine : LPWSAOVERLAPPED_COMPLETION_ROUTINE) : Integer; stdcall;
{$EXTERNALSYM LPFN_WSAREVERTIMPERSONATION}
LPFN_WSAREVERTIMPERSONATION = function : Integer; stdcall;
{$ENDIF}
const
{$NODEFINE fn_GetAddrInfo}
{$NODEFINE fn_getnameinfo}
{$NODEFINE fn_freeaddrinfo}
{$IFNDEF WINCE}
{$NODEFINE fn_GetAddrInfoEx}
{$NODEFINE fn_SetAddrInfoEx}
{$NODEFINE fn_FreeAddrInfoEx}
{$NODEFINE fn_inet_pton}
{$NODEFINE fn_inet_ntop}
{$ENDIF}
{$IFDEF UNICODE}
// WinCE does not support GetAddrInfoW(), GetNameInfoW(), or FreeAddrInfoW().
// To support IPv6 on WinCE when UNICODE is defined, we will use our own
// wrappers that internally call WinCE's functions...
fn_GetAddrInfo = {$IFDEF WINCE}'getaddrinfo'{$ELSE}'GetAddrInfoW'{$ENDIF};
fn_getnameinfo = {$IFDEF WINCE}'getnameinfo'{$ELSE}'GetNameInfoW'{$ENDIF};
fn_freeaddrinfo = {$IFDEF WINCE}'freeaddrinfo'{$ELSE}'FreeAddrInfoW'{$ENDIF};
{$IFNDEF WINCE}
fn_GetAddrInfoEx = 'GetAddrInfoExW';
fn_SetAddrInfoEx = 'SetAddrInfoExW';
fn_FreeAddrInfoEx = 'FreeAddrInfoExW';
fn_inet_pton = 'InetPtonW';
fn_inet_ntop = 'InetNtopW';
{$ENDIF}
{$ELSE}
fn_GetAddrInfo = 'getaddrinfo';
fn_getnameinfo = 'getnameinfo';
fn_freeaddrinfo = 'freeaddrinfo';
{$IFNDEF WINCE}
fn_GetAddrInfoEx = 'GetAddrInfoExA';
fn_SetAddrInfoEx = 'SetAddrInfoExA';
fn_FreeAddrInfoEx = 'FreeAddrInfoEx';
fn_inet_pton = 'inet_pton';
fn_inet_ntop = 'inet_ntop';
{$ENDIF}
{$ENDIF}
{$UNDEF WINCE_UNICODE}
{$IFDEF WINCE}
{$IFDEF UNICODE}
{$DEFINE WINCE_UNICODE}
{$ENDIF}
{$ENDIF}
var
{$EXTERNALSYM getaddrinfo}
{$EXTERNALSYM getnameinfo}
{$EXTERNALSYM freeaddrinfo}
{$IFNDEF WINCE}
{$EXTERNALSYM inet_pton}
{$EXTERNALSYM inet_ntop}
{$ENDIF}
{$IFDEF UNICODE}
{$IFDEF WINCE}
getaddrinfoCE: LPFN_GETADDRINFO = nil;
getnameinfoCE: LPFN_GETNAMEINFO = nil;
freeaddrinfoCE: LPFN_FREEADDRINFO = nil;
{$ENDIF}
getaddrinfo: LPFN_GETADDRINFOW = nil;
getnameinfo: LPFN_GETNAMEINFOW = nil;
freeaddrinfo: LPFN_FREEADDRINFOW = nil;
{$IFNDEF WINCE}
//These are here for completeness
inet_pton : LPFN_inet_ptonW = nil;
inet_ntop : LPFN_inet_ntopW = nil;
{$ENDIF}
{$ELSE}
getaddrinfo: LPFN_GETADDRINFO = nil;
getnameinfo: LPFN_GETNAMEINFO = nil;
freeaddrinfo: LPFN_FREEADDRINFO = nil;
{$IFNDEF WINCE}
//These are here for completeness
inet_pton : LPFN_inet_pton = nil;
inet_ntop : LPFN_inet_ntop = nil;
{$ENDIF}
{$ENDIF}
{$IFNDEF WINCE}
{
IMPORTANT!!!
These are Windows Vista functions and there's no guarantee that you will have
them so ALWAYS check the function pointer before calling them.
}
{$EXTERNALSYM GetAddrInfoEx}
GetAddrInfoEx : LPFN_GETADDRINFOEX = nil;
{$EXTERNALSYM SetAddrInfoEx}
SetAddrInfoEx : LPFN_SETADDRINFOEX = nil;
{$EXTERNALSYM FreeAddrInfoEx}
//You can't alias the LPFN for this because the ASCII version of this
//does not end with an "a"
{$IFDEF UNICODE}
FreeAddrInfoEx : LPFN_FREEADDRINFOEXW = nil;
{$ELSE}
FreeAddrInfoEx : LPFN_FREEADDRINFOEX = nil;
{$ENDIF}
//Fwpuclnt.dll available for Windows Vista and later
{$EXTERNALSYM WSASetSocketSecurity}
WSASetSocketSecurity : LPFN_WSASetSocketSecurity = nil;
{$EXTERNALSYM WSASETSOCKETPEERTARGETNAME}
WSASetSocketPeerTargetName : LPFN_WSASETSOCKETPEERTARGETNAME = nil;
{$EXTERNALSYM WSADELETESOCKETPEERTARGETNAME}
WSADeleteSocketPeerTargetName : LPFN_WSADELETESOCKETPEERTARGETNAME = nil;
{$EXTERNALSYM WSAImpersonateSocketPeer}
WSAImpersonateSocketPeer : LPFN_WSAIMPERSONATESOCKETPEER = nil;
{$EXTERNALSYM WSAQUERYSOCKETSECURITY}
WSAQUERYSOCKETSECURITY : LPFN_WSAQUERYSOCKETSECURITY = nil;
{$EXTERNALSYM WSAREVERTIMPERSONATION}
WSARevertImpersonation : LPFN_WSAREVERTIMPERSONATION = nil;
{$ENDIF}
var
GIdIPv6FuncsAvailable: Boolean = False {$IFDEF HAS_DEPRECATED}deprecated{$ENDIF};
function gaiErrorToWsaError(const gaiError: Integer): Integer;
//We want to load this library only after loading Winsock and unload immediately
//before unloading Winsock.
procedure InitLibrary;
procedure CloseLibrary;
implementation
uses
SysUtils
{$IFDEF HAS_SIZE_T}
, IdGlobal
{$ENDIF};
var
hWship6Dll : THandle = 0; // Wship6.dll handle
//Use this instead of hWship6Dll because this will point to the correct lib.
hProcHandle : THandle = 0;
{$IFNDEF WINCE}
hfwpuclntDll : THandle = 0;
{$ENDIF}
function gaiErrorToWsaError(const gaiError: Integer): Integer;
begin
case gaiError of
GIA_EAI_ADDRFAMILY: Result := 0; // TODO: find a decent error for here
GIA_EAI_AGAIN: Result := WSATRY_AGAIN;
GIA_EAI_BADFLAGS: Result := WSAEINVAL;
GIA_EAI_FAIL: Result := WSANO_RECOVERY;
GIA_EAI_FAMILY: Result := WSAEAFNOSUPPORT;
GIA_EAI_MEMORY: Result := WSA_NOT_ENOUGH_MEMORY;
GIA_EAI_NODATA: Result := WSANO_DATA;
GIA_EAI_NONAME: Result := WSAHOST_NOT_FOUND;
GIA_EAI_SERVICE: Result := WSATYPE_NOT_FOUND;
GIA_EAI_SOCKTYPE: Result := WSAESOCKTNOSUPPORT;
GIA_EAI_SYSTEM:
begin
Result := 0; // avoid warning
IndyRaiseLastError;
end;
else
Result := gaiError;
end;
end;
procedure CloseLibrary;
var
h : THandle;
begin
h := InterlockedExchangeTHandle(hWship6Dll, 0);
if h <> 0 then begin
FreeLibrary(h);
end;
{$IFNDEF WINCE}
h := InterlockedExchangeTHandle(hfwpuclntDll, 0);
if h <> 0 then begin
FreeLibrary(h);
end;
{$ENDIF}
{$I IdSymbolDeprecatedOff.inc}
GIdIPv6FuncsAvailable := False;
{$I IdSymbolDeprecatedOn.inc}
{$IFDEF WINCE_UNICODE}
getaddrinfoCE := nil;
getnameinfoCE := nil;
freeaddrinfoCE := nil;
{$ENDIF}
getaddrinfo := nil;
getnameinfo := nil;
freeaddrinfo := nil;
{$IFNDEF WINCE}
inet_pton := nil;
inet_ntop := nil;
GetAddrInfoEx := nil;
SetAddrInfoEx := nil;
FreeAddrInfoEx := nil;
WSASetSocketPeerTargetName := nil;
WSADeleteSocketPeerTargetName := nil;
WSAImpersonateSocketPeer := nil;
WSAQuerySocketSecurity := nil;
WSARevertImpersonation := nil;
{$ENDIF}
end;
{$IFDEF FPC} //{$IFDEF STRING_IS_ANSI}
{$IFDEF UNICODE}
// FreePascal does not have PWideChar overloads of these functions
function StrComp(const Str1, Str2: PWideChar): Integer; overload;
var
P1, P2: PWideChar;
begin
P1 := Str1;
P2 := Str2;
while True do
begin
if (P1^ <> P2^) or (P1^ = #0) then
begin
Result := Ord(P1^) - Ord(P2^);
Exit;
end;
Inc(P1);
Inc(P2);
end;
Result := 0;
end;
function StrScan(const Str: PWideChar; Chr: WideChar): PWideChar; overload;
begin
Result := Str;
while Result^ <> #0 do
begin
if Result^ = Chr then begin
Exit;
end;
Inc(Result);
end;
if Chr <> #0 then begin
Result := nil;
end;
end;
{$ENDIF}
{$ENDIF}
// The IPv6 functions were added to the Ws2_32.dll on Windows XP and later.
// To execute an application that uses these functions on earlier versions of
// Windows, the functions are defined as inline functions in the Wspiapi.h file.
// At runtime, the functions are implemented in such a way that if the Ws2_32.dll
// or the Wship6.dll (the file containing the functions in the IPv6 Technology
// Preview for Windows 2000) does not include them, then versions are implemented
// inline based on code in the Wspiapi.h header file. This inline code will be
// used on older Windows platforms that do not natively support the functions.
// RLebeau: Wspiapi.h only defines Ansi versions of the legacy functions, but we
// need to handle Unicode as well...
function WspiapiMalloc(tSize: size_t): Pointer;
begin
try
GetMem(Result, tSize);
ZeroMemory(Result, tSize);
except
Result := nil;
end;
end;
procedure WspiapiFree(p: Pointer);
begin
FreeMem(p);
end;
procedure WspiapiSwap(var a, b, c: PIdPlatformChar);
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
c := a;
a := b;
b := c;
end;
function WspiapiStrdup(const pszString: PIdPlatformChar): PIdPlatformChar; stdcall;
var
pszMemory: PIdPlatformChar;
cchMemory: size_t;
begin
if pszString = nil then begin
Result := nil;
Exit;
end;
cchMemory := StrLen(pszString) + 1;
pszMemory := PIdPlatformChar(WspiapiMalloc(cchMemory * SizeOf(TIdPlatformChar)));
if pszMemory = nil then begin
Result := nil;
Exit;
end;
StrLCopy(pszMemory, pszString, cchMemory);
Result := pszMemory;
end;
function WspiapiParseV4Address(const pszAddress: PIdPlatformChar; var pdwAddress: DWORD): BOOL; stdcall;
var
dwAddress: DWORD;
pcNext: PIdPlatformChar;
iCount: Integer;
begin
iCount := 0;
// ensure there are 3 '.' (periods)
pcNext := pszAddress;
while pcNext^ <> TIdPlatformChar(0) do begin
if pcNext^ = '.' then begin
Inc(iCount);
end;
Inc(pcNext);
end;
if iCount <> 3 then begin
Result := FALSE;
Exit;
end;
// return an error if dwAddress is INADDR_NONE (255.255.255.255)
// since this is never a valid argument to getaddrinfo.
dwAddress := inet_addr(
{$IFNDEF UNICODE}
pszAddress
{$ELSE}
PAnsiChar(AnsiString(pszAddress))
{$ENDIF}
);
if dwAddress = INADDR_NONE then begin
Result := FALSE;
Exit;
end;
pdwAddress := dwAddress;
Result := TRUE;
end;
function WspiapiNewAddrInfo(iSocketType, iProtocol: Integer; wPort: WORD; dwAddress: DWORD): {$IFDEF UNICODE}PaddrinfoW{$ELSE}Paddrinfo{$ENDIF}; stdcall;
var
ptNew: {$IFDEF UNICODE}PaddrinfoW{$ELSE}Paddrinfo{$ENDIF};
ptAddress: PSockAddrIn;
begin
// allocate a new addrinfo structure.
{$IFDEF UNICODE}
ptNew := PaddrinfoW(WspiapiMalloc(SizeOf(addrinfoW)));
{$ELSE}
ptNew := Paddrinfo(WspiapiMalloc(SizeOf(addrinfo)));
{$ENDIF}
if ptNew = nil then begin
Result := nil;
Exit;
end;
ptAddress := PSockAddrIn(WspiapiMalloc(SizeOf(sockaddr_in)));
if ptAddress = nil then begin
WspiapiFree(ptNew);
Result := nil;
Exit;
end;
ptAddress^.sin_family := AF_INET;
ptAddress^.sin_port := wPort;
ptAddress^.sin_addr.s_addr := dwAddress;
// fill in the fields...
ptNew^.ai_family := PF_INET;
ptNew^.ai_socktype := iSocketType;
ptNew^.ai_protocol := iProtocol;
ptNew^.ai_addrlen := SizeOf(sockaddr_in);
ptNew^.ai_addr := Psockaddr(ptAddress);
Result := ptNew;
end;
function WspiapiQueryDNS(const pszNodeName: PIdPlatformChar; iSocketType, iProtocol: Integer;
wPort: WORD; pszAlias: PIdPlatformChar; var pptResult: {$IFDEF UNICODE}PaddrinfoW{$ELSE}Paddrinfo{$ENDIF}): Integer; stdcall;
var
pptNext: {$IFDEF UNICODE}PPaddrinfoW{$ELSE}PPaddrinfo{$ENDIF};
ptHost: Phostent;
ppAddresses: ^PInAddr;
begin
pptNext := @pptResult;
pptNext^ := nil;
pszAlias^ := TIdPlatformChar(0);
ptHost := gethostbyname(
{$IFNDEF UNICODE}
pszNodeName
{$ELSE}
PAnsiChar(AnsiString(pszNodeName))
{$ENDIF}
);
if ptHost <> nil then begin
if (ptHost^.h_addrtype = AF_INET) and (ptHost^.h_length = SizeOf(in_addr)) then begin
ppAddresses := Pointer(ptHost^.h_address_list);
while ppAddresses^ <> nil do begin
// create an addrinfo structure...
pptNext^ := WspiapiNewAddrInfo(iSocketType, iProtocol, wPort, ppAddresses^^.s_addr);
if pptNext^ = nil then begin
Result := EAI_MEMORY;
Exit;
end;
pptNext := @((pptNext^)^.ai_next);
Inc(ppAddresses);
end;
end;
// pick up the canonical name.
StrLCopy(pszAlias,
{$IFNDEF UNICODE}
ptHost^.h_name
{$ELSE}
PIdPlatformChar(TIdPlatformString(ptHost^.h_name))
{$ENDIF}
, NI_MAXHOST);
Result := 0;
Exit;
end;
case WSAGetLastError() of
WSAHOST_NOT_FOUND: Result := EAI_NONAME;
WSATRY_AGAIN: Result := EAI_AGAIN;
WSANO_RECOVERY: Result := EAI_FAIL;
WSANO_DATA: Result := EAI_NODATA;
else
Result := EAI_NONAME;
end;
end;
function WspiapiLookupNode(const pszNodeName: PIdPlatformChar; iSocketType: Integer;
iProtocol: Integer; wPort: WORD; bAI_CANONNAME: BOOL; var pptResult: {$IFDEF UNICODE}PaddrinfoW{$ELSE}Paddrinfo{$ENDIF}): Integer; stdcall;
var
iError: Integer;
iAliasCount: Integer;
szFQDN1: array[0..NI_MAXHOST-1] of TIdPlatformChar;
szFQDN2: array[0..NI_MAXHOST-1] of TIdPlatformChar;
pszName: PIdPlatformChar;
pszAlias: PIdPlatformChar;
pszScratch: PIdPlatformChar;
begin
iAliasCount := 0;
ZeroMemory(@szFQDN1, SizeOf(szFQDN1));
ZeroMemory(@szFQDN2, SizeOf(szFQDN2));
pszName := @szFQDN1[0];
pszAlias := @szFQDN2[0];
pszScratch := nil;
StrLCopy(pszName, pszNodeName, NI_MAXHOST);
repeat
iError := WspiapiQueryDNS(pszNodeName, iSocketType, iProtocol, wPort, pszAlias, pptResult);
if iError <> 0 then begin
Break;
end;
// if we found addresses, then we are done.
if pptResult <> nil then begin
Break;
end;
// stop infinite loops due to DNS misconfiguration. there appears
// to be no particular recommended limit in RFCs 1034 and 1035.
if (StrLen(pszAlias) = 0) or (StrComp(pszName, pszAlias) = 0) then begin
iError := EAI_FAIL;
Break;
end;
Inc(iAliasCount);
if iAliasCount = 16 then begin
iError := EAI_FAIL;
Break;
end;
// there was a new CNAME, look again.
WspiapiSwap(pszName, pszAlias, pszScratch);
until False;
if (iError = 0) and bAI_CANONNAME then begin
pptResult^.ai_canonname := WspiapiStrdup(pszAlias);
if pptResult^.ai_canonname = nil then begin
iError := EAI_MEMORY;
end;
end;
Result := iError;
end;
function WspiapiClone(wPort: WORD; ptResult: {$IFDEF UNICODE}PaddrinfoW{$ELSE}Paddrinfo{$ENDIF}): Integer; stdcall;
var
ptNext, ptNew: {$IFDEF UNICODE}PaddrinfoW{$ELSE}Paddrinfo{$ENDIF};
begin
ptNext := ptResult;
while ptNext <> nil do begin
// create an addrinfo structure...
ptNew := WspiapiNewAddrInfo(SOCK_DGRAM, ptNext^.ai_protocol, wPort, PSockAddrIn(ptNext^.ai_addr)^.sin_addr.s_addr);
if ptNew = nil then begin
Break;
end;
// link the cloned addrinfo
ptNew^.ai_next := ptNext^.ai_next;
ptNext^.ai_next := ptNew;
ptNext := ptNew^.ai_next;
end;
if ptNext <> nil then begin
Result := EAI_MEMORY;
Exit;
end;
Result := 0;
end;
procedure WspiapiLegacyFreeAddrInfo(ptHead: {$IFDEF UNICODE}PaddrinfoW{$ELSE}Paddrinfo{$ENDIF}); stdcall;
var
ptNext: {$IFDEF UNICODE}PaddrinfoW{$ELSE}Paddrinfo{$ENDIF};
begin
ptNext := ptHead;
while ptNext <> nil do
begin
if ptNext^.ai_canonname <> nil then begin
WspiapiFree(ptNext^.ai_canonname);
end;
if ptNext^.ai_addr <> nil then begin
WspiapiFree(ptNext^.ai_addr);
end;
ptHead := ptNext^.ai_next;
WspiapiFree(ptNext);
ptNext := ptHead;
end;
end;
{$IFNDEF HAS_TryStrToInt}
// TODO: use the implementation already in IdGlobalProtocols...
function TryStrToInt(const S: string; out Value: Integer): Boolean;
{$IFDEF USE_INLINE}inline;{$ENDIF}
var
E: Integer;
begin
Val(S, Value, E);
Result := E = 0;
end;
{$ENDIF}
function WspiapiLegacyGetAddrInfo(const pszNodeName: PIdPlatformChar; const pszServiceName: PIdPlatformChar;
const ptHints: {$IFDEF UNICODE}PaddrinfoW{$ELSE}Paddrinfo{$ENDIF};
var pptResult: {$IFDEF UNICODE}PaddrinfoW{$ELSE}Paddrinfo{$ENDIF}): Integer; stdcall;
var
iError: Integer;
iFlags: Integer;
iSocketType: Integer;
iProtocol: Integer;
wPort: WORD;
iTmp: Integer;
dwAddress: DWORD;
ptService: Pservent;
bClone: BOOL;
wTcpPort: WORD;
wUdpPort: WORD;
begin
iError := 0;
iFlags := 0;
iSocketType := 0;
iProtocol := 0;
wPort := 0;
dwAddress := 0;
bClone := FALSE;
wTcpPort := 0;
wUdpPort := 0;
// initialize pptResult with default return value.
pptResult := nil;
////////////////////////////////////////
// validate arguments...
//
// both the node name and the service name can't be NULL.
if (pszNodeName = nil) and (pszServiceName = nil) then begin
Result := EAI_NONAME;
Exit;
end;
// validate hints.
if ptHints <> nil then
begin
// all members other than ai_flags, ai_family, ai_socktype
// and ai_protocol must be zero or a null pointer.
if (ptHints^.ai_addrlen <> 0) or
(ptHints^.ai_canonname <> nil) or
(ptHints^.ai_addr <> nil) or
(ptHints^.ai_next <> nil) then
begin
Result := EAI_FAIL;
Exit;
end;
// the spec has the "bad flags" error code, so presumably we
// should check something here. insisting that there aren't
// any unspecified flags set would break forward compatibility,
// however. so we just check for non-sensical combinations.
//
// we cannot come up with a canonical name given a null node name.
iFlags := ptHints^.ai_flags;
if ((iFlags and AI_CANONNAME) <> 0) and (pszNodeName = nil) then begin
Result := EAI_BADFLAGS;
Exit;
end;
// we only support a limited number of protocol families.
if (ptHints^.ai_family <> PF_UNSPEC) and (ptHints^.ai_family <> PF_INET) then begin
Result := EAI_FAMILY;
Exit;
end;
// we only support only these socket types.
iSocketType := ptHints^.ai_socktype;
if (iSocketType <> 0) and
(iSocketType <> SOCK_STREAM) and
(iSocketType <> SOCK_DGRAM) and
(iSocketType <> SOCK_RAW) then
begin
Result := EAI_SOCKTYPE;
Exit;
end;
// REVIEW: What if ai_socktype and ai_protocol are at odds?
iProtocol := ptHints^.ai_protocol;
end;
////////////////////////////////////////
// do service lookup...
if pszServiceName <> nil then begin
if TryStrToInt(pszServiceName, iTmp) and (iTmp >= 0) then begin
wPort := htons(WORD(iTmp));
//wTcpPort := wPort; // never used
wUdpPort := wPort;
if iSocketType = 0 then begin
bClone := TRUE;
iSocketType := SOCK_STREAM;
end;
end else
begin
if (iSocketType = 0) or (iSocketType = SOCK_DGRAM) then begin
ptService := getservbyname(
{$IFNDEF UNICODE}
pszServiceName
{$ELSE}
PAnsiChar(AnsiString(pszServiceName))
{$ENDIF}
, 'udp'); {do not localize}
if ptService <> nil then begin
wPort := ptService^.s_port;
wUdpPort := wPort;
end;
end;
if (iSocketType = 0) or (iSocketType = SOCK_STREAM) then begin
ptService := getservbyname(
{$IFNDEF UNICODE}
pszServiceName
{$ELSE}
PAnsiChar(AnsiString(pszServiceName))
{$ENDIF}
, 'tcp'); {do not localize}
if ptService <> nil then begin
wPort := ptService^.s_port;
wTcpPort := wPort;
end;
end;
// assumes 0 is an invalid service port...
if wPort = 0 then begin
Result := iif(iSocketType <> 0, EAI_SERVICE, EAI_NONAME);
Exit;
end;
if iSocketType = 0 then begin
// if both tcp and udp, process tcp now & clone udp later.
iSocketType := iif(wTcpPort <> 0, SOCK_STREAM, SOCK_DGRAM);
bClone := (wTcpPort <> 0) and (wUdpPort <> 0);
end;
end;
end;
////////////////////////////////////////
// do node name lookup...
// if we weren't given a node name,
// return the wildcard or loopback address (depending on AI_PASSIVE).
//
// if we have a numeric host address string,
// return the binary address.
//
if ((pszNodeName = nil) or WspiapiParseV4Address(pszNodeName, dwAddress)) then begin
if pszNodeName = nil then begin
dwAddress := htonl(iif((iFlags and AI_PASSIVE) <> 0, INADDR_ANY, INADDR_LOOPBACK));
end;
// create an addrinfo structure...
pptResult := WspiapiNewAddrInfo(iSocketType, iProtocol, wPort, dwAddress);
if pptResult = nil then begin
iError := EAI_MEMORY;
end;
if (iError = 0) and (pszNodeName <> nil) then begin
// implementation specific behavior: set AI_NUMERICHOST
// to indicate that we got a numeric host address string.
pptResult^.ai_flags := pptResult^.ai_flags or AI_NUMERICHOST;
// return the numeric address string as the canonical name
if (iFlags and AI_CANONNAME) <> 0 then begin
pptResult^.ai_canonname := WspiapiStrdup(
{$IFNDEF UNICODE}
inet_ntoa(PInAddr(@dwAddress)^)
{$ELSE}
PWideChar(TIdUnicodeString(inet_ntoa(PInAddr(@dwAddress)^)))
{$ENDIF}
);
if pptResult^.ai_canonname = nil then begin
iError := EAI_MEMORY;
end;
end;
end;
end
// if we do not have a numeric host address string and
// AI_NUMERICHOST flag is set, return an error!
else if ((iFlags and AI_NUMERICHOST) <> 0) then begin
iError := EAI_NONAME;
end
// since we have a non-numeric node name,
// we have to do a regular node name lookup.
else begin
iError := WspiapiLookupNode(pszNodeName, iSocketType, iProtocol, wPort, (iFlags and AI_CANONNAME) <> 0, pptResult);
end;
if (iError = 0) and bClone then begin
iError := WspiapiClone(wUdpPort, pptResult);
end;
if iError <> 0 then begin
WspiapiLegacyFreeAddrInfo(pptResult);
pptResult := nil;
end;
Result := iError;
end;
function iif(ATest: Boolean; const ATrue, AFalse: PAnsiChar): PAnsiChar;
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
if ATest then begin
Result := ATrue;
end else begin
Result := AFalse;
end;
end;
function WspiapiLegacyGetNameInfo(ptSocketAddress: Psockaddr;
tSocketLength: u_int; pszNodeName: PIdPlatformChar; tNodeLength: size_t;
pszServiceName: PIdPlatformChar; tServiceLength: size_t; iFlags: Integer): Integer; stdcall;
var
ptService: Pservent;
wPort: WORD;
szBuffer: array[0..5] of TIdPlatformChar;
pszService: PIdPlatformChar;
ptHost: Phostent;
tAddress: in_addr;
pszNode: PIdPlatformChar;
pc: PIdPlatformChar;
{$IFDEF UNICODE}
tmpService: TIdUnicodeString;
tmpNode: TIdUnicodeString;
{$ENDIF}
begin
StrCopy(szBuffer, '65535');
pszService := szBuffer;
// sanity check ptSocketAddress and tSocketLength.
if (ptSocketAddress = nil) or (tSocketLength < SizeOf(sockaddr)) then begin
Result := EAI_FAIL;
Exit;
end;
if ptSocketAddress^.sa_family <> AF_INET then begin
Result := EAI_FAMILY;
Exit;
end;
if tSocketLength < SizeOf(sockaddr_in) then begin
Result := EAI_FAIL;
Exit;
end;
if (not ((pszNodeName <> nil) and (tNodeLength > 0))) and (not ((pszServiceName <> nil) and (tServiceLength > 0))) then begin
Result := EAI_NONAME;
Exit;
end;
// the draft has the "bad flags" error code, so presumably we
// should check something here. insisting that there aren't
// any unspecified flags set would break forward compatibility,
// however. so we just check for non-sensical combinations.
if ((iFlags and NI_NUMERICHOST) <> 0) and ((iFlags and NI_NAMEREQD) <> 0) then begin
Result := EAI_BADFLAGS;
Exit;
end;
// translate the port to a service name (if requested).
if (pszServiceName <> nil) and (tServiceLength > 0) then begin
wPort := PSockAddrIn(ptSocketAddress)^.sin_port;
if (iFlags and NI_NUMERICSERV) <> 0 then begin
// return numeric form of the address.
StrPLCopy(szBuffer, IntToStr(ntohs(wPort)), Length(szBuffer));
end else
begin
// return service name corresponding to port.
ptService := getservbyport(wPort, iif((iFlags and NI_DGRAM) <> 0, 'udp', nil));
if (ptService <> nil) and (ptService^.s_name <> nil) then begin
// lookup successful.
{$IFNDEF UNICODE}
pszService := ptService^.s_name;
{$ELSE}
tmpService := TIdUnicodeString(ptService^.s_name);
pszService := PWideChar(tmpService);
{$ENDIF}
end else begin
// DRAFT: return numeric form of the port!
StrPLCopy(szBuffer, IntToStr(ntohs(wPort)), Length(szBuffer));
end;
end;
if tServiceLength > size_t(StrLen(pszService)) then begin
StrLCopy(pszServiceName, pszService, tServiceLength);
end else begin
Result := EAI_FAIL;
Exit;
end;
end;
// translate the address to a node name (if requested).
if (pszNodeName <> nil) and (tNodeLength > 0) then begin
// this is the IPv4-only version, so we have an IPv4 address.
tAddress := PSockAddrIn(ptSocketAddress)^.sin_addr;
if (iFlags and NI_NUMERICHOST) <> 0 then begin
// return numeric form of the address.
{$IFNDEF UNICODE}
pszNode := inet_ntoa(tAddress);
{$ELSE}
tmpNode := TIdUnicodeString(inet_ntoa(tAddress));
pszNode := PWideChar(tmpNode);
{$ENDIF}
end else
begin
// return node name corresponding to address.
ptHost := gethostbyaddr(PAnsiChar(@tAddress), SizeOf(in_addr), AF_INET);
if (ptHost <> nil) and (ptHost^.h_name <> nil) then begin
// DNS lookup successful.
// stop copying at a "." if NI_NOFQDN is specified.
{$IFNDEF UNICODE}
pszNode := ptHost^.h_name;
{$ELSE}
tmpNode := TIdUnicodeString(ptHost^.h_name);
pszNode := PWideChar(tmpNode);
{$ENDIF}
if (iFlags and NI_NOFQDN) <> 0 then begin
pc := StrScan(pszNode, '.');
if pc <> nil then begin
pc^ := TIdPlatformChar(0);
end;
end;
end else
begin
// DNS lookup failed. return numeric form of the address.
if (iFlags and NI_NAMEREQD) <> 0 then begin
case WSAGetLastError() of
WSAHOST_NOT_FOUND: Result := EAI_NONAME;
WSATRY_AGAIN: Result := EAI_AGAIN;
WSANO_RECOVERY: Result := EAI_FAIL;
else
Result := EAI_NONAME;
end;
Exit;
end else begin
{$IFNDEF UNICODE}
pszNode := inet_ntoa(tAddress);
{$ELSE}
tmpNode := TIdUnicodeString(inet_ntoa(tAddress));
pszNode := PWideChar(tmpNode);
{$ENDIF}
end;
end;
end;
if tNodeLength > size_t(StrLen(pszNode)) then begin
StrLCopy(pszNodeName, pszNode, tNodeLength);
end else begin
Result := EAI_FAIL;
Exit;
end;
end;
Result := 0;
end;
{$IFDEF WINCE_UNICODE}
function IndyStrdupAToW(const pszString: PAnsiChar): PWideChar;
var
szStr: TIdUnicodeString;
pszMemory: PWideChar;
cchMemory: size_t;
begin
if pszString = nil then begin
Result := nil;
Exit;
end;
szStr := TIdUnicodeString(pszString);
cchMemory := Length(szStr) + 1;
pszMemory := PWideChar(WspiapiMalloc(cchMemory * SizeOf(WideChar)));
if pszMemory = nil then begin
Result := nil;
Exit;
end;
StrLCopy(pszMemory, PWideChar(szStr), cchMemory);
Result := pszMemory;
end;
procedure IndyFreeAddrInfoW(ptHead: PaddrinfoW); stdcall;
var
ptNext: PaddrinfoW;
begin
ptNext := ptHead;
while ptNext <> nil do
begin
if ptNext^.ai_canonname <> nil then begin
WspiapiFree(ptNext^.ai_canonname);
end;
if ptNext^.ai_addr <> nil then begin
WspiapiFree(ptNext^.ai_addr);
end;
ptHead := ptNext^.ai_next;
WspiapiFree(ptNext);
ptNext := ptHead;
end;
end;
function IndyAddrInfoConvert(AddrInfo: Paddrinfo): PaddrinfoW;
var
ptNew: PaddrinfoW;
ptAddress: Pointer;
begin
Result := nil;
if AddrInfo = nil then begin
Exit;
end;
// allocate a new addrinfo structure.
ptNew := PaddrinfoW(WspiapiMalloc(SizeOf(addrinfoW)));
if ptNew = nil then begin
WspiapiFree(ptNew);
Exit;
end;
ptAddress := WspiapiMalloc(AddrInfo^.ai_addrlen);
if ptAddress = nil then begin
WspiapiFree(ptNew);
Exit;
end;
Move(AddrInfo^.ai_addr^, ptAddress^, AddrInfo^.ai_addrlen);
// fill in the fields...
ptNew^.ai_flags := AddrInfo^.ai_flags;
ptNew^.ai_family := AddrInfo^.ai_family;
ptNew^.ai_socktype := AddrInfo^.ai_socktype;
ptNew^.ai_protocol := AddrInfo^.ai_protocol;
ptNew^.ai_addrlen := AddrInfo^.ai_addrlen;
ptNew^.ai_canonname := nil;
ptNew^.ai_addr := Psockaddr(ptAddress);
ptNew^.ai_next := nil;
if AddrInfo^.ai_canonname <> nil then begin
ptNew^.ai_canonname := IndyStrdupAToW(AddrInfo^.ai_canonname);
if ptNew^.ai_canonname = nil then begin
IndyFreeAddrInfoW(ptNew);
Exit;
end;
end;
if AddrInfo^.ai_next <> nil then begin
ptNew^.ai_next := IndyAddrInfoConvert(AddrInfo^.ai_next);
if ptNew^.ai_next = nil then begin
IndyFreeAddrInfoW(ptNew);
Exit;
end;
end;
Result := ptNew;
end;
function IndyGetAddrInfoW(const pszNodeName: PWideChar; const pszServiceName: PWideChar;
const ptHints: PaddrinfoW; var pptResult: PaddrinfoW): Integer; stdcall;
var
LNodeName: AnsiString;
LPNodeName: PAnsiChar;
LServiceName: AnsiString;
LPServiceName: PAnsiChar;
LHints: addrinfo;
LPHints: Paddrinfo;
LResult: Paddrinfo;
begin
// initialize pptResult with default return value.
pptResult := nil;
if pszNodeName <> nil then begin
LNodeName := AnsiString(pszNodeName);
LPNodeName := PAnsiChar(LNodeName);
end else begin
LPNodeName := nil;
end;
if pszServiceName <> nil then begin
LServiceName := AnsiString(pszServiceName);
LPServiceName := PAnsiChar(LServiceName);
end else begin
LPServiceName := nil;
end;
if ptHints <> nil then begin
ZeroMemory(@LHints, SizeOf(LHints));
LHints.ai_flags := ptHints^.ai_flags;
LHints.ai_family := ptHints^.ai_family;
LHints.ai_socktype := ptHints^.ai_socktype;
LHints.ai_protocol := ptHints^.ai_protocol;
LPHints := @LHints;
end else begin
LPHints := nil;
end;
Result := getaddrinfoCE(LPNodeName, LPServiceName, LPHints, @LResult);
if Result = 0 then begin
try
pptResult := IndyAddrInfoConvert(LResult);
finally
freeaddrinfoCE(LResult);
end;
if pptResult = nil then begin
Result := EAI_MEMORY;
end;
end;
end;
function IndyGetNameInfoW(ptSocketAddress: Psockaddr; tSocketLength: u_int;
pszNodeName: PWideChar; tNodeLength: size_t; pszServiceName: PWideChar;
tServiceLength: size_t; iFlags: Integer): Integer; stdcall;
var
LHost: array[0..NI_MAXHOST-1] of AnsiChar;
LPHost: PAnsiChar;
LHostLen: u_int;
LServ: array[0..NI_MAXSERV-1] of AnsiChar;
LPServ: PAnsiChar;
LServLen: u_int;
begin
if pszNodeName <> nil then
begin
LPHost := @LHost[0];
LHostLen := Length(LHost);
end else begin
LPHost := nil;
LHostLen := 0;
end;
if pszServiceName <> nil then
begin
LPServ := @LServ[0];
LServLen := Length(LServ);
end else begin
LPServ := nil;
LServLen := 0;
end;
Result := getnameinfoCE(ptSocketAddress, tSocketLength, LPHost, LHostLen, LPServ, LServLen, iFlags);
if Result = 0 then begin
if pszNodeName <> nil then begin
StrPLCopy(pszNodeName, TIdUnicodeString(LPHost), tNodeLength);
end;
if pszServiceName <> nil then begin
StrPLCopy(pszServiceName, TIdUnicodeString(LPServ), tServiceLength);
end;
end;
end;
{$ENDIF}
procedure InitLibrary;
var
{$IFDEF WINCE_UNICODE}
gai: LPFN_GETADDRINFO;
gni: LPFN_GETNAMEINFO;
fai: LPFN_FREEADDRINFO;
{$ELSE}
gai: {$IFDEF UNICODE}LPFN_GETADDRINFOW{$ELSE}LPFN_GETADDRINFO{$ENDIF};
gni: {$IFDEF UNICODE}LPFN_GETNAMEINFOW{$ELSE}LPFN_GETNAMEINFO{$ENDIF};
fai: {$IFDEF UNICODE}LPFN_FREEADDRINFOW{$ELSE}LPFN_FREEADDRINFO{$ENDIF};
{$ENDIF}
begin
{
IMPORTANT!!!
I am doing things this way because the functions we want are probably in
the Winsock2 dll. If they are not there, only then do you actually want
to try the Wship6.dll. I know it's a mess but I found that the functions
may not load if they aren't in Wship6.dll (and they aren't there in some
versions of Windows).
hProcHandle provides a transparant way of managing the two possible library
locations. hWship6Dll is kept so we can unload the Wship6.dll if necessary.
}
//Winsock2 has to be loaded by IdWinsock first.
if not IdWinsock2.Winsock2Loaded then
begin
IdWinsock2.InitializeWinSock;
end;
hProcHandle := IdWinsock2.WinsockHandle;
gai := GetProcAddress(hProcHandle, fn_getaddrinfo);
if not Assigned(gai) then
begin
hWship6Dll := SafeLoadLibrary(Wship6_dll);
hProcHandle := hWship6Dll;
gai := GetProcAddress(hProcHandle, fn_getaddrinfo); {do not localize}
end;
if Assigned(gai) then
begin
gni := GetProcAddress(hProcHandle, fn_getnameinfo); {do not localize}
if Assigned(gni) then
begin
fai := GetProcAddress(hProcHandle, fn_freeaddrinfo); {do not localize}
if Assigned(fai) then
begin
{$IFDEF WINCE_UNICODE}
getaddrinfoCE := gai;
getnameinfoCE := gni;
freeaddrinfoCE := fai;
getaddrinfo := @IndyGetAddrInfoW;
getnameinfo := @IndyGetNameInfoW;
freeaddrinfo := @IndyFreeAddrInfoW;
{$ELSE}
getaddrinfo := gai;
getnameinfo := gni;
freeaddrinfo := fai;
{$ENDIF}
//Additional functions should be initialized here.
{$IFNDEF WINCE}
inet_pton := GetProcAddress(hProcHandle, fn_inet_pton); {do not localize}
inet_ntop := GetProcAddress(hProcHandle, fn_inet_ntop); {do not localize}
GetAddrInfoEx := GetProcAddress(hProcHandle, fn_GetAddrInfoEx); {Do not localize}
SetAddrInfoEx := GetProcAddress(hProcHandle, fn_SetAddrInfoEx); {Do not localize}
FreeAddrInfoEx := GetProcAddress(hProcHandle, fn_FreeAddrInfoEx); {Do not localize}
hfwpuclntDll := SafeLoadLibrary(fwpuclnt_dll);
if hfwpuclntDll <> 0 then
begin
WSASetSocketSecurity := GetProcAddress(hfwpuclntDll,
'WSASetSocketSecurity');
WSAQuerySocketSecurity := GetProcAddress(hfwpuclntDll, 'WSAQuerySocketSecurity'); {Do not localize}
WSASetSocketPeerTargetName := GetProcAddress(hfwpuclntDll, 'WSASetSocketPeerTargetName'); {Do not localize}
WSADeleteSocketPeerTargetName := GetProcAddress(hfwpuclntDll, 'WSADeleteSocketPeerTargetName'); {Do not localize}
WSAImpersonateSocketPeer := GetProcAddress(hfwpuclntDll, 'WSAImpersonateSocketPeer'); {Do not localize}
WSARevertImpersonation := GetProcAddress(hfwpuclntDll, 'WSARevertImpersonation'); {Do not localize}
end;
{$ENDIF}
Exit;
end;
end;
end;
CloseLibrary;
getaddrinfo := Addr(WspiapiLegacyGetAddrInfo);
getnameinfo := Addr(WspiapiLegacyGetNameInfo);
freeaddrinfo := Addr(WspiapiLegacyFreeAddrInfo);
{$I IdSymbolDeprecatedOff.inc}
GIdIPv6FuncsAvailable := True;
{$I IdSymbolDeprecatedOn.inc}
end;
initialization
finalization
CloseLibrary;
end.