mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-12-17 01:40:55 +01:00
* First version, a simple starting point for further development
This commit is contained in:
parent
b3b9175ad0
commit
6c8db02009
245
fcl/net/fpsock.pp
Normal file
245
fcl/net/fpsock.pp
Normal file
@ -0,0 +1,245 @@
|
|||||||
|
{
|
||||||
|
$Id$
|
||||||
|
|
||||||
|
Socket components
|
||||||
|
Copyright (c) 2003 by
|
||||||
|
Areca Systems GmbH / Sebastian Guenther, sg@freepascal.org
|
||||||
|
|
||||||
|
See the file COPYING.FPC, included in this distribution,
|
||||||
|
for details about the copyright.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
}
|
||||||
|
|
||||||
|
unit fpSock;
|
||||||
|
|
||||||
|
interface
|
||||||
|
|
||||||
|
uses SysUtils, Sockets, Classes, fpAsync;
|
||||||
|
|
||||||
|
type
|
||||||
|
|
||||||
|
ESocketError = class(Exception)
|
||||||
|
end;
|
||||||
|
|
||||||
|
TSocketComponent = class(TComponent)
|
||||||
|
private
|
||||||
|
FEventLoop: TEventLoop;
|
||||||
|
protected
|
||||||
|
DataAvailableNotifyHandle: Pointer;
|
||||||
|
public
|
||||||
|
destructor Destroy; override;
|
||||||
|
property EventLoop: TEventLoop read FEventLoop write FEventLoop;
|
||||||
|
end;
|
||||||
|
|
||||||
|
TSocketStream = class(THandleStream)
|
||||||
|
private
|
||||||
|
FOnDisconnect: TNotifyEvent;
|
||||||
|
function GetLocalAddress: TSockAddr;
|
||||||
|
function GetPeerAddress: TSockAddr;
|
||||||
|
public
|
||||||
|
destructor Destroy; override;
|
||||||
|
function Read(var Buffer; Count: LongInt): LongInt; override;
|
||||||
|
function Write(const Buffer; Count: LongInt): LongInt; override;
|
||||||
|
|
||||||
|
property LocalAddress: TSockAddr read GetLocalAddress;
|
||||||
|
property PeerAddress: TSockAddr read GetPeerAddress;
|
||||||
|
property OnDisconnect: TNotifyEvent read FOnDisconnect write FOnDisconnect;
|
||||||
|
end;
|
||||||
|
|
||||||
|
// TCP/IP components
|
||||||
|
|
||||||
|
TTCPConnection = class(TSocketComponent)
|
||||||
|
end;
|
||||||
|
|
||||||
|
TTCPClient = class(TTCPConnection)
|
||||||
|
end;
|
||||||
|
|
||||||
|
TCustomTCPServer = class;
|
||||||
|
|
||||||
|
TQueryConnectEvent = procedure(Sender: TCustomTCPServer; Socket: Integer;
|
||||||
|
var DoConnect: Boolean) of object;
|
||||||
|
TConnectEvent = procedure(Sender: TCustomTCPServer;
|
||||||
|
Stream: TSocketStream) of object;
|
||||||
|
|
||||||
|
TCustomTCPServer = class(TTCPConnection)
|
||||||
|
private
|
||||||
|
FActive: Boolean;
|
||||||
|
FPort: Word;
|
||||||
|
FOnQueryConnect: TQueryConnectEvent;
|
||||||
|
FOnConnect: TConnectEvent;
|
||||||
|
procedure SetActive(Value: Boolean);
|
||||||
|
procedure ListenerDataAvailable(Sender: TObject);
|
||||||
|
protected
|
||||||
|
FSocket: Integer;
|
||||||
|
|
||||||
|
function DoQueryConnect(ASocket: Integer): Boolean; virtual;
|
||||||
|
procedure DoConnect(AStream: TSocketStream); virtual;
|
||||||
|
|
||||||
|
//!!!: Interface/bindings list?
|
||||||
|
property Active: Boolean read FActive write SetActive;
|
||||||
|
property Port: Word read FPort write FPort;
|
||||||
|
property OnQueryConnect: TQueryConnectEvent read FOnQueryConnect
|
||||||
|
write FOnQueryConnect;
|
||||||
|
property OnConnect: TConnectEvent read FOnConnect write FOnConnect;
|
||||||
|
end;
|
||||||
|
|
||||||
|
TTCPServer = class(TCustomTCPServer)
|
||||||
|
public
|
||||||
|
property Socket: Integer read FSocket;
|
||||||
|
published
|
||||||
|
property Active;
|
||||||
|
property Port;
|
||||||
|
property OnQueryConnect;
|
||||||
|
property OnConnect;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
// UDP/IP components
|
||||||
|
|
||||||
|
TUDPBase = class(TSocketComponent)
|
||||||
|
end;
|
||||||
|
|
||||||
|
TUDPClient = class(TUDPBase)
|
||||||
|
end;
|
||||||
|
|
||||||
|
TUDPServer = class(TUDPBase)
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
implementation
|
||||||
|
|
||||||
|
uses Resolve;
|
||||||
|
|
||||||
|
resourcestring
|
||||||
|
SSocketCreationError = 'Could not create socket';
|
||||||
|
SSocketBindingError = 'Could not bind socket to port %d';
|
||||||
|
SSocketAcceptError = 'Connection accept failed';
|
||||||
|
|
||||||
|
destructor TSocketComponent.Destroy;
|
||||||
|
begin
|
||||||
|
if Assigned(DataAvailableNotifyHandle) then
|
||||||
|
begin
|
||||||
|
EventLoop.ClearDataAvailableNotify(DataAvailableNotifyHandle);
|
||||||
|
// Set to nil to be sure that descendant classes don't do something stupid
|
||||||
|
DataAvailableNotifyHandle := nil;
|
||||||
|
end;
|
||||||
|
inherited Destroy;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
destructor TSocketStream.Destroy;
|
||||||
|
begin
|
||||||
|
FileClose(Handle);
|
||||||
|
inherited Destroy;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TSocketStream.Read(var Buffer; Count: LongInt): LongInt;
|
||||||
|
begin
|
||||||
|
Result := recv(Handle, Buffer, Count, MSG_NOSIGNAL);
|
||||||
|
if Result = -1 then
|
||||||
|
begin
|
||||||
|
Result := 0;
|
||||||
|
if Assigned(OnDisconnect) then
|
||||||
|
OnDisconnect(Self);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TSocketStream.Write(const Buffer; Count: LongInt): LongInt;
|
||||||
|
begin
|
||||||
|
Result := send(Handle, Buffer, Count, MSG_NOSIGNAL);
|
||||||
|
if Result = -1 then
|
||||||
|
begin
|
||||||
|
Result := 0;
|
||||||
|
if Assigned(OnDisconnect) then
|
||||||
|
OnDisconnect(Self);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TSocketStream.GetLocalAddress: TSockAddr;
|
||||||
|
var
|
||||||
|
len: LongInt;
|
||||||
|
begin
|
||||||
|
len := SizeOf(TSockAddr);
|
||||||
|
if GetSocketName(Handle, Result, len) <> 0 then
|
||||||
|
FillChar(Result, SizeOf(Result), 0);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TSocketStream.GetPeerAddress: TSockAddr;
|
||||||
|
var
|
||||||
|
len: LongInt;
|
||||||
|
begin
|
||||||
|
len := SizeOf(TSockAddr);
|
||||||
|
if GetPeerName(Handle, Result, len) <> 0 then
|
||||||
|
FillChar(Result, SizeOf(Result), 0);
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
function TCustomTCPServer.DoQueryConnect(ASocket: Integer): Boolean;
|
||||||
|
begin
|
||||||
|
Result := True;
|
||||||
|
if Assigned(OnQueryConnect) then
|
||||||
|
OnQueryConnect(Self, ASocket, Result);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TCustomTCPServer.DoConnect(AStream: TSocketStream);
|
||||||
|
begin
|
||||||
|
if Assigned(OnConnect) then
|
||||||
|
OnConnect(Self, AStream);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TCustomTCPServer.SetActive(Value: Boolean);
|
||||||
|
var
|
||||||
|
Addr: TInetSockAddr;
|
||||||
|
begin
|
||||||
|
if Active <> Value then
|
||||||
|
begin
|
||||||
|
FActive := False;
|
||||||
|
if Value then
|
||||||
|
begin
|
||||||
|
FSocket := Sockets.Socket(AF_INET, SOCK_STREAM, 0);
|
||||||
|
if FSocket = -1 then
|
||||||
|
raise ESocketError.Create(SSocketCreationError);
|
||||||
|
Addr.Family := AF_INET;
|
||||||
|
Addr.Port := ShortHostToNet(Port);
|
||||||
|
Addr.Addr := 0;
|
||||||
|
if not Bind(FSocket, Addr, SizeOf(Addr)) then
|
||||||
|
raise ESocketError.CreateFmt(SSocketBindingError, [Port]);
|
||||||
|
Listen(FSocket, 5);
|
||||||
|
DataAvailableNotifyHandle := EventLoop.SetDataAvailableNotify(FSocket,
|
||||||
|
@ListenerDataAvailable, nil);
|
||||||
|
end else
|
||||||
|
begin
|
||||||
|
FileClose(FSocket);
|
||||||
|
EventLoop.ClearDataAvailableNotify(DataAvailableNotifyHandle);
|
||||||
|
DataAvailableNotifyHandle := nil;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TCustomTCPServer.ListenerDataAvailable(Sender: TObject);
|
||||||
|
var
|
||||||
|
ClientSocket: Integer;
|
||||||
|
Addr: TInetSockAddr;
|
||||||
|
AddrSize: Integer;
|
||||||
|
begin
|
||||||
|
AddrSize := SizeOf(Addr);
|
||||||
|
ClientSocket := Accept(FSocket, Addr, AddrSize);
|
||||||
|
if ClientSocket = -1 then
|
||||||
|
raise ESocketError.Create(SSocketAcceptError);
|
||||||
|
|
||||||
|
if DoQueryConnect(ClientSocket) then
|
||||||
|
DoConnect(TSocketStream.Create(ClientSocket));
|
||||||
|
end;
|
||||||
|
|
||||||
|
end.
|
||||||
|
|
||||||
|
|
||||||
|
{
|
||||||
|
$Log$
|
||||||
|
Revision 1.1 2003-11-22 11:55:28 sg
|
||||||
|
* First version, a simple starting point for further development
|
||||||
|
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user