clientthread.pas

来自「著名的SecureBlackBox控件完整源码」· PAS 代码 · 共 586 行 · 第 1/2 页

PAS
586
字号
  if (AThread.Connection <> nil) and (AThread.Connection.Socket <> nil) and
    (AThread.Connection.Socket.Binding <> nil) then
  begin
    Conn.FRemoteHost := AThread.Connection.Socket.Binding.PeerIP;
    Conn.FRemotePort := AThread.Connection.Socket.Binding.PeerPort;
  end;
  while (not AThread.Terminated) and
    not ((Conn.FInState = icsClosed) and (Conn.FOutState = ocsClosed)) do
  begin
    // processing socket endpoint
    if (Conn.FInState = icsActive) then
    begin
      if AThread.Connection.Connected then
      begin
        try
          AThread.Connection.CheckForGracefulDisconnect();
          AThread.Connection.CheckForDisconnect();
          // reading data from socket connection
          if (AThread.Connection.InputBuffer.Size > 0) then
          begin
            //S := AThread.Connection.CurrentReadBuffer;
            S := AThread.Connection.InputBuffer.Extract(AThread.Connection.InputBuffer.Size);
            if Length(S) > 0 then
              Conn.WriteToChannelBuffer(@S[1], Length(S));
          end;
          // writing cached data to socket connection
          repeat
            Read := Conn.ReadFromSocketBuffer(@Buf[0], Length(Buf));
            if Read > 0 then
              AThread.Connection.WriteBuffer(Buf[0], Read);
          until Read = 0;
        except
          on E : Exception do
          begin
            Log(E.Message, false);
            Conn.FInState := icsClosing;
            if (AThread.Connection <> nil) and
              (AThread.Connection.Connected) and (AThread.Connection.Socket <> nil) and
              (AThread.Connection.Socket.Binding <> nil) then
              AThread.Connection.Disconnect;
          end;
        end;
      end
      else
      begin
        Conn.FInState := icsClosed;
      end;
    end;

    // processing channel endpoint
    if Conn.FOutState = ocsActive then
    begin
      repeat
        Read := Conn.ReadFromChannelBuffer(@Buf[0], Length(Buf));
        if Read > 0 then
        begin
          FCS.Acquire;
          try
            Conn.FChannel.SendData(@Buf[0], Read);
          finally
            FCS.Release;
          end;
          Inc(Conn.FSent, Read);
        end;
      until Read = 0;
    end;

    // checking connection states
    if (Conn.FInState = icsActive) and (Conn.FOutState in [ocsClosed, ocsClosing]) then
    begin
      Conn.FInState := icsClosing;
      Conn.FThread.Connection.Disconnect;
    end
    else if (Conn.FOutState = ocsActive) and (Conn.FInState in [icsClosing, icsClosed]) then
    begin
      Conn.FOutState := ocsClosing;
      FCS.Acquire;
      try
        Conn.FChannel.Close(true);
      finally
        FCS.Release;
      end;
    end
    else if (Conn.FInState = icsClosing) and (not AThread.Connection.Connected) then
    begin
      Conn.FInState := icsClosed;
    end;

    if not FNoGUI then
    begin
      FGuiCS.Acquire;
      try
        DoConnectionChange(Conn);
      finally
        FGuiCS.Release;
      end;
    end;
    Sleep(50);
  end;
  // clearing the 'Data' property due to a bug in Indy 9 implementation
  // (the FreeAndNil is called for object referenced by Data property)
  if not FNoGUI then
  begin
    FGuiCS.Acquire;
    try
      DoConnectionRemove(Conn);
    finally
      FGuiCS.Release;
    end;
  end;
  TConnection(AThread.Data).Free;
  AThread.Data := nil;
end;             

procedure TClientThread.TCPServerThreadTerminate(Sender: TObject);
begin
end;

procedure TClientThread.Execute;
begin
  try
    FError := false;
    // opening listening socket
    FTCPServer.Active := true;
    // establishing TCP connection
    FTCPClient.Connect();
    // opening SSH client
    FSSHClient.Open;
    // running client loop
    while (not Terminated) and (not FError) and (FTCPClient.Connected) do
    begin
      try
        while (FTCPClient.Socket <> nil) and (FTCPClient.Socket.Readable()) do
        begin
          FCS.Acquire;
          try
            FSSHClient.DataAvailable;
          finally
            FCS.Release;
          end;
        end;
        Sleep(50);
      except
        Break;
      end;
    end;
    // closing sockets
    if FTCPClient.Connected then
      FTCPClient.Disconnect;
    if FTCPServer.Active then
      FTCPServer.Active := false;
  except
    on E : Exception do
      Log('Error: ' + E.Message, true);
  end;
end;

procedure TClientThread.Log(const S : string; Error : boolean);
begin
  if not FNoGUI then
  begin
    FGuiCS.Acquire;
    try
      FLogString := S;
      FLogError := Error;
      Synchronize(TriggerLog);
    finally
      FGuiCS.Release;
    end;
  end;
end;

procedure TClientThread.DoConnectionAdd(Conn : TConnection);
begin
  FConn := Conn;
  Synchronize(TriggerConnectionAdd);
end;

procedure TClientThread.DoConnectionRemove(Conn : TConnection);
begin
  FConn := Conn;
  Synchronize(TriggerConnectionRemove);
end;

procedure TClientThread.DoConnectionChange(Conn : TConnection);
begin
  FConn := Conn;
  Synchronize(TriggerConnectionChange);
end;

procedure TClientThread.TriggerLog;
begin
  if Assigned(FOnLog) then
    FOnLog(Self, FLogString, FLogError);
end;

procedure TClientThread.TriggerConnectionChange;
begin
  if Assigned(FOnChange) then
    FOnChange(Self, FConn);
end;

procedure TClientThread.TriggerConnectionAdd;
begin
  if Assigned(FOnConnectionAdd) then
    FOnConnectionAdd(Self, FConn);
end;

procedure TClientThread.TriggerConnectionRemove;
begin
  if Assigned(FOnConnectionRemove) then
    FOnConnectionRemove(Self, FConn);
end;

////////////////////////////////////////////////////////////////////////////////
// TConnection class

constructor TConnection.Create;
begin
  inherited;
  FChannel := nil;
  FThread := nil;
  SetLength(FChannelBuffer, 0);
  SetLength(FSocketBuffer, 0);
  FSharedResource := TElSharedResource.Create;
  FInState := icsActive;
  FOutState := ocsEstablishing;
  FSent := 0;
  FReceived := 0;
end;

destructor TConnection.Destroy;
begin
  FreeAndNil(FSharedResource);
  inherited;
end;

function TConnection.ReadFromSocketBuffer(Buffer: pointer; MaxSize: integer): integer;
begin
  FSharedResource.WaitToRead;
  try
    Result := Min(MaxSize, Length(FSocketBuffer));
    Move(FSocketBuffer[0], Buffer^, Result);
    Move(FSocketBuffer[Result], FSocketBuffer[0], Length(FSocketBuffer) - Result);
    SetLength(FSocketBuffer, Length(FSocketBuffer) - Result);
  finally
    FSharedResource.Done;
  end;
end;

function TConnection.ReadFromChannelBuffer(Buffer: pointer; MaxSize: integer): integer;
begin
  FSharedResource.WaitToRead;
  try
    Result := Min(MaxSize, Length(FChannelBuffer));
    Move(FChannelBuffer[0], Buffer^, Result);
    Move(FChannelBuffer[Result], FChannelBuffer[0], Length(FChannelBuffer) - Result);
    SetLength(FChannelBuffer, Length(FChannelBuffer) - Result);
  finally
    FSharedResource.Done;
  end;
end;

procedure TConnection.WriteToSocketBuffer(Buffer: pointer; Size: integer);
var
  OldLen : integer;
begin
  FSharedResource.WaitToWrite;
  try
    OldLen := Length(FSocketBuffer);
    SetLength(FSocketBuffer, OldLen + Size);
    Move(Buffer^, FSocketBuffer[OldLen], Size);
  finally
    FSharedResource.Done;
  end;
end;

procedure TConnection.WriteToChannelBuffer(Buffer: pointer; Size: integer);
var
  OldLen : integer;
begin
  FSharedResource.WaitToWrite;
  try
    OldLen := Length(FChannelBuffer);
    SetLength(FChannelBuffer, OldLen + Size);
    Move(Buffer^, FChannelBuffer[OldLen], Size);
  finally
    FSharedResource.Done;
  end;
end;

end.

⌨️ 快捷键说明

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