IdStack.pas 41 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254
  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. }
  13. {
  14. $Log$
  15. }
  16. {
  17. Rev 1.7 1/17/2005 7:25:48 PM JPMugaas
  18. Moved some stack management code here to so that we can reuse it in
  19. non-TIdComponent classes.
  20. Made HostToNetwork and NetworkToHost byte order overload functions for IPv6
  21. addresses.
  22. Rev 1.6 10/26/2004 8:12:30 PM JPMugaas
  23. Now uses TIdStrings and TIdStringList for portability.
  24. Rev 1.5 6/30/2004 12:41:14 PM BGooijen
  25. Added SetStackClass
  26. Rev 1.4 6/11/2004 8:28:50 AM DSiders
  27. Added "Do not Localize" comments.
  28. Rev 1.3 4/18/04 2:45:38 PM RLebeau
  29. Conversion support for Int64 values
  30. Rev 1.2 2004.03.07 11:45:22 AM czhower
  31. Flushbuffer fix + other minor ones found
  32. Rev 1.1 3/6/2004 5:16:20 PM JPMugaas
  33. Bug 67 fixes. Do not write to const values.
  34. Rev 1.0 2004.02.03 3:14:42 PM czhower
  35. Move and updates
  36. Rev 1.39 2/1/2004 6:10:50 PM JPMugaas
  37. GetSockOpt.
  38. Rev 1.38 2/1/2004 3:28:24 AM JPMugaas
  39. Changed WSGetLocalAddress to GetLocalAddress and moved into IdStack since
  40. that will work the same in the DotNET as elsewhere. This is required to
  41. reenable IPWatch.
  42. Rev 1.37 2/1/2004 1:54:56 AM JPMugaas
  43. Missapplied fix. IP 0.0.0.0 should now be accepted.
  44. Rev 1.36 1/31/2004 4:39:12 PM JPMugaas
  45. Removed empty methods.
  46. Rev 1.35 1/31/2004 1:13:04 PM JPMugaas
  47. Minor stack changes required as DotNET does support getting all IP addresses
  48. just like the other stacks.
  49. Rev 1.34 2004.01.22 5:59:10 PM czhower
  50. IdCriticalSection
  51. Rev 1.33 1/18/2004 11:15:52 AM JPMugaas
  52. IsIP was not handling "0" in an IP address. This caused the address
  53. "127.0.0.1" to be treated as a hostname.
  54. Rev 1.32 12/4/2003 3:14:50 PM BGooijen
  55. Added HostByAddress
  56. Rev 1.31 1/3/2004 12:21:44 AM BGooijen
  57. Added function SupportsIPv6
  58. Rev 1.30 12/31/2003 9:54:16 PM BGooijen
  59. Added IPv6 support
  60. Rev 1.29 2003.12.31 3:47:42 PM czhower
  61. Changed to use TextIsSame
  62. Rev 1.28 10/21/2003 9:24:32 PM BGooijen
  63. Started on SendTo, ReceiveFrom
  64. Rev 1.27 10/19/2003 5:21:28 PM BGooijen
  65. SetSocketOption
  66. Rev 1.26 10/15/2003 7:21:02 PM DSiders
  67. Added resource strings in TIdStack.Make.
  68. Rev 1.25 2003.10.11 5:51:02 PM czhower
  69. -VCL fixes for servers
  70. -Chain suport for servers (Super core)
  71. -Scheduler upgrades
  72. -Full yarn support
  73. Rev 1.24 10/5/2003 9:55:30 PM BGooijen
  74. TIdTCPServer works on D7 and DotNet now
  75. Rev 1.23 04/10/2003 22:31:56 HHariri
  76. moving of WSNXXX method to IdStack and renaming of the DotNet ones
  77. Rev 1.22 10/2/2003 7:31:18 PM BGooijen
  78. .net
  79. Rev 1.21 10/2/2003 6:05:16 PM GGrieve
  80. DontNet
  81. Rev 1.20 2003.10.02 10:16:30 AM czhower
  82. .Net
  83. Rev 1.19 2003.10.01 9:11:20 PM czhower
  84. .Net
  85. Rev 1.18 2003.10.01 5:05:16 PM czhower
  86. .Net
  87. Rev 1.17 2003.10.01 2:30:40 PM czhower
  88. .Net
  89. Rev 1.16 2003.10.01 12:30:08 PM czhower
  90. .Net
  91. Rev 1.14 2003.10.01 1:37:36 AM czhower
  92. .Net
  93. Rev 1.12 9/30/2003 7:15:46 PM BGooijen
  94. IdCompilerDefines.inc is included now
  95. Rev 1.11 2003.09.30 1:23:04 PM czhower
  96. Stack split for DotNet
  97. }
  98. unit IdStack;
  99. interface
  100. {$I IdCompilerDefines.inc}
  101. uses
  102. Classes,
  103. IdException, IdStackConsts, IdGlobal, SysUtils;
  104. type
  105. EIdSocketError = class(EIdException)
  106. protected
  107. FLastError: Integer;
  108. public
  109. // Params must be in this order to avoid conflict with CreateHelp
  110. // constructor in CBuilder as CB does not differentiate constructors
  111. // by name as Delphi does
  112. constructor CreateError(const AErr: Integer; const AMsg: string); virtual;
  113. //
  114. property LastError: Integer read FLastError;
  115. end;
  116. { resolving hostnames }
  117. EIdStackError = class (EIdException);
  118. EIdIPVersionUnsupported = class (EIdStackError);
  119. {$IFDEF UNIX}
  120. EIdResolveError = class(EIdSocketError);
  121. EIdReverseResolveError = class(EIdSocketError);
  122. EIdMaliciousPtrRecord = class(EIdReverseResolveError);
  123. {$ELSE}
  124. EIdMaliciousPtrRecord = class(EIdSocketError);
  125. {$ENDIF}
  126. EIdNotASocket = class(EIdSocketError);
  127. // TODO: move this to IdStackVCLPosix...
  128. {$IFDEF USE_VCL_POSIX}
  129. {$IFDEF ANDROID}
  130. EIdAndroidPermissionNeeded = class(EIdSocketError);
  131. EIdInternetPermissionNeeded = class(EIdAndroidPermissionNeeded);
  132. {$ENDIF}
  133. {$ENDIF}
  134. TIdServeFile = function(ASocket: TIdStackSocketHandle; const AFileName: string): Int64;
  135. TIdPacketInfo = class
  136. protected
  137. FSourceIP: String;
  138. FSourcePort : TIdPort;
  139. FSourceIF: UInt32;
  140. FSourceIPVersion: TIdIPVersion;
  141. FDestIP: String;
  142. FDestPort : TIdPort;
  143. FDestIF: UInt32;
  144. FDestIPVersion: TIdIPVersion;
  145. FTTL: Byte;
  146. public
  147. procedure Reset;
  148. property TTL : Byte read FTTL write FTTL;
  149. //The computer that sent it to you
  150. property SourceIP : String read FSourceIP write FSourceIP;
  151. property SourcePort : TIdPort read FSourcePort write FSourcePort;
  152. property SourceIF : UInt32 read FSourceIF write FSourceIF;
  153. property SourceIPVersion : TIdIPVersion read FSourceIPVersion write FSourceIPVersion;
  154. //you, the receiver - this is provided for multihomed machines
  155. property DestIP : String read FDestIP write FDestIP;
  156. property DestPort : TIdPort read FDestPort write FDestPort;
  157. property DestIF : UInt32 read FDestIF write FDestIF;
  158. property DestIPVersion : TIdIPVersion read FDestIPVersion write FDestIPVersion;
  159. end;
  160. TIdSocketListClass = class of TIdSocketList;
  161. // Descend from only TObject. This objects is created a lot and should be fast
  162. // and small
  163. TIdSocketList = class(TObject)
  164. protected
  165. FLock: TIdCriticalSection;
  166. //
  167. function GetItem(AIndex: Integer): TIdStackSocketHandle; virtual; abstract;
  168. public
  169. constructor Create; virtual;
  170. destructor Destroy; override;
  171. procedure Add(AHandle: TIdStackSocketHandle); virtual; abstract;
  172. function Clone: TIdSocketList; virtual; abstract;
  173. function Count: Integer; virtual; abstract;
  174. class function CreateSocketList: TIdSocketList;
  175. property Items[AIndex: Integer]: TIdStackSocketHandle read GetItem; default;
  176. procedure Remove(AHandle: TIdStackSocketHandle); virtual; abstract;
  177. procedure Clear; virtual; abstract;
  178. function ContainsSocket(AHandle: TIdStackSocketHandle): boolean; virtual; abstract;
  179. procedure Lock;
  180. class function Select(AReadList: TIdSocketList; AWriteList: TIdSocketList;
  181. AExceptList: TIdSocketList; const ATimeout: Integer = IdTimeoutInfinite): Boolean; virtual;
  182. function SelectRead(const ATimeout: Integer = IdTimeoutInfinite): Boolean; virtual; abstract;
  183. function SelectReadList(var VSocketList: TIdSocketList; const ATimeout: Integer = IdTimeoutInfinite): Boolean; virtual; abstract;
  184. procedure Unlock;
  185. end;
  186. TIdStackLocalAddress = class(TCollectionItem)
  187. protected
  188. FIPVersion: TIdIPVersion;
  189. FIPAddress: String;
  190. FInterfaceName: String;
  191. FInterfaceIndex: UInt32;
  192. FDescription: String;
  193. FFriendlyName: String;
  194. public
  195. constructor Create(ACollection: TCollection; const AIPVersion: TIdIPVersion; const AIPAddress: string); reintroduce;
  196. property IPVersion: TIdIPVersion read FIPVersion;
  197. property IPAddress: String read FIPAddress;
  198. property InterfaceName: String read FInterfaceName;
  199. property InterfaceIndex: UInt32 read FInterfaceIndex;
  200. property Description: String read FDescription;
  201. property FriendlyName: String read FFriendlyName;
  202. end;
  203. TIdStackLocalAddressIPv4 = class(TIdStackLocalAddress)
  204. protected
  205. FSubNetMask: String;
  206. public
  207. constructor Create(ACollection: TCollection; const AIPAddress, ASubNetMask: string); reintroduce;
  208. property SubNetMask: String read FSubNetMask;
  209. // TODO: add BroadcastIP
  210. end;
  211. TIdStackLocalAddressIPv6 = class(TIdStackLocalAddress)
  212. public
  213. constructor Create(ACollection: TCollection; const AIPAddress: string); reintroduce;
  214. end;
  215. TIdStackLocalAddressList = class(TCollection)
  216. protected
  217. function GetAddress(AIndex: Integer): TIdStackLocalAddress;
  218. public
  219. constructor Create; reintroduce;
  220. function IndexOfIP(const AIP: String): Integer; overload;
  221. function IndexOfIP(const AIP: String; AIPVersion: TIdIPVersion): Integer; overload;
  222. property Addresses[AIndex: Integer]: TIdStackLocalAddress read GetAddress; default;
  223. end;
  224. TIdStack = class(TObject)
  225. protected
  226. FLocalAddresses: TStrings;
  227. //
  228. procedure IPVersionUnsupported; {$IFDEF USE_NORETURN_DECL}noreturn;{$ENDIF}
  229. function HostByName(const AHostName: string;
  230. const AIPVersion: TIdIPVersion = ID_DEFAULT_IP_VERSION): string; virtual; abstract;
  231. function MakeCanonicalIPv6Address(const AAddr: string): string; {$IFDEF HAS_DEPRECATED}deprecated{$IFDEF HAS_DEPRECATED_MSG} 'Use IdGlobal.MakeCanonicalIPv6Address()'{$ENDIF};{$ENDIF}
  232. function ReadHostName: string; virtual; abstract;
  233. function GetLocalAddress: string;
  234. function GetLocalAddresses: TStrings;
  235. public
  236. function Accept(ASocket: TIdStackSocketHandle; var VIP: string; var VPort: TIdPort): TIdStackSocketHandle; overload;
  237. function Accept(ASocket: TIdStackSocketHandle; var VIP: string; var VPort: TIdPort;
  238. var VIPVersion: TIdIPVersion): TIdStackSocketHandle; overload; virtual; abstract;
  239. procedure Bind(ASocket: TIdStackSocketHandle; const AIP: string;
  240. const APort: TIdPort; const AIPVersion: TIdIPVersion = ID_DEFAULT_IP_VERSION ); virtual; abstract;
  241. procedure Connect(const ASocket: TIdStackSocketHandle; const AIP: string;
  242. const APort: TIdPort; const AIPVersion: TIdIPVersion = ID_DEFAULT_IP_VERSION); virtual; abstract;
  243. constructor Create; virtual;
  244. destructor Destroy; override;
  245. procedure Disconnect(ASocket: TIdStackSocketHandle); virtual; abstract;
  246. function IOControl(const s: TIdStackSocketHandle; const cmd: UInt32;
  247. var arg: UInt32): Integer; virtual; abstract;
  248. class procedure IncUsage; //create stack if necessary and inc counter
  249. class procedure DecUsage; //decrement counter and free if it gets to zero
  250. procedure GetPeerName(ASocket: TIdStackSocketHandle; var VIP: string;
  251. var VPort: TIdPort); overload;
  252. procedure GetPeerName(ASocket: TIdStackSocketHandle; var VIP: string;
  253. var VPort: TIdPort; var VIPVersion: TIdIPVersion); overload; virtual; abstract;
  254. procedure GetSocketName(ASocket: TIdStackSocketHandle; var VIP: string;
  255. var VPort: TIdPort); overload;
  256. procedure GetSocketName(ASocket: TIdStackSocketHandle; var VIP: string;
  257. var VPort: TIdPort; var VIPVersion: TIdIPVersion); overload; virtual; abstract;
  258. function HostByAddress(const AAddress: string;
  259. const AIPVersion: TIdIPVersion = ID_DEFAULT_IP_VERSION): string; virtual; abstract;
  260. function HostToNetwork(AValue: UInt16): UInt16; overload; virtual; abstract;
  261. function HostToNetwork(AValue: UInt32): UInt32; overload; virtual; abstract;
  262. function HostToNetwork(AValue: TIdUInt64): TIdUInt64; overload; virtual; abstract;
  263. function HostToNetwork(const AValue: TIdIPv6Address): TIdIPv6Address; overload; virtual;
  264. function IsIP(AIP: string): Boolean;
  265. procedure Listen(ASocket: TIdStackSocketHandle; ABackLog: Integer); virtual; abstract;
  266. function WSGetLastError: Integer; virtual; abstract;
  267. procedure WSSetLastError(const AErr : Integer); virtual; abstract;
  268. function WSTranslateSocketErrorMsg(const AErr: integer): string; virtual;
  269. function CheckForSocketError(const AResult: Integer): Integer; overload;
  270. function CheckForSocketError(const AResult: Integer; const AIgnore: array of Integer): Integer; overload;
  271. procedure RaiseLastSocketError; {$IFDEF USE_NORETURN_DECL}noreturn;{$ENDIF}
  272. procedure RaiseSocketError(AErr: integer); virtual;
  273. function NewSocketHandle(const ASocketType: TIdSocketType; const AProtocol: TIdSocketProtocol;
  274. const AIPVersion: TIdIPVersion = ID_DEFAULT_IP_VERSION; const ANonBlocking: Boolean = False)
  275. : TIdStackSocketHandle; virtual; abstract;
  276. function NetworkToHost(AValue: UInt16): UInt16; overload; virtual; abstract;
  277. function NetworkToHost(AValue: UInt32): UInt32; overload; virtual; abstract;
  278. function NetworkToHost(AValue: TIdUInt64): TIdUInt64; overload; virtual; abstract;
  279. function NetworkToHost(const AValue: TIdIPv6Address): TIdIPv6Address; overload; virtual;
  280. procedure GetSocketOption(ASocket: TIdStackSocketHandle;
  281. ALevel: TIdSocketOptionLevel; AOptName: TIdSocketOption;
  282. out AOptVal: Integer); overload; virtual; abstract;
  283. procedure SetSocketOption(ASocket: TIdStackSocketHandle; ALevel: TIdSocketOptionLevel;
  284. AOptName: TIdSocketOption; AOptVal: Integer); overload; virtual; abstract;
  285. function ResolveHost(const AHost: string;
  286. const AIPVersion: TIdIPVersion = ID_DEFAULT_IP_VERSION): string;
  287. // Result:
  288. // > 0: Number of bytes received
  289. // 0: Connection closed gracefully
  290. // Will raise exceptions in other cases
  291. function Receive(ASocket: TIdStackSocketHandle; var VBuffer: TIdBytes): Integer; virtual; abstract;
  292. function Send(ASocket: TIdStackSocketHandle; const ABuffer: TIdBytes;
  293. const AOffset: Integer = 0; const ASize: Integer = -1): Integer; virtual; abstract;
  294. function ReceiveFrom(ASocket: TIdStackSocketHandle; var VBuffer: TIdBytes;
  295. var VIP: string; var VPort: TIdPort; var VIPVersion: TIdIPVersion): Integer; virtual; abstract;
  296. function SendTo(ASocket: TIdStackSocketHandle; const ABuffer: TIdBytes;
  297. const AOffset: Integer; const AIP: string; const APort: TIdPort;
  298. const AIPVersion: TIdIPVersion = ID_DEFAULT_IP_VERSION): Integer; overload;
  299. function SendTo(ASocket: TIdStackSocketHandle; const ABuffer: TIdBytes;
  300. const AOffset: Integer; const ASize: Integer; const AIP: string;
  301. const APort: TIdPort; const AIPVersion: TIdIPVersion = ID_DEFAULT_IP_VERSION)
  302. : Integer; overload; virtual; abstract;
  303. function ReceiveMsg(ASocket: TIdStackSocketHandle; var VBuffer: TIdBytes;
  304. APkt: TIdPacketInfo): UInt32; virtual; abstract;
  305. function SupportsIPv4: Boolean; virtual; abstract;
  306. function SupportsIPv6: Boolean; virtual; abstract;
  307. //multicast stuff Kudzu permitted me to add here.
  308. function IsValidIPv4MulticastGroup(const Value: string): Boolean;
  309. function IsValidIPv6MulticastGroup(const Value: string): Boolean;
  310. procedure SetKeepAliveValues(ASocket: TIdStackSocketHandle;
  311. const AEnabled: Boolean; const ATimeMS, AInterval: Integer); virtual;
  312. procedure SetMulticastTTL(AHandle: TIdStackSocketHandle;
  313. const AValue : Byte; const AIPVersion: TIdIPVersion = ID_DEFAULT_IP_VERSION); virtual; abstract;
  314. procedure SetLoopBack(AHandle: TIdStackSocketHandle; const AValue: Boolean;
  315. const AIPVersion: TIdIPVersion = ID_DEFAULT_IP_VERSION); virtual; abstract;
  316. procedure DropMulticastMembership(AHandle: TIdStackSocketHandle;
  317. const AGroupIP, ALocalIP : String; const AIPVersion: TIdIPVersion = ID_DEFAULT_IP_VERSION); virtual; abstract;
  318. procedure AddMulticastMembership(AHandle: TIdStackSocketHandle;
  319. const AGroupIP, ALocalIP : String; const AIPVersion: TIdIPVersion = ID_DEFAULT_IP_VERSION); virtual; abstract;
  320. //I know this looks like an odd place to put a function for calculating a
  321. //packet checksum. There is a reason for it though. The reason is that
  322. //you need it for ICMPv6 and in Windows, you do that with some other stuff
  323. //in the stack descendants
  324. function CalcCheckSum(const AData : TIdBytes): UInt16; virtual;
  325. //In Windows, this writes a checksum into a buffer. In Linux, it would probably
  326. //simply have the kernal write the checksum with something like this (RFC 2292):
  327. //
  328. // int offset = 2;
  329. // setsockopt(fd, IPPROTO_IPV6, IPV6_CHECKSUM, &offset, sizeof(offset));
  330. //
  331. // Note that this should be called
  332. //IMMEDIATELY before you do a SendTo because the Local IPv6 address might change
  333. procedure WriteChecksum(s : TIdStackSocketHandle;
  334. var VBuffer : TIdBytes; const AOffset : Integer; const AIP : String;
  335. const APort : TIdPort; const AIPVersion: TIdIPVersion = ID_DEFAULT_IP_VERSION); virtual; abstract;
  336. //
  337. procedure AddLocalAddressesToList(AAddresses: TStrings); {$IFDEF HAS_DEPRECATED}deprecated{$IFDEF HAS_DEPRECATED_MSG} 'use GetLocalAddressList()'{$ENDIF};{$ENDIF}
  338. procedure GetLocalAddressList(AAddresses: TIdStackLocalAddressList); virtual; abstract;
  339. //
  340. // Properties
  341. //
  342. property HostName: string read ReadHostName;
  343. property LocalAddress: string read GetLocalAddress; // {$IFDEF HAS_DEPRECATED}deprecated{$IFDEF HAS_DEPRECATED_MSG} 'use GetLocalAddressList()'{$ENDIF};{$ENDIF}
  344. property LocalAddresses: TStrings read GetLocalAddresses; // {$IFDEF HAS_DEPRECATED}deprecated{$IFDEF HAS_DEPRECATED_MSG} 'use GetLocalAddressList()'{$ENDIF};{$ENDIF}
  345. end;
  346. TIdStackClass = class of TIdStack;
  347. var
  348. GStack: TIdStack = nil;
  349. GServeFileProc: TIdServeFile = nil;
  350. GSocketListClass: TIdSocketListClass;
  351. // Procedures
  352. procedure SetStackClass( AStackClass: TIdStackClass );
  353. // TODO: move this to IdStackVCLPosix...
  354. {$IFDEF USE_VCL_POSIX}
  355. {$IFDEF ANDROID}
  356. function HasAndroidPermission(const Permission: string): Boolean;
  357. {$ENDIF}
  358. {$ENDIF}
  359. implementation
  360. {$O-}
  361. uses
  362. //done this way so we can have a separate stack for FPC under Unix systems
  363. {$IFDEF DOTNET}
  364. IdStackDotNet,
  365. {$ELSE}
  366. {$IFDEF WINDOWS}
  367. {$IFDEF USE_INLINE}
  368. Windows,
  369. {$ENDIF}
  370. IdStackWindows,
  371. {$ELSE}
  372. {$IFDEF USE_VCL_POSIX}
  373. IdStackVCLPosix,
  374. {$ELSE}
  375. {$IFDEF UNIX}
  376. {$IFDEF KYLIXCOMPAT}
  377. IdStackLibc,
  378. {$ELSE}
  379. {$IFDEF USE_BASEUNIX}
  380. IdStackUnix,
  381. {$ENDIF}
  382. {$ENDIF}
  383. {$ENDIF}
  384. {$ENDIF}
  385. {$ENDIF}
  386. {$ENDIF}
  387. // TODO: move this to IdStackVCLPosix...
  388. {$IFDEF USE_VCL_POSIX}
  389. {$IFDEF ANDROID}
  390. {$IFNDEF VCL_XE6_OR_ABOVE}
  391. // StringToJString() is here in XE5
  392. Androidapi.JNI.JavaTypes,
  393. {$ENDIF}
  394. {$IFNDEF VCL_XE7_OR_ABOVE}
  395. // SharedActivityContext() is here in XE5 and XE6
  396. FMX.Helpers.Android,
  397. {$ENDIF}
  398. {$IFDEF VCL_XE6_OR_ABOVE}
  399. {$IFDEF VCL_10_0_OR_ABOVE}
  400. // StringToJString() is inline in Seattle and later, so we need JavaTypes again...
  401. Androidapi.JNI.JavaTypes,
  402. {$ENDIF}
  403. // StringToJString() was moved here in XE6
  404. // SharedActivityContext() was moved here in XE7
  405. // TAndroidHelper was added here in Seattle
  406. Androidapi.Helpers,
  407. {$ENDIF}
  408. Androidapi.JNI.GraphicsContentViewText,
  409. {$ENDIF}
  410. {$ENDIF}
  411. IdResourceStrings;
  412. var
  413. GStackClass: TIdStackClass = nil;
  414. var
  415. {$IFNDEF USE_OBJECT_ARC}
  416. GInstanceCount: UInt32 = 0;
  417. {$ENDIF}
  418. GStackCriticalSection: TIdCriticalSection = nil;
  419. //for IPv4 Multicast address chacking
  420. const
  421. IPv4MCastLo = 224;
  422. IPv4MCastHi = 239;
  423. procedure SetStackClass(AStackClass: TIdStackClass);
  424. begin
  425. GStackClass := AStackClass;
  426. end;
  427. procedure TIdPacketInfo.Reset;
  428. begin
  429. FSourceIP := '';
  430. FSourcePort := 0;
  431. FSourceIF := 0;
  432. FSourceIPVersion := ID_DEFAULT_IP_VERSION;
  433. FDestIP := '';
  434. FDestPort:= 0;
  435. FDestIF := 0;
  436. FDestIPVersion := ID_DEFAULT_IP_VERSION;
  437. FTTL := 0;
  438. end;
  439. { TIdSocketList }
  440. constructor TIdSocketList.Create;
  441. begin
  442. inherited Create;
  443. FLock := TIdCriticalSection.Create;
  444. end;
  445. class function TIdSocketList.CreateSocketList: TIdSocketList;
  446. Begin
  447. Result := GSocketListClass.Create;
  448. End;
  449. destructor TIdSocketList.Destroy;
  450. begin
  451. FreeAndNil(FLock);
  452. inherited Destroy;
  453. end;
  454. procedure TIdSocketList.Lock;
  455. begin
  456. FLock.Acquire;
  457. end;
  458. class function TIdSocketList.Select(AReadList, AWriteList,
  459. AExceptList: TIdSocketList; const ATimeout: Integer): Boolean;
  460. begin
  461. // C++ Builder cannot have abstract class functions thus we need this base
  462. Result := False;
  463. end;
  464. procedure TIdSocketList.Unlock;
  465. begin
  466. FLock.Release;
  467. end;
  468. { EIdSocketError }
  469. constructor EIdSocketError.CreateError(const AErr: Integer; const AMsg: string);
  470. begin
  471. inherited Create(AMsg);
  472. FLastError := AErr;
  473. end;
  474. { TIdStackLocalAddressList }
  475. constructor TIdStackLocalAddress.Create(ACollection: TCollection; const AIPVersion: TIdIPVersion; const AIPAddress: string);
  476. begin
  477. inherited Create(ACollection);
  478. FIPVersion := AIPVersion;
  479. FIPAddress := AIPAddress;
  480. FInterfaceIndex := 0;
  481. end;
  482. constructor TIdStackLocalAddressIPv4.Create(ACollection: TCollection; const AIPAddress, ASubNetMask: string);
  483. begin
  484. inherited Create(ACollection, Id_IPv4, AIPAddress);
  485. FSubNetMask := ASubNetMask;
  486. end;
  487. constructor TIdStackLocalAddressIPv6.Create(ACollection: TCollection; const AIPAddress: string);
  488. begin
  489. inherited Create(ACollection, Id_IPv6, AIPAddress);
  490. end;
  491. constructor TIdStackLocalAddressList.Create;
  492. begin
  493. inherited Create(TIdStackLocalAddress);
  494. end;
  495. function TIdStackLocalAddressList.GetAddress(AIndex: Integer): TIdStackLocalAddress;
  496. begin
  497. Result := TIdStackLocalAddress(inherited Items[AIndex]);
  498. end;
  499. function TIdStackLocalAddressList.IndexOfIP(const AIP: String): Integer;
  500. var
  501. I: Integer;
  502. begin
  503. Result := -1;
  504. for I := 0 to Count-1 do begin
  505. if Addresses[I].IPAddress = AIP then begin
  506. Result := I;
  507. Exit;
  508. end;
  509. end;
  510. end;
  511. function TIdStackLocalAddressList.IndexOfIP(const AIP: String; AIPVersion: TIdIPVersion): Integer;
  512. var
  513. I: Integer;
  514. LAddr: TIdStackLocalAddress;
  515. begin
  516. Result := -1;
  517. for I := 0 to Count-1 do begin
  518. LAddr := Addresses[I];
  519. if (LAddr.IPVersion = AIPVersion) and (LAddr.IPAddress = AIP) then begin
  520. Result := I;
  521. Exit;
  522. end;
  523. end;
  524. end;
  525. { TIdStack }
  526. constructor TIdStack.Create;
  527. begin
  528. // Here for .net
  529. inherited Create;
  530. end;
  531. destructor TIdStack.Destroy;
  532. begin
  533. FreeAndNil(FLocalAddresses);
  534. inherited Destroy;
  535. end;
  536. procedure TIdStack.IPVersionUnsupported;
  537. {$IFDEF USE_NORETURN_IMPL}noreturn;{$ENDIF}
  538. begin
  539. raise EIdIPVersionUnsupported.Create(RSIPVersionUnsupported);
  540. end;
  541. function TIdStack.Accept(ASocket: TIdStackSocketHandle; var VIP: string;
  542. var VPort: TIdPort): TIdStackSocketHandle;
  543. var
  544. LIPVersion: TIdIPVersion;
  545. begin
  546. Result := Accept(ASocket, VIP, VPort, LIPVersion);
  547. end;
  548. procedure TIdStack.GetPeerName(ASocket: TIdStackSocketHandle; var VIP: string;
  549. var VPort: TIdPort);
  550. var
  551. LIPVersion: TIdIPVersion;
  552. begin
  553. GetPeerName(ASocket, VIP, VPort, LIPVersion);
  554. end;
  555. procedure TIdStack.GetSocketName(ASocket: TIdStackSocketHandle; var VIP: string;
  556. var VPort: TIdPort);
  557. var
  558. LIPVersion: TIdIPVersion;
  559. begin
  560. GetSocketName(ASocket, VIP, VPort, LIPVersion);
  561. end;
  562. {$I IdDeprecatedImplBugOff.inc}
  563. procedure TIdStack.AddLocalAddressesToList(AAddresses: TStrings);
  564. {$I IdDeprecatedImplBugOn.inc}
  565. var
  566. LList: TIdStackLocalAddressList;
  567. I: Integer;
  568. begin
  569. LList := TIdStackLocalAddressList.Create;
  570. try
  571. // for backwards compatibility, return only IPv4 addresses
  572. GetLocalAddressList(LList);
  573. if LList.Count > 0 then begin
  574. AAddresses.BeginUpdate;
  575. try
  576. for I := 0 to LList.Count-1 do begin
  577. if LList[I].IPVersion = Id_IPv4 then begin
  578. AAddresses.Add(LList[I].IPAddress);
  579. end;
  580. end;
  581. finally
  582. AAddresses.EndUpdate;
  583. end;
  584. end;
  585. finally
  586. LList.Free;
  587. end;
  588. end;
  589. function TIdStack.GetLocalAddresses: TStrings;
  590. var
  591. LList: TIdStackLocalAddressList;
  592. I: Integer;
  593. begin
  594. if FLocalAddresses = nil then begin
  595. FLocalAddresses := TStringList.Create;
  596. end;
  597. FLocalAddresses.BeginUpdate;
  598. try
  599. FLocalAddresses.Clear;
  600. LList := TIdStackLocalAddressList.Create;
  601. try
  602. // for backwards compatibility, return only IPv4 addresses
  603. GetLocalAddressList(LList);
  604. for I := 0 to LList.Count-1 do begin
  605. if LList[I].IPVersion = Id_IPv4 then begin
  606. FLocalAddresses.Add(LList[I].IPAddress);
  607. end;
  608. end;
  609. finally
  610. LList.Free;
  611. end;
  612. finally
  613. FLocalAddresses.EndUpdate;
  614. end;
  615. Result := FLocalAddresses;
  616. end;
  617. function TIdStack.GetLocalAddress: string;
  618. var
  619. LList: TIdStackLocalAddressList;
  620. I: Integer;
  621. begin
  622. // RLebeau: using a local list instead of the LocalAddresses
  623. // property so this method can be thread-safe...
  624. //
  625. // old code:
  626. // Result := LocalAddresses[0];
  627. Result := '';
  628. LList := TIdStackLocalAddressList.Create;
  629. try
  630. // for backwards compatibility, return only IPv4 addresses
  631. GetLocalAddressList(LList);
  632. for I := 0 to LList.Count-1 do begin
  633. if LList[I].IPVersion = Id_IPv4 then begin
  634. Result := LList[I].IPAddress;
  635. Exit;
  636. end;
  637. end;
  638. finally
  639. LList.Free;
  640. end;
  641. end;
  642. function TIdStack.IsIP(AIP: string): Boolean;
  643. var
  644. i: Integer;
  645. begin
  646. // TODO: support IPv6
  647. //
  648. //Result := Result and ((i > 0) and (i < 256));
  649. //
  650. i := IndyStrToInt(Fetch(AIP, '.'), -1); {Do not Localize}
  651. Result := (i > -1) and (i < 256);
  652. i := IndyStrToInt(Fetch(AIP, '.'), -1); {Do not Localize}
  653. Result := Result and ((i > -1) and (i < 256));
  654. i := IndyStrToInt(Fetch(AIP, '.'), -1); {Do not Localize}
  655. Result := Result and ((i > -1) and (i < 256));
  656. i := IndyStrToInt(Fetch(AIP, '.'), -1); {Do not Localize}
  657. Result := Result and ((i > -1) and (i < 256)) and (AIP = '');
  658. end;
  659. {$I IdDeprecatedImplBugOff.inc}
  660. function TIdStack.MakeCanonicalIPv6Address(const AAddr: string): string;
  661. {$I IdDeprecatedImplBugOn.inc}
  662. begin
  663. Result := IdGlobal.MakeCanonicalIPv6Address(AAddr);
  664. end;
  665. function TIdStack.ResolveHost(const AHost: string;
  666. const AIPVersion: TIdIPVersion = ID_DEFAULT_IP_VERSION): string;
  667. begin
  668. Result := '';
  669. case AIPVersion of
  670. Id_IPv4: begin
  671. // Sometimes 95 forgets who localhost is
  672. if TextIsSame(AHost, 'LOCALHOST') then begin {Do not Localize}
  673. Result := '127.0.0.1'; {Do not Localize}
  674. end else if IsIP(AHost) then begin
  675. Result := AHost;
  676. end else begin
  677. Result := HostByName(AHost, Id_IPv4);
  678. end;
  679. end;
  680. Id_IPv6: begin
  681. if TextIsSame(AHost, 'LOCALHOST') then begin {Do not Localize}
  682. Result := '::1'; {Do not Localize}
  683. end else begin
  684. Result := IdGlobal.MakeCanonicalIPv6Address(AHost);
  685. if Result = '' then begin
  686. Result := HostByName(AHost, Id_IPv6);
  687. end;
  688. end;
  689. end;
  690. else begin
  691. IPVersionUnsupported;
  692. end;
  693. end;
  694. end;
  695. function TIdStack.SendTo(ASocket: TIdStackSocketHandle; const ABuffer: TIdBytes;
  696. const AOffset: Integer; const AIP: string; const APort: TIdPort;
  697. const AIPVersion: TIdIPVersion = ID_DEFAULT_IP_VERSION): Integer;
  698. begin
  699. Result := SendTo(ASocket, ABuffer, AOffset, -1, AIP, APort, AIPVersion);
  700. end;
  701. class procedure TIdStack.DecUsage;
  702. var
  703. // under ARC, increment the lock's reference count before working with it
  704. LLock: TIdCriticalSection;
  705. begin
  706. LLock := GStackCriticalSection;
  707. if not Assigned(LLock) then begin
  708. raise EIdStackError.Create('GStackCriticalSection is nil in TIdStack.DecUsage'); {do not localize}
  709. end;
  710. LLock.Acquire;
  711. try
  712. // This CS will guarantee that during the FreeAndNil nobody
  713. // will try to use or construct GStack
  714. {$IFDEF USE_OBJECT_ARC}
  715. if GStack <> nil then begin
  716. if GStack.__ObjRelease = 0 then begin
  717. Pointer(GStack) := nil;
  718. end;
  719. end;
  720. {$ELSE}
  721. if GInstanceCount > 0 then begin
  722. Dec(GInstanceCount);
  723. if GInstanceCount = 0 then begin
  724. FreeAndNil(GStack);
  725. end;
  726. end;
  727. {$ENDIF}
  728. finally
  729. LLock.Release;
  730. end;
  731. end;
  732. class procedure TIdStack.IncUsage;
  733. var
  734. // under ARC, increment the lock's reference count before working with it
  735. LLock: TIdCriticalSection;
  736. begin
  737. LLock := GStackCriticalSection;
  738. if not Assigned(LLock) then begin
  739. raise EIdStackError.Create('GStackCriticalSection is nil in TIdStack.IncUsage'); {do not localize}
  740. end;
  741. LLock.Acquire;
  742. try
  743. {$IFDEF USE_OBJECT_ARC}
  744. if GStack = nil then begin
  745. if GStackClass = nil then begin
  746. raise EIdStackError.Create(RSStackClassUndefined);
  747. end;
  748. GStack := GStackClass.Create;
  749. end else begin
  750. GStack.__ObjAddRef;
  751. end;
  752. {$ELSE}
  753. if GInstanceCount = 0 then begin
  754. if GStack <> nil then begin
  755. raise EIdStackError.Create(RSStackAlreadyCreated);
  756. end;
  757. if GStackClass = nil then begin
  758. raise EIdStackError.Create(RSStackClassUndefined);
  759. end;
  760. GStack := GStackClass.Create;
  761. end;
  762. Inc(GInstanceCount);
  763. {$ENDIF}
  764. finally
  765. LLock.Release;
  766. end;
  767. end;
  768. function TIdStack.CheckForSocketError(const AResult: Integer): Integer;
  769. begin
  770. if AResult = Integer(Id_SOCKET_ERROR) then begin
  771. RaiseLastSocketError;
  772. end;
  773. Result := AResult;
  774. end;
  775. function TIdStack.CheckForSocketError(const AResult: Integer;
  776. const AIgnore: array of integer): Integer;
  777. var
  778. i: Integer;
  779. LLastError: Integer;
  780. begin
  781. Result := AResult;
  782. if AResult = Integer(Id_SOCKET_ERROR) then begin
  783. LLastError := WSGetLastError;
  784. for i := Low(AIgnore) to High(AIgnore) do begin
  785. if LLastError = AIgnore[i] then begin
  786. Result := LLastError;
  787. Exit;
  788. end;
  789. end;
  790. RaiseSocketError(LLastError);
  791. end;
  792. end;
  793. procedure TIdStack.RaiseLastSocketError;
  794. {$IFDEF USE_NORETURN_IMPL}noreturn;{$ENDIF}
  795. begin
  796. RaiseSocketError(WSGetLastError);
  797. end;
  798. // TODO: move this to IdStackVCLPosix...
  799. {$IFDEF USE_VCL_POSIX}
  800. {$IFDEF ANDROID}
  801. function GetActivityContext: JContext; {$IFDEF USE_INLINE}inline;{$ENDIF}
  802. begin
  803. {$IFDEF HAS_TAndroidHelper}
  804. Result := TAndroidHelper.Context;
  805. {$ELSE}
  806. Result := SharedActivityContext;
  807. {$ENDIF}
  808. end;
  809. function HasAndroidPermission(const Permission: string): Boolean;
  810. begin
  811. Result := GetActivityContext.checkCallingOrSelfPermission(StringToJString(Permission)) = TJPackageManager.JavaClass.PERMISSION_GRANTED;
  812. end;
  813. {$ENDIF}
  814. {$ENDIF}
  815. procedure RaiseIdSocketError(AErr: Integer; const AMsg: string);
  816. {$IFDEF USE_NORETURN}noreturn;{$ENDIF}
  817. begin
  818. (*
  819. RRRRR EEEEEE AAAA DDDDD MM MM EEEEEE !! !! !!
  820. RR RR EE AA AA DD DD MMMM MMMM EE !! !! !!
  821. RRRRR EEEE AAAAAA DD DD MM MMM MM EEEE !! !! !!
  822. RR RR EE AA AA DD DD MM MM EE
  823. RR RR EEEEEE AA AA DDDDD MM MM EEEEEE .. .. ..
  824. Please read the note in the next comment.
  825. *)
  826. if AErr = Id_WSAENOTSOCK then begin
  827. // You can add this to your exception ignore list for easier debugging.
  828. // However please note that sometimes it is a true error. Your program
  829. // will still run correctly, but the debugger will not stop on it if you
  830. // list it in the ignore list. But for most times its fine to put it in
  831. // the ignore list, it only affects your debugging.
  832. raise EIdNotASocket.CreateError(AErr, AMsg);
  833. end;
  834. // TODO: move this to IdStackVCLPosix...
  835. {$IFDEF USE_VCL_POSIX}
  836. {$IFDEF ANDROID}
  837. if (AErr = 9{EBADF}) or (AErr = 12{EBADR?}) or (AErr = 13{EACCES}) then begin
  838. if not HasAndroidPermission('android.permission.INTERNET') then begin {Do not Localize}
  839. raise EIdInternetPermissionNeeded.CreateError(AErr, AMsg);
  840. end;
  841. end;
  842. {$ENDIF}
  843. {$ENDIF}
  844. (*
  845. It is normal to receive a 10038 exception (10038, NOT others!) here when
  846. *shutting down* (NOT at other times!) servers (NOT clients!).
  847. If you receive a 10038 exception here please see the FAQ at:
  848. http://www.IndyProject.org/
  849. If you insist upon requesting help via our email boxes on the 10038 error
  850. that is already answered in the FAQ and you are simply too slothful to
  851. search for your answer and ask your question in the public forums you may be
  852. publicly flogged, tarred and feathered and your name may be added to every
  853. chain letter / EMail in existence today."
  854. Otherwise, if you DID read the FAQ and have further questions, please feel
  855. free to ask using one of the methods (Carefullly note that these methods do
  856. not list email) listed on the Tech Support link at:
  857. http://www.IndyProject.org/
  858. RRRRR EEEEEE AAAA DDDDD MM MM EEEEEE !! !! !!
  859. RR RR EE AA AA DD DD MMMM MMMM EE !! !! !!
  860. RRRRR EEEE AAAAAA DD DD MM MMM MM EEEE !! !! !!
  861. RR RR EE AA AA DD DD MM MM EE
  862. RR RR EEEEEE AA AA DDDDD MM MM EEEEEE .. .. ..
  863. *)
  864. raise EIdSocketError.CreateError(AErr, AMsg);
  865. end;
  866. procedure TIdStack.RaiseSocketError(AErr: integer);
  867. begin
  868. RaiseIdSocketError(AErr, WSTranslateSocketErrorMsg(AErr));
  869. end;
  870. function TIdStack.WSTranslateSocketErrorMsg(const AErr: integer): string;
  871. begin
  872. Result := ''; {Do not Localize}
  873. case AErr of
  874. Id_WSAEINTR: Result := RSStackEINTR;
  875. Id_WSAEBADF: Result := RSStackEBADF;
  876. Id_WSAEACCES: Result := RSStackEACCES;
  877. Id_WSAEFAULT: Result := RSStackEFAULT;
  878. Id_WSAEINVAL: Result := RSStackEINVAL;
  879. Id_WSAEMFILE: Result := RSStackEMFILE;
  880. Id_WSAEWOULDBLOCK: Result := RSStackEWOULDBLOCK;
  881. Id_WSAEINPROGRESS: Result := RSStackEINPROGRESS;
  882. Id_WSAEALREADY: Result := RSStackEALREADY;
  883. Id_WSAENOTSOCK: Result := RSStackENOTSOCK;
  884. Id_WSAEDESTADDRREQ: Result := RSStackEDESTADDRREQ;
  885. Id_WSAEMSGSIZE: Result := RSStackEMSGSIZE;
  886. Id_WSAEPROTOTYPE: Result := RSStackEPROTOTYPE;
  887. Id_WSAENOPROTOOPT: Result := RSStackENOPROTOOPT;
  888. Id_WSAEPROTONOSUPPORT: Result := RSStackEPROTONOSUPPORT;
  889. {$IFNDEF BEOS}
  890. Id_WSAESOCKTNOSUPPORT: Result := RSStackESOCKTNOSUPPORT;
  891. {$ENDIF}
  892. Id_WSAEOPNOTSUPP: Result := RSStackEOPNOTSUPP;
  893. Id_WSAEPFNOSUPPORT: Result := RSStackEPFNOSUPPORT;
  894. Id_WSAEAFNOSUPPORT: Result := RSStackEAFNOSUPPORT;
  895. Id_WSAEADDRINUSE: Result := RSStackEADDRINUSE;
  896. Id_WSAEADDRNOTAVAIL: Result := RSStackEADDRNOTAVAIL;
  897. Id_WSAENETDOWN: Result := RSStackENETDOWN;
  898. Id_WSAENETUNREACH: Result := RSStackENETUNREACH;
  899. Id_WSAENETRESET: Result := RSStackENETRESET;
  900. Id_WSAECONNABORTED: Result := RSStackECONNABORTED;
  901. Id_WSAECONNRESET: Result := RSStackECONNRESET;
  902. Id_WSAENOBUFS: Result := RSStackENOBUFS;
  903. Id_WSAEISCONN: Result := RSStackEISCONN;
  904. Id_WSAENOTCONN: Result := RSStackENOTCONN;
  905. Id_WSAESHUTDOWN: Result := RSStackESHUTDOWN;
  906. {$IFNDEF BEOS}
  907. Id_WSAETOOMANYREFS: Result := RSStackETOOMANYREFS;
  908. {$ENDIF}
  909. Id_WSAETIMEDOUT: Result := RSStackETIMEDOUT;
  910. Id_WSAECONNREFUSED: Result := RSStackECONNREFUSED;
  911. Id_WSAELOOP: Result := RSStackELOOP;
  912. Id_WSAENAMETOOLONG: Result := RSStackENAMETOOLONG;
  913. Id_WSAEHOSTDOWN: Result := RSStackEHOSTDOWN;
  914. Id_WSAEHOSTUNREACH: Result := RSStackEHOSTUNREACH;
  915. Id_WSAENOTEMPTY: Result := RSStackENOTEMPTY;
  916. end;
  917. Result := IndyFormat(RSStackError, [AErr, Result]);
  918. end;
  919. function TIdStack.HostToNetwork(const AValue: TIdIPv6Address): TIdIPv6Address;
  920. var
  921. i : Integer;
  922. begin
  923. for i := 0 to 7 do begin
  924. Result[i] := HostToNetwork(AValue[i]);
  925. end;
  926. end;
  927. function TIdStack.NetworkToHost(const AValue: TIdIPv6Address): TIdIPv6Address;
  928. var
  929. i : Integer;
  930. begin
  931. for i := 0 to 7 do begin
  932. Result[i] := NetworkToHost(AValue[i]);
  933. end;
  934. end;
  935. function TIdStack.IsValidIPv4MulticastGroup(const Value: string): Boolean;
  936. var
  937. LIP: string;
  938. LVal: Integer;
  939. begin
  940. Result := False;
  941. if IsIP(Value) then
  942. begin
  943. LIP := Value;
  944. LVal := IndyStrToInt(Fetch(LIP, '.')); {Do not Localize}
  945. Result := (LVal >= IPv4MCastLo) and (LVal <= IPv4MCastHi);
  946. end;
  947. end;
  948. { From "rfc 2373"
  949. 2.7 Multicast Addresses
  950. An IPv6 multicast address is an identifier for a group of nodes. A
  951. node may belong to any number of multicast groups. Multicast
  952. addresses have the following format:
  953. #
  954. | 8 | 4 | 4 | 112 bits |
  955. +------ -+----+----+---------------------------------------------+
  956. |11111111|flgs|scop| group ID |
  957. +--------+----+----+---------------------------------------------+
  958. 11111111 at the start of the address identifies the address as
  959. being a multicast address.
  960. +-+-+-+-+
  961. flgs is a set of 4 flags: |0|0|0|T|
  962. +-+-+-+-+
  963. The high-order 3 flags are reserved, and must be initialized to
  964. 0.
  965. T = 0 indicates a permanently-assigned ("well-known") multicast
  966. address, assigned by the global internet numbering authority.
  967. T = 1 indicates a non-permanently-assigned ("transient")
  968. multicast address.
  969. scop is a 4-bit multicast scope value used to limit the scope of
  970. the multicast group. The values are:
  971. 0 reserved
  972. 1 node-local scope
  973. 2 link-local scope
  974. 3 (unassigned)
  975. 4 (unassigned)
  976. 5 site-local scope
  977. 6 (unassigned)
  978. 7 (unassigned)
  979. 8 organization-local scope
  980. 9 (unassigned)
  981. A (unassigned)
  982. B (unassigned)
  983. C (unassigned)
  984. D (unassigned)
  985. E global scope
  986. F reserved
  987. group ID identifies the multicast group, either permanent or
  988. transient, within the given scope.
  989. The "meaning" of a permanently-assigned multicast address is
  990. independent of the scope value. For example, if the "NTP servers
  991. group" is assigned a permanent multicast address with a group ID of
  992. 101 (hex), then:
  993. FF01:0:0:0:0:0:0:101 means all NTP servers on the same node as the
  994. sender.
  995. FF02:0:0:0:0:0:0:101 means all NTP servers on the same link as the
  996. sender.
  997. FF05:0:0:0:0:0:0:101 means all NTP servers at the same site as the
  998. sender.
  999. FF0E:0:0:0:0:0:0:101 means all NTP servers in the internet.
  1000. Non-permanently-assigned multicast addresses are meaningful only
  1001. within a given scope. For example, a group identified by the non-
  1002. permanent, site-local multicast address FF15:0:0:0:0:0:0:101 at one
  1003. site bears no relationship to a group using the same address at a
  1004. different site, nor to a non-permanent group using the same group ID
  1005. with different scope, nor to a permanent group with the same group
  1006. ID.
  1007. Multicast addresses must not be used as source addresses in IPv6
  1008. packets or appear in any routing header.
  1009. }
  1010. function TIdStack.IsValidIPv6MulticastGroup(const Value: string): Boolean;
  1011. var
  1012. LTmp : String;
  1013. begin
  1014. LTmp := IdGlobal.MakeCanonicalIPv6Address(Value);
  1015. if LTmp <> '' then
  1016. begin
  1017. Result := TextStartsWith(LTmp, 'FF');
  1018. end else begin
  1019. Result := False;
  1020. end;
  1021. end;
  1022. function TIdStack.CalcCheckSum(const AData: TIdBytes): UInt16;
  1023. var
  1024. i : Integer;
  1025. LSize : Integer;
  1026. LCRC : UInt32;
  1027. begin
  1028. LCRC := 0;
  1029. i := 0;
  1030. LSize := Length(AData);
  1031. while LSize > 1 do
  1032. begin
  1033. LCRC := LCRC + BytesToUInt16(AData, i);
  1034. Dec(LSize, 2);
  1035. Inc(i, 2);
  1036. end;
  1037. if LSize > 0 then begin
  1038. LCRC := LCRC + AData[i];
  1039. end;
  1040. LCRC := (LCRC shr 16) + (LCRC and $ffff); //(LCRC >> 16)
  1041. LCRC := LCRC + (LCRC shr 16);
  1042. Result := not UInt16(LCRC);
  1043. end;
  1044. {$UNDEF HAS_TCP_KEEPIDLE_OR_KEEPINTVL}
  1045. {$IFDEF HAS_TCP_KEEPIDLE}
  1046. {$DEFINE HAS_TCP_KEEPIDLE_OR_KEEPINTVL}
  1047. {$ENDIF}
  1048. {$IFDEF HAS_TCP_KEEPINTVL}
  1049. {$DEFINE HAS_TCP_KEEPIDLE_OR_KEEPINTVL}
  1050. {$ENDIF}
  1051. procedure TIdStack.SetKeepAliveValues(ASocket: TIdStackSocketHandle;
  1052. const AEnabled: Boolean; const ATimeMS, AInterval: Integer);
  1053. begin
  1054. SetSocketOption(ASocket, Id_SOL_SOCKET, Id_SO_KEEPALIVE, iif(AEnabled, 1, 0));
  1055. {$IFDEF HAS_TCP_KEEPIDLE_OR_KEEPINTVL}
  1056. if AEnabled then
  1057. begin
  1058. // TODO: support TCP_KEEPCNT
  1059. {$IFDEF HAS_TCP_KEEPIDLE}
  1060. SetSocketOption(ASocket, Id_SOL_TCP, Id_TCP_KEEPIDLE, ATimeMS div MSecsPerSec);
  1061. {$ENDIF}
  1062. {$IFDEF HAS_TCP_KEEPINTVL}
  1063. SetSocketOption(ASocket, Id_SOL_TCP, Id_TCP_KEEPINTVL, AInterval div MSecsPerSec);
  1064. {$ENDIF}
  1065. end;
  1066. {$ENDIF}
  1067. end;
  1068. initialization
  1069. //done this way so we can have a separate stack just for FPC under Unix systems
  1070. GStackClass :=
  1071. {$IFDEF DOTNET}
  1072. TIdStackDotNet
  1073. {$ELSE}
  1074. {$IFDEF WINDOWS}
  1075. TIdStackWindows
  1076. {$ELSE}
  1077. {$IFDEF USE_VCL_POSIX}
  1078. TIdStackVCLPosix
  1079. {$ELSE}
  1080. {$IFDEF UNIX}
  1081. {$IFDEF KYLIXCOMPAT}
  1082. TIdStackLibc
  1083. {$ELSE}
  1084. {$IFDEF USE_BASEUNIX}
  1085. TIdStackUnix
  1086. {$ENDIF}
  1087. {$ENDIF}
  1088. {$ENDIF}
  1089. {$ENDIF}
  1090. {$ENDIF}
  1091. {$ENDIF}
  1092. ;
  1093. GStackCriticalSection := TIdCriticalSection.Create;
  1094. {$IFNDEF DOTNET}
  1095. {$IFDEF REGISTER_EXPECTED_MEMORY_LEAK}
  1096. IndyRegisterExpectedMemoryLeak(GStackCriticalSection);
  1097. {$ENDIF}
  1098. {$ENDIF}
  1099. finalization
  1100. // Dont Free. If shutdown is from another Init section, it can cause GPF when stack
  1101. // tries to access it. App will kill it off anyways, so just let it leak
  1102. {$IFDEF FREE_ON_FINAL}
  1103. FreeAndNil(GStackCriticalSection);
  1104. {$ENDIF}
  1105. end.