⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 idtunnelmaster.pas

📁 Indy控件的使用源代码
💻 PAS
📖 第 1 页 / 共 2 页
字号:
        break;
      end;

      if user.receiver.NewMessage then begin
        if user.Receiver.CRCFailed then begin
          Thread.Connection.Disconnect;
          break;
        end;

        // Custom data transformation
        try
          DoTransformRead(Thread);
        except
          Thread.Connection.Disconnect;
          Break;
        end;



        // Action
        case user.Receiver.Header.MsgType of
          // transformation of data failed, disconnect the tunnel
          tmError: begin
            try
              Thread.Connection.Disconnect;
              break;
            except
              ;
            end;
          end; // Failure END


          // Data
          tmData: begin
            try
              SetString(s, user.Receiver.Msg, user.Receiver.MsgLen);
              ClientOperation(tmData, user.Receiver.Header.UserId, s);
            except
              ;
            end;
          end;  // Data END

          // Disconnect
          tmDisconnect: begin
            try
              ClientOperation(tmDisconnect, user.Receiver.Header.UserId, '');    {Do not Localize}
            except
              ;
            end;
          end;  // Disconnect END

          // Connect
          tmConnect: begin
            // Connection should be done synchroneusly
            // because more data could arrive before client
            // connects asyncroneusly
            try
              clientThread := MClientThread.Create(self);
              try
                ErrorConnecting := False;
                with clientThread do begin
                  UserId := user.Receiver.Header.UserId;
                  MasterThread := Thread;
                  OutboundClient := TIdTCPClient.Create(nil);
                  sIP := GStack.TInAddrToString(user.Receiver.Header.IpAddr);
                  if fbLockDestinationHost then begin
                    OutboundClient.Host := fsMappedHost;
                    if fbLockDestinationPort then
                      OutboundClient.Port := fiMappedPort
                    else
                      OutboundClient.Port := user.Receiver.Header.Port;
                  end
                  else begin
                    // do we tunnel all connections from the slave to the specified host
                    if sIP = '0.0.0.0' then begin    {Do not Localize}
                      OutboundClient.Host := fsMappedHost;
                      OutboundClient.Port := user.Receiver.Header.Port; //fiMappedPort;
                    end
                    else begin
                      OutboundClient.Host := sIP;
                      OutboundClient.Port := user.Receiver.Header.Port;
                    end;
                  end;
                  OutboundClient.Connect;
                end;
              except
                ErrorConnecting := True;
              end;
              if ErrorConnecting then begin
                clientThread.Destroy;
              end
              else begin
                clientThread.Resume;
              end;
            except
              ;
            end;

          end;  // Connect END

          // Custom data interpretation
          tmCustom: begin
            CustomMsg := '';    {Do not Localize}
            DoInterpretMsg(Thread, CustomMsg);
            if Length(CustomMsg) > 0 then begin
              Header.MsgType := tmCustom;
              Header.UserId := 0;
              SendMsg(Thread, Header, CustomMsg);
            end;
          end;

        end; // case

        // Shift of data
        user.Receiver.ShiftData;

      end
      else
        break;  // break the loop

    end; // end while
  end;  // readable
end;


procedure TIdTunnelMaster.DoTransformRead(Thread: TIdPeerThread);
begin

  if Assigned(fOnTransformRead) then
    fOnTransformRead(Thread);

end;

procedure TIdTunnelMaster.DoTransformSend(Thread: TIdPeerThread; var Header: TIdHeader; var CustomMsg: String);
begin

  if Assigned(fOnTransformSend) then
    fOnTransformSend(Thread, Header, CustomMsg);

end;

procedure TIdTunnelMaster.DoInterpretMsg(Thread: TIdPeerThread; var CustomMsg: String);
begin

  if Assigned(fOnInterpretMsg) then
    fOnInterpretMsg(Thread, CustomMsg);

end;


// Disconnect all services owned by tunnel thread
procedure TIdTunnelMaster.DisconnectAllSubThreads(TunnelThread: TIdPeerThread);
var
  Thread: MClientThread;
  i: integer;
  listTemp: TList;
begin

  OnlyOneThread.Enter; // for now it is done with locking
  listTemp := Clients.LockList;
  try
    for i := 0 to listTemp.count - 1 do begin
      if Assigned(listTemp[i]) then begin
        Thread := MClientThread(listTemp[i]);
        if Thread.MasterThread = TunnelThread then begin
          Thread.DisconnectedOnRequest := True;
          Thread.OutboundClient.Disconnect;
        end;
      end;
    end;
  finally
    Clients.UnlockList;
    OnlyOneThread.Leave;
  end;

end;


procedure TIdTunnelMaster.SendMsg(MasterThread: TIdPeerThread; var Header: TIdHeader; s: String);
var
  user: TSlaveData;
  tmpString: String;
begin

  if Assigned(MasterThread.Data) then begin


  TSlaveData(MasterThread.Data).Locker.Enter;
  try
    user := TSlaveData(MasterThread.Data);
    try
      // Custom data transformation before send
      tmpString := s;
      try
        DoTransformSend(MasterThread, Header, tmpString);
      except
        on E: Exception do begin
          raise EIdTunnelTransformErrorBeforeSend.Create(RSTunnelTransformErrorBS);
        end;
      end;
      if Header.MsgType = tmError then begin // error ocured in transformation
        raise EIdTunnelTransformErrorBeforeSend.Create(RSTunnelTransformErrorBS);
      end;

      user.Sender.PrepareMsg(Header, PChar(@tmpString[1]), Length(tmpString));
      MasterThread.Connection.Write(user.Sender.Msg);
    except
      raise;
    end;
  finally
    TSlaveData(MasterThread.Data).Locker.Leave;
  end;


  end;
end;

function TIdTunnelMaster.GetClientThread(UserID: Integer): MClientThread;
var
  Thread: MClientThread;
  i: integer;
begin

  Result := nil;
  with Clients.LockList do
  try
    for i := 0 to Count-1 do begin
      try
        if Assigned(Items[i]) then begin
          Thread := MClientThread(Items[i]);
          if Thread.UserId = UserID then begin
            Result := Thread;
            break;
          end;
        end;
      except
        Result := nil;
      end;
    end;
  finally
    Clients.UnlockList;
  end;
end;


procedure TIdTunnelMaster.DisconectAllUsers;
begin
  TerminateAllThreads;
end;

procedure TIdTunnelMaster.ClientOperation(Operation: Integer; UserId: Integer; s: String);
var
  Thread: MClientThread;
begin
  Thread := GetClientThread(UserID);
  if Assigned(Thread) then begin
    Thread.Locker.Enter;
    try
      if not Thread.SelfDisconnected then begin
        case Operation of
          tmData: begin
            try
              Thread.OutboundClient.CheckForDisconnect;
              if Thread.OutboundClient.Connected then
                Thread.OutboundClient.Write(s);
            except
              try
                Thread.OutboundClient.Disconnect;
              except
                ;
              end;
            end;
          end;

          tmDisconnect: begin
            Thread.DisconnectedOnRequest := True;
            try
              Thread.OutboundClient.Disconnect;
            except
              ;
            end;
          end;
        end;
      end;
    finally
      Thread.Locker.Leave;
    end;
  end; // Assigned

end;


/////////////////////////////////////////////////////////////////
//
//  MClientThread thread, talks to the service
//
/////////////////////////////////////////////////////////////////
constructor MClientThread.Create(AMaster: TIdTunnelMaster);
begin
  MasterParent := AMaster;
  FreeOnTerminate := True;
  DisconnectedOnRequest := False;
  SelfDisconnected := False;
  Locker := TCriticalSection.Create;
  MasterParent.Clients.Add(self);
  AMaster.SetStatistics(NumberOfServicesType, Integer(soIncrease));

  inherited Create(True);
end;

destructor MClientThread.Destroy;
var
  Header: TIdHeader;
begin
  MasterParent.SetStatistics(NumberOfServicesType, Integer(soDecrease));

  MasterParent.Clients.Remove(self);
  try
    if not DisconnectedOnRequest then begin
     // service disconnected the thread
     try
       Header.MsgType := tmDisconnect;
       Header.UserId := UserId;
       MasterParent.SendMsg(MasterThread, Header, RSTunnelDisconnectMsg);
     except 
     end;
    end;

    if OutboundClient.Connected then
    begin
      OutboundClient.Disconnect;
    end;
  except
  end;

  MasterThread := nil;

  try
    OutboundClient.Free;
  except
  end;

  Locker.Free;
  Terminate; // dodano

  inherited Destroy;
end;

// thread which talks to the service
procedure MClientThread.Execute;
var
  s: String;
  Header: TIdHeader;
begin
  try
    while not Terminated do begin
      if OutboundClient.Connected then begin
        if OutboundClient.IOHandler.Readable(IdTimeoutInfinite) then  begin
          s := OutboundClient.CurrentReadBuffer;
          try
            Header.MsgType := tmData;
            Header.UserId := UserId;
            MasterParent.SendMsg(MasterThread, Header, s);
          except
            Terminate;
            break;
          end;
        end;
      end
      else begin
        Terminate;
        break;
      end;

    end;
  except
    ;
  end;

  Locker.Enter;
  try
    SelfDisconnected := True;
  finally
    Locker.Leave;
  end;
end;

end.

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -