|
@@ -22,10 +22,10 @@ interface
|
|
|
|
|
|
{$IFDEF FPC_DOTTEDUNITS}
|
|
{$IFDEF FPC_DOTTEDUNITS}
|
|
uses
|
|
uses
|
|
- System.SysUtils, System.Net.Sockets, System.Nullable;
|
|
|
|
|
|
+ System.SysUtils, System.Net.Sockets, System.Nullable, System.Tuples;
|
|
{$ELSE FPC_DOTTEDUNITS}
|
|
{$ELSE FPC_DOTTEDUNITS}
|
|
uses
|
|
uses
|
|
- sysutils, sockets, nullable;
|
|
|
|
|
|
+ sysutils, sockets, nullable, tuples;
|
|
{$ENDIF FPC_DOTTEDUNITS}
|
|
{$ENDIF FPC_DOTTEDUNITS}
|
|
|
|
|
|
type
|
|
type
|
|
@@ -77,9 +77,9 @@ type
|
|
EDualStackNotSupported = class(Exception);
|
|
EDualStackNotSupported = class(Exception);
|
|
EUnsupportedAddress = class(Exception);
|
|
EUnsupportedAddress = class(Exception);
|
|
|
|
|
|
- { ESocketError }
|
|
|
|
|
|
+ { ESocketCodeError }
|
|
|
|
|
|
- ESocketError = class(Exception)
|
|
|
|
|
|
+ ESocketCodeError = class(Exception)
|
|
private
|
|
private
|
|
FCode: Integer;
|
|
FCode: Integer;
|
|
public
|
|
public
|
|
@@ -125,6 +125,9 @@ function IN6Equal(const A, B: String): Boolean;
|
|
operator =(const A, B: TNetworkAddress): Boolean; inline;
|
|
operator =(const A, B: TNetworkAddress): Boolean; inline;
|
|
operator <>(const A, B: TNetworkAddress): Boolean; inline;
|
|
operator <>(const A, B: TNetworkAddress): Boolean; inline;
|
|
operator :=(const AStr: String): TNetworkAddress; inline;
|
|
operator :=(const AStr: String): TNetworkAddress; inline;
|
|
|
|
+operator :=(const AAddr: TNetworkAddress): String; inline;
|
|
|
|
+operator =(const AStr: String; const AAddr: TNetworkAddress): Boolean; inline;
|
|
|
|
+operator =(const AAddr: TNetworkAddress; const AStr: String): Boolean; inline;
|
|
|
|
|
|
{ Socket Functions }
|
|
{ Socket Functions }
|
|
|
|
|
|
@@ -171,6 +174,9 @@ generic function SendArrayTo<T>(const ASocket: TFPSocket; const ReceiverAddr: TN
|
|
|
|
|
|
procedure SetNonBlocking(const ASocket: TFPSocket; AValue: Boolean);
|
|
procedure SetNonBlocking(const ASocket: TFPSocket; AValue: Boolean);
|
|
|
|
|
|
|
|
+function LocalEndpoint(const ASocket: TFPSocket): specialize TPair<TNetworkAddress, Word>;
|
|
|
|
+function RemoteEndpoint(const ASocket: TFPSocket): specialize TPair<TNetworkAddress, Word>;
|
|
|
|
+
|
|
// Timeout in MS
|
|
// Timeout in MS
|
|
function DataAvailable(const SocketArray: specialize TArray<TFPSocket>; TimeOut: Integer = 0): specialize TArray<TFPSocket>; overload;
|
|
function DataAvailable(const SocketArray: specialize TArray<TFPSocket>; TimeOut: Integer = 0): specialize TArray<TFPSocket>; overload;
|
|
function DataAvailable(const ASocket: TFPSocket; TimeOut: Integer = 0): Boolean; overload; //inline;
|
|
function DataAvailable(const ASocket: TFPSocket; TimeOut: Integer = 0): Boolean; overload; //inline;
|
|
@@ -186,6 +192,25 @@ function StreamClosed(const ASocket: TFPSocket): Boolean; inline;
|
|
// if the stream is actually open
|
|
// if the stream is actually open
|
|
function ConnectionState(const ASocket: TFPSocket): TConnectionState;
|
|
function ConnectionState(const ASocket: TFPSocket): TConnectionState;
|
|
|
|
|
|
|
|
+
|
|
|
|
+{ Helper }
|
|
|
|
+
|
|
|
|
+type
|
|
|
|
+ PAddressUnion = ^TAddressUnion;
|
|
|
|
+ TAddressUnion = record
|
|
|
|
+ case TFPSocketType of
|
|
|
|
+ stIPv4: (In4Addr: sockaddr_in);
|
|
|
|
+ stIPv6: (In6Addr: sockaddr_in6);
|
|
|
|
+ stUnixSocket: (UnixAddr: sockaddr_un);
|
|
|
|
+ end;
|
|
|
|
+
|
|
|
|
+function SocketInvalid(ASocket: TSocket): Boolean; inline;
|
|
|
|
+
|
|
|
|
+function CreateAddr(AAddress: TNetworkAddress; APort: Word; DualStack: Boolean): TAddressUnion;
|
|
|
|
+procedure ReadAddr(constref Addr: TAddressUnion; DualStack: Boolean; out
|
|
|
|
+ AAddress: TNetworkAddress; out APort: Word);
|
|
|
|
+function CreateRawSocket(ADomain: TFPSocketType; ASockProto: TFPSocketProto; AProto: Integer; RaiseSocketException: Boolean=True): TSocket;
|
|
|
|
+
|
|
implementation
|
|
implementation
|
|
|
|
|
|
{$IFDEF FPC_DOTTEDUNITS}
|
|
{$IFDEF FPC_DOTTEDUNITS}
|
|
@@ -205,15 +230,6 @@ uses
|
|
|
|
|
|
{ Helper }
|
|
{ Helper }
|
|
|
|
|
|
-type
|
|
|
|
- _PAddressUnion = ^_TAddressUnion;
|
|
|
|
- _TAddressUnion = record
|
|
|
|
- case TFPSocketType of
|
|
|
|
- stIPv4: (In4Addr: socketsunit.sockaddr_in);
|
|
|
|
- stIPv6: (In6Addr: socketsunit.sockaddr_in6);
|
|
|
|
- stUnixSocket: (UnixAddr: socketsunit.sockaddr_un);
|
|
|
|
- end;
|
|
|
|
-
|
|
|
|
const
|
|
const
|
|
IPPROTO_IPV6 = {$IfDef WINDOWS}41{$Else}41{$EndIf};
|
|
IPPROTO_IPV6 = {$IfDef WINDOWS}41{$Else}41{$EndIf};
|
|
IPV6_V6ONLY = {$IfDef WINDOWS}27{$Else}26{$EndIf};
|
|
IPV6_V6ONLY = {$IfDef WINDOWS}27{$Else}26{$EndIf};
|
|
@@ -224,7 +240,8 @@ begin
|
|
{$IfDef Unix} or (SockErr = ESysEAGAIN) {$EndIf}
|
|
{$IfDef Unix} or (SockErr = ESysEAGAIN) {$EndIf}
|
|
end;
|
|
end;
|
|
|
|
|
|
-function CreateAddr(AAddress: TNetworkAddress; APort: Word; DualStack: Boolean): _TAddressUnion;
|
|
|
|
|
|
+function CreateAddr(AAddress:TNetworkAddress;APort:Word;DualStack:Boolean)
|
|
|
|
+ :TAddressUnion;
|
|
begin
|
|
begin
|
|
if (AAddress.AddressType = atIN4) and DualStack then
|
|
if (AAddress.AddressType = atIN4) and DualStack then
|
|
AAddress := IN4MappedIN6Address(AAddress.Address);
|
|
AAddress := IN4MappedIN6Address(AAddress.Address);
|
|
@@ -254,7 +271,7 @@ begin
|
|
raise EUnsupportedAddress.Create('Address type ' + ord(AAddress.AddressType).ToString + ' not supported');
|
|
raise EUnsupportedAddress.Create('Address type ' + ord(AAddress.AddressType).ToString + ' not supported');
|
|
end;
|
|
end;
|
|
|
|
|
|
-procedure ReadAddr(constref Addr: _TAddressUnion; DualStack: Boolean; out
|
|
|
|
|
|
+procedure ReadAddr(constref Addr: TAddressUnion; DualStack: Boolean; out
|
|
AAddress: TNetworkAddress; out APort: Word);
|
|
AAddress: TNetworkAddress; out APort: Word);
|
|
var
|
|
var
|
|
i:Integer;
|
|
i:Integer;
|
|
@@ -297,7 +314,7 @@ begin
|
|
{$EndIf}
|
|
{$EndIf}
|
|
end;
|
|
end;
|
|
|
|
|
|
-function CreateRawSocket(ADomain: TFPSocketType; ASockProto: TFPSocketProto; AProto: Integer): TSocket;
|
|
|
|
|
|
+function CreateRawSocket(ADomain: TFPSocketType; ASockProto: TFPSocketProto; AProto: Integer; RaiseSocketException: Boolean): TSocket;
|
|
var
|
|
var
|
|
AFam, AType, v6Only: Integer;
|
|
AFam, AType, v6Only: Integer;
|
|
begin
|
|
begin
|
|
@@ -313,7 +330,10 @@ begin
|
|
end;
|
|
end;
|
|
Result := fpsocket(AFam, AType, AProto);
|
|
Result := fpsocket(AFam, AType, AProto);
|
|
if SocketInvalid(Result) then
|
|
if SocketInvalid(Result) then
|
|
- raise ESocketError.Create(socketerror, 'socket');
|
|
|
|
|
|
+ if RaiseSocketException then
|
|
|
|
+ raise ESocketCodeError.Create(socketerror, 'socket')
|
|
|
|
+ else
|
|
|
|
+ exit;
|
|
|
|
|
|
if ADomain = stIPDualStack then
|
|
if ADomain = stIPDualStack then
|
|
begin
|
|
begin
|
|
@@ -477,29 +497,29 @@ procedure Bind(const ASocket: TFPSocket; const AAddress: TNetworkAddress;
|
|
APort: Word; ReuseAddr: Boolean);
|
|
APort: Word; ReuseAddr: Boolean);
|
|
var
|
|
var
|
|
enableReuse: Integer = 1;
|
|
enableReuse: Integer = 1;
|
|
- addr: _TAddressUnion;
|
|
|
|
|
|
+ addr: TAddressUnion;
|
|
begin
|
|
begin
|
|
if ReuseAddr then
|
|
if ReuseAddr then
|
|
fpsetsockopt(ASocket.FD, SOL_SOCKET, SO_REUSEADDR, @enableReuse, SizeOf(enableReuse));
|
|
fpsetsockopt(ASocket.FD, SOL_SOCKET, SO_REUSEADDR, @enableReuse, SizeOf(enableReuse));
|
|
addr := CreateAddr(AAddress, APort, ASocket.SocketType = stIPDualStack);
|
|
addr := CreateAddr(AAddress, APort, ASocket.SocketType = stIPDualStack);
|
|
if fpbind(ASocket.FD, socketsunit.PSockAddr(@addr), SizeOf(addr)) <> 0 then raise
|
|
if fpbind(ASocket.FD, socketsunit.PSockAddr(@addr), SizeOf(addr)) <> 0 then raise
|
|
- ESocketError.Create(socketerror, 'bind (%s:%d)'.Format([AAddress.Address, APort]));
|
|
|
|
|
|
+ ESocketCodeError.Create(socketerror, 'bind (%s:%d)'.Format([AAddress.Address, APort]));
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure Listen(const ASocket: TFPSocket; Backlog: Integer);
|
|
procedure Listen(const ASocket: TFPSocket; Backlog: Integer);
|
|
begin
|
|
begin
|
|
if fplisten(ASocket.FD, Backlog) <> 0 then raise
|
|
if fplisten(ASocket.FD, Backlog) <> 0 then raise
|
|
- ESocketError.Create(socketerror, 'listen');
|
|
|
|
|
|
+ ESocketCodeError.Create(socketerror, 'listen');
|
|
end;
|
|
end;
|
|
|
|
|
|
function AcceptConnection(const ASocket: TFPSocket): TFPSocketConnection;
|
|
function AcceptConnection(const ASocket: TFPSocket): TFPSocketConnection;
|
|
var
|
|
var
|
|
- addr: _TAddressUnion;
|
|
|
|
|
|
+ addr: TAddressUnion;
|
|
addrLen: TSocklen = SizeOf(addr);
|
|
addrLen: TSocklen = SizeOf(addr);
|
|
begin
|
|
begin
|
|
Result.Socket.FD := fpaccept(ASocket.FD, socketsunit.psockaddr(@addr), @addrLen);
|
|
Result.Socket.FD := fpaccept(ASocket.FD, socketsunit.psockaddr(@addr), @addrLen);
|
|
if SocketInvalid(Result.Socket.FD) then
|
|
if SocketInvalid(Result.Socket.FD) then
|
|
- raise ESocketError.Create(socketerror, 'accept');
|
|
|
|
|
|
+ raise ESocketCodeError.Create(socketerror, 'accept');
|
|
Result.Socket.SocketType := ASocket.SocketType;
|
|
Result.Socket.SocketType := ASocket.SocketType;
|
|
Result.Socket.Protocol := ASocket.Protocol;
|
|
Result.Socket.Protocol := ASocket.Protocol;
|
|
ReadAddr(addr, ASocket.SocketType = stIPDualStack, Result.ClientAddress, Result.ClientPort);
|
|
ReadAddr(addr, ASocket.SocketType = stIPDualStack, Result.ClientAddress, Result.ClientPort);
|
|
@@ -508,7 +528,7 @@ end;
|
|
function AcceptNonBlocking(const ASocket: TFPSocket): specialize TNullable<
|
|
function AcceptNonBlocking(const ASocket: TFPSocket): specialize TNullable<
|
|
TFPSocketConnection>;
|
|
TFPSocketConnection>;
|
|
var
|
|
var
|
|
- addr: _TAddressUnion;
|
|
|
|
|
|
+ addr: TAddressUnion;
|
|
addrLen: TSocklen = SizeOf(addr);
|
|
addrLen: TSocklen = SizeOf(addr);
|
|
begin
|
|
begin
|
|
Result.Ptr^.Socket.FD := fpaccept(ASocket.FD, socketsunit.psockaddr(@addr), @addrLen);
|
|
Result.Ptr^.Socket.FD := fpaccept(ASocket.FD, socketsunit.psockaddr(@addr), @addrLen);
|
|
@@ -516,7 +536,7 @@ begin
|
|
if WouldBlock(socketerror) then
|
|
if WouldBlock(socketerror) then
|
|
Exit(null)
|
|
Exit(null)
|
|
else
|
|
else
|
|
- raise ESocketError.Create(socketerror, 'accept');
|
|
|
|
|
|
+ raise ESocketCodeError.Create(socketerror, 'accept');
|
|
Result.Ptr^.Socket.SocketType := ASocket.SocketType;
|
|
Result.Ptr^.Socket.SocketType := ASocket.SocketType;
|
|
Result.Ptr^.Socket.Protocol := ASocket.Protocol;
|
|
Result.Ptr^.Socket.Protocol := ASocket.Protocol;
|
|
ReadAddr(addr, ASocket.SocketType = stIPDualStack, Result.Ptr^.ClientAddress, Result.Ptr^.ClientPort);
|
|
ReadAddr(addr, ASocket.SocketType = stIPDualStack, Result.Ptr^.ClientAddress, Result.Ptr^.ClientPort);
|
|
@@ -525,7 +545,7 @@ end;
|
|
function Connect(const ASocket: TFPSocket; const AAddress: TNetworkAddress;
|
|
function Connect(const ASocket: TFPSocket; const AAddress: TNetworkAddress;
|
|
APort: Word): TConnectionState;
|
|
APort: Word): TConnectionState;
|
|
var
|
|
var
|
|
- addr: _TAddressUnion;
|
|
|
|
|
|
+ addr: TAddressUnion;
|
|
const
|
|
const
|
|
EALREADY = {$IfDef Windows}WSAEALREADY{$Else}ESysEALREADY{$EndIf};
|
|
EALREADY = {$IfDef Windows}WSAEALREADY{$Else}ESysEALREADY{$EndIf};
|
|
EINPROGRESS = {$IfDef Windows}WSAEINPROGRESS{$Else}ESysEINPROGRESS{$EndIf};
|
|
EINPROGRESS = {$IfDef Windows}WSAEINPROGRESS{$Else}ESysEINPROGRESS{$EndIf};
|
|
@@ -541,7 +561,7 @@ begin
|
|
ECONNREFUSED:
|
|
ECONNREFUSED:
|
|
Exit(csRefused);
|
|
Exit(csRefused);
|
|
else
|
|
else
|
|
- raise ESocketError.Create(socketerror, 'connect');
|
|
|
|
|
|
+ raise ESocketCodeError.Create(socketerror, 'connect');
|
|
end;
|
|
end;
|
|
if ASocket.Protocol<>spStream then
|
|
if ASocket.Protocol<>spStream then
|
|
Result := csNotConnected
|
|
Result := csNotConnected
|
|
@@ -559,23 +579,23 @@ begin
|
|
if WouldBlock(socketerror) then
|
|
if WouldBlock(socketerror) then
|
|
Result := 0
|
|
Result := 0
|
|
else
|
|
else
|
|
- raise ESocketError.Create(socketerror, 'recv');
|
|
|
|
|
|
+ raise ESocketCodeError.Create(socketerror, 'recv');
|
|
end;
|
|
end;
|
|
|
|
|
|
function ReceiveFrom(const ASocket: TFPSocket; ABuffer: Pointer; MaxSize: SizeInt;
|
|
function ReceiveFrom(const ASocket: TFPSocket; ABuffer: Pointer; MaxSize: SizeInt;
|
|
AFlags: Integer): TReceiveFromResult;
|
|
AFlags: Integer): TReceiveFromResult;
|
|
var
|
|
var
|
|
- addr: _TAddressUnion;
|
|
|
|
|
|
+ addr: TAddressUnion;
|
|
addrLen: TSocklen;
|
|
addrLen: TSocklen;
|
|
begin
|
|
begin
|
|
Result := Default(TReceiveFromResult);
|
|
Result := Default(TReceiveFromResult);
|
|
- addrLen := SizeOf(_TAddressUnion);
|
|
|
|
|
|
+ addrLen := SizeOf(TAddressUnion);
|
|
Result.DataSize := fprecvfrom(ASocket.FD, ABuffer, MaxSize, AFlags, socketsunit.PSockAddr(@addr), @addrLen);
|
|
Result.DataSize := fprecvfrom(ASocket.FD, ABuffer, MaxSize, AFlags, socketsunit.PSockAddr(@addr), @addrLen);
|
|
if Result.DataSize < 0 then
|
|
if Result.DataSize < 0 then
|
|
if WouldBlock(socketerror) then
|
|
if WouldBlock(socketerror) then
|
|
Exit(Default(TReceiveFromResult)) // Will set the DataSize of return to 0
|
|
Exit(Default(TReceiveFromResult)) // Will set the DataSize of return to 0
|
|
else
|
|
else
|
|
- raise ESocketError.Create(socketerror, 'recvfrom');
|
|
|
|
|
|
+ raise ESocketCodeError.Create(socketerror, 'recvfrom');
|
|
ReadAddr(addr, ASocket.SocketType = stIPDualStack, Result.FromAddr, Result.FromPort);
|
|
ReadAddr(addr, ASocket.SocketType = stIPDualStack, Result.FromAddr, Result.FromPort);
|
|
end;
|
|
end;
|
|
|
|
|
|
@@ -595,14 +615,14 @@ begin
|
|
if WouldBlock(socketerror) then
|
|
if WouldBlock(socketerror) then
|
|
Result := 0
|
|
Result := 0
|
|
else
|
|
else
|
|
- raise ESocketError.Create(socketerror, 'send');
|
|
|
|
|
|
+ raise ESocketCodeError.Create(socketerror, 'send');
|
|
end;
|
|
end;
|
|
|
|
|
|
function SendTo(const ASocket: TFPSocket; const ReceiverAddr: TNetworkAddress;
|
|
function SendTo(const ASocket: TFPSocket; const ReceiverAddr: TNetworkAddress;
|
|
ReceiverPort: Word; ABuffer: Pointer; ASize: SizeInt; AFlags: Integer
|
|
ReceiverPort: Word; ABuffer: Pointer; ASize: SizeInt; AFlags: Integer
|
|
): SizeInt;
|
|
): SizeInt;
|
|
var
|
|
var
|
|
- addr: _TAddressUnion;
|
|
|
|
|
|
+ addr: TAddressUnion;
|
|
begin
|
|
begin
|
|
addr := CreateAddr(ReceiverAddr, ReceiverPort, ASocket.SocketType = stIPDualStack);
|
|
addr := CreateAddr(ReceiverAddr, ReceiverPort, ASocket.SocketType = stIPDualStack);
|
|
Result := fpsendto(ASocket.FD, ABuffer, ASize, AFlags, socketsunit.psockaddr(@addr), SizeOf(addr));
|
|
Result := fpsendto(ASocket.FD, ABuffer, ASize, AFlags, socketsunit.psockaddr(@addr), SizeOf(addr));
|
|
@@ -610,7 +630,7 @@ begin
|
|
if WouldBlock(socketerror) then
|
|
if WouldBlock(socketerror) then
|
|
Result := 0
|
|
Result := 0
|
|
else
|
|
else
|
|
- raise ESocketError.Create(socketerror, 'sendto');
|
|
|
|
|
|
+ raise ESocketCodeError.Create(socketerror, 'sendto');
|
|
end;
|
|
end;
|
|
|
|
|
|
function ReceiveStr(const ASocket: TFPSocket; MaxLength: SizeInt;
|
|
function ReceiveStr(const ASocket: TFPSocket; MaxLength: SizeInt;
|
|
@@ -703,7 +723,7 @@ begin
|
|
ReadLen := Receive(ASocket, @PByte(@Result)[Len], SizeOf(Result) - Len, AFlags);
|
|
ReadLen := Receive(ASocket, @PByte(@Result)[Len], SizeOf(Result) - Len, AFlags);
|
|
if ReadLen = 0 then
|
|
if ReadLen = 0 then
|
|
if Len = 0 then
|
|
if Len = 0 then
|
|
- raise ESocketError.Create(EsockEWOULDBLOCK, 'recv')
|
|
|
|
|
|
+ raise ESocketCodeError.Create(EsockEWOULDBLOCK, 'recv')
|
|
else // Fragment received but non blocking afterwards
|
|
else // Fragment received but non blocking afterwards
|
|
begin
|
|
begin
|
|
SetLength(Frag, Len);
|
|
SetLength(Frag, Len);
|
|
@@ -745,7 +765,7 @@ begin
|
|
UdpMessage := ReceiveFrom(ASocket, @Result.Data, SizeOf(Result.Data), AFlags);
|
|
UdpMessage := ReceiveFrom(ASocket, @Result.Data, SizeOf(Result.Data), AFlags);
|
|
if UdpMessage.DataSize < SizeOf(T) then
|
|
if UdpMessage.DataSize < SizeOf(T) then
|
|
if UdpMessage.DataSize = 0 then
|
|
if UdpMessage.DataSize = 0 then
|
|
- raise ESocketError.Create(EsockEWOULDBLOCK, 'recvfrom')
|
|
|
|
|
|
+ raise ESocketCodeError.Create(EsockEWOULDBLOCK, 'recvfrom')
|
|
else
|
|
else
|
|
begin
|
|
begin
|
|
SetLength(Frag, UdpMessage.DataSize);
|
|
SetLength(Frag, UdpMessage.DataSize);
|
|
@@ -966,7 +986,7 @@ begin
|
|
timeval.tv_usec := (TimeOut mod 1000) * 1000;
|
|
timeval.tv_usec := (TimeOut mod 1000) * 1000;
|
|
Ret := {$IfDef UNIX}fpselect{$else}select{$endif}(MaxSock + 1, @FDSet, nil, nil, @timeval);
|
|
Ret := {$IfDef UNIX}fpselect{$else}select{$endif}(MaxSock + 1, @FDSet, nil, nil, @timeval);
|
|
if Ret < 0 then
|
|
if Ret < 0 then
|
|
- raise ESocketError.Create(socketerror, 'select');
|
|
|
|
|
|
+ raise ESocketCodeError.Create(socketerror, 'select');
|
|
|
|
|
|
SetLength(Result, Ret);
|
|
SetLength(Result, Ret);
|
|
WriteHead := 0;
|
|
WriteHead := 0;
|
|
@@ -1040,9 +1060,48 @@ begin
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
|
|
-{ ESocketError }
|
|
|
|
|
|
+function LocalEndpoint(const ASocket:TFPSocket):specialize TPair<TNetworkAddress
|
|
|
|
+ ,Word>;
|
|
|
|
+var
|
|
|
|
+ addr: TAddressUnion;
|
|
|
|
+ len: TSocklen;
|
|
|
|
+begin
|
|
|
|
+ len:=SizeOf(addr);
|
|
|
|
+ if fpGetSockName(ASocket.FD,psockaddr(@addr),@len) <> 0 then
|
|
|
|
+ raise ESocketCodeError.Create(socketerror,'getsockname');
|
|
|
|
+ ReadAddr(addr,ASocket.SocketType=stIPDualStack,Result.First,Result.Second);
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function RemoteEndpoint(const ASocket:TFPSocket):specialize TPair<
|
|
|
|
+ TNetworkAddress,Word>;
|
|
|
|
+var
|
|
|
|
+ addr: TAddressUnion;
|
|
|
|
+ len: TSocklen;
|
|
|
|
+begin
|
|
|
|
+ len:=SizeOf(addr);
|
|
|
|
+ if fpGetPeerName(ASocket.FD,psockaddr(@addr),@len) <> 0 then
|
|
|
|
+ raise ESocketCodeError.Create(socketerror,'getpeername');
|
|
|
|
+ ReadAddr(addr,ASocket.SocketType=stIPDualStack,Result.First,Result.Second);
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+operator:=(const AAddr:TNetworkAddress):String;
|
|
|
|
+begin
|
|
|
|
+ Result := AAddr.Address;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+operator=(const AStr:String;const AAddr:TNetworkAddress):Boolean;
|
|
|
|
+begin
|
|
|
|
+ Result:=NetAddr(AStr)=AAddr;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+operator=(const AAddr:TNetworkAddress;const AStr:String):Boolean;
|
|
|
|
+begin
|
|
|
|
+ Result:=AAddr=NetAddr(AStr);
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+{ ESocketCodeError }
|
|
|
|
|
|
-constructor ESocketError.Create(ACode: Integer; const FunName: String);
|
|
|
|
|
|
+constructor ESocketCodeError.Create(ACode: Integer; const FunName: String);
|
|
begin
|
|
begin
|
|
inherited CreateFmt('[Socket Error: %d] %s call failed', [ACode, FunName]);
|
|
inherited CreateFmt('[Socket Error: %d] %s call failed', [ACode, FunName]);
|
|
FCode := ACode;
|
|
FCode := ACode;
|