IdStackBSDBase.pas 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639
  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. {$IFDEF DOTNET}
  112. Improper compile.
  113. This unit must NOT be linked into DotNet applications.
  114. {$ENDIF}
  115. uses
  116. Classes,
  117. IdException, IdStack, IdStackConsts, IdGlobal;
  118. type
  119. // RLebeau - for use with the HostToNetwork() and NetworkToHost()
  120. // methods under Windows and Linux since the Socket API doesn't
  121. // have native conversion functions for int64 values...
  122. TIdInt64Parts = packed record
  123. case Integer of
  124. 0: (
  125. {$IFDEF ENDIAN_BIG}
  126. HighPart: UInt32;
  127. LowPart: UInt32);
  128. {$ELSE}
  129. LowPart: UInt32;
  130. HighPart: UInt32);
  131. {$ENDIF}
  132. 1: (
  133. QuadPart: Int64);
  134. end;
  135. TIdUInt64Parts = packed record
  136. case Integer of
  137. 0: (
  138. {$IFDEF ENDIAN_BIG}
  139. HighPart: UInt32;
  140. LowPart: UInt32);
  141. {$ELSE}
  142. LowPart: UInt32;
  143. HighPart: UInt32);
  144. {$ENDIF}
  145. 1: (
  146. QuadPart: UInt64);
  147. end;
  148. TIdIPv6AddressRec = packed array[0..7] of UInt16;
  149. TIdIPAddressRec = packed record
  150. IPVer: TIdIPVersion;
  151. case Integer of
  152. 0: (IPv4, Junk1, Junk2, Junk3: UInt32);
  153. 2: (IPv6 : TIdIPv6AddressRec);
  154. end;
  155. //procedure EmptyIPRec(var VIP : TIdIPAddress);
  156. TIdSunB = packed record
  157. s_b1, s_b2, s_b3, s_b4: UInt8;
  158. end;
  159. TIdSunW = packed record
  160. s_w1, s_w2: UInt16;
  161. end;
  162. PIdIn4Addr = ^TIdIn4Addr;
  163. TIdIn4Addr = packed record
  164. case integer of
  165. 0: (S_un_b: TIdSunB);
  166. 1: (S_un_w: TIdSunW);
  167. 2: (S_addr: UInt32);
  168. end;
  169. PIdIn6Addr = ^TIdIn6Addr;
  170. TIdIn6Addr = packed record
  171. case Integer of
  172. 0: (s6_addr: packed array [0..16-1] of UInt8);
  173. 1: (s6_addr16: packed array [0..8-1] of UInt16);
  174. end;
  175. (*$HPPEMIT '#ifdef s6_addr'*)
  176. (*$HPPEMIT ' #undef s6_addr'*)
  177. (*$HPPEMIT '#endif'*)
  178. (*$HPPEMIT '#ifdef s6_addr16'*)
  179. (*$HPPEMIT ' #undef s6_addr16'*)
  180. (*$HPPEMIT '#endif'*)
  181. PIdInAddr = ^TIdInAddr;
  182. TIdInAddr = {$IFDEF IPv6} TIdIn6Addr; {$ELSE} TIdIn4Addr; {$ENDIF}
  183. //Do not change these structures or insist on objects
  184. //because these are parameters to IP_ADD_MEMBERSHIP and IP_DROP_MEMBERSHIP
  185. TIdIPMreq = packed record
  186. IMRMultiAddr : TIdIn4Addr; // IP multicast address of group */
  187. IMRInterface : TIdIn4Addr; // local IP address of interface */
  188. end;
  189. TIdIPv6Mreq = packed record
  190. ipv6mr_multiaddr : TIdIn6Addr; //IPv6 multicast addr
  191. ipv6mr_interface : UInt32; //interface index
  192. end;
  193. TIdStackBSDBase = class(TIdStack)
  194. protected
  195. function WSCloseSocket(ASocket: TIdStackSocketHandle): Integer; virtual; abstract;
  196. function WSRecv(ASocket: TIdStackSocketHandle; var ABuffer;
  197. const ABufferLength, AFlags: Integer): Integer; virtual; abstract;
  198. function WSSend(ASocket: TIdStackSocketHandle; const ABuffer;
  199. const ABufferLength, AFlags: Integer): Integer; virtual; abstract;
  200. function WSShutdown(ASocket: TIdStackSocketHandle; AHow: Integer): Integer;
  201. virtual; abstract;
  202. {$IFNDEF VCL_XE3_OR_ABOVE}
  203. procedure WSGetSocketOption(ASocket: TIdStackSocketHandle; ALevel: TIdSocketOptionLevel;
  204. AOptName: TIdSocketOption; var AOptVal; var AOptLen: Integer); virtual; abstract;
  205. procedure WSSetSocketOption(ASocket: TIdStackSocketHandle; ALevel: TIdSocketOptionLevel;
  206. AOptName: TIdSocketOption; const AOptVal; const AOptLen: Integer); virtual; abstract;
  207. {$ENDIF}
  208. //internal for multicast membership stuff
  209. procedure MembershipSockOpt(AHandle: TIdStackSocketHandle;
  210. const AGroupIP, ALocalIP : String; const ASockOpt : Integer;
  211. const AIPVersion: TIdIPVersion = ID_DEFAULT_IP_VERSION);
  212. public
  213. constructor Create; override;
  214. function CheckIPVersionSupport(const AIPVersion: TIdIPVersion): boolean; virtual; abstract;
  215. function Receive(ASocket: TIdStackSocketHandle; var VBuffer: TIdBytes): Integer; override;
  216. function Send(ASocket: TIdStackSocketHandle; const ABuffer: TIdBytes;
  217. const AOffset: Integer = 0; const ASize: Integer = -1): Integer; override;
  218. function ReceiveFrom(ASocket: TIdStackSocketHandle; var VBuffer: TIdBytes;
  219. var VIP: string; var VPort: TIdPort; var VIPVersion: TIdIPVersion): Integer; override;
  220. function SendTo(ASocket: TIdStackSocketHandle; const ABuffer: TIdBytes;
  221. const AOffset: Integer; const ASize: Integer; const AIP: string;
  222. const APort: TIdPort; const AIPVersion: TIdIPVersion = ID_DEFAULT_IP_VERSION): Integer; override;
  223. procedure GetSocketOption(ASocket: TIdStackSocketHandle; ALevel: TIdSocketOptionLevel;
  224. AOptName: TIdSocketOption; out AOptVal: Integer); overload; override;
  225. procedure GetSocketOption(ASocket: TIdStackSocketHandle; ALevel: TIdSocketOptionLevel;
  226. AOptName: TIdSocketOption; var AOptVal; var AOptLen: Integer); {$IFDEF VCL_XE3_OR_ABOVE}overload; virtual; abstract;{$ELSE}reintroduce; overload;{$ENDIF}
  227. procedure SetSocketOption(ASocket: TIdStackSocketHandle; ALevel: TIdSocketOptionLevel;
  228. AOptName: TIdSocketOption; AOptVal: Integer); overload; override;
  229. procedure SetSocketOption(ASocket: TIdStackSocketHandle; ALevel: TIdSocketOptionLevel;
  230. AOptName: TIdSocketOption; const AOptVal; const AOptLen: Integer); {$IFDEF VCL_XE3_OR_ABOVE}overload; virtual; abstract;{$ELSE}reintroduce; overload;{$ENDIF}
  231. function TranslateTInAddrToString(var AInAddr; const AIPVersion: TIdIPVersion): string;
  232. procedure TranslateStringToTInAddr(const AIP: string; var AInAddr; const AIPVersion: TIdIPVersion);
  233. function WSGetServByName(const AServiceName: string): TIdPort; virtual; abstract;
  234. function WSGetServByPort(const APortNumber: TIdPort): TStrings; virtual; {$IFDEF HAS_DEPRECATED}deprecated{$IFDEF HAS_DEPRECATED_MSG} 'Use AddServByPortToList()'{$ENDIF};{$ENDIF}
  235. procedure AddServByPortToList(const APortNumber: TIdPort; AAddresses: TStrings); virtual; abstract;
  236. function RecvFrom(const ASocket: TIdStackSocketHandle; var ABuffer;
  237. const ALength, AFlags: Integer; var VIP: string; var VPort: TIdPort;
  238. var VIPVersion: TIdIPVersion): Integer; virtual; abstract;
  239. procedure WSSendTo(ASocket: TIdStackSocketHandle; const ABuffer;
  240. const ABufferLength, AFlags: Integer; const AIP: string; const APort: TIdPort;
  241. AIPVersion: TIdIPVersion = ID_DEFAULT_IP_VERSION); virtual; abstract;
  242. function WSSocket(AFamily : Integer; AStruct : TIdSocketType; AProtocol: Integer;
  243. const ANonBlocking: Boolean = False): TIdStackSocketHandle; virtual; abstract;
  244. procedure SetBlocking(ASocket: TIdStackSocketHandle;
  245. const ABlocking: Boolean); virtual; abstract;
  246. function WouldBlock(const AResult: Integer): Boolean; virtual; abstract;
  247. function NewSocketHandle(const ASocketType: TIdSocketType;
  248. const AProtocol: TIdSocketProtocol;
  249. const AIPVersion: TIdIPVersion = ID_DEFAULT_IP_VERSION;
  250. const ANonBlocking: Boolean = False)
  251. : TIdStackSocketHandle; override;
  252. //multicast stuff Kudzu permitted me to add here.
  253. procedure SetMulticastTTL(AHandle: TIdStackSocketHandle;
  254. const AValue : Byte; const AIPVersion: TIdIPVersion = ID_DEFAULT_IP_VERSION); override;
  255. procedure SetLoopBack(AHandle: TIdStackSocketHandle; const AValue: Boolean;
  256. const AIPVersion: TIdIPVersion = ID_DEFAULT_IP_VERSION); override;
  257. procedure DropMulticastMembership(AHandle: TIdStackSocketHandle;
  258. const AGroupIP, ALocalIP : String;
  259. const AIPVersion: TIdIPVersion = ID_DEFAULT_IP_VERSION); override;
  260. procedure AddMulticastMembership(AHandle: TIdStackSocketHandle;
  261. const AGroupIP, ALocalIP : String;
  262. const AIPVersion: TIdIPVersion = ID_DEFAULT_IP_VERSION); override;
  263. end;
  264. EIdInvalidServiceName = class(EIdException);
  265. EIdStackInitializationFailed = class (EIdStackError);
  266. EIdStackSetSizeExceeded = class (EIdStackError);
  267. //for some reason, if GDBSDStack is in the same block as GServeFileProc then
  268. //FPC gives a type declaration error.
  269. var
  270. GBSDStack: TIdStackBSDBase = nil;
  271. const
  272. IdIPFamily : array[TIdIPVersion] of Integer = (Id_PF_INET4, Id_PF_INET6);
  273. implementation
  274. uses
  275. //done this way so we can have a separate stack for the Unix systems in FPC
  276. {$IFDEF DOTNET}
  277. IdStackDotNet,
  278. {$ELSE}
  279. {$IFDEF WINDOWS}
  280. IdStackWindows,
  281. {$ELSE}
  282. {$IFDEF USE_VCL_POSIX}
  283. IdStackVCLPosix,
  284. {$ELSE}
  285. {$IFDEF UNIX}
  286. {$IFDEF KYLIXCOMPAT}
  287. IdStackLibc,
  288. {$ELSE}
  289. {$IFDEF USE_BASEUNIX}
  290. IdStackUnix,
  291. {$ENDIF}
  292. {$ENDIF}
  293. {$ENDIF}
  294. {$ENDIF}
  295. {$ENDIF}
  296. {$ENDIF}
  297. SysUtils;
  298. { TIdStackBSDBase }
  299. function TIdStackBSDBase.TranslateTInAddrToString(var AInAddr;
  300. const AIPVersion: TIdIPVersion): string;
  301. var
  302. i: Integer;
  303. begin
  304. case AIPVersion of
  305. Id_IPv4: begin
  306. // TODO: use RtlIpv4AddressToString() on Windows when available...
  307. Result := IntToStr(TIdIn4Addr(AInAddr).S_un_b.s_b1) + '.' {Do not Localize}
  308. + IntToStr(TIdIn4Addr(AInAddr).S_un_b.s_b2) + '.' {Do not Localize}
  309. + IntToStr(TIdIn4Addr(AInAddr).S_un_b.s_b3) + '.' {Do not Localize}
  310. + IntToStr(TIdIn4Addr(AInAddr).S_un_b.s_b4);
  311. end;
  312. Id_IPv6: begin
  313. // TODO: use RtlIpv6AddressToString() on Windows when available...
  314. Result := '';
  315. for i := 0 to 7 do begin
  316. Result := Result + IntToHex(NetworkToHost(TIdIn6Addr(AInAddr).s6_addr16[i]), 1) + ':';
  317. end;
  318. SetLength(Result, Length(Result)-1);
  319. end;
  320. else begin
  321. IPVersionUnsupported;
  322. end;
  323. end;
  324. end;
  325. procedure TIdStackBSDBase.TranslateStringToTInAddr(const AIP: string;
  326. var AInAddr; const AIPVersion: TIdIPVersion);
  327. var
  328. LIP: String;
  329. LAddress: TIdIPv6Address;
  330. begin
  331. case AIPVersion of
  332. Id_IPv4: begin
  333. // TODO: use RtlIpv4StringToAddress() on Windows when available...
  334. LIP := AIP;
  335. TIdIn4Addr(AInAddr).S_un_b.s_b1 := IndyStrToInt(Fetch(LIP, '.')); {Do not Localize}
  336. TIdIn4Addr(AInAddr).S_un_b.s_b2 := IndyStrToInt(Fetch(LIP, '.')); {Do not Localize}
  337. TIdIn4Addr(AInAddr).S_un_b.s_b3 := IndyStrToInt(Fetch(LIP, '.')); {Do not Localize}
  338. TIdIn4Addr(AInAddr).S_un_b.s_b4 := IndyStrToInt(Fetch(LIP, '.')); {Do not Localize}
  339. end;
  340. Id_IPv6: begin
  341. // TODO: use RtlIpv6StringToAddress() on Windows when available...
  342. IPv6ToIdIPv6Address(AIP, LAddress);
  343. TIdIPv6Address(TIdIn6Addr(AInAddr).s6_addr16) := HostToNetwork(LAddress);
  344. end;
  345. else begin
  346. IPVersionUnsupported;
  347. end;
  348. end;
  349. end;
  350. function TIdStackBSDBase.NewSocketHandle(const ASocketType:TIdSocketType;
  351. const AProtocol: TIdSocketProtocol;
  352. const AIPVersion: TIdIPVersion = ID_DEFAULT_IP_VERSION;
  353. const ANonBlocking: Boolean = False): TIdStackSocketHandle;
  354. begin
  355. // RLebeau 04/17/2008: Don't use CheckForSocketError() here. It expects
  356. // an Integer error code, not a TSocket handle. When WSSocket() fails,
  357. // it returns Id_INVALID_SOCKET. Although that is technically the same
  358. // value as Id_SOCKET_ERROR, passing Id_INVALID_SOCKET to CheckForSocketError()
  359. // causes a range check error to be raised.
  360. Result := WSSocket(IdIPFamily[AIPVersion], ASocketType, AProtocol, ANonBlocking);
  361. if Result = Id_INVALID_SOCKET then begin
  362. RaiseLastSocketError;
  363. end;
  364. end;
  365. constructor TIdStackBSDBase.Create;
  366. begin
  367. inherited Create;
  368. GBSDStack := Self;
  369. end;
  370. function TIdStackBSDBase.Receive(ASocket: TIdStackSocketHandle;
  371. var VBuffer: TIdBytes): Integer;
  372. begin
  373. Result := CheckForSocketError(WSRecv(ASocket, VBuffer[0], Length(VBuffer) , 0));
  374. end;
  375. function TIdStackBSDBase.Send(ASocket: TIdStackSocketHandle; const ABuffer: TIdBytes;
  376. const AOffset: Integer = 0; const ASize: Integer = -1): Integer;
  377. var
  378. Tmp: Byte;
  379. begin
  380. Result := IndyLength(ABuffer, ASize, AOffset);
  381. if Result > 0 then begin
  382. Result := WSSend(ASocket, ABuffer[AOffset], Result, 0);
  383. end else begin
  384. // RLebeau: this is to allow UDP sockets to send 0-length packets.
  385. // Have to use a variable because the Buffer parameter is declared
  386. // as an untyped 'const'...
  387. //
  388. // TODO: check the socket type and only allow this for UDP sockets...
  389. //
  390. Result := WSSend(ASocket, Tmp, 0, 0);
  391. end;
  392. end;
  393. function TIdStackBSDBase.ReceiveFrom(ASocket: TIdStackSocketHandle;
  394. var VBuffer: TIdBytes; var VIP: string; var VPort: TIdPort;
  395. var VIPVersion: TIdIPVersion): Integer;
  396. begin
  397. Result := CheckForSocketError(RecvFrom(ASocket, VBuffer[0], Length(VBuffer),
  398. 0, VIP, VPort, VIPVersion));
  399. end;
  400. function TIdStackBSDBase.SendTo(ASocket: TIdStackSocketHandle;
  401. const ABuffer: TIdBytes; const AOffset: Integer; const ASize: Integer;
  402. const AIP: string; const APort: TIdPort;
  403. const AIPVersion: TIdIPVersion = ID_DEFAULT_IP_VERSION): Integer;
  404. var
  405. Tmp: Byte;
  406. begin
  407. Result := IndyLength(ABuffer, ASize, AOffset);
  408. if Result > 0 then begin
  409. WSSendTo(ASocket, ABuffer[AOffset], Result, 0, AIP, APort, AIPVersion);
  410. end else begin
  411. // RLebeau: this is to allow UDP sockets to send 0-length packets.
  412. // Have to use a variable because the Buffer parameter is declared
  413. // as an untyped 'const'...
  414. //
  415. // TODO: check the socket type and only allow this for UDP sockets...
  416. //
  417. WSSendTo(ASocket, Tmp, 0, 0, AIP, APort, AIPVersion);
  418. end;
  419. end;
  420. procedure TIdStackBSDBase.GetSocketOption(ASocket: TIdStackSocketHandle;
  421. ALevel: TIdSocketOptionLevel; AOptName: TIdSocketOption; out AOptVal: Integer);
  422. var
  423. LBuf, LLen: Integer;
  424. begin
  425. LLen := SizeOf(LBuf);
  426. {$IFDEF VCL_XE3_OR_ABOVE}GetSocketOption{$ELSE}WSGetSocketOption{$ENDIF}(ASocket, ALevel, AOptName, LBuf, LLen);
  427. AOptVal := LBuf;
  428. end;
  429. {$IFNDEF VCL_XE3_OR_ABOVE}
  430. procedure TIdStackBSDBase.GetSocketOption(ASocket: TIdStackSocketHandle;
  431. ALevel: TIdSocketOptionLevel; AOptName: TIdSocketOption; var AOptVal;
  432. var AOptLen: Integer);
  433. begin
  434. WSGetSocketOption(ASocket, ALevel, AOptName, AOptVal, AOptLen);
  435. end;
  436. {$ENDIF}
  437. procedure TIdStackBSDBase.SetSocketOption(ASocket: TIdStackSocketHandle;
  438. ALevel: TIdSocketOptionLevel; AOptName: TIdSocketOption; AOptVal: Integer);
  439. begin
  440. {$IFDEF VCL_XE3_OR_ABOVE}SetSocketOption{$ELSE}WSSetSocketOption{$ENDIF}(ASocket, ALevel, AOptName, AOptVal, SizeOf(AOptVal));
  441. end;
  442. {$IFNDEF VCL_XE3_OR_ABOVE}
  443. procedure TIdStackBSDBase.SetSocketOption(ASocket: TIdStackSocketHandle;
  444. ALevel: TIdSocketOptionLevel; AOptName: TIdSocketOption; const AOptVal;
  445. const AOptLen: Integer);
  446. begin
  447. WSSetSocketOption(ASocket, ALevel, AOptName, AOptVal, AOptLen);
  448. end;
  449. {$ENDIF}
  450. procedure TIdStackBSDBase.DropMulticastMembership(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_DROP_MEMBERSHIP, Id_IPV6_DROP_MEMBERSHIP),
  455. AIPVersion);
  456. end;
  457. procedure TIdStackBSDBase.AddMulticastMembership(AHandle: TIdStackSocketHandle;
  458. const AGroupIP, ALocalIP : String; const AIPVersion: TIdIPVersion = ID_DEFAULT_IP_VERSION);
  459. begin
  460. MembershipSockOpt(AHandle, AGroupIP, ALocalIP,
  461. iif(AIPVersion = Id_IPv4, Id_IP_ADD_MEMBERSHIP, Id_IPV6_ADD_MEMBERSHIP),
  462. AIPVersion);
  463. end;
  464. procedure TIdStackBSDBase.SetMulticastTTL(AHandle: TIdStackSocketHandle;
  465. const AValue: Byte; const AIPVersion: TIdIPVersion = ID_DEFAULT_IP_VERSION);
  466. var
  467. LLevel, LOpt: Integer;
  468. begin
  469. case AIPVersion of
  470. Id_IPv4: begin
  471. LLevel := Id_IPPROTO_IP;
  472. LOpt := Id_IP_MULTICAST_TTL;
  473. end;
  474. id_IPv6: begin
  475. LLevel := Id_IPPROTO_IPv6;
  476. LOpt := Id_IPV6_MULTICAST_HOPS;
  477. end;
  478. else begin
  479. // keep the compiler happy
  480. LLevel := 0;
  481. LOpt := 0;
  482. IPVersionUnsupported;
  483. end;
  484. end;
  485. SetSocketOption(AHandle, LLevel, LOpt, AValue);
  486. end;
  487. procedure TIdStackBSDBase.SetLoopBack(AHandle: TIdStackSocketHandle;
  488. const AValue: Boolean; const AIPVersion: TIdIPVersion = ID_DEFAULT_IP_VERSION);
  489. var
  490. LLevel, LOpt: Integer;
  491. begin
  492. case AIPVersion of
  493. Id_IPv4: begin
  494. LLevel := Id_IPPROTO_IP;
  495. LOpt := Id_IP_MULTICAST_LOOP;
  496. end;
  497. Id_IPv6: begin
  498. LLevel := Id_IPPROTO_IPv6;
  499. LOpt := Id_IPV6_MULTICAST_LOOP;
  500. end;
  501. else begin
  502. // keep the compiler happy
  503. LLevel := 0;
  504. LOpt := 0;
  505. IPVersionUnsupported;
  506. end;
  507. end;
  508. SetSocketOption(AHandle, LLevel, LOpt, Ord(AValue));
  509. end;
  510. procedure TIdStackBSDBase.MembershipSockOpt(AHandle: TIdStackSocketHandle;
  511. const AGroupIP, ALocalIP: String; const ASockOpt: Integer;
  512. const AIPVersion: TIdIPVersion = ID_DEFAULT_IP_VERSION);
  513. var
  514. LIP4: TIdIPMreq;
  515. LIP6: TIdIPv6Mreq;
  516. begin
  517. case AIPVersion of
  518. Id_IPv4: begin
  519. if IsValidIPv4MulticastGroup(AGroupIP) then
  520. begin
  521. TranslateStringToTInAddr(AGroupIP, LIP4.IMRMultiAddr, Id_IPv4);
  522. TranslateStringToTInAddr(ALocalIP, LIP4.IMRInterface, Id_IPv4);
  523. SetSocketOption(AHandle, Id_IPPROTO_IP, ASockOpt, LIP4, SizeOf(LIP4));
  524. end;
  525. end;
  526. Id_IPv6: begin
  527. if IsValidIPv6MulticastGroup(AGroupIP) then
  528. begin
  529. TranslateStringToTInAddr(AGroupIP, LIP6.ipv6mr_multiaddr, Id_IPv6);
  530. //this should be safe meaning any adaptor
  531. //we can't support a localhost address in IPv6 because we can't get that
  532. //and even if you could, you would have to convert it into a network adaptor
  533. //index - Yuk
  534. LIP6.ipv6mr_interface := 0;
  535. SetSocketOption(AHandle, Id_IPPROTO_IPv6, ASockOpt, LIP6, SizeOf(LIP6));
  536. end;
  537. end;
  538. else begin
  539. IPVersionUnsupported;
  540. end;
  541. end;
  542. end;
  543. {$I IdDeprecatedImplBugOff.inc}
  544. function TIdStackBSDBase.WSGetServByPort(const APortNumber: TIdPort): TStrings;
  545. {$I IdDeprecatedImplBugOn.inc}
  546. begin
  547. Result := TStringList.Create;
  548. try
  549. AddServByPortToList(APortNumber, Result);
  550. except
  551. FreeAndNil(Result);
  552. raise;
  553. end;
  554. end;
  555. end.