mirror of https://github.com/rusefi/openblt.git
1551 lines
42 KiB
Plaintext
1551 lines
42 KiB
Plaintext
unit WSockets;
|
|
{
|
|
|
|
WSockets Version 1.20 - A Simple VCL Encapsulation of the WinSocket API
|
|
|
|
VCL Classes in this Unit:
|
|
TTCPClient - A TCP Client (derived from TCustomWSocket)
|
|
TTCPServer - A TCP Server (derived from TCustomWSocket)
|
|
TUDPClient - A UDP Client (derived from TCustomWSocket)
|
|
TUDPServer - A UDP Server (derived from TCustomWSocket)
|
|
|
|
Other classes ni this Unit:
|
|
TCustomWSocket - A generic base class for other socket classes
|
|
TClientList - A list class used only by the TTCPServer class
|
|
|
|
Legal issues:
|
|
|
|
Copyright (C) 1997 by Robert T. Palmqvist <robert.palmqvist@skanska.se>
|
|
|
|
This software is provided 'as-is', without any express or implied
|
|
warranty. In no event will the author be held liable for any damages
|
|
arising from the use of this software.
|
|
|
|
Permission is granted to anyone to use this software for any purpose,
|
|
including commercial applications, and to alter it and redistribute it
|
|
freely, subject to the following restrictions:
|
|
|
|
1. The origin of this software must not be misrepresented, you must not
|
|
claim that you wrote the original software. If you use this software
|
|
in a product, an acknowledgment in the product documentation would be
|
|
appreciated but is not required.
|
|
|
|
2. Altered source versions must be plainly marked as such, and must not be
|
|
misrepresented as being the original software.
|
|
|
|
3. This notice may not be removed or altered from any source distribution.
|
|
|
|
Credits go to:
|
|
|
|
Gary T. Desrosiers. His unit "Sockets" inspired me to write my own.
|
|
|
|
Martin Hall, Mark Towfig, Geoff Arnold, David Treadwell, Henry Sanders
|
|
and InfoMagic, Inc. for their Windows Help File "WinSock.hlp".
|
|
|
|
All the guys at Borland who gave us a marvellous tool named "Delphi"!
|
|
|
|
Recommended information sources:
|
|
|
|
Specification:
|
|
Windows Sockets Version 1.1 Specification
|
|
|
|
Textbook:
|
|
Quinn and Shute. "Windows Sockets Network Programming"
|
|
1996 by Addison-Wesley Publishing Company, Inc. ISBN 0-201-63372-8
|
|
|
|
World Wide Web:
|
|
http://www.sockets.com
|
|
http://www.stardust.com
|
|
|
|
Network News:
|
|
alt.winsock.programming
|
|
|
|
Frequently Asked Questions:
|
|
"WinSock Application FAQ" Mailto: info@lcs.com Subject: faq
|
|
|
|
Requests for Comments:
|
|
RFC 768 "User Datagram Protocol"
|
|
RFC 791 "Internet Protocol"
|
|
RFC 793 "Transmission Control Protocol"
|
|
|
|
}
|
|
interface
|
|
|
|
uses
|
|
Windows, WinSock, SysUtils, Classes, Messages, Forms;
|
|
|
|
const
|
|
WM_ASYNCSELECT = WM_USER + 1;
|
|
READ_BUFFER_SIZE = 1024;
|
|
MAX_LOOP = 100;
|
|
|
|
type
|
|
TSocketState = (ssNotStarted, ssClosed, ssConnected, ssListening, ssOpen);
|
|
|
|
TOnError = procedure(Sender: TObject; Error: integer; Msg: string) of object;
|
|
TOnData = procedure(Sender: TObject; Socket: TSocket) of object;
|
|
TOnAccept = procedure(Sender: TObject; Socket: TSocket) of object;
|
|
TOnConnect = procedure(Sender: TObject; Socket: TSocket) of object;
|
|
TOnClose = procedure(Sender: TObject; Socket: TSocket) of object;
|
|
|
|
TReadBuffer = array[1..READ_BUFFER_SIZE] of byte;
|
|
|
|
TClientList = class(TObject)
|
|
private
|
|
FSockets: TList;
|
|
protected
|
|
function GetSockets(Index: integer): TSocket;
|
|
function GetCount: integer;
|
|
public
|
|
constructor Create;
|
|
destructor Destroy; override;
|
|
function Add(Socket: TSocket): boolean;
|
|
procedure Delete(Socket: TSocket);
|
|
procedure Clear;
|
|
function IndexOf(Socket: TSocket): integer;
|
|
property Sockets[Index: integer]: TSocket read GetSockets; default;
|
|
property Count: integer read GetCount;
|
|
end;
|
|
|
|
TCustomWSocket = class(TComponent)
|
|
private
|
|
{WinSocket Information Private Fields}
|
|
FVersion: string;
|
|
FDescription: string;
|
|
FSystemStatus: string;
|
|
FMaxSockets: integer;
|
|
FMaxUDPSize: integer;
|
|
{End WinSocket Information Private Fields}
|
|
FProtocol: integer;
|
|
FType: integer;
|
|
|
|
FReadBuffer: TReadBuffer;
|
|
FLocalSocket: TSocket;
|
|
FSocketState: TSocketState;
|
|
FLastError: integer;
|
|
FOnError: TOnError;
|
|
protected
|
|
procedure SocketError(Error: integer);
|
|
function LastErrorDesc: string;
|
|
|
|
function GetLocalHostAddress: string;
|
|
function GetLocalHostName: string;
|
|
{Socket Helper Functions}
|
|
procedure SocketClose(var Socket: TSocket; Handle: HWND);
|
|
function SocketQueueSize(Socket: TSocket): longint;
|
|
|
|
procedure SocketWrite(Socket: TSocket; Flag: integer; Data: string);
|
|
function SocketRead(Socket: TSocket; Flag: integer): string;
|
|
function SocketWriteBuffer(Socket: TSocket; Buffer: Pointer; Size, Flag: integer): integer;
|
|
function SocketReadBuffer(Socket: TSocket; Buffer: Pointer; Size, Flag: integer): integer;
|
|
|
|
procedure SocketWriteTo(Socket: TSocket; Flag: integer; Data: string; var SockAddrIn: TSockAddrIn);
|
|
function SocketReadFrom(Socket: TSocket; Flag: integer; var SockAddrIn: TSockAddrIn): string;
|
|
function SocketWriteBufferTo(Socket: TSocket; Buffer: Pointer; Size, Flag: integer; var SockAddrIn: TSockAddrIn): integer;
|
|
function SocketReadBufferFrom(Socket: TSocket; Buffer: Pointer; Size, Flag: integer; var SockAddrIn: TSockAddrIn): integer;
|
|
public
|
|
constructor Create(AOwner: TComponent); override;
|
|
destructor Destroy; override;
|
|
{Address and Port Resolving Helper Functions}
|
|
function GetSockAddrIn(Host, Port: string; var SockAddrIn: TSockAddrIn): boolean;
|
|
function GetAnySockAddrIn(Port: string; var SockAddrIn: TSockAddrIn): boolean;
|
|
function GetBroadcastSockAddrIn(Port: string; var SockAddrIn: TSockAddrIn): boolean;
|
|
function SockAddrInToName(SockAddrIn: TSockAddrIn): string;
|
|
function SockAddrInToAddress(SockAddrIn: TSockAddrIn): string;
|
|
function SockAddrInToPort(SockAddrIn: TSockAddrIn): string;
|
|
function SocketToName(Socket: TSocket): string;
|
|
function SocketToAddress(Socket: TSocket): string;
|
|
function SocketToPort(Socket: TSocket): string;
|
|
function PeerToName(Socket: TSocket): string;
|
|
function PeerToAddress(Socket: TSocket): string;
|
|
function PeerToPort(Socket: TSocket): string;
|
|
{WinSocket Information Properties}
|
|
property Version: string read FVersion;
|
|
property Description: string read FDescription;
|
|
property SystemStatus: string read FSystemStatus;
|
|
property MaxSockets: integer read FMaxSockets;
|
|
property MaxUDPSize: integer read FMaxUDPSize;
|
|
{End WinSocket Information Properties}
|
|
property LocalSocket: TSocket read FLocalSocket;
|
|
property SocketState: TSocketState read FSocketState;
|
|
property LastError: integer read FLastError;
|
|
property LocalHostAddress: string read GetLocalHostAddress;
|
|
property LocalHostName: string read GetLocalHostName;
|
|
published
|
|
property OnError: TOnError read FOnError write FOnError;
|
|
end;
|
|
|
|
TTCPClient = class(TCustomWSocket)
|
|
private
|
|
FHandle: HWND;
|
|
|
|
FHost: string;
|
|
FPort: string;
|
|
|
|
FOnData: TOnData;
|
|
FOnConnect: TOnConnect;
|
|
FOnClose: TOnClose;
|
|
protected
|
|
procedure WndProc(var AMsg: TMessage);
|
|
procedure OpenConnection(Socket: TSocket; Error: word);
|
|
procedure IncommingData(Socket: TSocket; Error: word);
|
|
procedure CloseConnection(Socket: TSocket; Error: word);
|
|
|
|
function GetPeerAddress: string;
|
|
function GetPeerPort: string;
|
|
public
|
|
constructor Create(AOwner: TComponent); override;
|
|
destructor Destroy; override;
|
|
|
|
procedure Open;
|
|
procedure Close;
|
|
|
|
function Peek: string;
|
|
|
|
procedure Write(Data: string);
|
|
function Read: string;
|
|
|
|
function WriteBuffer(Buffer: Pointer; Size: integer): integer;
|
|
function ReadBuffer(Buffer: Pointer; Size: integer): integer;
|
|
|
|
property Handle: HWND read FHandle;
|
|
|
|
property PeerAddress: string read GetPeerAddress;
|
|
property PeerPort: string read GetPeerPort;
|
|
published
|
|
property Host: string read FHost write FHost;
|
|
property Port: string read FPort write FPort;
|
|
|
|
property OnData: TOnData read FOnData write FOnData;
|
|
property OnConnect: TOnConnect read FOnConnect write FOnConnect;
|
|
property OnClose: TOnClose read FOnClose write FOnClose;
|
|
end;
|
|
|
|
TTCPServer = class(TCustomWSocket)
|
|
private
|
|
FHandle: HWND;
|
|
FPort: string;
|
|
|
|
FOnData: TOnData;
|
|
FOnAccept: TOnAccept;
|
|
FOnClose: TOnClose;
|
|
|
|
FClients: TClientList;
|
|
protected
|
|
procedure WndProc(var AMsg: TMessage);
|
|
procedure OpenConnection(Socket: TSocket; Error: word);
|
|
procedure IncommingData(Socket: TSocket; Error: word);
|
|
procedure CloseConnection(Socket: TSocket; Error: word);
|
|
public
|
|
constructor Create(AOwner: TComponent); override;
|
|
destructor Destroy; override;
|
|
|
|
procedure Open;
|
|
procedure Close;
|
|
|
|
function Peek(Socket: TSocket): string;
|
|
|
|
procedure Write(Socket: TSocket; Data: string);
|
|
function Read(Socket: TSocket): string;
|
|
|
|
function WriteBuffer(Socket: TSocket; Buffer: Pointer; Size: integer): integer;
|
|
function ReadBuffer(Socket: TSocket; Buffer: Pointer; Size: integer): integer;
|
|
|
|
procedure Disconnect(Socket: TSocket);
|
|
|
|
property Handle: HWND read FHandle;
|
|
property Clients: TClientList read FClients;
|
|
published
|
|
property Port: string read FPort write FPort;
|
|
|
|
property OnData: TOnData read FOnData write FOnData;
|
|
property OnAccept: TOnAccept read FOnAccept write FOnAccept;
|
|
property OnClose: TOnClose read FOnClose write FOnClose;
|
|
end;
|
|
|
|
TUDPClient = class(TCustomWSocket)
|
|
private
|
|
FHandle: HWND;
|
|
|
|
FHost: string;
|
|
FPort: string;
|
|
|
|
FOnData: TOnData;
|
|
protected
|
|
procedure WndProc(var AMsg: TMessage);
|
|
procedure IncommingData(Socket: TSocket; Error: word);
|
|
|
|
function GetPeerAddress: string;
|
|
function GetPeerPort: string;
|
|
public
|
|
constructor Create(AOwner: TComponent); override;
|
|
destructor Destroy; override;
|
|
|
|
procedure Open;
|
|
procedure Close;
|
|
|
|
function Peek: string;
|
|
|
|
procedure Write(Data: string);
|
|
function Read: string;
|
|
|
|
function WriteBuffer(Buffer: Pointer; Size: integer): integer;
|
|
function ReadBuffer(Buffer: Pointer; Size: integer): integer;
|
|
|
|
property Handle: HWND read FHandle;
|
|
|
|
property PeerAddress: string read GetPeerAddress;
|
|
property PeerPort: string read GetPeerPort;
|
|
published
|
|
property Host: string read FHost write FHost;
|
|
property Port: string read FPort write FPort;
|
|
|
|
property OnData: TOnData read FOnData write FOnData;
|
|
end;
|
|
|
|
TUDPServer = class(TCustomWSocket)
|
|
private
|
|
FHandle: HWND;
|
|
FPort: string;
|
|
|
|
FOnData: TOnData;
|
|
protected
|
|
procedure WndProc(var AMsg: TMessage);
|
|
procedure IncommingData(Socket: TSocket; Error: word);
|
|
public
|
|
constructor Create(AOwner: TComponent); override;
|
|
destructor Destroy; override;
|
|
|
|
procedure Open;
|
|
procedure Close;
|
|
|
|
function Peek(Socket: TSocket; var SockAddrIn: TSockAddrIn): string;
|
|
|
|
procedure Write(Socket: TSocket; Data: string; var SockAddrIn: TSockAddrIn);
|
|
function Read(Socket: TSocket; var SockAddrIn: TSockAddrIn): string;
|
|
|
|
function WriteBuffer(Socket: TSocket; Buffer: Pointer; Size: integer; var SockAddrIn: TSockAddrIn): integer;
|
|
function ReadBuffer(Socket: TSocket; Buffer: Pointer; Size: integer; var SockAddrIn: TSockAddrIn): integer;
|
|
|
|
property Handle: HWND read FHandle;
|
|
published
|
|
property Port: string read FPort write FPort;
|
|
|
|
property OnData: TOnData read FOnData write FOnData;
|
|
end;
|
|
|
|
procedure Register;
|
|
|
|
implementation
|
|
|
|
procedure Register;
|
|
begin
|
|
RegisterComponents('Samples', [TTCPClient, TTCPServer, TUDPClient, TUDPServer]);
|
|
end;
|
|
|
|
(**** TClientList Class ****)
|
|
|
|
constructor TClientList.Create;
|
|
begin
|
|
inherited Create;
|
|
FSockets:= TList.Create;
|
|
end;
|
|
|
|
destructor TClientList.Destroy;
|
|
begin
|
|
Clear;
|
|
FSockets.Free;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
function TClientList.GetSockets(Index: integer): TSocket;
|
|
begin
|
|
Result:= TSocket(FSockets[Index]);
|
|
end;
|
|
|
|
function TClientList.GetCount: integer;
|
|
begin
|
|
Result:= FSockets.Count;
|
|
end;
|
|
|
|
function TClientList.Add(Socket: TSocket): boolean;
|
|
begin
|
|
Result:= (FSockets.Add(Ptr(Socket)) >= 0);
|
|
end;
|
|
|
|
procedure TClientList.Delete(Socket: TSocket);
|
|
var
|
|
i: integer;
|
|
begin
|
|
for i:= 0 to FSockets.Count-1 do
|
|
begin
|
|
if TSocket(FSockets[i]) = Socket then
|
|
begin
|
|
FSockets.Delete(i);
|
|
Break;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TClientList.Clear;
|
|
begin
|
|
FSockets.Clear;
|
|
end;
|
|
|
|
function TClientList.IndexOf(Socket: TSocket): integer;
|
|
var
|
|
i: integer;
|
|
begin
|
|
Result:= -1;
|
|
for i:= 0 to FSockets.Count-1 do
|
|
begin
|
|
if TSocket(FSockets[i]) = Socket then
|
|
begin
|
|
Result:= i;
|
|
Break;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
(**** TCustomWSocket Class ****)
|
|
|
|
constructor TCustomWSocket.Create(AOwner: TComponent);
|
|
var
|
|
WSAData: TWSAData;
|
|
begin
|
|
inherited Create(AOwner);
|
|
FProtocol:= IPPROTO_IP;
|
|
FType:= SOCK_RAW;
|
|
FLocalSocket:= INVALID_SOCKET;
|
|
FSocketState:= ssNotStarted;
|
|
FLastError:= WSAStartup($101, WSAData);
|
|
if FLastError = 0 then
|
|
begin
|
|
FSocketState:= ssClosed;
|
|
with WSAData do
|
|
begin
|
|
FVersion:= Concat(IntToStr(Hi(wVersion)),'.',(IntToStr(Lo(wVersion))));
|
|
FDescription:= String(szDescription);
|
|
FSystemStatus:= String(szSystemStatus);
|
|
FMaxSockets:= iMaxSockets;
|
|
FMaxUDPSize:= iMaxUDPDg;
|
|
end;
|
|
end
|
|
else
|
|
SocketError(FLastError);
|
|
end;
|
|
|
|
destructor TCustomWSocket.Destroy;
|
|
begin
|
|
if FLocalSocket <> INVALID_SOCKET then
|
|
closesocket(FLocalSocket);
|
|
if FSocketState <> ssNotStarted then
|
|
if WSACleanUp = SOCKET_ERROR then
|
|
SocketError(WSAGetLastError);
|
|
inherited Destroy;
|
|
end;
|
|
|
|
function TCustomWSocket.GetSockAddrIn(
|
|
Host, Port: string; var SockAddrIn: TSockAddrIn): boolean;
|
|
var
|
|
ProtoEnt: PProtoEnt;
|
|
ServEnt: PServEnt;
|
|
HostEnt: PHostEnt;
|
|
begin
|
|
Result:= false;
|
|
SockAddrIn.sin_family:= AF_INET;
|
|
|
|
ProtoEnt:= getprotobynumber(FProtocol);
|
|
if ProtoEnt = nil then
|
|
begin
|
|
SocketError(WSAGetLastError);
|
|
Exit;
|
|
end;
|
|
|
|
ServEnt:= getservbyname(PAnsiChar(AnsiString(Port)), ProtoEnt^.p_name);
|
|
if ServEnt = nil then
|
|
SockAddrIn.sin_port:= htons(StrToInt(Port))
|
|
else
|
|
SockAddrIn.sin_port:= ServEnt^.s_port;
|
|
|
|
SockAddrIn.sin_addr.s_addr:= inet_addr(PAnsiChar(AnsiString(Host)));
|
|
if SockAddrIn.sin_addr.s_addr = Integer(INADDR_NONE) then
|
|
begin
|
|
HostEnt:= gethostbyname(PAnsiChar(AnsiString(Host)));
|
|
if HostEnt = nil then
|
|
begin
|
|
SocketError(WSAGetLastError);
|
|
Exit;
|
|
end;
|
|
SockAddrIn.sin_addr.S_addr:= longint(plongint(HostEnt^.h_addr_list^)^);
|
|
end;
|
|
Result:= true;
|
|
end;
|
|
|
|
function TCustomWSocket.GetAnySockAddrIn(
|
|
Port: string; var SockAddrIn: TSockAddrIn): boolean;
|
|
var
|
|
ProtoEnt: PProtoEnt;
|
|
ServEnt: PServEnt;
|
|
begin
|
|
Result:= false;
|
|
SockAddrIn.sin_family:= AF_INET;
|
|
|
|
ProtoEnt:= getprotobynumber(FProtocol);
|
|
if ProtoEnt = nil then
|
|
Exit;
|
|
|
|
ServEnt:= getservbyname(PAnsiChar(AnsiString(Port)), ProtoEnt^.p_name);
|
|
if ServEnt = nil then
|
|
SockAddrIn.sin_port:= htons(StrToInt(Port))
|
|
else
|
|
SockAddrIn.sin_port:= ServEnt^.s_port;
|
|
|
|
SockAddrIn.sin_addr.s_addr:= INADDR_ANY;
|
|
Result:= true;
|
|
end;
|
|
|
|
function TCustomWSocket.GetBroadcastSockAddrIn(
|
|
Port: string; var SockAddrIn: TSockAddrIn): boolean;
|
|
var
|
|
ProtoEnt: PProtoEnt;
|
|
ServEnt: PServEnt;
|
|
begin
|
|
Result:= false;
|
|
SockAddrIn.sin_family:= AF_INET;
|
|
|
|
ProtoEnt:= getprotobynumber(FProtocol);
|
|
if ProtoEnt = nil then
|
|
Exit;
|
|
|
|
ServEnt:= getservbyname(PAnsiChar(AnsiString(Port)), ProtoEnt^.p_name);
|
|
if ServEnt = nil then
|
|
SockAddrIn.sin_port:= htons(StrToInt(Port))
|
|
else
|
|
SockAddrIn.sin_port:= ServEnt^.s_port;
|
|
|
|
SockAddrIn.sin_addr.s_addr:= Integer(INADDR_BROADCAST);
|
|
Result:= true;
|
|
end;
|
|
|
|
function TCustomWSocket.SockAddrInToName(SockAddrIn: TSockAddrIn): string;
|
|
var
|
|
HostEnt: PHostEnt;
|
|
begin
|
|
HostEnt:= gethostbyaddr(@SockAddrIn.sin_addr.S_addr, 4, AF_INET);
|
|
if HostEnt <> nil then
|
|
Result:= String(AnsiString(HostEnt.h_name));
|
|
end;
|
|
|
|
function TCustomWSocket.SockAddrInToAddress(SockAddrIn: TSockAddrIn): string;
|
|
begin
|
|
Result:= String(AnsiString(inet_ntoa(SockAddrIn.sin_addr)));
|
|
end;
|
|
|
|
function TCustomWSocket.SockAddrInToPort(SockAddrIn: TSockAddrIn): string;
|
|
begin
|
|
Result:= IntToStr(ntohs(SockAddrIn.sin_port));
|
|
end;
|
|
|
|
function TCustomWSocket.SocketToName(Socket: TSocket): string;
|
|
var
|
|
SockAddrIn: TSockAddrIn;
|
|
Len: integer;
|
|
HostEnt: PHostEnt;
|
|
begin
|
|
if Socket <> INVALID_SOCKET then
|
|
begin
|
|
Len:= SizeOf(SockAddrIn);
|
|
if getsockname(Socket, SockAddrIn, Len) <> SOCKET_ERROR then
|
|
begin
|
|
HostEnt:= gethostbyaddr(@SockAddrIn.sin_addr.S_addr, 4, AF_INET);
|
|
if HostEnt <> nil then
|
|
Result:= String(AnsiString(HostEnt.h_name));
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TCustomWSocket.SocketToAddress(Socket: TSocket): string;
|
|
var
|
|
SockAddrIn: TSockAddrIn;
|
|
Len: integer;
|
|
begin
|
|
if Socket <> INVALID_SOCKET then
|
|
begin
|
|
Len:= SizeOf(SockAddrIn);
|
|
if getsockname(Socket, SockAddrIn, Len) <> SOCKET_ERROR then
|
|
Result:= String(AnsiString(inet_ntoa(SockAddrIn.sin_addr)));
|
|
end;
|
|
end;
|
|
|
|
function TCustomWSocket.SocketToPort(Socket: TSocket): string;
|
|
var
|
|
SockAddrIn: TSockAddrIn;
|
|
Len: integer;
|
|
begin
|
|
if Socket <> INVALID_SOCKET then
|
|
begin
|
|
Len:= SizeOf(SockAddrIn);
|
|
if getsockname(Socket, SockAddrIn, Len) <> SOCKET_ERROR then
|
|
Result:= IntToStr(ntohs(SockAddrIn.sin_port));
|
|
end;
|
|
end;
|
|
|
|
function TCustomWSocket.PeerToName(Socket: TSocket): string;
|
|
var
|
|
SockAddrIn: TSockAddrIn;
|
|
Len: integer;
|
|
HostEnt: PHostEnt;
|
|
begin
|
|
if Socket <> INVALID_SOCKET then
|
|
begin
|
|
Len:= SizeOf(SockAddrIn);
|
|
if getpeername(Socket, SockAddrIn, Len) <> SOCKET_ERROR then
|
|
begin
|
|
HostEnt:= gethostbyaddr(@SockAddrIn.sin_addr.S_addr, 4, AF_INET);
|
|
if HostEnt <> nil then
|
|
Result:= String(AnsiString(HostEnt.h_name));
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TCustomWSocket.PeerToAddress(Socket: TSocket): string;
|
|
var
|
|
SockAddrIn: TSockAddrIn;
|
|
Len: integer;
|
|
begin
|
|
if Socket <> INVALID_SOCKET then
|
|
begin
|
|
Len:= SizeOf(SockAddrIn);
|
|
if getpeername(Socket, SockAddrIn, Len) <> SOCKET_ERROR then
|
|
Result:= String(AnsiString(inet_ntoa(SockAddrIn.sin_addr)));
|
|
end;
|
|
end;
|
|
|
|
function TCustomWSocket.PeerToPort(Socket: TSocket): string;
|
|
var
|
|
SockAddrIn: TSockAddrIn;
|
|
Len: integer;
|
|
begin
|
|
if Socket <> INVALID_SOCKET then
|
|
begin
|
|
Len:= SizeOf(SockAddrIn);
|
|
if getpeername(Socket, SockAddrIn, Len) <> SOCKET_ERROR then
|
|
Result:= IntToStr(ntohs(SockAddrIn.sin_port));
|
|
end;
|
|
end;
|
|
|
|
procedure TCustomWSocket.SocketClose(var Socket: TSocket; Handle: HWND);
|
|
var
|
|
RC: integer;
|
|
begin
|
|
if Socket <> INVALID_SOCKET then
|
|
begin
|
|
if WSAASyncSelect(Socket, Handle, WM_ASYNCSELECT, 0) <> 0 then
|
|
begin
|
|
SocketError(WSAGetLastError);
|
|
Exit;
|
|
end;
|
|
|
|
if shutdown(Socket, 1) <> 0 then
|
|
if WSAGetLastError <> WSAENOTCONN then
|
|
begin
|
|
SocketError(WSAGetLastError);
|
|
Exit;
|
|
end;
|
|
|
|
repeat
|
|
RC:= recv(Socket, FReadBuffer, SizeOf(TReadBuffer), 0);
|
|
until (RC = 0) or (RC = SOCKET_ERROR);
|
|
|
|
if closesocket(Socket) <> 0 then
|
|
SocketError(WSAGetLastError)
|
|
else
|
|
Socket:= INVALID_SOCKET;
|
|
end;
|
|
end;
|
|
|
|
function TCustomWSocket.SocketQueueSize(Socket: TSocket): longint;
|
|
var
|
|
Size: longint;
|
|
begin
|
|
Result:= 0;
|
|
if ioctlsocket(Socket, FIONREAD, Size) <> 0 then
|
|
SocketError(WSAGetLastError)
|
|
else
|
|
Result:= Size;
|
|
end;
|
|
|
|
procedure TCustomWSocket.SocketWrite(Socket: TSocket; Flag: integer; Data: string);
|
|
var
|
|
TotSent, ToSend, Sent, ErrorLoop: integer;
|
|
begin
|
|
if Data <> '' then
|
|
begin
|
|
ErrorLoop:= 0;
|
|
TotSent:= 0;
|
|
ToSend:= Length(Data);
|
|
repeat
|
|
Sent:= send(Socket, Data[TotSent+1], (ToSend-TotSent), Flag);
|
|
if Sent = SOCKET_ERROR then
|
|
begin
|
|
Inc(ErrorLoop);
|
|
if WSAGetLastError <> WSAEWOULDBLOCK then
|
|
begin
|
|
SocketError(WSAGetLastError);
|
|
Exit;
|
|
end;
|
|
end
|
|
else
|
|
Inc(TotSent, Sent);
|
|
until (TotSent >= ToSend) or (ErrorLoop > MAX_LOOP);
|
|
end;
|
|
end;
|
|
|
|
function TCustomWSocket.SocketRead(Socket: TSocket; Flag: integer): string;
|
|
var
|
|
Received: longint;
|
|
begin
|
|
Result:= '';
|
|
Received:= recv(Socket, FReadBuffer, SizeOf(TReadBuffer), Flag);
|
|
if Received = SOCKET_ERROR then
|
|
begin
|
|
if WSAGetLastError <> WSAEWOULDBLOCK then
|
|
SocketError(WSAGetLastError);
|
|
end
|
|
else
|
|
begin
|
|
SetLength(Result, Received);
|
|
Move(FReadBuffer, Result[1], Received);
|
|
end;
|
|
end;
|
|
|
|
function TCustomWSocket.SocketWriteBuffer(Socket: TSocket; Buffer: Pointer; Size, Flag: integer): integer;
|
|
begin
|
|
Result:= send(Socket, Buffer^, Size, Flag);
|
|
if Result = SOCKET_ERROR then
|
|
begin
|
|
Result:= 0;
|
|
if WSAGetLastError <> WSAEWOULDBLOCK then
|
|
SocketError(WSAGetLastError);
|
|
end;
|
|
end;
|
|
|
|
function TCustomWSocket.SocketReadBuffer(Socket: TSocket; Buffer: Pointer; Size, Flag: integer): integer;
|
|
begin
|
|
Result:= recv(Socket, Buffer^, Size, Flag);
|
|
if Result = SOCKET_ERROR then
|
|
begin
|
|
Result:= 0;
|
|
if WSAGetLastError <> WSAEWOULDBLOCK then
|
|
SocketError(WSAGetLastError);
|
|
end;
|
|
end;
|
|
|
|
procedure TCustomWSocket.SocketWriteTo(Socket: TSocket; Flag: integer; Data: string; var SockAddrIn: TSockAddrIn);
|
|
var
|
|
TotSent, ToSend, Sent, ErrorLoop: integer;
|
|
begin
|
|
if Data <> '' then
|
|
begin
|
|
ErrorLoop:= 0;
|
|
TotSent:= 0;
|
|
ToSend:= Length(Data);
|
|
repeat
|
|
Sent:= sendto(Socket, Data[TotSent+1], (ToSend-TotSent), Flag, SockAddrIn, SizeOf(SockAddrIn));
|
|
if Sent = SOCKET_ERROR then
|
|
begin
|
|
Inc(ErrorLoop);
|
|
if WSAGetLastError <> WSAEWOULDBLOCK then
|
|
begin
|
|
SocketError(WSAGetLastError);
|
|
Exit;
|
|
end;
|
|
end
|
|
else
|
|
Inc(TotSent, Sent);
|
|
until (TotSent >= ToSend) or (ErrorLoop > MAX_LOOP);
|
|
end;
|
|
end;
|
|
|
|
function TCustomWSocket.SocketReadFrom(Socket: TSocket; Flag: integer; var SockAddrIn: TSockAddrIn): string;
|
|
var
|
|
Len: integer;
|
|
Received: longint;
|
|
begin
|
|
Len:= SizeOf(SockAddrIn);
|
|
Received:= recvfrom(Socket, FReadBuffer, SizeOf(TReadBuffer), Flag, SockAddrIn, Len);
|
|
if Received = SOCKET_ERROR then
|
|
begin
|
|
if WSAGetLastError <> WSAEWOULDBLOCK then
|
|
SocketError(WSAGetLastError);
|
|
end
|
|
else
|
|
begin
|
|
SetLength(Result, Received);
|
|
Move(FReadBuffer, Result[1], Received);
|
|
end;
|
|
end;
|
|
|
|
function TCustomWSocket.SocketWriteBufferTo(Socket: TSocket; Buffer: Pointer; Size, Flag: integer; var SockAddrIn: TSockAddrIn): integer;
|
|
begin
|
|
Result:= sendto(Socket, Buffer^, Size, Flag, SockAddrIn, SizeOf(SockAddrIn));
|
|
if Result = SOCKET_ERROR then
|
|
begin
|
|
Result:= 0;
|
|
if WSAGetLastError <> WSAEWOULDBLOCK then
|
|
SocketError(WSAGetLastError);
|
|
end;
|
|
end;
|
|
|
|
function TCustomWSocket.SocketReadBufferFrom(Socket: TSocket; Buffer: Pointer; Size, Flag: integer; var SockAddrIn: TSockAddrIn): integer;
|
|
var
|
|
Len: integer;
|
|
begin
|
|
Len:= SizeOf(SockAddrIn);
|
|
Result:= recvfrom(Socket, Buffer^, Size, Flag, SockAddrIn, Len);
|
|
if Result = SOCKET_ERROR then
|
|
begin
|
|
Result:= 0;
|
|
if WSAGetLastError <> WSAEWOULDBLOCK then
|
|
SocketError(WSAGetLastError);
|
|
end;
|
|
end;
|
|
|
|
procedure TCustomWSocket.SocketError(Error: integer);
|
|
begin
|
|
FLastError:= Error;
|
|
if Assigned(FOnError) then
|
|
FOnError(Self, FLastError, LastErrorDesc);
|
|
end;
|
|
|
|
function TCustomWSocket.LastErrorDesc: string;
|
|
begin
|
|
case FLastError of
|
|
WSAEINTR : Result:= 'Interrupted system call';
|
|
WSAEBADF : Result:= 'Bad file number';
|
|
WSAEACCES : Result:= 'Permission denied';
|
|
WSAEFAULT : Result:= 'Bad address';
|
|
WSAEINVAL : Result:= 'Invalid argument';
|
|
WSAEMFILE : Result:= 'Too many open files';
|
|
WSAEWOULDBLOCK : Result:= 'Operation would block';
|
|
WSAEINPROGRESS : Result:= 'Operation now in progress';
|
|
WSAEALREADY : Result:= 'Operation already in progress';
|
|
WSAENOTSOCK : Result:= 'Socket operation on nonsocket';
|
|
WSAEDESTADDRREQ : Result:= 'Destination address required';
|
|
WSAEMSGSIZE : Result:= 'Message too long';
|
|
WSAEPROTOTYPE : Result:= 'Protocol wrong type for socket';
|
|
WSAENOPROTOOPT : Result:= 'Protocol not available';
|
|
WSAEPROTONOSUPPORT : Result:= 'Protocol not supported';
|
|
WSAESOCKTNOSUPPORT : Result:= 'Socket not supported';
|
|
WSAEOPNOTSUPP : Result:= 'Operation not supported on socket';
|
|
WSAEPFNOSUPPORT : Result:= 'Protocol family not supported';
|
|
WSAEAFNOSUPPORT : Result:= 'Address family not supported';
|
|
WSAEADDRINUSE : Result:= 'Address already in use';
|
|
WSAEADDRNOTAVAIL : Result:= 'Can''t assign requested address';
|
|
WSAENETDOWN : Result:= 'Network is down';
|
|
WSAENETUNREACH : Result:= 'Network is unreachable';
|
|
WSAENETRESET : Result:= 'Network dropped connection on reset';
|
|
WSAECONNABORTED : Result:= 'Software caused connection abort';
|
|
WSAECONNRESET : Result:= 'Connection reset by peer';
|
|
WSAENOBUFS : Result:= 'No buffer space available';
|
|
WSAEISCONN : Result:= 'Socket is already connected';
|
|
WSAENOTCONN : Result:= 'Socket is not connected';
|
|
WSAESHUTDOWN : Result:= 'Can''t send after socket shutdown';
|
|
WSAETOOMANYREFS : Result:= 'Too many references:can''t splice';
|
|
WSAETIMEDOUT : Result:= 'Connection timed out';
|
|
WSAECONNREFUSED : Result:= 'Connection refused';
|
|
WSAELOOP : Result:= 'Too many levels of symbolic links';
|
|
WSAENAMETOOLONG : Result:= 'File name is too long';
|
|
WSAEHOSTDOWN : Result:= 'Host is down';
|
|
WSAEHOSTUNREACH : Result:= 'No route to host';
|
|
WSAENOTEMPTY : Result:= 'Directory is not empty';
|
|
WSAEPROCLIM : Result:= 'Too many processes';
|
|
WSAEUSERS : Result:= 'Too many users';
|
|
WSAEDQUOT : Result:= 'Disk quota exceeded';
|
|
WSAESTALE : Result:= 'Stale NFS file handle';
|
|
WSAEREMOTE : Result:= 'Too many levels of remote in path';
|
|
WSASYSNOTREADY : Result:= 'Network subsystem is unusable';
|
|
WSAVERNOTSUPPORTED : Result:= 'Winsock DLL cannot support this application';
|
|
WSANOTINITIALISED : Result:= 'Winsock not initialized';
|
|
WSAHOST_NOT_FOUND : Result:= 'Host not found';
|
|
WSATRY_AGAIN : Result:= 'Non authoritative - host not found';
|
|
WSANO_RECOVERY : Result:= 'Non recoverable error';
|
|
WSANO_DATA : Result:= 'Valid name, no data record of requested type'
|
|
else
|
|
Result:= 'Not a Winsock error';
|
|
end;
|
|
end;
|
|
|
|
function TCustomWSocket.GetLocalHostAddress: string;
|
|
var
|
|
SockAddrIn: TSockAddrIn;
|
|
HostEnt: PHostEnt;
|
|
szHostName: array[0..128] of ansichar;
|
|
begin
|
|
if gethostname(szHostName, 128) = 0 then
|
|
begin
|
|
HostEnt:= gethostbyname(szHostName);
|
|
if HostEnt = nil then
|
|
Result:= ''
|
|
else
|
|
begin
|
|
SockAddrIn.sin_addr.S_addr:= longint(plongint(HostEnt^.h_addr_list^)^);
|
|
Result:= String(AnsiString(inet_ntoa(SockAddrIn.sin_addr)));
|
|
end;
|
|
end
|
|
else
|
|
SocketError(WSAGetLastError);
|
|
end;
|
|
|
|
function TCustomWSocket.GetLocalHostName: string;
|
|
var
|
|
szHostName: array[0..128] of ansichar;
|
|
begin
|
|
if gethostname(szHostName, 128) = 0 then
|
|
Result:= String(AnsiString(szHostName))
|
|
else
|
|
SocketError(WSAGetLastError);
|
|
end;
|
|
|
|
(**** TTCPClient Class ****)
|
|
|
|
constructor TTCPClient.Create(AOwner: TComponent);
|
|
begin
|
|
inherited Create(AOwner);
|
|
FHandle:= AllocateHWnd(WndProc);
|
|
FProtocol:= IPPROTO_TCP;
|
|
FType:= SOCK_STREAM;
|
|
end;
|
|
|
|
destructor TTCPClient.Destroy;
|
|
begin
|
|
Close;
|
|
DeallocateHWnd(FHandle);
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TTCPClient.OpenConnection(Socket: TSocket; Error: word);
|
|
var
|
|
EventMask: longint;
|
|
begin
|
|
if Error <> 0 then
|
|
SocketError(Error)
|
|
else
|
|
begin
|
|
EventMask:= FD_READ or FD_CLOSE;
|
|
if WSAASyncSelect(FLocalSocket, FHandle, WM_ASYNCSELECT, EventMask) <> 0 then
|
|
SocketError(WSAGetLastError)
|
|
else
|
|
begin
|
|
if Assigned(FOnConnect) then
|
|
FOnConnect(Self, Socket);
|
|
FSocketState:= ssConnected;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TTCPClient.CloseConnection(Socket: TSocket; Error: word);
|
|
begin
|
|
if Error = WSAENETDOWN then
|
|
SocketError(Error)
|
|
else
|
|
begin
|
|
if Assigned(FOnClose) then
|
|
FOnClose(Self, Socket);
|
|
Close;
|
|
end;
|
|
end;
|
|
|
|
procedure TTCPClient.IncommingData(Socket: TSocket; Error: word);
|
|
begin
|
|
if Error <> 0 then
|
|
SocketError(Error)
|
|
else
|
|
if Assigned(FOnData) then
|
|
FOnData(Self, Socket);
|
|
end;
|
|
|
|
procedure TTCPClient.WndProc(var AMsg: TMessage);
|
|
var
|
|
Error: word;
|
|
begin
|
|
with AMsg do
|
|
case Msg of
|
|
WM_ASYNCSELECT:
|
|
begin
|
|
if (FSocketState = ssClosed) then
|
|
Exit;
|
|
Error:= WSAGetSelectError(LParam);
|
|
case WSAGetSelectEvent(LParam) of
|
|
FD_READ : IncommingData(WParam, Error);
|
|
FD_CONNECT: OpenConnection(WParam, Error);
|
|
FD_CLOSE : CloseConnection(WParam, Error);
|
|
else
|
|
if Error <> 0 then
|
|
SocketError(Error);
|
|
end;
|
|
end;
|
|
else
|
|
Result:= DefWindowProc(FHandle, Msg, WParam, LParam);
|
|
end;
|
|
end;
|
|
|
|
procedure TTCPClient.Open;
|
|
var
|
|
SockAddrIn: TSockAddrIn;
|
|
SockOpt: LongBool;
|
|
EventMask: longint;
|
|
begin
|
|
if (FSocketState <> ssClosed) then
|
|
Exit;
|
|
|
|
if not GetSockAddrIn(FHost, FPort, SockAddrIn) then
|
|
Exit;
|
|
|
|
FLocalSocket:= socket(PF_INET, FType, 0);
|
|
if FLocalSocket = INVALID_SOCKET then
|
|
begin
|
|
SocketError(WSAGetLastError);
|
|
Exit;
|
|
end;
|
|
|
|
EventMask:= (FD_CONNECT or FD_READ or FD_CLOSE);
|
|
if WSAASyncSelect(FLocalSocket, FHandle, WM_ASYNCSELECT, EventMask) <> 0 then
|
|
begin
|
|
SocketError(WSAGetLastError);
|
|
closesocket(FLocalSocket);
|
|
Exit;
|
|
end;
|
|
|
|
SockOpt:= true; {Enable OOB Data inline}
|
|
if setsockopt(FLocalSocket, SOL_SOCKET, SO_OOBINLINE, PAnsiChar(@SockOpt), SizeOf(SockOpt)) <> 0 then
|
|
begin
|
|
SocketError(WSAGetLastError);
|
|
closesocket(FLocalSocket);
|
|
Exit;
|
|
end;
|
|
|
|
if connect(FLocalSocket, SockAddrIn, SizeOf(SockAddrIn)) <> 0 then
|
|
begin
|
|
if WSAGetLastError <> WSAEWOULDBLOCK then
|
|
begin
|
|
SocketError(WSAGetLastError);
|
|
closesocket(FLocalSocket);
|
|
Exit;
|
|
end;
|
|
end;
|
|
|
|
FSocketState:= ssOpen;
|
|
end;
|
|
|
|
procedure TTCPClient.Close;
|
|
begin
|
|
if (FSocketState = ssNotStarted) or (FSocketState = ssClosed) then
|
|
Exit;
|
|
|
|
SocketClose(FLocalSocket, FHandle);
|
|
if FLocalSocket = INVALID_SOCKET then
|
|
FSocketState:= ssClosed;
|
|
end;
|
|
|
|
procedure TTCPClient.Write(Data: string);
|
|
begin
|
|
SocketWrite(FLocalSocket, 0, Data);
|
|
end;
|
|
|
|
function TTCPClient.Read: string;
|
|
begin
|
|
Result:= SocketRead(FLocalSocket, 0);
|
|
end;
|
|
|
|
function TTCPClient.Peek: string;
|
|
begin
|
|
Result:= SocketRead(FLocalSocket, MSG_PEEK);
|
|
end;
|
|
|
|
function TTCPClient.WriteBuffer(Buffer: Pointer; Size: integer): integer;
|
|
begin
|
|
Result:= SocketWriteBuffer(FLocalSocket, Buffer, Size, 0);
|
|
end;
|
|
|
|
function TTCPClient.ReadBuffer(Buffer: Pointer; Size: integer): integer;
|
|
begin
|
|
Result:= SocketReadBuffer(FLocalSocket, Buffer, Size, 0);
|
|
end;
|
|
|
|
function TTCPClient.GetPeerAddress: string;
|
|
begin
|
|
Result:= PeerToAddress(FLocalSocket);
|
|
end;
|
|
|
|
function TTCPClient.GetPeerPort: string;
|
|
begin
|
|
Result:= PeerToPort(FLocalSocket);
|
|
end;
|
|
|
|
(**** TTCPServer Class ****)
|
|
|
|
constructor TTCPServer.Create(AOwner: TComponent);
|
|
begin
|
|
inherited Create(AOwner);
|
|
FHandle:= AllocateHWnd(WndProc);
|
|
FProtocol:= IPPROTO_TCP;
|
|
FType:= SOCK_STREAM;
|
|
FClients:= TClientList.Create;
|
|
end;
|
|
|
|
destructor TTCPServer.Destroy;
|
|
begin
|
|
Close;
|
|
DeallocateHWnd(FHandle);
|
|
FClients.Free;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TTCPServer.OpenConnection(Socket: TSocket; Error: word);
|
|
var
|
|
Len: integer;
|
|
NewSocket: TSocket;
|
|
SockAddrIn: TSockAddrIn;
|
|
SockOpt: LongBool;
|
|
EventMask: longint;
|
|
begin
|
|
if Error <> 0 then
|
|
SocketError(Error)
|
|
else
|
|
begin
|
|
Len:= SizeOf(SockAddrIn);
|
|
//{$IFDEF VER100} // Delphi 3
|
|
NewSocket:= accept(FLocalSocket, @SockAddrIn, @Len);
|
|
//{$ELSE} // Delphi 2
|
|
//NewSocket:= accept(FLocalSocket, SockAddrIn, Len);
|
|
//{$ENDIF}
|
|
if NewSocket = INVALID_SOCKET then
|
|
begin
|
|
SocketError(WSAGetLastError);
|
|
Exit;
|
|
end;
|
|
|
|
EventMask:= (FD_READ or FD_CLOSE);
|
|
if WSAASyncSelect(NewSocket, FHandle, WM_ASYNCSELECT, EventMask) <> 0 then
|
|
begin
|
|
SocketError(WSAGetLastError);
|
|
closesocket(NewSocket);
|
|
Exit;
|
|
end;
|
|
|
|
SockOpt:= true; {Enable OOB Data inline}
|
|
if setsockopt(NewSocket, SOL_SOCKET, SO_OOBINLINE , PAnsiChar(@SockOpt), SizeOf(SockOpt)) <> 0 then
|
|
begin
|
|
SocketError(WSAGetLastError);
|
|
closesocket(NewSocket);
|
|
Exit;
|
|
end;
|
|
|
|
if not FClients.Add(NewSocket) then
|
|
SocketClose(NewSocket, FHandle)
|
|
else
|
|
if Assigned(FOnAccept) then
|
|
FOnAccept(Self, NewSocket);
|
|
end;
|
|
end;
|
|
|
|
procedure TTCPServer.CloseConnection(Socket: TSocket; Error: word);
|
|
begin
|
|
if Error = WSAENETDOWN then
|
|
SocketError(Error)
|
|
else
|
|
begin
|
|
if Assigned(FOnClose) then
|
|
FOnClose(Self, Socket);
|
|
Disconnect(Socket);
|
|
end;
|
|
end;
|
|
|
|
procedure TTCPServer.IncommingData(Socket: TSocket; Error: word);
|
|
begin
|
|
if Error <> 0 then
|
|
SocketError(Error)
|
|
else
|
|
if Assigned(FOnData) then
|
|
FOnData(Self, Socket);
|
|
end;
|
|
|
|
procedure TTCPServer.WndProc(var AMsg: TMessage);
|
|
var
|
|
Error: word;
|
|
begin
|
|
with AMsg do
|
|
case Msg of
|
|
WM_ASYNCSELECT:
|
|
begin
|
|
if (FSocketState = ssClosed) then
|
|
Exit;
|
|
Error:= WSAGetSelectError(LParam);
|
|
case WSAGetSelectEvent(LParam) of
|
|
FD_READ : IncommingData(WParam, Error);
|
|
FD_ACCEPT: OpenConnection(WParam, Error);
|
|
FD_CLOSE : CloseConnection(WParam, Error);
|
|
else
|
|
if Error <> 0 then
|
|
SocketError(Error);
|
|
end;
|
|
end;
|
|
else
|
|
Result:= DefWindowProc(FHandle, Msg, WParam, LParam);
|
|
end;
|
|
end;
|
|
|
|
procedure TTCPServer.Open;
|
|
var
|
|
SockAddrIn: TSockAddrIn;
|
|
begin
|
|
if (FSocketState <> ssClosed) then
|
|
Exit;
|
|
|
|
if not GetAnySockAddrIn(FPort, SockAddrIn) then
|
|
Exit;
|
|
|
|
FLocalSocket:= socket(PF_INET, FType, 0);
|
|
if FLocalSocket = INVALID_SOCKET then
|
|
begin
|
|
SocketError(WSAGetLastError);
|
|
Exit;
|
|
end;
|
|
|
|
if WSAASyncSelect(FLocalSocket, FHandle, WM_ASYNCSELECT, FD_ACCEPT) <> 0 then
|
|
begin
|
|
SocketError(WSAGetLastError);
|
|
closesocket(FLocalSocket);
|
|
Exit;
|
|
end;
|
|
|
|
if bind(FLocalSocket, SockAddrIn, SizeOf(SockAddrIn)) <> 0 then
|
|
begin
|
|
SocketError(WSAGetLastError);
|
|
closesocket(FLocalSocket);
|
|
Exit;
|
|
end;
|
|
|
|
if listen(FLocalSocket, 5) <> 0 then
|
|
begin
|
|
SocketError(WSAGetLastError);
|
|
closesocket(FLocalSocket);
|
|
Exit;
|
|
end;
|
|
|
|
FSocketState:= ssListening;
|
|
end;
|
|
|
|
procedure TTCPServer.Close;
|
|
var
|
|
i: integer;
|
|
Dummy: TSocket;
|
|
begin
|
|
if (FSocketState = ssNotStarted) or (FSocketState = ssClosed) then
|
|
Exit;
|
|
|
|
for i:= 0 to FClients.Count-1 do
|
|
begin
|
|
Dummy:= FClients[i];
|
|
SocketClose(Dummy, FHandle);
|
|
end;
|
|
FClients.Clear;
|
|
|
|
SocketClose(FLocalSocket, FHandle);
|
|
if FLocalSocket = INVALID_SOCKET then
|
|
FSocketState:= ssClosed;
|
|
end;
|
|
|
|
procedure TTCPServer.Write(Socket: TSocket; Data: string);
|
|
begin
|
|
SocketWrite(Socket, 0, Data);
|
|
end;
|
|
|
|
function TTCPServer.Read(Socket: TSocket): string;
|
|
begin
|
|
Result:= SocketRead(Socket, 0);
|
|
end;
|
|
|
|
function TTCPServer.Peek(Socket: TSocket): string;
|
|
begin
|
|
Result:= SocketRead(Socket, MSG_PEEK);
|
|
end;
|
|
|
|
function TTCPServer.WriteBuffer(Socket: TSocket; Buffer: Pointer; Size: integer): integer;
|
|
begin
|
|
Result:= SocketWriteBuffer(Socket, Buffer, Size, 0);
|
|
end;
|
|
|
|
function TTCPServer.ReadBuffer(Socket: TSocket; Buffer: Pointer; Size: integer): integer;
|
|
begin
|
|
Result:= SocketReadBuffer(Socket, Buffer, Size, 0);
|
|
end;
|
|
|
|
procedure TTCPServer.Disconnect(Socket: TSocket);
|
|
begin
|
|
FClients.Delete(Socket);
|
|
SocketClose(Socket, FHandle);
|
|
end;
|
|
|
|
(**** TUDPClient Class ****)
|
|
|
|
constructor TUDPClient.Create(AOwner: TComponent);
|
|
begin
|
|
inherited Create(AOwner);
|
|
FHandle:= AllocateHWnd(WndProc);
|
|
FProtocol:= IPPROTO_UDP;
|
|
FType:= SOCK_DGRAM;
|
|
end;
|
|
|
|
destructor TUDPClient.Destroy;
|
|
begin
|
|
Close;
|
|
DeallocateHWnd(FHandle);
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TUDPClient.IncommingData(Socket: TSocket; Error: word);
|
|
begin
|
|
if Error <> 0 then
|
|
SocketError(Error)
|
|
else
|
|
if Assigned(FOnData) then
|
|
FOnData(Self, Socket);
|
|
end;
|
|
|
|
procedure TUDPClient.WndProc(var AMsg: TMessage);
|
|
var
|
|
Error: word;
|
|
begin
|
|
with AMsg do
|
|
case Msg of
|
|
WM_ASYNCSELECT:
|
|
begin
|
|
if (FSocketState = ssClosed) then
|
|
Exit;
|
|
Error:= WSAGetSelectError(LParam);
|
|
case WSAGetSelectEvent(LParam) of
|
|
FD_READ : IncommingData(WParam, Error);
|
|
else
|
|
if Error <> 0 then
|
|
SocketError(Error);
|
|
end;
|
|
end;
|
|
else
|
|
Result:= DefWindowProc(FHandle, Msg, WParam, LParam);
|
|
end;
|
|
end;
|
|
|
|
procedure TUDPClient.Open;
|
|
var
|
|
SockAddrIn: TSockAddrIn;
|
|
begin
|
|
if (FSocketState <> ssClosed) then
|
|
Exit;
|
|
|
|
if not GetSockAddrIn(FHost, FPort, SockAddrIn) then
|
|
Exit;
|
|
|
|
FLocalSocket:= socket(PF_INET, FType, 0);
|
|
if FLocalSocket = INVALID_SOCKET then
|
|
begin
|
|
SocketError(WSAGetLastError);
|
|
Exit;
|
|
end;
|
|
|
|
if WSAASyncSelect(FLocalSocket, FHandle, WM_ASYNCSELECT, FD_READ) <> 0 then
|
|
begin
|
|
SocketError(WSAGetLastError);
|
|
closesocket(FLocalSocket);
|
|
Exit;
|
|
end;
|
|
|
|
if connect(FLocalSocket, SockAddrIn, SizeOf(SockAddrIn)) <> 0 then
|
|
begin
|
|
if WSAGetLastError <> WSAEWOULDBLOCK then
|
|
begin
|
|
SocketError(WSAGetLastError);
|
|
closesocket(FLocalSocket);
|
|
Exit;
|
|
end;
|
|
end;
|
|
|
|
FSocketState:= ssOpen;
|
|
end;
|
|
|
|
procedure TUDPClient.Close;
|
|
begin
|
|
if (FSocketState = ssNotStarted) or (FSocketState = ssClosed) then
|
|
Exit;
|
|
|
|
SocketClose(FLocalSocket, FHandle);
|
|
if FLocalSocket = INVALID_SOCKET then
|
|
FSocketState:= ssClosed;
|
|
end;
|
|
|
|
procedure TUDPClient.Write(Data: string);
|
|
begin
|
|
SocketWrite(FLocalSocket, 0, Data);
|
|
end;
|
|
|
|
function TUDPClient.Read: string;
|
|
begin
|
|
Result:= SocketRead(FLocalSocket, 0);
|
|
end;
|
|
|
|
function TUDPClient.Peek: string;
|
|
begin
|
|
Result:= SocketRead(FLocalSocket, MSG_PEEK);
|
|
end;
|
|
|
|
function TUDPClient.WriteBuffer(Buffer: Pointer; Size: integer): integer;
|
|
begin
|
|
Result:= SocketWriteBuffer(FLocalSocket, Buffer, Size, 0);
|
|
end;
|
|
|
|
function TUDPClient.ReadBuffer(Buffer: Pointer; Size: integer): integer;
|
|
begin
|
|
Result:= SocketReadBuffer(FLocalSocket, Buffer, Size, 0);
|
|
end;
|
|
|
|
function TUDPClient.GetPeerAddress: string;
|
|
begin
|
|
Result:= PeerToAddress(FLocalSocket);
|
|
end;
|
|
|
|
function TUDPClient.GetPeerPort: string;
|
|
begin
|
|
Result:= PeerToPort(FLocalSocket);
|
|
end;
|
|
|
|
(**** TUDPServer Class ****)
|
|
|
|
constructor TUDPServer.Create(AOwner: TComponent);
|
|
begin
|
|
inherited Create(AOwner);
|
|
FHandle:= AllocateHWnd(WndProc);
|
|
FProtocol:= IPPROTO_UDP;
|
|
FType:= SOCK_DGRAM;
|
|
end;
|
|
|
|
destructor TUDPServer.Destroy;
|
|
begin
|
|
Close;
|
|
DeallocateHWnd(FHandle);
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TUDPServer.IncommingData(Socket: TSocket; Error: word);
|
|
begin
|
|
if Error <> 0 then
|
|
SocketError(Error)
|
|
else
|
|
if Assigned(FOnData) then
|
|
FOnData(Self, Socket);
|
|
end;
|
|
|
|
procedure TUDPServer.WndProc(var AMsg: TMessage);
|
|
var
|
|
Error: word;
|
|
begin
|
|
with AMsg do
|
|
case Msg of
|
|
WM_ASYNCSELECT:
|
|
begin
|
|
if (FSocketState = ssClosed) then
|
|
Exit;
|
|
Error:= WSAGetSelectError(LParam);
|
|
case WSAGetSelectEvent(LParam) of
|
|
FD_READ : IncommingData(WParam, Error);
|
|
else
|
|
if Error <> 0 then
|
|
SocketError(Error);
|
|
end;
|
|
end;
|
|
else
|
|
Result:= DefWindowProc(FHandle, Msg, WParam, LParam);
|
|
end;
|
|
end;
|
|
|
|
procedure TUDPServer.Open;
|
|
var
|
|
SockAddrIn: TSockAddrIn;
|
|
SockOpt: LongBool;
|
|
begin
|
|
if (FSocketState <> ssClosed) then
|
|
Exit;
|
|
|
|
if not GetAnySockAddrIn(FPort, SockAddrIn) then
|
|
Exit;
|
|
|
|
FLocalSocket:= socket(PF_INET, FType, 0);
|
|
if FLocalSocket = INVALID_SOCKET then
|
|
begin
|
|
SocketError(WSAGetLastError);
|
|
Exit;
|
|
end;
|
|
|
|
if WSAASyncSelect(FLocalSocket, FHandle, WM_ASYNCSELECT, FD_READ) <> 0 then
|
|
begin
|
|
SocketError(WSAGetLastError);
|
|
closesocket(FLocalSocket);
|
|
Exit;
|
|
end;
|
|
|
|
SockOpt:= true; {Enable Broadcasting on this Socket}
|
|
if setsockopt(FLocalSocket, SOL_SOCKET, SO_BROADCAST, PAnsiChar(@SockOpt), SizeOf(SockOpt)) <> 0 then
|
|
begin
|
|
SocketError(WSAGetLastError);
|
|
closesocket(FLocalSocket);
|
|
Exit;
|
|
end;
|
|
|
|
if bind(FLocalSocket, SockAddrIn, SizeOf(SockAddrIn)) <> 0 then
|
|
begin
|
|
SocketError(WSAGetLastError);
|
|
closesocket(FLocalSocket);
|
|
Exit;
|
|
end;
|
|
|
|
FSocketState:= ssListening;
|
|
end;
|
|
|
|
procedure TUDPServer.Close;
|
|
begin
|
|
if (FSocketState = ssNotStarted) or (FSocketState = ssClosed) then
|
|
Exit;
|
|
|
|
SocketClose(FLocalSocket, FHandle);
|
|
if FLocalSocket = INVALID_SOCKET then
|
|
FSocketState:= ssClosed;
|
|
end;
|
|
|
|
procedure TUDPServer.Write(Socket: TSocket; Data: string; var SockAddrIn: TSockAddrIn);
|
|
begin
|
|
SocketWriteTo(Socket, 0, Data, SockAddrIn);
|
|
end;
|
|
|
|
function TUDPServer.Read(Socket: TSocket; var SockAddrIn: TSockAddrIn): string;
|
|
begin
|
|
Result:= SocketReadFrom(Socket, 0, SockAddrIn);
|
|
end;
|
|
|
|
function TUDPServer.Peek(Socket: TSocket; var SockAddrIn: TSockAddrIn): string;
|
|
begin
|
|
Result:= SocketReadFrom(Socket, MSG_PEEK, SockAddrIn);
|
|
end;
|
|
|
|
function TUDPServer.WriteBuffer(Socket: TSocket; Buffer: Pointer; Size: integer; var SockAddrIn: TSockAddrIn): integer;
|
|
begin
|
|
Result:= SocketWriteBufferTo(Socket, Buffer, Size, 0, SockAddrIn);
|
|
end;
|
|
|
|
function TUDPServer.ReadBuffer(Socket: TSocket; Buffer: Pointer; Size: integer; var SockAddrIn: TSockAddrIn): integer;
|
|
begin
|
|
Result:= SocketReadBufferFrom(Socket, Buffer, Size, 0, SockAddrIn);
|
|
end;
|
|
|
|
end.
|