IdStackWindows.pas 76 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510
  1. {
  2. $Project$
  3. $Workfile$
  4. $Revision$
  5. $DateUTC$
  6. $Id$
  7. This file is part of the Indy (Internet Direct) project, and is offered
  8. under the dual-licensing agreement described on the Indy website.
  9. (http://www.indyproject.org/)
  10. Copyright:
  11. (c) 1993-2005, Chad Z. Hower and the Indy Pit Crew. All rights reserved.
  12. $Log$
  13. Rev 1.8 10/26/2004 8:20:04 PM JPMugaas
  14. Fixed some oversights with conversion. OOPS!!!
  15. Rev 1.7 07/06/2004 21:31:24 CCostelloe
  16. Kylix 3 changes
  17. Rev 1.6 4/18/04 10:43:24 PM RLebeau
  18. Fixed syntax error
  19. Rev 1.5 4/18/04 10:29:58 PM RLebeau
  20. Renamed Int64Parts structure to TIdInt64Parts
  21. Rev 1.4 4/18/04 2:47:46 PM RLebeau
  22. Conversion support for Int64 values
  23. Rev 1.3 2004.03.07 11:45:28 AM czhower
  24. Flushbuffer fix + other minor ones found
  25. Rev 1.2 3/6/2004 5:16:34 PM JPMugaas
  26. Bug 67 fixes. Do not write to const values.
  27. Rev 1.1 3/6/2004 4:23:52 PM JPMugaas
  28. Error #62 fix. This seems to work in my tests.
  29. Rev 1.0 2004.02.03 3:14:48 PM czhower
  30. Move and updates
  31. Rev 1.33 2/1/2004 6:10:56 PM JPMugaas
  32. GetSockOpt.
  33. Rev 1.32 2/1/2004 3:28:36 AM JPMugaas
  34. Changed WSGetLocalAddress to GetLocalAddress and moved into IdStack since
  35. that will work the same in the DotNET as elsewhere. This is required to
  36. reenable IPWatch.
  37. Rev 1.31 1/31/2004 1:12:48 PM JPMugaas
  38. Minor stack changes required as DotNET does support getting all IP addresses
  39. just like the other stacks.
  40. Rev 1.30 12/4/2003 3:14:52 PM BGooijen
  41. Added HostByAddress
  42. Rev 1.29 1/3/2004 12:38:56 AM BGooijen
  43. Added function SupportsIPv6
  44. Rev 1.28 12/31/2003 9:52:02 PM BGooijen
  45. Added IPv6 support
  46. Rev 1.27 10/26/2003 05:33:14 PM JPMugaas
  47. LocalAddresses should work.
  48. Rev 1.26 10/26/2003 5:04:28 PM BGooijen
  49. UDP Server and Client
  50. Rev 1.25 10/26/2003 09:10:26 AM JPMugaas
  51. Calls necessary for IPMulticasting.
  52. Rev 1.24 10/22/2003 04:40:52 PM JPMugaas
  53. Should compile with some restored functionality. Still not finished.
  54. Rev 1.23 10/21/2003 11:04:20 PM BGooijen
  55. Fixed name collision
  56. Rev 1.22 10/21/2003 01:20:02 PM JPMugaas
  57. Restore GWindowsStack because it was needed by SuperCore.
  58. Rev 1.21 10/21/2003 06:24:28 AM JPMugaas
  59. BSD Stack now have a global variable for refercing by platform specific
  60. things. Removed corresponding var from Windows stack.
  61. Rev 1.20 10/19/2003 5:21:32 PM BGooijen
  62. SetSocketOption
  63. Rev 1.19 2003.10.11 5:51:16 PM czhower
  64. -VCL fixes for servers
  65. -Chain suport for servers (Super core)
  66. -Scheduler upgrades
  67. -Full yarn support
  68. Rev 1.18 2003.10.02 8:01:08 PM czhower
  69. .Net
  70. Rev 1.17 2003.10.02 12:44:44 PM czhower
  71. Fix for Bind, Connect
  72. Rev 1.16 2003.10.02 10:16:32 AM czhower
  73. .Net
  74. Rev 1.15 2003.10.01 9:11:26 PM czhower
  75. .Net
  76. Rev 1.14 2003.10.01 12:30:08 PM czhower
  77. .Net
  78. Rev 1.12 10/1/2003 12:14:12 AM BGooijen
  79. DotNet: removing CheckForSocketError
  80. Rev 1.11 2003.10.01 1:12:40 AM czhower
  81. .Net
  82. Rev 1.10 2003.09.30 1:23:04 PM czhower
  83. Stack split for DotNet
  84. Rev 1.9 9/8/2003 02:13:10 PM JPMugaas
  85. SupportsIP6 function added for determining if IPv6 is installed on a system.
  86. Rev 1.8 2003.07.14 1:57:24 PM czhower
  87. -First set of IOCP fixes.
  88. -Fixed a threadsafe problem with the stack class.
  89. Rev 1.7 7/1/2003 05:20:44 PM JPMugaas
  90. Minor optimizations. Illiminated some unnecessary string operations.
  91. Rev 1.5 7/1/2003 03:39:58 PM JPMugaas
  92. Started numeric IP function API calls for more efficiency.
  93. Rev 1.4 7/1/2003 12:46:06 AM JPMugaas
  94. Preliminary stack functions taking an IP address numerical structure instead
  95. of a string.
  96. Rev 1.3 5/19/2003 6:00:28 PM BGooijen
  97. TIdStackWindows.WSGetHostByAddr raised an ERangeError when the last number in
  98. the ip>127
  99. Rev 1.2 5/10/2003 4:01:28 PM BGooijen
  100. Rev 1.1 2003.05.09 10:59:28 PM czhower
  101. Rev 1.0 11/13/2002 08:59:38 AM JPMugaas
  102. }
  103. unit IdStackWindows;
  104. interface
  105. {$I IdCompilerDefines.inc}
  106. uses
  107. Classes,
  108. IdGlobal, IdException, IdStackBSDBase, IdStackConsts, IdWinsock2, IdStack,
  109. SysUtils,
  110. Windows;
  111. type
  112. EIdIPv6Unavailable = class(EIdException);
  113. TIdSocketListWindows = class(TIdSocketList)
  114. protected
  115. FFDSet: TFDSet;
  116. //
  117. class function FDSelect(AReadSet: PFDSet; AWriteSet: PFDSet; AExceptSet: PFDSet;
  118. const ATimeout: Integer = IdTimeoutInfinite): Boolean;
  119. function GetItem(AIndex: Integer): TIdStackSocketHandle; override;
  120. public
  121. procedure Add(AHandle: TIdStackSocketHandle); override;
  122. procedure Remove(AHandle: TIdStackSocketHandle); override;
  123. function Count: Integer; override;
  124. procedure Clear; override;
  125. function Clone: TIdSocketList; override;
  126. function ContainsSocket(AHandle: TIdStackSocketHandle): boolean; override;
  127. procedure GetFDSet(var VSet: TFDSet);
  128. procedure SetFDSet(var VSet: TFDSet);
  129. class function Select(AReadList: TIdSocketList; AWriteList: TIdSocketList;
  130. AExceptList: TIdSocketList; const ATimeout: Integer = IdTimeoutInfinite): Boolean; override;
  131. function SelectRead(const ATimeout: Integer = IdTimeoutInfinite): Boolean; override;
  132. function SelectReadList(var VSocketList: TIdSocketList;
  133. const ATimeout: Integer = IdTimeoutInfinite): Boolean; override;
  134. end;
  135. TIdStackWindows = class(TIdStackBSDBase)
  136. protected
  137. procedure WSQuerryIPv6Route(ASocket: TIdStackSocketHandle;
  138. const AIP: String; const APort : UInt16; var VSource; var VDest);
  139. procedure WriteChecksumIPv6(s : TIdStackSocketHandle; var VBuffer : TIdBytes;
  140. const AOffset : Integer; const AIP : String; const APort : TIdPort);
  141. function HostByName(const AHostName: string;
  142. const AIPVersion: TIdIPVersion = ID_DEFAULT_IP_VERSION): string; override;
  143. function ReadHostName: string; override;
  144. function WSCloseSocket(ASocket: TIdStackSocketHandle): Integer; override;
  145. function WSRecv(ASocket: TIdStackSocketHandle; var ABuffer;
  146. const ABufferLength, AFlags: Integer): Integer; override;
  147. function WSSend(ASocket: TIdStackSocketHandle; const ABuffer;
  148. const ABufferLength, AFlags: Integer): Integer; override;
  149. function WSShutdown(ASocket: TIdStackSocketHandle; AHow: Integer): Integer; override;
  150. {$IFNDEF VCL_XE3_OR_ABOVE}
  151. procedure WSGetSocketOption(ASocket: TIdStackSocketHandle; ALevel: TIdSocketOptionLevel;
  152. AOptName: TIdSocketOption; var AOptVal; var AOptLen: Integer); override;
  153. procedure WSSetSocketOption(ASocket: TIdStackSocketHandle; ALevel: TIdSocketOptionLevel;
  154. AOptName: TIdSocketOption; const AOptVal; const AOptLen: Integer); override;
  155. {$ENDIF}
  156. public
  157. function Accept(ASocket: TIdStackSocketHandle; var VIP: string; var VPort: TIdPort;
  158. var VIPVersion: TIdIPVersion): TIdStackSocketHandle; override;
  159. function HostToNetwork(AValue: UInt16): UInt16; override;
  160. function HostToNetwork(AValue: UInt32): UInt32; override;
  161. function HostToNetwork(AValue: TIdUInt64): TIdUInt64; override;
  162. procedure Listen(ASocket: TIdStackSocketHandle; ABackLog: Integer); override;
  163. function NetworkToHost(AValue: UInt16): UInt16; override;
  164. function NetworkToHost(AValue: UInt32): UInt32; override;
  165. function NetworkToHost(AValue: TIdUInt64): TIdUInt64; override;
  166. procedure SetBlocking(ASocket: TIdStackSocketHandle; const ABlocking: Boolean); override;
  167. function WouldBlock(const AResult: Integer): Boolean; override;
  168. //
  169. function HostByAddress(const AAddress: string;
  170. const AIPVersion: TIdIPVersion = ID_DEFAULT_IP_VERSION): string; override;
  171. function WSGetServByName(const AServiceName: string): TIdPort; override;
  172. procedure AddServByPortToList(const APortNumber: TIdPort; AAddresses: TStrings); override;
  173. function RecvFrom(const ASocket: TIdStackSocketHandle; var VBuffer;
  174. const ALength, AFlags: Integer; var VIP: string; var VPort: TIdPort;
  175. var VIPVersion: TIdIPVersion): Integer; override;
  176. function ReceiveMsg(ASocket: TIdStackSocketHandle; var VBuffer: TIdBytes;
  177. APkt : TIdPacketInfo): UInt32; override;
  178. procedure WSSendTo(ASocket: TIdStackSocketHandle; const ABuffer;
  179. const ABufferLength, AFlags: Integer; const AIP: string; const APort: TIdPort; AIPVersion: TIdIPVersion = ID_DEFAULT_IP_VERSION); override;
  180. function WSSocket(AFamily : Integer; AStruct : TIdSocketType; AProtocol: Integer;
  181. const AOverlapped: Boolean = False): TIdStackSocketHandle; override;
  182. function WSTranslateSocketErrorMsg(const AErr: integer): string; override;
  183. function WSGetLastError: Integer; override;
  184. procedure WSSetLastError(const AErr : Integer); override;
  185. //
  186. procedure Bind(ASocket: TIdStackSocketHandle; const AIP: string;
  187. const APort: TIdPort; const AIPVersion: TIdIPVersion = ID_DEFAULT_IP_VERSION); override;
  188. procedure Connect(const ASocket: TIdStackSocketHandle; const AIP: string;
  189. const APort: TIdPort; const AIPVersion: TIdIPVersion = ID_DEFAULT_IP_VERSION); override;
  190. constructor Create; override;
  191. destructor Destroy; override;
  192. procedure Disconnect(ASocket: TIdStackSocketHandle); override;
  193. procedure GetPeerName(ASocket: TIdStackSocketHandle; var VIP: string;
  194. var VPort: TIdPort; var VIPVersion: TIdIPVersion); override;
  195. procedure GetSocketName(ASocket: TIdStackSocketHandle; var VIP: string;
  196. var VPort: TIdPort; var VIPVersion: TIdIPVersion); override;
  197. {$IFDEF VCL_XE3_OR_ABOVE}
  198. procedure GetSocketOption(ASocket: TIdStackSocketHandle; ALevel: TIdSocketOptionLevel;
  199. AOptName: TIdSocketOption; var AOptVal; var AOptLen: Integer); override;
  200. procedure SetSocketOption(ASocket: TIdStackSocketHandle; ALevel: TIdSocketOptionLevel;
  201. AOptName: TIdSocketOption; const AOptVal; const AOptLen: Integer); override;
  202. {$ENDIF}
  203. function IOControl(const s: TIdStackSocketHandle; const cmd: UInt32; var arg: UInt32): Integer; override;
  204. function SupportsIPv4: Boolean; override;
  205. function SupportsIPv6: Boolean; override;
  206. function CheckIPVersionSupport(const AIPVersion: TIdIPVersion): boolean; override;
  207. procedure WriteChecksum(s : TIdStackSocketHandle;
  208. var VBuffer : TIdBytes;
  209. const AOffset : Integer;
  210. const AIP : String;
  211. const APort : TIdPort;
  212. const AIPVersion: TIdIPVersion = ID_DEFAULT_IP_VERSION); override;
  213. procedure GetLocalAddressList(AAddresses: TIdStackLocalAddressList); override;
  214. procedure SetKeepAliveValues(ASocket: TIdStackSocketHandle;
  215. const AEnabled: Boolean; const ATimeMS, AInterval: Integer); override;
  216. end;
  217. var
  218. //This is for the Win32-only package (SuperCore)
  219. GWindowsStack : TIdStackWindows = nil;
  220. implementation
  221. {$DEFINE USE_IPHLPAPI}
  222. {$IFDEF USE_IPHLPAPI}
  223. {$IFDEF VCL_XE2_OR_ABOVE}
  224. {$DEFINE HAS_UNIT_IpTypes}
  225. {$DEFINE HAS_UNIT_IpHlpApi}
  226. {$ENDIF}
  227. {$ENDIF}
  228. uses
  229. IdIDN, IdResourceStrings, IdWship6
  230. {$IFDEF USE_IPHLPAPI}
  231. {$IFDEF HAS_UNIT_IpTypes}
  232. , IpTypes
  233. {$ENDIF}
  234. {$IFDEF HAS_UNIT_IpHlpApi}
  235. , IpHlpApi
  236. {$ENDIF}
  237. {$ENDIF}
  238. ;
  239. {$IFNDEF WINCE}
  240. type
  241. TGetFileSizeEx = function(hFile : THandle; var lpFileSize : LARGE_INTEGER) : BOOL; stdcall;
  242. {$ENDIF}
  243. const
  244. SIZE_HOSTNAME = 250;
  245. var
  246. GStarted: Boolean = False;
  247. {$IFNDEF WINCE}
  248. GetFileSizeEx : TGetFileSizeEx = nil;
  249. {$ENDIF}
  250. { IPHLPAPI support }
  251. {$IFDEF USE_IPHLPAPI}
  252. const
  253. IPHLPAPI_DLL = 'iphlpapi.dll';
  254. {$IFNDEF HAS_UNIT_IpTypes}
  255. MAX_ADAPTER_DESCRIPTION_LENGTH = 128;
  256. MAX_ADAPTER_NAME_LENGTH = 256;
  257. MAX_ADAPTER_ADDRESS_LENGTH = 8;
  258. MAX_DHCPV6_DUID_LENGTH = 130;
  259. MAX_DNS_SUFFIX_STRING_LENGTH = 256;
  260. GAA_FLAG_SKIP_UNICAST = $0001;
  261. GAA_FLAG_SKIP_ANYCAST = $0002;
  262. GAA_FLAG_SKIP_MULTICAST = $0004;
  263. GAA_FLAG_SKIP_DNS_SERVER = $0008;
  264. GAA_FLAG_INCLUDE_PREFIX = $0010;
  265. GAA_FLAG_SKIP_FRIENDLY_NAME = $0020;
  266. IP_ADAPTER_RECEIVE_ONLY = $08;
  267. {$ENDIF}
  268. IF_TYPE_SOFTWARE_LOOPBACK = 24;
  269. type
  270. PIP_UNIDIRECTIONAL_ADAPTER_ADDRESS = ^IP_UNIDIRECTIONAL_ADAPTER_ADDRESS;
  271. IP_UNIDIRECTIONAL_ADAPTER_ADDRESS = record
  272. NumAdapters: ULONG;
  273. Address: array[0..0] of TInAddr;
  274. end;
  275. {$IFNDEF HAS_UNIT_IpTypes}
  276. {$MINENUMSIZE 4}
  277. time_t = TIdNativeInt;
  278. IFTYPE = ULONG;
  279. IF_INDEX = ULONG;
  280. NET_IF_COMPARTMENT_ID = UINT32;
  281. NET_IF_NETWORK_GUID = TGUID;
  282. IP_PREFIX_ORIGIN = (
  283. IpPrefixOriginOther,
  284. IpPrefixOriginManual,
  285. IpPrefixOriginWellKnown,
  286. IpPrefixOriginDhcp,
  287. IpPrefixOriginRouterAdvertisement,
  288. {$IFNDEF HAS_ENUM_ELEMENT_VALUES}
  289. ippoUnused5,
  290. ippoUnused6,
  291. ippoUnused7,
  292. ippoUnused8,
  293. ippoUnused9,
  294. ippoUnused10,
  295. ippoUnused11,
  296. ippoUnused12,
  297. ippoUnused13,
  298. ippoUnused14,
  299. ippoUnused15,
  300. {$ENDIF}
  301. IpPrefixOriginUnchanged);
  302. IP_SUFFIX_ORIGIN = (
  303. IpSuffixOriginOther,
  304. IpSuffixOriginManual,
  305. IpSuffixOriginWellKnown,
  306. IpSuffixOriginDhcp,
  307. IpSuffixOriginLinkLayerAddress,
  308. IpSuffixOriginRandom,
  309. {$IFNDEF HAS_ENUM_ELEMENT_VALUES}
  310. ipsoUnued6,
  311. ipsoUnued7,
  312. ipsoUnued8,
  313. ipsoUnued9,
  314. ipsoUnued10,
  315. ipsoUnued11,
  316. ipsoUnued12,
  317. ipsoUnued13,
  318. ipsoUnued14,
  319. ipsoUnued15,
  320. {$ENDIF}
  321. IpSuffixOriginUnchanged);
  322. IP_DAD_STATE = (
  323. IpDadStateInvalid,
  324. IpDadStateTentative,
  325. IpDadStateDuplicate,
  326. IpDadStateDeprecated,
  327. IpDadStatePreferred);
  328. IF_OPER_STATUS = (
  329. {$IFNDEF HAS_ENUM_ELEMENT_VALUES}
  330. ifosUnused,
  331. IfOperStatusUp,
  332. {$ELSE}
  333. IfOperStatusUp = 1,
  334. {$ENDIF}
  335. IfOperStatusDown,
  336. IfOperStatusTesting,
  337. IfOperStatusUnknown,
  338. IfOperStatusDormant,
  339. IfOperStatusNotPresent,
  340. IfOperStatusLowerLayerDown);
  341. NET_IF_CONNECTION_TYPE = (
  342. {$IFNDEF HAS_ENUM_ELEMENT_VALUES}
  343. nictUnused,
  344. NetIfConnectionDedicated,
  345. {$ELSE}
  346. NetIfConnectionDedicated = 1,
  347. {$ENDIF}
  348. NetIfConnectionPassive,
  349. NetIfConnectionDemand,
  350. NetIfConnectionMaximum);
  351. TUNNEL_TYPE = (
  352. TunnelTypeNone,
  353. TunnelTypeOther,
  354. TunnelTypeDirect,
  355. TunnelType6To4,
  356. TunnelTypeIsatap,
  357. TunnelTypeTeredo,
  358. TunnelTypeIPHTTPS);
  359. IP_ADDRESS_STRING = record
  360. S: array [0..15] of TIdAnsiChar;
  361. end;
  362. IP_MASK_STRING = IP_ADDRESS_STRING;
  363. PIP_ADDR_STRING = ^IP_ADDR_STRING;
  364. IP_ADDR_STRING = record
  365. Next: PIP_ADDR_STRING;
  366. IpAddress: IP_ADDRESS_STRING;
  367. IpMask: IP_MASK_STRING;
  368. Context: DWORD;
  369. end;
  370. PIP_ADAPTER_INFO = ^IP_ADAPTER_INFO;
  371. IP_ADAPTER_INFO = record
  372. Next: PIP_ADAPTER_INFO;
  373. ComboIndex: DWORD;
  374. AdapterName: array [0..MAX_ADAPTER_NAME_LENGTH + 3] of TIdAnsiChar;
  375. Description: array [0..MAX_ADAPTER_DESCRIPTION_LENGTH + 3] of TIdAnsiChar;
  376. AddressLength: UINT;
  377. Address: array [0..MAX_ADAPTER_ADDRESS_LENGTH - 1] of BYTE;
  378. Index: DWORD;
  379. Type_: UINT;
  380. DhcpEnabled: UINT;
  381. CurrentIpAddress: PIP_ADDR_STRING;
  382. IpAddressList: IP_ADDR_STRING;
  383. GatewayList: IP_ADDR_STRING;
  384. DhcpServer: IP_ADDR_STRING;
  385. HaveWins: BOOL;
  386. PrimaryWinsServer: IP_ADDR_STRING;
  387. SecondaryWinsServer: IP_ADDR_STRING;
  388. LeaseObtained: time_t;
  389. LeaseExpires: time_t;
  390. end;
  391. SOCKET_ADDRESS = record
  392. lpSockaddr: IdWinsock2.LPSOCKADDR;
  393. iSockaddrLength: Integer;
  394. end;
  395. PIP_ADAPTER_UNICAST_ADDRESS = ^IP_ADAPTER_UNICAST_ADDRESS;
  396. IP_ADAPTER_UNICAST_ADDRESS = record
  397. Union: record
  398. case Integer of
  399. 0: (
  400. Alignment: ULONGLONG);
  401. 1: (
  402. Length: ULONG;
  403. Flags: DWORD);
  404. end;
  405. Next: PIP_ADAPTER_UNICAST_ADDRESS;
  406. Address: SOCKET_ADDRESS;
  407. PrefixOrigin: IP_PREFIX_ORIGIN;
  408. SuffixOrigin: IP_SUFFIX_ORIGIN;
  409. DadState: IP_DAD_STATE;
  410. ValidLifetime: ULONG;
  411. PreferredLifetime: ULONG;
  412. LeaseLifetime: ULONG;
  413. // This structure member is only available on Windows Vista and later
  414. OnLinkPrefixLength: UCHAR;
  415. end;
  416. PIP_ADAPTER_ANYCAST_ADDRESS = ^IP_ADAPTER_ANYCAST_ADDRESS;
  417. IP_ADAPTER_ANYCAST_ADDRESS = record
  418. Union: record
  419. case Integer of
  420. 0: (
  421. Alignment: ULONGLONG);
  422. 1: (
  423. Length: ULONG;
  424. Flags: DWORD);
  425. end;
  426. Next: PIP_ADAPTER_ANYCAST_ADDRESS;
  427. Address: SOCKET_ADDRESS;
  428. end;
  429. PIP_ADAPTER_MULTICAST_ADDRESS = ^IP_ADAPTER_MULTICAST_ADDRESS;
  430. IP_ADAPTER_MULTICAST_ADDRESS = record
  431. Union: record
  432. case Integer of
  433. 0: (
  434. Alignment: ULONGLONG);
  435. 1: (
  436. Length: ULONG;
  437. Flags: DWORD);
  438. end;
  439. Next: PIP_ADAPTER_MULTICAST_ADDRESS;
  440. Address: SOCKET_ADDRESS;
  441. end;
  442. PIP_ADAPTER_DNS_SERVER_ADDRESS = ^IP_ADAPTER_DNS_SERVER_ADDRESS;
  443. IP_ADAPTER_DNS_SERVER_ADDRESS = record
  444. Union: record
  445. case Integer of
  446. 0: (
  447. Alignment: ULONGLONG);
  448. 1: (
  449. Length: ULONG;
  450. Reserved: DWORD);
  451. end;
  452. Next: PIP_ADAPTER_DNS_SERVER_ADDRESS;
  453. Address: SOCKET_ADDRESS;
  454. end;
  455. PIP_ADAPTER_PREFIX = ^IP_ADAPTER_PREFIX;
  456. IP_ADAPTER_PREFIX = record
  457. Union: record
  458. case Integer of
  459. 0: (
  460. Alignment: ULONGLONG);
  461. 1: (
  462. Length: ULONG;
  463. Flags: DWORD);
  464. end;
  465. Next: PIP_ADAPTER_PREFIX;
  466. Address: SOCKET_ADDRESS;
  467. PrefixLength: ULONG;
  468. end;
  469. PIP_ADAPTER_WINS_SERVER_ADDRESS_LH = ^IP_ADAPTER_WINS_SERVER_ADDRESS_LH;
  470. IP_ADAPTER_WINS_SERVER_ADDRESS_LH = record
  471. Union: record
  472. case Integer of
  473. 0: (
  474. Alignment: ULONGLONG);
  475. 1: (
  476. Length: ULONG;
  477. Reserved: DWORD);
  478. end;
  479. Next: PIP_ADAPTER_WINS_SERVER_ADDRESS_LH;
  480. Address: SOCKET_ADDRESS;
  481. end;
  482. PIP_ADAPTER_GATEWAY_ADDRESS_LH = ^IP_ADAPTER_GATEWAY_ADDRESS_LH;
  483. IP_ADAPTER_GATEWAY_ADDRESS_LH = record
  484. Union: record
  485. case Integer of
  486. 0: (
  487. Alignment: ULONGLONG);
  488. 1: (
  489. Length: ULONG;
  490. Reserved: DWORD);
  491. end;
  492. Next: PIP_ADAPTER_GATEWAY_ADDRESS_LH;
  493. Address: SOCKET_ADDRESS;
  494. end;
  495. IF_LUID = record
  496. case Integer of
  497. 0: (
  498. Value: ULONG64);
  499. 1: (
  500. Info: ULONG64);
  501. end;
  502. PIP_ADAPTER_DNS_SUFFIX = ^IP_ADAPTER_DNS_SUFFIX;
  503. IP_ADAPTER_DNS_SUFFIX = record
  504. Next: PIP_ADAPTER_DNS_SUFFIX;
  505. AString: array[0..MAX_DNS_SUFFIX_STRING_LENGTH - 1] of WCHAR;
  506. end;
  507. PIP_ADAPTER_ADDRESSES = ^IP_ADAPTER_ADDRESSES;
  508. IP_ADAPTER_ADDRESSES = record
  509. Union: record
  510. case Integer of
  511. 0: (
  512. Alignment: ULONGLONG);
  513. 1: (
  514. Length: ULONG;
  515. IfIndex: DWORD);
  516. end;
  517. Next: PIP_ADAPTER_ADDRESSES;
  518. AdapterName: PIdAnsiChar;
  519. FirstUnicastAddress: PIP_ADAPTER_UNICAST_ADDRESS;
  520. FirstAnycastAddress: PIP_ADAPTER_ANYCAST_ADDRESS;
  521. FirstMulticastAddress: PIP_ADAPTER_MULTICAST_ADDRESS;
  522. FirstDnsServerAddress: PIP_ADAPTER_DNS_SERVER_ADDRESS;
  523. DnsSuffix: PWCHAR;
  524. Description: PWCHAR;
  525. FriendlyName: PWCHAR;
  526. PhysicalAddress: array [0..MAX_ADAPTER_ADDRESS_LENGTH - 1] of BYTE;
  527. PhysicalAddressLength: DWORD;
  528. Flags: DWORD;
  529. Mtu: DWORD;
  530. IfType: IFTYPE;
  531. OperStatus: IF_OPER_STATUS;
  532. Ipv6IfIndex: IF_INDEX;
  533. ZoneIndices: array [0..15] of DWORD;
  534. FirstPrefix: PIP_ADAPTER_PREFIX;
  535. TransmitLinkSpeed: ULONG64;
  536. ReceiveLinkSpeed: ULONG64;
  537. FirstWinsServerAddress: PIP_ADAPTER_WINS_SERVER_ADDRESS_LH;
  538. FirstGatewayAddress: PIP_ADAPTER_GATEWAY_ADDRESS_LH;
  539. Ipv4Metric: ULONG;
  540. Ipv6Metric: ULONG;
  541. Luid: IF_LUID;
  542. Dhcpv4Server: SOCKET_ADDRESS;
  543. CompartmentId: NET_IF_COMPARTMENT_ID;
  544. NetworkGuid: NET_IF_NETWORK_GUID;
  545. ConnectionType: NET_IF_CONNECTION_TYPE;
  546. TunnelType: TUNNEL_TYPE;
  547. //
  548. // DHCP v6 Info.
  549. //
  550. Dhcpv6Server: SOCKET_ADDRESS;
  551. Dhcpv6ClientDuid: array [0..MAX_DHCPV6_DUID_LENGTH - 1] of Byte;
  552. Dhcpv6ClientDuidLength: ULONG;
  553. Dhcpv6Iaid: ULONG;
  554. FirstDnsSuffix: PIP_ADAPTER_DNS_SUFFIX;
  555. end;
  556. {$ENDIF}
  557. PMIB_IPADDRROW = ^MIB_IPADDRROW;
  558. MIB_IPADDRROW = record
  559. dwAddr: DWORD;
  560. dwIndex: DWORD;
  561. dwMask: DWORD;
  562. dwBCastAddr: DWORD;
  563. dwReasmSize: DWORD;
  564. unused1: Word;
  565. wType: Word;
  566. end;
  567. PMIB_IPADDRTABLE = ^MIB_IPADDRTABLE;
  568. MIB_IPADDRTABLE = record
  569. dwNumEntries: DWORD;
  570. table: array[0..0] of MIB_IPADDRROW;
  571. end;
  572. NETIO_STATUS = DWORD;
  573. TGetIpAddrTable = function(pIpAddrTable: PMIB_IPADDRTABLE; var pdwSize: ULONG; bOrder: BOOL): DWORD; stdcall;
  574. TGetUniDirectionalAdapterInfo = function(pIPIfInfo: PIP_UNIDIRECTIONAL_ADAPTER_ADDRESS; var dwOutBufLen: ULONG): DWORD; stdcall;
  575. TGetAdaptersInfo = function(pAdapterInfo: PIP_ADAPTER_INFO; var pOutBufLen: ULONG): DWORD; stdcall;
  576. TGetAdaptersAddresses = function(Family: ULONG; Flags: DWORD; Reserved: PVOID; pAdapterAddresses: PIP_ADAPTER_ADDRESSES; var OutBufLen: ULONG): DWORD; stdcall;
  577. TConvertLengthToIpv4Mask = function(MaskLength: ULONG; var Mask: ULONG): NETIO_STATUS; stdcall;
  578. var
  579. hIpHlpApi: TIdLibHandle = IdNilHandle;
  580. GetIpAddrTable: TGetIpAddrTable = nil;
  581. GetUniDirectionalAdapterInfo: TGetUniDirectionalAdapterInfo = nil;
  582. GetAdaptersInfo: TGetAdaptersInfo = nil;
  583. GetAdaptersAddresses: TGetAdaptersAddresses = nil;
  584. ConvertLengthToIpv4Mask: TConvertLengthToIpv4Mask = nil;
  585. function FixupIPHelperStub(const AName:{$IFDEF WINCE}TIdUnicodeString{$ELSE}string{$ENDIF}; DefImpl: Pointer): Pointer;
  586. {$IFDEF USE_INLINE}inline;{$ENDIF}
  587. begin
  588. Result := nil;
  589. if hIpHlpApi <> IdNilHandle then begin
  590. Result := Windows.GetProcAddress(hIpHlpApi, {$IFDEF WINCE}PWideChar{$ELSE}PChar{$ENDIF}(AName));
  591. end;
  592. if Result = nil then begin
  593. Result := DefImpl;
  594. end;
  595. end;
  596. function Impl_GetIpAddrTable(pIpAddrTable: PMIB_IPADDRTABLE; var pdwSize: ULONG; bOrder: BOOL): DWORD; stdcall;
  597. begin
  598. pdwSize := 0;
  599. Result := ERROR_NOT_SUPPORTED;
  600. end;
  601. function Stub_GetIpAddrTable(pIpAddrTable: PMIB_IPADDRTABLE; var pdwSize: ULONG; bOrder: BOOL): DWORD; stdcall;
  602. begin
  603. @GetIpAddrTable := FixupIPHelperStub('GetIpAddrTable', @Impl_GetIpAddrTable); {Do not localize}
  604. Result := GetIpAddrTable(pIpAddrTable, pdwSize, bOrder);
  605. end;
  606. function Impl_GetUniDirectionalAdapterInfo(pIPIfInfo: PIP_UNIDIRECTIONAL_ADAPTER_ADDRESS; var dwOutBufLen: ULONG): DWORD; stdcall;
  607. begin
  608. dwOutBufLen := 0;
  609. Result := ERROR_NOT_SUPPORTED;
  610. end;
  611. function Stub_GetUniDirectionalAdapterInfo(pIPIfInfo: PIP_UNIDIRECTIONAL_ADAPTER_ADDRESS; var dwOutBufLen: ULONG): DWORD; stdcall;
  612. begin
  613. @GetUniDirectionalAdapterInfo := FixupIPHelperStub('GetUniDirectionalAdapterInfo', @Impl_GetUniDirectionalAdapterInfo); {Do not localize}
  614. Result := GetUniDirectionalAdapterInfo(pIPIfInfo, dwOutBufLen);
  615. end;
  616. function Impl_GetAdaptersInfo(pAdapterInfo: PIP_ADAPTER_INFO; var pOutBufLen: ULONG): DWORD; stdcall;
  617. begin
  618. pOutBufLen := 0;
  619. Result := ERROR_NOT_SUPPORTED;
  620. end;
  621. function Stub_GetAdaptersInfo(pAdapterInfo: PIP_ADAPTER_INFO; var pOutBufLen: ULONG): DWORD; stdcall;
  622. begin
  623. @GetAdaptersInfo := FixupIPHelperStub('GetAdaptersInfo', @Impl_GetAdaptersInfo); {Do not localize}
  624. Result := GetAdaptersInfo(pAdapterInfo, pOutBufLen);
  625. end;
  626. function Impl_GetAdaptersAddresses(Family: ULONG; Flags: DWORD; Reserved: PVOID; pAdapterAddresses: PIP_ADAPTER_ADDRESSES; var OutBufLen: ULONG): DWORD; stdcall;
  627. begin
  628. OutBufLen := 0;
  629. Result := ERROR_NOT_SUPPORTED;
  630. end;
  631. function Stub_GetAdaptersAddresses(Family: ULONG; Flags: DWORD; Reserved: PVOID; pAdapterAddresses: PIP_ADAPTER_ADDRESSES; var OutBufLen: ULONG): DWORD; stdcall;
  632. begin
  633. @GetAdaptersAddresses := FixupIPHelperStub('GetAdaptersAddresses', @Impl_GetAdaptersAddresses); {Do not localize}
  634. Result := GetAdaptersAddresses(Family, Flags, Reserved, pAdapterAddresses, OutBufLen);
  635. end;
  636. function Impl_ConvertLengthToIpv4Mask(MaskLength: ULONG; var Mask: ULONG): NETIO_STATUS; stdcall;
  637. begin
  638. // TODO: implement manually
  639. Mask := INADDR_NONE;
  640. if MaskLength > 32 then begin
  641. Result := ERROR_INVALID_PARAMETER;
  642. end else begin
  643. Result := ERROR_NOT_SUPPORTED;
  644. end;
  645. end;
  646. function Stub_ConvertLengthToIpv4Mask(MaskLength: ULONG; var Mask: ULONG): NETIO_STATUS; stdcall;
  647. begin
  648. @ConvertLengthToIpv4Mask := FixupIPHelperStub('ConvertLengthToIpv4Mask', @Impl_ConvertLengthToIpv4Mask); {Do not localize}
  649. Result := ConvertLengthToIpv4Mask(MaskLength, Mask);
  650. end;
  651. procedure InitializeIPHelperStubs;
  652. begin
  653. GetIpAddrTable := Stub_GetIpAddrTable;
  654. GetUniDirectionalAdapterInfo := Stub_GetUniDirectionalAdapterInfo;
  655. GetAdaptersInfo := Stub_GetAdaptersInfo;
  656. GetAdaptersAddresses := Stub_GetAdaptersAddresses;
  657. ConvertLengthToIpv4Mask := Stub_ConvertLengthToIpv4Mask;
  658. end;
  659. procedure InitializeIPHelperAPI;
  660. begin
  661. if hIpHlpApi = IdNilHandle then begin
  662. hIpHlpApi := SafeLoadLibrary(IPHLPAPI_DLL);
  663. end;
  664. end;
  665. procedure UninitializeIPHelperAPI;
  666. begin
  667. if hIpHlpApi <> IdNilHandle then
  668. begin
  669. FreeLibrary(hIpHlpApi);
  670. hIpHlpApi := IdNilHandle;
  671. end;
  672. InitializeIPHelperStubs;
  673. end;
  674. {$ENDIF}
  675. { TIdStackWindows }
  676. constructor TIdStackWindows.Create;
  677. begin
  678. inherited Create;
  679. if not GStarted then begin
  680. try
  681. InitializeWinSock;
  682. IdWship6.InitLibrary;
  683. IdIDN.InitIDNLibrary;
  684. {$IFDEF USE_IPHLPAPI}
  685. InitializeIPHelperAPI;
  686. {$ENDIF}
  687. except
  688. on E: Exception do begin
  689. IndyRaiseOuterException(EIdStackInitializationFailed.Create(E.Message));
  690. end;
  691. end;
  692. GStarted := True;
  693. end;
  694. GWindowsStack := Self;
  695. end;
  696. destructor TIdStackWindows.Destroy;
  697. begin
  698. //DLL Unloading and Cleanup is done at finalization
  699. inherited Destroy;
  700. end;
  701. function TIdStackWindows.Accept(ASocket: TIdStackSocketHandle;
  702. var VIP: string; var VPort: TIdPort; var VIPVersion: TIdIPVersion): TIdStackSocketHandle;
  703. var
  704. LSize: Integer;
  705. LAddr: SOCKADDR_STORAGE;
  706. begin
  707. LSize := SizeOf(LAddr);
  708. Result := IdWinsock2.accept(ASocket, IdWinsock2.PSOCKADDR(@LAddr), @LSize);
  709. if Result <> INVALID_SOCKET then begin
  710. case LAddr.ss_family of
  711. Id_PF_INET4: begin
  712. VIP := TranslateTInAddrToString(PSockAddrIn(@LAddr)^.sin_addr, Id_IPv4);
  713. VPort := ntohs(PSockAddrIn(@LAddr)^.sin_port);
  714. VIPVersion := Id_IPv4;
  715. end;
  716. Id_PF_INET6: begin
  717. VIP := TranslateTInAddrToString(PSockAddrIn6(@LAddr)^.sin6_addr, Id_IPv6);
  718. VPort := ntohs(PSockAddrIn6(@LAddr)^.sin6_port);
  719. VIPVersion := Id_IPv6;
  720. end;
  721. else begin
  722. CloseSocket(Result);
  723. Result := INVALID_SOCKET;
  724. IPVersionUnsupported;
  725. end;
  726. end;
  727. end;
  728. end;
  729. procedure TIdStackWindows.Bind(ASocket: TIdStackSocketHandle;
  730. const AIP: string; const APort: TIdPort;
  731. const AIPVersion: TIdIPVersion = ID_DEFAULT_IP_VERSION);
  732. var
  733. LAddr: SOCKADDR_STORAGE;
  734. LSize: Integer;
  735. begin
  736. FillChar(LAddr, SizeOf(LAddr), 0);
  737. case AIPVersion of
  738. Id_IPv4: begin
  739. PSockAddrIn(@LAddr)^.sin_family := Id_PF_INET4;
  740. if AIP <> '' then begin
  741. TranslateStringToTInAddr(AIP, PSockAddrIn(@LAddr)^.sin_addr, Id_IPv4);
  742. end;
  743. PSockAddrIn(@LAddr)^.sin_port := htons(APort);
  744. LSize := SIZE_TSOCKADDRIN;
  745. end;
  746. Id_IPv6: begin
  747. PSockAddrIn6(@LAddr)^.sin6_family := Id_PF_INET6;
  748. if AIP <> '' then begin
  749. TranslateStringToTInAddr(AIP, PSockAddrIn6(@LAddr)^.sin6_addr, Id_IPv6);
  750. end;
  751. PSockAddrIn6(@LAddr)^.sin6_port := htons(APort);
  752. LSize := SIZE_TSOCKADDRIN6;
  753. end;
  754. else begin
  755. LSize := 0; // avoid warning
  756. IPVersionUnsupported;
  757. end;
  758. end;
  759. CheckForSocketError(IdWinsock2.bind(ASocket, IdWinsock2.PSOCKADDR(@LAddr), LSize));
  760. end;
  761. function TIdStackWindows.WSCloseSocket(ASocket: TIdStackSocketHandle): Integer;
  762. begin
  763. Result := CloseSocket(ASocket);
  764. end;
  765. function TIdStackWindows.HostByAddress(const AAddress: string;
  766. const AIPVersion: TIdIPVersion = ID_DEFAULT_IP_VERSION): string;
  767. var
  768. {$IFDEF UNICODE}
  769. Hints: TAddrInfoW;
  770. LAddrInfo: pAddrInfoW;
  771. {$ELSE}
  772. Hints: TAddrInfo;
  773. LAddrInfo: pAddrInfo;
  774. {$ENDIF}
  775. RetVal: Integer;
  776. {$IFDEF STRING_UNICODE_MISMATCH}
  777. LTemp: TIdPlatformString;
  778. {$ENDIF}
  779. begin
  780. if not (AIPVersion in [Id_IPv4, Id_IPv6]) then begin
  781. IPVersionUnsupported;
  782. end;
  783. // TODO: should this be calling getnameinfo() first and then getaddrinfo()
  784. // to check for a malicious PTR record, like the other TIdStack classes do?
  785. // TODO: use TranslateStringToTInAddr() instead of getaddrinfo() to convert
  786. // the IP address to a sockaddr struct for getnameinfo(), like other TIdStack
  787. // classes do.
  788. FillChar(Hints, SizeOf(Hints), 0);
  789. Hints.ai_family := IdIPFamily[AIPVersion];
  790. Hints.ai_socktype := Integer(SOCK_STREAM);
  791. Hints.ai_flags := AI_NUMERICHOST;
  792. LAddrInfo := nil;
  793. {$IFDEF STRING_UNICODE_MISMATCH}
  794. LTemp := TIdPlatformString(AAddress); // explicit convert to Ansi/Unicode
  795. {$ENDIF}
  796. RetVal := getaddrinfo(
  797. {$IFDEF STRING_UNICODE_MISMATCH}PIdPlatformChar(LTemp){$ELSE}PChar(AAddress){$ENDIF},
  798. nil, @Hints, @LAddrInfo);
  799. if RetVal <> 0 then begin
  800. RaiseSocketError(gaiErrorToWsaError(RetVal));
  801. end;
  802. try
  803. SetLength(
  804. {$IFDEF STRING_UNICODE_MISMATCH}LTemp{$ELSE}Result{$ENDIF},
  805. NI_MAXHOST);
  806. RetVal := getnameinfo(
  807. LAddrInfo.ai_addr, LAddrInfo.ai_addrlen,
  808. {$IFDEF STRING_UNICODE_MISMATCH}PIdPlatformChar(LTemp){$ELSE}PChar(Result){$ENDIF},
  809. NI_MAXHOST, nil, 0, NI_NAMEREQD);
  810. if RetVal <> 0 then begin
  811. RaiseSocketError(gaiErrorToWsaError(RetVal));
  812. end;
  813. Result := {$IFDEF STRING_UNICODE_MISMATCH}PIdPlatformChar(LTemp){$ELSE}PChar(Result){$ENDIF};
  814. finally
  815. freeaddrinfo(LAddrInfo);
  816. end;
  817. end;
  818. function TIdStackWindows.ReadHostName: string;
  819. var
  820. // Note that there is no Unicode version of gethostname.
  821. // Maybe use getnameinfo() instead?
  822. LStr: array[0..SIZE_HOSTNAME] of TIdAnsiChar;
  823. {$IFDEF USE_MARSHALLED_PTRS}
  824. LStrPtr: TPtrWrapper;
  825. {$ENDIF}
  826. begin
  827. {$IFDEF USE_MARSHALLED_PTRS}
  828. LStrPtr := TPtrWrapper.Create(@LStr[0]);
  829. {$ENDIF}
  830. if gethostname(
  831. {$IFDEF USE_MARSHALLED_PTRS}
  832. LStrPtr.ToPointer
  833. {$ELSE}
  834. LStr
  835. {$ENDIF}, SIZE_HOSTNAME) <> Id_SOCKET_ERROR then
  836. begin
  837. {$IFDEF USE_MARSHALLED_PTRS}
  838. Result := TMarshal.ReadStringAsAnsiUpTo(CP_ACP, LStrPtr, SIZE_HOSTNAME);
  839. {$ELSE}
  840. //we have to specifically type cast a PIdAnsiChar to a string for D2009+.
  841. //otherwise, we will get a warning about implicit typecast from AnsiString
  842. //to string
  843. LStr[SIZE_HOSTNAME] := TIdAnsiChar(0);
  844. Result := String(LStr);
  845. {$ENDIF}
  846. end else begin
  847. Result := '';
  848. end;
  849. end;
  850. procedure TIdStackWindows.Listen(ASocket: TIdStackSocketHandle; ABackLog: Integer);
  851. begin
  852. CheckForSocketError(IdWinsock2.listen(ASocket, ABacklog));
  853. end;
  854. // RLebeau 12/16/09: MS Hotfix #971383 supposedly fixes a bug in Windows
  855. // Server 2003 when client and server are running on the same machine.
  856. // The bug can cause recv() to return 0 bytes prematurely even though data
  857. // is actually pending. Uncomment the below define if you do not want to
  858. // rely on the Hotfix always being installed. The workaround described by
  859. // MS is to simply call recv() again to make sure data is really not pending.
  860. //
  861. {.$DEFINE IGNORE_KB971383_FIX}
  862. function TIdStackWindows.WSRecv(ASocket: TIdStackSocketHandle; var ABuffer;
  863. const ABufferLength, AFlags: Integer) : Integer;
  864. begin
  865. Result := recv(ASocket, ABuffer, ABufferLength, AFlags);
  866. {$IFDEF IGNORE_KB971383_FIX}
  867. if Result = 0 then begin
  868. Result := recv(ASocket, ABuffer, ABufferLength, AFlags);
  869. end;
  870. {$ENDIF}
  871. end;
  872. function TIdStackWindows.RecvFrom(const ASocket: TIdStackSocketHandle;
  873. var VBuffer; const ALength, AFlags: Integer; var VIP: string;
  874. var VPort: TIdPort; var VIPVersion: TIdIPVersion): Integer;
  875. var
  876. LSize: Integer;
  877. LAddr: SOCKADDR_STORAGE;
  878. begin
  879. LSize := SizeOf(LAddr);
  880. Result := IdWinsock2.recvfrom(ASocket, VBuffer, ALength, AFlags, IdWinsock2.PSOCKADDR(@LAddr), @LSize);
  881. if Result >= 0 then
  882. begin
  883. case LAddr.ss_family of
  884. Id_PF_INET4: begin
  885. VIP := TranslateTInAddrToString(PSockAddrIn(@LAddr)^.sin_addr, Id_IPv4);
  886. VPort := ntohs(PSockAddrIn(@LAddr)^.sin_port);
  887. VIPVersion := Id_IPv4;
  888. end;
  889. Id_PF_INET6: begin
  890. VIP := TranslateTInAddrToString(PSockAddrIn6(@LAddr)^.sin6_addr, Id_IPv6);
  891. VPort := ntohs(PSockAddrIn6(@LAddr)^.sin6_port);
  892. VIPVersion := Id_IPv6;
  893. end;
  894. else begin
  895. IPVersionUnsupported;
  896. end;
  897. end;
  898. end;
  899. end;
  900. function TIdStackWindows.WSSend(ASocket: TIdStackSocketHandle;
  901. const ABuffer; const ABufferLength, AFlags: Integer): Integer;
  902. begin
  903. Result := CheckForSocketError(IdWinsock2.send(ASocket, ABuffer, ABufferLength, AFlags));
  904. end;
  905. procedure TIdStackWindows.WSSendTo(ASocket: TIdStackSocketHandle;
  906. const ABuffer; const ABufferLength, AFlags: Integer; const AIP: string;
  907. const APort: TIdPort; AIPVersion: TIdIPVersion = ID_DEFAULT_IP_VERSION);
  908. var
  909. LAddr: SOCKADDR_STORAGE;
  910. LSize: Integer;
  911. begin
  912. FillChar(LAddr, SizeOf(LAddr), 0);
  913. case AIPVersion of
  914. Id_IPv4: begin
  915. PSockAddrIn(@LAddr)^.sin_family := Id_PF_INET4;
  916. TranslateStringToTInAddr(AIP, PSockAddrIn(@LAddr)^.sin_addr, Id_IPv4);
  917. PSockAddrIn(@LAddr)^.sin_port := htons(APort);
  918. LSize := SIZE_TSOCKADDRIN;
  919. end;
  920. Id_IPv6: begin
  921. PSockAddrIn6(@LAddr)^.sin6_family := Id_PF_INET6;
  922. TranslateStringToTInAddr(AIP, PSockAddrIn6(@LAddr)^.sin6_addr, Id_IPv6);
  923. PSockAddrIn6(@LAddr)^.sin6_port := htons(APort);
  924. LSize := SIZE_TSOCKADDRIN6;
  925. end;
  926. else begin
  927. LSize := 0; // avoid warning
  928. IPVersionUnsupported;
  929. end;
  930. end;
  931. LSize := IdWinsock2.sendto(ASocket, ABuffer, ABufferLength, AFlags, IdWinsock2.PSOCKADDR(@LAddr), LSize);
  932. // TODO: call CheckForSocketError() here
  933. if LSize = Id_SOCKET_ERROR then begin
  934. // TODO: move this into RaiseLastSocketError() directly
  935. if WSGetLastError() = Id_WSAEMSGSIZE then begin
  936. raise EIdPackageSizeTooBig.Create(RSPackageSizeTooBig);
  937. end else begin
  938. RaiseLastSocketError;
  939. end;
  940. end
  941. else if LSize <> ABufferLength then begin
  942. raise EIdNotAllBytesSent.Create(RSNotAllBytesSent);
  943. end;
  944. end;
  945. function TIdStackWindows.WSGetLastError: Integer;
  946. begin
  947. Result := WSAGetLastError;
  948. if Result = -1073741251{STATUS_HOST_UNREACHABLE} then begin
  949. Result := WSAEHOSTUNREACH;
  950. end
  951. end;
  952. procedure TIdStackWindows.WSSetLastError(const AErr : Integer);
  953. begin
  954. WSASetLastError(AErr);
  955. end;
  956. function TIdStackWindows.WSSocket(AFamily : Integer; AStruct : TIdSocketType; AProtocol: Integer;
  957. const AOverlapped: Boolean = False): TIdStackSocketHandle;
  958. begin
  959. if AOverlapped then begin
  960. Result := WSASocket(AFamily, AStruct, AProtocol, nil, 0, WSA_FLAG_OVERLAPPED);
  961. end else begin
  962. Result := IdWinsock2.socket(AFamily, AStruct, AProtocol);
  963. end;
  964. end;
  965. function TIdStackWindows.WSGetServByName(const AServiceName: string): TIdPort;
  966. var
  967. // Note that there is no Unicode version of getservbyname.
  968. // Maybe use getaddrinfo() instead?
  969. ps: PServEnt;
  970. LPort: Integer;
  971. {$IFDEF USE_MARSHALLED_PTRS}
  972. M: TMarshaller;
  973. {$ENDIF}
  974. begin
  975. ps := getservbyname(
  976. {$IFDEF USE_MARSHALLED_PTRS}
  977. M.AsAnsi(AServiceName).ToPointer
  978. {$ELSE}
  979. PIdAnsiChar(
  980. {$IFDEF STRING_IS_ANSI}
  981. AServiceName
  982. {$ELSE}
  983. AnsiString(AServiceName) // explicit convert to Ansi
  984. {$ENDIF}
  985. )
  986. {$ENDIF},
  987. nil);
  988. if ps <> nil then begin
  989. Result := ntohs(ps^.s_port);
  990. end else begin
  991. try
  992. LPort := IndyStrToInt(AServiceName);
  993. except
  994. on EConvertError do begin
  995. LPort := -1;
  996. IndyRaiseOuterException(EIdInvalidServiceName.CreateFmt(RSInvalidServiceName, [AServiceName]));
  997. end;
  998. end;
  999. if (LPort < 0) or (LPort > High(TIdPort)) then begin
  1000. raise EIdInvalidServiceName.CreateFmt(RSInvalidServiceName, [AServiceName]);
  1001. end;
  1002. Result := TIdPort(LPort);
  1003. end;
  1004. end;
  1005. procedure TIdStackWindows.AddServByPortToList(const APortNumber: TIdPort; AAddresses: TStrings);
  1006. type
  1007. // Note that there is no Unicode version of getservbyport.
  1008. PPAnsiCharArray = ^TPAnsiCharArray;
  1009. TPAnsiCharArray = packed array[0..(MaxInt div SizeOf(PIdAnsiChar))-1] of PIdAnsiChar;
  1010. var
  1011. ps: PServEnt;
  1012. i: integer;
  1013. p: PPAnsiCharArray;
  1014. begin
  1015. ps := getservbyport(htons(APortNumber), nil);
  1016. if ps = nil then begin
  1017. RaiseLastSocketError;
  1018. end;
  1019. AAddresses.BeginUpdate;
  1020. try
  1021. //we have to specifically type cast a PIdAnsiChar to a string for D2009+.
  1022. //otherwise, we will get a warning about implicit typecast from AnsiString
  1023. //to string
  1024. AAddresses.Add(String(ps^.s_name));
  1025. i := 0;
  1026. p := Pointer(ps^.s_aliases);
  1027. while p[i] <> nil do
  1028. begin
  1029. AAddresses.Add(String(p[i]));
  1030. Inc(i);
  1031. end;
  1032. finally
  1033. AAddresses.EndUpdate;
  1034. end;
  1035. end;
  1036. function TIdStackWindows.HostToNetwork(AValue: UInt16): UInt16;
  1037. begin
  1038. Result := htons(AValue);
  1039. end;
  1040. function TIdStackWindows.NetworkToHost(AValue: UInt16): UInt16;
  1041. begin
  1042. Result := ntohs(AValue);
  1043. end;
  1044. function TIdStackWindows.HostToNetwork(AValue: UInt32): UInt32;
  1045. begin
  1046. Result := htonl(AValue);
  1047. end;
  1048. function TIdStackWindows.NetworkToHost(AValue: UInt32): UInt32;
  1049. begin
  1050. Result := ntohl(AValue);
  1051. end;
  1052. function TIdStackWindows.HostToNetwork(AValue: TIdUInt64): TIdUInt64;
  1053. var
  1054. LParts: TIdUInt64Parts;
  1055. L: UInt32;
  1056. begin
  1057. // TODO: ARM is bi-endian, so if Windows is running on ARM instead of x86,
  1058. // can it ever be big endian? Or do ARM manufacturers put it in little endian
  1059. // for Windows installations?
  1060. //if (htonl(1) <> 1) then begin
  1061. LParts.QuadPart := AValue{$IFDEF TIdUInt64_HAS_QuadPart}.QuadPart{$ENDIF};
  1062. L := htonl(LParts.HighPart);
  1063. LParts.HighPart := htonl(LParts.LowPart);
  1064. LParts.LowPart := L;
  1065. Result{$IFDEF TIdUInt64_HAS_QuadPart}.QuadPart{$ENDIF} := LParts.QuadPart;
  1066. //end else begin
  1067. // Result{$IFDEF TIdUInt64_HAS_QuadPart}.QuadPart{$ENDIF} := AValue{$IFDEF TIdUInt64_HAS_QuadPart}.QuadPart{$ENDIF};
  1068. //end;
  1069. end;
  1070. function TIdStackWindows.NetworkToHost(AValue: TIdUInt64): TIdUInt64;
  1071. var
  1072. LParts: TIdUInt64Parts;
  1073. L: UInt32;
  1074. begin
  1075. // TODO: ARM is bi-endian, so if Windows is running on ARM instead of x86,
  1076. // can it ever be big endian? Or do ARM manufacturers put it in little endian
  1077. // for Windows installations?
  1078. //if (ntohl(1) <> 1) then begin
  1079. LParts.QuadPart := AValue{$IFDEF TIdUInt64_HAS_QuadPart}.QuadPart{$ENDIF};
  1080. L := ntohl(LParts.HighPart);
  1081. LParts.HighPart := ntohl(LParts.LowPart);
  1082. LParts.LowPart := L;
  1083. Result{$IFDEF TIdUInt64_HAS_QuadPart}.QuadPart{$ENDIF} := LParts.QuadPart;
  1084. //end else begin
  1085. // Result{$IFDEF TIdUInt64_HAS_QuadPart}.QuadPart{$ENDIF} := AValue{$IFDEF TIdUInt64_HAS_QuadPart}.QuadPart{$ENDIF};
  1086. //end;
  1087. end;
  1088. procedure TIdStackWindows.GetLocalAddressList(AAddresses: TIdStackLocalAddressList);
  1089. {$IFDEF USE_IPHLPAPI}
  1090. function IPv4MaskLengthToString(MaskLength: ULONG): String;
  1091. var
  1092. Mask: ULONG;
  1093. begin
  1094. if ConvertLengthToIpv4Mask(MaskLength, Mask) = ERROR_SUCCESS then begin
  1095. Result := TranslateTInAddrToString(Mask, Id_IPv4);
  1096. end else begin
  1097. Result := '';
  1098. end;
  1099. end;
  1100. procedure GetIPv4SubNetMasks(ASubNetMasks: TStrings);
  1101. var
  1102. Ret: DWORD;
  1103. BufLen: ULONG;
  1104. Table: PMIB_IPADDRTABLE;
  1105. pRow: PMIB_IPADDRROW;
  1106. I: ULONG;
  1107. begin
  1108. BufLen := 0;
  1109. Table := nil;
  1110. try
  1111. repeat
  1112. // Alternatively, use WSAIoctl(SIO_GET_INTERFACE_LIST), but
  1113. // I have noticed it does not always return IPv4 subnets!
  1114. Ret := GetIpAddrTable(Table, BufLen, FALSE);
  1115. case Ret of
  1116. ERROR_SUCCESS:
  1117. begin
  1118. if BufLen = 0 then begin
  1119. Exit;
  1120. end;
  1121. Break;
  1122. end;
  1123. ERROR_NOT_SUPPORTED:
  1124. Exit;
  1125. ERROR_INSUFFICIENT_BUFFER:
  1126. ReallocMem(Table, BufLen);
  1127. else
  1128. SetLastError(Ret);
  1129. IndyRaiseLastError;
  1130. end;
  1131. until False;
  1132. if Ret = ERROR_SUCCESS then
  1133. begin
  1134. if Table^.dwNumEntries > 0 then
  1135. begin
  1136. pRow := @(Table^.table[0]);
  1137. for I := 0 to Table^.dwNumEntries-1 do begin
  1138. IndyAddPair(ASubNetMasks,
  1139. TranslateTInAddrToString(pRow^.dwAddr, Id_IPv4),
  1140. TranslateTInAddrToString(pRow^.dwMask, Id_IPv4));
  1141. Inc(pRow);
  1142. end;
  1143. end;
  1144. end;
  1145. finally
  1146. FreeMem(Table);
  1147. end;
  1148. end;
  1149. function GetLocalAddressesByAdaptersAddresses: Boolean;
  1150. var
  1151. Ret: DWORD;
  1152. BufLen: ULONG;
  1153. Adapter, Adapters: PIP_ADAPTER_ADDRESSES;
  1154. UnicastAddr: PIP_ADAPTER_UNICAST_ADDRESS;
  1155. IPAddr: string;
  1156. SubNetStr: String;
  1157. SubNetMasks: TStringList;
  1158. begin
  1159. // assume True unless ERROR_NOT_SUPPORTED is reported...
  1160. Result := True;
  1161. // MSDN says:
  1162. // The recommended method of calling the GetAdaptersAddresses function is
  1163. // to pre-allocate a 15KB working buffer pointed to by the AdapterAddresses
  1164. // parameter. On typical computers, this dramatically reduces the chances
  1165. // that the GetAdaptersAddresses function returns ERROR_BUFFER_OVERFLOW,
  1166. // which would require calling GetAdaptersAddresses function multiple times.
  1167. BufLen := 1024*15;
  1168. GetMem(Adapters, BufLen);
  1169. try
  1170. repeat
  1171. // TODO: include GAA_FLAG_INCLUDE_PREFIX on XPSP1+?
  1172. // TODO: include GAA_FLAG_INCLUDE_ALL_INTERFACES on Vista+?
  1173. Ret := GetAdaptersAddresses(PF_UNSPEC, GAA_FLAG_SKIP_ANYCAST or GAA_FLAG_SKIP_MULTICAST or GAA_FLAG_SKIP_DNS_SERVER or GAA_FLAG_SKIP_FRIENDLY_NAME, nil, Adapters, BufLen);
  1174. case Ret of
  1175. ERROR_SUCCESS:
  1176. begin
  1177. // Windows CE versions earlier than 4.1 may return ERROR_SUCCESS and
  1178. // BufLen=0 if no adapter info is available, instead of returning
  1179. // ERROR_NO_DATA as documented...
  1180. if BufLen = 0 then begin
  1181. Exit;
  1182. end;
  1183. Break;
  1184. end;
  1185. ERROR_NOT_SUPPORTED:
  1186. begin
  1187. Result := False;
  1188. Exit;
  1189. end;
  1190. ERROR_NO_DATA,
  1191. ERROR_ADDRESS_NOT_ASSOCIATED:
  1192. Exit;
  1193. ERROR_BUFFER_OVERFLOW:
  1194. ReallocMem(Adapters, BufLen);
  1195. else
  1196. SetLastError(Ret);
  1197. IndyRaiseLastError;
  1198. end;
  1199. until False;
  1200. if Ret = ERROR_SUCCESS then
  1201. begin
  1202. SubNetMasks := nil;
  1203. try
  1204. AAddresses.BeginUpdate;
  1205. try
  1206. Adapter := Adapters;
  1207. repeat
  1208. if (Adapter.IfType <> IF_TYPE_SOFTWARE_LOOPBACK) and
  1209. ((Adapter.Flags and IP_ADAPTER_RECEIVE_ONLY) = 0) then
  1210. begin
  1211. UnicastAddr := Adapter^.FirstUnicastAddress;
  1212. while UnicastAddr <> nil do
  1213. begin
  1214. if UnicastAddr^.DadState = IpDadStatePreferred then
  1215. begin
  1216. case UnicastAddr^.Address.lpSockaddr.sin_family of
  1217. AF_INET: begin
  1218. IPAddr := TranslateTInAddrToString(PSockAddrIn(UnicastAddr^.Address.lpSockaddr)^.sin_addr, Id_IPv4);
  1219. // The OnLinkPrefixLength member is only available on Windows Vista and later
  1220. if IndyCheckWindowsVersion(6) then begin
  1221. SubNetStr := IPv4MaskLengthToString(UnicastAddr^.OnLinkPrefixLength);
  1222. end else
  1223. begin
  1224. // TODO: on XP SP1+, can the subnet mask be determined
  1225. // by analyzing the Adapter's Prefix list without resorting
  1226. // to reading the Registry?
  1227. if SubNetMasks = nil then
  1228. begin
  1229. SubNetMasks := TStringList.Create;
  1230. GetIPv4SubNetMasks(SubNetMasks);
  1231. end;
  1232. SubNetStr := SubNetMasks.Values[IPAddr];
  1233. end;
  1234. TIdStackLocalAddressIPv4.Create(AAddresses, IPAddr, SubNetStr);
  1235. end;
  1236. AF_INET6: begin
  1237. TIdStackLocalAddressIPv6.Create(AAddresses,
  1238. TranslateTInAddrToString(PSockAddrIn6(UnicastAddr^.Address.lpSockaddr)^.sin6_addr, Id_IPv6));
  1239. end;
  1240. end;
  1241. end;
  1242. UnicastAddr := UnicastAddr^.Next;
  1243. end;
  1244. end;
  1245. Adapter := Adapter^.Next;
  1246. until Adapter = nil;
  1247. finally
  1248. AAddresses.EndUpdate;
  1249. end;
  1250. finally
  1251. SubNetMasks.Free;
  1252. end;
  1253. end;
  1254. finally
  1255. FreeMem(Adapters);
  1256. end;
  1257. end;
  1258. procedure GetUniDirAddresseses(AUniDirAddresses: TStrings);
  1259. var
  1260. Ret: DWORD;
  1261. BufLen: ULONG;
  1262. Adapters: PIP_UNIDIRECTIONAL_ADAPTER_ADDRESS;
  1263. pUniDirAddr: PInAddr;
  1264. I: ULONG;
  1265. begin
  1266. BufLen := 1024*15;
  1267. GetMem(Adapters, BufLen);
  1268. try
  1269. repeat
  1270. Ret := GetUniDirectionalAdapterInfo(Adapters, BufLen);
  1271. case Ret of
  1272. ERROR_SUCCESS:
  1273. begin
  1274. if BufLen = 0 then begin
  1275. Exit;
  1276. end;
  1277. Break;
  1278. end;
  1279. ERROR_NOT_SUPPORTED,
  1280. ERROR_NO_DATA:
  1281. Exit;
  1282. ERROR_MORE_DATA:
  1283. ReallocMem(Adapters, BufLen);
  1284. else
  1285. SetLastError(Ret);
  1286. IndyRaiseLastError;
  1287. end;
  1288. until False;
  1289. if Ret = ERROR_SUCCESS then
  1290. begin
  1291. if Adapters^.NumAdapters > 0 then
  1292. begin
  1293. pUniDirAddr := @(Adapters^.Address[0]);
  1294. for I := 0 to Adapters^.NumAdapters-1 do begin
  1295. AUniDirAddresses.Add(TranslateTInAddrToString(pUniDirAddr^, Id_IPv4));
  1296. Inc(pUniDirAddr);
  1297. end;
  1298. end;
  1299. end;
  1300. finally
  1301. FreeMem(Adapters);
  1302. end;
  1303. end;
  1304. procedure GetLocalAddressesByAdaptersInfo;
  1305. var
  1306. Ret: DWORD;
  1307. BufLen: ULONG;
  1308. UniDirAddresses: TStringList;
  1309. Adapter, Adapters: PIP_ADAPTER_INFO;
  1310. IPAddr: PIP_ADDR_STRING;
  1311. IPStr, MaskStr: String;
  1312. begin
  1313. BufLen := 1024*15;
  1314. GetMem(Adapters, BufLen);
  1315. try
  1316. repeat
  1317. Ret := GetAdaptersInfo(Adapters, BufLen);
  1318. case Ret of
  1319. ERROR_SUCCESS:
  1320. begin
  1321. // Windows CE versions earlier than 4.1 may return ERROR_SUCCESS and
  1322. // BufLen=0 if no adapter info is available, instead of returning
  1323. // ERROR_NO_DATA as documented...
  1324. if BufLen = 0 then begin
  1325. Exit;
  1326. end;
  1327. Break;
  1328. end;
  1329. ERROR_NOT_SUPPORTED,
  1330. ERROR_NO_DATA:
  1331. Exit;
  1332. ERROR_BUFFER_OVERFLOW:
  1333. ReallocMem(Adapters, BufLen);
  1334. else
  1335. SetLastError(Ret);
  1336. IndyRaiseLastError;
  1337. end;
  1338. until False;
  1339. if Ret = ERROR_SUCCESS then
  1340. begin
  1341. // on XP and later, GetAdaptersInfo() includes uni-directional adapters.
  1342. // Need to use GetUniDirectionalAdapterInfo() to filter them out of the
  1343. // list ...
  1344. if IndyCheckWindowsVersion(5, 1) then begin
  1345. UniDirAddresses := TStringList.Create;
  1346. end else begin
  1347. UniDirAddresses := nil;
  1348. end;
  1349. try
  1350. if UniDirAddresses <> nil then begin
  1351. GetUniDirAddresseses(UniDirAddresses);
  1352. end;
  1353. AAddresses.BeginUpdate;
  1354. try
  1355. Adapter := Adapters;
  1356. repeat
  1357. IPAddr := @(Adapter^.IpAddressList);
  1358. repeat
  1359. {$IFDEF USE_MARSHALLED_PTRS}
  1360. IPStr := TMarshal.ReadStringAsAnsiUpTo(CP_ACP, TPtrWrapper.Create(@(IPAddr^.IpAddress.S[0]), 15);
  1361. {$ELSE}
  1362. IPStr := String(IPAddr^.IpAddress.S);
  1363. {$ENDIF}
  1364. if (IPStr <> '') and (IPStr <> '0.0.0.0') then
  1365. begin
  1366. if UniDirAddresses <> nil then begin
  1367. if UniDirAddresses.IndexOf(IPStr) <> -1 then begin
  1368. IPAddr := IPAddr^.Next;
  1369. Continue;
  1370. end;
  1371. end;
  1372. {$IFDEF USE_MARSHALLED_PTRS}
  1373. MaskStr := TMarshal.ReadStringAsAnsiUpTo(CP_ACP, TPtrWrapper.Create(@(IPAddr^.IpMask.S[0]), 15);
  1374. {$ELSE}
  1375. MaskStr := String(IPAddr^.IpMask.S);
  1376. {$ENDIF}
  1377. TIdStackLocalAddressIPv4.Create(AAddresses, IPStr, MaskStr);
  1378. end;
  1379. IPAddr := IPAddr^.Next;
  1380. until IPAddr = nil;
  1381. Adapter := Adapter^.Next;
  1382. until Adapter = nil;
  1383. finally
  1384. AAddresses.EndUpdate;
  1385. end;
  1386. finally
  1387. UniDirAddresses.Free;
  1388. end;
  1389. end;
  1390. finally
  1391. FreeMem(Adapters);
  1392. end;
  1393. end;
  1394. {$ELSE}
  1395. procedure GetLocalAddressesByHostName;
  1396. var
  1397. {$IFDEF UNICODE}
  1398. Hints: TAddrInfoW;
  1399. LAddrList, LAddrInfo: pAddrInfoW;
  1400. {$ELSE}
  1401. Hints: TAddrInfo;
  1402. LAddrList, LAddrInfo: pAddrInfo;
  1403. {$ENDIF}
  1404. RetVal: Integer;
  1405. LHostName: String;
  1406. {$IFDEF STRING_UNICODE_MISMATCH}
  1407. LTemp: TIdPlatformString;
  1408. {$ENDIF}
  1409. begin
  1410. LHostName := HostName;
  1411. ZeroMemory(@Hints, SIZE_TADDRINFO);
  1412. Hints.ai_family := PF_UNSPEC; // returns both IPv4 and IPv6 addresses
  1413. Hints.ai_socktype := SOCK_STREAM;
  1414. LAddrList := nil;
  1415. {$IFDEF STRING_UNICODE_MISMATCH}
  1416. LTemp := TIdPlatformString(LHostName); // explicit convert to Ansi/Unicode
  1417. {$ENDIF}
  1418. RetVal := getaddrinfo(
  1419. {$IFDEF STRING_UNICODE_MISMATCH}PIdPlatformChar(LTemp){$ELSE}PChar(LHostName){$ENDIF},
  1420. nil, @Hints, @LAddrList);
  1421. if RetVal <> 0 then begin
  1422. RaiseSocketError(gaiErrorToWsaError(RetVal));
  1423. end;
  1424. try
  1425. AAddresses.BeginUpdate;
  1426. try
  1427. LAddrInfo := LAddrList;
  1428. repeat
  1429. case LAddrInfo^.ai_addr^.sa_family of
  1430. AF_INET: begin
  1431. TIdStackLocalAddressIPv4.Create(AAddresses,
  1432. TranslateTInAddrToString(PSockAddrIn(LAddrInfo^.ai_addr)^.sin_addr, Id_IPv4),
  1433. ''); // TODO: SubNet
  1434. end;
  1435. AF_INET6: begin
  1436. TIdStackLocalAddressIPv6.Create(AAddresses,
  1437. TranslateTInAddrToString(PSockAddrIn6(LAddrInfo^.ai_addr)^.sin6_addr, Id_IPv6));
  1438. end;
  1439. end;
  1440. LAddrInfo := LAddrInfo^.ai_next;
  1441. until LAddrInfo = nil;
  1442. finally
  1443. AAddresses.EndUpdate;
  1444. end;
  1445. finally
  1446. freeaddrinfo(LAddrList);
  1447. end;
  1448. end;
  1449. {$ENDIF}
  1450. begin
  1451. // Using gethostname() and (gethostbyname|getaddrinfo)() may not always return
  1452. // just the machine's IP addresses. Technically speaking, they will return
  1453. // the local hostname, and then return the address(es) to which that hostname
  1454. // resolves. It is possible for a machine to (a) be configured such that its
  1455. // name does not resolve to an IP, or (b) be configured such that its name
  1456. // resolves to multiple IPs, only one of which belongs to the local machine.
  1457. // For better results, we should use the Win32 API GetAdaptersInfo() and/or
  1458. // GetAdaptersAddresses() functions instead. GetAdaptersInfo() only supports
  1459. // IPv4, but GetAdaptersAddresses() supports both IPv4 and IPv6...
  1460. {$IFDEF USE_IPHLPAPI}
  1461. // try GetAdaptersAddresses() first, then fall back to GetAdaptersInfo()...
  1462. if not GetLocalAddressesByAdaptersAddresses then begin
  1463. GetLocalAddressesByAdaptersInfo;
  1464. end;
  1465. {$ELSE}
  1466. GetLocalAddressesByHostName;
  1467. {$ENDIF}
  1468. end;
  1469. { TIdStackVersionWinsock }
  1470. function TIdStackWindows.WSShutdown(ASocket: TIdStackSocketHandle; AHow: Integer): Integer;
  1471. begin
  1472. Result := Shutdown(ASocket, AHow);
  1473. end;
  1474. procedure TIdStackWindows.GetSocketName(ASocket: TIdStackSocketHandle;
  1475. var VIP: string; var VPort: TIdPort; var VIPVersion: TIdIPVersion);
  1476. var
  1477. LSize: Integer;
  1478. LAddr: SOCKADDR_STORAGE;
  1479. begin
  1480. LSize := SizeOf(LAddr);
  1481. CheckForSocketError(getsockname(ASocket, IdWinsock2.PSOCKADDR(@LAddr), LSize));
  1482. case LAddr.ss_family of
  1483. Id_PF_INET4: begin
  1484. VIP := TranslateTInAddrToString(PSockAddrIn(@LAddr)^.sin_addr, Id_IPv4);
  1485. VPort := ntohs(PSockAddrIn(@LAddr)^.sin_port);
  1486. VIPVersion := Id_IPv4;
  1487. end;
  1488. Id_PF_INET6: begin
  1489. VIP := TranslateTInAddrToString(PSockAddrIn6(@LAddr)^.sin6_addr, Id_IPv6);
  1490. VPort := Ntohs(PSockAddrIn6(@LAddr)^.sin6_port);
  1491. VIPVersion := Id_IPv6;
  1492. end;
  1493. else begin
  1494. IPVersionUnsupported;
  1495. end;
  1496. end;
  1497. end;
  1498. { TIdSocketListWindows }
  1499. procedure TIdSocketListWindows.Add(AHandle: TIdStackSocketHandle);
  1500. begin
  1501. Lock;
  1502. try
  1503. if FFDSet.fd_count >= FD_SETSIZE then begin
  1504. raise EIdStackSetSizeExceeded.Create(RSSetSizeExceeded);
  1505. end;
  1506. FFDSet.fd_array[FFDSet.fd_count] := AHandle;
  1507. Inc(FFDSet.fd_count);
  1508. finally
  1509. Unlock;
  1510. end;
  1511. end;
  1512. procedure TIdSocketListWindows.Clear;
  1513. begin
  1514. Lock;
  1515. try
  1516. fd_zero(FFDSet);
  1517. finally
  1518. Unlock;
  1519. end;
  1520. end;
  1521. function TIdSocketListWindows.ContainsSocket(AHandle: TIdStackSocketHandle): Boolean;
  1522. begin
  1523. Lock;
  1524. try
  1525. Result := fd_isset(AHandle, FFDSet);
  1526. finally
  1527. Unlock;
  1528. end;
  1529. end;
  1530. function TIdSocketListWindows.Count: Integer;
  1531. begin
  1532. Lock;
  1533. try
  1534. Result := FFDSet.fd_count;
  1535. finally
  1536. Unlock;
  1537. end;
  1538. end;
  1539. function TIdSocketListWindows.GetItem(AIndex: Integer): TIdStackSocketHandle;
  1540. begin
  1541. Result := 0;
  1542. Lock;
  1543. try
  1544. //We can't redefine AIndex to be a UInt32 because the libc Interface
  1545. //and DotNET define it as a LongInt. OS/2 defines it as a UInt16.
  1546. if (AIndex >= 0) and (u_int(AIndex) < FFDSet.fd_count) then begin
  1547. Result := FFDSet.fd_array[AIndex];
  1548. end else begin
  1549. raise EIdStackSetSizeExceeded.Create(RSSetSizeExceeded);
  1550. end;
  1551. finally
  1552. Unlock;
  1553. end;
  1554. end;
  1555. procedure TIdSocketListWindows.Remove(AHandle: TIdStackSocketHandle);
  1556. var
  1557. i: Integer;
  1558. begin
  1559. Lock;
  1560. try
  1561. {
  1562. IMPORTANT!!!
  1563. Sometimes, there may not be a member of the FDSET. If you attempt to "remove"
  1564. an item, the loop would execute once.
  1565. }
  1566. if FFDSet.fd_count > 0 then
  1567. begin
  1568. for i:= 0 to FFDSet.fd_count - 1 do
  1569. begin
  1570. if FFDSet.fd_array[i] = AHandle then
  1571. begin
  1572. Dec(FFDSet.fd_count);
  1573. FFDSet.fd_array[i] := FFDSet.fd_array[FFDSet.fd_count];
  1574. FFDSet.fd_array[FFDSet.fd_count] := 0; //extra purity
  1575. Break;
  1576. end;//if found
  1577. end;
  1578. end;
  1579. finally
  1580. Unlock;
  1581. end;
  1582. end;
  1583. function TIdStackWindows.WSTranslateSocketErrorMsg(const AErr: Integer): string;
  1584. begin
  1585. if AErr = WSAHOST_NOT_FOUND then begin
  1586. Result := IndyFormat(RSStackError, [AErr, RSStackHOST_NOT_FOUND]);
  1587. end else begin
  1588. Result := inherited WSTranslateSocketErrorMsg(AErr);
  1589. end;
  1590. end;
  1591. function TIdSocketListWindows.SelectRead(const ATimeout: Integer): Boolean;
  1592. var
  1593. LSet: TFDSet;
  1594. begin
  1595. // Windows updates this structure on return, so we need to copy it each time we need it
  1596. GetFDSet(LSet);
  1597. Result := FDSelect(@LSet, nil, nil, ATimeout);
  1598. end;
  1599. class function TIdSocketListWindows.FDSelect(AReadSet, AWriteSet,
  1600. AExceptSet: PFDSet; const ATimeout: Integer): Boolean;
  1601. var
  1602. LResult: Integer;
  1603. LTime: TTimeVal;
  1604. LTimePtr: PTimeVal;
  1605. begin
  1606. if ATimeout = IdTimeoutInfinite then begin
  1607. LTimePtr := nil;
  1608. end else begin
  1609. LTime.tv_sec := ATimeout div 1000;
  1610. LTime.tv_usec := (ATimeout mod 1000) * 1000;
  1611. LTimePtr := @LTime;
  1612. end;
  1613. LResult := IdWinsock2.select(0, AReadSet, AWriteSet, AExceptSet, LTimePtr);
  1614. //TODO: Remove this cast
  1615. Result := GStack.CheckForSocketError(LResult) > 0;
  1616. end;
  1617. function TIdSocketListWindows.SelectReadList(var VSocketList: TIdSocketList;
  1618. const ATimeout: Integer): Boolean;
  1619. var
  1620. LSet: TFDSet;
  1621. begin
  1622. // Windows updates this structure on return, so we need to copy it each time we need it
  1623. GetFDSet(LSet);
  1624. Result := FDSelect(@LSet, nil, nil, ATimeout);
  1625. if Result then
  1626. begin
  1627. if VSocketList = nil then begin
  1628. VSocketList := TIdSocketList.CreateSocketList;
  1629. end;
  1630. TIdSocketListWindows(VSocketList).SetFDSet(LSet);
  1631. end;
  1632. end;
  1633. class function TIdSocketListWindows.Select(AReadList, AWriteList,
  1634. AExceptList: TIdSocketList; const ATimeout: Integer): Boolean;
  1635. var
  1636. LReadSet: TFDSet;
  1637. LWriteSet: TFDSet;
  1638. LExceptSet: TFDSet;
  1639. LPReadSet: PFDSet;
  1640. LPWriteSet: PFDSet;
  1641. LPExceptSet: PFDSet;
  1642. procedure ReadSet(AList: TIdSocketList; var ASet: TFDSet; var APSet: PFDSet);
  1643. begin
  1644. if AList <> nil then begin
  1645. TIdSocketListWindows(AList).GetFDSet(ASet);
  1646. APSet := @ASet;
  1647. end else begin
  1648. APSet := nil;
  1649. end;
  1650. end;
  1651. begin
  1652. ReadSet(AReadList, LReadSet, LPReadSet);
  1653. ReadSet(AWriteList, LWriteSet, LPWriteSet);
  1654. ReadSet(AExceptList, LExceptSet, LPExceptSet);
  1655. Result := FDSelect(LPReadSet, LPWriteSet, LPExceptSet, ATimeout);
  1656. if AReadList <> nil then begin
  1657. TIdSocketListWindows(AReadList).SetFDSet(LReadSet);
  1658. end;
  1659. if AWriteList <> nil then begin
  1660. TIdSocketListWindows(AWriteList).SetFDSet(LWriteSet);
  1661. end;
  1662. if AExceptList <> nil then begin
  1663. TIdSocketListWindows(AExceptList).SetFDSet(LExceptSet);
  1664. end;
  1665. end;
  1666. procedure TIdSocketListWindows.SetFDSet(var VSet: TFDSet);
  1667. begin
  1668. Lock;
  1669. try
  1670. FFDSet := VSet;
  1671. finally
  1672. Unlock;
  1673. end;
  1674. end;
  1675. procedure TIdSocketListWindows.GetFDSet(var VSet: TFDSet);
  1676. begin
  1677. Lock;
  1678. try
  1679. VSet := FFDSet;
  1680. finally
  1681. Unlock;
  1682. end;
  1683. end;
  1684. procedure TIdStackWindows.SetBlocking(ASocket: TIdStackSocketHandle;
  1685. const ABlocking: Boolean);
  1686. var
  1687. LValue: UInt32;
  1688. begin
  1689. LValue := UInt32(not ABlocking);
  1690. CheckForSocketError(ioctlsocket(ASocket, FIONBIO, LValue));
  1691. end;
  1692. function TIdSocketListWindows.Clone: TIdSocketList;
  1693. begin
  1694. Result := TIdSocketListWindows.Create;
  1695. try
  1696. Lock;
  1697. try
  1698. TIdSocketListWindows(Result).SetFDSet(FFDSet);
  1699. finally
  1700. Unlock;
  1701. end;
  1702. except
  1703. FreeAndNil(Result);
  1704. raise;
  1705. end;
  1706. end;
  1707. function TIdStackWindows.WouldBlock(const AResult: Integer): Boolean;
  1708. begin
  1709. Result := (AResult = WSAEWOULDBLOCK);
  1710. end;
  1711. function TIdStackWindows.HostByName(const AHostName: string;
  1712. const AIPVersion: TIdIPVersion = ID_DEFAULT_IP_VERSION): string;
  1713. var
  1714. {$IFDEF UNICODE}
  1715. LAddrInfo: pAddrInfoW;
  1716. Hints: TAddrInfoW;
  1717. {$ELSE}
  1718. LAddrInfo: pAddrInfo;
  1719. Hints: TAddrInfo;
  1720. {$ENDIF}
  1721. RetVal: Integer;
  1722. LHostName: String;
  1723. {$IFDEF STRING_UNICODE_MISMATCH}
  1724. LTemp: TIdPlatformString;
  1725. {$ENDIF}
  1726. begin
  1727. if not (AIPVersion in [Id_IPv4, Id_IPv6]) then begin
  1728. IPVersionUnsupported;
  1729. end;
  1730. ZeroMemory(@Hints, SIZE_TADDRINFO);
  1731. Hints.ai_family := IdIPFamily[AIPVersion];
  1732. Hints.ai_socktype := SOCK_STREAM;
  1733. LAddrInfo := nil;
  1734. if UseIDNAPI then begin
  1735. LHostName := IDNToPunnyCode(
  1736. {$IFDEF STRING_IS_UNICODE}
  1737. AHostName
  1738. {$ELSE}
  1739. TIdUnicodeString(AHostName) // explicit convert to Unicode
  1740. {$ENDIF}
  1741. );
  1742. end else begin
  1743. LHostName := AHostName;
  1744. end;
  1745. {$IFDEF STRING_UNICODE_MISMATCH}
  1746. LTemp := TIdPlatformString(LHostName); // explicit convert to Ansi/Unicode
  1747. {$ENDIF}
  1748. RetVal := getaddrinfo(
  1749. {$IFDEF STRING_UNICODE_MISMATCH}PIdPlatformChar(LTemp){$ELSE}PChar(LHostName){$ENDIF},
  1750. nil, @Hints, @LAddrInfo);
  1751. if RetVal <> 0 then begin
  1752. RaiseSocketError(gaiErrorToWsaError(RetVal));
  1753. end;
  1754. try
  1755. if AIPVersion = Id_IPv4 then begin
  1756. Result := TranslateTInAddrToString(PSockAddrIn(LAddrInfo^.ai_addr)^.sin_addr, Id_IPv4)
  1757. end else begin
  1758. Result := TranslateTInAddrToString(PSockAddrIn6(LAddrInfo^.ai_addr)^.sin6_addr, Id_IPv6);
  1759. end;
  1760. finally
  1761. freeaddrinfo(LAddrInfo);
  1762. end;
  1763. end;
  1764. procedure TIdStackWindows.Connect(const ASocket: TIdStackSocketHandle;
  1765. const AIP: string; const APort: TIdPort;
  1766. const AIPVersion: TIdIPVersion = ID_DEFAULT_IP_VERSION);
  1767. var
  1768. LAddr: SOCKADDR_STORAGE;
  1769. LSize: Integer;
  1770. begin
  1771. FillChar(LAddr, SizeOf(LAddr), 0);
  1772. case AIPVersion of
  1773. Id_IPv4: begin
  1774. PSockAddrIn(@LAddr)^.sin_family := Id_PF_INET4;
  1775. TranslateStringToTInAddr(AIP, PSockAddrIn(@LAddr)^.sin_addr, Id_IPv4);
  1776. PSockAddrIn(@LAddr)^.sin_port := htons(APort);
  1777. LSize := SIZE_TSOCKADDRIN;
  1778. end;
  1779. Id_IPv6: begin
  1780. PSockAddrIn6(@LAddr)^.sin6_family := Id_PF_INET6;
  1781. TranslateStringToTInAddr(AIP, PSockAddrIn6(@LAddr)^.sin6_addr, Id_IPv6);
  1782. PSockAddrIn6(@LAddr)^.sin6_port := htons(APort);
  1783. LSize := SIZE_TSOCKADDRIN6;
  1784. end;
  1785. else begin
  1786. LSize := 0; // avoid warning
  1787. IPVersionUnsupported;
  1788. end;
  1789. end;
  1790. CheckForSocketError(IdWinsock2.connect(ASocket, IdWinsock2.PSOCKADDR(@LAddr), LSize));
  1791. end;
  1792. procedure TIdStackWindows.GetPeerName(ASocket: TIdStackSocketHandle;
  1793. var VIP: string; var VPort: TIdPort; var VIPVersion: TIdIPVersion);
  1794. var
  1795. LSize: Integer;
  1796. LAddr: SOCKADDR_STORAGE;
  1797. begin
  1798. LSize := SizeOf(LAddr);
  1799. CheckForSocketError(IdWinsock2.getpeername(ASocket, IdWinsock2.PSOCKADDR(@LAddr), LSize));
  1800. case LAddr.ss_family of
  1801. Id_PF_INET4: begin
  1802. VIP := TranslateTInAddrToString(PSockAddrIn(@LAddr)^.sin_addr, Id_IPv4);
  1803. VPort := ntohs(PSockAddrIn(@LAddr)^.sin_port);
  1804. VIPVersion := Id_IPv4;
  1805. end;
  1806. Id_PF_INET6: begin
  1807. VIP := TranslateTInAddrToString(PSockAddrIn6(@LAddr)^.sin6_addr, Id_IPv6);
  1808. VPort := ntohs(PSockAddrIn6(@LAddr)^.sin6_port);
  1809. VIPVersion := Id_IPv6;
  1810. end;
  1811. else begin
  1812. IPVersionUnsupported;
  1813. end;
  1814. end;
  1815. end;
  1816. procedure TIdStackWindows.Disconnect(ASocket: TIdStackSocketHandle);
  1817. begin
  1818. // Windows uses Id_SD_Send, Linux should use Id_SD_Both
  1819. WSShutdown(ASocket, Id_SD_Send);
  1820. // SO_LINGER is false - socket may take a little while to actually close after this
  1821. WSCloseSocket(ASocket);
  1822. end;
  1823. procedure TIdStackWindows.{$IFDEF VCL_XE3_OR_ABOVE}GetSocketOption{$ELSE}WSGetSocketOption{$ENDIF}
  1824. (ASocket: TIdStackSocketHandle; ALevel: TIdSocketOptionLevel; AOptName: TIdSocketOption;
  1825. var AOptVal; var AOptLen: Integer);
  1826. begin
  1827. CheckForSocketError(
  1828. getsockopt(ASocket, ALevel, AOptName,
  1829. {$IFNDEF HAS_PAnsiChar}
  1830. // TODO: use TPtrWrapper here?
  1831. {PIdAnsiChar}@AOptVal
  1832. {$ELSE}
  1833. PIdAnsiChar(@AOptVal)
  1834. {$ENDIF},
  1835. AOptLen
  1836. )
  1837. );
  1838. end;
  1839. procedure TIdStackWindows.{$IFDEF VCL_XE3_OR_ABOVE}SetSocketOption{$ELSE}WSSetSocketOption{$ENDIF}
  1840. (ASocket: TIdStackSocketHandle; ALevel: TIdSocketOptionLevel; AOptName: TIdSocketOption;
  1841. const AOptVal; const AOptLen: Integer);
  1842. begin
  1843. CheckForSocketError(
  1844. setsockopt(ASocket, ALevel, Aoptname,
  1845. {$IFNDEF HAS_PAnsiChar}
  1846. // TODO: use TPtrWrapper here?
  1847. {PIdAnsiChar}@AOptVal
  1848. {$ELSE}
  1849. PIdAnsiChar(@AOptVal)
  1850. {$ENDIF},
  1851. AOptLen
  1852. )
  1853. );
  1854. end;
  1855. function TIdStackWindows.SupportsIPv4: Boolean;
  1856. var
  1857. LLen : DWORD;
  1858. LPInfo, LPCurPtr: LPWSAPROTOCOL_INFO;
  1859. LCount : Integer;
  1860. i : Integer;
  1861. begin
  1862. // TODO: move this logic into CheckIPVersionSupport() instead...
  1863. // Result := CheckIPVersionSupport(Id_IPv4);
  1864. Result := False;
  1865. LPInfo := nil;
  1866. try
  1867. LLen := 0;
  1868. // Note: WSAEnumProtocols returns -1 when it is just called to get the needed Buffer Size!
  1869. repeat
  1870. LCount := IdWinsock2.WSAEnumProtocols(nil, LPInfo, LLen);
  1871. if LCount = SOCKET_ERROR then
  1872. begin
  1873. if WSAGetLastError() <> WSAENOBUFS then begin
  1874. Exit;
  1875. end;
  1876. ReallocMem(LPInfo, LLen);
  1877. end else begin
  1878. Break;
  1879. end;
  1880. until False;
  1881. if LCount > 0 then
  1882. begin
  1883. LPCurPtr := LPInfo;
  1884. for i := 0 to LCount-1 do
  1885. begin
  1886. if LPCurPtr^.iAddressFamily = AF_INET then
  1887. begin
  1888. Result := True;
  1889. Exit;
  1890. end;
  1891. Inc(LPCurPtr);
  1892. end;
  1893. end;
  1894. finally
  1895. FreeMem(LPInfo);
  1896. end;
  1897. end;
  1898. {
  1899. based on
  1900. http://groups.google.com/groups?q=Winsock2+Delphi+protocol&hl=en&lr=&ie=UTF-8&oe=utf-8&selm=3cebe697_2%40dnews&rnum=9
  1901. }
  1902. function TIdStackWindows.SupportsIPv6: Boolean;
  1903. var
  1904. LLen : DWORD;
  1905. LPInfo, LPCurPtr: LPWSAPROTOCOL_INFO;
  1906. LCount : Integer;
  1907. i : Integer;
  1908. begin
  1909. // TODO: move this logic into CheckIPVersionSupport() instead...
  1910. // Result := CheckIPVersionSupport(Id_IPv6);
  1911. Result := False;
  1912. LPInfo := nil;
  1913. try
  1914. LLen := 0;
  1915. // Note: WSAEnumProtocols returns -1 when it is just called to get the needed Buffer Size!
  1916. repeat
  1917. LCount := IdWinsock2.WSAEnumProtocols(nil, LPInfo, LLen);
  1918. if LCount = SOCKET_ERROR then
  1919. begin
  1920. if WSAGetLastError() <> WSAENOBUFS then begin
  1921. Exit;
  1922. end;
  1923. ReallocMem(LPInfo, LLen);
  1924. end else begin
  1925. Break;
  1926. end;
  1927. until False;
  1928. if LCount > 0 then
  1929. begin
  1930. LPCurPtr := LPInfo;
  1931. for i := 0 to LCount-1 do
  1932. begin
  1933. if LPCurPtr^.iAddressFamily = AF_INET6 then
  1934. begin
  1935. Result := True;
  1936. Exit;
  1937. end;
  1938. Inc(LPCurPtr);
  1939. end;
  1940. end;
  1941. finally
  1942. FreeMem(LPInfo);
  1943. end;
  1944. end;
  1945. function TIdStackWindows.IOControl(const s: TIdStackSocketHandle;
  1946. const cmd: UInt32; var arg: UInt32): Integer;
  1947. begin
  1948. Result := IdWinsock2.ioctlsocket(s, cmd, arg);
  1949. end;
  1950. procedure TIdStackWindows.WSQuerryIPv6Route(ASocket: TIdStackSocketHandle;
  1951. const AIP: String; const APort: TIdPort; var VSource; var VDest);
  1952. var
  1953. Llocalif : TSockAddrIn6;
  1954. LAddr : TSockAddrIn6;
  1955. Bytes : DWORD;
  1956. begin
  1957. //make our LAddrInfo structure
  1958. FillChar(LAddr, SizeOf(LAddr), 0);
  1959. LAddr.sin6_family := AF_INET6;
  1960. TranslateStringToTInAddr(AIP, LAddr.sin6_addr, Id_IPv6);
  1961. Move(LAddr.sin6_addr, VDest, SizeOf(in6_addr));
  1962. LAddr.sin6_port := htons(APort);
  1963. // Find out which local interface for the destination
  1964. // RLebeau: in XE4+, PDWORD is NOT defined as ^DWORD, so we have to use a type-cast!
  1965. CheckForSocketError(WSAIoctl(ASocket, SIO_ROUTING_INTERFACE_QUERY,
  1966. @LAddr, SizeOf(LAddr), @Llocalif, SizeOf(Llocalif), PDWORD(@Bytes), nil, nil));
  1967. Move(Llocalif.sin6_addr, VSource, SizeOf(in6_addr));
  1968. end;
  1969. procedure TIdStackWindows.WriteChecksum(s: TIdStackSocketHandle;
  1970. var VBuffer: TIdBytes; const AOffset: Integer; const AIP: String;
  1971. const APort: TIdPort; const AIPVersion: TIdIPVersion);
  1972. begin
  1973. case AIPVersion of
  1974. Id_IPv4 : CopyTIdUInt16(HostToLittleEndian(CalcCheckSum(VBuffer)), VBuffer, AOffset);
  1975. Id_IPv6 : WriteChecksumIPv6(s, VBuffer, AOffset, AIP, APort);
  1976. else
  1977. IPVersionUnsupported;
  1978. end;
  1979. end;
  1980. procedure TIdStackWindows.WriteChecksumIPv6(s: TIdStackSocketHandle;
  1981. var VBuffer: TIdBytes; const AOffset: Integer; const AIP: String;
  1982. const APort: TIdPort);
  1983. var
  1984. LSource : TIdIn6Addr;
  1985. LDest : TIdIn6Addr;
  1986. LTmp : TIdBytes;
  1987. LIdx : Integer;
  1988. LC : UInt32;
  1989. {
  1990. +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  1991. | |
  1992. + +
  1993. | |
  1994. + Source Address +
  1995. | |
  1996. + +
  1997. | |
  1998. +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  1999. | |
  2000. + +
  2001. | |
  2002. + Destination Address +
  2003. | |
  2004. + +
  2005. | |
  2006. +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  2007. | Upper-Layer Packet Length |
  2008. +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  2009. | zero | Next Header |
  2010. +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  2011. }
  2012. begin
  2013. WSQuerryIPv6Route(s, AIP, APort, LSource, LDest);
  2014. SetLength(LTmp, 40+Length(VBuffer));
  2015. //16
  2016. Move(LSource, LTmp[0], SIZE_TSOCKADDRIN6);
  2017. LIdx := SIZE_TSOCKADDRIN6;
  2018. //32
  2019. Move(LDest, LTmp[LIdx], SIZE_TSOCKADDRIN6);
  2020. Inc(LIdx, SIZE_TSOCKADDRIN6);
  2021. //use a word so you don't wind up using the wrong network byte order function
  2022. LC := UInt32(Length(VBuffer));
  2023. CopyTIdUInt32(HostToNetwork(LC), LTmp, LIdx);
  2024. Inc(LIdx, 4);
  2025. //36
  2026. //zero the next three bytes
  2027. FillChar(LTmp[LIdx], 3, 0);
  2028. Inc(LIdx, 3);
  2029. //next header (protocol type determines it
  2030. LTmp[LIdx] := Id_IPPROTO_ICMPV6; // Id_IPPROTO_ICMP6;
  2031. Inc(LIdx);
  2032. //combine the two
  2033. CopyTIdBytes(VBuffer, 0, LTmp, LIdx, Length(VBuffer));
  2034. //zero out the checksum field
  2035. CopyTIdUInt16(0, LTmp, LIdx+AOffset);
  2036. CopyTIdUInt16(HostToLittleEndian(CalcCheckSum(LTmp)), VBuffer, AOffset);
  2037. end;
  2038. function TIdStackWindows.ReceiveMsg(ASocket: TIdStackSocketHandle; var VBuffer : TIdBytes;
  2039. APkt: TIdPacketInfo): UInt32;
  2040. var
  2041. LIP : String;
  2042. LPort : TIdPort;
  2043. LIPVersion : TIdIPVersion;
  2044. {Windows CE does not have WSARecvMsg}
  2045. {$IFNDEF WINCE}
  2046. LSize: PtrUInt;
  2047. LAddr: TIdBytes;
  2048. PAddr: PSOCKADDR_STORAGE;
  2049. LMsg : TWSAMSG;
  2050. LMsgBuf : TWSABUF;
  2051. LControl : TIdBytes;
  2052. LCurCmsg : LPWSACMSGHDR; //for iterating through the control buffer
  2053. PPktInfo: PInPktInfo;
  2054. PPktInfo6: PIn6PktInfo;
  2055. {$ENDIF}
  2056. begin
  2057. {$IFNDEF WINCE}
  2058. //This runs only on WIndows XP or later
  2059. // XP 5.1 at least, Vista 6.0
  2060. if IndyCheckWindowsVersion(5, 1) then
  2061. begin
  2062. //we call the macro twice because we specified two possible structures.
  2063. //Id_IPV6_HOPLIMIT and Id_IPV6_PKTINFO
  2064. LSize := WSA_CMSG_LEN(WSA_CMSG_LEN(Length(VBuffer)));
  2065. SetLength(LControl, LSize);
  2066. LMsgBuf.len := Length(VBuffer); // Length(VMsgData);
  2067. LMsgBuf.buf := PIdAnsiChar(Pointer(VBuffer)); // @VMsgData[0];
  2068. FillChar(LMsg, SIZE_TWSAMSG, 0);
  2069. LMsg.lpBuffers := @LMsgBuf;
  2070. LMsg.dwBufferCount := 1;
  2071. LMsg.Control.Len := LSize;
  2072. LMsg.Control.buf := PIdAnsiChar(Pointer(LControl));
  2073. // RLebeau: despite that we are not performing an overlapped I/O operation,
  2074. // WSARecvMsg() does not like the SOCKADDR variable being allocated on the
  2075. // stack, at least on my tests with Windows 7. So we will allocate it on
  2076. // the heap instead to keep WinSock happy...
  2077. SetLength(LAddr, SizeOf(SOCKADDR_STORAGE));
  2078. PAddr := PSOCKADDR_STORAGE(@LAddr[0]);
  2079. LMsg.name := IdWinsock2.PSOCKADDR(PAddr);
  2080. LMsg.namelen := Length(LAddr);
  2081. CheckForSocketError(WSARecvMsg(ASocket, @LMsg, Result, nil, nil));
  2082. APkt.Reset;
  2083. case PAddr^.ss_family of
  2084. Id_PF_INET4: begin
  2085. APkt.SourceIP := TranslateTInAddrToString(PSockAddrIn(PAddr)^.sin_addr, Id_IPv4);
  2086. APkt.SourcePort := ntohs(PSockAddrIn(PAddr)^.sin_port);
  2087. APkt.SourceIPVersion := Id_IPv4;
  2088. end;
  2089. Id_PF_INET6: begin
  2090. APkt.SourceIP := TranslateTInAddrToString(PSockAddrIn6(PAddr)^.sin6_addr, Id_IPv6);
  2091. APkt.SourcePort := ntohs(PSockAddrIn6(PAddr)^.sin6_port);
  2092. APkt.SourceIPVersion := Id_IPv6;
  2093. end;
  2094. else begin
  2095. Result := 0; // avoid warning
  2096. IPVersionUnsupported;
  2097. end;
  2098. end;
  2099. LCurCmsg := nil;
  2100. repeat
  2101. LCurCmsg := WSA_CMSG_NXTHDR(@LMsg, LCurCmsg);
  2102. if LCurCmsg = nil then begin
  2103. Break;
  2104. end;
  2105. case LCurCmsg^.cmsg_type of
  2106. IP_PKTINFO : //done this way because IPV6_PKTINF and IP_PKTINFO are both 19
  2107. begin
  2108. case PAddr^.ss_family of
  2109. Id_PF_INET4: begin
  2110. PPktInfo := PInPktInfo(WSA_CMSG_DATA(LCurCmsg));
  2111. APkt.DestIP := TranslateTInAddrToString(PPktInfo^.ipi_addr, Id_IPv4);
  2112. APkt.DestIF := PPktInfo^.ipi_ifindex;
  2113. APkt.DestIPVersion := Id_IPv4;
  2114. end;
  2115. Id_PF_INET6: begin
  2116. PPktInfo6 := PIn6PktInfo(WSA_CMSG_DATA(LCurCmsg));
  2117. APkt.DestIP := TranslateTInAddrToString(PPktInfo6^.ipi6_addr, Id_IPv6);
  2118. APkt.DestIF := PPktInfo6^.ipi6_ifindex;
  2119. APkt.DestIPVersion := Id_IPv6;
  2120. end;
  2121. end;
  2122. end;
  2123. Id_IPV6_HOPLIMIT :
  2124. begin
  2125. APkt.TTL := WSA_CMSG_DATA(LCurCmsg)^;
  2126. end;
  2127. end;
  2128. until False;
  2129. end else
  2130. begin
  2131. {$ENDIF}
  2132. Result := RecvFrom(ASocket, VBuffer, Length(VBuffer), 0, LIP, LPort, LIPVersion);
  2133. APkt.Reset;
  2134. APkt.SourceIP := LIP;
  2135. APkt.SourcePort := LPort;
  2136. APkt.SourceIPVersion := LIPVersion;
  2137. APkt.DestIPVersion := LIPVersion;
  2138. {$IFNDEF WINCE}
  2139. end;
  2140. {$ENDIF}
  2141. end;
  2142. function TIdStackWindows.CheckIPVersionSupport(const AIPVersion: TIdIPVersion): Boolean;
  2143. var
  2144. LTmpSocket: TIdStackSocketHandle;
  2145. begin
  2146. LTmpSocket := WSSocket(IdIPFamily[AIPVersion], Id_SOCK_STREAM, Id_IPPROTO_IP);
  2147. Result := LTmpSocket <> Id_INVALID_SOCKET;
  2148. if Result then begin
  2149. WSCloseSocket(LTmpSocket);
  2150. end;
  2151. end;
  2152. {$IFNDEF WINCE}
  2153. {
  2154. This is somewhat messy but I wanted to do things this way to support Int64
  2155. file sizes.
  2156. }
  2157. function ServeFile(ASocket: TIdStackSocketHandle; const AFileName: string): Int64;
  2158. var
  2159. LFileHandle: THandle;
  2160. LSize: LARGE_INTEGER;
  2161. {$IFDEF STRING_UNICODE_MISMATCH}
  2162. LTemp: TIdPlatformString;
  2163. {$ENDIF}
  2164. begin
  2165. Result := 0;
  2166. {$IFDEF STRING_UNICODE_MISMATCH}
  2167. LTemp := TIdPlatformString(AFileName); // explicit convert to Ansi/Unicode
  2168. {$ENDIF}
  2169. LFileHandle := CreateFile(
  2170. {$IFDEF STRING_UNICODE_MISMATCH}PIdPlatformChar(LTemp){$ELSE}PChar(AFileName){$ENDIF},
  2171. GENERIC_READ, FILE_SHARE_READ, nil, OPEN_EXISTING,
  2172. FILE_ATTRIBUTE_NORMAL or FILE_FLAG_SEQUENTIAL_SCAN, 0);
  2173. if LFileHandle <> INVALID_HANDLE_VALUE then
  2174. begin
  2175. try
  2176. if TransmitFile(ASocket, LFileHandle, 0, 0, nil, nil, 0) then
  2177. begin
  2178. if Assigned(GetFileSizeEx) then
  2179. begin
  2180. if not GetFileSizeEx(LFileHandle, LSize) then begin
  2181. Exit;
  2182. end;
  2183. end else
  2184. begin
  2185. LSize.LowPart := GetFileSize(LFileHandle, @LSize.HighPart);
  2186. if (LSize.LowPart = $FFFFFFFF) and (GetLastError() <> 0) then begin
  2187. Exit;
  2188. end;
  2189. end;
  2190. Result := LSize.QuadPart;
  2191. end;
  2192. finally
  2193. CloseHandle(LFileHandle);
  2194. end;
  2195. end;
  2196. end;
  2197. {$ENDIF}
  2198. procedure TIdStackWindows.SetKeepAliveValues(ASocket: TIdStackSocketHandle;
  2199. const AEnabled: Boolean; const ATimeMS, AInterval: Integer);
  2200. var
  2201. ka: _tcp_keepalive;
  2202. Bytes: DWORD;
  2203. begin
  2204. // TODO: instead of doing an OS version check, always call SIO_KEEPALIVE_VALS
  2205. // when AEnabled is True, and then fallback to SO_KEEPALIVE if WSAIoctl()
  2206. // reports that SIO_KEEPALIVE_VALS is not supported...
  2207. // SIO_KEEPALIVE_VALS is supported on Win2K+ and WinCE 4.x only
  2208. if AEnabled and IndyCheckWindowsVersion({$IFDEF WINCE}4{$ELSE}5{$ENDIF}) then
  2209. begin
  2210. ka.onoff := 1;
  2211. ka.keepalivetime := ATimeMS;
  2212. ka.keepaliveinterval := AInterval;
  2213. // RLebeau: in XE4+, PDWORD is NOT defined as ^DWORD, so we have to use a type-cast!
  2214. WSAIoctl(ASocket, SIO_KEEPALIVE_VALS, @ka, SizeOf(ka), nil, 0, PDWORD(@Bytes), nil, nil);
  2215. end else begin
  2216. SetSocketOption(ASocket, Id_SOL_SOCKET, Id_SO_KEEPALIVE, iif(AEnabled, 1, 0));
  2217. end;
  2218. end;
  2219. initialization
  2220. GStarted := False;
  2221. GSocketListClass := TIdSocketListWindows;
  2222. // Check if we are running under windows NT
  2223. {$IFNDEF WINCE}
  2224. if IndyWindowsPlatform = VER_PLATFORM_WIN32_NT then begin
  2225. GetFileSizeEx := Windows.GetProcAddress(GetModuleHandle('Kernel32.dll'), 'GetFileSizeEx');
  2226. GServeFileProc := ServeFile;
  2227. end;
  2228. {$ENDIF}
  2229. {$IFDEF USE_IPHLPAPI}
  2230. InitializeIPHelperStubs;
  2231. {$ENDIF}
  2232. finalization
  2233. IdWship6.CloseLibrary;
  2234. UninitializeWinSock;
  2235. {$IFDEF USE_IPHLPAPI}
  2236. UninitializeIPHelperAPI;
  2237. {$ENDIF}
  2238. GStarted := False;
  2239. end.