Oracle端口映射

来源:互联网 发布:漫画软件推荐知乎 编辑:程序博客网 时间:2024/06/05 03:18

{$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; 

原创粉丝点击