I came to conclusion, that it's not possible to make it work 100% correct as expected from user point of view, because of OS-specific implementations of networking.
Following code provides solution:
void initNetwork() {
//...
/* It will be needed to filter out own loopbacked datagrams */
local_addresses = QNetworkInterface::allAddresses();
/* Interface, selected by user */
QNetworkInterface multicast_netif = <user selected>;
/* Two separate sockets for receiving and sending (allows differentiate source port from destination port) */
udpSocketIn = new QUdpSocket(this);
udpSocketOut = new QUdpSocket(this);
/* It's important to bind to Any for multicast to work, also port must be reusable by all application instances on same host */
udpSocketIn->bind(QHostAddress::Any, MULTICAST_PORT, QUdpSocket::ShareAddress | QUdpSocket::ReuseAddressHint);
/* It required to only make application know real(!) udpSocketOut->localPort() in order to be able filter own datagrams */
udpSocketOut->bind();
/* Obvious... */
udpSocketIn->joinMulticastGroup(QHostAddress(MULTICAST_ADDR), multicast_netif);
udpSocketOut->setMulticastInterface(multicast_netif);
/* Multicast loopback is set by default, but set it explicitly just in case. */
udpSocketIn->setSocketOption(QAbstractSocket::MulticastLoopbackOption, QVariant(1));
udpSocketOut->setSocketOption(QAbstractSocket::MulticastLoopbackOption, QVariant(1));
//...
}
void sendDatagram() {
//...
udpSocketOut->writeDatagram(datagram, QHostAddress((MULTICAST_ADDR), MULTICAST_PORT);
//...
}
void readPendingDatagrams() {
//...
udpSocketIn->readDatagram(datagram, &senderHost, &senderPort);
/* Thanks to udpSocketOut->bind() we are able to filter out own packets sent from udpSocketOut */
if ((local_addresses.contains(senderHost)) && (senderPort == udpSocketOut->localPort())) {
// ignore loopbacked datagram
} else {
// accept diagram
}
//...
Tests on Linux (with two interfaces only: lo
and eth0
) showed perfect results. I select desired interface and it works 99% correct as expected. It would be 100% if it weren't small bug: on binded lo
interface first datagram is being sent (or received) with source ip of eth0
interface.
Tests on Windows 7 64-bit (with many different interfaces) showed, that in some cases user have to play with system network configuration to make it work. Here are some observations:
- with selected "Loopback Pseudo-Interface 1" diagrams not transferred, if there are any other interface is up, solution: either disable all interfaces, or modify metrics in route table
- with selected "Teredo Tunneling Pseudo-Interface" it works always (it acts as loopback interface)
- regardless of selected interface, socket(s) binded to any interface and diagrams will be transfered with source ip of that interface (i.e. if user selected loopback interface and thinks that it works locally, it's not true, diagrams go out to real network also), solution would be same as in clause 1.
Tests on Windows XP SP3 showed satisfactory results: only clause 3 (see above) retains.
Hope my research will be useful for people experiencing similar problems.