IdStackLibc.pas 46 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484
  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 10/26/2004 8:20:04 PM JPMugaas
  18. Fixed some oversights with conversion. OOPS!!!
  19. Rev 1.6 10/26/2004 8:12:32 PM JPMugaas
  20. Now uses TIdStrings and TIdStringList for portability.
  21. Rev 1.5 12/06/2004 15:17:20 CCostelloe
  22. Restructured to correspond with IdStackWindows, now works.
  23. Rev 1.4 07/06/2004 21:31:02 CCostelloe
  24. Kylix 3 changes
  25. Rev 1.3 4/18/04 10:43:22 PM RLebeau
  26. Fixed syntax error
  27. Rev 1.2 4/18/04 10:29:46 PM RLebeau
  28. Renamed Int64Parts structure to TIdInt64Parts
  29. Rev 1.1 4/18/04 2:47:28 PM RLebeau
  30. Conversion support for Int64 values
  31. Removed WSHToNs(), WSNToHs(), WSHToNL(), and WSNToHL() methods, obsolete
  32. Rev 1.0 2004.02.03 3:14:48 PM czhower
  33. Move and updates
  34. Rev 1.3 10/19/2003 5:35:14 PM BGooijen
  35. SetSocketOption
  36. Rev 1.2 2003.10.01 9:11:24 PM czhower
  37. .Net
  38. Rev 1.1 7/5/2003 07:25:50 PM JPMugaas
  39. Added functions to the Linux stack which use the new TIdIPAddress record type
  40. for IP address parameters. I also fixed a compile bug.
  41. Rev 1.0 11/13/2002 08:59:24 AM JPMugaas
  42. }
  43. unit IdStackLibc;
  44. interface
  45. {$i IdCompilerDefines.inc}
  46. uses
  47. Classes,
  48. Libc,
  49. IdStack,
  50. IdStackConsts,
  51. IdGlobal,
  52. IdStackBSDBase;
  53. {$UNDEF LIBCPASS_STRUCT}
  54. {$IFDEF KYLIX}
  55. {$DEFINE LIBCPASS_STRUCT}
  56. {$ENDIF}
  57. {$IFDEF DELPHI_CROSS}
  58. {$DEFINE LIBCPASS_STRUCT}
  59. {$ENDIF}
  60. type
  61. // TODO: move this class into the implementation section! It is not used outside of this unit
  62. TIdSocketListLibc = class (TIdSocketList)
  63. protected
  64. FCount: integer;
  65. FFDSet: TFDSet;
  66. //
  67. class function FDSelect(AReadSet: PFDSet; AWriteSet: PFDSet; AExceptSet: PFDSet;
  68. const ATimeout: Integer = IdTimeoutInfinite): integer;
  69. function GetItem(AIndex: Integer): TIdStackSocketHandle; override;
  70. public
  71. procedure Add(AHandle: TIdStackSocketHandle); override;
  72. procedure Remove(AHandle: TIdStackSocketHandle); override;
  73. function Count: Integer; override;
  74. procedure Clear; override;
  75. function Clone: TIdSocketList; override;
  76. function ContainsSocket(AHandle: TIdStackSocketHandle): boolean; override;
  77. procedure GetFDSet(var VSet: TFDSet);
  78. procedure SetFDSet(var VSet: TFDSet);
  79. class function Select(AReadList: TIdSocketList; AWriteList: TIdSocketList;
  80. AExceptList: TIdSocketList; const ATimeout: Integer = IdTimeoutInfinite): Boolean; override;
  81. function SelectRead(const ATimeout: Integer = IdTimeoutInfinite): Boolean;
  82. override;
  83. function SelectReadList(var VSocketList: TIdSocketList;
  84. const ATimeout: Integer = IdTimeoutInfinite): Boolean; override;
  85. End;//TIdSocketList
  86. TIdStackLibc = class(TIdStackBSDBase)
  87. private
  88. procedure WriteChecksumIPv6(s: TIdStackSocketHandle;
  89. var VBuffer: TIdBytes; const AOffset: Integer; const AIP: String;
  90. const APort: TIdPort);
  91. protected
  92. function GetLastError : Integer;
  93. procedure SetLastError(Const AError : Integer);
  94. function HostByName(const AHostName: string;
  95. const AIPVersion: TIdIPVersion = ID_DEFAULT_IP_VERSION): string; override;
  96. function ReadHostName: string; override;
  97. function WSCloseSocket(ASocket: TIdStackSocketHandle): Integer; override;
  98. function WSRecv(ASocket: TIdStackSocketHandle;
  99. var ABuffer; const ABufferLength, AFlags: Integer): Integer; override;
  100. function WSSend(ASocket: TIdStackSocketHandle; const ABuffer; const ABufferLength, AFlags: Integer): Integer; override;
  101. function WSShutdown(ASocket: TIdStackSocketHandle; AHow: Integer): Integer; override;
  102. {$IFNDEF VCL_XE3_OR_ABOVE}
  103. procedure WSGetSocketOption(ASocket: TIdStackSocketHandle; ALevel: TIdSocketOptionLevel;
  104. AOptName: TIdSocketOption; var AOptVal; var AOptLen: Integer); override;
  105. procedure WSSetSocketOption(ASocket: TIdStackSocketHandle; ALevel: TIdSocketOptionLevel;
  106. AOptName: TIdSocketOption; const AOptVal; const AOptLen: Integer); override;
  107. {$ENDIF}
  108. public
  109. procedure SetBlocking(ASocket: TIdStackSocketHandle;
  110. const ABlocking: Boolean); override;
  111. function WouldBlock(const AResult: Integer): Boolean; override;
  112. function WSTranslateSocketErrorMsg(const AErr: Integer): string; override;
  113. function Accept(ASocket: TIdStackSocketHandle; var VIP: string; var VPort: TIdPort;
  114. var VIPVersion: TIdIPVersion): TIdStackSocketHandle; override;
  115. procedure Bind(ASocket: TIdStackSocketHandle; const AIP: string;
  116. const APort: TIdPort; const AIPVersion: TIdIPVersion = ID_DEFAULT_IP_VERSION); override;
  117. procedure Connect(const ASocket: TIdStackSocketHandle; const AIP: string;
  118. const APort: TIdPort; const AIPVersion: TIdIPVersion = ID_DEFAULT_IP_VERSION); override;
  119. function HostByAddress(const AAddress: string;
  120. const AIPVersion: TIdIPVersion = ID_DEFAULT_IP_VERSION): string; override;
  121. function WSGetLastError: Integer; override;
  122. procedure WSSetLastError(const AErr : Integer); override;
  123. function WSGetServByName(const AServiceName: string): TIdPort; override;
  124. function WSGetServByPort(const APortNumber: TIdPort): TStrings; override;
  125. procedure GetPeerName(ASocket: TIdStackSocketHandle; var VIP: string;
  126. var VPort: TIdPort; var VIPVersion: TIdIPVersion); override;
  127. procedure GetSocketName(ASocket: TIdStackSocketHandle; var VIP: string;
  128. var VPort: TIdPort; var VIPVersion: TIdIPVersion); override;
  129. procedure Listen(ASocket: TIdStackSocketHandle; ABackLog: Integer); override;
  130. function HostToNetwork(AValue: UInt16): UInt16; override;
  131. function NetworkToHost(AValue: UInt16): UInt16; override;
  132. function HostToNetwork(AValue: UInt32): UInt32; override;
  133. function NetworkToHost(AValue: UInt32): UInt32; override;
  134. function HostToNetwork(AValue: TIdUInt64): TIdUInt64; override;
  135. function NetworkToHost(AValue: TIdUInt64): TIdUInt64; override;
  136. function RecvFrom(const ASocket: TIdStackSocketHandle; var VBuffer;
  137. const ALength, AFlags: Integer; var VIP: string; var VPort: TIdPort;
  138. AIPVersion: TIdIPVersion = ID_DEFAULT_IP_VERSION): Integer; override;
  139. function ReceiveMsg(ASocket: TIdStackSocketHandle; var VBuffer: TIdBytes;
  140. APkt: TIdPacketInfo): UInt32; override;
  141. procedure WSSendTo(ASocket: TIdStackSocketHandle; const ABuffer;
  142. const ABufferLength, AFlags: Integer;
  143. const AIP: string; const APort: TIdPort; AIPVersion: TIdIPVersion = ID_DEFAULT_IP_VERSION); override;
  144. function WSSocket(AFamily : Integer; AStruct : TIdSocketType; AProtocol: Integer;
  145. const ANonBlocking: Boolean = False): TIdStackSocketHandle; override;
  146. procedure Disconnect(ASocket: TIdStackSocketHandle); override;
  147. {$IFDEF VCL_XE3_OR_ABOVE}
  148. procedure GetSocketOption(ASocket: TIdStackSocketHandle; ALevel: TIdSocketOptionLevel;
  149. AOptName: TIdSocketOption; var AOptVal; var AOptLen: Integer); override;
  150. procedure SetSocketOption(ASocket: TIdStackSocketHandle; ALevel: TIdSocketOptionLevel;
  151. AOptName: TIdSocketOption; const AOptVal; const AOptLen: Integer); override;
  152. {$ENDIF}
  153. procedure SetKeepAliveValues(ASocket: TIdStackSocketHandle;
  154. const AEnabled: Boolean; const ATimeMS, AInterval: Integer); override;
  155. function SupportsIPv4: Boolean; overload; override;
  156. function SupportsIPv6: Boolean; overload; override;
  157. function CheckIPVersionSupport(const AIPVersion: TIdIPVersion): boolean; override;
  158. constructor Create; override;
  159. destructor Destroy; override;
  160. //In Windows, this writes a checksum into a buffer. In Linux, it would probably
  161. //simply have the kernal write the checksum with something like this (RFC 2292):
  162. //
  163. // int offset = 2;
  164. // setsockopt(fd, IPPROTO_IPV6, IPV6_CHECKSUM, &offset, sizeof(offset));
  165. //
  166. // Note that this should be called
  167. //IMMEDIATELY before you do a SendTo because the Local IPv6 address might change
  168. procedure WriteChecksum(s : TIdStackSocketHandle;
  169. var VBuffer : TIdBytes;
  170. const AOffset : Integer;
  171. const AIP : String;
  172. const APort : TIdPort;
  173. const AIPVersion: TIdIPVersion = ID_DEFAULT_IP_VERSION); override;
  174. function IOControl(const s: TIdStackSocketHandle; const cmd: UInt32;
  175. var arg: UInt32): Integer; override;
  176. procedure GetLocalAddressList(AAddresses: TIdStackLocalAddressList); override;
  177. end;
  178. TLinger = record
  179. l_onoff: UInt16;
  180. l_linger: UInt16;
  181. end;
  182. TIdLinger = TLinger;
  183. implementation
  184. uses
  185. IdResourceStrings,
  186. IdException,
  187. SysUtils;
  188. type
  189. psockaddr_in6 = ^sockaddr_in6;
  190. const
  191. Id_MSG_NOSIGNAL = MSG_NOSIGNAL;
  192. Id_WSAEPIPE = EPIPE;
  193. constructor TIdStackLibc.Create;
  194. begin
  195. inherited Create;
  196. end;
  197. destructor TIdStackLibc.Destroy;
  198. begin
  199. inherited Destroy;
  200. end;
  201. function TIdStackLibc.GetLastError : Integer;
  202. begin
  203. Result := errno;
  204. end;
  205. procedure TIdStackLibc.SetLastError(Const AError : Integer);
  206. begin
  207. __errno_location^ := AError;
  208. end;
  209. procedure TIdStackLibc.WSSetLastError(const AErr : Integer);
  210. begin
  211. SetLastError(AErr);
  212. end;
  213. function TIdStackLibc.Accept(ASocket: TIdStackSocketHandle;
  214. var VIP: string; var VPort: TIdPort; var VIPVersion: TIdIPVersion): TIdStackSocketHandle;
  215. var
  216. LN: UInt32;
  217. LAddr: sockaddr_in6;
  218. begin
  219. LN := SizeOf(LAddr);
  220. Result := Libc.accept(ASocket, PSockAddr(@LAddr), @LN);
  221. if Result <> SOCKET_ERROR then begin
  222. case LAddr.sin6_family of
  223. Id_PF_INET4: begin
  224. with Psockaddr(@LAddr)^ do
  225. begin
  226. VIP := TranslateTInAddrToString(sin_addr, Id_IPv4);
  227. VPort := Ntohs(sin_port);
  228. end;
  229. VIPVersion := Id_IPV4;
  230. end;
  231. Id_PF_INET6: begin
  232. with LAddr do
  233. begin
  234. VIP := TranslateTInAddrToString(sin6_addr, Id_IPv6);
  235. VPort := ntohs(sin6_port);
  236. end;
  237. VIPVersion := Id_IPV6;
  238. end;
  239. else begin
  240. Libc.__close(Result);
  241. Result := Id_INVALID_SOCKET;
  242. IPVersionUnsupported;
  243. end;
  244. end;
  245. end else begin
  246. if GetLastError = EBADF then begin
  247. SetLastError(EINTR);
  248. end;
  249. end;
  250. end;
  251. procedure TIdStackLibc.Bind(ASocket: TIdStackSocketHandle;
  252. const AIP: string; const APort: TIdPort;
  253. const AIPVersion: TIdIPVersion = ID_DEFAULT_IP_VERSION);
  254. var
  255. LAddr: sockaddr_in6;
  256. begin
  257. FillChar(LAddr, SizeOf(LAddr), 0);
  258. case AIPVersion of
  259. Id_IPv4: begin
  260. with Psockaddr(@LAddr)^ do
  261. begin
  262. sin_family := Id_PF_INET4;
  263. if AIP <> '' then begin
  264. TranslateStringToTInAddr(AIP, sin_addr, Id_IPv4);
  265. end;
  266. sin_port := htons(APort);
  267. end;
  268. CheckForSocketError(Libc.bind(ASocket, {$IFDEF LIBCPASS_STRUCT}PSockAddr(@LAddr)^ {$ELSE} Psockaddr(@LAddr) {$ENDIF},SizeOf(sockaddr)));
  269. end;
  270. Id_IPv6: begin
  271. with LAddr do
  272. begin
  273. sin6_family := Id_PF_INET6;
  274. if AIP <> '' then begin
  275. TranslateStringToTInAddr(AIP, sin6_addr, Id_IPv6);
  276. end;
  277. sin6_port := htons(APort);
  278. end;
  279. CheckForSocketError(Libc.bind(ASocket, {$IFDEF LIBCPASS_STRUCT}Psockaddr(@LAddr)^ {$ELSE}Psockaddr(@LAddr){$ENDIF}, SizeOf(sockaddr_in6)));
  280. end;
  281. else begin
  282. IPVersionUnsupported;
  283. end;
  284. end;
  285. end;
  286. function TIdStackLibc.WSCloseSocket(ASocket: TIdStackSocketHandle): Integer;
  287. begin
  288. Result := Libc.__close(ASocket);
  289. end;
  290. procedure TIdStackLibc.Connect(const ASocket: TIdStackSocketHandle;
  291. const AIP: string; const APort: TIdPort;
  292. const AIPVersion: TIdIPVersion = ID_DEFAULT_IP_VERSION);
  293. var
  294. LAddr: sockAddr_in6;
  295. begin
  296. FillChar(LAddr, SizeOf(LAddr), 0);
  297. case AIPVersion of
  298. Id_IPv4: begin
  299. with Psockaddr(@LAddr)^ do
  300. begin
  301. sin_family := Id_PF_INET4;
  302. TranslateStringToTInAddr(AIP, sin_addr, Id_IPv4);
  303. sin_port := htons(APort);
  304. end;
  305. CheckForSocketError(Libc.connect(
  306. ASocket,
  307. {$IFDEF LIBCPASS_STRUCT}PSockAddr(@LAddr)^{$ELSE}Psockaddr(@LAddr){$ENDIF},
  308. SizeOf(sockaddr)));
  309. end;
  310. Id_IPv6: begin
  311. with LAddr do
  312. begin
  313. sin6_family := Id_PF_INET6;
  314. TranslateStringToTInAddr(AIP, sin6_addr, Id_IPv6);
  315. sin6_port := htons(APort);
  316. end;
  317. CheckForSocketError(Libc.connect(
  318. ASocket,
  319. {$IFDEF LIBCPASS_STRUCT}Psockaddr(@LAddr)^{$ELSE}Psockaddr(@LAddr){$ENDIF},
  320. SizeOf(sockaddr_in6)));
  321. end;
  322. else begin
  323. IPVersionUnsupported;
  324. end;
  325. end;
  326. end;
  327. function TIdStackLibc.HostByName(const AHostName: string;
  328. const AIPVersion: TIdIPVersion = ID_DEFAULT_IP_VERSION): string;
  329. var
  330. Lpa: PAnsiChar;
  331. Lsa: TInAddr;
  332. LHost: PHostEnt;
  333. // ipv6
  334. LHints: TAddressInfo;
  335. {$IFDEF LIBCPASS_STRUCT}
  336. LAddrInfo: PAddressInfo;
  337. {$ELSE}
  338. LAddrInfo: PAddrInfo;
  339. {$ENDIF}
  340. LRetVal: Integer;
  341. {$IFDEF STRING_IS_UNICODE}
  342. LAStr: AnsiString;
  343. {$ENDIF}
  344. begin
  345. case AIPVersion of
  346. Id_IPv4: begin
  347. {$IFDEF STRING_IS_UNICODE}
  348. LAStr := AnsiString(AHostName); // explicit convert to Ansi
  349. {$ENDIF}
  350. // TODO: use getaddrinfo() instead for IPv4 as well...
  351. LHost := Libc.gethostbyname(
  352. PAnsiChar({$IFDEF STRING_IS_UNICODE}LAStr{$ELSE}AHostName{$ENDIF}));
  353. if LHost <> nil then begin
  354. // TODO: gethostbynaame() might return other things besides IPv4
  355. // addresses, so we should be validating the address type before
  356. // attempting the conversion...
  357. Lpa := LHost^.h_addr_list^;
  358. Lsa.S_un_b.s_b1 := Ord(Lpa[0]);
  359. Lsa.S_un_b.s_b2 := Ord(Lpa[1]);
  360. Lsa.S_un_b.s_b3 := Ord(Lpa[2]);
  361. Lsa.S_un_b.s_b4 := Ord(Lpa[3]);
  362. Result := TranslateTInAddrToString(Lsa, Id_IPv4);
  363. end else begin
  364. //RaiseSocketError(h_errno);
  365. RaiseLastSocketError;
  366. end;
  367. end;
  368. Id_IPv6: begin
  369. FillChar(LHints, SizeOf(LHints), 0);
  370. LHints.ai_family := IdIPFamily[AIPVersion];
  371. LHints.ai_socktype := Integer(SOCK_STREAM);
  372. LAddrInfo := nil;
  373. {$IFDEF STRING_IS_UNICODE}
  374. LAStr := AnsiString(AHostName); // explicit convert to Ansi
  375. {$ENDIF}
  376. LRetVal := getaddrinfo(
  377. PAnsiChar({$IFDEF STRING_IS_UNICODE}LAStr{$ELSE}AHostName{$ENDIF}),
  378. nil, @LHints, {$IFDEF LIBCPASS_STRUCT}LAddrInfo{$ELSE}@LAddrInfo{$ENDIF});
  379. if LRetVal <> 0 then begin
  380. if LRetVal = EAI_SYSTEM then begin
  381. IndyRaiseLastError;
  382. end else begin
  383. raise EIdResolveError.CreateFmt(RSResolveError, [AHostName, gai_strerror(LRetVal), LRetVal]);
  384. end;
  385. end;
  386. try
  387. Result := TranslateTInAddrToString(LAddrInfo^.ai_addr^.sin_zero, Id_IPv6);
  388. finally
  389. freeaddrinfo(LAddrInfo);
  390. end;
  391. end
  392. else
  393. Result := ''; // avoid warning
  394. IPVersionUnsupported;
  395. end;
  396. end;
  397. function TIdStackLibc.ReadHostName: string;
  398. var
  399. LStr: array[0..250] of AnsiChar;
  400. begin
  401. if Libc.gethostname(LStr, 250) = 0 then begin
  402. LStr[250] := #0;
  403. Result := String(LStr);
  404. end else begin
  405. Result := '';
  406. end;
  407. end;
  408. procedure TIdStackLibc.Listen(ASocket: TIdStackSocketHandle; ABackLog: Integer);
  409. begin
  410. CheckForSocketError(Libc.listen(ASocket, ABacklog));
  411. end;
  412. function TIdStackLibc.WSRecv(ASocket: TIdStackSocketHandle; var ABuffer;
  413. const ABufferLength, AFlags: Integer): Integer;
  414. begin
  415. //IdStackWindows is just: Result := Recv(ASocket, ABuffer, ABufferLength, AFlags);
  416. Result := Recv(ASocket, ABuffer, ABufferLength, AFlags or Id_MSG_NOSIGNAL);
  417. end;
  418. function TIdStackLibc.RecvFrom(const ASocket: TIdStackSocketHandle;
  419. var VBuffer; const ALength, AFlags: Integer; var VIP: string;
  420. var VPort: TIdPort; AIPVersion: TIdIPVersion = ID_DEFAULT_IP_VERSION ): Integer;
  421. var
  422. LiSize: UInt32;
  423. LAddr: sockaddr_in6;
  424. begin
  425. case AIPVersion of
  426. Id_IPv4,
  427. Id_IPv6: begin
  428. if AIPVersion = Id_IPv4 then begin
  429. LiSize := SizeOf(sockaddr);
  430. end else begin
  431. LiSize := SizeOf(sockaddr_in6);
  432. end;
  433. Result := Libc.recvfrom(ASocket, VBuffer, ALength, AFlags or Id_MSG_NOSIGNAL, PSockAddr(@LAddr), @LiSize);
  434. if AIPVersion = Id_IPv4 then begin
  435. with Psockaddr(@LAddr)^ do begin
  436. VIP := TranslateTInAddrToString(sin_addr, Id_IPv4);
  437. VPort := ntohs(sin_port);
  438. end;
  439. end else begin
  440. with LAddr do begin
  441. VIP := TranslateTInAddrToString(sin6_addr, Id_IPv6);
  442. VPort := ntohs(sin6_port);
  443. end;
  444. end;
  445. end;
  446. else begin
  447. Result := 0;
  448. IPVersionUnsupported;
  449. end;
  450. end;
  451. end;
  452. function TIdStackLibc.ReceiveMsg(ASocket: TIdStackSocketHandle;
  453. var VBuffer: TIdBytes; APkt: TIdPacketInfo): UInt32;
  454. {var
  455. LIP : String;
  456. LPort : TIdPort;
  457. LSize: UInt32;
  458. LAddr: SockAddr_In6;
  459. LMsg : msghdr;
  460. LMsgBuf : BUF;
  461. LControl : TIdBytes;
  462. LCurCmsg : CMSGHDR; //for iterating through the control buffer
  463. LCurPt : Pin_pktinfo;
  464. LCurPt6 : Pin6_pktinfo;
  465. LByte : PByte;
  466. LDummy, LDummy2 : UInt32;
  467. begin
  468. //we call the macro twice because we specified two possible structures.
  469. //Id_IPV6_HOPLIMIT and Id_IPV6_PKTINFO
  470. LSize := CMSG_SPACE(SizeOf(Byte)) + CMSG_SPACE(SizeOf(in6_pktinfo));
  471. SetLength(LControl, LSize);
  472. LMsgBuf.len := Length(VBuffer); // Length(VMsgData);
  473. LMsgBuf.buf := @VBuffer[0]; // @VMsgData[0];
  474. FillChar(LMsg,SizeOf(LMsg),0);
  475. LMsg.lpBuffers := @LMsgBuf;
  476. LMsg.dwBufferCount := 1;
  477. LMsg.Control.Len := LSize;
  478. LMsg.Control.buf := @LControl[0];
  479. LMsg.name := PSOCKADDR(@LAddr);
  480. LMsg.namelen := SizeOf(LAddr);
  481. CheckForSocketError(RecvMsg(ASocket, @LMsg, Result, @LDummy, LPwsaoverlapped_COMPLETION_ROUTINE(@LDummy2)));
  482. APkt.Reset;
  483. case LAddr.sin6_family of
  484. Id_PF_INET4: begin
  485. with PSOCKADDR(@LAddr)^ do
  486. begin
  487. APkt.SourceIP := TranslateTInAddrToString(sin_addr, Id_IPv4);
  488. APkt.SourcePort := NToHs(sin_port);
  489. end;
  490. APkt.SourceIPVersion := Id_IPv4;
  491. end;
  492. Id_PF_INET6: begin
  493. with LAddr do
  494. begin
  495. APkt.SourceIP := TranslateTInAddrToString(sin6_addr, Id_IPv6);
  496. APkt.SourcePort := NToHs(sin6_port);
  497. end;
  498. APkt.SourceIPVersion := Id_IPv6;
  499. end;
  500. else begin
  501. Result := 0; // avoid warning
  502. IPVersionUnsupported;
  503. end;
  504. end;
  505. LCurCmsg := nil;
  506. repeat
  507. LCurCmsg := CMSG_NXTHDR(@LMsg,LCurCmsg);
  508. if LCurCmsg=nil then
  509. begin
  510. break;
  511. end;
  512. case LCurCmsg^.cmsg_type of
  513. IP_PKTINFO : //done this way because IPV6_PKTINF and IP_PKTINFO are both 19
  514. begin
  515. case LAddr.sin6_family of
  516. Id_PF_INET4:
  517. begin
  518. LCurPt := WSA_CMSG_DATA(LCurCmsg);
  519. APkt.DestIP := GWindowsStack.TranslateTInAddrToString(LCurPt^.ipi_addr,Id_IPv4);
  520. APkt.DestIF := LCurPt^.ipi_ifindex;
  521. APkt.DestIPVersion := Id_IPv4;
  522. end;
  523. Id_PF_INET6:
  524. begin
  525. LCurPt6 := WSA_CMSG_DATA(LCurCmsg);
  526. APkt.DestIP := GWindowsStack.TranslateTInAddrToString(LCurPt6^.ipi6_addr,Id_IPv6);
  527. APkt.DestIF := LCurPt6^.ipi6_ifindex;
  528. APkt.DestIPVersion := Id_IPv6;
  529. end;
  530. end;
  531. end;
  532. Id_IPV6_HOPLIMIT :
  533. begin
  534. LByte := PByte(WSA_CMSG_DATA(LCurCmsg));
  535. APkt.TTL := LByte^;
  536. end;
  537. end;
  538. until False; }
  539. begin
  540. APkt.Reset;
  541. Result := 0; // avoid warning
  542. end;
  543. function TIdStackLibc.WSSend(ASocket: TIdStackSocketHandle;
  544. const ABuffer; const ABufferLength, AFlags: Integer): Integer;
  545. begin
  546. //CC: Should Id_MSG_NOSIGNAL be included?
  547. // Result := Send(ASocket, ABuffer, ABufferLength, AFlags or Id_MSG_NOSIGNAL);
  548. Result := CheckForSocketError(Libc.send(ASocket, ABuffer, ABufferLength, AFlags));
  549. end;
  550. procedure TIdStackLibc.WSSendTo(ASocket: TIdStackSocketHandle;
  551. const ABuffer; const ABufferLength, AFlags: Integer; const AIP: string;
  552. const APort: TIdPort; AIPVersion: TIdIPVersion = ID_DEFAULT_IP_VERSION);
  553. var
  554. LAddr: sockaddr_in6;
  555. LiSize, LBytesOut: Integer;
  556. begin
  557. case AIPVersion of
  558. Id_IPv4, Id_IPv6:
  559. begin
  560. FillChar(LAddr, SizeOf(LAddr), 0);
  561. if AIPVersion = Id_IPv4 then begin
  562. with PsockAddr(@LAddr)^ do begin
  563. sin_family := Id_PF_INET4;
  564. TranslateStringToTInAddr(AIP, sin_addr, Id_IPV4);
  565. sin_port := htons(APort);
  566. end;
  567. LiSize := SizeOf(sockaddr);
  568. end else begin
  569. with LAddr do begin
  570. sin6_family := Id_PF_INET6;
  571. TranslateStringToTInAddr(AIP, sin6_addr, AIPVersion);
  572. sin6_port := htons(APort);
  573. end;
  574. LiSize := SizeOf(sockaddr_in6);
  575. end;
  576. LBytesOut := Libc.sendto(
  577. ASocket, ABuffer, ABufferLength, AFlags or Id_MSG_NOSIGNAL,
  578. {$IFDEF LIBCPASS_STRUCT}Psockaddr(@LAddr)^{$ELSE}Psockaddr(@LAddr){$ENDIF},
  579. LiSize);
  580. end;
  581. else begin
  582. LBytesOut := 0; // avoid warning
  583. IPVersionUnsupported;
  584. end;
  585. end;
  586. if LBytesOut = Id_SOCKET_ERROR then begin
  587. // TODO: move this into RaiseLastSocketError directly
  588. if WSGetLastError() = Id_WSAEMSGSIZE then begin
  589. raise EIdPackageSizeTooBig.Create(RSPackageSizeTooBig);
  590. end else begin
  591. RaiseLastSocketError;
  592. end;
  593. end else if LBytesOut <> ABufferLength then begin
  594. raise EIdNotAllBytesSent.Create(RSNotAllBytesSent);
  595. end;
  596. end;
  597. procedure TIdStackLibc.{$IFDEF VCL_XE3_OR_ABOVE}GetSocketOption{$ELSE}WSGetSocketOption{$ENDIF}
  598. (ASocket: TIdStackSocketHandle; ALevel: TIdSocketOptionLevel; AOptName: TIdSocketOption;
  599. var AOptVal; var AOptLen: Integer);
  600. var
  601. LLen: UInt32;
  602. begin
  603. LLen := AOptLen;
  604. CheckForSocketError(Libc.getsockopt(ASocket, ALevel, AOptName, PIdAnsiChar(@AOptVal), LLen));
  605. AOptLen := LLen;
  606. end;
  607. procedure TIdStackLibc.{$IFDEF VCL_XE3_OR_ABOVE}SetSocketOption{$ELSE}WSSetSocketOption{$ENDIF}
  608. (ASocket: TIdStackSocketHandle; ALevel: TIdSocketOptionLevel; AOptName: TIdSocketOption;
  609. const AOptVal; const AOptLen: Integer);
  610. begin
  611. CheckForSocketError(Libc.setsockopt(ASocket, ALevel, AOptName, PIdAnsiChar(@AOptVal), AOptLen));
  612. end;
  613. function TIdStackLibc.WSGetLastError: Integer;
  614. begin
  615. //IdStackWindows just uses result := WSAGetLastError;
  616. Result := GetLastError; //System.GetLastOSError; - FPC doesn't define it in System
  617. if Result = Id_WSAEPIPE then begin
  618. Result := Id_WSAECONNRESET;
  619. end;
  620. end;
  621. function TIdStackLibc.WSSocket(AFamily : Integer; AStruct : TIdSocketType; AProtocol: Integer;
  622. const ANonBlocking: Boolean = False): TIdStackSocketHandle; override;
  623. begin
  624. Result := Libc.socket(AFamily, AStruct or iif(ANonBlocking, SOCK_NONBLOCK, 0), AProtocol);
  625. end;
  626. function TIdStackLibc.WSGetServByName(const AServiceName: string): TIdPort;
  627. var
  628. Lps: PServEnt;
  629. {$IFDEF STRING_IS_UNICODE}
  630. LAStr: AnsiString;
  631. {$ENDIF}
  632. begin
  633. {$IFDEF STRING_IS_UNICODE}
  634. LAStr := AnsiString(AServiceName); // explicit convert to Ansi
  635. {$ENDIF}
  636. Lps := Libc.getservbyname(
  637. PAnsiChar({$IFDEF STRING_IS_UNICODE}LAStr{$ELSE}AServiceName{$ENDIF}),
  638. nil);
  639. if Lps <> nil then begin
  640. Result := ntohs(Lps^.s_port);
  641. end else begin
  642. try
  643. Result := IndyStrToInt(AServiceName);
  644. except
  645. on EConvertError do begin
  646. IndyRaiseOuterException(EIdInvalidServiceName.CreateFmt(RSInvalidServiceName, [AServiceName]));
  647. end;
  648. end;
  649. end;
  650. end;
  651. function TIdStackLibc.WSGetServByPort(const APortNumber: TIdPort): TStrings;
  652. type
  653. PPAnsiCharArray = ^TPAnsiCharArray;
  654. TPAnsiCharArray = packed array[0..(Maxint div SizeOf(PAnsiChar))-1] of PAnsiChar;
  655. var
  656. Lps: PServEnt;
  657. Li: Integer;
  658. Lp: PPAnsiCharArray;
  659. begin
  660. Result := TStringList.Create;
  661. try
  662. Lps := Libc.getservbyport(htons(APortNumber), nil);
  663. if Lps <> nil then begin
  664. Result.Add(String(Lps^.s_name));
  665. Li := 0;
  666. Lp := Pointer(Lps^.s_aliases);
  667. while Lp[Li] <> nil do begin
  668. Result.Add(String(Lp[Li]));
  669. Inc(Li);
  670. end;
  671. end;
  672. except
  673. FreeAndNil(Result);
  674. raise;
  675. end;
  676. end;
  677. function TIdStackLibc.HostToNetwork(AValue: UInt16): UInt16;
  678. begin
  679. Result := htons(AValue);
  680. end;
  681. function TIdStackLibc.NetworkToHost(AValue: UInt16): UInt16;
  682. begin
  683. Result := ntohs(AValue);
  684. end;
  685. function TIdStackLibc.HostToNetwork(AValue: UInt32): UInt32;
  686. begin
  687. Result := htonl(AValue);
  688. end;
  689. function TIdStackLibc.NetworkToHost(AValue: UInt32): UInt32;
  690. begin
  691. Result := ntohl(AValue);
  692. end;
  693. { RP - I'm not sure what endian Linux natively uses, thus the
  694. check to see if the bytes need swapping or not ... }
  695. function TIdStackLibc.HostToNetwork(AValue: TIdUInt64): TIdUInt64;
  696. var
  697. LParts: TIdUInt64Parts;
  698. L: UInt32;
  699. begin
  700. if (htonl(1) <> 1) then begin
  701. LParts.QuadPart := AValue{$IFDEF TIdUInt64_HAS_QuadPart}.QuadPart{$ENDIF};
  702. L := htonl(LParts.HighPart);
  703. LParts.HighPart := htonl(LParts.LowPart);
  704. LParts.LowPart := L;
  705. Result{$IFDEF TIdUInt64_HAS_QuadPart}.QuadPart{$ENDIF} := LParts.QuadPart;
  706. end else begin
  707. Result{$IFDEF TIdUInt64_HAS_QuadPart}.QuadPart{$ENDIF} := AValue{$IFDEF TIdUInt64_HAS_QuadPart}.QuadPart{$ENDIF};
  708. end;
  709. end;
  710. function TIdStackLibc.NetworkToHost(AValue: TIdUInt64): TIdUInt64;
  711. var
  712. LParts: TIdUInt64Parts;
  713. L: UInt32;
  714. begin
  715. if (ntohl(1) <> 1) then begin
  716. LParts.QuadPart := AValue{$IFDEF TIdUInt64_HAS_QuadPart}.QuadPart{$ENDIF};
  717. L := ntohl(LParts.HighPart);
  718. LParts.HighPart := ntohl(LParts.LowPart);
  719. LParts.LowPart := L;
  720. Result{$IFDEF TIdUInt64_HAS_QuadPart}.QuadPart{$ENDIF} := LParts.QuadPart;
  721. end else begin
  722. Result{$IFDEF TIdUInt64_HAS_QuadPart}.QuadPart{$ENDIF} := AValue{$IFDEF TIdUInt64_HAS_QuadPart}.QuadPart{$ENDIF};
  723. end;
  724. end;
  725. {$IFDEF HAS_getifaddrs}
  726. type
  727. TIdStackLocalAddressAccess = class(TIdStackLocalAddress)
  728. end;
  729. {$ENDIF}
  730. procedure TIdStackLibc.GetLocalAddressList(AAddresses: TIdStackLocalAddressList);
  731. {$IFNDEF HAS_getifaddrs}
  732. type
  733. TaPInAddr = array[0..250] of PInAddr;
  734. PaPInAddr = ^TaPInAddr;
  735. TaPIn6Addr = array[0..250] of PIn6Addr;
  736. PaPIn6Addr = ^TaPIn6Addr;
  737. {$ENDIF}
  738. var
  739. {$IFDEF HAS_getifaddrs}
  740. LAddrList, LAddrInfo: pifaddrs;
  741. LSubNetStr: string;
  742. LAddress: TIdStackLocalAddress;
  743. LName: string;
  744. {$ELSE}
  745. Li: Integer;
  746. LAHost: PHostEnt;
  747. LPAdrPtr: PaPInAddr;
  748. LPAdr6Ptr: PaPIn6Addr;
  749. LHostName: AnsiString;
  750. {$ENDIF}
  751. begin
  752. // TODO: Using gethostname() and gethostbyname() like this may not always
  753. // return just the machine's IP addresses. Technically speaking, they will
  754. // return the local hostname, and then return the address(es) to which that
  755. // hostname resolves. It is possible for a machine to (a) be configured such
  756. // that its name does not resolve to an IP, or (b) be configured such that
  757. // its name resolves to multiple IPs, only one of which belongs to the local
  758. // machine. For better results, we should use getifaddrs() on platforms that
  759. // support it...
  760. {$IFDEF HAS_getifaddrs}
  761. if getifaddrs(@LAddrList) = 0 then // TODO: raise an exception if it fails
  762. try
  763. AAddresses.BeginUpdate;
  764. try
  765. LAddrInfo := LAddrList;
  766. repeat
  767. if (LAddrInfo^.ifa_addr <> nil) and ((LAddrInfo^.ifa_flags and IFF_LOOPBACK) = 0) then
  768. begin
  769. LAddress := nil;
  770. case LAddrInfo^.ifa_addr^.sa_family of
  771. Id_PF_INET4: begin
  772. if LAddrInfo^.ifa_netmask <> nil then begin
  773. LSubNetStr := TranslateTInAddrToString(PSockAddr_In(LAddrInfo^.ifa_netmask)^.sin_addr, Id_IPv4);
  774. end else begin
  775. LSubNetStr := '';
  776. end;
  777. LAddress := TIdStackLocalAddressIPv4.Create(AAddresses, TranslateTInAddrToString(PSockAddr_In(LAddrInfo^.ifa_addr)^.sin_addr, Id_IPv4), LSubNetStr);
  778. end;
  779. Id_PF_INET6: begin
  780. LAddress := TIdStackLocalAddressIPv6.Create(AAddresses, TranslateTInAddrToString(PSockAddr_In6(LAddrInfo^.ifa_addr)^.sin6_addr, Id_IPv6));
  781. end;
  782. end;
  783. if LAddress <> nil then begin
  784. LName := LAddrInfo^.ifa_name;
  785. {$I IdObjectChecksOff.inc}
  786. TIdStackLocalAddressAccess(LAddress).FDescription := LName;
  787. TIdStackLocalAddressAccess(LAddress).FFriendlyName := LName;
  788. TIdStackLocalAddressAccess(LAddress).FInterfaceName := LName;
  789. {$IFDEF HAS_if_nametoindex}
  790. TIdStackLocalAddressAccess(LAddress).FInterfaceIndex := if_nametoindex(LAddrInfo^.ifa_name);
  791. {$ENDIF}
  792. {$I IdObjectChecksOn.inc}
  793. end;
  794. end;
  795. LAddrInfo := LAddrInfo^.ifa_next;
  796. until LAddrInfo = nil;
  797. finally
  798. AAddresses.EndUpdate;
  799. end;
  800. finally
  801. freeifaddrs(LAddrList);
  802. end;
  803. {$ELSE}
  804. // this won't get IPv6 addresses as I didn't find a way
  805. // to enumerate IPv6 addresses on a linux machine
  806. LHostName := AnsiString(HostName);
  807. LAHost := Libc.gethostbyname(PAnsiChar(LHostName));
  808. if LAHost = nil then begin
  809. RaiseLastSocketError;
  810. end;
  811. // gethostbyname() might return other things besides IPv4 addresses, so we
  812. // need to validate the address type before attempting the conversion...
  813. case LAHost^.h_addrtype of
  814. Id_PF_INET4: begin
  815. LPAdrPtr := PAPInAddr(LAHost^.h_addr_list);
  816. Li := 0;
  817. if LPAdrPtr^[Li] <> nil then begin
  818. AAddresses.BeginUpdate;
  819. try
  820. repeat
  821. TIdStackLocalAddressIPv4.Create(Addresses, TranslateTInAddrToString(LPAdrPtr^[Li]^, Id_IPv4), ''); // TODO: SubNet
  822. Inc(Li);
  823. until LPAdrPtr^[Li] = nil;
  824. finally
  825. AAddresses.EndUpdate;
  826. end;
  827. end;
  828. end;
  829. Id_PF_INET6: begin
  830. LPAdr6Ptr := PAPIn6Addr(LAHost^.h_addr_list);
  831. Li := 0;
  832. if LPAdr6Ptr^[Li] <> nil then begin
  833. AAddresses.BeginUpdate;
  834. try
  835. repeat
  836. TIdStackLocalAddressIPv6.Create(Addresses, TranslateTInAddrToString(LPAdr6Ptr^[Li]^, Id_IPv6));
  837. Inc(Li);
  838. until LPAdr6Ptr^[Li] = nil;
  839. finally
  840. AAddresses.EndUpdate;
  841. end;
  842. end;
  843. end;
  844. end;
  845. {$ENDIF}
  846. end;
  847. function TIdStackLibc.HostByAddress(const AAddress: string;
  848. const AIPVersion: TIdIPVersion = ID_DEFAULT_IP_VERSION): string;
  849. var
  850. LAddr: sockaddr_in6;
  851. LSize: UInt32;
  852. LHostName : array[0..NI_MAXHOST] of TIdAnsiChar;
  853. {$IFDEF USE_MARSHALLED_PTRS}
  854. LHostNamePtr: TPtrWrapper;
  855. {$ENDIF}
  856. LRet : Integer;
  857. {$IFDEF LIBCPASS_STRUCT}
  858. LHints: TAddressInfo;
  859. LAddrInfo: PAddressInfo;
  860. {$ELSE}
  861. LHints: AddrInfo; //The T is no omission - that's what I found in the header
  862. LAddrInfo: PAddrInfo;
  863. {$ENDIF}
  864. begin
  865. FillChar(LAddr, SizeOf(LAddr), 0);
  866. case AIPVersion of
  867. Id_IPv4: begin
  868. with Psockaddr(@LAddr)^ do begin
  869. sin_family := Id_PF_INET4;
  870. TranslateStringToTInAddr(AAddress, sin_addr, Id_IPv4);
  871. end;
  872. LSize := SizeOf(sockaddr);
  873. end;
  874. Id_IPv6: begin
  875. with LAddr do begin
  876. sin6_family := Id_PF_INET6;
  877. TranslateStringToTInAddr(AAddress, sin6_addr, Id_IPv6);
  878. end;
  879. LSize := SizeOf(sockaddr_in6);
  880. end;
  881. else begin
  882. LSize := 0; // avoid warning
  883. IPVersionUnsupported;
  884. end;
  885. end;
  886. FillChar(LHostName[0],Length(LHostName),0);
  887. {$IFDEF USE_MARSHALLED_PTRS}
  888. LHostNamePtr := TPtrWrapper.Create(@LHostName[0]);
  889. {$ENDIF}
  890. LRet := getnameinfo(
  891. {$IFDEF LIBCPASS_STRUCT}Psockaddr(@LAddr)^{$ELSE}Psockaddr(@LAddr){$ENDIF},
  892. LSize,
  893. {$IFDEF USE_MARSHALLED_PTRS}
  894. LHostNamePtr.ToPointer
  895. {$ELSE}
  896. LHostName
  897. {$ENDIF},
  898. NI_MAXHOST,nil,0,NI_NAMEREQD );
  899. if LRet <> 0 then begin
  900. if LRet = EAI_SYSTEM then begin
  901. RaiseLastOSError;
  902. end else begin
  903. raise EIdReverseResolveError.CreateFmt(RSReverseResolveError, [AAddress, gai_strerror(LRet), LRet]);
  904. end;
  905. end;
  906. {
  907. IMPORTANT!!!
  908. getnameinfo can return either results from a numeric to text conversion or
  909. results from a DNS reverse lookup. Someone could make a malicous PTR record
  910. such as
  911. 1.0.0.127.in-addr.arpa. IN PTR 10.1.1.1
  912. and trick a caller into beleiving the socket address is 10.1.1.1 instead of
  913. 127.0.0.1. If there is a numeric host in LAddr, than this is the case and
  914. we disregard the result and raise an exception.
  915. }
  916. FillChar(LHints,SizeOf(LHints),0);
  917. LHints.ai_socktype := SOCK_DGRAM; //*dummy*/
  918. LHints.ai_flags := AI_NUMERICHOST;
  919. if getaddrinfo(
  920. {$IFDEF USE_MARSHALLED_PTRS}
  921. LHostNamePtr.ToPointer
  922. {$ELSE}
  923. LHostName
  924. {$ENDIF},
  925. '0', LHints, LAddrInfo) = 0 then
  926. begin
  927. freeaddrinfo(LAddrInfo^);
  928. Result := '';
  929. raise EIdMaliciousPtrRecord.Create(RSMaliciousPtrRecord);
  930. end;
  931. {$IFDEF USE_MARSHALLED_PTRS}
  932. Result := TMarshal.ReadStringAsAnsi(LHostNamePtr);
  933. {$ELSE}
  934. Result := String(LHostName);
  935. {$ENDIF}
  936. (* JMB: I left this in here just in case someone
  937. complains, but the other code works on all
  938. linux systems for all addresses and is thread-safe
  939. variables for it:
  940. Host: PHostEnt;
  941. LAddr: u_long;
  942. Id_IPv4: begin
  943. // GetHostByAddr is thread-safe in Linux.
  944. // It might not be safe in Solaris or BSD Unix
  945. LAddr := inet_addr(PAnsiChar(AAddress));
  946. Host := GetHostByAddr(@LAddr,SizeOf(LAddr),AF_INET);
  947. if (Host <> nil) then begin
  948. Result := Host^.h_name;
  949. end else begin
  950. RaiseSocketError(h_errno);
  951. end;
  952. end;
  953. *)
  954. end;
  955. function TIdStackLibc.WSShutdown(ASocket: TIdStackSocketHandle; AHow: Integer): Integer;
  956. begin
  957. Result := Libc.shutdown(ASocket, AHow);
  958. end;
  959. procedure TIdStackLibc.Disconnect(ASocket: TIdStackSocketHandle);
  960. begin
  961. // Windows uses Id_SD_Send, Linux should use Id_SD_Both
  962. WSShutdown(ASocket, Id_SD_Both);
  963. // SO_LINGER is false - socket may take a little while to actually close after this
  964. WSCloseSocket(ASocket);
  965. end;
  966. procedure TIdStackLibc.GetPeerName(ASocket: TIdStackSocketHandle;
  967. var VIP: string; var VPort: TIdPort; var VIPVersion: TIdIPVersion);
  968. var
  969. i: UInt32;
  970. LAddr: sockaddr_in6;
  971. begin
  972. i := SizeOf(LAddr);
  973. CheckForSocketError(Libc.getpeername(ASocket, Psockaddr(@LAddr)^, i));
  974. case LAddr.sin6_family of
  975. Id_PF_INET4: begin
  976. with Psockaddr(@LAddr)^ do
  977. begin
  978. VIP := TranslateTInAddrToString(sin_addr, Id_IPv4);
  979. VPort := ntohs(sin_port);
  980. end;
  981. VIPVersion := Id_IPV4;
  982. end;
  983. Id_PF_INET6: begin
  984. with LAddr do
  985. begin
  986. VIP := TranslateTInAddrToString(sin6_addr, Id_IPv6);
  987. VPort := Ntohs(sin6_port);
  988. end;
  989. VIPVersion := Id_IPV6;
  990. end;
  991. else begin
  992. IPVersionUnsupported;
  993. end;
  994. end;
  995. end;
  996. procedure TIdStackLibc.GetSocketName(ASocket: TIdStackSocketHandle;
  997. var VIP: string; var VPort: TIdPort; var VIPVersion: TIdIPVersion);
  998. var
  999. i: UInt32;
  1000. LAddr: sockaddr_in6;
  1001. begin
  1002. i := SizeOf(LAddr);
  1003. CheckForSocketError(Libc.getsockname(ASocket, Psockaddr(@LAddr)^, i));
  1004. case LAddr.sin6_family of
  1005. Id_PF_INET4: begin
  1006. with Psockaddr(@LAddr)^ do
  1007. begin
  1008. VIP := TranslateTInAddrToString(sin_addr, Id_IPv4);
  1009. VPort := ntohs(sin_port);
  1010. end;
  1011. VIPVersion := Id_IPV4;
  1012. end;
  1013. Id_PF_INET6: begin
  1014. with LAddr do
  1015. begin
  1016. VIP := TranslateTInAddrToString(sin6_addr, Id_IPv6);
  1017. VPort := ntohs(sin6_port);
  1018. end;
  1019. VIPVersion := Id_IPV6;
  1020. end;
  1021. else begin
  1022. IPVersionUnsupported;
  1023. end;
  1024. end;
  1025. end;
  1026. function TIdStackLibc.WouldBlock(const AResult: Integer): Boolean;
  1027. begin
  1028. // using if-else instead of in..range because EAGAIN and EWOULDBLOCK
  1029. // have often the same value and so FPC might report a range error
  1030. Result := (AResult = Id_WSAEAGAIN) or
  1031. (AResult = Id_WSAEWOULDBLOCK) or
  1032. (AResult = Id_WSAEINPROGRESS);
  1033. end;
  1034. function TIdStackLibc.SupportsIPv4: Boolean;
  1035. begin
  1036. //In Windows, this does something else. It checks the LSP's installed.
  1037. Result := CheckIPVersionSupport(Id_IPv4);
  1038. end;
  1039. function TIdStackLibc.SupportsIPv6: Boolean;
  1040. begin
  1041. //In Windows, this does something else. It checks the LSP's installed.
  1042. Result := CheckIPVersionSupport(Id_IPv6);
  1043. end;
  1044. function TIdStackLibc.CheckIPVersionSupport(const AIPVersion: TIdIPVersion): Boolean;
  1045. var
  1046. LTmpSocket: TIdStackSocketHandle;
  1047. begin
  1048. // TODO: on nix systems (or maybe just Linux?), an alternative would be to
  1049. // check for the existance of the '/proc/net/if_inet6' kernel pseudo-file
  1050. LTmpSocket := WSSocket(IdIPFamily[AIPVersion], Integer(Id_SOCK_STREAM), Id_IPPROTO_IP );
  1051. Result := LTmpSocket <> Id_INVALID_SOCKET;
  1052. if Result then begin
  1053. WSCloseSocket(LTmpSocket);
  1054. end;
  1055. end;
  1056. procedure TIdStackLibc.WriteChecksum(s: TIdStackSocketHandle;
  1057. var VBuffer: TIdBytes; const AOffset: Integer; const AIP: String;
  1058. const APort: TIdPort; const AIPVersion: TIdIPVersion);
  1059. begin
  1060. case AIPVersion of
  1061. Id_IPv4 : CopyTIdUInt16(HostToLittleEndian(CalcCheckSum(VBuffer)), VBuffer, AOffset);
  1062. Id_IPv6 : WriteChecksumIPv6(s, VBuffer, AOffset, AIP, APort);
  1063. else
  1064. IPVersionUnsupported;
  1065. end;
  1066. end;
  1067. procedure TIdStackLibc.WriteChecksumIPv6(s: TIdStackSocketHandle;
  1068. var VBuffer: TIdBytes; const AOffset: Integer; const AIP: String;
  1069. const APort: TIdPort);
  1070. begin
  1071. //we simply request that the kernal write the checksum when the data
  1072. //is sent. All of the parameters required are because Windows is bonked
  1073. //because it doesn't have the IPV6CHECKSUM socket option meaning we have
  1074. //to querry the network interface in TIdStackWindows -- yuck!!
  1075. SetSocketOption(s, IPPROTO_IPV6, IPV6_CHECKSUM, AOffset);
  1076. end;
  1077. function TIdStackLibc.IOControl(const s: TIdStackSocketHandle;
  1078. const cmd: UInt32; var arg: UInt32): Integer;
  1079. begin
  1080. Result := ioctl(s, cmd, @arg);
  1081. end;
  1082. procedure TIdStackLibc.SetKeepAliveValues(ASocket: TIdStackSocketHandle;
  1083. const AEnabled: Boolean; const ATimeMS, AInterval: Integer);
  1084. begin
  1085. inherited; // turn SO_KEEPALIVE on/off first...
  1086. // TODO: remove below, as it should be handled by TIdStack.SetKeepAliveValues() now...
  1087. if AEnabled then begin
  1088. SetSocketOption(ASocket, Id_SOL_TCP, Id_TCP_KEEPIDLE, ATimeMS div MSecsPerSec);
  1089. SetSocketOption(ASocket, Id_SOL_TCP, Id_TCP_KEEPINTVL, AInterval div MSecsPerSec);
  1090. end;
  1091. end;
  1092. { TIdSocketListLibc }
  1093. procedure TIdSocketListLibc.Add(AHandle: TIdStackSocketHandle);
  1094. begin
  1095. Lock;
  1096. try
  1097. if not FD_ISSET(AHandle, FFDSet) then begin
  1098. if AHandle >= __FD_SETSIZE then begin
  1099. raise EIdStackSetSizeExceeded.Create(RSSetSizeExceeded);
  1100. end;
  1101. FD_SET(AHandle, FFDSet);
  1102. Inc(FCount);
  1103. end;
  1104. finally
  1105. Unlock;
  1106. end;
  1107. end;//
  1108. procedure TIdSocketListLibc.Clear;
  1109. begin
  1110. Lock;
  1111. try
  1112. FD_ZERO(FFDSet);
  1113. FCount := 0;
  1114. finally
  1115. Unlock;
  1116. end;
  1117. end;
  1118. function TIdSocketListLibc.ContainsSocket(
  1119. AHandle: TIdStackSocketHandle): boolean;
  1120. begin
  1121. Lock;
  1122. try
  1123. Result := FD_ISSET(AHandle, FFDSet);
  1124. finally
  1125. Unlock;
  1126. end;
  1127. end;
  1128. function TIdSocketListLibc.Count: Integer;
  1129. begin
  1130. Lock;
  1131. try
  1132. Result := FCount;
  1133. finally
  1134. Unlock;
  1135. end;
  1136. end;//
  1137. class function TIdSocketListLibc.FDSelect(AReadSet, AWriteSet,
  1138. AExceptSet: PFDSet; const ATimeout: Integer): integer;
  1139. var
  1140. LTime: TTimeVal;
  1141. LTimePtr: PTimeVal;
  1142. begin
  1143. if ATimeout = IdTimeoutInfinite then begin
  1144. LTimePtr := nil;
  1145. end else begin
  1146. LTime.tv_sec := ATimeout div 1000;
  1147. LTime.tv_usec := (ATimeout mod 1000) * 1000;
  1148. LTimePtr := @LTime;
  1149. end;
  1150. // TODO: calculate the actual nfds value based on the Sets provided...
  1151. // TODO: use poll() instead of select() to remove limit on how many sockets can be queried
  1152. Result := Libc.select(__FD_SETSIZE, AReadSet, AWriteSet, AExceptSet, LTimePtr);
  1153. end;
  1154. procedure TIdSocketListLibc.GetFDSet(var VSet: TFDSet);
  1155. begin
  1156. Lock;
  1157. try
  1158. VSet := FFDSet;
  1159. finally
  1160. Unlock;
  1161. end;
  1162. end;
  1163. function TIdSocketListLibc.GetItem(AIndex: Integer): TIdStackSocketHandle;
  1164. var
  1165. LIndex, i: Integer;
  1166. begin
  1167. Result := 0;
  1168. Lock;
  1169. try
  1170. LIndex := 0;
  1171. //? use FMaxHandle div x
  1172. for i:= 0 to __FD_SETSIZE - 1 do begin
  1173. if FD_ISSET(i, FFDSet) then begin
  1174. if LIndex = AIndex then begin
  1175. Result := i;
  1176. Break;
  1177. end;
  1178. Inc(LIndex);
  1179. end;
  1180. end;
  1181. finally
  1182. Unlock;
  1183. end;
  1184. end;//
  1185. procedure TIdSocketListLibc.Remove(AHandle: TIdStackSocketHandle);
  1186. begin
  1187. Lock;
  1188. try
  1189. if FD_ISSET(AHandle, FFDSet) then begin
  1190. Dec(FCount);
  1191. FD_CLR(AHandle, FFDSet);
  1192. end;
  1193. finally
  1194. Unlock;
  1195. end;
  1196. end;//
  1197. function TIdStackLibc.WSTranslateSocketErrorMsg(const AErr: Integer): string;
  1198. begin
  1199. //we override this function for the herr constants that
  1200. //are returned by the DNS functions
  1201. case AErr of
  1202. Libc.HOST_NOT_FOUND: Result := RSStackHOST_NOT_FOUND;
  1203. Libc.TRY_AGAIN: Result := RSStackTRY_AGAIN;
  1204. Libc.NO_RECOVERY: Result := RSStackNO_RECOVERY;
  1205. Libc.NO_DATA: Result := RSStackNO_DATA;
  1206. else
  1207. Result := inherited WSTranslateSocketErrorMsg(AErr);
  1208. end;
  1209. end;
  1210. procedure TIdSocketListLibc.SetFDSet(var VSet: TFDSet);
  1211. begin
  1212. Lock;
  1213. try
  1214. FFDSet := VSet;
  1215. finally
  1216. Unlock;
  1217. end;
  1218. end;
  1219. class function TIdSocketListLibc.Select(AReadList: TIdSocketList; AWriteList: TIdSocketList;
  1220. AExceptList: TIdSocketList; const ATimeout: Integer = IdTimeoutInfinite): Boolean;
  1221. var
  1222. LReadSet: TFDSet;
  1223. LWriteSet: TFDSet;
  1224. LExceptSet: TFDSet;
  1225. LPReadSet: PFDSet;
  1226. LPWriteSet: PFDSet;
  1227. LPExceptSet: PFDSet;
  1228. procedure ReadSet(AList: TIdSocketList; var ASet: TFDSet; var APSet: PFDSet);
  1229. begin
  1230. if AList <> nil then begin
  1231. TIdSocketListLibc(AList).GetFDSet(ASet);
  1232. APSet := @ASet;
  1233. end else begin
  1234. APSet := nil;
  1235. end;
  1236. end;
  1237. begin
  1238. ReadSet(AReadList, LReadSet, LPReadSet);
  1239. ReadSet(AWriteList, LWriteSet, LPWriteSet);
  1240. ReadSet(AExceptList, LExceptSet, LPExceptSet);
  1241. //
  1242. Result := FDSelect(LPReadSet, LPWriteSet, LPExceptSet, ATimeout) >0;
  1243. //
  1244. if AReadList <> nil then begin
  1245. TIdSocketListLibc(AReadList).SetFDSet(LReadSet);
  1246. end;
  1247. if AWriteList <> nil then begin
  1248. TIdSocketListLibc(AWriteList).SetFDSet(LWriteSet);
  1249. end;
  1250. if AExceptList <> nil then begin
  1251. TIdSocketListLibc(AExceptList).SetFDSet(LExceptSet);
  1252. end;
  1253. end;
  1254. function TIdSocketListLibc.SelectRead(const ATimeout: Integer): Boolean;
  1255. var
  1256. LSet: TFDSet;
  1257. begin
  1258. Lock;
  1259. try
  1260. LSet := FFDSet;
  1261. // select() updates this structure on return,
  1262. // so we need to copy it each time we need it
  1263. finally
  1264. Unlock;
  1265. end;
  1266. Result := FDSelect(@LSet, nil, nil, ATimeout) > 0;
  1267. end;
  1268. function TIdSocketListLibc.SelectReadList(var VSocketList: TIdSocketList;
  1269. const ATimeout: Integer = IdTimeoutInfinite): Boolean;
  1270. var
  1271. LSet: TFDSet;
  1272. begin
  1273. Lock;
  1274. try
  1275. LSet := FFDSet;
  1276. // select() updates this structure on return,
  1277. // so we need to copy it each time we need it
  1278. finally
  1279. Unlock;
  1280. end;
  1281. Result := FDSelect(@LSet, nil, nil, ATimeout) > 0;
  1282. if Result then begin
  1283. if VSocketList = nil then begin
  1284. VSocketList := TIdSocketList.CreateSocketList;
  1285. end;
  1286. TIdSocketListLibc(VSocketList).SetFDSet(LSet);
  1287. end;
  1288. end;
  1289. procedure TIdStackLibc.SetBlocking(ASocket: TIdStackSocketHandle;
  1290. const ABlocking: Boolean);
  1291. var
  1292. LFlags: Integer;
  1293. //LValue: UInt32;
  1294. begin
  1295. LFlags := CheckForSocketError(Libc.fcntl(ASocket, F_GETFL, 0));
  1296. if ABlocking then begin
  1297. LFlags := LFlags and not O_NONBLOCK;
  1298. end else begin
  1299. LFlags := LFlags or O_NONBLOCK;
  1300. end;
  1301. CheckForSocketError(Libc.fcntl(ASocket, F_SETFL, LFlags));
  1302. {
  1303. LValue := UInt32(not ABlocking);
  1304. CheckForSocketError(Libc.ioctl(ASocket, FIONBIO, @LValue));
  1305. }
  1306. end;
  1307. (*
  1308. Why did I remove this again?
  1309. 1) it sends SIGPIPE even if the socket is created with the no-sigpipe bit set
  1310. that could be solved by blocking sigpipe within this thread
  1311. This is probably a bug in the Linux kernel, but we could work around it
  1312. by blocking that signal for the time of sending the file (just get the
  1313. sigprocmask, see if pipe bit is set, if not set it and remove again after
  1314. sending the file)
  1315. But the more serious reason is another one, which exists in Windows too:
  1316. 2) I think that ServeFile is misdesigned:
  1317. ServeFile does not raise an exception if it didn't send all the bytes.
  1318. Now what happens if I have OnExecute assigned like this
  1319. AThread.Connection.ServeFile('...', True); // <-- true to send via kernel
  1320. is that it will return 0, but notice that in this case I didn't ask for the
  1321. result. Net effect is that the thread will loop in OnExecute even if the
  1322. socket is long gone. This doesn't fit Indy semantics at all, exceptions are
  1323. always raised if the remote end disconnects. Even if I would do
  1324. AThread.Connection.ServeFile('...', False);
  1325. then it would raise an exception.
  1326. I think this is a big flaw in the design of the ServeFile function.
  1327. Maybe GServeFile should only return the bytes sent, but then
  1328. TCPConnection.ServeFile() should raise an exception if GServeFile didn't
  1329. send all the bytes.
  1330. JM Berg, 2002-09-09
  1331. function ServeFile(ASocket: TIdStackSocketHandle; AFileName: string): UInt32;
  1332. var
  1333. LFileHandle: integer;
  1334. offset: integer;
  1335. stat: _stat;
  1336. begin
  1337. LFileHandle := open(PAnsiChar(AFileName), O_RDONLY);
  1338. try
  1339. offset := 0;
  1340. fstat(LFileHandle, stat);
  1341. Result := sendfile(ASocket, LFileHandle, offset, stat.st_size);
  1342. //** if Result = UInt32(-1) then RaiseLastOSError;
  1343. finally libc.__close(LFileHandle); end;
  1344. end;
  1345. *)
  1346. function TIdSocketListLibc.Clone: TIdSocketList;
  1347. begin
  1348. Result := TIdSocketListLibc.Create;
  1349. try
  1350. Lock;
  1351. try
  1352. TIdSocketListLibc(Result).SetFDSet(FFDSet);
  1353. finally
  1354. Unlock;
  1355. end;
  1356. except
  1357. FreeAndNil(Result);
  1358. raise;
  1359. end;
  1360. end;
  1361. initialization
  1362. GSocketListClass := TIdSocketListLibc;
  1363. end.