从这里到end. 为一个单元,可以copy到delphi中保存
{-----------------------------------------------------------------------------
Unit Name: IdMappedOra
Author: LCK
-----------------------------------------------------------------------------}
//如果你想用indy10版的就去掉下面 点点
{$DEFINE ID10}
unit IdMappedORACLE;
interface
uses
Classes,
{$IFDEF ID10}
IdContext,IdStackConsts,
IdCustomTCPServer, IdObjs, IdMappedPortTCP, IdThread,
IdGlobal, IdStack, IdSys, IdTCPConnection, IdTCPServer, IdYarn,
{$ELSE}
IdGlobal, IdStack,IdTCPServer, IdMappedPortTCP, IdAssignedNumbers, IdThread,
IdTCPConnection,
{$ENDIF}
SysUtils;
type
{$IFDEF ID10}
{$ELSE}
TIdContext = TIdPeerThread;
TIdMappedPortContext = TIdMappedPortThread;
{$ENDIF}
//1521连接处理
TIdMappedOraThread = class({$IFDEF ID10}TIdMappedPortContext{$ELSE}TIdMappedPortThread{$ENDIF})
protected
//Ora包命令
FOraCommand: string;
//Ora包数据
FOraParams: string;
FBackHost, FHost, FoutboundHost: string; //local,remote(mapped)
FBackPort, FPort, FoutboundPort: Integer;
function ProcessOraCommand: Boolean; virtual;
public
{$IFDEF ID10}
constructor Create(
AConnection: TIdTCPConnection;
AYarn: TIdYarn;
AList: TIdThreadList = nil
); override;
{$ELSE}
constructor Create(ACreateSuspended: Boolean = True); override;
{$ENDIF}
property OraCommand: string read FOraCommand write FOraCommand;
property OraParams: string read FOraParams write FOraParams;
property Host: string read FHost write FHost;
property OutboundHost: string read FOutboundHost write FOutboundHost;
property Port: Integer read FPort write FPort;
property OutboundPort: Integer read FOutboundPort write FOutboundPort;
end; //TIdMappedOraThread
TIdMappedOra = class(TIdMappedPortTCP)
protected
FBackMapped : TIdMappedPortTCP;
{$IFDEF ID10}
procedure BackConnect(AThread: TIdContext);
{$ELSE}
procedure BackConnect(AThread: TIdMappedPortThread);
{$ENDIF}
procedure SetActive(AValue: Boolean); override;
function DoExecute(AThread: TIdContext): boolean; override;
public
constructor Create(AOwner: TComponent); reintroduce; overload;
published
property DefaultPort default 1521; //向外公布的端口
property MappedPort default 1521; //映射的oraTNS端口
end; //TIdMappedOra
//=============================================================================
implementation
uses
IdIOHandlerSocket, IdException, IdResourceStrings,
IdTcpClient, IdSimpleServer;
var
//backPort作为队列存贮TNS分配的数据连接端口
backPort : TThreadList;
type
//Ora包word高低位与pascal是相反的!!
psWord = ^tsWord;
tsWord = packed record
b1 : byte;
b2 : byte;
end;
{ TIdMappedOra }
//连接了映射的数据端口
procedure TIdMappedOra.BackConnect;
var
i : integer;
f : TList;
tcpc : TIdTcpClient;
begin
{$IFDEF ID10}
tcpc := TIDTCPClient(TIdMappedPortContext(AThread).OutboundClient);
{$ELSE}
tcpc := TIDTCPClient(AThread.OutboundClient);
{$ENDIF}
//内部再去连真正的ora数据端口
tcpc.Host := self.MappedHost;
tcpc.Port := 0;
f := backPort.LockList;
try
if f.Count = 0 then exit;
i := integer(f.First);
tcpc.Port := i;
f.Delete(0);
finally
backPort.UnlockList;
end;
end;
constructor TIdMappedOra.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
backPort := TThreadList.Create;
backPort.Duplicates := dupIgnore;
DefaultPort := 1521;
MappedPort := 1521;
FBackMapped := TIdMappedPortTCP.Create(nil);
//我们默认数据映射端口为DefaultPort+1
FBackMapped.DefaultPort := 1522;
FBackMapped.OnConnect := BackConnect;
{$IFDEF ID10}
ContextClass := TIdMappedOraThread;
{$ELSE}
ThreadClass := TIdMappedOraThread;
{$ENDIF}
end; //TIdMappedOra.Create
function TIdMappedOra.DoExecute(AThread: TIdContext): boolean;
var
{$IFDEF ID10}
LConnectionHandle: TIdStackSocketHandle;
LOutBoundHandle: TIdStackSocketHandle;
tmpBytes : TIdBytes;
{$ELSE}
LConnectionHandle: TObject;
LOutBoundHandle: TObject;
{$ENDIF}
wSize2, wSize,sSize, tmpPos : Word;
begin
Result := TRUE;
try
LConnectionHandle := {$IFDEF ID10}{$ELSE}TObject{$ENDIF}(//local client
(AThread.Connection.IOHandler as TIdIOHandlerSocket).Binding.Handle);
LOutBoundHandle := {$IFDEF ID10}{$ELSE}TObject{$ENDIF}(//remote (mapped) server
(TIdMappedOraThread(AThread).FOutboundClient.IOHandler as
TIdIOHandlerSocket).Binding.Handle);
with TIdMappedOraThread(AThread).FReadList do
begin
Clear;
Add(LConnectionHandle);
Add(LOutBoundHandle);
//Indy10改动了read/write/select方式,就是因为indy10是iocp模式啦!
{$IFDEF ID10}
if TIdMappedOraThread(AThread).FReadList.SelectRead(IdTimeoutInfinite) then
{$ELSE}
if GStack.WSSelect(TIdMappedOraThread(AThread).FReadList, nil, nil,
IdTimeoutInfinite) > 0 then
{$ENDIF}
begin
//TODO: Make a select list that also has a function to check of handles
if
{$IFDEF ID10}Contains(LOutBoundHandle)
{$ELSE}IndexOf(LOutBoundHandle) > -1
{$ENDIF} then
begin
//我们开始解包吃馅了
repeat
TIdMappedOraThread(AThread).FOutboundClient.
{$IFDEF ID10}IOHandler.ReadBytes(tmpBytes,2,false);
wSize2 := PWord(@tmpBytes[0])^;
{$ELSE}ReadBuffer(wSize2, 2);{$ENDIF}
psWord(@wSize).b1 := psWord(@wSize2).b2;
psWord(@wSize).b2 := psWord(@wSize2).b1;
//取数据啦,上面是读长度哟
SetLength(TIdMappedOraThread(AThread).FNetData, 2);
System.Move(wSize2, TIdMappedOraThread(AThread).FNetData[1], 2);
TIdMappedOraThread(AThread).FNetData :=
TIdMappedOraThread(AThread).FNetData +
{$IFDEF ID10}
TIdMappedOraThread(AThread).FOutboundClient.IOHandler.ReadString(wSize-2);
{$ELSE}
TIdMappedOraThread(AThread).FOutboundClient.ReadString(wSize-2);
{$ENDIF}
if Length(TIdMappedOraThread(AThread).FNetData) > 0 then
begin
TIdMappedOraThread(AThread).FOraParams := TIdMappedOraThread(AThread).FNetData;
TIdMappedOraThread(AThread).FOraCommand := #0;
if Length(TIdMappedOraThread(AThread).FOraParams) >= 5 then
TIdMappedOraThread(AThread).FOraCommand := TIdMappedOraThread(AThread).FOraParams[5]; {Do not Localize}
//你可以在OutboundClient事件中处理自己的事情
DoOutboundClientData(TIdMappedOraThread(AThread));
//开始处理了
if not TIdMappedOraThread(AThread).ProcessOraCommand then
AThread.Connection.{$IFDEF ID10}IOHandler.{$ENDIF}Write(TIdMappedOraThread(AThread).FNetData);
end; //if
until
{$IFDEF ID10}
TIdMappedOraThread(AThread).FOutboundClient.IOHandler.InputBufferIsEmpty;
{$ELSE}
TIdMappedOraThread(AThread).FOutboundClient.InputBuffer.Size <= 0;
{$ENDIF}
end; //if >-1 chance for server (passive side)
//Ora Client:
if
{$IFDEF ID10}Contains(LConnectionHandle)
{$ELSE}IndexOf(LConnectionHandle) > -1
{$ENDIF} then
begin
repeat
AThread.Connection.
{$IFDEF ID10}IOHandler.ReadBytes(tmpBytes,2,false);
wSize2 := PWord(@tmpBytes[0])^;
{$ELSE}ReadBuffer(wSize2, 2);{$ENDIF}
psWord(@wSize).b1 := psWord(@wSize2).b2;
psWord(@wSize).b2 := psWord(@wSize2).b1;
SetLength(TIdMappedOraThread(AThread).FNetData, 2);
System.Move(wSize2, TIdMappedOraThread(AThread).FNetData[1], 2);
TIdMappedOraThread(AThread).FNetData :=
TIdMappedOraThread(AThread).FNetData +
AThread.Connection{$IFDEF ID10}.IOHandler{$ENDIF}.ReadString(wSize-2);
if Length(TIdMappedOraThread(AThread).FNetData) > 0 then
begin
//1#命令是我们需要改的包
if TIdMappedOraThread(AThread).FNetData[5] = #1 then
begin
wSize := Pos('HOST=', TIdMappedOraThread(AThread).FNetData);
TIdMappedOraThread(AThread).FHost := '';
if wSize > 0 then
begin
inc(wSize,5);
tmpPos := 0;
sSize := Length(TIdMappedOraThread(AThread).FNetData);
while (tmpPos + wSize) <= sSize do
begin
if TIdMappedOraThread(AThread).FNetData[wSize+tmpPos] = ')' then Break;
inc(tmpPos);
end;
TIdMappedOraThread(AThread).FBackPort := self.FBackMapped.DefaultPort;
TIdMappedOraThread(AThread).FBackHost := copy(TIdMappedOraThread(AThread).FNetData,
wSize, tmpPos);
end;
end;
DoLocalClientData(TIdMappedPortContext(AThread)); //bServer
TIdMappedOraThread(AThread).FOutboundClient{$IFDEF ID10}.IOHandler{$ENDIF}.Write(TIdMappedOraThread(AThread).FNetData);
// TIdMappedOraThread(AThread).ProcessDataCommand;
end;
until {$IFDEF ID10}
AThread.Connection.IOHandler.InputBufferIsEmpty
{$ELSE}AThread.Connection.InputBuffer.Size <= 0;{$ENDIF}
end; //if >-1
end; //if select
end; //with
finally
if not TIdMappedOraThread(AThread).FOutboundClient.Connected then
begin
DoOutboundDisconnect(TIdMappedPortContext(AThread));
end; //if
end; //tryf
end; //TIdMappedPortTCP.DoExecute
procedure TIdMappedOra.SetActive(AValue: Boolean);
begin
inherited;
if Active and (not FBackMapped.Active) then
FBackMapped.DefaultPort := self.DefaultPort+1;
try
FBackMapped.Active := Active;
except
raise;
end;
end;
{ TIdMappedOraThread }
constructor TIdMappedOraThread.Create;
begin
{$IFDEF ID10}
inherited Create(AConnection, AYarn, AList);
{$ELSE}
inherited Create(ACreateSuspended);
{$ENDIF}
FHost := ''; {Do not Localize}
FoutboundHost := ''; {Do not Localize}
FPort := 0; //system choice
FoutboundPort := 0;
end; //TIdMappedOraThread.Create
function TIdMappedOraThread.ProcessOraCommand: Boolean;
procedure ParsePasv;
var
LParm, tmp: string;
wSize,wSize2, tmpPos, sSize : Word;
ppp : Pchar;
begin
//1.setup local
// Host := TIdIOHandlerSocket(Connection.IOHandler).Binding.IP;
// CreateDataChannelThread;
// DataChannelThread.FConnection := TIdSimpleServer.Create(nil);
// with TIdSimpleServer(DataChannelThread.FConnection) do
begin
// BoundIP := TIdIOHandlerSocket(Connection.IOHandler).Binding.IP;
// BoundPort := Self.Connection.Server.DefaultPort+1;
// BeginListen;
// Self.Host := Binding.IP;
// Self.Port := Binding.Port;
// self.
// self.FBackPort := self.//Binding.Port;
wSize := Pos('HOST=', FOraParams);
if wSize > 0 then
begin
inc(wSize,5);
tmpPos := 0;
sSize := Length(FOraParams);
while (tmpPos + wSize) <= sSize do
begin
if FOraParams[wSize+tmpPos] = ')' then Break;
inc(tmpPos);
end;
FOutboundHost := copy(FOraParams, wSize, tmpPos);
LParm := copy(FOraParams,1, wSize-1)+self.FBackHost;
end;
wSize := Pos('PORT=', FOraParams);
if wSize > 0 then
begin
inc(wSize,5);
tmpPos := 0;
sSize := Length(FOraParams);
while (tmpPos + wSize) <= sSize do
begin
if FOraParams[wSize+tmpPos] = ')' then Break;
inc(tmpPos);
end;
self.FOutboundPort := StrToInt(copy(FOraParams, wSize, tmpPos));
backPort.Add(Pointer(self.FOutboundPort));
tmp := ')(PORT='+inttostr(self.FBackPort);
AppendStr(tmp, copy(FOraParams, wSize+tmpPos, sSize-wSize+tmpPos+1));
AppendStr(LParm, tmp);
end;
//改了数据还得改长度
wSize := Length(LParm);
ppp := @LParm[1];
psWord(@wSize2).b2 := psWord(@wSize).b1;
psWord(@wSize2).b1 := psWord(@wSize).b2;
Move(wSize2, ppp^, 2);
Inc(ppp, 8);
move(ppp^, wSize2, 2);
wSize := wSize-10;
psWord(@wSize2).b2 := psWord(@wSize).b1;
psWord(@wSize2).b1 := psWord(@wSize).b2;
Move(wSize2, ppp^, 2);
end;
//3. send ack to client
Connection{$IFDEF ID10}.IOHandler{$ENDIF}.Write(LParm);
// DataChannelThread.Start;
end;
begin //===ProcessOraCommand
Result := FALSE; //comamnd NOT processed
if FOraCommand = #5 then {Do not Localize}
begin
ParsePasv;
Result := TRUE;
end;
end; //ProcessoraCommand
end.
//例子如下:
procedure TForm1.BitBtn1Click(Sender: TObject);
begin
//对外公开的端口
FMapSer.DefaultPort := strtointdef(edit3.Text,22222);
//要映射的端口和地址
FMapSer.MappedPort := strtointdef(edit2.Text,1521);
FMapSer.MappedHost := edit1.Text;
FMapSer.Active := True;
end;
procedure TForm1.BitBtn2Click(Sender: TObject);
begin
//关闭事件
if FMapSer.Active then
begin
FMapSer.Active := False;
end;
Close;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
//建立
FMapSer := TIdMappedOra.Create(self);
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
//FREE
FMapSer.Free;
end;