IdStackWindows.pas 81 KB

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