Problem binding UDP (server) socket to an interface
-
I am writing a UDP server application that needs to know which interface received a request, so I can know what IP address to deliver in the response.
To accomplish that, I am creating a separate UDP socket for each interface, and binding each socket to a specific interface address.
Here is a piece of code so you can see what I am doing to initialize it:
@PXEResponder::PXEResponder(QObject *parent)
: QObject(parent)
{
bool ok;// Get network interface list addresses = QNetworkInterface::allAddresses(); signalMapper = new QSignalMapper(this); listeners.reserve(interfaces.size()); for (int i = 0; i < addresses.size(); ++i) { // Only support IPv4 if (addresses[i].protocol() != QUdpSocket::IPv4Protocol) continue; qDebug() << addresses[i]; // Create a UDP socket and bind it to port 67 QUdpSocket *listener = new QUdpSocket(this); if (!listener->bind(addresses[i], 67, QUdpSocket::DefaultForPlatform)) //if (!listener->bind(67)) qDebug() << "Failed to bind DHCP listener"; // Connect the readyRead signal to our slot ok = connect(listener, SIGNAL(readyRead()), signalMapper, SLOT(map())); signalMapper->setMapping(listener, i); listenerAddress.insert(listener, addresses[i]); listeners.push_back(listener); } ok = connect(signalMapper, SIGNAL(mapped(int)), this, SLOT(on_packet(int)));
}
@Everything completes without error, but I don't get any readyRead signals.
NOTE:
- My program is running as root, so it is allowed to bind port 67
- There is no DHCP server running on my machine
- I am using the signal mapper so I can identify which QUdpSocket causes the event. That part works.
- The "bind" call that doesn't work (the one that specifies an address) returns true.
- Removing the "QUdpSocket::DefaultForPlatform" parameter doesn't help.
- The qDebug() output (the interface address) looks correct.
- If I comment-out the bind call that I'm trying to use, and uncomment the one that doesn't specify an interface address, everything works.
Here's the weird part: when I bind to specific interfaces, I see the socket in the "netstat -a" output. Is there a reason I am not receiving broadcasts when bound to a specific interface?
I found a partial answer:
Linux won't receive broadcast packets when the socket is bound because it will only receive packets sent (directly) to the bound address. The solution is to use SO_BINDTODEVICE socket option and use INADDR_ANY as the bind address.
Is there a way to bind to a network interface in Qt (without binding to the address of the interface)?
-
try this:
@
#include <sys/socket.h>m_udpSocket = new QUdpSocket( this );
if( m_udpSocket )
{
connect( m_udpSocket, SIGNAL( readyRead() ), this, SLOT( SLOT_ondataReceived() ) );
connect( m_udpSocket, SIGNAL( disconnected() ), this, SLOT( SLOT_disconnected() ) );retVal = m_udpSocket->bind( QHostAddress::Any, m_port );
// set the socket option here.....
const char dev[] = "eth0";
if (0 != setsockopt(m_udpSocket->socketDescriptor(), SOL_SOCKET, SO_BINDTODEVICE, dev, sizeof(dev) ))
{}
}@