IdStackVCLPosix.pas 50 KB

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