Search code examples
androidsocketsc++builderindy10

Indy10 on Android. How can I force TIdUDPClient to respects BoundPort Property for GSM network connection?


In a C++Builder Android project, TIdUDPClient on a TDataModule respects its BoundPort as expected when the device is connected to a WiFi network:

// BoundPort property is set to 55555...

amcDeviceDM->UDPC->Active = true;
amcDeviceDM->UDPC->Connect();
if(amcDeviceDM->UDPC->Connected())
{
    amcDeviceDM->UDPC->SendBuffer(fHost,fPort,Id_IPv4,DataPkt);
}

Extract from UDP Server receive log:

PeerPort = 55555

If WiFi is disabled, and instead the device is connected to a GSM network (like Telstra Australia), the BoundPort property is ignored, and the UDP Server receive log shows:

PeerPort = 37091

If WiFi is reactivated, the server once again shows:

PeerPort = 55555

Does anyone know how to ensure the correct sending port is always selected, even if the network socket changes?


Solution

  • Indy has no concept of WiFi vs GSM networks. It is simply binding a socket to a local IP/port, regardless of what they happen to be associated to at the OS/hardware layers. The fact that you are not seeing any exceptions raised means the binding is successful (and you can verify that by looking at the amcDeviceDM->UDPC->Binding->Port property after activating the socket).

    When connected to a GSM network, the device does not have a direct connection to the Internet. The provider is acting as a gateway/proxy to give the device Internet access. As such, the UDP server is going to be receiving packets from a PeerIP/PeerPort pair that belongs to the provider's system, not the device (you would see that more clearly if the UDP server were logging the PeerIP). Whatever BoundPort you decide to bind TIdUDPClient to locally on your device has no effect whatsoever on the port binding used by the provider's system, and you have no control over that. And that is perfectly fine, as the provider will handle the linkage between the device's IP/Port and the provider's IP/Port for you so packets can be routed between them as needed.

    When connected to WiFi, the device still does not have a direct connection to the Internet. The router is acting as a gateway to give the device Internet access. As such, the UDP server is going to be receiving packets from a PeerIP/PeerPort pair that belongs to the router, not the device. Whatever BoundPort you decide to bind TIdUDPClient to locally may or may not be preserved by the router. When a router sees an outgoing UDP packet that it needs to forward to the public (Internet) side of the network, the router will open a port that is bound to the router's public IP (if not already open), and then send the packet from that public IP/Port. Any UDP packets that are received by that public IP/port will then be forwarded to the device's IP/Port. That opened port number will usually be the same port number used by the original packet, if that port number is currently available on the router, but that is not a guarantee. So, even on a WiFi network, it is still possible for the UDP server to see a different PeerPort than what the device is bound to. And that is perfectly fine, as the router will handle the linkage between the device's IP/Port and the router's IP/Port for you so packets can be routed between them as needed. If you need to guarantee the router's public port number, you will have to configure a port mapping rule on the router before your device starts sending packets, either in the router's configuration statically, or dynamically via uPNP.