📄 blcksock.pas
字号:
{==============================================================================|
| Project : Delphree - Synapse | 004.000.000 |
|==============================================================================|
| Content: Library base |
|==============================================================================|
| The contents of this file are subject to the Mozilla Public License Ver. 1.1 |
| (the "License"); you may not use this file except in compliance with the |
| License. You may obtain a copy of the License at http://www.mozilla.org/MPL/ |
| |
| Software distributed under the License is distributed on an "AS IS" basis, |
| WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for |
| the specific language governing rights and limitations under the License. |
|==============================================================================|
| The Original Code is Synapse Delphi Library. |
|==============================================================================|
| The Initial Developer of the Original Code is Lukas Gebauer (Czech Republic).|
| Portions created by Lukas Gebauer are Copyright (c)1999,2000,2001. |
| All Rights Reserved. |
|==============================================================================|
| Contributor(s): |
|==============================================================================|
| History: see HISTORY.HTM from distribution package |
| (Found at URL: http://www.ararat.cz/synapse/) |
|==============================================================================}
{$WEAKPACKAGEUNIT ON}
unit blcksock;
interface
uses
SysUtils, Classes,
{$IFDEF LINUX}
Libc, kernelioctl,
{$ELSE}
Windows, WinSock,
{$ENDIF}
synsock, SynaUtil;
const
cLocalhost = 'localhost';
type
ESynapseError = class(Exception)
public
ErrorCode: Integer;
ErrorMessage: string;
end;
THookSocketReason = (
HR_ResolvingBegin,
HR_ResolvingEnd,
HR_SocketCreate,
HR_SocketClose,
HR_Bind,
HR_Connect,
HR_CanRead,
HR_CanWrite,
HR_Listen,
HR_Accept,
HR_ReadCount,
HR_WriteCount
);
THookSocketStatus = procedure(Sender: TObject; Reason: THookSocketReason;
const Value: string) of object;
TBlockSocket = class(TObject)
private
FOnStatus: THookSocketStatus;
FWsaData: TWSADATA;
FLocalSin: TSockAddrIn;
FRemoteSin: TSockAddrIn;
FLastError: Integer;
FBuffer: string;
FRaiseExcept: Boolean;
function GetSizeRecvBuffer: Integer;
procedure SetSizeRecvBuffer(Size: Integer);
function GetSizeSendBuffer: Integer;
procedure SetSizeSendBuffer(Size: Integer);
protected
FSocket: TSocket;
FProtocol: Integer;
procedure CreateSocket; virtual;
procedure SetSin(var Sin: TSockAddrIn; IP, Port: string);
function GetSinIP(Sin: TSockAddrIn): string;
function GetSinPort(Sin: TSockAddrIn): Integer;
procedure DoStatus(Reason: THookSocketReason; const Value: string);
public
constructor Create;
constructor CreateAlternate(Stub: string);
destructor Destroy; override;
procedure CloseSocket; virtual;
procedure Bind(IP, Port: string);
procedure Connect(IP, Port: string); virtual;
function SendBuffer(Buffer: Pointer; Length: Integer): Integer; virtual;
procedure SendByte(Data: Byte); virtual;
procedure SendString(const Data: string); virtual;
function RecvBuffer(Buffer: Pointer; Length: Integer): Integer; virtual;
function RecvBufferEx(Buffer: Pointer; Length: Integer;
Timeout: Integer): Integer; virtual;
function RecvByte(Timeout: Integer): Byte; virtual;
function RecvString(Timeout: Integer): string; virtual;
function RecvPacket(Timeout: Integer): string; virtual;
function PeekBuffer(Buffer: Pointer; Length: Integer): Integer; virtual;
function PeekByte(Timeout: Integer): Byte; virtual;
function WaitingData: Integer;
procedure SetLinger(Enable: Boolean; Linger: Integer);
procedure GetSins;
function SockCheck(SockResult: Integer): Integer;
procedure ExceptCheck;
function LocalName: string;
procedure ResolveNameToIP(Name: string; IPList: TStrings);
function ResolveName(Name: string): string;
function ResolvePort(Port: string): Word;
procedure SetRemoteSin(IP, Port: string);
function GetLocalSinIP: string; virtual;
function GetRemoteSinIP: string; virtual;
function GetLocalSinPort: Integer; virtual;
function GetRemoteSinPort: Integer; virtual;
function CanRead(Timeout: Integer): Boolean;
function CanWrite(Timeout: Integer): Boolean;
function SendBufferTo(Buffer: Pointer; Length: Integer): Integer; virtual;
function RecvBufferFrom(Buffer: Pointer; Length: Integer): Integer; virtual;
function GroupCanRead(const SocketList: TList; Timeout: Integer;
const CanReadList: TList): Boolean;
//See 'winsock2.txt' file in distribute package!
function SetTimeout(Timeout: Integer): Boolean;
function SetSendTimeout(Timeout: Integer): Boolean;
function SetRecvTimeout(Timeout: Integer): Boolean;
property LocalSin: TSockAddrIn read FLocalSin;
property RemoteSin: TSockAddrIn read FRemoteSin;
published
class function GetErrorDesc(ErrorCode: Integer): string;
property Socket: TSocket read FSocket write FSocket;
property LastError: Integer read FLastError;
property Protocol: Integer read FProtocol;
property LineBuffer: string read FBuffer write FBuffer;
property RaiseExcept: Boolean read FRaiseExcept write FRaiseExcept;
property SizeRecvBuffer: Integer read GetSizeRecvBuffer write SetSizeRecvBuffer;
property SizeSendBuffer: Integer read GetSizeSendBuffer write SetSizeSendBuffer;
property WSAData: TWSADATA read FWsaData;
property OnStatus: THookSocketStatus read FOnStatus write FOnStatus;
end;
TSocksBlockSocket = class(TBlockSocket)
protected
FSocksIP: string;
FSocksPort: string;
FSocksTimeout: integer;
FSocksUsername: string;
FSocksPassword: string;
FUsingSocks: Boolean;
FSocksResolver: Boolean;
FSocksLastError: integer;
FSocksResponseIP: string;
FSocksResponsePort: string;
FSocksLocalIP: string;
FSocksLocalPort: string;
FSocksRemoteIP: string;
FSocksRemotePort: string;
function SocksCode(IP, Port: string): string;
function SocksDecode(Value: string): integer;
public
constructor Create;
function SocksOpen: Boolean;
function SocksRequest(Cmd: Byte; const IP, Port: string): Boolean;
function SocksResponse: Boolean;
published
property SocksIP: string read FSocksIP write FSocksIP;
property SocksPort: string read FSocksPort write FSocksPort;
property SocksUsername: string read FSocksUsername write FSocksUsername;
property SocksPassword: string read FSocksPassword write FSocksPassword;
property UsingSocks: Boolean read FUsingSocks;
property SocksResolver: Boolean read FSocksResolver write FSocksResolver;
property SocksLastError: integer read FSocksLastError;
end;
TTCPBlockSocket = class(TSocksBlockSocket)
public
procedure CreateSocket; override;
procedure CloseSocket; override;
procedure Listen;
function Accept: TSocket;
procedure Connect(IP, Port: string); override;
function GetLocalSinIP: string; override;
function GetRemoteSinIP: string; override;
function GetLocalSinPort: Integer; override;
function GetRemoteSinPort: Integer; override;
end;
TUDPBlockSocket = class(TSocksBlockSocket)
protected
FSocksControlSock: TTCPBlockSocket;
function UdpAssociation: Boolean;
public
destructor Destroy; override;
procedure CreateSocket; override;
function EnableBroadcast(Value: Boolean): Boolean;
procedure Connect(IP, Port: string); override;
function SendBuffer(Buffer: Pointer; Length: Integer): Integer; override;
function RecvBuffer(Buffer: Pointer; Length: Integer): Integer; override;
function SendBufferTo(Buffer: Pointer; Length: Integer): Integer; override;
function RecvBufferFrom(Buffer: Pointer; Length: Integer): Integer; override;
end;
//See 'winsock2.txt' file in distribute package!
TICMPBlockSocket = class(TBlockSocket)
public
procedure CreateSocket; override;
end;
//See 'winsock2.txt' file in distribute package!
TRAWBlockSocket = class(TBlockSocket)
public
procedure CreateSocket; override;
end;
TIPHeader = record
VerLen: Byte;
TOS: Byte;
TotalLen: Word;
Identifer: Word;
FragOffsets: Word;
TTL: Byte;
Protocol: Byte;
CheckSum: Word;
SourceIp: DWORD;
DestIp: DWORD;
Options: DWORD;
end;
implementation
constructor TBlockSocket.Create;
var
e: ESynapseError;
begin
inherited Create;
FRaiseExcept := False;
FSocket := INVALID_SOCKET;
FProtocol := IPPROTO_IP;
FBuffer := '';
if not InitSocketInterface('') then
begin
e := ESynapseError.Create('Error loading Winsock DLL!');
e.ErrorCode := 0;
e.ErrorMessage := 'Error loading Winsock DLL!';
raise e;
end;
SockCheck(synsock.WSAStartup($101, FWsaData));
ExceptCheck;
end;
constructor TBlockSocket.CreateAlternate(Stub: string);
var
e: ESynapseError;
begin
inherited Create;
FRaiseExcept := False;
FSocket := INVALID_SOCKET;
FProtocol := IPPROTO_IP;
FBuffer := '';
if not InitSocketInterface(Stub) then
begin
e := ESynapseError.Create('Error loading alternate Winsock DLL (' + Stub + ')!');
e.ErrorCode := 0;
e.ErrorMessage := 'Error loading Winsock DLL (' + Stub + ')!';
raise e;
end;
SockCheck(synsock.WSAStartup($101, FWsaData));
ExceptCheck;
end;
destructor TBlockSocket.Destroy;
begin
CloseSocket;
synsock.WSACleanup;
DestroySocketInterface;
inherited Destroy;
end;
procedure TBlockSocket.SetSin(var Sin: TSockAddrIn; IP, Port: string);
var
ProtoEnt: PProtoEnt;
ServEnt: PServEnt;
HostEnt: PHostEnt;
begin
DoStatus(HR_ResolvingBegin, IP + ':' + Port);
FillChar(Sin, Sizeof(Sin), 0);
Sin.sin_family := AF_INET;
ProtoEnt := synsock.GetProtoByNumber(FProtocol);
ServEnt := nil;
if ProtoEnt <> nil then
ServEnt := synsock.GetServByName(PChar(Port), ProtoEnt^.p_name);
if ServEnt = nil then
Sin.sin_port := synsock.htons(StrToIntDef(Port, 0))
else
Sin.sin_port := ServEnt^.s_port;
if IP = '255.255.255.255' then
Sin.sin_addr.s_addr := u_long(INADDR_BROADCAST)
else
begin
Sin.sin_addr.s_addr := synsock.inet_addr(PChar(IP));
if SIn.sin_addr.s_addr = u_long(INADDR_NONE) then
begin
HostEnt := synsock.GetHostByName(PChar(IP));
if HostEnt <> nil then
SIn.sin_addr.S_addr := Longint(PLongint(HostEnt^.h_addr_list^)^);
end;
end;
DoStatus(HR_ResolvingEnd, IP+':'+Port);
end;
function TBlockSocket.GetSinIP(Sin: TSockAddrIn): string;
var
p: PChar;
begin
p := synsock.inet_ntoa(Sin.sin_addr);
if p = nil then
Result := ''
else
Result := p;
end;
function TBlockSocket.GetSinPort(Sin: TSockAddrIn): Integer;
begin
Result := synsock.ntohs(Sin.sin_port);
end;
procedure TBlockSocket.CreateSocket;
begin
FBuffer := '';
if FSocket = INVALID_SOCKET then
FLastError := synsock.WSAGetLastError
else
FLastError := 0;
ExceptCheck;
DoStatus(HR_SocketCreate, '');
end;
procedure TBlockSocket.CloseSocket;
begin
synsock.CloseSocket(FSocket);
DoStatus(HR_SocketClose, '');
end;
procedure TBlockSocket.Bind(IP, Port: string);
var
Sin: TSockAddrIn;
Len: Integer;
begin
SetSin(Sin, IP, Port);
SockCheck(synsock.Bind(FSocket, Sin, SizeOf(Sin)));
Len := SizeOf(FLocalSin);
synsock.GetSockName(FSocket, FLocalSin, Len);
FBuffer := '';
ExceptCheck;
DoStatus(HR_Bind, IP + ':' + Port);
end;
procedure TBlockSocket.Connect(IP, Port: string);
var
Sin: TSockAddrIn;
begin
SetSin(Sin, IP, Port);
SockCheck(synsock.Connect(FSocket, Sin, SizeOf(Sin)));
GetSins;
FBuffer := '';
ExceptCheck;
DoStatus(HR_Connect, IP + ':' + Port);
end;
procedure TBlockSocket.GetSins;
var
Len: Integer;
begin
Len := SizeOf(FLocalSin);
synsock.GetSockName(FSocket, FLocalSin, Len);
Len := SizeOf(FRemoteSin);
synsock.GetPeerName(FSocket, FremoteSin, Len);
end;
function TBlockSocket.SendBuffer(Buffer: Pointer; Length: Integer): Integer;
begin
Result := synsock.Send(FSocket, Buffer^, Length, 0);
SockCheck(Result);
ExceptCheck;
DoStatus(HR_WriteCount, IntToStr(Result));
end;
procedure TBlockSocket.SendByte(Data: Byte);
begin
SendBuffer(@Data, 1);
end;
procedure TBlockSocket.SendString(const Data: string);
begin
SendBuffer(PChar(Data), Length(Data));
end;
function TBlockSocket.RecvBuffer(Buffer: Pointer; Length: Integer): Integer;
begin
Result := synsock.Recv(FSocket, Buffer^, Length, 0);
if Result = 0 then
FLastError := WSAECONNRESET
else
SockCheck(Result);
ExceptCheck;
DoStatus(HR_ReadCount, IntToStr(Result));
end;
function TBlockSocket.RecvBufferEx(Buffer: Pointer; Length: Integer;
Timeout: Integer): Integer;
var
s, ss, st: string;
x, l, lss: Integer;
fb, fs: Integer;
max: Integer;
begin
FLastError := 0;
x := System.Length(FBuffer);
if Length <= x then
begin
fb := Length;
fs := 0;
end
else
begin
fb := x;
fs := Length - x;
end;
ss := '';
if fb > 0 then
begin
s := Copy(FBuffer, 1, fb);
Delete(FBuffer, 1, fb);
end;
if fs > 0 then
begin
Max := GetSizeRecvBuffer;
ss := '';
while System.Length(ss) < fs do
begin
if CanRead(Timeout) then
begin
l := WaitingData;
if l > max then
l := max;
if (system.Length(ss) + l) > fs then
l := fs - system.Length(ss);
SetLength(st, l);
x := synsock.Recv(FSocket, Pointer(st)^, l, 0);
if x = 0 then
FLastError := WSAECONNRESET
else
SockCheck(x);
if FLastError <> 0 then
Break;
DoStatus(HR_ReadCount, IntToStr(x));
lss := system.Length(ss);
SetLength(ss, lss + x);
Move(Pointer(st)^, Pointer(@ss[lss + 1])^, x);
{It is 3x faster then ss:=ss+copy(st,1,x);}
Sleep(0);
end
else
FLastError := WSAETIMEDOUT;
if FLastError <> 0 then
Break;
end;
fs := system.Length(ss);
end;
Result := fb + fs;
s := s + ss;
Move(Pointer(s)^, Buffer^, Result);
ExceptCheck;
end;
function TBlockSocket.RecvPacket(Timeout: Integer): string;
var
x: integer;
s: string;
begin
Result := '';
FLastError := 0;
x := -1;
if FBuffer <> '' then
begin
Result := FBuffer;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -