IdStackWindows.pas 80 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580
  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. LPort := -1;
  1015. IndyRaiseOuterException(EIdInvalidServiceName.CreateFmt(RSInvalidServiceName, [AServiceName]));
  1016. end;
  1017. end;
  1018. if (LPort < 0) or (LPort > High(TIdPort)) then begin
  1019. raise EIdInvalidServiceName.CreateFmt(RSInvalidServiceName, [AServiceName]);
  1020. end;
  1021. Result := TIdPort(LPort);
  1022. end;
  1023. end;
  1024. procedure TIdStackWindows.AddServByPortToList(const APortNumber: TIdPort; AAddresses: TStrings);
  1025. type
  1026. // Note that there is no Unicode version of getservbyport.
  1027. PPAnsiCharArray = ^TPAnsiCharArray;
  1028. TPAnsiCharArray = packed array[0..(MaxInt div SizeOf(PIdAnsiChar))-1] of PIdAnsiChar;
  1029. var
  1030. ps: PServEnt;
  1031. i: integer;
  1032. p: PPAnsiCharArray;
  1033. begin
  1034. ps := getservbyport(htons(APortNumber), nil);
  1035. if ps = nil then begin
  1036. RaiseLastSocketError;
  1037. end;
  1038. AAddresses.BeginUpdate;
  1039. try
  1040. //we have to specifically type cast a PIdAnsiChar to a string for D2009+.
  1041. //otherwise, we will get a warning about implicit typecast from AnsiString
  1042. //to string
  1043. AAddresses.Add(String(ps^.s_name));
  1044. i := 0;
  1045. p := Pointer(ps^.s_aliases);
  1046. while p[i] <> nil do
  1047. begin
  1048. AAddresses.Add(String(p[i]));
  1049. Inc(i);
  1050. end;
  1051. finally
  1052. AAddresses.EndUpdate;
  1053. end;
  1054. end;
  1055. function TIdStackWindows.HostToNetwork(AValue: UInt16): UInt16;
  1056. begin
  1057. Result := htons(AValue);
  1058. end;
  1059. function TIdStackWindows.NetworkToHost(AValue: UInt16): UInt16;
  1060. begin
  1061. Result := ntohs(AValue);
  1062. end;
  1063. function TIdStackWindows.HostToNetwork(AValue: UInt32): UInt32;
  1064. begin
  1065. Result := htonl(AValue);
  1066. end;
  1067. function TIdStackWindows.NetworkToHost(AValue: UInt32): UInt32;
  1068. begin
  1069. Result := ntohl(AValue);
  1070. end;
  1071. function TIdStackWindows.HostToNetwork(AValue: TIdUInt64): TIdUInt64;
  1072. var
  1073. LParts: TIdUInt64Parts;
  1074. L: UInt32;
  1075. begin
  1076. // TODO: ARM is bi-endian, so if Windows is running on ARM instead of x86,
  1077. // can it ever be big endian? Or do ARM manufacturers put it in little endian
  1078. // for Windows installations?
  1079. //if (htonl(1) <> 1) then begin
  1080. LParts.QuadPart := AValue{$IFDEF TIdUInt64_HAS_QuadPart}.QuadPart{$ENDIF};
  1081. L := htonl(LParts.HighPart);
  1082. LParts.HighPart := htonl(LParts.LowPart);
  1083. LParts.LowPart := L;
  1084. Result{$IFDEF TIdUInt64_HAS_QuadPart}.QuadPart{$ENDIF} := LParts.QuadPart;
  1085. //end else begin
  1086. // Result{$IFDEF TIdUInt64_HAS_QuadPart}.QuadPart{$ENDIF} := AValue{$IFDEF TIdUInt64_HAS_QuadPart}.QuadPart{$ENDIF};
  1087. //end;
  1088. end;
  1089. function TIdStackWindows.NetworkToHost(AValue: TIdUInt64): TIdUInt64;
  1090. var
  1091. LParts: TIdUInt64Parts;
  1092. L: UInt32;
  1093. begin
  1094. // TODO: ARM is bi-endian, so if Windows is running on ARM instead of x86,
  1095. // can it ever be big endian? Or do ARM manufacturers put it in little endian
  1096. // for Windows installations?
  1097. //if (ntohl(1) <> 1) then begin
  1098. LParts.QuadPart := AValue{$IFDEF TIdUInt64_HAS_QuadPart}.QuadPart{$ENDIF};
  1099. L := ntohl(LParts.HighPart);
  1100. LParts.HighPart := ntohl(LParts.LowPart);
  1101. LParts.LowPart := L;
  1102. Result{$IFDEF TIdUInt64_HAS_QuadPart}.QuadPart{$ENDIF} := LParts.QuadPart;
  1103. //end else begin
  1104. // Result{$IFDEF TIdUInt64_HAS_QuadPart}.QuadPart{$ENDIF} := AValue{$IFDEF TIdUInt64_HAS_QuadPart}.QuadPart{$ENDIF};
  1105. //end;
  1106. end;
  1107. type
  1108. TIdStackLocalAddressAccess = class(TIdStackLocalAddress)
  1109. end;
  1110. procedure TIdStackWindows.GetLocalAddressList(AAddresses: TIdStackLocalAddressList);
  1111. {$IFDEF USE_IPHLPAPI}
  1112. function IPv4MaskLengthToString(MaskLength: ULONG): String;
  1113. var
  1114. Mask: ULONG;
  1115. begin
  1116. if ConvertLengthToIpv4Mask(MaskLength, Mask) = ERROR_SUCCESS then begin
  1117. Result := TranslateTInAddrToString(Mask, Id_IPv4);
  1118. end else begin
  1119. Result := '';
  1120. end;
  1121. end;
  1122. procedure GetIPv4SubNetMasks(ASubNetMasks: TStrings);
  1123. var
  1124. Ret: DWORD;
  1125. BufLen: ULONG;
  1126. Table: PMIB_IPADDRTABLE;
  1127. pRow: PMIB_IPADDRROW;
  1128. I: ULONG;
  1129. begin
  1130. BufLen := 0;
  1131. Table := nil;
  1132. try
  1133. repeat
  1134. // Alternatively, use WSAIoctl(SIO_GET_INTERFACE_LIST), but
  1135. // I have noticed it does not always return IPv4 subnets!
  1136. Ret := GetIpAddrTable(Table, BufLen, FALSE);
  1137. case Ret of
  1138. ERROR_SUCCESS:
  1139. begin
  1140. if BufLen = 0 then begin
  1141. Exit;
  1142. end;
  1143. Break;
  1144. end;
  1145. ERROR_NOT_SUPPORTED:
  1146. Exit;
  1147. ERROR_INSUFFICIENT_BUFFER:
  1148. ReallocMem(Table, BufLen);
  1149. else
  1150. SetLastError(Ret);
  1151. IndyRaiseLastError;
  1152. end;
  1153. until False;
  1154. if Ret = ERROR_SUCCESS then
  1155. begin
  1156. if Table^.dwNumEntries > 0 then
  1157. begin
  1158. pRow := @(Table^.table[0]);
  1159. for I := 0 to Table^.dwNumEntries-1 do begin
  1160. IndyAddPair(ASubNetMasks,
  1161. TranslateTInAddrToString(pRow^.dwAddr, Id_IPv4),
  1162. TranslateTInAddrToString(pRow^.dwMask, Id_IPv4));
  1163. Inc(pRow);
  1164. end;
  1165. end;
  1166. end;
  1167. finally
  1168. FreeMem(Table);
  1169. end;
  1170. end;
  1171. function GetLocalAddressesByAdaptersAddresses: Boolean;
  1172. var
  1173. Ret: DWORD;
  1174. BufLen: ULONG;
  1175. Adapter, Adapters: PIP_ADAPTER_ADDRESSES;
  1176. UnicastAddr: PIP_ADAPTER_UNICAST_ADDRESS;
  1177. IPAddr: string;
  1178. SubNetStr: String;
  1179. SubNetMasks: TStringList;
  1180. LAddress: TIdStackLocalAddress;
  1181. begin
  1182. // assume True unless ERROR_NOT_SUPPORTED is reported...
  1183. Result := True;
  1184. // MSDN says:
  1185. // The recommended method of calling the GetAdaptersAddresses function is
  1186. // to pre-allocate a 15KB working buffer pointed to by the AdapterAddresses
  1187. // parameter. On typical computers, this dramatically reduces the chances
  1188. // that the GetAdaptersAddresses function returns ERROR_BUFFER_OVERFLOW,
  1189. // which would require calling GetAdaptersAddresses function multiple times.
  1190. BufLen := 1024*15;
  1191. GetMem(Adapters, BufLen);
  1192. try
  1193. repeat
  1194. // TODO: include GAA_FLAG_INCLUDE_PREFIX on XPSP1+?
  1195. // TODO: include GAA_FLAG_INCLUDE_ALL_INTERFACES on Vista+?
  1196. Ret := GetAdaptersAddresses(PF_UNSPEC, GAA_FLAG_SKIP_ANYCAST or GAA_FLAG_SKIP_MULTICAST or GAA_FLAG_SKIP_DNS_SERVER, nil, Adapters, BufLen);
  1197. case Ret of
  1198. ERROR_SUCCESS:
  1199. begin
  1200. // Windows CE versions earlier than 4.1 may return ERROR_SUCCESS and
  1201. // BufLen=0 if no adapter info is available, instead of returning
  1202. // ERROR_NO_DATA as documented...
  1203. if BufLen = 0 then begin
  1204. Exit;
  1205. end;
  1206. Break;
  1207. end;
  1208. ERROR_NOT_SUPPORTED:
  1209. begin
  1210. Result := False;
  1211. Exit;
  1212. end;
  1213. ERROR_NO_DATA,
  1214. ERROR_ADDRESS_NOT_ASSOCIATED:
  1215. Exit;
  1216. ERROR_BUFFER_OVERFLOW:
  1217. ReallocMem(Adapters, BufLen);
  1218. else
  1219. SetLastError(Ret);
  1220. IndyRaiseLastError;
  1221. end;
  1222. until False;
  1223. if Ret = ERROR_SUCCESS then
  1224. begin
  1225. SubNetMasks := nil;
  1226. try
  1227. AAddresses.BeginUpdate;
  1228. try
  1229. Adapter := Adapters;
  1230. repeat
  1231. if (Adapter.IfType <> IF_TYPE_SOFTWARE_LOOPBACK) and
  1232. ((Adapter.Flags and IP_ADAPTER_RECEIVE_ONLY) = 0) then
  1233. begin
  1234. UnicastAddr := Adapter^.FirstUnicastAddress;
  1235. while UnicastAddr <> nil do
  1236. begin
  1237. if UnicastAddr^.DadState = IpDadStatePreferred then
  1238. begin
  1239. LAddress := nil;
  1240. case UnicastAddr^.Address.lpSockaddr.sin_family of
  1241. AF_INET: begin
  1242. IPAddr := TranslateTInAddrToString(PSockAddrIn(UnicastAddr^.Address.lpSockaddr)^.sin_addr, Id_IPv4);
  1243. // TODO: use the UnicastAddr^.Length field to determine which version of
  1244. // IP_ADAPTER_UNICAST_ADDRESS is being provided, rather than checking the
  1245. // OS version number...
  1246. if IndyCheckWindowsVersion(6) then begin
  1247. // The OnLinkPrefixLength member is only available on Windows Vista and later
  1248. SubNetStr := IPv4MaskLengthToString(UnicastAddr^.OnLinkPrefixLength);
  1249. end else
  1250. begin
  1251. // TODO: on XP SP1+, can the subnet mask be determined
  1252. // by analyzing the Adapter's Prefix list without resorting
  1253. // to reading the Registry?
  1254. if SubNetMasks = nil then
  1255. begin
  1256. SubNetMasks := TStringList.Create;
  1257. GetIPv4SubNetMasks(SubNetMasks);
  1258. end;
  1259. SubNetStr := SubNetMasks.Values[IPAddr];
  1260. end;
  1261. LAddress := TIdStackLocalAddressIPv4.Create(AAddresses, IPAddr, SubNetStr);
  1262. TIdStackLocalAddressAccess(LAddress).FInterfaceIndex := Adapter^.Union.IfIndex;
  1263. end;
  1264. AF_INET6: begin
  1265. LAddress := TIdStackLocalAddressIPv6.Create(AAddresses,
  1266. TranslateTInAddrToString(PSockAddrIn6(UnicastAddr^.Address.lpSockaddr)^.sin6_addr, Id_IPv6));
  1267. // The Ipv6IfIndex member is only available on Windows XP SP1 and later
  1268. if IndyCheckWindowsVersion(5, 2) or (IndyCheckWindowsVersion(5, 1) {TODO: and SP1+}) then begin
  1269. TIdStackLocalAddressAccess(LAddress).FInterfaceIndex := Adapter^.Ipv6IfIndex;
  1270. end;
  1271. end;
  1272. end;
  1273. if LAddress <> nil then begin
  1274. TIdStackLocalAddressAccess(LAddress).FDescription := String(Adapter^.Description);
  1275. TIdStackLocalAddressAccess(LAddress).FFriendlyName := String(Adapter^.FriendlyName);
  1276. TIdStackLocalAddressAccess(LAddress).FInterfaceName := String(Adapter^.AdapterName);
  1277. end;
  1278. end;
  1279. UnicastAddr := UnicastAddr^.Next;
  1280. end;
  1281. end;
  1282. Adapter := Adapter^.Next;
  1283. until Adapter = nil;
  1284. finally
  1285. AAddresses.EndUpdate;
  1286. end;
  1287. finally
  1288. SubNetMasks.Free;
  1289. end;
  1290. end;
  1291. finally
  1292. FreeMem(Adapters);
  1293. end;
  1294. end;
  1295. procedure GetUniDirAddresseses(AUniDirAddresses: TStrings);
  1296. var
  1297. Ret: DWORD;
  1298. BufLen: ULONG;
  1299. Adapters: PIP_UNIDIRECTIONAL_ADAPTER_ADDRESS;
  1300. pUniDirAddr: PInAddr;
  1301. I: ULONG;
  1302. begin
  1303. BufLen := 1024*15;
  1304. GetMem(Adapters, BufLen);
  1305. try
  1306. repeat
  1307. Ret := GetUniDirectionalAdapterInfo(Adapters, BufLen);
  1308. case Ret of
  1309. ERROR_SUCCESS:
  1310. begin
  1311. if BufLen = 0 then begin
  1312. Exit;
  1313. end;
  1314. Break;
  1315. end;
  1316. ERROR_NOT_SUPPORTED,
  1317. ERROR_NO_DATA:
  1318. Exit;
  1319. ERROR_MORE_DATA:
  1320. ReallocMem(Adapters, BufLen);
  1321. else
  1322. SetLastError(Ret);
  1323. IndyRaiseLastError;
  1324. end;
  1325. until False;
  1326. if Ret = ERROR_SUCCESS then
  1327. begin
  1328. if Adapters^.NumAdapters > 0 then
  1329. begin
  1330. pUniDirAddr := @(Adapters^.Address[0]);
  1331. for I := 0 to Adapters^.NumAdapters-1 do begin
  1332. AUniDirAddresses.Add(TranslateTInAddrToString(pUniDirAddr^, Id_IPv4));
  1333. Inc(pUniDirAddr);
  1334. end;
  1335. end;
  1336. end;
  1337. finally
  1338. FreeMem(Adapters);
  1339. end;
  1340. end;
  1341. procedure GetLocalAddressesByAdaptersInfo;
  1342. var
  1343. Ret: DWORD;
  1344. BufLen: ULONG;
  1345. UniDirAddresses: TStringList;
  1346. Adapter, Adapters: PIP_ADAPTER_INFO;
  1347. IPAddr: PIP_ADDR_STRING;
  1348. IPStr, MaskStr: String;
  1349. LAddress: TIdStackLocalAddress;
  1350. begin
  1351. BufLen := 1024*15;
  1352. GetMem(Adapters, BufLen);
  1353. try
  1354. repeat
  1355. Ret := GetAdaptersInfo(Adapters, BufLen);
  1356. case Ret of
  1357. ERROR_SUCCESS:
  1358. begin
  1359. // Windows CE versions earlier than 4.1 may return ERROR_SUCCESS and
  1360. // BufLen=0 if no adapter info is available, instead of returning
  1361. // ERROR_NO_DATA as documented...
  1362. if BufLen = 0 then begin
  1363. Exit;
  1364. end;
  1365. Break;
  1366. end;
  1367. ERROR_NOT_SUPPORTED,
  1368. ERROR_NO_DATA:
  1369. Exit;
  1370. ERROR_BUFFER_OVERFLOW:
  1371. ReallocMem(Adapters, BufLen);
  1372. else
  1373. SetLastError(Ret);
  1374. IndyRaiseLastError;
  1375. end;
  1376. until False;
  1377. if Ret = ERROR_SUCCESS then
  1378. begin
  1379. // on XP and later, GetAdaptersInfo() includes uni-directional adapters.
  1380. // Need to use GetUniDirectionalAdapterInfo() to filter them out of the
  1381. // list ...
  1382. if IndyCheckWindowsVersion(5, 1) then begin
  1383. UniDirAddresses := TStringList.Create;
  1384. end else begin
  1385. UniDirAddresses := nil;
  1386. end;
  1387. try
  1388. if UniDirAddresses <> nil then begin
  1389. GetUniDirAddresseses(UniDirAddresses);
  1390. end;
  1391. AAddresses.BeginUpdate;
  1392. try
  1393. Adapter := Adapters;
  1394. repeat
  1395. IPAddr := @(Adapter^.IpAddressList);
  1396. repeat
  1397. {$IFDEF USE_MARSHALLED_PTRS}
  1398. IPStr := TMarshal.ReadStringAsAnsiUpTo(CP_ACP, TPtrWrapper.Create(@(IPAddr^.IpAddress.S[0]), 15);
  1399. {$ELSE}
  1400. IPStr := String(IPAddr^.IpAddress.S);
  1401. {$ENDIF}
  1402. if (IPStr <> '') and (IPStr <> '0.0.0.0') then
  1403. begin
  1404. if UniDirAddresses <> nil then begin
  1405. if UniDirAddresses.IndexOf(IPStr) <> -1 then begin
  1406. IPAddr := IPAddr^.Next;
  1407. Continue;
  1408. end;
  1409. end;
  1410. {$IFDEF USE_MARSHALLED_PTRS}
  1411. MaskStr := TMarshal.ReadStringAsAnsiUpTo(CP_ACP, TPtrWrapper.Create(@(IPAddr^.IpMask.S[0]), 15);
  1412. {$ELSE}
  1413. MaskStr := String(IPAddr^.IpMask.S);
  1414. {$ENDIF}
  1415. LAddress := TIdStackLocalAddressIPv4.Create(AAddresses, IPStr, MaskStr);
  1416. TIdStackLocalAddressAccess(LAddress).FDescription := String(Adapter^.Description);
  1417. TIdStackLocalAddressAccess(LAddress).FFriendlyName := String(Adapter^.AdapterName);
  1418. TIdStackLocalAddressAccess(LAddress).FInterfaceName := String(Adapter^.AdapterName);
  1419. TIdStackLocalAddressAccess(LAddress).FInterfaceIndex := Adapter^.Index;
  1420. end;
  1421. IPAddr := IPAddr^.Next;
  1422. until IPAddr = nil;
  1423. Adapter := Adapter^.Next;
  1424. until Adapter = nil;
  1425. finally
  1426. AAddresses.EndUpdate;
  1427. end;
  1428. finally
  1429. UniDirAddresses.Free;
  1430. end;
  1431. end;
  1432. finally
  1433. FreeMem(Adapters);
  1434. end;
  1435. end;
  1436. {$ELSE}
  1437. procedure GetLocalAddressesByHostName;
  1438. var
  1439. {$IFDEF UNICODE}
  1440. Hints: TAddrInfoW;
  1441. LAddrList, LAddrInfo: pAddrInfoW;
  1442. {$ELSE}
  1443. Hints: TAddrInfo;
  1444. LAddrList, LAddrInfo: pAddrInfo;
  1445. {$ENDIF}
  1446. RetVal: Integer;
  1447. LHostName: String;
  1448. {$IFDEF STRING_UNICODE_MISMATCH}
  1449. LTemp: TIdPlatformString;
  1450. {$ENDIF}
  1451. //LAddress: TIdStackLocalAddress;
  1452. begin
  1453. LHostName := HostName;
  1454. ZeroMemory(@Hints, SIZE_TADDRINFO);
  1455. Hints.ai_family := PF_UNSPEC; // returns both IPv4 and IPv6 addresses
  1456. Hints.ai_socktype := SOCK_STREAM;
  1457. LAddrList := nil;
  1458. {$IFDEF STRING_UNICODE_MISMATCH}
  1459. LTemp := TIdPlatformString(LHostName); // explicit convert to Ansi/Unicode
  1460. {$ENDIF}
  1461. RetVal := getaddrinfo(
  1462. {$IFDEF STRING_UNICODE_MISMATCH}PIdPlatformChar(LTemp){$ELSE}PChar(LHostName){$ENDIF},
  1463. nil, @Hints, @LAddrList);
  1464. if RetVal <> 0 then begin
  1465. RaiseSocketError(gaiErrorToWsaError(RetVal));
  1466. end;
  1467. try
  1468. AAddresses.BeginUpdate;
  1469. try
  1470. LAddrInfo := LAddrList;
  1471. repeat
  1472. //LAddress := nil;
  1473. case LAddrInfo^.ai_addr^.sa_family of
  1474. AF_INET: begin
  1475. {LAddress :=} TIdStackLocalAddressIPv4.Create(AAddresses,
  1476. TranslateTInAddrToString(PSockAddrIn(LAddrInfo^.ai_addr)^.sin_addr, Id_IPv4),
  1477. ''); // TODO: SubNet
  1478. end;
  1479. AF_INET6: begin
  1480. {LAddress :=} TIdStackLocalAddressIPv6.Create(AAddresses,
  1481. TranslateTInAddrToString(PSockAddrIn6(LAddrInfo^.ai_addr)^.sin6_addr, Id_IPv6));
  1482. end;
  1483. end;
  1484. // TODO: implement this...
  1485. {
  1486. if LAddress <> nil then begin
  1487. TIdStackLocalAddressAccess(LAddress).FDescription := ?;
  1488. TIdStackLocalAddressAccess(LAddress).FFriendlyName := ?;
  1489. TIdStackLocalAddressAccess(LAddress).FInterfaceName := ?;
  1490. TIdStackLocalAddressAccess(LAddress).FInterfaceIndex := ?;
  1491. end;
  1492. }
  1493. LAddrInfo := LAddrInfo^.ai_next;
  1494. until LAddrInfo = nil;
  1495. finally
  1496. AAddresses.EndUpdate;
  1497. end;
  1498. finally
  1499. freeaddrinfo(LAddrList);
  1500. end;
  1501. end;
  1502. {$ENDIF}
  1503. begin
  1504. // Using gethostname() and (gethostbyname|getaddrinfo)() may not always return
  1505. // just the machine's IP addresses. Technically speaking, they will return
  1506. // the local hostname, and then return the address(es) to which that hostname
  1507. // resolves. It is possible for a machine to (a) be configured such that its
  1508. // name does not resolve to an IP, or (b) be configured such that its name
  1509. // resolves to multiple IPs, only one of which belongs to the local machine.
  1510. // For better results, we should use the Win32 API GetAdaptersInfo() and/or
  1511. // GetAdaptersAddresses() functions instead. GetAdaptersInfo() only supports
  1512. // IPv4, but GetAdaptersAddresses() supports both IPv4 and IPv6...
  1513. {$IFDEF USE_IPHLPAPI}
  1514. // try GetAdaptersAddresses() first, then fall back to GetAdaptersInfo()...
  1515. if not GetLocalAddressesByAdaptersAddresses then begin
  1516. GetLocalAddressesByAdaptersInfo;
  1517. end;
  1518. {$ELSE}
  1519. GetLocalAddressesByHostName;
  1520. {$ENDIF}
  1521. end;
  1522. { TIdStackVersionWinsock }
  1523. function TIdStackWindows.WSShutdown(ASocket: TIdStackSocketHandle; AHow: Integer): Integer;
  1524. begin
  1525. Result := Shutdown(ASocket, AHow);
  1526. end;
  1527. procedure TIdStackWindows.GetSocketName(ASocket: TIdStackSocketHandle;
  1528. var VIP: string; var VPort: TIdPort; var VIPVersion: TIdIPVersion);
  1529. var
  1530. LSize: Integer;
  1531. LAddr: SOCKADDR_STORAGE;
  1532. begin
  1533. LSize := SizeOf(LAddr);
  1534. CheckForSocketError(getsockname(ASocket, IdWinsock2.PSOCKADDR(@LAddr), LSize));
  1535. case LAddr.ss_family of
  1536. Id_PF_INET4: begin
  1537. VIP := TranslateTInAddrToString(PSockAddrIn(@LAddr)^.sin_addr, Id_IPv4);
  1538. VPort := ntohs(PSockAddrIn(@LAddr)^.sin_port);
  1539. VIPVersion := Id_IPv4;
  1540. end;
  1541. Id_PF_INET6: begin
  1542. VIP := TranslateTInAddrToString(PSockAddrIn6(@LAddr)^.sin6_addr, Id_IPv6);
  1543. VPort := Ntohs(PSockAddrIn6(@LAddr)^.sin6_port);
  1544. VIPVersion := Id_IPv6;
  1545. end;
  1546. else begin
  1547. IPVersionUnsupported;
  1548. end;
  1549. end;
  1550. end;
  1551. { TIdSocketListWindows }
  1552. procedure TIdSocketListWindows.Add(AHandle: TIdStackSocketHandle);
  1553. begin
  1554. Lock;
  1555. try
  1556. // TODO: on Windows, the number of sockets that select() can query is limited only
  1557. // by available memory, unlike other platforms which are limited to querying sockets
  1558. // whose descriptors are less than FD_SETSIZE (1024). However, the Winsock SDK does
  1559. // define FD_SETSIZE for compatibilty with other platforms, but it is a meesely 64
  1560. // by default, and the IdWinSock2 unit does use FD_SETSIZE in its definition of
  1561. // TFDSet. C/C++ programs can freely override the value of FD_SETSIZE at compile-time,
  1562. // but that is not an option for Pascal programs. So, we need to find a way to make
  1563. // this more dynamic/configurable. For instance, by having this class hold a dynamic
  1564. // byte array that is casted to PFDSet when needed...
  1565. if not fd_isset(AHandle, FFDSet) then begin
  1566. if FFDSet.fd_count >= u_int(Length(FFDSet.fd_array)){FD_SETSIZE} then begin
  1567. raise EIdStackSetSizeExceeded.Create(RSSetSizeExceeded);
  1568. end;
  1569. FFDSet.fd_array[FFDSet.fd_count] := AHandle;
  1570. Inc(FFDSet.fd_count);
  1571. end;
  1572. finally
  1573. Unlock;
  1574. end;
  1575. end;
  1576. procedure TIdSocketListWindows.Clear;
  1577. begin
  1578. Lock;
  1579. try
  1580. fd_zero(FFDSet);
  1581. finally
  1582. Unlock;
  1583. end;
  1584. end;
  1585. function TIdSocketListWindows.ContainsSocket(AHandle: TIdStackSocketHandle): Boolean;
  1586. begin
  1587. Lock;
  1588. try
  1589. Result := fd_isset(AHandle, FFDSet);
  1590. finally
  1591. Unlock;
  1592. end;
  1593. end;
  1594. function TIdSocketListWindows.Count: Integer;
  1595. begin
  1596. Lock;
  1597. try
  1598. Result := FFDSet.fd_count;
  1599. finally
  1600. Unlock;
  1601. end;
  1602. end;
  1603. function TIdSocketListWindows.GetItem(AIndex: Integer): TIdStackSocketHandle;
  1604. begin
  1605. // keep the compiler happy (when was this fixed exactly?)
  1606. {$IFDEF DCC}{$IFNDEF VCL_8_OR_ABOVE}
  1607. Result := INVALID_SOCKET;
  1608. {$ENDIF}{$ENDIF}
  1609. Lock;
  1610. try
  1611. //We can't redefine AIndex to be a UInt32 because the libc Interface
  1612. //and DotNET define it as a LongInt. OS/2 defines it as a UInt16.
  1613. if (AIndex < 0) or (u_int(AIndex) >= FFDSet.fd_count) then begin
  1614. // TODO: just return 0/invalid, like most of the other Stack classes do?
  1615. raise EIdStackSetSizeExceeded.Create(RSSetSizeExceeded);
  1616. end;
  1617. Result := FFDSet.fd_array[AIndex];
  1618. finally
  1619. Unlock;
  1620. end;
  1621. end;
  1622. procedure TIdSocketListWindows.Remove(AHandle: TIdStackSocketHandle);
  1623. var
  1624. i: Integer;
  1625. begin
  1626. Lock;
  1627. try
  1628. {
  1629. IMPORTANT!!!
  1630. Sometimes, there may not be a member of the FDSET. If you attempt to "remove"
  1631. an item, the loop would execute once.
  1632. }
  1633. if FFDSet.fd_count > 0 then
  1634. begin
  1635. for i:= 0 to FFDSet.fd_count - 1 do
  1636. begin
  1637. if FFDSet.fd_array[i] = AHandle then
  1638. begin
  1639. Dec(FFDSet.fd_count);
  1640. FFDSet.fd_array[i] := FFDSet.fd_array[FFDSet.fd_count];
  1641. FFDSet.fd_array[FFDSet.fd_count] := 0; //extra purity
  1642. Break;
  1643. end;//if found
  1644. end;
  1645. end;
  1646. finally
  1647. Unlock;
  1648. end;
  1649. end;
  1650. function TIdStackWindows.WSTranslateSocketErrorMsg(const AErr: Integer): string;
  1651. begin
  1652. if AErr = WSAHOST_NOT_FOUND then begin
  1653. Result := IndyFormat(RSStackError, [AErr, RSStackHOST_NOT_FOUND]);
  1654. end else begin
  1655. Result := inherited WSTranslateSocketErrorMsg(AErr);
  1656. end;
  1657. end;
  1658. function TIdSocketListWindows.SelectRead(const ATimeout: Integer): Boolean;
  1659. var
  1660. LSet: TFDSet;
  1661. begin
  1662. // Windows updates this structure on return, so we need to copy it each time we need it
  1663. GetFDSet(LSet);
  1664. Result := FDSelect(@LSet, nil, nil, ATimeout);
  1665. end;
  1666. class function TIdSocketListWindows.FDSelect(AReadSet, AWriteSet,
  1667. AExceptSet: PFDSet; const ATimeout: Integer): Boolean;
  1668. var
  1669. LResult: Integer;
  1670. LTime: TTimeVal;
  1671. LTimePtr: PTimeVal;
  1672. begin
  1673. if ATimeout = IdTimeoutInfinite then begin
  1674. LTimePtr := nil;
  1675. end else begin
  1676. LTime.tv_sec := ATimeout div 1000;
  1677. LTime.tv_usec := (ATimeout mod 1000) * 1000;
  1678. LTimePtr := @LTime;
  1679. end;
  1680. LResult := IdWinsock2.select(0, AReadSet, AWriteSet, AExceptSet, LTimePtr);
  1681. //TODO: Remove this cast
  1682. Result := GStack.CheckForSocketError(LResult) > 0;
  1683. end;
  1684. function TIdSocketListWindows.SelectReadList(var VSocketList: TIdSocketList;
  1685. const ATimeout: Integer): Boolean;
  1686. var
  1687. LSet: TFDSet;
  1688. begin
  1689. // Windows updates this structure on return, so we need to copy it each time we need it
  1690. GetFDSet(LSet);
  1691. Result := FDSelect(@LSet, nil, nil, ATimeout);
  1692. if Result then
  1693. begin
  1694. if VSocketList = nil then begin
  1695. VSocketList := TIdSocketList.CreateSocketList;
  1696. end;
  1697. TIdSocketListWindows(VSocketList).SetFDSet(LSet);
  1698. end;
  1699. end;
  1700. class function TIdSocketListWindows.Select(AReadList, AWriteList,
  1701. AExceptList: TIdSocketList; const ATimeout: Integer): Boolean;
  1702. var
  1703. LReadSet: TFDSet;
  1704. LWriteSet: TFDSet;
  1705. LExceptSet: TFDSet;
  1706. LPReadSet: PFDSet;
  1707. LPWriteSet: PFDSet;
  1708. LPExceptSet: PFDSet;
  1709. procedure ReadSet(AList: TIdSocketList; var ASet: TFDSet; var APSet: PFDSet);
  1710. begin
  1711. if AList <> nil then begin
  1712. TIdSocketListWindows(AList).GetFDSet(ASet);
  1713. APSet := @ASet;
  1714. end else begin
  1715. APSet := nil;
  1716. end;
  1717. end;
  1718. begin
  1719. ReadSet(AReadList, LReadSet, LPReadSet);
  1720. ReadSet(AWriteList, LWriteSet, LPWriteSet);
  1721. ReadSet(AExceptList, LExceptSet, LPExceptSet);
  1722. Result := FDSelect(LPReadSet, LPWriteSet, LPExceptSet, ATimeout);
  1723. if AReadList <> nil then begin
  1724. TIdSocketListWindows(AReadList).SetFDSet(LReadSet);
  1725. end;
  1726. if AWriteList <> nil then begin
  1727. TIdSocketListWindows(AWriteList).SetFDSet(LWriteSet);
  1728. end;
  1729. if AExceptList <> nil then begin
  1730. TIdSocketListWindows(AExceptList).SetFDSet(LExceptSet);
  1731. end;
  1732. end;
  1733. procedure TIdSocketListWindows.SetFDSet(var VSet: TFDSet);
  1734. begin
  1735. Lock;
  1736. try
  1737. FFDSet := VSet;
  1738. finally
  1739. Unlock;
  1740. end;
  1741. end;
  1742. procedure TIdSocketListWindows.GetFDSet(var VSet: TFDSet);
  1743. begin
  1744. Lock;
  1745. try
  1746. VSet := FFDSet;
  1747. finally
  1748. Unlock;
  1749. end;
  1750. end;
  1751. procedure TIdStackWindows.SetBlocking(ASocket: TIdStackSocketHandle;
  1752. const ABlocking: Boolean);
  1753. var
  1754. LValue: UInt32;
  1755. begin
  1756. LValue := UInt32(not ABlocking);
  1757. CheckForSocketError(ioctlsocket(ASocket, FIONBIO, LValue));
  1758. end;
  1759. function TIdSocketListWindows.Clone: TIdSocketList;
  1760. begin
  1761. Result := TIdSocketListWindows.Create;
  1762. try
  1763. Lock;
  1764. try
  1765. TIdSocketListWindows(Result).SetFDSet(FFDSet);
  1766. finally
  1767. Unlock;
  1768. end;
  1769. except
  1770. FreeAndNil(Result);
  1771. raise;
  1772. end;
  1773. end;
  1774. function TIdStackWindows.WouldBlock(const AResult: Integer): Boolean;
  1775. begin
  1776. Result := (AResult = WSAEWOULDBLOCK);
  1777. end;
  1778. function TIdStackWindows.HostByName(const AHostName: string;
  1779. const AIPVersion: TIdIPVersion = ID_DEFAULT_IP_VERSION): string;
  1780. var
  1781. {$IFDEF UNICODE}
  1782. LAddrInfo: pAddrInfoW;
  1783. Hints: TAddrInfoW;
  1784. {$ELSE}
  1785. LAddrInfo: pAddrInfo;
  1786. Hints: TAddrInfo;
  1787. {$ENDIF}
  1788. RetVal: Integer;
  1789. LHostName: String;
  1790. {$IFDEF STRING_UNICODE_MISMATCH}
  1791. LTemp: TIdPlatformString;
  1792. {$ENDIF}
  1793. begin
  1794. if not (AIPVersion in [Id_IPv4, Id_IPv6]) then begin
  1795. IPVersionUnsupported;
  1796. end;
  1797. ZeroMemory(@Hints, SIZE_TADDRINFO);
  1798. Hints.ai_family := IdIPFamily[AIPVersion];
  1799. Hints.ai_socktype := SOCK_STREAM;
  1800. LAddrInfo := nil;
  1801. if UseIDNAPI then begin
  1802. LHostName := IDNToPunnyCode(
  1803. {$IFDEF STRING_IS_UNICODE}
  1804. AHostName
  1805. {$ELSE}
  1806. TIdUnicodeString(AHostName) // explicit convert to Unicode
  1807. {$ENDIF}
  1808. );
  1809. end else begin
  1810. LHostName := AHostName;
  1811. end;
  1812. {$IFDEF STRING_UNICODE_MISMATCH}
  1813. LTemp := TIdPlatformString(LHostName); // explicit convert to Ansi/Unicode
  1814. {$ENDIF}
  1815. RetVal := getaddrinfo(
  1816. {$IFDEF STRING_UNICODE_MISMATCH}PIdPlatformChar(LTemp){$ELSE}PChar(LHostName){$ENDIF},
  1817. nil, @Hints, @LAddrInfo);
  1818. if RetVal <> 0 then begin
  1819. RaiseSocketError(gaiErrorToWsaError(RetVal));
  1820. end;
  1821. try
  1822. if AIPVersion = Id_IPv4 then begin
  1823. Result := TranslateTInAddrToString(PSockAddrIn(LAddrInfo^.ai_addr)^.sin_addr, Id_IPv4)
  1824. end else begin
  1825. Result := TranslateTInAddrToString(PSockAddrIn6(LAddrInfo^.ai_addr)^.sin6_addr, Id_IPv6);
  1826. end;
  1827. finally
  1828. freeaddrinfo(LAddrInfo);
  1829. end;
  1830. end;
  1831. procedure TIdStackWindows.Connect(const ASocket: TIdStackSocketHandle;
  1832. const AIP: string; const APort: TIdPort;
  1833. const AIPVersion: TIdIPVersion = ID_DEFAULT_IP_VERSION);
  1834. var
  1835. LAddr: SOCKADDR_STORAGE;
  1836. LSize: Integer;
  1837. begin
  1838. FillChar(LAddr, SizeOf(LAddr), 0);
  1839. case AIPVersion of
  1840. Id_IPv4: begin
  1841. PSockAddrIn(@LAddr)^.sin_family := Id_PF_INET4;
  1842. TranslateStringToTInAddr(AIP, PSockAddrIn(@LAddr)^.sin_addr, Id_IPv4);
  1843. PSockAddrIn(@LAddr)^.sin_port := htons(APort);
  1844. LSize := SIZE_TSOCKADDRIN;
  1845. end;
  1846. Id_IPv6: begin
  1847. PSockAddrIn6(@LAddr)^.sin6_family := Id_PF_INET6;
  1848. TranslateStringToTInAddr(AIP, PSockAddrIn6(@LAddr)^.sin6_addr, Id_IPv6);
  1849. PSockAddrIn6(@LAddr)^.sin6_port := htons(APort);
  1850. LSize := SIZE_TSOCKADDRIN6;
  1851. end;
  1852. else begin
  1853. LSize := 0; // avoid warning
  1854. IPVersionUnsupported;
  1855. end;
  1856. end;
  1857. CheckForSocketError(IdWinsock2.connect(ASocket, IdWinsock2.PSOCKADDR(@LAddr), LSize));
  1858. end;
  1859. procedure TIdStackWindows.GetPeerName(ASocket: TIdStackSocketHandle;
  1860. var VIP: string; var VPort: TIdPort; var VIPVersion: TIdIPVersion);
  1861. var
  1862. LSize: Integer;
  1863. LAddr: SOCKADDR_STORAGE;
  1864. begin
  1865. LSize := SizeOf(LAddr);
  1866. CheckForSocketError(IdWinsock2.getpeername(ASocket, IdWinsock2.PSOCKADDR(@LAddr), LSize));
  1867. case LAddr.ss_family of
  1868. Id_PF_INET4: begin
  1869. VIP := TranslateTInAddrToString(PSockAddrIn(@LAddr)^.sin_addr, Id_IPv4);
  1870. VPort := ntohs(PSockAddrIn(@LAddr)^.sin_port);
  1871. VIPVersion := Id_IPv4;
  1872. end;
  1873. Id_PF_INET6: begin
  1874. VIP := TranslateTInAddrToString(PSockAddrIn6(@LAddr)^.sin6_addr, Id_IPv6);
  1875. VPort := ntohs(PSockAddrIn6(@LAddr)^.sin6_port);
  1876. VIPVersion := Id_IPv6;
  1877. end;
  1878. else begin
  1879. IPVersionUnsupported;
  1880. end;
  1881. end;
  1882. end;
  1883. procedure TIdStackWindows.Disconnect(ASocket: TIdStackSocketHandle);
  1884. begin
  1885. // Windows uses Id_SD_Send, Linux should use Id_SD_Both
  1886. // RLebeau: why Id_SD_Send and not Id_SD_Both on Windows? What if a blocking read is in progress?
  1887. WSShutdown(ASocket, Id_SD_Send);
  1888. // SO_LINGER is false - socket may take a little while to actually close after this
  1889. WSCloseSocket(ASocket);
  1890. end;
  1891. procedure TIdStackWindows.{$IFDEF VCL_XE3_OR_ABOVE}GetSocketOption{$ELSE}WSGetSocketOption{$ENDIF}
  1892. (ASocket: TIdStackSocketHandle; ALevel: TIdSocketOptionLevel; AOptName: TIdSocketOption;
  1893. var AOptVal; var AOptLen: Integer);
  1894. begin
  1895. CheckForSocketError(
  1896. getsockopt(ASocket, ALevel, AOptName,
  1897. {$IFNDEF HAS_PAnsiChar}
  1898. // TODO: use TPtrWrapper here?
  1899. {PIdAnsiChar}@AOptVal
  1900. {$ELSE}
  1901. PIdAnsiChar(@AOptVal)
  1902. {$ENDIF},
  1903. AOptLen
  1904. )
  1905. );
  1906. end;
  1907. procedure TIdStackWindows.{$IFDEF VCL_XE3_OR_ABOVE}SetSocketOption{$ELSE}WSSetSocketOption{$ENDIF}
  1908. (ASocket: TIdStackSocketHandle; ALevel: TIdSocketOptionLevel; AOptName: TIdSocketOption;
  1909. const AOptVal; const AOptLen: Integer);
  1910. begin
  1911. CheckForSocketError(
  1912. setsockopt(ASocket, ALevel, Aoptname,
  1913. {$IFNDEF HAS_PAnsiChar}
  1914. // TODO: use TPtrWrapper here?
  1915. {PIdAnsiChar}@AOptVal
  1916. {$ELSE}
  1917. PIdAnsiChar(@AOptVal)
  1918. {$ENDIF},
  1919. AOptLen
  1920. )
  1921. );
  1922. end;
  1923. function TIdStackWindows.SupportsIPv4: Boolean;
  1924. var
  1925. LLen : DWORD;
  1926. LPInfo, LPCurPtr: LPWSAPROTOCOL_INFO;
  1927. LCount : Integer;
  1928. i : Integer;
  1929. begin
  1930. // TODO: move this logic into CheckIPVersionSupport() instead...
  1931. // Result := CheckIPVersionSupport(Id_IPv4);
  1932. Result := False;
  1933. LPInfo := nil;
  1934. try
  1935. LLen := 0;
  1936. // Note: WSAEnumProtocols returns -1 when it is just called to get the needed Buffer Size!
  1937. repeat
  1938. LCount := IdWinsock2.WSAEnumProtocols(nil, LPInfo, LLen);
  1939. if LCount = SOCKET_ERROR then
  1940. begin
  1941. if WSAGetLastError() <> WSAENOBUFS then begin
  1942. Exit;
  1943. end;
  1944. ReallocMem(LPInfo, LLen);
  1945. end else begin
  1946. Break;
  1947. end;
  1948. until False;
  1949. if LCount > 0 then
  1950. begin
  1951. LPCurPtr := LPInfo;
  1952. for i := 0 to LCount-1 do
  1953. begin
  1954. if LPCurPtr^.iAddressFamily = AF_INET then
  1955. begin
  1956. Result := True;
  1957. Exit;
  1958. end;
  1959. Inc(LPCurPtr);
  1960. end;
  1961. end;
  1962. finally
  1963. FreeMem(LPInfo);
  1964. end;
  1965. end;
  1966. {
  1967. based on
  1968. http://groups.google.com/groups?q=Winsock2+Delphi+protocol&hl=en&lr=&ie=UTF-8&oe=utf-8&selm=3cebe697_2%40dnews&rnum=9
  1969. }
  1970. function TIdStackWindows.SupportsIPv6: Boolean;
  1971. var
  1972. LLen : DWORD;
  1973. LPInfo, LPCurPtr: LPWSAPROTOCOL_INFO;
  1974. LCount : Integer;
  1975. i : Integer;
  1976. begin
  1977. // TODO: move this logic into CheckIPVersionSupport() instead...
  1978. // Result := CheckIPVersionSupport(Id_IPv6);
  1979. Result := False;
  1980. LPInfo := nil;
  1981. try
  1982. LLen := 0;
  1983. // Note: WSAEnumProtocols returns -1 when it is just called to get the needed Buffer Size!
  1984. repeat
  1985. LCount := IdWinsock2.WSAEnumProtocols(nil, LPInfo, LLen);
  1986. if LCount = SOCKET_ERROR then
  1987. begin
  1988. if WSAGetLastError() <> WSAENOBUFS then begin
  1989. Exit;
  1990. end;
  1991. ReallocMem(LPInfo, LLen);
  1992. end else begin
  1993. Break;
  1994. end;
  1995. until False;
  1996. if LCount > 0 then
  1997. begin
  1998. LPCurPtr := LPInfo;
  1999. for i := 0 to LCount-1 do
  2000. begin
  2001. if LPCurPtr^.iAddressFamily = AF_INET6 then
  2002. begin
  2003. Result := True;
  2004. Exit;
  2005. end;
  2006. Inc(LPCurPtr);
  2007. end;
  2008. end;
  2009. finally
  2010. FreeMem(LPInfo);
  2011. end;
  2012. end;
  2013. function TIdStackWindows.IOControl(const s: TIdStackSocketHandle;
  2014. const cmd: UInt32; var arg: UInt32): Integer;
  2015. begin
  2016. Result := IdWinsock2.ioctlsocket(s, cmd, arg);
  2017. end;
  2018. procedure TIdStackWindows.WSQuerryIPv6Route(ASocket: TIdStackSocketHandle;
  2019. const AIP: String; const APort: TIdPort; var VSource; var VDest);
  2020. var
  2021. Llocalif : TSockAddrIn6;
  2022. LAddr : TSockAddrIn6;
  2023. Bytes : DWORD;
  2024. begin
  2025. //make our LAddrInfo structure
  2026. FillChar(LAddr, SizeOf(LAddr), 0);
  2027. LAddr.sin6_family := AF_INET6;
  2028. TranslateStringToTInAddr(AIP, LAddr.sin6_addr, Id_IPv6);
  2029. Move(LAddr.sin6_addr, VDest, SizeOf(in6_addr));
  2030. LAddr.sin6_port := htons(APort);
  2031. // Find out which local interface for the destination
  2032. // RLebeau: in XE4+, PDWORD is NOT defined as ^DWORD, so we have to use a type-cast!
  2033. CheckForSocketError(WSAIoctl(ASocket, SIO_ROUTING_INTERFACE_QUERY,
  2034. @LAddr, SizeOf(LAddr), @Llocalif, SizeOf(Llocalif), PDWORD(@Bytes), nil, nil));
  2035. Move(Llocalif.sin6_addr, VSource, SizeOf(in6_addr));
  2036. end;
  2037. procedure TIdStackWindows.WriteChecksum(s: TIdStackSocketHandle;
  2038. var VBuffer: TIdBytes; const AOffset: Integer; const AIP: String;
  2039. const APort: TIdPort; const AIPVersion: TIdIPVersion);
  2040. begin
  2041. case AIPVersion of
  2042. Id_IPv4 : CopyTIdUInt16(HostToLittleEndian(CalcCheckSum(VBuffer)), VBuffer, AOffset);
  2043. Id_IPv6 : WriteChecksumIPv6(s, VBuffer, AOffset, AIP, APort);
  2044. else
  2045. IPVersionUnsupported;
  2046. end;
  2047. end;
  2048. procedure TIdStackWindows.WriteChecksumIPv6(s: TIdStackSocketHandle;
  2049. var VBuffer: TIdBytes; const AOffset: Integer; const AIP: String;
  2050. const APort: TIdPort);
  2051. var
  2052. LSource : TIdIn6Addr;
  2053. LDest : TIdIn6Addr;
  2054. LTmp : TIdBytes;
  2055. LIdx : Integer;
  2056. LC : UInt32;
  2057. {
  2058. +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  2059. | |
  2060. + +
  2061. | |
  2062. + Source Address +
  2063. | |
  2064. + +
  2065. | |
  2066. +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  2067. | |
  2068. + +
  2069. | |
  2070. + Destination Address +
  2071. | |
  2072. + +
  2073. | |
  2074. +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  2075. | Upper-Layer Packet Length |
  2076. +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  2077. | zero | Next Header |
  2078. +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  2079. }
  2080. begin
  2081. WSQuerryIPv6Route(s, AIP, APort, LSource, LDest);
  2082. SetLength(LTmp, 40+Length(VBuffer));
  2083. //16
  2084. Move(LSource, LTmp[0], SIZE_TIN6ADDR);
  2085. LIdx := SIZE_TIN6ADDR;
  2086. //32
  2087. Move(LDest, LTmp[LIdx], SIZE_TIN6ADDR);
  2088. Inc(LIdx, SIZE_TIN6ADDR);
  2089. //use a word so you don't wind up using the wrong network byte order function
  2090. LC := UInt32(Length(VBuffer));
  2091. CopyTIdUInt32(HostToNetwork(LC), LTmp, LIdx);
  2092. Inc(LIdx, 4);
  2093. //36
  2094. //zero the next three bytes
  2095. FillChar(LTmp[LIdx], 3, 0);
  2096. Inc(LIdx, 3);
  2097. //next header (protocol type determines it
  2098. LTmp[LIdx] := Id_IPPROTO_ICMPV6; // Id_IPPROTO_ICMP6;
  2099. Inc(LIdx);
  2100. //combine the two
  2101. CopyTIdBytes(VBuffer, 0, LTmp, LIdx, Length(VBuffer));
  2102. //zero out the checksum field
  2103. CopyTIdUInt16(0, LTmp, LIdx+AOffset);
  2104. CopyTIdUInt16(HostToLittleEndian(CalcCheckSum(LTmp)), VBuffer, AOffset);
  2105. end;
  2106. function TIdStackWindows.ReceiveMsg(ASocket: TIdStackSocketHandle; var VBuffer : TIdBytes;
  2107. APkt: TIdPacketInfo): UInt32;
  2108. var
  2109. LIP : String;
  2110. LPort : TIdPort;
  2111. LIPVersion : TIdIPVersion;
  2112. {Windows CE does not have WSARecvMsg}
  2113. {$IFNDEF WINCE}
  2114. LSize: PtrUInt;
  2115. LAddr: TIdBytes;
  2116. PAddr: PSOCKADDR_STORAGE;
  2117. LMsg : TWSAMSG;
  2118. LMsgBuf : TWSABUF;
  2119. LControl : TIdBytes;
  2120. LCurCmsg : LPWSACMSGHDR; //for iterating through the control buffer
  2121. PPktInfo: PInPktInfo;
  2122. PPktInfo6: PIn6PktInfo;
  2123. {$ENDIF}
  2124. begin
  2125. {$IFNDEF WINCE}
  2126. //This runs only on WIndows XP or later
  2127. // XP 5.1 at least, Vista 6.0
  2128. if IndyCheckWindowsVersion(5, 1) then
  2129. begin
  2130. //we call the macro twice because we specified two possible structures.
  2131. //Id_IPV6_HOPLIMIT and Id_IPV6_PKTINFO
  2132. LSize := WSA_CMSG_SPACE(SizeOf(Byte)) + WSA_CMSG_SPACE(SizeOf(IN6_PKTINFO));
  2133. SetLength(LControl, LSize);
  2134. LMsgBuf.len := Length(VBuffer); // Length(VMsgData);
  2135. LMsgBuf.buf := PIdAnsiChar(Pointer(VBuffer)); // @VMsgData[0];
  2136. FillChar(LMsg, SIZE_TWSAMSG, 0);
  2137. LMsg.lpBuffers := @LMsgBuf;
  2138. LMsg.dwBufferCount := 1;
  2139. LMsg.Control.Len := LSize;
  2140. LMsg.Control.buf := PIdAnsiChar(Pointer(LControl));
  2141. // RLebeau: despite that we are not performing an overlapped I/O operation,
  2142. // WSARecvMsg() does not like the SOCKADDR variable being allocated on the
  2143. // stack, at least on my tests with Windows 7. So we will allocate it on
  2144. // the heap instead to keep WinSock happy...
  2145. SetLength(LAddr, SizeOf(SOCKADDR_STORAGE));
  2146. PAddr := PSOCKADDR_STORAGE(@LAddr[0]);
  2147. LMsg.name := IdWinsock2.PSOCKADDR(PAddr);
  2148. LMsg.namelen := Length(LAddr);
  2149. CheckForSocketError(WSARecvMsg(ASocket, @LMsg, Result, nil, nil));
  2150. APkt.Reset;
  2151. case PAddr^.ss_family of
  2152. Id_PF_INET4: begin
  2153. APkt.SourceIP := TranslateTInAddrToString(PSockAddrIn(PAddr)^.sin_addr, Id_IPv4);
  2154. APkt.SourcePort := ntohs(PSockAddrIn(PAddr)^.sin_port);
  2155. APkt.SourceIPVersion := Id_IPv4;
  2156. end;
  2157. Id_PF_INET6: begin
  2158. APkt.SourceIP := TranslateTInAddrToString(PSockAddrIn6(PAddr)^.sin6_addr, Id_IPv6);
  2159. APkt.SourcePort := ntohs(PSockAddrIn6(PAddr)^.sin6_port);
  2160. APkt.SourceIPVersion := Id_IPv6;
  2161. end;
  2162. else begin
  2163. Result := 0; // avoid warning
  2164. IPVersionUnsupported;
  2165. end;
  2166. end;
  2167. LCurCmsg := nil;
  2168. repeat
  2169. LCurCmsg := WSA_CMSG_NXTHDR(@LMsg, LCurCmsg);
  2170. if LCurCmsg = nil then begin
  2171. Break;
  2172. end;
  2173. case LCurCmsg^.cmsg_type of
  2174. IP_PKTINFO : //done this way because IPV6_PKTINF and IP_PKTINFO are both 19
  2175. begin
  2176. case PAddr^.ss_family of
  2177. Id_PF_INET4: begin
  2178. PPktInfo := PInPktInfo(WSA_CMSG_DATA(LCurCmsg));
  2179. APkt.DestIP := TranslateTInAddrToString(PPktInfo^.ipi_addr, Id_IPv4);
  2180. APkt.DestIF := PPktInfo^.ipi_ifindex;
  2181. APkt.DestIPVersion := Id_IPv4;
  2182. end;
  2183. Id_PF_INET6: begin
  2184. PPktInfo6 := PIn6PktInfo(WSA_CMSG_DATA(LCurCmsg));
  2185. APkt.DestIP := TranslateTInAddrToString(PPktInfo6^.ipi6_addr, Id_IPv6);
  2186. APkt.DestIF := PPktInfo6^.ipi6_ifindex;
  2187. APkt.DestIPVersion := Id_IPv6;
  2188. end;
  2189. end;
  2190. end;
  2191. Id_IPV6_HOPLIMIT :
  2192. begin
  2193. APkt.TTL := WSA_CMSG_DATA(LCurCmsg)^;
  2194. end;
  2195. end;
  2196. until False;
  2197. end else
  2198. begin
  2199. {$ENDIF}
  2200. Result := RecvFrom(ASocket, VBuffer, Length(VBuffer), 0, LIP, LPort, LIPVersion);
  2201. APkt.Reset;
  2202. APkt.SourceIP := LIP;
  2203. APkt.SourcePort := LPort;
  2204. APkt.SourceIPVersion := LIPVersion;
  2205. APkt.DestIPVersion := LIPVersion;
  2206. {$IFNDEF WINCE}
  2207. end;
  2208. {$ENDIF}
  2209. end;
  2210. function TIdStackWindows.CheckIPVersionSupport(const AIPVersion: TIdIPVersion): Boolean;
  2211. var
  2212. LTmpSocket: TIdStackSocketHandle;
  2213. begin
  2214. LTmpSocket := WSSocket(IdIPFamily[AIPVersion], Id_SOCK_STREAM, Id_IPPROTO_IP);
  2215. Result := LTmpSocket <> Id_INVALID_SOCKET;
  2216. if Result then begin
  2217. WSCloseSocket(LTmpSocket);
  2218. end;
  2219. end;
  2220. {$IFNDEF WINCE}
  2221. {
  2222. This is somewhat messy but I wanted to do things this way to support Int64
  2223. file sizes.
  2224. }
  2225. function ServeFile(ASocket: TIdStackSocketHandle; const AFileName: string): Int64;
  2226. var
  2227. LFileHandle: THandle;
  2228. LSize: LARGE_INTEGER;
  2229. {$IFDEF STRING_UNICODE_MISMATCH}
  2230. LTemp: TIdPlatformString;
  2231. {$ENDIF}
  2232. begin
  2233. Result := 0;
  2234. {$IFDEF STRING_UNICODE_MISMATCH}
  2235. LTemp := TIdPlatformString(AFileName); // explicit convert to Ansi/Unicode
  2236. {$ENDIF}
  2237. LFileHandle := CreateFile(
  2238. {$IFDEF STRING_UNICODE_MISMATCH}PIdPlatformChar(LTemp){$ELSE}PChar(AFileName){$ENDIF},
  2239. GENERIC_READ, FILE_SHARE_READ, nil, OPEN_EXISTING,
  2240. FILE_ATTRIBUTE_NORMAL or FILE_FLAG_SEQUENTIAL_SCAN, 0);
  2241. if LFileHandle <> INVALID_HANDLE_VALUE then
  2242. begin
  2243. try
  2244. if TransmitFile(ASocket, LFileHandle, 0, 0, nil, nil, 0) then
  2245. begin
  2246. if Assigned(GetFileSizeEx) then
  2247. begin
  2248. if not GetFileSizeEx(LFileHandle, LSize) then begin
  2249. Exit;
  2250. end;
  2251. end else
  2252. begin
  2253. LSize.LowPart := GetFileSize(LFileHandle, @LSize.HighPart);
  2254. if (LSize.LowPart = $FFFFFFFF) and (GetLastError() <> 0) then begin
  2255. Exit;
  2256. end;
  2257. end;
  2258. Result := LSize.QuadPart;
  2259. end;
  2260. finally
  2261. CloseHandle(LFileHandle);
  2262. end;
  2263. end;
  2264. end;
  2265. {$ENDIF}
  2266. procedure TIdStackWindows.SetKeepAliveValues(ASocket: TIdStackSocketHandle;
  2267. const AEnabled: Boolean; const ATimeMS, AInterval: Integer);
  2268. var
  2269. ka: _tcp_keepalive;
  2270. Bytes: DWORD;
  2271. begin
  2272. // TODO: instead of doing an OS version check, always call SIO_KEEPALIVE_VALS
  2273. // when AEnabled is True, and then fallback to SO_KEEPALIVE if WSAIoctl()
  2274. // reports that SIO_KEEPALIVE_VALS is not supported...
  2275. // SIO_KEEPALIVE_VALS is supported on Win2K+ and WinCE 4.x only
  2276. if AEnabled and IndyCheckWindowsVersion({$IFDEF WINCE}4{$ELSE}5{$ENDIF}) then
  2277. begin
  2278. ka.onoff := 1;
  2279. ka.keepalivetime := ATimeMS;
  2280. ka.keepaliveinterval := AInterval;
  2281. // RLebeau: in XE4+, PDWORD is NOT defined as ^DWORD, so we have to use a type-cast!
  2282. WSAIoctl(ASocket, SIO_KEEPALIVE_VALS, @ka, SizeOf(ka), nil, 0, PDWORD(@Bytes), nil, nil);
  2283. end else begin
  2284. SetSocketOption(ASocket, Id_SOL_SOCKET, Id_SO_KEEPALIVE, iif(AEnabled, 1, 0));
  2285. end;
  2286. end;
  2287. initialization
  2288. GStarted := False;
  2289. GSocketListClass := TIdSocketListWindows;
  2290. // Check if we are running under windows NT
  2291. {$IFNDEF WINCE}
  2292. if IndyWindowsPlatform = VER_PLATFORM_WIN32_NT then begin
  2293. GetFileSizeEx := LoadLibFunction(GetModuleHandle('Kernel32.dll'), 'GetFileSizeEx');
  2294. GServeFileProc := ServeFile;
  2295. end;
  2296. {$ENDIF}
  2297. {$IFDEF USE_IPHLPAPI}
  2298. InitializeIPHelperStubs;
  2299. {$ENDIF}
  2300. finalization
  2301. IdWship6.CloseLibrary;
  2302. UninitializeWinSock;
  2303. {$IFDEF USE_IPHLPAPI}
  2304. UninitializeIPHelperAPI;
  2305. {$ENDIF}
  2306. GStarted := False;
  2307. end.