Search code examples
delphiindyfreepascal

How to bind new server binding while server active


How i can let the OS assign available ports to new bindings in Indy server while the server is active ?

  IdUDPServer.Active := True;

  for I := 0 to 4 do
  begin
    IdUDPServer.Bindings.add;
  end;

  for I := 0 to IdUDPServer.Bindings.Count-1 do
  begin
    WriteLn(IdUDPServer.Bindings[I].Port);
  end; 

Will print the following :

40371
0
0
0
0
0

I try this

var
  H : TIdSocketHandle; 
  ...
  for I := 0 to 4 do
  begin
    H := IdUDPServer.Bindings.add;
    try
      H.Bind;
    except
      On E: Exception do
        WriteLn(e.Message);
    end;
  end; 
  ...

I got the following:

Socket Error # 9
Bad file number.
Socket Error # 9
Bad file number.
Socket Error # 9
Bad file number.
Socket Error # 9
Bad file number.
Socket Error # 9
Bad file number.
56554
0
0
0
0
0

Is there any way to accomplish this without deactivate and reactive the server ?

because i don't want to lose any active client while adding new binding.


Solution

  • At this time, you can't add new listening ports to TIdUDPServer while it is already active 1. It is simply not designed to allow that (compared to TIdTCPServer, which is). TIdUDPServer's listening ports are opened only when its Active property is toggled from False to True.

    1: well, you can call Bindings.Add() all you want, but the new bindings won't have any effect in TIdUDPServer.

    When you call Bindings.Add(), it assigns the server's DefaultPort to the Port property of the new TIdSocketHandle object. The DefaultPort is 0 by default. But to actually open the TIdSocketHandle.Port to listen for packets requires TIdUDPServer to be deactivated first.

    Calling TIdSocketHandle.Bind() updates the TIdSocketHandle.Port if accessful (thus allowing you to bind to port 0 to assign an available ephemeral port), but the way you are using Bind() does not work because you are not calling TIdSocketHandle.AllocateSocket() beforehand, so the TIdSocketHandle.Handle is not valid for Bind() to use. But even if you did get Bind() to work, it still would not help you, because TIdUDPServer creates a separate listener thread for each Binding object only when the Active property is toggled to True, so any new TIdSocketHandle objects you add to the Bindings while the server is already active will not read packets to give to your OnUDPRead event handler.

    So, if you want to modify the Bindings ports in TIdUDPServer, you must set Active=False first, then modify as needed, and then set Active=True. I have added an enhancement request to Indy's issue tracker for you:

    #294: Update TIdUDPServer to allow updating Bindings while active

    Note that UDP is connection-less, so you won't "lose clients" like in TCP, unless your UDP clients are designed to stop sending packets to your server if its listening port(s) are reported by the OS as closed when the packets are sent.