Working implementation attached.
For a UDP discovery tool i built i used TUDPBlockSocket. It works great, but i noticed Windows would send a broadcast with the wrong "From" IP address over other interfaces (with other IP's). As such the UDP devices failed to reply.
This situation can occur when a laptop for example has a wireless connection and you also plug in a Ethernet cable. Using wireshark, you can see UDP messages sent "from" the IP of the wireless adapter over the Ethernet cable. In my case the Ethernet adapter had DHCP disabled, or the situation may be reversed because Windows could then prefer the wired over the wireless connection.
The problem is by design and so the solution is simple. Send one UDP packet to each broadcast address, and Windows will send the UDP packages with the correct "from" IP.
It turns out there is no way in Synapse to list the broadcast addresses (correct me if i am wrong) so i implemented one myself.
I would like this feature to be included in the Synapse library.
My example implementation (see attachment) may not work with IPV6 out of the box, but that could be added. If integration is desired (perhaps for supporting IPv6 out of the box), it seems possible to using a TBlockSocket descendant that overrides the 2 custom synsock.socket() parameters, but i'm sure there are other ways as i am not that familiar with the whole Synapse library.
A working implementation.
Example usage:
(i do Connect('255.255.255.255',1234) before and after just to be sure, i left that out here)
uses
BarryFix_Synapse;
const
DEVICEPORT = '1234';
var
fSynUDP : TUDPBlockSocket;
var
a : TStringList;
i: Integer;
receiving : Boolean;
buf : RawByteString;
begin
fSynUDP.Connect('255.255.255.255', DEVICEPORT);
// Send to every Broadcast address i can think of:
a := TStringList.Create;
try
ResolveBroadcastForAllInterfaces(a);
for i := 0 to a.Count - 1 do
begin
fSynUDP.Connect(a.Strings[i], DEVICEPORT);
fSynUDP.SendString( 'some discovery request string' );
end;
finally
a.Destroy;
end;
fSynUDP.Connect('255.255.255.255', DEVICEPORT);
while receiving do
begin
// Receive:
buf := fSynUDP.RecvPacket(fTimeoutMs);
receiving := fSynUDP.LastError = 0;
// Parse:
if receiving then SomeResponseChewer(fSynUDP.GetRemoteSinIP, buf);
end;
end;
I would like to (again) point out that a working implementation has been attached:
procedure ResolveBroadcastForAllInterfaces(var ipList : TStringList);
I can confirm it works, my software relies on it to send one UDP broadcast packet from each IP the computer has. (most common example is WiFi + LAN, but also dual LAN or VPNs)
My implementation uses IdWinsock2.pas for (four or so) records/constants. I have not been able to factor that out without degrading functionality.
IMHO the only issue regarding inclusion in Synapse is a dependance on IdWinsock2.pas.