IdStackVCLPosix.pas 46 KB

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