1528 lines
48 KiB
Plaintext
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.
|