IdStackBSDBase.pas 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620
  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.8 10/26/2004 8:12:30 PM JPMugaas
  18. Now uses TIdStrings and TIdStringList for portability.
  19. Rev 1.7 12/06/2004 15:16:44 CCostelloe
  20. Restructured to remove inconsistencies with derived classes
  21. Rev 1.6 07/06/2004 21:30:48 CCostelloe
  22. Kylix 3 changes
  23. Rev 1.5 5/15/2004 3:32:30 AM DSiders
  24. Corrected case in name of TIdIPAddressRec.
  25. Rev 1.4 4/18/04 10:29:24 PM RLebeau
  26. Added TIdInt64Parts structure
  27. Rev 1.3 2004.04.18 4:41:40 PM czhower
  28. RaiseSocketError
  29. Rev 1.2 2004.03.07 11:45:24 AM czhower
  30. Flushbuffer fix + other minor ones found
  31. Rev 1.1 3/6/2004 5:16:24 PM JPMugaas
  32. Bug 67 fixes. Do not write to const values.
  33. Rev 1.0 2004.02.03 3:14:44 PM czhower
  34. Move and updates
  35. Rev 1.22 2/1/2004 3:28:26 AM JPMugaas
  36. Changed WSGetLocalAddress to GetLocalAddress and moved into IdStack since
  37. that will work the same in the DotNET as elsewhere. This is required to
  38. reenable IPWatch.
  39. Rev 1.21 1/31/2004 1:13:00 PM JPMugaas
  40. Minor stack changes required as DotNET does support getting all IP addresses
  41. just like the other stacks.
  42. Rev 1.20 12/4/2003 3:14:56 PM BGooijen
  43. Added HostByAddress
  44. Rev 1.19 12/31/2003 9:52:00 PM BGooijen
  45. Added IPv6 support
  46. Rev 1.18 10/26/2003 5:04:24 PM BGooijen
  47. UDP Server and Client
  48. Rev 1.17 10/26/2003 09:10:24 AM JPMugaas
  49. Calls necessary for IPMulticasting.
  50. Rev 1.16 10/22/2003 04:41:04 PM JPMugaas
  51. Should compile with some restored functionality. Still not finished.
  52. Rev 1.15 10/21/2003 06:24:24 AM JPMugaas
  53. BSD Stack now have a global variable for refercing by platform specific
  54. things. Removed corresponding var from Windows stack.
  55. Rev 1.14 10/19/2003 5:21:28 PM BGooijen
  56. SetSocketOption
  57. Rev 1.13 2003.10.11 5:51:08 PM czhower
  58. -VCL fixes for servers
  59. -Chain suport for servers (Super core)
  60. -Scheduler upgrades
  61. -Full yarn support
  62. Rev 1.12 10/5/2003 9:55:28 PM BGooijen
  63. TIdTCPServer works on D7 and DotNet now
  64. Rev 1.11 04/10/2003 22:32:02 HHariri
  65. moving of WSNXXX method to IdStack and renaming of the DotNet ones
  66. Rev 1.10 10/2/2003 7:36:28 PM BGooijen
  67. .net
  68. Rev 1.9 2003.10.02 10:16:30 AM czhower
  69. .Net
  70. Rev 1.8 2003.10.01 9:11:22 PM czhower
  71. .Net
  72. Rev 1.7 2003.10.01 5:05:16 PM czhower
  73. .Net
  74. Rev 1.6 2003.10.01 2:30:42 PM czhower
  75. .Net
  76. Rev 1.3 10/1/2003 12:14:16 AM BGooijen
  77. DotNet: removing CheckForSocketError
  78. Rev 1.2 2003.10.01 1:12:38 AM czhower
  79. .Net
  80. Rev 1.1 2003.09.30 1:25:02 PM czhower
  81. Added .inc file.
  82. Rev 1.0 2003.09.30 1:24:20 PM czhower
  83. Initial Checkin
  84. Rev 1.10 2003.09.30 10:36:02 AM czhower
  85. Moved stack creation to IdStack
  86. Added DotNet stack.
  87. Rev 1.9 9/8/2003 02:13:14 PM JPMugaas
  88. SupportsIP6 function added for determining if IPv6 is installed on a system.
  89. Rev 1.8 2003.07.17 4:57:04 PM czhower
  90. Added new exception type so it can be added to debugger list of ignored
  91. exceptions.
  92. Rev 1.7 2003.07.14 11:46:46 PM czhower
  93. IOCP now passes all bubbles.
  94. Rev 1.6 2003.07.14 1:57:24 PM czhower
  95. -First set of IOCP fixes.
  96. -Fixed a threadsafe problem with the stack class.
  97. Rev 1.5 7/1/2003 05:20:38 PM JPMugaas
  98. Minor optimizations. Illiminated some unnecessary string operations.
  99. Rev 1.4 7/1/2003 03:39:54 PM JPMugaas
  100. Started numeric IP function API calls for more efficiency.
  101. Rev 1.3 7/1/2003 12:46:08 AM JPMugaas
  102. Preliminary stack functions taking an IP address numerical structure instead
  103. of a string.
  104. Rev 1.2 5/10/2003 4:02:22 PM BGooijen
  105. Rev 1.1 2003.05.09 10:59:26 PM czhower
  106. Rev 1.0 11/13/2002 08:59:02 AM JPMugaas
  107. }
  108. unit IdStackBSDBase;
  109. interface
  110. {$I IdCompilerDefines.inc}
  111. uses
  112. Classes,
  113. IdException, IdStack, IdStackConsts, IdGlobal;
  114. type
  115. // RLebeau - for use with the HostToNetwork() and NetworkToHost()
  116. // methods under Windows and Linux since the Socket API doesn't
  117. // have native conversion functions for int64 values...
  118. TIdInt64Parts = packed record
  119. case Integer of
  120. 0: (
  121. {$IFDEF ENDIAN_BIG}
  122. HighPart: UInt32;
  123. LowPart: UInt32);
  124. {$ELSE}
  125. LowPart: UInt32;
  126. HighPart: UInt32);
  127. {$ENDIF}
  128. 1: (
  129. QuadPart: Int64);
  130. end;
  131. TIdUInt64Parts = packed record
  132. case Integer of
  133. 0: (
  134. {$IFDEF ENDIAN_BIG}
  135. HighPart: UInt32;
  136. LowPart: UInt32);
  137. {$ELSE}
  138. LowPart: UInt32;
  139. HighPart: UInt32);
  140. {$ENDIF}
  141. 1: (
  142. QuadPart: UInt64);
  143. end;
  144. {
  145. TIdUInt64Words = packed record
  146. case Integer of
  147. 0: (LongWords: array[0..1] of UInt32);
  148. 1: (QuadPart: UInt64);
  149. end;
  150. }
  151. TIdIPv6AddressRec = packed array[0..7] of UInt16;
  152. TIdIPAddressRec = packed record
  153. IPVer: TIdIPVersion;
  154. case Integer of
  155. 0: (IPv4, Junk1, Junk2, Junk3: UInt32);
  156. 2: (IPv6 : TIdIPv6AddressRec);
  157. end;
  158. //procedure EmptyIPRec(var VIP : TIdIPAddress);
  159. TIdSunB = packed record
  160. s_b1, s_b2, s_b3, s_b4: UInt8;
  161. end;
  162. TIdSunW = packed record
  163. s_w1, s_w2: UInt16;
  164. end;
  165. PIdIn4Addr = ^TIdIn4Addr;
  166. TIdIn4Addr = packed record
  167. case integer of
  168. 0: (S_un_b: TIdSunB);
  169. 1: (S_un_w: TIdSunW);
  170. 2: (S_addr: UInt32);
  171. end;
  172. PIdIn6Addr = ^TIdIn6Addr;
  173. TIdIn6Addr = packed record
  174. case Integer of
  175. 0: (s6_addr: packed array [0..16-1] of UInt8);
  176. 1: (s6_addr16: packed array [0..8-1] of UInt16);
  177. end;
  178. (*$HPPEMIT '#ifdef s6_addr'*)
  179. (*$HPPEMIT ' #undef s6_addr'*)
  180. (*$HPPEMIT '#endif'*)
  181. (*$HPPEMIT '#ifdef s6_addr16'*)
  182. (*$HPPEMIT ' #undef s6_addr16'*)
  183. (*$HPPEMIT '#endif'*)
  184. PIdInAddr = ^TIdInAddr;
  185. TIdInAddr = {$IFDEF IPv6} TIdIn6Addr; {$ELSE} TIdIn4Addr; {$ENDIF}
  186. //Do not change these structures or insist on objects
  187. //because these are parameters to IP_ADD_MEMBERSHIP and IP_DROP_MEMBERSHIP
  188. TIdIPMreq = packed record
  189. IMRMultiAddr : TIdIn4Addr; // IP multicast address of group */
  190. IMRInterface : TIdIn4Addr; // local IP address of interface */
  191. end;
  192. TIdIPv6Mreq = packed record
  193. ipv6mr_multiaddr : TIdIn6Addr; //IPv6 multicast addr
  194. ipv6mr_interface : UInt32; //interface index
  195. end;
  196. TIdStackBSDBase = class(TIdStack)
  197. protected
  198. function WSCloseSocket(ASocket: TIdStackSocketHandle): Integer; virtual; abstract;
  199. function WSRecv(ASocket: TIdStackSocketHandle; var ABuffer;
  200. const ABufferLength, AFlags: Integer): Integer; virtual; abstract;
  201. function WSSend(ASocket: TIdStackSocketHandle; const ABuffer;
  202. const ABufferLength, AFlags: Integer): Integer; virtual; abstract;
  203. function WSShutdown(ASocket: TIdStackSocketHandle; AHow: Integer): Integer;
  204. virtual; abstract;
  205. {$IFNDEF DCC_XE3_OR_ABOVE}
  206. procedure WSGetSocketOption(ASocket: TIdStackSocketHandle; ALevel: TIdSocketOptionLevel;
  207. AOptName: TIdSocketOption; var AOptVal; var AOptLen: Integer); virtual; abstract;
  208. procedure WSSetSocketOption(ASocket: TIdStackSocketHandle; ALevel: TIdSocketOptionLevel;
  209. AOptName: TIdSocketOption; const AOptVal; const AOptLen: Integer); virtual; abstract;
  210. {$ENDIF}
  211. //internal for multicast membership stuff
  212. procedure MembershipSockOpt(AHandle: TIdStackSocketHandle;
  213. const AGroupIP, ALocalIP : String; const ASockOpt : Integer;
  214. const AIPVersion: TIdIPVersion = ID_DEFAULT_IP_VERSION);
  215. public
  216. constructor Create; override;
  217. function CheckIPVersionSupport(const AIPVersion: TIdIPVersion): boolean; virtual; abstract;
  218. function Receive(ASocket: TIdStackSocketHandle; var VBuffer: TIdBytes): Integer; override;
  219. function Send(ASocket: TIdStackSocketHandle; const ABuffer: TIdBytes;
  220. const AOffset: Integer = 0; const ASize: Integer = -1): Integer; override;
  221. function ReceiveFrom(ASocket: TIdStackSocketHandle; var VBuffer: TIdBytes;
  222. var VIP: string; var VPort: TIdPort; var VIPVersion: TIdIPVersion): Integer; override;
  223. function SendTo(ASocket: TIdStackSocketHandle; const ABuffer: TIdBytes;
  224. const AOffset: Integer; const ASize: Integer; const AIP: string;
  225. const APort: TIdPort; const AIPVersion: TIdIPVersion = ID_DEFAULT_IP_VERSION): Integer; override;
  226. procedure GetSocketOption(ASocket: TIdStackSocketHandle; ALevel: TIdSocketOptionLevel;
  227. AOptName: TIdSocketOption; out AOptVal: Integer); overload; override;
  228. procedure GetSocketOption(ASocket: TIdStackSocketHandle; ALevel: TIdSocketOptionLevel;
  229. AOptName: TIdSocketOption; var AOptVal; var AOptLen: Integer); {$IFDEF DCC_XE3_OR_ABOVE}overload; virtual; abstract;{$ELSE}reintroduce; overload;{$ENDIF}
  230. procedure SetSocketOption(ASocket: TIdStackSocketHandle; ALevel: TIdSocketOptionLevel;
  231. AOptName: TIdSocketOption; AOptVal: Integer); overload; override;
  232. procedure SetSocketOption(ASocket: TIdStackSocketHandle; ALevel: TIdSocketOptionLevel;
  233. AOptName: TIdSocketOption; const AOptVal; const AOptLen: Integer); {$IFDEF DCC_XE3_OR_ABOVE}overload; virtual; abstract;{$ELSE}reintroduce; overload;{$ENDIF}
  234. function TranslateTInAddrToString(var AInAddr; const AIPVersion: TIdIPVersion): string;
  235. procedure TranslateStringToTInAddr(const AIP: string; var AInAddr; const AIPVersion: TIdIPVersion);
  236. function WSGetServByName(const AServiceName: string): TIdPort; virtual; abstract;
  237. procedure AddServByPortToList(const APortNumber: TIdPort; AAddresses: TStrings); virtual; abstract;
  238. function RecvFrom(const ASocket: TIdStackSocketHandle; var ABuffer;
  239. const ALength, AFlags: Integer; var VIP: string; var VPort: TIdPort;
  240. var VIPVersion: TIdIPVersion): Integer; virtual; abstract;
  241. procedure WSSendTo(ASocket: TIdStackSocketHandle; const ABuffer;
  242. const ABufferLength, AFlags: Integer; const AIP: string; const APort: TIdPort;
  243. AIPVersion: TIdIPVersion = ID_DEFAULT_IP_VERSION); virtual; abstract;
  244. function WSSocket(AFamily : Integer; AStruct : TIdSocketType; AProtocol: Integer;
  245. const ANonBlocking: Boolean = False): TIdStackSocketHandle; virtual; abstract;
  246. procedure SetBlocking(ASocket: TIdStackSocketHandle;
  247. const ABlocking: Boolean); virtual; abstract;
  248. function WouldBlock(const AResult: Integer): Boolean; virtual; abstract;
  249. function NewSocketHandle(const ASocketType: TIdSocketType;
  250. const AProtocol: TIdSocketProtocol;
  251. const AIPVersion: TIdIPVersion = ID_DEFAULT_IP_VERSION;
  252. const ANonBlocking: Boolean = False)
  253. : TIdStackSocketHandle; override;
  254. //multicast stuff Kudzu permitted me to add here.
  255. procedure SetMulticastTTL(AHandle: TIdStackSocketHandle;
  256. const AValue : Byte; const AIPVersion: TIdIPVersion = ID_DEFAULT_IP_VERSION); override;
  257. procedure SetLoopBack(AHandle: TIdStackSocketHandle; const AValue: Boolean;
  258. const AIPVersion: TIdIPVersion = ID_DEFAULT_IP_VERSION); override;
  259. procedure DropMulticastMembership(AHandle: TIdStackSocketHandle;
  260. const AGroupIP, ALocalIP : String;
  261. const AIPVersion: TIdIPVersion = ID_DEFAULT_IP_VERSION); override;
  262. procedure AddMulticastMembership(AHandle: TIdStackSocketHandle;
  263. const AGroupIP, ALocalIP : String;
  264. const AIPVersion: TIdIPVersion = ID_DEFAULT_IP_VERSION); override;
  265. end;
  266. EIdInvalidServiceName = class(EIdException);
  267. EIdStackInitializationFailed = class (EIdStackError);
  268. EIdStackSetSizeExceeded = class (EIdStackError);
  269. //for some reason, if GDBSDStack is in the same block as GServeFileProc then
  270. //FPC gives a type declaration error.
  271. var
  272. GBSDStack: TIdStackBSDBase = nil;
  273. const
  274. IdIPFamily : array[TIdIPVersion] of Integer = (Id_PF_INET4, Id_PF_INET6);
  275. implementation
  276. uses
  277. //done this way so we can have a separate stack for the Unix systems in FPC
  278. {$IF DEFINED(WINDOWS)}
  279. IdStackWindows,
  280. {$ELSEIF DEFINED(USE_VCL_POSIX)}
  281. IdStackVCLPosix,
  282. {$ELSEIF DEFINED(UNIX)}
  283. {$IF DEFINED(KYLIXCOMPAT)}
  284. IdStackLibc,
  285. {$ELSEIF DEFINED(USE_BASEUNIX)}
  286. IdStackUnix,
  287. {$IFEND}
  288. {$IFEND}
  289. SysUtils;
  290. { TIdStackBSDBase }
  291. function TIdStackBSDBase.TranslateTInAddrToString(var AInAddr;
  292. const AIPVersion: TIdIPVersion): string;
  293. var
  294. i: Integer;
  295. begin
  296. case AIPVersion of
  297. Id_IPv4: begin
  298. // TODO: use RtlIpv4AddressToString() on Windows when available...
  299. Result := IntToStr(TIdIn4Addr(AInAddr).S_un_b.s_b1) + '.' {Do not Localize}
  300. + IntToStr(TIdIn4Addr(AInAddr).S_un_b.s_b2) + '.' {Do not Localize}
  301. + IntToStr(TIdIn4Addr(AInAddr).S_un_b.s_b3) + '.' {Do not Localize}
  302. + IntToStr(TIdIn4Addr(AInAddr).S_un_b.s_b4);
  303. end;
  304. Id_IPv6: begin
  305. // TODO: use RtlIpv6AddressToString() on Windows when available...
  306. Result := '';
  307. for i := 0 to 7 do begin
  308. Result := Result + IntToHex(NetworkToHost(TIdIn6Addr(AInAddr).s6_addr16[i]), 1) + ':';
  309. end;
  310. SetLength(Result, Length(Result)-1);
  311. end;
  312. else begin
  313. IPVersionUnsupported;
  314. end;
  315. end;
  316. end;
  317. procedure TIdStackBSDBase.TranslateStringToTInAddr(const AIP: string;
  318. var AInAddr; const AIPVersion: TIdIPVersion);
  319. var
  320. LIPv4: UInt32;
  321. LIPv6: TIdIPv6Address;
  322. begin
  323. case AIPVersion of
  324. Id_IPv4: begin
  325. // TODO: use RtlIpv4StringToAddress() on Windows when available...
  326. //TIdIn4Addr(AInAddr).S_addr := HostToNetwork(IPv4ToUInt32(AIP));
  327. LIPv4 := IPv4ToUInt32(AIP);
  328. TIdIn4Addr(AInAddr).S_un_b.s_b1 := ((LIPv4 shr 24) and $FF);
  329. TIdIn4Addr(AInAddr).S_un_b.s_b2 := ((LIPv4 shr 16) and $FF);
  330. TIdIn4Addr(AInAddr).S_un_b.s_b3 := ((LIPv4 shr 8) and $FF);
  331. TIdIn4Addr(AInAddr).S_un_b.s_b4 := ( LIPv4 and $FF);
  332. end;
  333. Id_IPv6: begin
  334. // TODO: use RtlIpv6StringToAddress() on Windows when available...
  335. IPv6ToIdIPv6Address(AIP, LIPv6);
  336. TIdIPv6Address(TIdIn6Addr(AInAddr).s6_addr16) := HostToNetwork(LIPv6);
  337. end;
  338. else begin
  339. IPVersionUnsupported;
  340. end;
  341. end;
  342. end;
  343. function TIdStackBSDBase.NewSocketHandle(const ASocketType:TIdSocketType;
  344. const AProtocol: TIdSocketProtocol;
  345. const AIPVersion: TIdIPVersion = ID_DEFAULT_IP_VERSION;
  346. const ANonBlocking: Boolean = False): TIdStackSocketHandle;
  347. begin
  348. // RLebeau 04/17/2008: Don't use CheckForSocketError() here. It expects
  349. // an Integer error code, not a TSocket handle. When WSSocket() fails,
  350. // it returns Id_INVALID_SOCKET. Although that is technically the same
  351. // value as Id_SOCKET_ERROR, passing Id_INVALID_SOCKET to CheckForSocketError()
  352. // causes a range check error to be raised.
  353. Result := WSSocket(IdIPFamily[AIPVersion], ASocketType, AProtocol, ANonBlocking);
  354. if Result = Id_INVALID_SOCKET then begin
  355. RaiseLastSocketError;
  356. end;
  357. end;
  358. constructor TIdStackBSDBase.Create;
  359. begin
  360. inherited Create;
  361. GBSDStack := Self;
  362. end;
  363. function TIdStackBSDBase.Receive(ASocket: TIdStackSocketHandle;
  364. var VBuffer: TIdBytes): Integer;
  365. begin
  366. Result := CheckForSocketError(WSRecv(ASocket, VBuffer[0], Length(VBuffer) , 0));
  367. end;
  368. function TIdStackBSDBase.Send(ASocket: TIdStackSocketHandle; const ABuffer: TIdBytes;
  369. const AOffset: Integer = 0; const ASize: Integer = -1): Integer;
  370. var
  371. Tmp: Byte;
  372. begin
  373. Result := IndyLength(ABuffer, ASize, AOffset);
  374. if Result > 0 then begin
  375. Result := WSSend(ASocket, ABuffer[AOffset], Result, 0);
  376. end else begin
  377. // RLebeau: this is to allow UDP sockets to send 0-length packets.
  378. // Have to use a variable because the Buffer parameter is declared
  379. // as an untyped 'const'...
  380. //
  381. // TODO: check the socket type and only allow this for UDP sockets...
  382. //
  383. Result := WSSend(ASocket, Tmp, 0, 0);
  384. end;
  385. end;
  386. function TIdStackBSDBase.ReceiveFrom(ASocket: TIdStackSocketHandle;
  387. var VBuffer: TIdBytes; var VIP: string; var VPort: TIdPort;
  388. var VIPVersion: TIdIPVersion): Integer;
  389. begin
  390. Result := CheckForSocketError(RecvFrom(ASocket, VBuffer[0], Length(VBuffer),
  391. 0, VIP, VPort, VIPVersion));
  392. end;
  393. function TIdStackBSDBase.SendTo(ASocket: TIdStackSocketHandle;
  394. const ABuffer: TIdBytes; const AOffset: Integer; const ASize: Integer;
  395. const AIP: string; const APort: TIdPort;
  396. const AIPVersion: TIdIPVersion = ID_DEFAULT_IP_VERSION): Integer;
  397. var
  398. Tmp: Byte;
  399. begin
  400. Result := IndyLength(ABuffer, ASize, AOffset);
  401. if Result > 0 then begin
  402. WSSendTo(ASocket, ABuffer[AOffset], Result, 0, AIP, APort, AIPVersion);
  403. end else begin
  404. // RLebeau: this is to allow UDP sockets to send 0-length packets.
  405. // Have to use a variable because the Buffer parameter is declared
  406. // as an untyped 'const'...
  407. //
  408. // TODO: check the socket type and only allow this for UDP sockets...
  409. //
  410. WSSendTo(ASocket, Tmp, 0, 0, AIP, APort, AIPVersion);
  411. end;
  412. end;
  413. procedure TIdStackBSDBase.GetSocketOption(ASocket: TIdStackSocketHandle;
  414. ALevel: TIdSocketOptionLevel; AOptName: TIdSocketOption; out AOptVal: Integer);
  415. var
  416. LBuf, LLen: Integer;
  417. begin
  418. LLen := SizeOf(LBuf);
  419. {$IFDEF DCC_XE3_OR_ABOVE}GetSocketOption{$ELSE}WSGetSocketOption{$ENDIF}(ASocket, ALevel, AOptName, LBuf, LLen);
  420. AOptVal := LBuf;
  421. end;
  422. {$IFNDEF DCC_XE3_OR_ABOVE}
  423. procedure TIdStackBSDBase.GetSocketOption(ASocket: TIdStackSocketHandle;
  424. ALevel: TIdSocketOptionLevel; AOptName: TIdSocketOption; var AOptVal;
  425. var AOptLen: Integer);
  426. begin
  427. WSGetSocketOption(ASocket, ALevel, AOptName, AOptVal, AOptLen);
  428. end;
  429. {$ENDIF}
  430. procedure TIdStackBSDBase.SetSocketOption(ASocket: TIdStackSocketHandle;
  431. ALevel: TIdSocketOptionLevel; AOptName: TIdSocketOption; AOptVal: Integer);
  432. begin
  433. {$IFDEF DCC_XE3_OR_ABOVE}SetSocketOption{$ELSE}WSSetSocketOption{$ENDIF}(ASocket, ALevel, AOptName, AOptVal, SizeOf(AOptVal));
  434. end;
  435. {$IFNDEF DCC_XE3_OR_ABOVE}
  436. procedure TIdStackBSDBase.SetSocketOption(ASocket: TIdStackSocketHandle;
  437. ALevel: TIdSocketOptionLevel; AOptName: TIdSocketOption; const AOptVal;
  438. const AOptLen: Integer);
  439. begin
  440. WSSetSocketOption(ASocket, ALevel, AOptName, AOptVal, AOptLen);
  441. end;
  442. {$ENDIF}
  443. procedure TIdStackBSDBase.DropMulticastMembership(AHandle: TIdStackSocketHandle;
  444. const AGroupIP, ALocalIP : String; const AIPVersion: TIdIPVersion = ID_DEFAULT_IP_VERSION);
  445. begin
  446. MembershipSockOpt(AHandle, AGroupIP, ALocalIP,
  447. iif(AIPVersion = Id_IPv4, Id_IP_DROP_MEMBERSHIP, Id_IPV6_DROP_MEMBERSHIP),
  448. AIPVersion);
  449. end;
  450. procedure TIdStackBSDBase.AddMulticastMembership(AHandle: TIdStackSocketHandle;
  451. const AGroupIP, ALocalIP : String; const AIPVersion: TIdIPVersion = ID_DEFAULT_IP_VERSION);
  452. begin
  453. MembershipSockOpt(AHandle, AGroupIP, ALocalIP,
  454. iif(AIPVersion = Id_IPv4, Id_IP_ADD_MEMBERSHIP, Id_IPV6_ADD_MEMBERSHIP),
  455. AIPVersion);
  456. end;
  457. procedure TIdStackBSDBase.SetMulticastTTL(AHandle: TIdStackSocketHandle;
  458. const AValue: Byte; const AIPVersion: TIdIPVersion = ID_DEFAULT_IP_VERSION);
  459. var
  460. LLevel, LOpt: Integer;
  461. begin
  462. case AIPVersion of
  463. Id_IPv4: begin
  464. LLevel := Id_IPPROTO_IP;
  465. LOpt := Id_IP_MULTICAST_TTL;
  466. end;
  467. id_IPv6: begin
  468. LLevel := Id_IPPROTO_IPv6;
  469. LOpt := Id_IPV6_MULTICAST_HOPS;
  470. end;
  471. else begin
  472. // keep the compiler happy
  473. LLevel := 0;
  474. LOpt := 0;
  475. IPVersionUnsupported;
  476. end;
  477. end;
  478. SetSocketOption(AHandle, LLevel, LOpt, AValue);
  479. end;
  480. procedure TIdStackBSDBase.SetLoopBack(AHandle: TIdStackSocketHandle;
  481. const AValue: Boolean; const AIPVersion: TIdIPVersion = ID_DEFAULT_IP_VERSION);
  482. var
  483. LLevel, LOpt: Integer;
  484. begin
  485. case AIPVersion of
  486. Id_IPv4: begin
  487. LLevel := Id_IPPROTO_IP;
  488. LOpt := Id_IP_MULTICAST_LOOP;
  489. end;
  490. Id_IPv6: begin
  491. LLevel := Id_IPPROTO_IPv6;
  492. LOpt := Id_IPV6_MULTICAST_LOOP;
  493. end;
  494. else begin
  495. // keep the compiler happy
  496. LLevel := 0;
  497. LOpt := 0;
  498. IPVersionUnsupported;
  499. end;
  500. end;
  501. SetSocketOption(AHandle, LLevel, LOpt, Ord(AValue));
  502. end;
  503. procedure TIdStackBSDBase.MembershipSockOpt(AHandle: TIdStackSocketHandle;
  504. const AGroupIP, ALocalIP: String; const ASockOpt: Integer;
  505. const AIPVersion: TIdIPVersion = ID_DEFAULT_IP_VERSION);
  506. var
  507. LIP4: TIdIPMreq;
  508. LIP6: TIdIPv6Mreq;
  509. begin
  510. case AIPVersion of
  511. Id_IPv4: begin
  512. if IsValidIPv4MulticastGroup(AGroupIP) then
  513. begin
  514. TranslateStringToTInAddr(AGroupIP, LIP4.IMRMultiAddr, Id_IPv4);
  515. TranslateStringToTInAddr(ALocalIP, LIP4.IMRInterface, Id_IPv4);
  516. SetSocketOption(AHandle, Id_IPPROTO_IP, ASockOpt, LIP4, SizeOf(LIP4));
  517. end;
  518. end;
  519. Id_IPv6: begin
  520. if IsValidIPv6MulticastGroup(AGroupIP) then
  521. begin
  522. TranslateStringToTInAddr(AGroupIP, LIP6.ipv6mr_multiaddr, Id_IPv6);
  523. //this should be safe meaning any adaptor
  524. //we can't support a localhost address in IPv6 because we can't get that
  525. //and even if you could, you would have to convert it into a network adaptor
  526. //index - Yuk
  527. LIP6.ipv6mr_interface := 0;
  528. SetSocketOption(AHandle, Id_IPPROTO_IPv6, ASockOpt, LIP6, SizeOf(LIP6));
  529. end;
  530. end;
  531. else begin
  532. IPVersionUnsupported;
  533. end;
  534. end;
  535. end;
  536. end.