fpsockets.pp 38 KB

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