Search code examples
delphinetworkingindy

Is there a way to reset the Binding of a TIdUDPServer, without restarting the server?


I have an TIdUDPServer which listens to the port 255. The event OnUDPRead is assigned to listen for any inbound packets, and occasionally needs to reply back to the client.

To reply, I use the ABinding socket handle provided in the event, and return a TIdBytes array to the server. But, In order to to this I need to connect the binding. Here is my approach:

procedure TExplorer.IdUDPServer1UDPRead(AThread: TIdUDPListenerThread;
  const AData: TIdBytes; ABinding: TIdSocketHandle);
begin
  // Here FReplyData would be initiated

  // Reply
  if Length(FReplyData) > 0 then
    begin
      ABinding.Connect;
      ABinding.Send(FReplyData);
    end;
end;

This would work perfectly, but after executing Connect(), the binding no longer listens for all adresses, and only for the Peer address. From 0.0.0.0 to <client_adress>.

This is intended behaviour, as stated in the Indy10 documentation:

Connect is a virtual procedure used to open a connection to the PeerIP and PeerPort using the socket handle for the descriptor. Connect uses the GStack global protocol stack to connect the socket handle to the remote system.

Connect calls UpdateBindingLocal and UpdateBindingPeer to reflect the real IP address and Port numbers used for the connection when the socket handle is allocated. This operation is thread-safe; it is protected by an internal TIdCriticalSection instance.

Use CloseSocket to close and destroy the socket handle.

The problem is that once I have sent the packet, I would like to continue listening to all other requests, or more exactly, to keep the binding to '0.0.0.0' to Un-connect It.

As of now, I tried the following:

  • Creating a new socket and use this one to send the data
  • Changing the Ip of the ASocket and re-binding It
  • Using SendTo instead, but It's basically the same thing And a few other things, but none of them worked.

So, what am I doing wrong? Any ideas would be greatly appreciated!


Solution

  • I figured it out.

    Using ABinding.Connect() would assign the socket to the Peer IP. From what I tested, I believe there is no way to change the binding after the fact, or maybe there is and I just have not looked deep enough into this matter.

    But, in order to reply to a request, without connecting to the Peer socket, you will need to use ABinding.SendTo() instead. This should have been more evident from the start, but I missed this fact as I used ABinding.IP instead of ABinding.PeerIP, which would send the packet to the wrong destination.

    So, to send a packet from the Binding to the Peer, you can use the following code:

    ABinding.SendTo(ABinding.PeerIP, ABinding.PeerPort, FReplyData, ABinding.IPVersion);
    

    The destination being the Peer, and FReplyData is of TIdBytes type.