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