home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Chip 2002 November
/
Chip_2002-11_cd1.bin
/
zkuste
/
delphi
/
kompon
/
d3456
/
ICQ.ZIP
/
ICQ
/
Component
/
MySocket.pas
< prev
Wrap
Pascal/Delphi Source File
|
2002-08-16
|
30KB
|
1,011 lines
unit MySocket;
{(C) Alex Demchenko(alex@ritlabs.com)}
{$DEFINE USE_FORMS} //If you don't use forms unit remove this line
{$R-}
interface
uses
Windows, Messages, WinSock, {$IFDEF USE_FORMS}Forms, {$ENDIF} Classes, ICQWorks;
function InitMySocket(var WSA: TWSAData): LongWord;
procedure FinalMySocket;
type
{$IFNDEF USE_FORMS}
TWndMethod = procedure(var Message: TMessage) of object;
{$ENDIF}
TOnRecv = procedure(Sender: TObject; Socket: TSocket; Buffer: Pointer; BufLen: LongWord) of object;
TOnPktParse = procedure(Sender: TObject; Buffer: Pointer; BufLen: LongWord) of object;
TOnPktParseAdv = procedure(Sender: TObject; Buffer: Pointer; BufLen: LongWord; Incoming: Boolean) of object;
TOnAdvPktParse = procedure(Sender: TObject; Buffer: Pointer; BufLen: LongWord; Incoming: Boolean) of object;
TOnResolve = procedure(Sender: TObject; Addr: String) of object;
TOnError = procedure(Sender: TObject; ErrorType: TErrorType; ErrorMsg: String) of object;
TClSock = class(TObject)
private
FIp: String;
FDestPort: LongWord;
FClSock: TSocket;
FWndHandle: THandle;
FOnRecv: TOnRecv;
FOnDisconnect: TNotifyEvent;
FOnConnect: TNotifyEvent;
FOnConnectError: TNotifyEvent;
FOnPktParse: TOnPktParse;
FHostIp: array[0..MAXGETHOSTSTRUCT - 1] of Char;
FResolve: Boolean;
FOnResolve: TOnResolve;
FOnFailed: TNotifyEvent;
FOnError: TOnError;
function ResolveAddr(Value: Pointer): LongInt;
function TestResolve(IP: String): Boolean;
procedure InitConnect(dwIP: LongWord);
procedure OnSockMsg(var Msg: TMessage);
function IsConnected: Boolean;
public
constructor Create;
destructor Destroy; override;
procedure Connect; //Connect to remote host
procedure Resolve; //Just resolve remote host w/o connecting
procedure Disconnect;
procedure SendData(var Buf; BufLen: LongWord);
property IP: String read FIp write FIp;
property DestPort: LongWord read FDestPort write FDestPort;
property Connected: Boolean read IsConnected;
published
property OnRecieve: TOnRecv read FOnRecv write FOnRecv;
property OnDisconnect: TNotifyEvent read FOnDisconnect write FOnDisconnect;
property OnConnect: TNotifyEvent read FOnConnect write FOnConnect;
property OnConnectError: TNotifyEvent read FOnConnectError write FOnConnectError;
property OnPktParse: TOnPktParse read FOnPktParse write FOnPktParse;
property OnResolve: TOnResolve read FOnResolve write FOnResolve;
property OnResolveFailed: TNotifyEvent read FOnFailed write FOnFailed;
property OnError: TOnError read FOnError write FOnError;
end;
TProxySock = class(TObject)
private
FSrcBuf: array[0..MAX_DATA_LEN - 1] of Byte;
FSrcLen: Word;
FSock: TClSock;
FProxyType: TProxyType;
FProxyHost: String;
FProxyPort: Word;
FProxyAuth: Boolean;
FProxyPass: String;
FUserID: String;
FHost: String;
FPort: Word;
FResolve: Boolean;
FSocks: Word;
FOnConnectError: TNotifyEvent;
FOnDisconnect: TNotifyEvent;
FOnPktParse: TOnAdvPktParse;
FOnError: TOnError;
FOnRecv: TOnRecv;
FOnConnectProc: TNotifyEvent;
private
procedure OnSockResolve(Sender: TObject; Addr: String);
procedure OnSockResolveFailed(Sender: TObject);
procedure OnSockConnect(Sender: TObject);
procedure OnSockRecv(Sender: TObject; Socket: TSocket; Buffer: Pointer; BufLen: LongWord);
procedure OnSockConnectError(Sender: TObject);
procedure OnSockDisconnect(Sender: TObject);
procedure OnSockError(Sender: TObject; ErrorType: TErrorType; ErrorMsg: String);
procedure OnPktParse(Sender: TObject; Buffer: Pointer; BufLen: LongWord);
protected
procedure OnReceive(Buffer: Pointer; BufLen: LongWord); dynamic;
public
constructor Create;
destructor Destroy; override;
procedure Connect; dynamic;
procedure Disconnect;
procedure SendData(var Buf; BufLen: LongWord);
property Host: String read FHost write FHost;
property Port: Word read FPort write FPort;
property ProxyType: TProxyType read FProxyType write FProxyType;
property ProxyHost: String read FProxyHost write FProxyHost;
property ProxyPort: Word read FProxyPort write FProxyPort;
property ProxyUserID: String read FUserID write FUserID;
property ProxyAuth: Boolean read FProxyAuth write FProxyAuth;
property ProxyPass: String read FProxyPass write FProxyPass;
property UseProxyResolve: Boolean read FResolve write FResolve default False;
published
property OnConnectError: TNotifyEvent read FOnConnectError write FOnConnectError;
property OnDisconnect: TNotifyEvent read FOnDisconnect write FOnDisconnect;
property OnPktParseA: TOnAdvPktParse read FOnPktParse write FOnPktParse;
property OnError: TOnError read FOnError write FOnError;
property OnReceiveProc: TOnRecv read FOnRecv write FOnRecv;
property OnConnectProc: TNotifyEvent read FOnConnectProc write FOnConnectProc;
end;
TMySock = class(TProxySock)
private
function GetClientSocket: TSocket;
procedure SetClientSocket(Socket: TSocket);
function IsConnected: Boolean;
public
property ClientSocket: TSocket read GetClientSocket write SetClientSocket;
property Connected: Boolean read IsConnected;
end;
TOnClientConnected = procedure(Sender: TObject; Socket: TMySock) of object;
TSrvSock = class(TObject)
private
FWndHandle: THandle;
FSrvSock: TSocket;
FOnClientConnected: TOnClientConnected;
procedure OnSockMsg(var Msg: TMessage);
public
constructor Create;
destructor Destroy; override;
function StartServer(Port: Word): Boolean;
function StopServer: Boolean;
published
property OnClientConnected: TOnClientConnected read FOnClientConnected write FOnClientConnected;
end;
function GetLocalIP: LongInt;
function FindBindPort: Word;
implementation
const
WSA_ACCEPT = WM_USER + $10;
WSA_NETEVENT = WM_USER + $20;
WSA_RESOLVE_COMPLETE = WM_USER + $30;
function InitMySocket(var WSA: TWSAData): LongWord;
begin
Result := WSAStartup(MAKEWORD(1, 1), WSA);
end;
procedure FinalMySocket;
begin
WSACleanUp;
end;
//////////////////////////////////////////////////////////////////////////////////////////////////////////
{$IFNDEF USE_FORMS}
type
PObjectInstance = ^TObjectInstance;
TObjectInstance = packed record
Code: Byte;
Offset: Integer;
case Integer of
0: (Next: PObjectInstance);
1: (Method: TWndMethod);
end;
PInstanceBlock = ^TInstanceBlock;
TInstanceBlock = packed record
Next: PInstanceBlock;
Code: array[1..2] of Byte;
WndProcPtr: Pointer;
Instances: array[0..100] of TObjectInstance;
end;
var
InstBlockList: PInstanceBlock;
InstFreeList: PObjectInstance;
{ Standard window procedure }
{ In ECX = Address of method pointer }
{ Out EAX = Result }
function StdWndProc(Window: HWND; Message, WParam: Longint;
LParam: Longint): Longint; stdcall; assembler;
asm
XOR EAX,EAX
PUSH EAX
PUSH LParam
PUSH WParam
PUSH Message
MOV EDX,ESP
MOV EAX,[ECX].Longint[4]
CALL [ECX].Pointer
ADD ESP,12
POP EAX
end;
{ Allocate an object instance }
function CalcJmpOffset(Src, Dest: Pointer): Longint;
begin
Result := Longint(Dest) - (Longint(Src) + 5);
end;
function MakeObjectInstance(Method: TWndMethod): Pointer;
const
BlockCode: array[1..2] of Byte = (
$59, { POP ECX }
$E9); { JMP StdWndProc }
PageSize = 4096;
var
Block: PInstanceBlock;
Instance: PObjectInstance;
begin
if InstFreeList = nil then
begin
Block := VirtualAlloc(nil, PageSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
Block^.Next := InstBlockList;
Move(BlockCode, Block^.Code, SizeOf(BlockCode));
Block^.WndProcPtr := Pointer(CalcJmpOffset(@Block^.Code[2], @StdWndProc));
Instance := @Block^.Instances;
repeat
Instance^.Code := $E8; { CALL NEAR PTR Offset }
Instance^.Offset := CalcJmpOffset(Instance, @Block^.Code);
Instance^.Next := InstFreeList;
InstFreeList := Instance;
Inc(Longint(Instance), SizeOf(TObjectInstance));
until Longint(Instance) - Longint(Block) >= SizeOf(TInstanceBlock);
InstBlockList := Block;
end;
Result := InstFreeList;
Instance := InstFreeList;
InstFreeList := Instance^.Next;
Instance^.Method := Method;
end;
{ Free an object instance }
procedure FreeObjectInstance(ObjectInstance: Pointer);
begin
if ObjectInstance <> nil then
begin
PObjectInstance(ObjectInstance)^.Next := InstFreeList;
InstFreeList := ObjectInstance;
end;
end;
var
UtilWindowClass: TWndClass = (
style: 0;
lpfnWndProc: @DefWindowProc;
cbClsExtra: 0;
cbWndExtra: 0;
hInstance: 0;
hIcon: 0;
hCursor: 0;
hbrBackground: 0;
lpszMenuName: nil;
lpszClassName: 'TPUtilWindow');
function AllocateHWnd(Method: TWndMethod): THandle;
var
TempClass: TWndClass;
ClassRegistered: Boolean;
begin
UtilWindowClass.hInstance := HInstance;
ClassRegistered := GetClassInfo(HInstance, UtilWindowClass.lpszClassName,
TempClass);
if not ClassRegistered or (TempClass.lpfnWndProc <> @DefWindowProc) then
begin
if ClassRegistered then
Windows.UnregisterClass(UtilWindowClass.lpszClassName, HInstance);
Windows.RegisterClass(UtilWindowClass);
end;
Result := CreateWindow(UtilWindowClass.lpszClassName,
'', WS_POPUP, 0, 0, 0, 0, 0, 0, HInstance, nil);
if Assigned(Method) then
SetWindowLong(Result, GWL_WNDPROC, Longint(MakeObjectInstance(Method)));
end;
procedure DeallocateHWnd(Wnd: THandle);
var
Instance: Pointer;
begin
Instance := Pointer(GetWindowLong(Wnd, GWL_WNDPROC));
DestroyWindow(Wnd);
if Instance <> @DefWindowProc then FreeObjectInstance(Instance);
end;
{$ENDIF}
/////////////////////////////////////////////////////////////////////////////////////////////////////////
constructor TClSock.Create;
begin
inherited;
FWndHandle := AllocateHwnd(OnSockMsg);
FClSock := INVALID_SOCKET;
FResolve := False;
end;
destructor TClSock.Destroy;
begin
closesocket(FClSock);
DeallocateHwnd(FWndHandle);
inherited;
end;
function TClSock.ResolveAddr(Value: Pointer): LongInt;
var
addr: in_addr;
hostent: PHostEnt;
begin
Result := -1;
hostent := Value;
if hostent^.h_addr_list <> nil then
begin
addr.S_addr := PLongInt(hostent^.h_addr_list^)^;
Result := addr.S_addr;
end else
Exit;
end;
function TClSock.TestResolve(IP: String): Boolean;
begin
Result := inet_addr(PChar(IP)) <> LongInt(INADDR_NONE);
end;
procedure TClSock.InitConnect(dwIP: LongWord);
var
dest_sin: TSockAddr;
begin
FClSock := socket(AF_INET, SOCK_STREAM, 0);
WSAAsyncSelect(FClSock, FWndHandle, WSA_NETEVENT, FD_CONNECT or FD_CLOSE or FD_READ);
dest_sin.sin_family := AF_INET;
dest_sin.sin_addr.s_addr := dwIP;
dest_sin.sin_port := htons(FDestPort);
if (WinSock.connect(FClSock, dest_sin, SizeOf(TSockAddr)) = SOCKET_ERROR) and (WSAGetLastError <> WSAEWOULDBLOCK) then
begin
if Assigned(OnError) then
FOnError(Self, ERR_SOCKET, 'connect() returned SOCKET_ERROR');
if Assigned(OnConnectError) then
FOnConnectError(Self);
Disconnect;
Exit;
end;
end;
procedure TClSock.OnSockMsg(var Msg: TMessage);
var
rc: Integer;
buf: array[0..1023] of Byte;
inaddr: in_addr;
begin
case Msg.Msg of
WSA_RESOLVE_COMPLETE:
begin
if FResolve then
begin
if Assigned(OnResolve) then
begin
if HIWORD(Msg.wParam) <> 0 then
begin
if Assigned(OnError) then
FOnError(Self, ERR_SOCKET, 'Cannot resolve host');
if Assigned(OnResolveFailed) then
FOnFailed(Self);
Exit;
end;
inaddr.S_addr := ResolveAddr(@FHostIP);
if Assigned(OnResolve) then
FOnResolve(Self, inet_ntoa(inaddr));
Exit;
end;
end;
if HIWORD(Msg.wParam) <> 0 then
begin
if Assigned(OnError) then
FOnError(Self, ERR_SOCKET, 'Cannot resolve host');
if Assigned(OnConnectError) then
FOnConnectError(Self);
Disconnect;
Exit;
end;
InitConnect(ResolveAddr(@FHostIP));
end;
WSA_NETEVENT:
begin
if WSAGetSelectEvent(Msg.lParam) = FD_READ then
begin
rc := recv(Msg.wParam, buf, SizeOf(buf) - 1, 0);
if rc <> SOCKET_ERROR then
begin
if Assigned(OnRecieve) then
FOnRecv(Self, Msg.wParam, @buf, rc);
end else
begin
if Assigned(OnError) then
FOnError(Self, ERR_SOCKET, 'Received some data, but recv() returned 0');
Disconnect;
end;
Exit;
end
//Connection with server was lost
else if WSAGetSelectEvent(Msg.lParam) = FD_CLOSE then
Disconnect
else if WSAGetSelectEvent(Msg.lParam) = FD_CONNECT then
begin
if HIWORD(Msg.lParam) = 0 then
begin
if Assigned(OnConnect) then
FOnConnect(Self);
end else
begin
if Assigned(OnError) then
FOnError(Self, ERR_SOCKET, 'Cannot connect: no rote to host.');
if Assigned(OnConnectError) then
FOnConnectError(Self);
Disconnect;
Exit;
end;
end;
end;
end;
end;
function TClSock.IsConnected: Boolean;
begin
Result := FClSock <> INVALID_SOCKET;
end;
procedure TClSock.Connect;
begin
FResolve := False;
if not TestResolve(FIp) then
begin
if WSAAsyncGetHostByName(FWndHandle, WSA_RESOLVE_COMPLETE, PChar(FIp), @FHostIp, SizeOf(FHostIp)) = 0 then
begin
if Assigned(OnError) then
FOnError(Self, ERR_SOCKET, 'Cannot init async. resolving');
if Assigned(OnConnectError) then
FOnConnectError(Self);
Disconnect;
Exit;
end;
end else
begin
InitConnect(inet_addr(PChar(FIp)));
end;
end;
procedure TClSock.Resolve;
begin
if not TestResolve(FIp) then
begin
FResolve := True;
if WSAAsyncGetHostByName(FWndHandle, WSA_RESOLVE_COMPLETE, PChar(FIp), @FHostIp, SizeOf(FHostIp)) = 0 then
begin
if Assigned(OnError) then
FOnError(Self, ERR_SOCKET, 'Cannot init async. resolving');
if Assigned(OnResolveFailed) then
FOnFailed(Self);
end;
end else
begin
FResolve := False;
if Assigned(OnResolve) then
FOnResolve(Self, FIp);
end;
end;
procedure TClSock.Disconnect;
begin
if FClSock <> INVALID_SOCKET then
begin
closesocket(FClSock);
FClSock := INVALID_SOCKET;
if Assigned(OnDisconnect) then
FOnDisconnect(Self);
end;
end;
procedure TClSock.SendData(var Buf; BufLen: LongWord);
var
ret: LongInt;
begin
if FClSock <> INVALID_SOCKET then
begin
ret := send(FClSock, Buf, BufLen, 0);
if ret = SOCKET_ERROR then
begin
if Assigned(OnError) then
FOnError(Self, ERR_SOCKET, 'Could not send data');
Disconnect;
Exit;
end;
if Assigned(OnPktParse) then
FOnPktParse(Self, @Buf, BufLen);
end;
end;
function GetLocalIP: LongInt;
type
PaPInAddr = ^TaPInAddr;
TaPInAddr = array[0..$FFFE] of PInAddr;
var
phe: PHostEnt;
pptr: PaPInAddr;
Buffer: array[0..63] of Char;
I: Integer;
begin
Result := -1;
GetHostName(Buffer, SizeOf(Buffer));
phe := GetHostByName(buffer);
if phe = nil then Exit;
pptr := PaPInAddr(Phe^.h_addr_list);
I := 0;
while pptr^[I] <> nil do
begin
Result := pptr^[I]^.S_addr;
Inc(I);
end;
end;
function FindBindPort: Word;
var
i: Word;
srv_address: sockaddr_in;
sock: TSocket;
begin
Result := 0;
sock := socket(AF_INET, SOCK_STREAM, 0);
if sock = INVALID_SOCKET then
Exit;
srv_address.sin_family := AF_INET;
srv_address.sin_addr.s_addr := INADDR_ANY;
for i := 3000 to 50000 do
begin
srv_address.sin_port := htons(i);
if bind(sock, srv_address, SizeOf(srv_address)) <> SOCKET_ERROR then
begin
closesocket(sock);
Result := i;
Exit;
end;
end;
end;
{@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@2}
constructor TProxySock.Create;
begin
inherited Create;
//Socket for working with TCP connections
FSock := TClSock.Create;
FSrcLen := 0;
//Assign internal Events
FSock.OnRecieve := OnSockRecv;
FSock.OnDisconnect := OnSockDisconnect;
FSock.OnConnectError := OnSockConnectError;
FSock.OnPktParse := OnPktParse;
FSock.OnConnect := OnSockConnect;
FSock.OnResolve := OnSockResolve;
FSock.OnResolveFailed := OnSockResolveFailed;
FSock.OnError := OnSockError;
end;
{*** DESTRUCTOR ***}
destructor TProxySock.Destroy;
begin
FSock.OnRecieve := nil; //. .
FSock.OnDisconnect := nil; //. .
FSock.OnConnectError := nil; //. DO NOT USE NOTIFICATIONS WHILE DESTROYING .
FSock.OnPktParse := nil; //. THE OBJECT, CAUSES ACCESS VIOLATIONS .
FSock.OnConnect := nil; //. .
FSock.OnResolve := nil; //.
FSock.OnError := nil;
FSock.Free;
inherited;
end;
{Connect procedure. Use it to connect to the remote server.}
procedure TProxySock.Connect;
begin
if (ProxyType = P_SOCKS4) or (ProxyType = P_SOCKS5) then
begin
FSock.OnPktParse := nil; //Do not dump proxy data
if not FResolve then
begin
FSock.IP := Host;
FSock.Resolve;
Exit;
end;
FSock.IP := ProxyHost;
FSock.DestPort := ProxyPort;
FSock.Connect;
end else
begin
FSock.IP := Host;
FSock.DestPort := Port;
FSock.Connect;
end;
end;
{Force socket disconnection.}
procedure TProxySock.Disconnect;
begin
FSock.Disconnect;
end;
{Called when socket cannot connect to remote host.}
procedure TProxySock.OnSockConnectError(Sender: TObject);
begin
if Assigned(OnConnectError) then
FOnConnectError(Self);
end;
{Called when closed connection.}
procedure TProxySock.OnSockDisconnect(Sender: TObject);
begin
if Assigned(OnDisconnect) then
FOnDisconnect(Self);
end;
procedure TProxySock.OnSockError(Sender: TObject; ErrorType: TErrorType; ErrorMsg: String);
begin
if Assigned(OnError) then
FOnError(Self, ErrorType, ErrorMsg);
end;
{Called when resolving of Host has been complete.}
procedure TProxySock.OnSockResolve(Sender: TObject; Addr: String);
begin
if FProxyType = P_NONE then Exit;
Host := Addr;
FSock.IP := ProxyHost;
FSock.DestPort := ProxyPort;
FSock.Connect;
end;
{Called when resolving failed.}
procedure TProxySock.OnSockResolveFailed(Sender: TObject);
begin
if Assigned(OnConnectError) then
FOnConnectError(Self);
end;
{Called after our socket connected to server.}
procedure TProxySock.OnSockConnect(Sender: TObject);
var
buf: array[0..255] of Byte;
begin
if ProxyType = P_NONE then //Do nothing if we are not using proxies
begin
if Assigned(OnConnectProc) then
FOnConnectProc(Self);
Exit
end
else if ProxyType = P_SOCKS4 then
begin
buf[0] := 4; //Socks4
buf[1] := 1; //Code: 1 - Connect
PWord(Ptr(LongWord(@Buf) + 2))^ := htons(Port); //Port
PDWord(Ptr(LongWord(@Buf) + 4))^ := inet_addr(PChar(Host)); //Host
if ProxyAuth then //Add some packet specified data when using proxy authentication
begin
if Length(ProxyUserID) > 0 then //Test if ProxyUserID string is not nil
Move(PChar(ProxyUserID)^, buf[8], Length(ProxyUserID)); //If it's not then add it to packet
buf[8 + Length(ProxyUserID) + 1] := 0; //Always present NULL termination byte
end else
buf[9] := 0; //Always present NULL termination byte
FSock.SendData(buf, 8 + Length(ProxyUserID) + 1);
end
else if ProxyType = P_SOCKS5 then
begin
FSocks := 0; //Socks authorization progress
buf[0] := 5; //Socks5
buf[1] := 1; //Number of methods
if ProxyAuth then //Choose auth method
buf[2] := 2 //Use authentication
else
buf[2] := 0; //Plain connect
FSock.SendData(buf, 3); //Send SOCKS5 initialization packet
end;
end;
{Called when something received on socket.}
procedure TProxySock.OnSockRecv(Sender: TObject; Socket: TSocket; Buffer: Pointer; BufLen: LongWord);
var
i: Word;
UserLen, PassLen: Word;
procedure DoSocks5Connect;
var
len: Word;
buf: array[0..255] of Byte;
begin
if not UseProxyResolve then //Socks5 supports on-server-resolving
len := 4
else
len := Length(Host) + 1;
buf[0] := 5; //Socks5
buf[1] := 1; //Command: connect
buf[2] := 0; //Reserved
if UseProxyResolve then
begin
buf[3] := 3;
buf[4] := len - 1;
Move(PChar(Host)^, buf[5], len - 1);
end else
begin
buf[3] := 1;
PDWord(LongWord(@buf) + 4)^ := inet_addr(PChar(Host));
end;
PWord(LongWord(@buf) + 4 + Len)^ := htons(Port);
FSock.SendData(buf, 6 + Len);
end;
begin
if BufLen = 0 then Exit;
if ProxyType = P_SOCKS4 then
begin
for i := 0 to BufLen - 1 do
begin
FSrcBuf[FSrcLen] := PByte(LongWord(Buffer) + i)^;
Inc(FSrcLen);
if FSrcLen = 8 then
begin
FProxyType := P_NONE; //After we connected to proxy we work as usual
Dec(BufLen, i);
FSrcLen := 0;
if PByte(Ptr(LongWord(Buffer) + 1))^ <> 90 then
begin
if Assigned(OnError) then
FOnError(Self, ERR_PROXY, 'SOCKS4 server cannot connect to remote server');
if Assigned(OnConnectError) then
FOnConnectError(Self);
Exit;
end;
FSock.OnPktParse := OnPktParse;
if Assigned(OnConnectProc) then
FOnConnectProc(Self);
if i < BufLen - 1 then
OnSockRecv(Sender, Socket, Ptr(LongWord(Buffer) + i), BufLen); //Continue handling of remaining data
end;
end;
Exit;
end else
if ProxyType = P_SOCKS5 then
begin
for i := 0 to BufLen - 1 do
begin
FSrcBuf[FSrcLen] := PByte(LongWord(Buffer) + i)^;
Inc(FSrcLen);
case FSocks of
0:
begin
if FSrcLen = 2 then
begin
if FSrcBuf[1] = $ff then
begin
if Assigned(OnError) then
FOnError(Self, ERR_PROXY, 'Auth methods are not supported by SOCKS5 server');
if Assigned(OnConnectError) then
FOnConnectError(Self);
Exit;
end;
FSrcLen := 0;
if FSrcBuf[1] = 2 then
begin
UserLen := Length(ProxyUserID);
PassLen := Length(ProxyPass);
FSrcBuf[0] := 1;
FSrcBuf[1] := UserLen;
Move(PChar(ProxyUserID)^, Ptr(LongWord(@FSrcBuf) + 2)^, UserLen);
FSrcBuf[UserLen + 2] := PassLen;
Move(PChar(ProxyPass)^, Ptr(LongWord(@FSrcBuf) + 3 + UserLen)^, UserLen);
FSock.SendData(FSrcBuf, 3 + UserLen + PassLen);
Inc(FSocks);
end else
begin
Inc(FSocks, 2);
DoSocks5Connect;
end;
end;
end;
1:
begin
if FSrcLen = 2 then
begin
if FSrcBuf[1] <> 0 then
begin
if Assigned(OnError) then
FOnError(Self, ERR_PROXY, 'SOCKS5 server cannot authenticate us');
if Assigned(OnConnectError) then
FOnConnectError(Self);
Exit;
end;
FSrcLen := 0;
Inc(FSocks);
DoSocks5Connect;
end;
end;
2:
begin
if FSrcLen = 10 then
begin
if (FSrcBuf[0] <> 5) or (FSrcBuf[1] <> 0) then
begin
if Assigned(OnError) then
FOnError(Self, ERR_PROXY, 'SOCKS5 server cannot connect to remote server');
if Assigned(OnConnectError) then
FOnConnectError(Self);
Exit;
end;
FSrcLen := 0;
ProxyType := P_NONE;
FSock.OnPktParse := OnPktParse;
if Assigned(OnConnectProc) then
FOnConnectProc(Self);
if i < BufLen - 1 then
OnSockRecv(Sender, Socket, Ptr(LongWord(Buffer) + i), BufLen); //Continue handling of remaining data
end;
end;
end;
end;
Exit;
end;
OnReceive(Buffer, BufLen);
end;
{Called when some data has been sent through socket.}
procedure TProxySock.OnPktParse(Sender: TObject; Buffer: Pointer; BufLen: LongWord);
begin
if Assigned(OnPktParseA) then
FOnPktParse(Sender, Buffer, BufLen, False);
end;
{Sending data throgh socket.}
procedure TProxySock.SendData(var Buf; BufLen: LongWord);
begin
FSock.SendData(Buf, BufLen);
end;
{Forward handlers.}
procedure TProxySock.OnReceive;
begin
if Assigned(OnReceiveProc) then
FOnRecv(Self, FSock.FClSock, Buffer, BufLen);
end;
function TMySock.GetClientSocket: TSocket;
begin
Result := FSock.FClSock;
end;
procedure TMySock.SetClientSocket(Socket: TSocket);
begin
FSock.FClSock := Socket;
end;
function TMySock.IsConnected: Boolean;
begin
Result := FSock.IsConnected;
end;
{@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@}
{-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=}
constructor TSrvSock.Create;
begin
inherited;
FWndHandle := AllocateHwnd(OnSockMsg);
FSrvSock := INVALID_SOCKET;
end;
destructor TSrvSock.Destroy;
begin
DeallocateHwnd(FWndHandle);
StopServer;
inherited;
end;
procedure TSrvSock.OnSockMsg(var Msg: TMessage);
var
//rc: Integer;
acc_sin_len: Integer;
acc_sin: sockaddr_in;
FClSock: TSocket;
FCl: TMySock;
begin
case Msg.Msg of
WSA_ACCEPT:
begin
if WSAGETSELECTERROR(Msg.lParam) <> 0 then
begin
MessageBox(0, 'accept Error', 'Error', MB_OK);
//WSAAsyncSelect(FSrvSock, FWndHandle, 0, 0);
Exit;
end;
//Size of acc_sin
acc_sin_len := SizeOf(acc_sin);
//Allow connection
FClSock := accept(FSrvSock, @acc_sin, @acc_sin_len);
if FClSock = INVALID_SOCKET then
begin
MessageBox(0, 'accept Error, invalid socket', 'Error', MB_OK);
Exit;
end;
FCl := TMySock.Create;
FCl.ClientSocket := FClSock;
//Allow network notifies in client socket
{rc := WSAAsyncSelect(FClSock, FCl.FWndHandle, WSA_NETEVENT,
FD_READ or FD_CLOSE);
if rc > 0 then
begin
closesocket(FClSock);
MessageBox(0, 'WSAAsyncSelect Error', 'Error', MB_OK);
FCl.Free;
Exit;
end;}
if Assigned(OnClientConnected) then
FOnClientConnected(Self, FCl);
end;
end;
end;
function TSrvSock.StartServer(Port: Word): Boolean;
var
srv_address: sockaddr_in;
rc: Integer;
begin
Result := False;
//Creating server socket
FSrvSock := socket(AF_INET, SOCK_STREAM, 0);
if FSrvSock = INVALID_SOCKET then
begin
MessageBox(0, 'Could not create server socket', 'Error', MB_OK);
Exit;
end;
srv_address.sin_family := AF_INET;
srv_address.sin_addr.s_addr := INADDR_ANY; //Accept connection from all addresses
srv_address.sin_port := htons(Port); //Set local port
//Binding a port
if bind(FSrvSock, srv_address, SizeOf(srv_address)) = SOCKET_ERROR then
begin
//Closing socket on error
closesocket(FSrvSock);
MessageBox(0, 'Could not bind server', 'Error', MB_OK);
Exit;
end;
//Setting socket in listen status
if listen(FSrvSock, 5) = SOCKET_ERROR then
begin
closesocket(FSrvSock);
MessageBox(0, 'listen Error', 'Error', MB_OK);
Exit;
end;
rc := WSAAsyncSelect(FSrvSock, FWndHandle, WSA_ACCEPT, FD_ACCEPT);
if rc > 0 then
begin
closesocket(FSrvSock);
MessageBox(0, 'WSAAsyncSelect Error', 'Error', MB_OK);
Exit;
end;
Result := True;
end;
function TSrvSock.StopServer: Boolean;
begin
Result := False;
if FSrvSock <> INVALID_SOCKET then
begin
//Removing receiveing of all notifications
WSAAsyncSelect(FSrvSock, FWndHandle, 0, 0);
//If socket was created then close it
closesocket(FSrvSock);
FSrvSock := INVALID_SOCKET;
Result := True;
end;
end;
end.