IdStackVCLPosix.pas 46 KB

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