These are chat archives for IndySockets/Indy

28th
Jun 2017
elekgeek
@elekgeek
Jun 28 2017 11:19 UTC

What is the correct way of shutting IdTCPServer down while it has clients connected to it? If I use this code:

IdTCPServer1.Active := False;

the application simply hangs.

Matthijs ter Woord
@mterwoord
Jun 28 2017 11:24 UTC
you mean you want to force disconnect all existing connections?
elekgeek
@elekgeek
Jun 28 2017 11:34 UTC
yes
I am wondering why IdTCPServer1.Active := False; is not allowing me to kill all existing connections
Kudzu
@czhower
Jun 28 2017 13:00 UTC
because you likely have code in them preventing the threads from terminating properly.
Walter Prins
@ByteJuggler
Jun 28 2017 13:06 UTC
@rlebeau I know redirects are not part of authentication(!) -- However I'm describing what appears to be happening. The bottom line remains: The same NTLM proxy with the same request (with a 302 thrown in) works via browser and does not with Indy. This seems to imply Indy somehow being improperly set up (where? how?), or at fault. But both work if I manually avoid the 302 redirect. I'll debug some more, though for the time being I've just changed the URL to avoid the problem. Thanks for your comments.
elekgeek
@elekgeek
Jun 28 2017 13:09 UTC
What am I supposed to do then?
Kudzu
@czhower
Jun 28 2017 13:15 UTC
You need to trace your code and find out where its getting stuck. Indy code will not get stuck on its own during thread shut down.
elekgeek
@elekgeek
Jun 28 2017 13:38 UTC
OnExecute
try
  with AContext.Connection.IOHandler do
  begin
    CheckForDataOnSource(10);
    if not InputBufferIsEmpty then
    begin
      RxBufStr := InputBuffer.ExtractToString(-1, IndyTextEncoding_UTF8);
      Log(RxBufStr);
      AContext.Binding.SendTo(AContext.Binding.PeerIP, 7, RxBufStr, Id_IPv4);
IdBuffer.Extract()
    end;
  end;
finally
end;
So, why would it hang when its asked to terminate its own threads... this is silly...
Why would I even be responsible to terminate internal socket connections threads...
Remy Lebeau
@rlebeau
Jun 28 2017 16:04 UTC
@elekgeek why are you using code like this? This is not a good use of TIdBuffer.ExtractString(), especially with a text encoding involved. You are reading arbitrary bytes and assuming they constitute a complete sequence of characters, which is not guaranteed, so the bytes may not decode to a string properly. And, you shouldn't be calling Binding.SendTo() directly at all (and besides, using sendto() on a TCP/IP socket is meaningless anyway, the destination parameters are ignored so it acts the same as send()). This kind of code is a good way to bypass TIdTCPServer's ability to auto-stop its client threads. It expects an exception to be raised when the socket is closed, but you are not allowing it to raise anything. The correct thing to do would be to use TIdIOHandler.ReadBytes() instead, letting it block until new bytes arrive and raise an exception if the client disconnects or the server is being shutting down. And use TIdIOHandler.Write() instead of Binding.Send/To() directly.
@elekgeek If you are just trying to implement an echoing server with logging, I would suggest using this instead:
var
  RxBufStr: string;
begin
  with AContext.Connection.IOHandler do
  begin
    CheckForDataOnSource(10);
    CheckForDisconnect; // <-- add this
    if not InputBufferIsEmpty then
    begin
      RxBufStr := InputBufferAsString(IndyTextEncoding_8Bit); // <-- don't assume any encoding
      Log(RxBufStr);
      Write(RxBufStr, IndyTextEncoding_8Bit); // <-- use TIdIOHandler.Write() instead
    end;
  end;
end;
@elekgeek Personally, I would not use a string at all:
var
  RxBuf: TIdBytes;
begin
  with AContext.Connection.IOHandler do
  begin
    ReadBytes(RxBuf, -1);
    Log(RxBuf);
    Write(RxBuf);
  end;
end;
@elekgeek in which case, you might consider using TIdECHOServer instead of TIdTCPServer. For logging, you can assign a TIdLog... component (TIdLogFile, TIdLogEvent, etc) to the AContext.Connection.IOHandler.Intercept property, such as in the OnConnect event.
elekgeek
@elekgeek
Jun 28 2017 16:15 UTC
I am trying to do echo thing just for testing purposes, other than that I will not need the echo functionality.
Remy Lebeau
@rlebeau
Jun 28 2017 16:17 UTC
@ByteJuggler handling redirects should not be affecting TIdHTTP's ability to handle authentication. If anything, a redirect simply resets the AuthRetries and ProxyAuthRetries counters, giving TIdHTTP more chances to continue authentication attempts. Please don't assume what you think is happening, debug and find out exactly what is really happening.
elekgeek
@elekgeek
Jun 28 2017 16:18 UTC
concerning the code above, it did not solve the issue. Once a client is connected, it is not possible to deactivate the server, so same issue. Also rubbish text is received.
Remy Lebeau
@rlebeau
Jun 28 2017 16:19 UTC
@elekgeek the preferred way to use TIdTCPServeris to use blocking I/O that follows a defined protocol, raising exceptions on errors/disconnects/shutdowns, and let the server handle the exceptions. If you skip that logic, you become responsible for handling certain things manually, like shutdown. For instance, you could set a variable before setting Active=False (or, just look at Active itself, since it is toggled to false before thread shutdowns occur), and then have OnExecute look at that variable, and if set then call AContext.Connection.Disconnect, or raise your own exception, before exiting the event.
Remy Lebeau
@rlebeau
Jun 28 2017 16:25 UTC
@elekgeek the code I gave works just fine for shutting down clients. So, the most likely possibility is if Log() itself is deadlocking, such as if it tries to synchronize with the main UI thread while the main UI thread is blocked waiting for the server to finish shutdown. Do not synchronize with the thread that is shutting down the server, that is a guaranteed deadlock. Either skip the synched operation during shutdown, or use a separate worker thread to shutdown the server so syncs can still be processed.
Kudzu
@czhower
Jun 28 2017 16:27 UTC
I realize you are having issues elekgeek, but it is either your code, or milliions of Indy servers out there are all somehow not having the same Indy issue. I can tell you which I think it is.
Remy Lebeau
@rlebeau
Jun 28 2017 16:31 UTC
@elekgeek As for "rubbish text", that is just because of the use of the 8bit encoding, which stores each byte as-is as a separate char and your code is not accounting for that. You can't use UTF-8 unless you ensure complete byte sequences for multi-byte characters, but your original code was not doing that. What kind of protocol is your server implementing? If the text is line-based, for instance, then you could just use TIdIOHandler.ReadLn(), in which case using UTF-8 would be OK. But if you use ReadBytes(-1) or ExtractString(-1) or InputBufferAsString then all guarantees about the completeness of multi-byte sequences go out the window