www.pudn.com > oicqspysrc.zip > ProxySocket.pas


unit ProxySocket; 
{$define SYNC} 
{ 
UDP Proxy core unit 
copyright (C) 2000-2002 NetGale 
 
} 
interface 
uses SysUtils,WIndows,WinSock,Classes,Dialogs; 
type 
    TProxySock=class; 
    TProxyReadThread=class(TThread) 
        private 
        FProxySock:TProxySock; 
        FBuffer:array [0..2048] of char; 
        FBuflen:Integer; 
        FFromAddr:TSockAddr; 
        procedure DoNotify; 
        protected 
        procedure DoTerminate; override; 
        procedure Execute; override; 
        public 
        constructor Create(CreateSuspended:Boolean;ASock:TProxySock); 
        destructor  Destroy;override; 
        end; 
 
    TSwitchDirection=(sdRecv,sdSend); 
    TSockNotifyEvent=procedure (buf:array of char;buflen:integer;from:TSockAddr;Dest:TSockAddr;var drop:Boolean) of object; 
    TUDPSwitcher=class; 
    PUDPSwitcher=^TUDPSwitcher; 
    TProxySock=class 
        private 
        FDirection:TSwitchDirection; 
        FSocket:TSocket; 
        FReadThread:TProxyReadThread; 
        FSwitcher:TUDPSwitcher; 
        procedure   Init; 
        public 
        Tag:Integer; 
        ThisAddr,ProxyAddr:TSockAddr; 
        constructor Create(aProxyAddr:TSockAddr);overload; 
        constructor Create(aThisAddr:TSockAddr;aProxyAddr:TSockAddr);overload; 
        constructor Create(ThisPort:WORD;aProxyAddr:TSockAddr);overload; 
        constructor Create(ThisPort:WORD;ProxyIp:String;ProxyPort:WORD);overload; 
        destructor  Destroy;override; 
 
 
        function    CreateSocket:Boolean; 
        procedure   OnRecv(buf:array of char;buflen:Integer;from:TSockAddr); 
        function    SendBuf(buf:array of char;buflen:Integer;Dest:TSockAddr):Boolean;overload; 
        function    SendBuf(buf:array of char;buflen:Integer;DestIp:String;DestPort:Word):Boolean;overload; 
 
        function    StartThread:Boolean; 
        procedure   StopThread; 
        end; 
    PProxySock=^TProxySock; 
    TUDPSwitcher=class 
        private 
        FSockets:array of TProxySock; 
        FInternalFlag:array of boolean; 
 
        FOnSend: TSockNotifyEvent; 
        FOnRecv: TSockNotifyEvent; 
        FOnNewSocket: TNotifyEvent; 
{$ifdef SYNC} 
        FSockLock:TMultiReadExclusiveWriteSynchronizer; 
{$endif} 
        FInternalProxyCount: Integer; 
        FExternalProxyCount: Integer; 
        procedure SetOnRecv(const Value: TSockNotifyEvent); 
        procedure SetOnSend(const Value: TSockNotifyEvent); 
        procedure SetOnNewSocket(const Value: TNotifyEvent); 
        function  GetSocketByDirection(index:integer;direction:TSwitchDirection):TProxySock; 
        public 
 
 
        property  OnNewSocket:TNotifyEvent read FOnNewSocket write SetOnNewSocket; 
        property  OnRecv:TSockNotifyEvent read FOnRecv write SetOnRecv; 
        property  OnSend:TSockNotifyEvent read FOnSend write SetOnSend; 
        property  InternalProxyCount:Integer read FInternalProxyCount; 
        property  ExternalProxyCount:Integer read FExternalProxyCount; 
 
        function  RegisterSocket(sock:TProxySock;Direction:TSwitchDirection;InternalFlag:Boolean=false):Integer; 
        procedure UnregisterSocket(sock:TProxySock); 
 
        function  FindSocket(addr:TSockAddr):TProxySock;overload; 
        function  FindSocket(ip:String;port:WORD):TProxySock;overload; 
 
        function  FindSocketByTag(tag:Integer):TProxySock; 
 
        function  GetInternalProxy(index:Integer):TProxySock; 
        function  GetExternalProxy(index:Integer):TProxySock; 
 
        procedure SwitchPackage(buf:array of char;buflen:Integer;from:TSockAddr;Dest:TSockAddr;hint:TSwitchDirection); 
 
        constructor Create(primary:TProxySock);overload; 
        constructor Create(thisPort:Word;proxyAddr:String;proxyPort:Word);overload; 
        destructor  Destroy;override; 
 
        function  GetPrimarySocket:TProxySock; 
        end; 
implementation 
uses IpHdr; 
{ TProxySock } 
constructor TProxySock.Create(aThisAddr, aProxyAddr: TSockAddr); 
begin 
Init; 
ThisAddr:=aThisAddr; 
ProxyAddr:=aProxyAddr; 
end; 
 
constructor TProxySock.Create(aProxyAddr: TSockAddr); 
begin 
Init; 
ThisAddr.sin_family:=AF_INET; 
ThisAddr.sin_addr.S_addr:=INADDR_ANY; 
ThisAddr.sin_port:=0; 
ProxyAddr:=aProxyAddr; 
CreateSocket; 
end; 
 
constructor TProxySock.Create(ThisPort: WORD; ProxyIp: String; 
  ProxyPort: WORD); 
begin 
Init; 
ThisAddr.sin_family:=AF_INET; 
ThisAddr.sin_addr.S_addr:=INADDR_ANY; 
ThisAddr.sin_port:=htons(ThisPort); 
 
ProxyAddr.sin_family:=AF_INET; 
ProxyAddr.sin_port:=htons(ProxyPort); 
LookupName(proxyIp,ProxyAddr.sin_addr); 
 
CreateSocket; 
end; 
 
constructor TProxySock.Create(ThisPort: WORD; aProxyAddr: TSockAddr); 
begin 
Init; 
ThisAddr.sin_family:=AF_INET; 
ThisAddr.sin_port:=htons(ThisPort); 
ThisAddr.sin_addr.S_addr:=INADDR_ANY; 
 
ProxyAddr:=aProxyAddr; 
 
CreateSocket; 
end; 
 
function TProxySock.CreateSocket: Boolean; 
begin 
FSocket:=socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP); 
if(FSocket<>INVALID_SOCKET)then 
    begin 
    if(bind(FSocket,ThisAddr,SizeOf(ThisAddr))<>SOCKET_ERROR)then 
        begin 
        if(not StartThread)then 
            begin 
            closesocket(FSocket); 
            FSocket:=INVALID_SOCKET; 
            Result:=False; 
            end 
        else Result:=TRUE; 
        end 
    else 
        begin 
        closesocket(FSocket); 
        FSocket:=INVALID_SOCKET; 
        Result:=False; 
        end; 
    end 
else Result:=False; 
end; 
 
destructor TProxySock.Destroy; 
begin 
if(FSocket<>INVALID_SOCKET)then closesocket(FSocket); 
if(Assigned(FReadThread))then FReadThread.Terminate; 
if(FSwitcher<>nil)then FSwitcher.UnregisterSocket(self); 
inherited; 
end; 
 
procedure TProxySock.Init; 
begin 
FReadThread:=nil; 
FSocket:=INVALID_SOCKET; 
FSwitcher:=nil; 
end; 
 
procedure TProxySock.OnRecv(buf: array of char; buflen: Integer; 
  from: TSockAddr); 
var 
drop:Boolean; 
begin 
drop:=False; 
case FDirection of 
    sdSend: 
        begin 
        if(Assigned(FSwitcher) and Assigned(FSwitcher.FOnSend))then 
            FSwitcher.FOnSend(buf,buflen,from,ProxyAddr,drop); 
        end; 
    sdRecv: 
        begin 
        if(Assigned(FSwitcher)and Assigned(FSwitcher.FOnRecv))then 
            FSwitcher.FOnRecv(buf,buflen,from,ProxyAddr,drop); 
        end; 
    end; 
if((not drop) and (FSwitcher<>nil))then 
    begin 
    FSwitcher.SwitchPackage(buf,buflen,from,ProxyAddr,FDirection); 
    end; 
end; 
 
function TProxySock.SendBuf(buf: array of char; buflen: Integer; 
  Dest: TSockAddr): Boolean; 
begin 
if(FSocket<>INVALID_SOCKET)then 
    begin 
    Result:=(WinSock.sendto(FSocket,buf,buflen,0,Dest,SizeOf(Dest))<>SOCKET_ERROR); 
    end 
else Result:=False; 
end; 
 
function TProxySock.SendBuf(buf: array of char; buflen: Integer; 
  DestIp: String; DestPort: Word): Boolean; 
var 
addr:TSockAddr; 
begin 
addr.sin_family:=AF_INET; 
addr.sin_addr.S_addr:=inet_addr(PChar(DestIp)); 
addr.sin_port:=DestPort; 
Result:=SendBuf(buf,buflen,addr); 
end; 
 
function TProxySock.StartThread: Boolean; 
begin 
try 
    FReadThread:=TProxyReadThread.Create(False,self); 
    Result:=True; 
except 
    Result:=False; 
    end; 
end; 
 
procedure TProxySock.StopThread; 
begin 
FReadThread.Terminate; 
end; 
 
{ TUDPSwitcher } 
 
constructor TUDPSwitcher.Create(primary: TProxySock); 
begin 
FOnRecv:=nil; 
FOnSend:=nil; 
{$ifdef SYNC} 
FSockLock:=TMultiReadExclusiveWriteSynchronizer.Create; 
{$endif} 
RegisterSocket(primary,sdSend,true); 
end; 
 
constructor TUDPSwitcher.Create(thisPort: Word; proxyAddr: String; 
  proxyPort: Word); 
var 
s:TProxySock; 
begin 
FOnRecv:=nil; 
FOnSend:=nil; 
{$ifdef SYNC} 
FSockLock:=TMultiReadExclusiveWriteSynchronizer.Create; 
{$endif} 
s:=TProxySock.Create(thisPort,ProxyAddr,ProxyPort); 
RegisterSocket(s,sdSend,true); 
end; 
 
destructor TUDPSwitcher.Destroy; 
var 
i,len:Integer; 
begin 
len:=Length(FSockets); 
for i:=0 to len-1 do 
    begin 
    UnregisterSocket(FSockets[i]); 
    end; 
end; 
 
function TUDPSwitcher.FindSocket(addr: TSockAddr): TProxySock; 
var 
i,len:Integer; 
begin 
Result:=nil; 
{$ifdef SYNC} 
FSockLock.BeginRead; 
{$endif} 
len:=Length(FSockets); 
for i:=0 to len-1 do 
    begin 
    if((FSockets[i].ProxyAddr.sin_addr.S_addr=addr.sin_addr.S_addr) 
        and(FSockets[i].ProxyAddr.sin_port=addr.sin_port) 
        and(FSockets[i].ProxyAddr.sin_family=addr.sin_family))then 
        begin 
        Result:=FSockets[i]; 
        end; 
    end; 
{$ifdef SYNC} 
FSockLock.EndRead; 
{$endif} 
end; 
 
function TUDPSwitcher.FindSocket(ip: String; port: WORD): TProxySock; 
var 
addr:TSockAddr; 
begin 
addr.sin_family:=AF_INET; 
addr.sin_addr.S_addr:=inet_addr(PChar(ip)); 
addr.sin_port:=htons(port); 
Result:=FindSocket(addr); 
end; 
 
function TUDPSwitcher.FindSocketByTag(tag: Integer): TProxySock; 
var 
i,len:Integer; 
begin 
Result:=nil; 
len:=Length(FSockets); 
for i:=0 to len-1 do 
    begin 
    if(FSockets[i].Tag=tag)then 
        begin 
        Result:=FSockets[i]; 
        end; 
    end; 
end; 
 
function TUDPSwitcher.GetExternalProxy(index: Integer): TProxySock; 
begin 
Result:=GetSocketByDirection(index,sdRecv); 
end; 
 
function TUDPSwitcher.GetInternalProxy(index: Integer): TProxySock; 
begin 
Result:=GetSocketByDirection(index,sdSend); 
end; 
 
function TUDPSwitcher.GetPrimarySocket: TProxySock; 
begin 
Result:=FSockets[0]; 
end; 
 
function TUDPSwitcher.GetSocketByDirection(index: integer; 
  direction: TSwitchDirection): TProxySock; 
var 
cnt,i,len:Integer; 
begin 
Result:=nil; 
cnt:=0; 
len:=Length(FSockets); 
for i:=0 to len-1 do 
    begin 
    if(FSockets[i].FDirection=direction)then 
        begin 
        if(cnt=index)then 
            begin 
            Result:=FSockets[i]; 
            Break; 
            end; 
        Inc(cnt); 
        end; 
    end; 
end; 
 
function TUDPSwitcher.RegisterSocket(sock: TProxySock;Direction:TSwitchDirection;InternalFlag:Boolean=false):Integer; 
var 
len,i:Integer; 
begin 
Result:=-1; 
{$ifdef SYNC} 
FSockLock.BeginWrite; 
{$endif} 
sock.FSwitcher:=self; 
sock.FDirection:=Direction; 
len:=Length(FSockets); 
for i:=0 to len-1 do 
    begin 
    if(FSockets[i]=nil)then 
        begin 
        FSockets[i]:=sock; 
        FInternalFlag[i]:=InternalFlag; 
        Result:=i; 
        end; 
    end; 
if(Result=-1)then 
    begin 
    SetLength(FSockets,len+1); 
    SetLength(FInternalFlag,len+1); 
    FSockets[len]:=sock; 
    FInternalFlag[len]:=InternalFlag; 
    Result:=len; 
    end; 
{$ifdef SYNC} 
FSockLock.EndWrite; 
{$endif} 
end; 
 
procedure TUDPSwitcher.SetOnNewSocket(const Value: TNotifyEvent); 
begin 
  FOnNewSocket := Value; 
end; 
 
procedure TUDPSwitcher.SetOnRecv(const Value: TSockNotifyEvent); 
begin 
  FOnRecv := Value; 
end; 
 
procedure TUDPSwitcher.SetOnSend(const Value: TSockNotifyEvent); 
begin 
  FOnSend := Value; 
end; 
 
procedure TUDPSwitcher.SwitchPackage(buf: array of char; buflen: Integer; 
  from, Dest: TSockAddr;hint:TSwitchDirection); 
var 
sock:TProxySock; 
begin 
sock:=FindSocket(from); 
if(sock=nil)then 
    begin 
 
    if(hint=sdSend)then hint:=sdRecv 
    else hint:=sdSend; 
 
    sock:=TProxySock.Create(from); 
    if(sock<>nil)then 
        begin 
        RegisterSocket(sock,hint,true); 
        if(Assigned(OnNewSocket))then  OnNewSocket(sock); 
        end; 
    end; 
sock.SendBuf(buf,buflen,Dest); 
end; 
 
procedure TUDPSwitcher.UnregisterSocket(sock: TProxySock); 
var 
i,len:Integer; 
begin 
{$ifdef SYNC} 
FSockLock.BeginWrite; 
{$endif} 
len:=Length(FSockets); 
sock.FSwitcher:=nil; 
for i:=0 to len-1 do 
    begin 
    if(FSockets[i]=sock)then 
        begin 
        if(FInternalFlag[i])then sock.Destroy; 
        FSockets[i]:=nil; 
        Break; 
        end; 
    end; 
{$ifdef SYNC} 
FSockLock.EndWrite; 
{$endif} 
end; 
 
{ TProxyReadThread } 
 
constructor TProxyReadThread.Create(CreateSuspended: Boolean; 
  ASock: TProxySock); 
begin 
FreeOnTerminate := True; 
FProxySock:=ASock; 
inherited Create(CreateSuspended); 
end; 
 
destructor TProxyReadThread.Destroy; 
begin 
inherited; 
end; 
 
procedure TProxyReadThread.DoNotify; 
begin 
if(Assigned(FProxySock))then 
    FProxySock.OnRecv(FBuffer,FBuflen,FFromAddr); 
end; 
 
procedure TProxyReadThread.DoTerminate; 
begin 
  inherited; 
if(Assigned(FProxySock) 
    and Assigned(FProxySock.FReadThread) 
    and (FProxySock.FReadThread=self))then 
    begin 
    FProxySock.FReadThread:=nil; 
    end; 
end; 
 
procedure TProxyReadThread.Execute; 
var 
fromlen:Integer; 
begin 
while((not Terminated) and Assigned(FProxySock))do 
    begin 
    fromlen:=sizeof(FFromAddr); 
    FBufLen:=recvfrom(FProxySock.FSocket,FBuffer,2048,0,FFromAddr,fromlen); 
    if(FBuflen<>SOCKET_ERROR)then 
        begin 
        Synchronize(DoNotify); 
        end; 
    end; 
end; 
 
end.