Question

I have one external program which doesn't support proxy to access internet and but I need proxy.

As a solution, I've written one simple Delphi Application using Indy 10.6.0.5040 and its TIdMappedPortTCP component. How it works simply, external application connects to IdMappedPortTCP locally and IdMappedPortTCP connects to real server using my proxy settings.

To do my proxy setting, I handled OnConnect event of IdMappedPortTCP like below:

procedure TForm1.IdMappedPortTCP1Connect(AContext: TIdContext);
var
  io: TIdIOHandlerStack;
  proxy: TIdConnectThroughHttpProxy;

begin
  if Assigned(TIdMappedPortContext(AContext).OutboundClient) then
   begin
    io := TIdIOHandlerStack.Create(TIdMappedPortContext(AContext).OutboundClient);

    proxy := TIdConnectThroughHttpProxy.Create(io);

    proxy.Enabled := False;
    proxy.Host := FSettings.ProxyAddress;
    proxy.Port := FSettings.ProxyPort;
    proxy.Username := FSettings.ProxyUserName;
    proxy.Password := FSettings.ProxyPassword;
    If (proxy.Username <> '') or (proxy.Password <> '') then proxy.AuthorizationRequired(True);
    proxy.Enabled := True;

    io.DefaultPort := FSettings.DestinationPort[0];
    io.Port := FSettings.DestinationPort[0];
    io.Destination := FSettings.DestinationHostAddress[0];
    io.Host := FSettings.DestinationHostAddress[0];
    io.TransparentProxy := proxy;
    io.OnStatus := StackStatus;

    TIdMappedPortContext(AContext).OutboundClient.IOHandler := io;
   end;

  Log(Format('Listener connected at %s:%d', [TIdMappedPortContext(AContext).Server.MappedHost, TIdMappedPortContext(AContext).Server.MappedPort]));
end;

{ TIdConnectThroughHttpProxyHelper }

procedure TIdConnectThroughHttpProxyHelper.AuthorizationRequired(const val: boolean);
begin
  Self.FAuthorizationRequired := val;
end;

procedure TForm1.Log(const s: string);
begin
  Memo1.Lines.Add(Format('(%s)  %s', [FormatDateTime('hh:nn:ss:zzz', Now), s]));
end;

procedure TForm1.IdMappedPortTCP1Disconnect(AContext: TIdContext);
begin
//  Log(Format('Listener disconnected at %s:%d', [TIdMappedPortContext(AContext).Server.MappedHost, TIdMappedPortContext(AContext).Server.MappedPort]));
end;

procedure TForm1.IdMappedPortTCP1Exception(AContext: TIdContext;
  AException: Exception);
begin
  Log(Format('Exception: %s (%s:%d)', [AException.Message,TIdMappedPortContext(AContext).Server.MappedHost, TIdMappedPortContext(AContext).Server.MappedPort]));
end;

procedure TForm1.IdMappedPortTCP1ListenException(AThread: TIdListenerThread;
  AException: Exception);
begin
  Log(Format('Listener Exception: %s', [AException.Message]));
end;

procedure TForm1.IdMappedPortTCP1OutboundConnect(AContext: TIdContext);
begin
  Log('MappedPort Destination connected.');
end;

procedure TForm1.IdMappedPortTCP1OutboundDisconnect(AContext: TIdContext);
begin
  Log('MappedPort Destination disconnected.');
end;

procedure TForm1.StackStatus(ASender: TObject;
  const AStatus: TIdStatus; const AStatusText: string);
begin
  Log(Format('Stack Status: %s', [AStatusText]));
end;

I have many active connections and all work flawlessly. My problem is that, if I try to deactivate IdMappedPortTCP using "IdMappedPortTCP.Active := false;" while there are active traffics, connections, it hangs there and I had to terminate delphi application using task manager.

Is there anything that I need to do manually before setting Active to false?

Thanks.

Was it helpful?

Solution

Indy servers are multi-threaded. Their events (like OnConnect, OnDisconnect, OnExecute, OnException, and OnListenException) are triggered in the context of worker threads, not the context of the main UI thread. As such, you must sync with the main thread, such as with the TThread.Synchronize() or TThread.Queue() methods, or Indy's TIdSync or TIdNotify classes, in order to access UI components safely.

If the main thread is busy deactivating the server, it cannot process sync requests, so an asynchronous approach (TThread.Queue() or TIdNotify) is preferred over a synchronous one (TThread.Synchronize() or TIdSync) to avoid a deadlock. Alternatively, deactivate the server in a worker thread so the main thread is free to process sync requests.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top