fpsockets.pp 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062
  1. {
  2. This file is part of the Free Component Library (FCL)
  3. Copyright (c) 2024 by Frederic Kehrein
  4. See the file COPYING.FPC, included in this distribution,
  5. for details about the copyright.
  6. This program is distributed in the hope that it will be useful,
  7. but WITHOUT ANY WARRANTY; without even the implied warranty of
  8. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  9. **********************************************************************}
  10. {$IFNDEF FPC_DOTTEDUNITS}
  11. unit fpsockets;
  12. {$ENDIF FPC_DOTTEDUNITS}
  13. {$mode ObjFPC}{$H+}
  14. {$TypedAddress on}
  15. interface
  16. {$IFDEF FPC_DOTTEDUNITS}
  17. uses
  18. System.SysUtils, System.Net.Sockets, SystemNullable;
  19. {$ELSE FPC_DOTTEDUNITS}
  20. uses
  21. sysutils, sockets, nullable;
  22. {$ENDIF FPC_DOTTEDUNITS}
  23. type
  24. { Basic Socket Types }
  25. TFPSocketType = (stIPv4, stIPv6, stIPDualStack, stUnixSocket);
  26. TFPSocketProto = (spStream, spDatagram);
  27. TFPSocket = record
  28. FD: TSocket;
  29. Protocol: TFPSocketProto;
  30. SocketType: TFPSocketType;
  31. end;
  32. TAddressType = (atIN4, atIN6, atUnixSock);
  33. TNetworkAddress = record
  34. Address: String;
  35. AddressType: TAddressType;
  36. end;
  37. TFPSocketConnection = record
  38. ClientAddress: TNetworkAddress;
  39. ClientPort: Word;
  40. Socket: TFPSocket;
  41. end;
  42. { ReceiveFrom Return Types }
  43. TReceiveFromResult = record
  44. FromAddr: TNetworkAddress;
  45. FromPort: Word;
  46. DataSize: SizeInt;
  47. end;
  48. generic TReceiveFromMessage<T> = record
  49. FromAddr: TNetworkAddress;
  50. FromPort: Word;
  51. Data: T;
  52. end;
  53. TReceiveFromStringMessage = specialize TReceiveFromMessage<String>;
  54. { State Management }
  55. TConnectionState = (csError, csNotConnected, csRefused, csPending, csConnected);
  56. { Exceptions }
  57. EDualStackNotSupported = class(Exception);
  58. EUnsupportedAddress = class(Exception);
  59. { ESocketError }
  60. ESocketError = class(Exception)
  61. private
  62. FCode: Integer;
  63. public
  64. constructor Create(ACode: Integer; const FunName: String);
  65. property Code: Integer read FCode;
  66. end;
  67. EConnectionClosedException = class(Exception);
  68. { EFragmentedData }
  69. EFragmentedData = class(Exception)
  70. private
  71. FFragment: TBytes;
  72. FExpectedSize: SizeInt;
  73. public
  74. constructor Create(const AFragment: TBytes; AExpected: SizeInt; const AMessage: String);
  75. property Fragment: TBytes read FFragment;
  76. property ExpectedSize: SizeInt read FExpectedSize;
  77. end;
  78. const
  79. MaxUDPPackageSize = 512;
  80. { Address Management }
  81. function isIPv4Address(const Address: String): Boolean; inline;
  82. function isIPv6Address(const Address: String): Boolean; inline;
  83. function IN4Address(const Address: String): TNetworkAddress; inline;
  84. function IN6Address(const Address: String): TNetworkAddress; inline;
  85. function IN4MappedIN6Address(const In4Address: String): TNetworkAddress; inline;
  86. function UnixAddr(const Address: String): TNetworkAddress; inline;
  87. function NetAddr(const Address: String): TNetworkAddress; inline;
  88. function isINAddr(const AAddr: TNetworkAddress): Boolean; inline;
  89. function IsIPv4Mapped(const IPv6Addr: TNetworkAddress): Boolean; inline;
  90. function ExtractIPv4Address(const IPv6Addr: TNetworkAddress): TNetworkAddress; inline;
  91. function IN6Equal(const A, B: String): Boolean;
  92. operator =(const A, B: TNetworkAddress): Boolean; inline;
  93. operator <>(const A, B: TNetworkAddress): Boolean; inline;
  94. operator :=(const AStr: String): TNetworkAddress; inline;
  95. { Socket Functions }
  96. function TCPSocket(AType: TFPSocketType): TFPSocket; inline;
  97. function UDPSocket(AType: TFPSocketType): TFPSocket; inline;
  98. procedure CloseSocket(const ASocket: TFPSocket); inline;
  99. procedure Bind(const ASocket: TFPSocket; const AAddress: TNetworkAddress; APort: Word; ReuseAddr: Boolean = True);
  100. procedure Listen(const ASocket: TFPSocket; Backlog: Integer); inline;
  101. function AcceptConnection(const ASocket: TFPSocket): TFPSocketConnection; inline;
  102. function AcceptNonBlocking(const ASocket: TFPSocket): specialize TNullable<TFPSocketConnection>; inline;
  103. function Connect(const ASocket: TFPSocket; const AAddress: TNetworkAddress; APort: Word): TConnectionState; inline;
  104. function Receive(const ASocket: TFPSocket; ABuffer: Pointer; MaxSize: SizeInt; AFlags: Integer = 0): SizeInt; inline;
  105. function ReceiveFrom(const ASocket: TFPSocket; ABuffer: Pointer; MaxSize: SizeInt; AFlags: Integer = 0): TReceiveFromResult;
  106. function ReceiveFromNonBlocking(const ASocket: TFPSocket; ABuffer: Pointer; MaxSize: SizeInt; AFlags: Integer = 0): specialize TNullable<TReceiveFromResult>; inline;
  107. function Send(const ASocket: TFPSocket; ABuffer: Pointer; ASize: SizeInt; AFlags: Integer = 0): SizeInt; inline;
  108. function SendTo(const ASocket: TFPSocket; const ReceiverAddr: TNetworkAddress;
  109. ReceiverPort: Word; ABuffer: Pointer; ASize: SizeInt; AFlags: Integer = 0): SizeInt; inline;
  110. function ReceiveStr(const ASocket: TFPSocket; MaxLength: SizeInt = -1; AFlags: Integer = 0): String;
  111. function ReceiveStrFrom(const ASocket: TFPSocket; MaxLength: SizeInt = MaxUDPPackageSize; AFlags: Integer = 0): TReceiveFromStringMessage; inline;
  112. function ReceiveStrFromNonBlocking(const ASocket: TFPSocket; MaxLength: SizeInt = MaxUDPPackageSize; AFlags: Integer = 0): specialize TNullable<TReceiveFromStringMessage>; inline;
  113. function SendStr(const ASocket: TFPSocket; const AData: String; AFlags: Integer = 0): SizeInt; inline;
  114. function SendStrTo(const ASocket: TFPSocket; const ReceiverAddr: TNetworkAddress; ReceiverPort: Word; const AData: String; AFlags: Integer = 0): SizeInt; inline;
  115. generic function Receive<T>(const ASocket: TFPSocket; AFlags: Integer = 0): T;
  116. generic function ReceiveNonBlocking<T>(const ASocket: TFPSocket; AFlags: Integer = 0): specialize TNullable<T>;
  117. generic function ReceiveFrom<T>(const ASocket: TFPSocket; AFlags: Integer = 0): specialize TReceiveFromMessage<T>;
  118. generic function ReceiveFromNonBlocking<T>(const ASocket: TFPSocket; AFlags: Integer = 0): specialize TNullable<specialize TReceiveFromMessage<T>>;
  119. generic function Send<T>(const ASocket: TFPSocket; constref AData: T; AFlags: Integer = 0): SizeInt; inline;
  120. generic function SendTo<T>(const ASocket: TFPSocket; constref ReceiverAddr: TNetworkAddress; ReceiverPort: Word; const AData: T; AFlags: Integer = 0): SizeInt; inline;
  121. generic function ReceiveArray<T>(const ASocket: TFPSocket; MaxCount: SizeInt = -1; AFlags: Integer = 0): specialize TArray<T>;
  122. generic function ReceiveArrayFrom<T>(const ASocket: TFPSocket; MaxCount: SizeInt = -1; AFlags: Integer = 0): specialize TReceiveFromMessage<specialize TArray<T>>; inline;
  123. generic function ReceiveArrayFromNonBlocking<T>(const ASocket: TFPSocket; MaxCount: SizeInt = -1; AFlags: Integer = 0): specialize TNullable<specialize TReceiveFromMessage<specialize TArray<T>>>; inline;
  124. generic function SendArray<T>(const ASocket: TFPSocket; const AData: specialize TArray<T>; AFlags: Integer = 0): SizeInt; inline;
  125. generic function SendArrayTo<T>(const ASocket: TFPSocket; const ReceiverAddr: TNetworkAddress; ReceiverPort: Word; const AData: specialize TArray<T>; AFlags: Integer = 0): SizeInt; inline;
  126. { Socket/Connection State Management }
  127. procedure SetNonBlocking(const ASocket: TFPSocket; AValue: Boolean);
  128. // Timeout in MS
  129. function DataAvailable(const SocketArray: specialize TArray<TFPSocket>; TimeOut: Integer = 0): specialize TArray<TFPSocket>; overload;
  130. function DataAvailable(const ASocket: TFPSocket; TimeOut: Integer = 0): Boolean; overload; //inline;
  131. function DataAvailable(const SocketArray: array of TFPSocket; TimeOut: Integer = 0): specialize TArray<TFPSocket>; overload; inline;
  132. function BytesAvailable(const ASocket: TFPSocket): SizeInt;
  133. function StreamClosed(const ASocket: TFPSocket): Boolean; inline;
  134. // For non blocking connections, connect will return a pending connection that needs to be checked
  135. // Note: csConnected means that connection was establised at least once
  136. // If it has been closed by the other side, it is still csConnected, use StreamClosed to figure out
  137. // if the stream is actually open
  138. function ConnectionState(const ASocket: TFPSocket): TConnectionState;
  139. implementation
  140. {$IFDEF FPC_DOTTEDUNITS}
  141. uses
  142. {$IfDef WINDOWS}WinApi.WinSock2{$Else}UnixApi.Base, UnixApi.TermIO{$EndIf}, System.Math;
  143. {$ELSE FPC_DOTTEDUNITS}
  144. uses
  145. {$IfDef WINDOWS}WinSock2{$Else}BaseUnix, termio{$EndIf}, math;
  146. {$ENDIF FPC_DOTTEDUNITS}
  147. {$macro on}
  148. {$IFDEF FPC_DOTTEDUNITS}
  149. {$define socketsunit:=System.Net.Sockets}
  150. {$ELSE FPC_DOTTEDUNITS}
  151. {$define socketsunit:=sockets}
  152. {$ENDIF FPC_DOTTEDUNITS}
  153. { Helper }
  154. type
  155. _PAddressUnion = ^_TAddressUnion;
  156. _TAddressUnion = record
  157. case TFPSocketType of
  158. stIPv4: (In4Addr: socketsunit.sockaddr_in);
  159. stIPv6: (In6Addr: socketsunit.sockaddr_in6);
  160. stUnixSocket: (UnixAddr: socketsunit.sockaddr_un);
  161. end;
  162. const
  163. IPPROTO_IPV6 = {$IfDef WINDOWS}41{$Else}41{$EndIf};
  164. IPV6_V6ONLY = {$IfDef WINDOWS}27{$Else}26{$EndIf};
  165. function WouldBlock(SockErr: Integer): Boolean; inline;
  166. begin
  167. Result := (SockErr = EsockEWOULDBLOCK)
  168. {$IfDef Unix} or (SockErr = ESysEAGAIN) {$EndIf}
  169. end;
  170. function CreateAddr(AAddress: TNetworkAddress; APort: Word; DualStack: Boolean): _TAddressUnion;
  171. begin
  172. if (AAddress.AddressType = atIN4) and DualStack then
  173. AAddress := IN4MappedIN6Address(AAddress.Address);
  174. if AAddress.AddressType = atIN4 then
  175. begin
  176. Result.In4Addr.sin_family := AF_INET;
  177. Result.In4Addr.sin_port := HToNS(APort);
  178. Result.In4Addr.sin_addr.s_addr := LongWord(StrToNetAddr(AAddress.Address));
  179. end
  180. else if AAddress.AddressType = atIN6 then
  181. begin
  182. Result.In6Addr.sin6_family := AF_INET6;
  183. Result.In6Addr.sin6_port := HToNS(APort);
  184. Result.In6Addr.sin6_addr := StrToHostAddr6(AAddress.Address);
  185. Result.In6Addr.sin6_flowinfo := 0;
  186. Result.In6Addr.sin6_scope_id := 0;
  187. end
  188. else if AAddress.AddressType = atUnixSock then
  189. begin
  190. if Length(AAddress.Address) > SizeOf(Result.UnixAddr.sun_path)-1 then
  191. raise EUnsupportedAddress.Create('Unix address should be at most 108 characters');
  192. Result.UnixAddr.sun_family := AF_UNIX;
  193. FillChar(Result.UnixAddr, SizeOf(Result.UnixAddr), #00);
  194. Move(AAddress.Address[1], Result.UnixAddr.sun_path, Length(AAddress.Address));
  195. end
  196. else
  197. raise EUnsupportedAddress.Create('Address type ' + ord(AAddress.AddressType).ToString + ' not supported');
  198. end;
  199. procedure ReadAddr(constref Addr: _TAddressUnion; DualStack: Boolean; out
  200. AAddress: TNetworkAddress; out APort: Word);
  201. var
  202. i:Integer;
  203. begin
  204. if Addr.In4Addr.sin_family = AF_INET then
  205. begin
  206. AAddress := IN4Address(NetAddrToStr(Addr.In4Addr.sin_addr));
  207. APort := NToHs(Addr.In4Addr.sin_port);
  208. end
  209. else if Addr.In6Addr.sin6_family = AF_INET6 then
  210. begin
  211. AAddress := IN6Address(HostAddrToStr6(Addr.In6Addr.sin6_addr));
  212. if DualStack and IsIPv4Mapped(AAddress.Address) then
  213. AAddress := ExtractIPv4Address(AAddress);
  214. APort := NToHs(Addr.In6Addr.sin6_port);
  215. end
  216. else if Addr.In6Addr.sin6_family = AF_INET6 then
  217. begin
  218. AAddress.AddressType := atUnixSock;
  219. SetLength(AAddress.Address, SizeOf(Addr.UnixAddr.sun_path));
  220. i:=0;
  221. while i < Length(Addr.UnixAddr.sun_path) do
  222. if Addr.UnixAddr.sun_path[i+low(Addr.UnixAddr.sun_path)] = #00 then
  223. break
  224. else
  225. AAddress.Address[i+1] := Addr.UnixAddr.sun_path[i+low(Addr.UnixAddr.sun_path)];
  226. SetLength(AAddress.Address, i);
  227. APort := 0;
  228. end
  229. else
  230. raise EUnsupportedAddress.Create('Address Family ' + Addr.In4Addr.sin_family.ToString + ' not supported');
  231. end;
  232. function SocketInvalid(ASocket: TSocket): Boolean; inline;
  233. begin
  234. {$IfDef Windows}
  235. Result := ASocket = TSocket(INVALID_SOCKET);
  236. {$Else}
  237. Result := ASocket < 0;
  238. {$EndIf}
  239. end;
  240. function CreateRawSocket(ADomain: TFPSocketType; ASockProto: TFPSocketProto; AProto: Integer): TSocket;
  241. var
  242. AFam, AType, v6Only: Integer;
  243. begin
  244. case ADomain of
  245. stIPv4: AFam := AF_INET;
  246. stIPv6,
  247. stIPDualStack: AFam := AF_INET6;
  248. stUnixSocket: AFam := AF_UNIX;
  249. end;
  250. case ASockProto of
  251. spStream: AType := SOCK_STREAM;
  252. spDatagram: AType := SOCK_DGRAM;
  253. end;
  254. Result := fpsocket(AFam, AType, AProto);
  255. if SocketInvalid(Result) then
  256. raise ESocketError.Create(socketerror, 'socket');
  257. if ADomain = stIPDualStack then
  258. begin
  259. v6Only := 0;
  260. if fpsetsockopt(Result, IPPROTO_IPV6, IPV6_V6ONLY, @v6Only, SizeOf(v6Only)) <> 0 then
  261. begin
  262. socketsunit.CloseSocket(Result);
  263. raise EDualStackNotSupported.Create('Dualstack option not supported on this system: ' + socketerror.ToString);
  264. end;
  265. end;
  266. end;
  267. function isIPv4Address(const Address:String):Boolean;
  268. var
  269. dummy:socketsunit.in_addr;
  270. begin
  271. Result := TryStrToHostAddr(Address, dummy);
  272. end;
  273. function isIPv6Address(const Address:String):Boolean;
  274. var
  275. dummy:in6_addr;
  276. begin
  277. Result := TryStrToHostAddr6(Address, dummy);
  278. end;
  279. function IN4Address(const Address: String): TNetworkAddress;
  280. begin
  281. Result := Default(TNetworkAddress);
  282. Result.Address := Address;
  283. Result.AddressType := atIN4;
  284. end;
  285. function IN6Address(const Address: String): TNetworkAddress;
  286. begin
  287. Result := Default(TNetworkAddress);
  288. Result.Address := Address;
  289. Result.AddressType := atIN6;
  290. end;
  291. function IN4MappedIN6Address(const In4Address: String): TNetworkAddress;
  292. var
  293. InAddr: TIn_addr;
  294. begin
  295. InAddr := StrToNetAddr(In4Address);
  296. Result := IN6Address('::FFFF:%x:%x'.Format([(InAddr.s_bytes[1] shl 8) or InAddr.s_bytes[2],
  297. (InAddr.s_bytes[3] shl 8) or InAddr.s_bytes[4]]));
  298. end;
  299. function UnixAddr(const Address: String):TNetworkAddress;
  300. begin
  301. Result := Default(TNetworkAddress);
  302. Result.Address := Address;
  303. Result.AddressType := atUnixSock;
  304. end;
  305. function NetAddr(const Address: String): TNetworkAddress;
  306. begin
  307. Result := Default(TNetworkAddress);
  308. if isIPv4Address(Address) then
  309. Result.AddressType := atIN4
  310. else if isIPv6Address(Address) then
  311. Result.AddressType := atIN6
  312. else // Filenames can be pretty much anything
  313. Result.AddressType := atUnixSock;
  314. Result.Address := Address;
  315. end;
  316. function IsIPv4Mapped(const IPv6Addr: TNetworkAddress): Boolean;
  317. var
  318. In6Addr: socketsunit.TIn6Addr;
  319. begin
  320. if IPv6Addr.AddressType = atIN4 then
  321. Exit(True);
  322. if IPv6Addr.AddressType <> atIN6 then
  323. raise EUnsupportedAddress.Create('Can only check IPv4 mapping for IPv6 addresses');
  324. IN6Addr := StrToHostAddr6(IPv6Addr.Address);
  325. Result := (IN6Addr.u6_addr16[0] = 0) and
  326. (IN6Addr.u6_addr16[1] = 0) and
  327. (IN6Addr.u6_addr16[2] = 0) and
  328. (IN6Addr.u6_addr16[3] = 0) and
  329. (IN6Addr.u6_addr16[4] = 0) and
  330. (IN6Addr.u6_addr16[5] = $FFFF);
  331. end;
  332. function isINAddr(const AAddr:TNetworkAddress):Boolean;
  333. begin
  334. Result := AAddr.AddressType in [atIN4, atIN6];
  335. end;
  336. function ExtractIPv4Address(const IPv6Addr: TNetworkAddress): TNetworkAddress;
  337. var
  338. In6Addr: socketsunit.TIn6Addr;
  339. begin
  340. if IPv6Addr.AddressType = atIN4 then
  341. Exit(IPv6Addr);
  342. if IPv6Addr.AddressType <> atIN6 then
  343. raise EUnsupportedAddress.Create('Can only extract IPv4 mapping from IPv6 addresses');
  344. IN6Addr := StrToHostAddr6(IPv6Addr.Address);
  345. Result := IN4Address('%d.%d.%d.%d'.Format([IN6Addr.s6_addr8[12],
  346. IN6Addr.s6_addr8[13],
  347. IN6Addr.s6_addr8[14],
  348. IN6Addr.s6_addr8[15]]));
  349. end;
  350. function IN6Equal(const A, B: String): Boolean;
  351. var
  352. AAddr, BAddr: socketsunit.Tin6_addr;
  353. begin
  354. AAddr := StrToHostAddr6(A);
  355. BAddr := StrToHostAddr6(B);
  356. Result := (AAddr.s6_addr32[0] = BAddr.s6_addr32[0]) and
  357. (AAddr.s6_addr32[1] = BAddr.s6_addr32[1]) and
  358. (AAddr.s6_addr32[2] = BAddr.s6_addr32[2]) and
  359. (AAddr.s6_addr32[3] = BAddr.s6_addr32[3]);
  360. end;
  361. operator=(const A, B: TNetworkAddress): Boolean;
  362. begin
  363. Result := (A.AddressType = B.AddressType) and (
  364. ((A.AddressType = atIN4) and (A.Address = B.Address)) or // IPv4: simple string equality
  365. ((A.AddressType = atIN6) and IN6Equal(A.Address, B.Address)) or // IPv6 check binary equality
  366. ((A.AddressType = atUnixSock) and SameFileName(A.Address, B.Address)) // UnixSock check if filename equals
  367. );
  368. end;
  369. operator<>(const A, B: TNetworkAddress): Boolean;
  370. begin
  371. Result := (A.AddressType <> B.AddressType) or not (
  372. ((A.AddressType = atIN4) and (A.Address = B.Address)) or // IPv4: simple string equality
  373. ((A.AddressType = atIN6) and IN6Equal(A.Address, B.Address)) or // IPv6 check binary equality
  374. ((A.AddressType = atUnixSock) and SameFileName(A.Address, B.Address)) // UnixSock check if filename equals
  375. );
  376. end;
  377. operator:=(const AStr: String): TNetworkAddress;
  378. begin
  379. Result := NetAddr(AStr);
  380. end;
  381. function TCPSocket(AType: TFPSocketType): TFPSocket;
  382. begin
  383. Result.SocketType := AType;
  384. Result.Protocol := spStream;
  385. Result.FD := CreateRawSocket(Result.SocketType, Result.Protocol, 0);
  386. end;
  387. function UDPSocket(AType: TFPSocketType): TFPSocket;
  388. begin
  389. Result.SocketType := AType;
  390. Result.Protocol := spDatagram;
  391. Result.FD := CreateRawSocket(Result.SocketType, Result.Protocol, 0);
  392. end;
  393. procedure CloseSocket(const ASocket: TFPSocket);
  394. begin
  395. socketsunit.CloseSocket(ASocket.FD);
  396. end;
  397. procedure Bind(const ASocket: TFPSocket; const AAddress: TNetworkAddress;
  398. APort: Word; ReuseAddr: Boolean);
  399. var
  400. enableReuse: Integer = 1;
  401. addr: _TAddressUnion;
  402. begin
  403. if ReuseAddr then
  404. fpsetsockopt(ASocket.FD, SOL_SOCKET, SO_REUSEADDR, @enableReuse, SizeOf(enableReuse));
  405. addr := CreateAddr(AAddress, APort, ASocket.SocketType = stIPDualStack);
  406. if fpbind(ASocket.FD, socketsunit.PSockAddr(@addr), SizeOf(addr)) <> 0 then raise
  407. ESocketError.Create(socketerror, 'bind (%s:%d)'.Format([AAddress.Address, APort]));
  408. end;
  409. procedure Listen(const ASocket: TFPSocket; Backlog: Integer);
  410. begin
  411. if fplisten(ASocket.FD, Backlog) <> 0 then raise
  412. ESocketError.Create(socketerror, 'listen');
  413. end;
  414. function AcceptConnection(const ASocket: TFPSocket): TFPSocketConnection;
  415. var
  416. addr: _TAddressUnion;
  417. addrLen: TSocklen = SizeOf(addr);
  418. begin
  419. Result.Socket.FD := fpaccept(ASocket.FD, socketsunit.psockaddr(@addr), @addrLen);
  420. if SocketInvalid(Result.Socket.FD) then
  421. raise ESocketError.Create(socketerror, 'accept');
  422. Result.Socket.SocketType := ASocket.SocketType;
  423. Result.Socket.Protocol := ASocket.Protocol;
  424. ReadAddr(addr, ASocket.SocketType = stIPDualStack, Result.ClientAddress, Result.ClientPort);
  425. end;
  426. function AcceptNonBlocking(const ASocket: TFPSocket): specialize TNullable<
  427. TFPSocketConnection>;
  428. var
  429. addr: _TAddressUnion;
  430. addrLen: TSocklen = SizeOf(addr);
  431. begin
  432. Result.Ptr^.Socket.FD := fpaccept(ASocket.FD, socketsunit.psockaddr(@addr), @addrLen);
  433. if SocketInvalid(Result.Ptr^.Socket.FD) then
  434. if WouldBlock(socketerror) then
  435. Exit(null)
  436. else
  437. raise ESocketError.Create(socketerror, 'accept');
  438. Result.Ptr^.Socket.SocketType := ASocket.SocketType;
  439. Result.Ptr^.Socket.Protocol := ASocket.Protocol;
  440. ReadAddr(addr, ASocket.SocketType = stIPDualStack, Result.Ptr^.ClientAddress, Result.Ptr^.ClientPort);
  441. end;
  442. function Connect(const ASocket: TFPSocket; const AAddress: TNetworkAddress;
  443. APort: Word): TConnectionState;
  444. var
  445. addr: _TAddressUnion;
  446. const
  447. EALREADY = {$IfDef Windows}WSAEALREADY{$Else}ESysEALREADY{$EndIf};
  448. EINPROGRESS = {$IfDef Windows}WSAEINPROGRESS{$Else}ESysEINPROGRESS{$EndIf};
  449. ECONNREFUSED = {$IfDef Windows}WSAECONNREFUSED{$Else}ESysECONNREFUSED{$EndIf};
  450. begin
  451. addr := CreateAddr(AAddress, APort, ASocket.SocketType = stIPDualStack);
  452. if fpconnect(ASocket.FD, socketsunit.psockaddr(@addr), SizeOf(addr)) <> 0 then
  453. case socketerror of
  454. EALREADY,
  455. EINPROGRESS,
  456. EsockEWOULDBLOCK:
  457. Exit(csPending);
  458. ECONNREFUSED:
  459. Exit(csRefused);
  460. else
  461. raise ESocketError.Create(socketerror, 'connect');
  462. end;
  463. if ASocket.Protocol<>spStream then
  464. Result := csNotConnected
  465. else
  466. Result := csConnected;
  467. end;
  468. function Receive(const ASocket: TFPSocket; ABuffer: Pointer; MaxSize: SizeInt;
  469. AFlags: Integer): SizeInt;
  470. begin
  471. Result := fprecv(ASocket.FD, ABuffer, MaxSize, AFlags);
  472. if Result = 0 then
  473. raise EConnectionClosedException.Create('The connection closed')
  474. else if Result < 0 then
  475. if WouldBlock(socketerror) then
  476. Result := 0
  477. else
  478. raise ESocketError.Create(socketerror, 'recv');
  479. end;
  480. function ReceiveFrom(const ASocket: TFPSocket; ABuffer: Pointer; MaxSize: SizeInt;
  481. AFlags: Integer): TReceiveFromResult;
  482. var
  483. addr: _TAddressUnion;
  484. addrLen: TSocklen;
  485. begin
  486. Result := Default(TReceiveFromResult);
  487. addrLen := SizeOf(_TAddressUnion);
  488. Result.DataSize := fprecvfrom(ASocket.FD, ABuffer, MaxSize, AFlags, socketsunit.PSockAddr(@addr), @addrLen);
  489. if Result.DataSize < 0 then
  490. if WouldBlock(socketerror) then
  491. Exit(Default(TReceiveFromResult)) // Will set the DataSize of return to 0
  492. else
  493. raise ESocketError.Create(socketerror, 'recvfrom');
  494. ReadAddr(addr, ASocket.SocketType = stIPDualStack, Result.FromAddr, Result.FromPort);
  495. end;
  496. function ReceiveFromNonBlocking(const ASocket:TFPSocket;ABuffer:Pointer;MaxSize:
  497. SizeInt;AFlags:Integer):specialize TNullable<TReceiveFromResult>;
  498. begin
  499. Result := ReceiveFromNonBlocking(ASocket, ABuffer, MaxSize, AFlags);
  500. if Result.Value.DataSize = 0 then
  501. Result := null;
  502. end;
  503. function Send(const ASocket: TFPSocket; ABuffer: Pointer; ASize: SizeInt;
  504. AFlags: Integer): SizeInt;
  505. begin
  506. Result := fpsend(ASocket.FD, ABuffer, ASize, AFlags);
  507. if Result < 0 then
  508. if WouldBlock(socketerror) then
  509. Result := 0
  510. else
  511. raise ESocketError.Create(socketerror, 'send');
  512. end;
  513. function SendTo(const ASocket: TFPSocket; const ReceiverAddr: TNetworkAddress;
  514. ReceiverPort: Word; ABuffer: Pointer; ASize: SizeInt; AFlags: Integer
  515. ): SizeInt;
  516. var
  517. addr: _TAddressUnion;
  518. begin
  519. addr := CreateAddr(ReceiverAddr, ReceiverPort, ASocket.SocketType = stIPDualStack);
  520. Result := fpsendto(ASocket.FD, ABuffer, ASize, AFlags, socketsunit.psockaddr(@addr), SizeOf(addr));
  521. if Result < 0 then
  522. if WouldBlock(socketerror) then
  523. Result := 0
  524. else
  525. raise ESocketError.Create(socketerror, 'sendto');
  526. end;
  527. function ReceiveStr(const ASocket: TFPSocket; MaxLength: SizeInt;
  528. AFlags: Integer): String;
  529. const
  530. ReadSize = 1024;
  531. var
  532. Len, ReadLen: SizeInt;
  533. begin
  534. Result := '';
  535. if (MaxLength < 0) and (ASocket.Protocol = spDatagram) then
  536. MaxLength := MaxUDPPackageSize;
  537. // If maxlength read as much
  538. if MaxLength > 0 then
  539. begin
  540. SetLength(Result, MaxLength);
  541. Len := Receive(ASocket, @Result[1], MaxLength, AFlags);
  542. SetLength(Result, Len);
  543. Exit;
  544. end;
  545. // If no maxlength do a blocking read (required to figure if stream was closed)
  546. Len := 0;
  547. MaxLength := BytesAvailable(ASocket);
  548. if MaxLength = 0 then
  549. MaxLength := ReadSize;
  550. repeat
  551. SetLength(Result, Len + MaxLength);
  552. ReadLen := Receive(ASocket, @Result[1+Len], MaxLength, AFlags);
  553. if ReadLen = 0 then // non blocking
  554. break;
  555. Len += ReadLen;
  556. // Check if more was received while reading
  557. MaxLength:=BytesAvailable(ASocket);
  558. until (Len < Length(Result)) or (MaxLength <= 0);
  559. SetLength(Result, Len);
  560. end;
  561. function ReceiveStrFrom(const ASocket: TFPSocket; MaxLength: SizeInt;
  562. AFlags: Integer): TReceiveFromStringMessage;
  563. var
  564. UdpMessage: TReceiveFromResult;
  565. begin
  566. Result := Default(TReceiveFromStringMessage);
  567. SetLength(Result.Data, MaxLength);
  568. UdpMessage := ReceiveFrom(ASocket, @Result.Data[1], MaxLength, AFlags);
  569. SetLength(Result.Data, UdpMessage.DataSize);
  570. Result.FromAddr := UdpMessage.FromAddr;
  571. Result.FromPort := UdpMessage.FromPort;
  572. end;
  573. function ReceiveStrFromNonBlocking(const ASocket: TFPSocket;
  574. MaxLength: SizeInt; AFlags: Integer): specialize TNullable<
  575. TReceiveFromStringMessage>;
  576. var
  577. UdpMessage: TReceiveFromResult;
  578. begin
  579. SetLength(Result.Ptr^.Data, MaxLength);
  580. UdpMessage := ReceiveFrom(ASocket, @Result.Ptr^.Data[1], MaxLength, AFlags);
  581. if UdpMessage.DataSize = 0 then
  582. Exit(null);
  583. SetLength(Result.Ptr^.Data, UdpMessage.DataSize);
  584. Result.Ptr^.FromAddr := UdpMessage.FromAddr;
  585. Result.Ptr^.FromPort := UdpMessage.FromPort;
  586. end;
  587. function SendStr(const ASocket: TFPSocket; const AData: String; AFlags: Integer
  588. ): SizeInt;
  589. begin
  590. if Length(AData) = 0 then Exit(0);
  591. Result := Send(ASocket, @AData[1], Length(AData), AFlags);
  592. end;
  593. function SendStrTo(const ASocket: TFPSocket;
  594. const ReceiverAddr: TNetworkAddress; ReceiverPort: Word; const AData: String; AFlags: Integer
  595. ): SizeInt;
  596. begin
  597. if Length(AData) = 0 then Exit(0);
  598. Result := SendTo(ASocket, ReceiverAddr, ReceiverPort, @AData[1], Length(AData), AFlags);
  599. end;
  600. generic function Receive<T>(const ASocket: TFPSocket; AFlags: Integer = 0): T;
  601. var
  602. Frag: TBytes;
  603. Len, ReadLen: SizeInt;
  604. begin
  605. Result := Default(T);
  606. Len := 0;
  607. while Len < SizeOf(Result) do
  608. begin
  609. ReadLen := Receive(ASocket, @PByte(@Result)[Len], SizeOf(Result) - Len, AFlags);
  610. if ReadLen = 0 then
  611. if Len = 0 then
  612. raise ESocketError.Create(EsockEWOULDBLOCK, 'recv')
  613. else // Fragment received but non blocking afterwards
  614. begin
  615. SetLength(Frag, Len);
  616. Move(Result, Frag[0], Len);
  617. raise EFragmentedData.Create(Frag, SizeOf(T), 'Only fragment received in non blocking read');
  618. end;
  619. Len += ReadLen;
  620. end;
  621. end;
  622. generic function ReceiveNonBlocking<T>(const ASocket: TFPSocket; AFlags: Integer = 0): specialize TNullable<T>;
  623. var
  624. Frag: TBytes;
  625. Len, ReadLen: SizeInt;
  626. begin
  627. Len := 0;
  628. while Len < SizeOf(Result.Ptr^) do
  629. begin
  630. ReadLen := Receive(ASocket, @PByte(@Result.Ptr^)[Len], SizeOf(Result.Ptr^) - Len, AFlags);
  631. if ReadLen = 0 then
  632. if Len = 0 then
  633. Exit(null)
  634. else // Fragment received but non blocking afterwards
  635. begin
  636. SetLength(Frag, Len);
  637. Move(Result.Ptr^, Frag[0], Len);
  638. raise EFragmentedData.Create(Frag, SizeOf(T), 'Only fragment received in non blocking read');
  639. end;
  640. Len += ReadLen;
  641. end;
  642. end;
  643. generic function ReceiveFrom<T>(const ASocket: TFPSocket; AFlags: Integer = 0): specialize TReceiveFromMessage<T>;
  644. var
  645. Frag: TBytes;
  646. UdpMessage: TReceiveFromResult;
  647. begin
  648. Result := Default(specialize TReceiveFromMessage<T>);
  649. UdpMessage := ReceiveFrom(ASocket, @Result.Data, SizeOf(Result.Data), AFlags);
  650. if UdpMessage.DataSize < SizeOf(T) then
  651. if UdpMessage.DataSize = 0 then
  652. raise ESocketError.Create(EsockEWOULDBLOCK, 'recvfrom')
  653. else
  654. begin
  655. SetLength(Frag, UdpMessage.DataSize);
  656. Move(Result.Data, Frag[0], UdpMessage.DataSize);
  657. raise EFragmentedData.Create(Frag, SizeOf(T), 'Only fragment received ReceiveFrom, likely UDP Fragmentation');
  658. end;
  659. Result.FromAddr := UdpMessage.FromAddr;
  660. Result.FromPort := UdpMessage.FromPort;
  661. end;
  662. generic function ReceiveFromNonBlocking<T>(const ASocket: TFPSocket; AFlags: Integer = 0): specialize TNullable<specialize TReceiveFromMessage<T>>;
  663. var
  664. Frag: TBytes;
  665. UdpMessage: TReceiveFromResult;
  666. begin
  667. UdpMessage := ReceiveFrom(ASocket, @Result.Ptr^.Data, SizeOf(Result.Ptr^.Data), AFlags);
  668. if UdpMessage.DataSize < SizeOf(T) then
  669. if UdpMessage.DataSize = 0 then
  670. Exit(null)
  671. else
  672. begin
  673. SetLength(Frag, UdpMessage.DataSize);
  674. Move(Result.Ptr^.Data, Frag[0], UdpMessage.DataSize);
  675. raise EFragmentedData.Create(Frag, SizeOf(T), 'Only fragment received ReceiveFrom, likely UDP Fragmentation');
  676. end;
  677. Result.Ptr^.FromAddr := UdpMessage.FromAddr;
  678. Result.Ptr^.FromPort := UdpMessage.FromPort;
  679. end;
  680. generic function Send<T>(const ASocket: TFPSocket; constref AData: T; AFlags: Integer = 0): SizeInt;
  681. begin
  682. Result := Send(ASocket, @AData, SizeOf(T), AFlags);
  683. end;
  684. generic function SendTo<T>(const ASocket: TFPSocket; const ReceiverAddr: TNetworkAddress; ReceiverPort: Word; constref AData: T; AFlags: Integer = 0): SizeInt;
  685. begin
  686. Result := SendTo(ASocket, ReceiverAddr, ReceiverPort, @AData, SizeOf(T), AFlags);
  687. end;
  688. generic function ReceiveArray<T>(const ASocket: TFPSocket; MaxCount: SizeInt;
  689. AFlags: Integer = 0): specialize TArray<T>;
  690. const
  691. SizeOfT = SizeOf(T);
  692. ReadCount = 1024 div SizeOfT;
  693. var
  694. Frag: TBytes;
  695. Len, ReadLen: SizeInt;
  696. begin
  697. Result := nil;
  698. if (MaxCount < 0) and (ASocket.Protocol = spDatagram) then
  699. {$Push}
  700. {$WARN 6018 off}
  701. if SizeOf(T) < MaxUDPPackageSize then
  702. MaxCount := MaxUDPPackageSize div SizeOf(T)
  703. else // Lets try anyway and if it fails it fails
  704. MaxCount := 1;
  705. {$Pop}
  706. // If MaxCount, read MaxCount
  707. if MaxCount > 0 then
  708. begin
  709. SetLength(Result, MaxCount);
  710. Len := 0;
  711. repeat
  712. ReadLen := Receive(ASocket, @PByte(@Result[0])[Len], MaxCount * SizeOf(T) - Len, AFlags);
  713. if ReadLen = 0 then
  714. if Len = 0 then
  715. break
  716. else
  717. begin
  718. SetLength(Frag, Len);
  719. Move(Result[0], Frag[0], Len);
  720. raise EFragmentedData.Create(Frag, (Len div SizeOf(T) + 1) * SizeOf(T),
  721. 'Receiving of fragmented data is not supported by typed receive');
  722. end;
  723. Len += ReadLen;
  724. until (Len mod SizeOf(T)) = 0;
  725. SetLength(Result, Len div SizeOf(T));
  726. Exit;
  727. end;
  728. // Else do a (blocking) read and then read as much as in buffer, plus block to finish open blocks
  729. Len := 0;
  730. MaxCount := BytesAvailable(ASocket) div SizeOfT;
  731. {$Push}
  732. {$WARN 6018 off}
  733. if MaxCount = 0 then
  734. if ReadCount = 0 then
  735. MaxCount := 1
  736. else
  737. MaxCount := ReadCount;
  738. {$Pop}
  739. repeat
  740. SetLength(Result, Length(Result)+MaxCount);
  741. ReadLen := Receive(ASocket, @PByte(@Result[0])[Len], MaxCount*SizeOfT, AFlags);
  742. if ReadLen = 0 then
  743. if Len = 0 then
  744. break
  745. else
  746. begin
  747. SetLength(Frag, Len);
  748. Move(Result[0], Frag[0], Len);
  749. raise EFragmentedData.Create(Frag, (Len div SizeOf(T) + 1) * SizeOf(T),
  750. 'Receiving of fragmented data is not supported by typed receive');
  751. end;
  752. Len += ReadLen;
  753. MaxCount := BytesAvailable(ASocket) div SizeOfT;
  754. until ((Len<Length(Result)*SizeOf(T)) Or (MaxCount = 0)) And ((Len mod SizeOf(T)) = 0);
  755. SetLength(Result, Len div SizeOf(T));
  756. end;
  757. generic function ReceiveArrayFrom<T>(const ASocket: TFPSocket; MaxCount: SizeInt;
  758. AFlags: Integer = 0): specialize TReceiveFromMessage<specialize TArray<T>>;
  759. var
  760. Frag: TBytes;
  761. UdpMessage: TReceiveFromResult;
  762. begin
  763. if MaxCount < 0 then
  764. if SizeOf(T) < MaxUDPPackageSize then
  765. MaxCount := MaxUDPPackageSize div SizeOf(T)
  766. else // Lets try anyway and if it fails it fails
  767. MaxCount := 1;
  768. Result.Data := nil;
  769. SetLength(Result.Data, MaxCount);
  770. UdpMessage := ReceiveFrom(ASocket, @Result.Data[0], MaxCount * SizeOf(T), AFlags);
  771. if UdpMessage.DataSize mod SizeOf(T) > 0 then
  772. begin
  773. SetLength(Frag, UdpMessage.DataSize);
  774. Move(Result.Data[0], Frag[0], UdpMessage.DataSize);
  775. raise EFragmentedData.Create(Frag, (UdpMessage.DataSize div SizeOf(T) + 1) * SizeOf(T),
  776. 'Receiving of fragmented data is not supported by typed receive');
  777. end;
  778. SetLength(Result.Data, UdpMessage.DataSize div SizeOf(T));
  779. Result.FromAddr := UdpMessage.FromAddr;
  780. Result.FromPort := UdpMessage.FromPort;
  781. end;
  782. generic function ReceiveArrayFromNonBlocking<T>(const ASocket: TFPSocket;
  783. MaxCount: SizeInt = -1; AFlags: Integer = 0
  784. ): specialize TNullable<specialize TReceiveFromMessage<specialize TArray<T>>>;
  785. var
  786. Frag: TBytes;
  787. UdpMessage: TReceiveFromResult;
  788. begin
  789. if MaxCount < 0 then
  790. if SizeOf(T) < MaxUDPPackageSize then
  791. MaxCount := MaxUDPPackageSize div SizeOf(T)
  792. else // Lets try anyway and if it fails it fails
  793. MaxCount := 1;
  794. Result.Ptr^.Data := nil;
  795. SetLength(Result.Ptr^.Data, MaxCount);
  796. UdpMessage := ReceiveFrom(ASocket, @Result.Ptr^.Data[0], MaxCount * SizeOf(T), AFlags);
  797. if UdpMessage.DataSize = 0 then
  798. Exit(null);
  799. if UdpMessage.DataSize mod SizeOf(T) > 0 then
  800. begin
  801. SetLength(Frag, UdpMessage.DataSize);
  802. Move(Result.Ptr^.Data[0], Frag[0], UdpMessage.DataSize);
  803. raise EFragmentedData.Create(Frag, (UdpMessage.DataSize div SizeOf(T) + 1) * SizeOf(T),
  804. 'Receiving of fragmented data is not supported by typed receive');
  805. end;
  806. SetLength(Result.Ptr^.Data, UdpMessage.DataSize div SizeOf(T));
  807. Result.Ptr^.FromAddr := UdpMessage.FromAddr;
  808. Result.Ptr^.FromPort := UdpMessage.FromPort;
  809. end;
  810. generic function SendArray<T>(const ASocket: TFPSocket; const AData: specialize TArray<T>; AFlags: Integer = 0): SizeInt;
  811. begin
  812. if Length(AData) = 0 then Exit(0);
  813. Result := Send(ASocket, @AData[0], Length(AData) * SizeOf(T), AFlags);
  814. end;
  815. generic function SendArrayTo<T>(const ASocket: TFPSocket; const ReceiverAddr: TNetworkAddress; ReceiverPort: Word; const AData: specialize TArray<T>; AFlags: Integer = 0): SizeInt;
  816. begin
  817. if Length(AData) = 0 then Exit(0);
  818. Result := SendTo(ASocket, ReceiverAddr, ReceiverPort, @AData[0], Length(AData) * SizeOf(T), AFlags);
  819. end;
  820. procedure SetNonBlocking(const ASocket: TFPSocket; AValue: Boolean);
  821. {$IfDef Windows}
  822. var
  823. nonblock: u_long;
  824. begin
  825. nonblock := Ord(AValue);
  826. ioctlsocket(ASocket.FD, LongInt(FIONBIO), @nonblock);
  827. end;
  828. {$Else}
  829. var
  830. State: cint;
  831. begin
  832. State := FpFcntl(ASocket.FD, F_GetFl);
  833. if AValue then
  834. State := State Or O_NONBLOCK
  835. else
  836. State := State And not O_NONBLOCK;
  837. FpFcntl(ASocket.FD, F_SetFL, state);
  838. end;
  839. {$EndIf}
  840. function DataAvailable(const SocketArray: specialize TArray<TFPSocket>;
  841. TimeOut: Integer): specialize TArray<TFPSocket>;
  842. var
  843. FDSet: TFDSet;
  844. MaxSock: socketsunit.TSocket;
  845. timeval: TTimeVal;
  846. Ret: LongInt;
  847. i, WriteHead: Integer;
  848. begin
  849. Result := nil;
  850. MaxSock := 0;
  851. {$IfDef UNIX}fpFD_ZERO{$else}FD_ZERO{$endif}(FDSet);
  852. for i:=0 to Length(SocketArray) - 1 do
  853. begin
  854. MaxSock := Max(MaxSock, SocketArray[i].FD);
  855. {$IfDef UNIX}fpFD_SET{$else}FD_SET{$endif}(SocketArray[i].FD, FDSet);
  856. end;
  857. timeval.tv_sec := TimeOut div 1000;
  858. timeval.tv_usec := (TimeOut mod 1000) * 1000;
  859. Ret := {$IfDef UNIX}fpselect{$else}select{$endif}(MaxSock + 1, @FDSet, nil, nil, @timeval);
  860. if Ret < 0 then
  861. raise ESocketError.Create(socketerror, 'select');
  862. SetLength(Result, Ret);
  863. WriteHead := 0;
  864. for i:=0 to Length(SocketArray) - 1 do
  865. if {$IfDef UNIX}fpFD_ISSET{$else}FD_ISSET{$endif}(SocketArray[i].FD, FDSet) {$Ifdef Unix}> 0{$Endif} then
  866. begin
  867. Result[WriteHead] := SocketArray[i];
  868. Inc(WriteHead);
  869. end;
  870. end;
  871. function DataAvailable(const ASocket: TFPSocket; TimeOut: Integer): Boolean;
  872. var
  873. Arr: array of TFPSocket;
  874. begin
  875. Arr := [ASocket];
  876. Result := Length(DataAvailable(Arr, TimeOut)) > 0;
  877. end;
  878. function DataAvailable(const SocketArray: array of TFPSocket; TimeOut: Integer
  879. ): specialize TArray<TFPSocket>;
  880. var
  881. Arr: array of TFPSocket;
  882. begin
  883. if Length(SocketArray) = 0 then Exit(nil);
  884. SetLength(Arr, Length(SocketArray));
  885. Move(SocketArray[0], Arr[0], Length(SocketArray) * SizeOf(SocketArray[0]));
  886. Result := DataAvailable(arr, TimeOut);
  887. end;
  888. function BytesAvailable(const ASocket: TFPSocket): SizeInt;
  889. var
  890. {$IfDef WINDOWS}
  891. count: DWord;
  892. {$Else}
  893. count: cint;
  894. {$EndIf}
  895. begin
  896. Result := -1;
  897. {$IfDef WINDOWS}
  898. if ioctlsocket(ASocket.FD, FIONREAD, @count) = 0 then
  899. {$Else}
  900. if FpIOCtl(ASocket.FD, FIONREAD, @count) = 0 then
  901. {$EndIf}
  902. Result := Count;
  903. end;
  904. function StreamClosed(const ASocket:TFPSocket):Boolean;
  905. begin
  906. Result := (ASocket.Protocol <> spStream) Or (
  907. DataAvailable(ASocket, 0) And
  908. (BytesAvailable(ASocket) = 0)
  909. );
  910. end;
  911. function ConnectionState(const ASocket:TFPSocket): TConnectionState;
  912. const
  913. ECONNREFUSED = {$IfDef WINDOWS}WSAECONNREFUSED{$ELSE}ESysECONNREFUSED{$EndIf};
  914. begin
  915. if (ASocket.Protocol <> spStream) then
  916. Exit(csNotConnected);
  917. if (socketsunit.fprecv(ASocket.FD, nil, 0, 0) = 0) And
  918. (socketsunit.fpsend(ASocket.FD, nil, 0, 0) = 0) then
  919. Exit(csConnected);
  920. case socketerror of
  921. EsockEWOULDBLOCK: Result := csConnected;
  922. ESockENOTCONN: Result := csPending;
  923. ECONNREFUSED: Result := csRefused;
  924. else
  925. Result := csError;
  926. end;
  927. end;
  928. { ESocketError }
  929. constructor ESocketError.Create(ACode: Integer; const FunName: String);
  930. begin
  931. inherited CreateFmt('[Socket Error: %d] %s call failed', [ACode, FunName]);
  932. FCode := ACode;
  933. end;
  934. { EFragmentedData }
  935. constructor EFragmentedData.Create(const AFragment: TBytes; AExpected: SizeInt;
  936. const AMessage: String);
  937. begin
  938. inherited Create(AMessage);
  939. FFragment := AFragment;
  940. FExpectedSize := AExpected;
  941. end;
  942. end.