IdStackVCLPosix.pas 48 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534
  1. unit IdStackVCLPosix;
  2. interface
  3. {$I IdCompilerDefines.inc}
  4. {IMPORTANT!!!
  5. Platform warnings in this unit should be disabled because Indy we have no
  6. intention of porting this unit to Windows or any non-Unix-like operating system.
  7. Any differences between Unix-like operating systems have to dealt with in other
  8. ways.
  9. }
  10. {$I IdSymbolPlatformOff.inc}
  11. {$I IdUnitPlatformOff.inc}
  12. uses
  13. Classes,
  14. IdCTypes,
  15. Posix.SysSelect,
  16. Posix.SysSocket,
  17. Posix.SysTime,
  18. IdStack,
  19. IdStackConsts,
  20. IdGlobal,
  21. IdStackBSDBase;
  22. type
  23. {$IFDEF USE_VCL_POSIX}
  24. {$IFDEF ANDROID}
  25. EIdAccessWifiStatePermissionNeeded = class(EIdAndroidPermissionNeeded);
  26. EIdAccessNetworkStatePermissionNeeded = class(EIdAndroidPermissionNeeded);
  27. {$ENDIF}
  28. {$ENDIF}
  29. TIdSocketListVCLPosix = class (TIdSocketList)
  30. protected
  31. FCount: Integer;
  32. FFDSet: fd_set;
  33. //
  34. class function FDSelect(AReadSet, AWriteSet,
  35. AExceptSet: Pfd_set; const ATimeout: Integer): Integer;
  36. function GetItem(AIndex: Integer): TIdStackSocketHandle; override;
  37. public
  38. procedure Add(AHandle: TIdStackSocketHandle); override;
  39. procedure Remove(AHandle: TIdStackSocketHandle); override;
  40. function Count: Integer; override;
  41. procedure Clear; override;
  42. function Clone: TIdSocketList; override;
  43. function ContainsSocket(AHandle: TIdStackSocketHandle): Boolean; override;
  44. procedure GetFDSet(var VSet: fd_set);
  45. procedure SetFDSet(var VSet: fd_set);
  46. class function Select(AReadList: TIdSocketList; AWriteList: TIdSocketList;
  47. AExceptList: TIdSocketList; const ATimeout: Integer = IdTimeoutInfinite): Boolean; override;
  48. function SelectRead(const ATimeout: Integer = IdTimeoutInfinite): Boolean; override;
  49. function SelectReadList(var VSocketList: TIdSocketList;
  50. const ATimeout: Integer = IdTimeoutInfinite): Boolean; override;
  51. end;
  52. TIdStackVCLPosix = class(TIdStackBSDBase)
  53. protected
  54. procedure WriteChecksumIPv6(s: TIdStackSocketHandle; var VBuffer: TIdBytes;
  55. const AOffset: Integer; const AIP: String; const APort: TIdPort);
  56. function GetLastError: Integer;
  57. procedure SetLastError(const AError: Integer);
  58. function HostByName(const AHostName: string;
  59. const AIPVersion: TIdIPVersion = ID_DEFAULT_IP_VERSION): string; override;
  60. function ReadHostName: string; override;
  61. function WSCloseSocket(ASocket: TIdStackSocketHandle): Integer; override;
  62. function WSRecv(ASocket: TIdStackSocketHandle; var ABuffer;
  63. const ABufferLength, AFlags: Integer): Integer; override;
  64. function WSSend(ASocket: TIdStackSocketHandle; const ABuffer;
  65. const ABufferLength, AFlags: Integer): Integer; override;
  66. function WSShutdown(ASocket: TIdStackSocketHandle; AHow: Integer): Integer; override;
  67. {$IFNDEF VCL_XE3_OR_ABOVE}
  68. procedure WSGetSocketOption(ASocket: TIdStackSocketHandle; ALevel: TIdSocketOptionLevel;
  69. AOptName: TIdSocketOption; var AOptVal; var AOptLen: Integer); override;
  70. procedure WSSetSocketOption(ASocket: TIdStackSocketHandle; ALevel: TIdSocketOptionLevel;
  71. AOptName: TIdSocketOption; const AOptVal; const AOptLen: Integer); override;
  72. {$ENDIF}
  73. public
  74. constructor Create; override;
  75. destructor Destroy; override;
  76. procedure SetBlocking(ASocket: TIdStackSocketHandle; const ABlocking: Boolean); override;
  77. function WouldBlock(const AResult: Integer): Boolean; override;
  78. function Accept(ASocket: TIdStackSocketHandle; var VIP: string; var VPort: TIdPort;
  79. var VIPVersion: TIdIPVersion): TIdStackSocketHandle; override;
  80. procedure Bind(ASocket: TIdStackSocketHandle; const AIP: string;
  81. const APort: TIdPort; const AIPVersion: TIdIPVersion = ID_DEFAULT_IP_VERSION); override;
  82. procedure Connect(const ASocket: TIdStackSocketHandle; const AIP: string;
  83. const APort: TIdPort; const AIPVersion: TIdIPVersion = ID_DEFAULT_IP_VERSION); override;
  84. function HostByAddress(const AAddress: string;
  85. const AIPVersion: TIdIPVersion = ID_DEFAULT_IP_VERSION): string; override;
  86. function WSGetLastError: Integer; override;
  87. procedure WSSetLastError(const AErr : Integer); override;
  88. function WSGetServByName(const AServiceName: string): TIdPort; override;
  89. procedure AddServByPortToList(const APortNumber: TIdPort; AAddresses: TStrings); override;
  90. procedure GetPeerName(ASocket: TIdStackSocketHandle; var VIP: string;
  91. var VPort: TIdPort; var VIPVersion: TIdIPVersion); override;
  92. procedure GetSocketName(ASocket: TIdStackSocketHandle; var VIP: string;
  93. var VPort: TIdPort; var VIPVersion: TIdIPVersion); override;
  94. procedure Listen(ASocket: TIdStackSocketHandle; ABackLog: Integer); override;
  95. function HostToNetwork(AValue: UInt16): UInt16; override;
  96. function NetworkToHost(AValue: UInt16): UInt16; override;
  97. function HostToNetwork(AValue: UInt32): UInt32; override;
  98. function NetworkToHost(AValue: UInt32): UInt32; override;
  99. function HostToNetwork(AValue: TIdUInt64): TIdUInt64; override;
  100. function NetworkToHost(AValue: TIdUInt64): TIdUInt64; override;
  101. function RecvFrom(const ASocket: TIdStackSocketHandle;
  102. var VBuffer; const ALength, AFlags: Integer; var VIP: string;
  103. var VPort: TIdPort; var VIPVersion: TIdIPVersion): Integer; override;
  104. function ReceiveMsg(ASocket: TIdStackSocketHandle;
  105. var VBuffer: TIdBytes; APkt: TIdPacketInfo): UInt32; override;
  106. procedure WSSendTo(ASocket: TIdStackSocketHandle; const ABuffer;
  107. const ABufferLength, AFlags: Integer; const AIP: string; const APort: TIdPort;
  108. AIPVersion: TIdIPVersion = ID_DEFAULT_IP_VERSION); override;
  109. function WSSocket(AFamily : Integer; AStruct : TIdSocketType; AProtocol: Integer;
  110. const ANonBlocking: Boolean = False): TIdStackSocketHandle; override;
  111. procedure Disconnect(ASocket: TIdStackSocketHandle); override;
  112. {$IFDEF VCL_XE3_OR_ABOVE}
  113. procedure GetSocketOption(ASocket: TIdStackSocketHandle; ALevel: TIdSocketOptionLevel;
  114. AOptName: TIdSocketOption; var AOptVal; var AOptLen: Integer); override;
  115. procedure SetSocketOption(ASocket: TIdStackSocketHandle; ALevel: TIdSocketOptionLevel;
  116. AOptName: TIdSocketOption; const AOptVal; const AOptLen: Integer); override;
  117. {$ENDIF}
  118. function SupportsIPv4: Boolean; overload; override;
  119. function SupportsIPv6: Boolean; overload; override;
  120. function CheckIPVersionSupport(const AIPVersion: TIdIPVersion): boolean; override;
  121. //In Windows, this writes a checksum into a buffer. In Linux, it would probably
  122. //simply have the kernal write the checksum with something like this (RFC 2292):
  123. //
  124. // int offset = 2;
  125. // setsockopt(fd, IPPROTO_IPV6, IPV6_CHECKSUM, &offset, sizeof(offset));
  126. //
  127. // Note that this should be called
  128. //IMMEDIATELY before you do a SendTo because the Local IPv6 address might change
  129. procedure WriteChecksum(s : TIdStackSocketHandle; var VBuffer : TIdBytes;
  130. const AOffset : Integer; const AIP : String; const APort : TIdPort;
  131. const AIPVersion: TIdIPVersion = ID_DEFAULT_IP_VERSION); override;
  132. function IOControl(const s: TIdStackSocketHandle; const cmd: UInt32;
  133. var arg: UInt32): Integer; override;
  134. procedure GetLocalAddressList(AAddresses: TIdStackLocalAddressList); override;
  135. end;
  136. implementation
  137. {$O-}
  138. // On Mac M1, it seems as though DNS resolution is not cached by the system.
  139. // so we're going to cache it here.
  140. {$IFDEF DCC}
  141. {$IFDEF CPUARM64}
  142. // DCC defines MACOS for both OSX and iOS
  143. {$IFDEF MACOS}
  144. {$DEFINE USE_DNSCACHE}
  145. {$ENDIF}
  146. {$ENDIF}
  147. {$ENDIF}
  148. {$IFDEF FPC}
  149. {$IFDEF CPUAARCH64}
  150. // FPC defines DARWIN for both OSX and iOS
  151. {$IFDEF DARWIN}
  152. {$DEFINE USE_DNSCACHE}
  153. {$ENDIF}
  154. {$ENDIF}
  155. {$ENDIF}
  156. uses
  157. IdResourceStrings,
  158. IdResourceStringsUnix,
  159. IdResourceStringsVCLPosix,
  160. IdException,
  161. {$IFDEF USE_DNSCACHE}IdStackDnsHostCache,{$ENDIF}
  162. IdVCLPosixSupplemental,
  163. Posix.Base,
  164. Posix.ArpaInet,
  165. Posix.Errno,
  166. Posix.NetDB,
  167. {$IFDEF HAS_getifaddrs}
  168. Posix.NetIf,
  169. {$ENDIF}
  170. Posix.NetinetIn,
  171. Posix.StrOpts,
  172. Posix.SysTypes,
  173. Posix.SysUio,
  174. Posix.Unistd,
  175. Posix.Fcntl,
  176. SysUtils;
  177. {$UNDEF HAS_MSG_NOSIGNAL}
  178. {$IFDEF LINUX} //this LINUX ifdef is deliberate
  179. {$DEFINE HAS_MSG_NOSIGNAL}
  180. {$ENDIF}
  181. const
  182. {$IFDEF HAS_MSG_NOSIGNAL}
  183. //fancy little trick since OS X does not have MSG_NOSIGNAL
  184. Id_MSG_NOSIGNAL = MSG_NOSIGNAL;
  185. {$ELSE}
  186. Id_MSG_NOSIGNAL = 0;
  187. {$ENDIF}
  188. Id_WSAEPIPE = EPIPE;
  189. //helper functions for some structs
  190. {Note: These hide an API difference in structures.
  191. BSD 4.4 introduced a minor API change. sa_family was changed from a 16bit
  192. word to an 8 bit byteee and an 8 bit byte feild named sa_len was added.
  193. }
  194. procedure InitSockAddr_In(var VSock : SockAddr_In);
  195. {$IFDEF USE_INLINE} inline; {$ENDIF}
  196. begin
  197. FillChar(VSock, SizeOf(SockAddr_In), 0);
  198. VSock.sin_family := PF_INET;
  199. {$IFDEF SOCK_HAS_SINLEN}
  200. VSock.sin_len := SizeOf(SockAddr_In);
  201. {$ENDIF}
  202. end;
  203. procedure InitSockAddr_in6(var VSock : SockAddr_in6);
  204. {$IFDEF USE_INLINE} inline; {$ENDIF}
  205. begin
  206. FillChar(VSock, SizeOf(SockAddr_in6), 0);
  207. {$IFDEF SOCK_HAS_SINLEN}
  208. VSock.sin6_len := SizeOf(SockAddr_in6);
  209. {$ENDIF}
  210. VSock.sin6_family := PF_INET6;
  211. end;
  212. //
  213. { TIdSocketListVCLPosix }
  214. procedure TIdSocketListVCLPosix.Add(AHandle: TIdStackSocketHandle);
  215. begin
  216. Lock;
  217. try
  218. if not __FD_ISSET(AHandle, FFDSet) then begin
  219. if Count >= FD_SETSIZE then begin
  220. raise EIdStackSetSizeExceeded.Create(RSSetSizeExceeded);
  221. end;
  222. __FD_SET(AHandle, FFDSet);
  223. Inc(FCount);
  224. end;
  225. finally
  226. Unlock;
  227. end;
  228. end;
  229. procedure TIdSocketListVCLPosix.Clear;
  230. begin
  231. Lock;
  232. try
  233. __FD_ZERO(FFDSet);
  234. FCount := 0;
  235. finally
  236. Unlock;
  237. end;
  238. end;
  239. function TIdSocketListVCLPosix.Clone: TIdSocketList;
  240. begin
  241. Result := TIdSocketListVCLPosix.Create;
  242. try
  243. Lock;
  244. try
  245. TIdSocketListVCLPosix(Result).SetFDSet(FFDSet);
  246. finally
  247. Unlock;
  248. end;
  249. except
  250. FreeAndNil(Result);
  251. raise;
  252. end;
  253. end;
  254. function TIdSocketListVCLPosix.ContainsSocket(
  255. AHandle: TIdStackSocketHandle): Boolean;
  256. begin
  257. Lock;
  258. try
  259. Result := __FD_ISSET(AHandle, FFDSet);
  260. finally
  261. Unlock;
  262. end;
  263. end;
  264. function TIdSocketListVCLPosix.Count: Integer;
  265. begin
  266. Lock;
  267. try
  268. Result := FCount;
  269. finally
  270. Unlock;
  271. end;
  272. end;
  273. class function TIdSocketListVCLPosix.FDSelect(AReadSet, AWriteSet,
  274. AExceptSet: Pfd_set; const ATimeout: Integer): Integer;
  275. var
  276. LTime: TimeVal;
  277. LTimePtr: PTimeVal;
  278. begin
  279. if ATimeout = IdTimeoutInfinite then begin
  280. LTimePtr := nil;
  281. end else begin
  282. LTime.tv_sec := ATimeout div 1000;
  283. LTime.tv_usec := (ATimeout mod 1000) * 1000;
  284. LTimePtr := @LTime;
  285. end;
  286. // TODO: calculate the actual nfds value based on the Sets provided...
  287. Result := Posix.SysSelect.select(FD_SETSIZE, AReadSet, AWriteSet, AExceptSet, LTimePtr);
  288. end;
  289. procedure TIdSocketListVCLPosix.GetFDSet(var VSet: fd_set);
  290. begin
  291. Lock;
  292. try
  293. VSet := FFDSet;
  294. finally
  295. Unlock;
  296. end;
  297. end;
  298. function TIdSocketListVCLPosix.GetItem(AIndex: Integer): TIdStackSocketHandle;
  299. var
  300. LIndex, i: Integer;
  301. begin
  302. Result := 0;
  303. Lock;
  304. try
  305. LIndex := 0;
  306. //? use FMaxHandle div x
  307. for i:= 0 to FD_SETSIZE - 1 do begin
  308. if __FD_ISSET(i, FFDSet) then begin
  309. if LIndex = AIndex then begin
  310. Result := i;
  311. Break;
  312. end;
  313. Inc(LIndex);
  314. end;
  315. end;
  316. finally
  317. Unlock;
  318. end;
  319. end;
  320. procedure TIdSocketListVCLPosix.Remove(AHandle: TIdStackSocketHandle);
  321. begin
  322. Lock;
  323. try
  324. if __FD_ISSET(AHandle, FFDSet) then begin
  325. Dec(FCount);
  326. __FD_CLR(AHandle, FFDSet);
  327. end;
  328. finally
  329. Unlock;
  330. end;
  331. end;
  332. class function TIdSocketListVCLPosix.Select(AReadList, AWriteList,
  333. AExceptList: TIdSocketList; const ATimeout: Integer): Boolean;
  334. var
  335. LReadSet: fd_set;
  336. LWriteSet: fd_set;
  337. LExceptSet: fd_set;
  338. LPReadSet: Pfd_set;
  339. LPWriteSet: Pfd_set;
  340. LPExceptSet: Pfd_set;
  341. procedure ReadSet(AList: TIdSocketList; var ASet: fd_set; var APSet: Pfd_set);
  342. begin
  343. if AList <> nil then begin
  344. TIdSocketListVCLPosix(AList).GetFDSet(ASet);
  345. APSet := @ASet;
  346. end else begin
  347. APSet := nil;
  348. end;
  349. end;
  350. begin
  351. ReadSet(AReadList, LReadSet, LPReadSet);
  352. ReadSet(AWriteList, LWriteSet, LPWriteSet);
  353. ReadSet(AExceptList, LExceptSet, LPExceptSet);
  354. //
  355. Result := FDSelect(LPReadSet, LPWriteSet, LPExceptSet, ATimeout) >0;
  356. //
  357. if AReadList <> nil then begin
  358. TIdSocketListVCLPosix(AReadList).SetFDSet(LReadSet);
  359. end;
  360. if AWriteList <> nil then begin
  361. TIdSocketListVCLPosix(AWriteList).SetFDSet(LWriteSet);
  362. end;
  363. if AExceptList <> nil then begin
  364. TIdSocketListVCLPosix(AExceptList).SetFDSet(LExceptSet);
  365. end;
  366. end;
  367. function TIdSocketListVCLPosix.SelectRead(const ATimeout: Integer): Boolean;
  368. var
  369. LSet: fd_set;
  370. begin
  371. Lock;
  372. try
  373. LSet := FFDSet;
  374. // select() updates this structure on return,
  375. // so we need to copy it each time we need it
  376. finally
  377. Unlock;
  378. end;
  379. Result := FDSelect(@LSet, nil, nil, ATimeout) > 0;
  380. end;
  381. function TIdSocketListVCLPosix.SelectReadList(var VSocketList: TIdSocketList;
  382. const ATimeout: Integer): Boolean;
  383. var
  384. LSet: fd_set;
  385. begin
  386. Lock;
  387. try
  388. LSet := FFDSet;
  389. // select() updates this structure on return,
  390. // so we need to copy it each time we need it
  391. finally
  392. Unlock;
  393. end;
  394. Result := FDSelect(@LSet, nil, nil, ATimeout) > 0;
  395. if Result then begin
  396. if VSocketList = nil then begin
  397. VSocketList := TIdSocketList.CreateSocketList;
  398. end;
  399. TIdSocketListVCLPosix(VSocketList).SetFDSet(LSet);
  400. end;
  401. end;
  402. procedure TIdSocketListVCLPosix.SetFDSet(var VSet: fd_set);
  403. begin
  404. Lock;
  405. try
  406. FFDSet := VSet;
  407. finally
  408. Unlock;
  409. end;
  410. end;
  411. { TIdStackVCLPosix }
  412. {
  413. IMPORTANT!!!
  414. Throughout much of this code, you will see stuff such as:
  415. var
  416. LAddrStore: sockaddr_storage;
  417. LAddrIPv4 : SockAddr_In absolute LAddrStore;
  418. LAddrIPv6 : sockaddr_in6 absolute LAddrStore;
  419. LAddr : sockaddr absolute LAddrStore;
  420. This is just a fancy way to do typecasting with various types of address type.
  421. Many functions take a sockaddr parameter but that parameter is typecast for various
  422. address types. The structures mentioned above are designed just for such
  423. typecasting. The reason we use sockaddr_storage instead of sockaddr is that
  424. we need something that is guaranteed to be able to contain various address types
  425. and sockaddr would be too short for some of them and we can't know what
  426. someone else will add to Indy as time goes by.
  427. }
  428. function TIdStackVCLPosix.Accept(ASocket: TIdStackSocketHandle; var VIP: string;
  429. var VPort: TIdPort; var VIPVersion: TIdIPVersion): TIdStackSocketHandle;
  430. var
  431. LN: socklen_t;
  432. LAddrStore: sockaddr_storage;
  433. LAddrIPv4 : SockAddr_In absolute LAddrStore;
  434. LAddrIPv6 : sockaddr_in6 absolute LAddrStore;
  435. LAddr : sockaddr absolute LAddrStore;
  436. begin
  437. LN := SizeOf(LAddrStore);
  438. Result := Posix.SysSocket.accept(ASocket, LAddr, LN);
  439. if Result <> -1 then begin
  440. {$IFDEF HAS_SOCKET_NOSIGPIPE}
  441. SetSocketOption(Result, SOL_SOCKET, SO_NOSIGPIPE, 1);
  442. {$ENDIF}
  443. case LAddrStore.ss_family of
  444. Id_PF_INET4: begin
  445. VIP := TranslateTInAddrToString( LAddrIPv4.sin_addr, Id_IPv4);
  446. VPort := ntohs(LAddrIPv4.sin_port);
  447. VIPVersion := Id_IPV4;
  448. end;
  449. Id_PF_INET6: begin
  450. VIP := TranslateTInAddrToString(LAddrIPv6.sin6_addr, Id_IPv6);
  451. VPort := ntohs(LAddrIPv6.sin6_port);
  452. VIPVersion := Id_IPV6;
  453. end
  454. else begin
  455. __close(Result);
  456. Result := Id_INVALID_SOCKET;
  457. IPVersionUnsupported;
  458. end;
  459. end;
  460. end else begin
  461. if GetLastError = EBADF then begin
  462. SetLastError(EINTR);
  463. end;
  464. end;
  465. end;
  466. {$IFDEF HAS_getifaddrs}
  467. function getifaddrs(var ifap: pifaddrs): Integer; cdecl; external libc name _PU + 'getifaddrs'; {do not localize}
  468. procedure freeifaddrs(ifap: pifaddrs); cdecl; external libc name _PU + 'freeifaddrs'; {do not localize}
  469. {$IFDEF HAS_if_nametoindex}
  470. function if_nametoindex(const ifname: PIdAnsiChar): UInt32; cdecl; external libc name _PU + 'if_nametoindex'; {do not localize}
  471. {$ENDIF}
  472. type
  473. TIdStackLocalAddressAccess = class(TIdStackLocalAddress)
  474. end;
  475. {$ELSE}
  476. {$IFDEF ANDROID}
  477. // TODO: implement getifaddrs() manually using code from https://github.com/morristech/android-ifaddrs
  478. {.$DEFINE HAS_getifaddrs}
  479. {$ENDIF}
  480. {$ENDIF}
  481. procedure TIdStackVCLPosix.GetLocalAddressList(AAddresses: TIdStackLocalAddressList);
  482. var
  483. {$IFDEF HAS_getifaddrs}
  484. LAddrList, LAddrInfo: pifaddrs;
  485. LSubNetStr: String;
  486. LAddress: TIdStackLocalAddress;
  487. LName: string;
  488. {$ELSE}
  489. LRetVal: Integer;
  490. LHostName: string;
  491. Hints: AddrInfo;
  492. LAddrList, LAddrInfo: pAddrInfo;
  493. {$IFDEF USE_MARSHALLED_PTRS}
  494. M: TMarshaller;
  495. {$ENDIF}
  496. {$ENDIF}
  497. begin
  498. // TODO: Using gethostname() and getaddrinfo() like this may not always return just
  499. // the machine's IP addresses. Technically speaking, they will return the local
  500. // hostname, and then return the address(es) to which that hostname resolves.
  501. // It is possible for a machine to (a) be configured such that its name does
  502. // not resolve to an IP, or (b) be configured such that its name resolves to
  503. // multiple IPs, only one of which belongs to the local machine. For better
  504. // results, we should use getifaddrs() on platforms that support it...
  505. {$IFDEF HAS_getifaddrs}
  506. if getifaddrs(LAddrList) = 0 then // TODO: raise an exception if it fails
  507. try
  508. AAddresses.BeginUpdate;
  509. try
  510. LAddrInfo := LAddrList;
  511. repeat
  512. if (LAddrInfo^.ifa_addr <> nil) and ((LAddrInfo^.ifa_flags and IFF_LOOPBACK) = 0) then
  513. begin
  514. LAddress := nil;
  515. case LAddrInfo^.ifa_addr^.sa_family of
  516. Id_PF_INET4: begin
  517. if LAddrInfo^.ifa_netmask <> nil then begin
  518. LSubNetStr := TranslateTInAddrToString( PSockAddr_In(LAddrInfo^.ifa_netmask)^.sin_addr, Id_IPv4);
  519. end else begin
  520. LSubNetStr := '';
  521. end;
  522. LAddress := TIdStackLocalAddressIPv4.Create(AAddresses, TranslateTInAddrToString( PSockAddr_In(LAddrInfo^.ifa_addr)^.sin_addr, Id_IPv4), LSubNetStr);
  523. end;
  524. Id_PF_INET6: begin
  525. LAddress := TIdStackLocalAddressIPv6.Create(AAddresses, TranslateTInAddrToString( PSockAddr_In6(LAddrInfo^.ifa_addr)^.sin6_addr, Id_IPv6));
  526. end;
  527. end;
  528. if LAddress <> nil then begin
  529. LName := String(LAddrInfo^.ifa_name);
  530. TIdStackLocalAddressAccess(LAddress).FDescription := LName;
  531. TIdStackLocalAddressAccess(LAddress).FFriendlyName := LName;
  532. TIdStackLocalAddressAccess(LAddress).FInterfaceName := LName;
  533. {$IFDEF HAS_if_nametoindex}
  534. TIdStackLocalAddressAccess(LAddress).FInterfaceIndex := if_nametoindex(LAddrInfo^.ifa_name);
  535. {$ENDIF}
  536. end;
  537. end;
  538. LAddrInfo := LAddrInfo^.ifa_next;
  539. until LAddrInfo = nil;
  540. finally
  541. AAddresses.EndUpdate;
  542. end;
  543. finally
  544. freeifaddrs(LAddrList);
  545. end;
  546. {$ELSE}
  547. // TODO: on Android, either implement getifaddrs() (https://github.com/morristech/android-ifaddrs)
  548. // or use the Java API to enumerate the local network interfaces and their IP addresses, eg:
  549. {
  550. var
  551. en, enumIpAddr: Enumeration;
  552. intf: NetworkInterface;
  553. inetAddress: InetAddress;
  554. LAddress: TIdStackLocalAddress;
  555. begin
  556. try
  557. en := NetworkInterface.getNetworkInterfaces;
  558. if en.hasMoreElements then begin
  559. AAddresses.BeginUpdate;
  560. try
  561. repeat
  562. intf := en.nextElement;
  563. enumIpAddr := intf.getInetAddresses;
  564. while enumIpAddr.hasMoreElements do begin
  565. inetAddress := enumIpAddr.nextElement;
  566. if not inetAddress.isLoopbackAddress then begin
  567. LAddress := nil;
  568. if (inetAddress instanceof Inet4Address) then begin
  569. LAddress := TIdStackLocalAddressIPv4.Create(AAddresses, inetAddress.getHostAddress.toString, ''); // TODO: subnet mask
  570. end
  571. else if (inetAddress instanceof Inet6Address) then begin
  572. LAddress := TIdStackLocalAddressIPv6.Create(AAddresses, inetAddress.getHostAddress.toString);
  573. end;
  574. if LAddress <> nil then begin
  575. TIdStackLocalAddressAccess(LAddress).FDescription := intf.getDisplayName;
  576. TIdStackLocalAddressAccess(LAddress).FInterfaceName := intf.getName;
  577. TIdStackLocalAddressAccess(LAddress).FInterfaceIndex := intf.getIndex (+1?);
  578. end;
  579. end;
  580. end;
  581. until not en.hasMoreElements;
  582. finally
  583. AAddresses.EndUpdate;
  584. end;
  585. end;
  586. except
  587. if not HasAndroidPermission('android.permission.ACCESS_NETWORK_STATE') then begin
  588. IndyRaiseOuterException(EIdAccessNetworkStatePermissionNeeded.CreateError(0, ''));
  589. end;
  590. if not HasAndroidPermission('android.permission.INTERNET') then begin
  591. IndyRaiseOuterException(EIdInternetPermissionNeeded.CreateError(0, ''));
  592. end;
  593. raise;
  594. end;
  595. end;
  596. Note that this requires the application to have ACCESS_NETWORK_STATE and INTERNET permissions.
  597. Or:
  598. uses
  599. if XE7+
  600. Androidapi.Helpers
  601. else
  602. FMX.Helpers.Android
  603. ;
  604. var
  605. LWifiManager: WifiManager;
  606. LWifiInfo: WifiInfo;
  607. LIPAddress: Integer;
  608. LAddress: TIdStackLocalAddressIPv4;
  609. begin
  610. try
  611. LWifiManager := (WifiManager) GetActivityContext.getSystemService(WIFI_SERVICE);
  612. LWifiInfo := LWifiManager.getConnectionInfo;
  613. LIPAddress := LWifiInfo.getIpAddress;
  614. // TODO: can we use the NetworkId or MacAddress to help find the network interface name and index?
  615. except
  616. if not HasAndroidPermission('android.permission.ACCESS_WIFI_STATE') then begin
  617. IndyRaiseOuterException(EIdAccessWifiStatePermissionNeeded.CreateError(0, ''));
  618. end;
  619. raise;
  620. end;
  621. // WiFiInfo only supports IPv4
  622. LAddress := TIdStackLocalAddressIPv4.Create(AAddresses,
  623. Format('%d.%d.%d.%d', [LIPAddress and $ff, (LIPAddress shr 8) and $ff, (LIPAddress shr 16) and $ff, (LIPAddress shr 24) and $ff]),
  624. '' // TODO: subnet mask
  625. );
  626. LAddress.FDescription := ?; // LWifiInfo.getNetworkId()? LWifiInfo.getSSID()? LWifiInfo.toString()?
  627. LAddress.FInterfaceName := ?;
  628. LAddress.FInterfaceIndex := ?;
  629. end;
  630. This requires only ACCESS_WIFI_STATE permission.
  631. }
  632. //IMPORTANT!!!
  633. //
  634. //The Hints structure must be zeroed out or you might get an AV.
  635. //I've seen this in Mac OS X
  636. FillChar(Hints, SizeOf(Hints), 0);
  637. Hints.ai_family := PF_UNSPEC; // returns both IPv4 and IPv6 addresses
  638. Hints.ai_socktype := SOCK_STREAM;
  639. LHostName := HostName;
  640. LRetVal := getaddrinfo(
  641. {$IFDEF USE_MARSHALLED_PTRS}
  642. M.AsAnsi(LHostName).ToPointer
  643. {$ELSE}
  644. PAnsiChar(
  645. {$IFDEF STRING_IS_ANSI}
  646. LHostName
  647. {$ELSE}
  648. AnsiString(LHostName) // explicit convert to Ansi
  649. {$ENDIF}
  650. )
  651. {$ENDIF},
  652. nil, Hints, LAddrList);
  653. if LRetVal <> 0 then begin
  654. if LRetVal = EAI_SYSTEM then begin
  655. RaiseLastOSError;
  656. end else begin
  657. raise EIdReverseResolveError.CreateFmt(RSReverseResolveError, [LHostName, gai_strerror(LRetVal), LRetVal]);
  658. end;
  659. end;
  660. try
  661. AAddresses.BeginUpdate;
  662. try
  663. LAddrInfo := LAddrList;
  664. repeat
  665. case LAddrInfo^.ai_addr^.sa_family of
  666. Id_PF_INET4 :
  667. begin
  668. TIdStackLocalAddressIPv4.Create(AAddresses, TranslateTInAddrToString( PSockAddr_In(LAddrInfo^.ai_addr)^.sin_addr, Id_IPv4), ''); // TODO: SubNet
  669. end;
  670. Id_PF_INET6 :
  671. begin
  672. TIdStackLocalAddressIPv6.Create(AAddresses, TranslateTInAddrToString( PSockAddr_In6(LAddrInfo^.ai_addr)^.sin6_addr, Id_IPv6));
  673. end;
  674. end;
  675. LAddrInfo := LAddrInfo^.ai_next;
  676. until LAddrInfo = nil;
  677. finally
  678. AAddresses.EndUpdate;
  679. end;
  680. finally
  681. freeaddrinfo(LAddrList^);
  682. end;
  683. {$ENDIF}
  684. end;
  685. procedure TIdStackVCLPosix.Bind(ASocket: TIdStackSocketHandle;
  686. const AIP: string; const APort: TIdPort; const AIPVersion: TIdIPVersion);
  687. var
  688. LAddrStore: sockaddr_storage;
  689. LAddrIPv4 : SockAddr_In absolute LAddrStore;
  690. LAddrIPv6 : sockaddr_in6 absolute LAddrStore;
  691. LAddr : sockaddr absolute LAddrStore;
  692. begin
  693. case AIPVersion of
  694. Id_IPv4: begin
  695. InitSockAddr_In(LAddrIPv4);
  696. if AIP <> '' then begin
  697. TranslateStringToTInAddr(AIP, LAddrIPv4.sin_addr, Id_IPv4);
  698. end;
  699. LAddrIPv4.sin_port := htons(APort);
  700. CheckForSocketError(Posix.SysSocket.bind(ASocket, LAddr, SizeOf(LAddrIPv4)));
  701. end;
  702. Id_IPv6: begin
  703. InitSockAddr_in6(LAddrIPv6);
  704. if AIP <> '' then begin
  705. TranslateStringToTInAddr(AIP, LAddrIPv6.sin6_addr, Id_IPv6);
  706. end;
  707. LAddrIPv6.sin6_port := htons(APort);
  708. CheckForSocketError(Posix.SysSocket.bind(ASocket,LAddr, SizeOf(LAddrIPv6)));
  709. end;
  710. else begin
  711. IPVersionUnsupported;
  712. end;
  713. end;
  714. end;
  715. function TIdStackVCLPosix.CheckIPVersionSupport(
  716. const AIPVersion: TIdIPVersion): boolean;
  717. var
  718. LTmpSocket: TIdStackSocketHandle;
  719. begin
  720. // TODO: on nix systems (or maybe just Linux?), an alternative would be to
  721. // check for the existance of the '/proc/net/if_inet6' kernel pseudo-file
  722. LTmpSocket := WSSocket(IdIPFamily[AIPVersion], Id_SOCK_STREAM, Id_IPPROTO_IP );
  723. Result := LTmpSocket <> Id_INVALID_SOCKET;
  724. if Result then begin
  725. WSCloseSocket(LTmpSocket);
  726. end;
  727. end;
  728. procedure TIdStackVCLPosix.Connect(const ASocket: TIdStackSocketHandle;
  729. const AIP: string; const APort: TIdPort; const AIPVersion: TIdIPVersion);
  730. var
  731. LAddrStore: sockaddr_storage;
  732. LAddrIPv4 : SockAddr_In absolute LAddrStore;
  733. LAddrIPv6 : sockaddr_in6 absolute LAddrStore;
  734. LAddr : sockaddr absolute LAddrStore;
  735. begin
  736. case AIPVersion of
  737. Id_IPv4: begin
  738. InitSockAddr_In(LAddrIPv4);
  739. TranslateStringToTInAddr(AIP, LAddrIPv4.sin_addr, Id_IPv4);
  740. LAddrIPv4.sin_port := htons(APort);
  741. CheckForSocketError(Posix.SysSocket.connect(ASocket, LAddr, SizeOf(LAddrIPv4)));
  742. end;
  743. Id_IPv6: begin
  744. InitSockAddr_in6(LAddrIPv6);
  745. TranslateStringToTInAddr(AIP, LAddrIPv6.sin6_addr, Id_IPv6);
  746. LAddrIPv6.sin6_port := htons(APort);
  747. CheckForSocketError(Posix.SysSocket.connect(ASocket, LAddr, SizeOf(LAddrIPv6)));
  748. end;
  749. else begin
  750. IPVersionUnsupported;
  751. end;
  752. end;
  753. end;
  754. constructor TIdStackVCLPosix.Create;
  755. begin
  756. inherited Create;
  757. end;
  758. destructor TIdStackVCLPosix.Destroy;
  759. begin
  760. inherited Destroy;
  761. end;
  762. procedure TIdStackVCLPosix.Disconnect(ASocket: TIdStackSocketHandle);
  763. begin
  764. // Windows uses Id_SD_Send, Linux should use Id_SD_Both
  765. WSShutdown(ASocket, Id_SD_Both);
  766. // SO_LINGER is false - socket may take a little while to actually close after this
  767. WSCloseSocket(ASocket);
  768. end;
  769. function TIdStackVCLPosix.GetLastError: Integer;
  770. begin
  771. Result := errno;
  772. end;
  773. procedure TIdStackVCLPosix.GetPeerName(ASocket: TIdStackSocketHandle;
  774. var VIP: string; var VPort: TIdPort; var VIPVersion: TIdIPVersion);
  775. var
  776. i: socklen_t;
  777. LAddrStore: sockaddr_storage;
  778. LAddrIPv4 : SockAddr_In absolute LAddrStore;
  779. LAddrIPv6 : sockaddr_in6 absolute LAddrStore;
  780. LAddr : sockaddr absolute LAddrStore;
  781. begin
  782. i := SizeOf(LAddrStore);
  783. CheckForSocketError(Posix.SysSocket.getpeername(ASocket, LAddr, i));
  784. case LAddrStore.ss_family of
  785. Id_PF_INET4: begin
  786. VIP := TranslateTInAddrToString(LAddrIPv4.sin_addr, Id_IPv4);
  787. VPort := ntohs(LAddrIPv4.sin_port);
  788. VIPVersion := Id_IPV4;
  789. end;
  790. Id_PF_INET6: begin
  791. VIP := TranslateTInAddrToString(LAddrIPv6.sin6_addr, Id_IPv6);
  792. VPort := ntohs(LAddrIPv6.sin6_port);
  793. VIPVersion := Id_IPV6;
  794. end;
  795. else begin
  796. IPVersionUnsupported;
  797. end;
  798. end;
  799. end;
  800. procedure TIdStackVCLPosix.GetSocketName(ASocket: TIdStackSocketHandle;
  801. var VIP: string; var VPort: TIdPort; var VIPVersion: TIdIPVersion);
  802. var
  803. LiSize: socklen_t;
  804. LAddrStore: sockaddr_storage;
  805. LAddrIPv4 : SockAddr_In absolute LAddrStore;
  806. LAddrIPv6 : sockaddr_in6 absolute LAddrStore;
  807. LAddr : sockaddr absolute LAddrStore;
  808. begin
  809. LiSize := SizeOf(LAddrStore);
  810. CheckForSocketError(getsockname(ASocket, LAddr, LiSize));
  811. case LAddrStore.ss_family of
  812. Id_PF_INET4: begin
  813. VIP := TranslateTInAddrToString(LAddrIPv4.sin_addr, Id_IPv4);
  814. VPort := ntohs(LAddrIPv4.sin_port);
  815. VIPVersion := Id_IPV4;
  816. end;
  817. Id_PF_INET6: begin
  818. VIP := TranslateTInAddrToString(LAddrIPv6.sin6_addr, Id_IPv6);
  819. VPort := ntohs(LAddrIPv6.sin6_port);
  820. VIPVersion := Id_IPV6;
  821. end;
  822. else begin
  823. IPVersionUnsupported;
  824. end;
  825. end;
  826. end;
  827. function TIdStackVCLPosix.HostByAddress(const AAddress: string;
  828. const AIPVersion: TIdIPVersion): string;
  829. var
  830. LiSize: socklen_t;
  831. LAddrStore: sockaddr_storage;
  832. LAddrIPv4 : SockAddr_In absolute LAddrStore;
  833. LAddrIPv6 : sockaddr_in6 absolute LAddrStore;
  834. LAddr : sockaddr absolute LAddrStore;
  835. LHostName : array[0..NI_MAXHOST] of TIdAnsiChar;
  836. {$IFDEF USE_MARSHALLED_PTRS}
  837. LHostNamePtr: TPtrWrapper;
  838. {$ENDIF}
  839. LRet : Integer;
  840. LHints : addrinfo;
  841. LAddrInfo: pAddrInfo;
  842. begin
  843. LiSize := 0;
  844. case AIPVersion of
  845. Id_IPv4 :
  846. begin
  847. InitSockAddr_In(LAddrIPv4);
  848. TranslateStringToTInAddr(AAddress,LAddrIPv4.sin_addr,Id_IPv4);
  849. LiSize := SizeOf(SockAddr_In);
  850. end;
  851. Id_IPv6 :
  852. begin
  853. InitSockAddr_In6(LAddrIPv6);
  854. TranslateStringToTInAddr(AAddress,LAddrIPv6.sin6_addr,Id_IPv6);
  855. LiSize := SizeOf(SockAddr_In6);
  856. end
  857. else
  858. IPVersionUnsupported;
  859. end;
  860. FillChar(LHostName[0],Length(LHostName),0);
  861. {$IFDEF USE_MARSHALLED_PTRS}
  862. LHostNamePtr := TPtrWrapper.Create(@LHostName[0]);
  863. {$ENDIF}
  864. LRet := getnameinfo(LAddr,LiSize,
  865. {$IFDEF USE_MARSHALLED_PTRS}
  866. LHostNamePtr.ToPointer
  867. {$ELSE}
  868. LHostName
  869. {$ENDIF},
  870. NI_MAXHOST,nil,0,NI_NAMEREQD );
  871. if LRet <> 0 then begin
  872. if LRet = EAI_SYSTEM then begin
  873. RaiseLastOSError;
  874. end else begin
  875. raise EIdReverseResolveError.CreateFmt(RSReverseResolveError, [AAddress, gai_strerror(LRet), LRet]);
  876. end;
  877. end;
  878. {
  879. IMPORTANT!!!
  880. getnameinfo can return either results from a numeric to text conversion or
  881. results from a DNS reverse lookup. Someone could make a malicous PTR record
  882. such as
  883. 1.0.0.127.in-addr.arpa. IN PTR 10.1.1.1
  884. and trick a caller into beleiving the socket address is 10.1.1.1 instead of
  885. 127.0.0.1. If there is a numeric host in LAddr, than this is the case and
  886. we disregard the result and raise an exception.
  887. }
  888. FillChar(LHints, SizeOf(LHints), 0);
  889. LHints.ai_socktype := SOCK_DGRAM; //*dummy*/
  890. LHints.ai_flags := AI_NUMERICHOST;
  891. if getaddrinfo(
  892. {$IFDEF USE_MARSHALLED_PTRS}
  893. LHostNamePtr.ToPointer
  894. {$ELSE}
  895. LHostName
  896. {$ENDIF},
  897. '0', LHints, LAddrInfo) = 0 then
  898. begin
  899. freeaddrinfo(LAddrInfo^);
  900. Result := '';
  901. raise EIdMaliciousPtrRecord.Create(RSMaliciousPtrRecord);
  902. end;
  903. {$IFDEF USE_MARSHALLED_PTRS}
  904. Result := TMarshal.ReadStringAsAnsi(LHostNamePtr);
  905. {$ELSE}
  906. Result := String(LHostName);
  907. {$ENDIF}
  908. end;
  909. function TIdStackVCLPosix.HostByName(const AHostName: string;
  910. const AIPVersion: TIdIPVersion): string;
  911. var
  912. LAddrInfo: pAddrInfo;
  913. LHints: AddrInfo;
  914. LRetVal: Integer;
  915. {$IFDEF USE_MARSHALLED_PTRS}
  916. M: TMarshaller;
  917. {$ENDIF}
  918. begin
  919. if not (AIPVersion in [Id_IPv4, Id_IPv6]) then begin
  920. IPVersionUnsupported;
  921. end;
  922. {$IFDEF USE_DNSCACHE}
  923. Result := GetCachedDnsHostAddress(AHostName, AIPVersion);
  924. if Result <> '' then Exit;
  925. {$ENDIF}
  926. //IMPORTANT!!!
  927. //
  928. //The Hints structure must be zeroed out or you might get an AV.
  929. //I've seen this in Mac OS X
  930. FillChar(LHints, SizeOf(LHints), 0);
  931. LHints.ai_family := IdIPFamily[AIPVersion];
  932. LHints.ai_socktype := SOCK_STREAM;
  933. LAddrInfo := nil;
  934. LRetVal := getaddrinfo(
  935. {$IFDEF USE_MARSHALLED_PTRS}
  936. M.AsAnsi(AHostName).ToPointer
  937. {$ELSE}
  938. PAnsiChar(
  939. {$IFDEF STRING_IS_ANSI}
  940. AHostName
  941. {$ELSE}
  942. AnsiString(AHostName) // explicit convert to Ansi
  943. {$ENDIF}
  944. )
  945. {$ENDIF},
  946. nil, LHints, LAddrInfo);
  947. if LRetVal <> 0 then begin
  948. if LRetVal = EAI_SYSTEM then begin
  949. RaiseLastOSError;
  950. end else begin
  951. raise EIdResolveError.CreateFmt(RSReverseResolveError, [AHostName, gai_strerror(LRetVal), LRetVal]);
  952. end;
  953. end;
  954. try
  955. if AIPVersion = Id_IPv4 then begin
  956. Result := TranslateTInAddrToString( PSockAddr_In( LAddrInfo^.ai_addr)^.sin_addr, AIPVersion);
  957. end else begin
  958. Result := TranslateTInAddrToString( PSockAddr_In6( LAddrInfo^.ai_addr)^.sin6_addr, AIPVersion);
  959. end;
  960. {$IFDEF USE_DNSCACHE}
  961. AddHostAddressToDnsCache(AHostName, AIPVersion, Result);
  962. {$ENDIF}
  963. finally
  964. freeaddrinfo(LAddrInfo^);
  965. end;
  966. end;
  967. function TIdStackVCLPosix.HostToNetwork(AValue: UInt32): UInt32;
  968. begin
  969. Result := htonl(AValue);
  970. end;
  971. function TIdStackVCLPosix.HostToNetwork(AValue: UInt16): UInt16;
  972. begin
  973. Result := htons(AValue);
  974. end;
  975. function TIdStackVCLPosix.HostToNetwork(AValue: TIdUInt64): TIdUInt64;
  976. var
  977. LParts: TIdUInt64Parts;
  978. L: UInt32;
  979. begin
  980. if (htonl(1) <> 1) then begin
  981. LParts.QuadPart := AValue;
  982. L := htonl(LParts.HighPart);
  983. LParts.HighPart := htonl(LParts.LowPart);
  984. LParts.LowPart := L;
  985. Result := LParts.QuadPart;
  986. end else begin
  987. Result := AValue;
  988. end;
  989. end;
  990. function TIdStackVCLPosix.IOControl(const s: TIdStackSocketHandle;
  991. const cmd: UInt32; var arg: UInt32): Integer;
  992. begin
  993. Result := ioctl(s, cmd, @arg);
  994. end;
  995. procedure TIdStackVCLPosix.Listen(ASocket: TIdStackSocketHandle;
  996. ABackLog: Integer);
  997. begin
  998. CheckForSocketError(Posix.SysSocket.listen(ASocket, ABacklog));
  999. end;
  1000. function TIdStackVCLPosix.NetworkToHost(AValue: UInt32): UInt32;
  1001. begin
  1002. Result := ntohl(AValue);
  1003. end;
  1004. function TIdStackVCLPosix.NetworkToHost(AValue: TIdUInt64): TIdUInt64;
  1005. var
  1006. LParts: TIdUInt64Parts;
  1007. L: UInt32;
  1008. begin
  1009. if (ntohl(1) <> 1) then begin
  1010. LParts.QuadPart := AValue;
  1011. L := ntohl(LParts.HighPart);
  1012. LParts.HighPart := ntohl(LParts.LowPart);
  1013. LParts.LowPart := L;
  1014. Result := LParts.QuadPart;
  1015. end else begin
  1016. Result := AValue;
  1017. end;
  1018. end;
  1019. function TIdStackVCLPosix.NetworkToHost(AValue: UInt16): UInt16;
  1020. begin
  1021. Result := ntohs(AValue);
  1022. end;
  1023. function TIdStackVCLPosix.ReadHostName: string;
  1024. const
  1025. sMaxHostSize = 250;
  1026. var
  1027. LStr: array[0..sMaxHostSize] of TIdAnsiChar;
  1028. {$IFDEF USE_MARSHALLED_PTRS}
  1029. LStrPtr: TPtrWrapper;
  1030. {$ENDIF}
  1031. begin
  1032. {$IFDEF USE_MARSHALLED_PTRS}
  1033. LStrPtr := TPtrWrapper.Create(@LStr[0]);
  1034. {$ENDIF}
  1035. if gethostname(
  1036. {$IFDEF USE_MARSHALLED_PTRS}
  1037. LStrPtr.ToPointer
  1038. {$ELSE}
  1039. LStr
  1040. {$ENDIF}, sMaxHostSize) = 0 then
  1041. begin
  1042. {$IFDEF USE_MARSHALLED_PTRS}
  1043. Result := TMarshal.ReadStringAsAnsiUpTo(0, LStrPtr, sMaxHostSize);
  1044. {$ELSE}
  1045. LStr[sMaxHostSize] := TIdAnsiChar(0);
  1046. Result := String(LStr);
  1047. {$ENDIF}
  1048. end else begin
  1049. Result := '';
  1050. end;
  1051. end;
  1052. function TIdStackVCLPosix.ReceiveMsg(ASocket: TIdStackSocketHandle;
  1053. var VBuffer: TIdBytes; APkt: TIdPacketInfo): UInt32;
  1054. var
  1055. LSize: socklen_t;
  1056. LAddrStore: sockaddr_storage;
  1057. LAddrIPv4 : SockAddr_In absolute LAddrStore;
  1058. LAddrIPv6 : sockaddr_in6 absolute LAddrStore;
  1059. LAddr : sockaddr absolute LAddrStore;
  1060. LMsg : msghdr;
  1061. LIOV : iovec;
  1062. LControl : TIdBytes;
  1063. LCurCmsg : Pcmsghdr; //for iterating through the control buffer
  1064. LByte : PByte;
  1065. begin
  1066. //we call the macro twice because we specified two possible structures.
  1067. //Id_IPV6_HOPLIMIT and Id_IPV6_PKTINFO
  1068. LSize := CMSG_SPACE(SizeOf(Byte)) + CMSG_SPACE(SizeOf(in6_pktinfo));
  1069. SetLength(LControl, LSize);
  1070. LIOV.iov_len := Length(VBuffer); // Length(VMsgData);
  1071. LIOV.iov_base := @VBuffer[0]; // @VMsgData[0];
  1072. FillChar(LMsg,SizeOf(LMsg),0);
  1073. LMsg.msg_iov := @LIOV;//lpBuffers := @LMsgBuf;
  1074. LMsg.msg_iovlen := 1;
  1075. LMsg.msg_controllen := LSize;
  1076. LMsg.msg_control := @LControl[0];
  1077. LMsg.msg_name := @LAddr;
  1078. LMsg.msg_namelen := SizeOf(LAddrStore);
  1079. Result := 0;
  1080. CheckForSocketError(RecvMsg(ASocket, LMsg, Result));
  1081. APkt.Reset;
  1082. case LAddrStore.ss_family of
  1083. Id_PF_INET4: begin
  1084. APkt.SourceIP := TranslateTInAddrToString(LAddrIPv4.sin_addr, Id_IPv4);
  1085. APkt.SourcePort := ntohs(LAddrIPv4.sin_port);
  1086. APkt.SourceIPVersion := Id_IPv4;
  1087. end;
  1088. Id_PF_INET6: begin
  1089. APkt.SourceIP := TranslateTInAddrToString(LAddrIPv6.sin6_addr, Id_IPv6);
  1090. APkt.SourcePort := ntohs(LAddrIPv6.sin6_port);
  1091. APkt.SourceIPVersion := Id_IPv6;
  1092. end;
  1093. else begin
  1094. Result := 0; // avoid warning
  1095. IPVersionUnsupported;
  1096. end;
  1097. end;
  1098. LCurCmsg := nil;
  1099. repeat
  1100. LCurCmsg := CMSG_NXTHDR(@LMsg, LCurCmsg);
  1101. if LCurCmsg = nil then begin
  1102. break;
  1103. end;
  1104. case LCurCmsg^.cmsg_type of
  1105. IPV6_PKTINFO : //done this way because IPV6_PKTINF and IP_PKTINFO are both 19
  1106. begin
  1107. case LAddrStore.ss_family of
  1108. Id_PF_INET4: begin
  1109. {$IFDEF IOS}
  1110. ToDo('PKTINFO not implemented for IPv4 under iOS yet');
  1111. {$ELSE}
  1112. {$IFNDEF OSX}
  1113. //This is not supported in OS X.
  1114. with Pin_pktinfo(CMSG_DATA(LCurCmsg))^ do begin
  1115. APkt.DestIP := TranslateTInAddrToString(ipi_addr, Id_IPv4);
  1116. APkt.DestIF := ipi_ifindex;
  1117. end;
  1118. APkt.DestIPVersion := Id_IPv4;
  1119. {$ENDIF}
  1120. {$ENDIF}
  1121. end;
  1122. Id_PF_INET6: begin
  1123. with pin6_pktinfo(CMSG_DATA(LCurCmsg))^ do begin
  1124. APkt.DestIP := TranslateTInAddrToString(ipi6_addr, Id_IPv6);
  1125. APkt.DestIF := ipi6_ifindex;
  1126. end;
  1127. APkt.DestIPVersion := Id_IPv6;
  1128. end;
  1129. end;
  1130. end;
  1131. Id_IPV6_HOPLIMIT :
  1132. begin
  1133. LByte := PByte(CMSG_DATA(LCurCmsg));
  1134. APkt.TTL := LByte^;
  1135. end;
  1136. end;
  1137. until False;
  1138. end;
  1139. function TIdStackVCLPosix.RecvFrom(const ASocket: TIdStackSocketHandle;
  1140. var VBuffer; const ALength, AFlags: Integer; var VIP: string;
  1141. var VPort: TIdPort; var VIPVersion: TIdIPVersion): Integer;
  1142. var
  1143. LiSize: socklen_t;
  1144. LAddrStore: sockaddr_storage;
  1145. LAddrIPv4 : SockAddr_In absolute LAddrStore;
  1146. LAddrIPv6 : sockaddr_in6 absolute LAddrStore;
  1147. LAddr : sockaddr absolute LAddrStore;
  1148. begin
  1149. LiSize := SizeOf(LAddrStore);
  1150. // TODO: only include MSG_NOSIGNAL if SO_NOSIGPIPE is not enabled?
  1151. Result := Posix.SysSocket.recvfrom(ASocket,VBuffer, ALength, AFlags or Id_MSG_NOSIGNAL, LAddr, LiSize);
  1152. if Result >= 0 then
  1153. begin
  1154. case LAddrStore.ss_family of
  1155. Id_PF_INET4: begin
  1156. VIP := TranslateTInAddrToString(LAddrIPv4.sin_addr, Id_IPv4);
  1157. VPort := ntohs(LAddrIPv4.sin_port);
  1158. VIPVersion := Id_IPV4;
  1159. end;
  1160. Id_PF_INET6: begin
  1161. VIP := TranslateTInAddrToString(LAddrIPv6.sin6_addr, Id_IPv6);
  1162. VPort := ntohs(LAddrIPv6.sin6_port);
  1163. VIPVersion := Id_IPV6;
  1164. end;
  1165. else begin
  1166. Result := 0;
  1167. IPVersionUnsupported;
  1168. end;
  1169. end;
  1170. end;
  1171. end;
  1172. procedure TIdStackVCLPosix.SetBlocking(ASocket: TIdStackSocketHandle;
  1173. const ABlocking: Boolean);
  1174. var
  1175. LFlags: Integer;
  1176. begin
  1177. LFlags := CheckForSocketError(fcntl(ASocket, F_GETFL, 0));
  1178. if ABlocking then begin
  1179. LFlags := LFlags and not O_NONBLOCK;
  1180. end else begin
  1181. LFlags := LFlags or O_NONBLOCK;
  1182. end;
  1183. CheckForSocketError(fcntl(ASocket, F_SETFL, LFlags));
  1184. end;
  1185. procedure TIdStackVCLPosix.SetLastError(const AError: Integer);
  1186. begin
  1187. __error^ := AError;
  1188. end;
  1189. procedure TIdStackVCLPosix.{$IFDEF VCL_XE3_OR_ABOVE}GetSocketOption{$ELSE}WSGetSocketOption{$ENDIF}
  1190. (ASocket: TIdStackSocketHandle; ALevel: TIdSocketOptionLevel; AOptName: TIdSocketOption;
  1191. var AOptVal; var AOptLen: Integer);
  1192. var
  1193. LLen : socklen_t;
  1194. begin
  1195. LLen := AOptLen;
  1196. CheckForSocketError(Posix.SysSocket.getsockopt(ASocket, ALevel, AOptName, AOptVal, LLen));
  1197. AOptLen := LLen;
  1198. end;
  1199. procedure TIdStackVCLPosix.{$IFDEF VCL_XE3_OR_ABOVE}SetSocketOption{$ELSE}WSSetSocketOption{$ENDIF}
  1200. (ASocket: TIdStackSocketHandle; ALevel: TIdSocketOptionLevel; AOptName: TIdSocketOption;
  1201. const AOptVal; const AOptLen: Integer);
  1202. begin
  1203. CheckForSocketError(Posix.SysSocket.setsockopt(ASocket, ALevel, AOptName, AOptVal, AOptLen));
  1204. end;
  1205. function TIdStackVCLPosix.SupportsIPv4: Boolean;
  1206. begin
  1207. {$IFDEF IOS}
  1208. // TODO: iOS 9+ is IPv6-only...
  1209. //Result := ([[[UIDevice currentDevice] systemVersion] compare:'9.0' options:NSNumericSearch] == NSOrderedAscending);
  1210. {$ENDIF}
  1211. //In Windows, this does something else. It checks the LSP's installed.
  1212. Result := CheckIPVersionSupport(Id_IPv4);
  1213. end;
  1214. function TIdStackVCLPosix.SupportsIPv6: Boolean;
  1215. begin
  1216. //In Windows, this does something else. It checks the LSP's installed.
  1217. Result := CheckIPVersionSupport(Id_IPv6);
  1218. end;
  1219. function TIdStackVCLPosix.WouldBlock(const AResult: Integer): Boolean;
  1220. begin
  1221. // using if-else instead of in..range because EAGAIN and EWOULDBLOCK
  1222. // have often the same value and so FPC might report a range error
  1223. Result := (AResult = Id_WSAEAGAIN) or
  1224. (AResult = Id_WSAEWOULDBLOCK) or
  1225. (AResult = Id_WSAEINPROGRESS);
  1226. end;
  1227. procedure TIdStackVCLPosix.WriteChecksum(s: TIdStackSocketHandle;
  1228. var VBuffer: TIdBytes; const AOffset: Integer; const AIP: String;
  1229. const APort: TIdPort; const AIPVersion: TIdIPVersion);
  1230. begin
  1231. case AIPVersion of
  1232. Id_IPv4 : CopyTIdUInt16(HostToLittleEndian(CalcCheckSum(VBuffer)), VBuffer, AOffset);
  1233. Id_IPv6 : WriteChecksumIPv6(s, VBuffer, AOffset, AIP, APort);
  1234. else
  1235. IPVersionUnsupported;
  1236. end;
  1237. end;
  1238. procedure TIdStackVCLPosix.WriteChecksumIPv6(s: TIdStackSocketHandle;
  1239. var VBuffer: TIdBytes; const AOffset: Integer; const AIP: String;
  1240. const APort: TIdPort);
  1241. begin
  1242. //we simply request that the kernal write the checksum when the data
  1243. //is sent. All of the parameters required are because Windows is bonked
  1244. //because it doesn't have the IPV6CHECKSUM socket option meaning we have
  1245. //to querry the network interface in TIdStackWindows -- yuck!!
  1246. SetSocketOption(s, Id_IPPROTO_IPV6, IPV6_CHECKSUM, AOffset);
  1247. end;
  1248. function TIdStackVCLPosix.WSCloseSocket(ASocket: TIdStackSocketHandle): Integer;
  1249. begin
  1250. Result := __close(ASocket);
  1251. end;
  1252. function TIdStackVCLPosix.WSGetLastError: Integer;
  1253. begin
  1254. //IdStackWindows just uses result := WSAGetLastError;
  1255. Result := GetLastError; //System.GetLastOSError; - FPC doesn't define it in System
  1256. if Result = Id_WSAEPIPE then begin
  1257. Result := Id_WSAECONNRESET;
  1258. end;
  1259. end;
  1260. function TIdStackVCLPosix.WSGetServByName(const AServiceName: string): TIdPort;
  1261. var
  1262. Lps: PServEnt;
  1263. {$IFDEF USE_MARSHALLED_PTRS}
  1264. M: TMarshaller;
  1265. {$ENDIF}
  1266. begin
  1267. Lps := Posix.NetDB.getservbyname(
  1268. {$IFDEF USE_MARSHALLED_PTRS}
  1269. M.AsAnsi(AServiceName).ToPointer
  1270. {$ELSE}
  1271. PAnsiChar(
  1272. {$IFDEF STRING_IS_ANSI}
  1273. AServiceName
  1274. {$ELSE}
  1275. AnsiString(AServiceName) // explicit convert to Ansi
  1276. {$ENDIF}
  1277. )
  1278. {$ENDIF},
  1279. nil);
  1280. if Lps <> nil then begin
  1281. Result := ntohs(Lps^.s_port);
  1282. end else begin
  1283. try
  1284. Result := IndyStrToInt(AServiceName);
  1285. except
  1286. on EConvertError do begin
  1287. Result := 0;
  1288. IndyRaiseOuterException(EIdInvalidServiceName.CreateFmt(RSInvalidServiceName, [AServiceName]));
  1289. end;
  1290. end;
  1291. end;
  1292. end;
  1293. procedure TIdStackVCLPosix.AddServByPortToList(const APortNumber: TIdPort; AAddresses: TStrings);
  1294. //function TIdStackVCLPosix.WSGetServByPort(const APortNumber: TIdPort): TStrings;
  1295. type
  1296. PPAnsiCharArray = ^TPAnsiCharArray;
  1297. TPAnsiCharArray = packed array[0..(MaxInt div SizeOf(PIdAnsiChar))-1] of PIdAnsiChar;
  1298. var
  1299. Lps: PServEnt;
  1300. Li: Integer;
  1301. Lp: PPAnsiCharArray;
  1302. begin
  1303. Lps := Posix.NetDB.getservbyport(htons(APortNumber), nil);
  1304. if Lps <> nil then begin
  1305. AAddresses.BeginUpdate;
  1306. try
  1307. AAddresses.Add(String(Lps^.s_name));
  1308. Li := 0;
  1309. Lp := Pointer(Lps^.s_aliases);
  1310. while Lp[Li] <> nil do begin
  1311. AAddresses.Add(String(Lp[Li]));
  1312. Inc(Li);
  1313. end;
  1314. finally
  1315. AAddresses.EndUpdate;
  1316. end;
  1317. end;
  1318. end;
  1319. function TIdStackVCLPosix.WSRecv(ASocket: TIdStackSocketHandle; var ABuffer;
  1320. const ABufferLength, AFlags: Integer): Integer;
  1321. begin
  1322. //IdStackWindows is just: Result := Recv(ASocket, ABuffer, ABufferLength, AFlags);
  1323. // TODO: only include MSG_NOSIGNAL if SO_NOSIGPIPE is not enabled?
  1324. Result := Posix.SysSocket.Recv(ASocket, ABuffer, ABufferLength, AFlags or Id_MSG_NOSIGNAL);
  1325. end;
  1326. function TIdStackVCLPosix.WSSend(ASocket: TIdStackSocketHandle; const ABuffer;
  1327. const ABufferLength, AFlags: Integer): Integer;
  1328. begin
  1329. // TODO: only include MSG_NOSIGNAL if SO_NOSIGPIPE is not enabled?
  1330. Result := CheckForSocketError(Posix.SysSocket.send(ASocket, ABuffer, ABufferLength, AFlags or Id_MSG_NOSIGNAL));
  1331. end;
  1332. procedure TIdStackVCLPosix.WSSendTo(ASocket: TIdStackSocketHandle;
  1333. const ABuffer; const ABufferLength, AFlags: Integer; const AIP: string;
  1334. const APort: TIdPort; AIPVersion: TIdIPVersion);
  1335. var
  1336. LAddrStore: sockaddr_storage;
  1337. LAddrIPv4 : SockAddr_In absolute LAddrStore;
  1338. LAddrIPv6 : sockaddr_in6 absolute LAddrStore;
  1339. LAddr : sockaddr absolute LAddrStore;
  1340. LiSize: socklen_t;
  1341. LBytesSent: Integer;
  1342. begin
  1343. case AIPVersion of
  1344. Id_IPv4: begin
  1345. InitSockAddr_In(LAddrIPv4);
  1346. TranslateStringToTInAddr(AIP, LAddrIPv4.sin_addr, Id_IPv4);
  1347. LAddrIPv4.sin_port := htons(APort);
  1348. LiSize := SizeOf(LAddrIPv4);
  1349. end;
  1350. Id_IPv6: begin
  1351. InitSockAddr_in6(LAddrIPv6);
  1352. TranslateStringToTInAddr(AIP, LAddrIPv6.sin6_addr, Id_IPv6);
  1353. LAddrIPv6.sin6_port := htons(APort);
  1354. LiSize := SizeOf(LAddrIPv6);
  1355. end;
  1356. else
  1357. LiSize := 0; // avoid warning
  1358. IPVersionUnsupported;
  1359. end;
  1360. // TODO: only include MSG_NOSIGNAL if SO_NOSIGPIPE is not enabled?
  1361. LBytesSent := Posix.SysSocket.sendto(
  1362. ASocket, ABuffer, ABufferLength, AFlags or Id_MSG_NOSIGNAL, LAddr, LiSize);
  1363. if LBytesSent = Id_SOCKET_ERROR then begin
  1364. // TODO: move this into RaiseLastSocketError directly
  1365. if WSGetLastError() = Id_WSAEMSGSIZE then begin
  1366. raise EIdPackageSizeTooBig.Create(RSPackageSizeTooBig);
  1367. end else begin
  1368. RaiseLastSocketError;
  1369. end;
  1370. end
  1371. else if LBytesSent <> ABufferLength then begin
  1372. raise EIdNotAllBytesSent.Create(RSNotAllBytesSent);
  1373. end;
  1374. end;
  1375. procedure TIdStackVCLPosix.WSSetLastError(const AErr: Integer);
  1376. begin
  1377. __error^ := AErr;
  1378. end;
  1379. function TIdStackVCLPosix.WSShutdown(ASocket: TIdStackSocketHandle;
  1380. AHow: Integer): Integer;
  1381. begin
  1382. Result := Posix.SysSocket.shutdown(ASocket, AHow);
  1383. end;
  1384. function TIdStackVCLPosix.WSSocket(AFamily : Integer; AStruct : TIdSocketType; AProtocol: Integer;
  1385. const ANonBlocking: Boolean = False): TIdStackSocketHandle;
  1386. var
  1387. LFlags: Integer;
  1388. begin
  1389. Result := Posix.SysSocket.socket(AFamily, AStruct, AProtocol);
  1390. if Result <> INVALID_SOCKET then begin
  1391. {$IFDEF HAS_SOCKET_NOSIGPIPE}
  1392. SetSocketOption(Result, SOL_SOCKET, SO_NOSIGPIPE, 1);
  1393. {$ENDIF}
  1394. //SetBlocking(Result, not ANonBlocking);
  1395. if ANonBlocking then begin
  1396. LFlags := fcntl(Result, F_GETFL, 0);
  1397. LFlags := LFlags or O_NONBLOCK;
  1398. fcntl(Result, F_SETFL, LFlags);
  1399. end;
  1400. end;
  1401. end;
  1402. {$I IdUnitPlatformOn.inc}
  1403. {$I IdSymbolPlatformOn.inc}
  1404. initialization
  1405. GSocketListClass := TIdSocketListVCLPosix;
  1406. end.