Rebind using new QUdpSocket - qt

I have a network application which uses UDP broadcasts for device discovery, but only accepts one connection at a time. So, when a new TCP connection is made, I delete the QUdpSocket that was used for discovery.
However, when the remote device is disconnected, I want to create a new QUdpSocket and start listening again:
// Set up a UDP server to respond to any "discovery" messages:
udpServer = new QUdpSocket(this);
if (udpServer -> bind(QHostAddress::Any, DISCOVERY_PORT))
connect(udpServer, SIGNAL(readyRead()),
this, SLOT(beDiscovered()));
else
{
fprintf(stderr, "UDP port not bound successfully: %d, ", udpServer ->error());
fprintf(stderr, udpServer ->errorString().toLocal8Bit());
fprintf(stderr, "\r\n");
fflush(stderr);
#ifdef WIN32
_commit(_fileno(stderr));
#else
fsync(_fileno(stderr));
#endif
}
The re-bind fails, however, with code 8, "The bound address is already in use".
So, how can I make sure that when the 'old' QUdpSocket was deleted, it fully releases the address(es) it was bound to?
Alternatievly, should I be binding with QUdpSocket::ShareAddress or QUdpSocket::ReuseAddressHint? This doesn't seem right, as neither really describe the behaviour I want, namely an exclusive binding for my QUdpSocket during its lifetime, and in any case QUdpSocket::ShareAddress is supposed to be the default on Windows.
Thanks,
Stephen.

...so in other words the question has answered itself!

Related

QT connectToHost() wrong host state

I am using QTcpSocket to connect to given host:
QHostAddress oAddr( u32Addr);
QTcpSocket* poSocket = new QTcpSocket(this);
connect(poSocket, SIGNAL(connected()), this, SLOT(readCheckConnection()));
poSocket->connectToHost( oAddr, 80);
I am not using waitForConnected() because I try to connect many hosts at once, sometimes with quite long time connection so I need to count on connected() signal.
Everything works fine with Windows 10, problem appears with Windows 11. Signal connected() is emitted although there is no host existing. Moreover when socket state is checked it also returns CONNECTED state.
I am working wit QT 5.15.2. What may cause this problem?

How does port numbering works for receiving MODBUS TCP packets?

I am running an application on my microcontroller(MSP432), which writes data to an Ethernet cable to send it over to PC.
I am using Packet sender to view the data received on the port(502) on PC from MC.
Data received on PC
As we can see in the above picture, the port numbers of MC are increment for every packet sent.
What will happen when it reaches to the maximum number?
Will it restart at some other port number and proceed with the process or will it stop?
Edit1: Modbus protocol library used from http://myarduinoprojects.com/modbus.html
Edit2:
Making a call to this function everytime i have a new data to send through MODBUS. Mb.Req(MB_FC_WRITE_MULTIPLE_REGISTERS, 0,11,0);
if (MbmClient.connect(ServerIp,502)) {
digitalWrite(GREEN_LED, HIGH);
#if DEBUG
//Serial.println("connected with modbus slave");
// Serial.print("Master : ");
for(int i=0;i<MbmByteArray[5]+6;i++) {
if(MbmByteArray[i] < 16){
//Serial.print("0");
}
//Serial.print(MbmByteArray[i],HEX);
if (i != MbmByteArray[5]+5) {
//Serial.print(".");
} else {
//Serial.println();
}
}
#endif
MbmClient.write(MbmByteArray,13+(Count*2));
MbmCounter = 0;
MbmByteArray[7] = 0;
MbmPos = Pos;
MbmBitCount = Count;
*state= true;
MbmClient.stop();
delay(100);
digitalWrite(GREEN_LED, LOW);
} else {
*state= false;
MbmClient.stop();
}
It seems you are using this Modbus example
I have never worked with that but I suppose that because the destination port in the code is the same you have in your sniffing image: 502
Probably you are repeatedly calling this method:
void MgsModbus::Req(MB_FC FC, word Ref, word Count, word Pos)
Inside this method you can see this line:
if (MbmClient.connect(ServerIp,502)) {
...
So every time you call that function a new connection is open. When you open a connection through a socket, the operating system or the network stack needs to select a source port and IP address from where the TCP message is sent.
This is why you see always a new source port and that port is increasing. This is what is called an ephemeral port. How the source port is selected by the TCP stack you are using is implementation dependent, though it's very common to begin with some port and every time a connection is open, it selects the next available port.
If the stack is well programmed, most probably your TCP stack will wrap around and begin with some specific port from 1024 up (First 1024 ports are restricted). The code I saw seems to close the port with this function:
MbmClient.stop()
You need to check ports, after being used, are closed. Otherwise, at some point you will run out of available ports (resource leak).
If you want your socket bound to a specific source port, you need to use a function similar to Linux socket bind
Now, a wiser way is to use all the time the same connection. You may need to modify that example.

Simple Qt code for network simplistic network connection

I'm completely new at using the QtNetwork for connecting computers.
Right now all I want is to see an attempt at a connection. So I create a GUI application and on the mainwindow.cpp I write these two functions as slots for two buttons:
void MainWindow::on_pbTalk_clicked(){
QString IP = ui->leIP->text();
ui->pteLog->appendPlainText("Now Talking to IP: " + IP);
talker = new Talker();
talker->connectToHost(IP,25000);
}
void MainWindow::on_pbListen_clicked(){
ui->pteLog->appendPlainText("Now listening on any port, I think");
listener = new Listener(this);
if (!connect(listener, SIGNAL(newConnection()), this, SLOT(on_newConnections()))){
ui->pteLog->appendPlainText("The connection of slot and signal failed!");
}
}
Now Talker is essentially a QTcpSocket there is nothing reimplemented just yet.
Listener is a QTcpServer with the following code con Listener.cpp:
Listener::Listener(QObject *parent) :
QTcpServer(parent)
{
qDebug() << "Listening on any port";
listen(QHostAddress::Any);
}
void Listener::incomingConnection(int socketDescriptor){
qDebug() << "New connection: " << socketDescriptor;
}
So I run two instances of the same program. One is in my machine. I run the program and push the Listen button (IP 10.255.255.101).
The second instance is run in a virtual machine (IP 10.255.255.215) where I run the program and push the Talk button. This, as I understand should attempt to open a connection to IP (which is 10.255.255.101) at port 25000 and I should get a "New connection" message in the console. However no such message appears. And since this is not working, I'm not moving on.
Can any one tell me what I might be doing wrong?
Check the documenation of QTcpServer::listen - it says:
Tells the server to listen for incoming connections on address address
and port port. If port is 0, a port is chosen automatically. If
address is QHostAddress::Any, the server will listen on all network
interfaces.
QHostAddress::Any means that you are listening on all network interfaces, not ports. (For example, if you want to have a local server only, you could use QHostAddress::LocalHost - check QHostAddress::SpecialAddress for more like that.
If you want to set the port manually, you have to call:
listen(QHostAddress::Any, 25000);
If not, you can get the automatically chosen port by calling
quint16 port = serverPort();
The "listening on any port" idiom isn't available for your use; it's not how UDP and TCP were meant to be used. Most likely you shouldn't be designing your communications that way. Use a dedicated port.
If you want to build a packet sniffer, you'll have to use the platform-specific mechanisms designed for that. There are libraries that help you with that task, the most notable would be WinPcap on Windows and cross-platform libpcap from the TcpDump project.

Platform independent Qt5 way to get open TCP port

Is there a platform independent way in Qt to get an unused TCP port? I have a need to launch an existing application which must be given an open TCP port in order for it to work.
use QTcpServer is easier way.
bool QTcpServer::listen(const QHostAddress & address = QHostAddress::Any, quint16 port = 0)
If port is 0, a port is chosen automatically, then you use quint16 QTcpServer::serverPort() const to get the "idle" port
then close your Tcp Server
OR
generate a ramdom port, use QTcpSocket to connect it(local connection)
if connected, your port is QTcpSocket::localPort() and close this tcp socket
if not connected, your port is random port;
Do you mean some kind of tcp server? Then there is QTcpServer class.
If you want to start an existiong server, then you need QProcess class. Example:
QString program = "path/to/server";
QStringList arguments;
arguments << "-p" << "1234"; //or what ever you want
QProcess *myProcess = new QProcess(parent);
myProcess->start(program, arguments);

How to tell which interface the socket received the message from?

If a socket is bound to IN6ADDR_ANY or INADDR_ANY and you use a call such as recvfrom() to receive messages on the socket. Is there a way to find out which interface the message came from?
In the case of IPv6 link-scope messages, I was hoping that the from argument of recvfrom() would have the scope_id field initialized to the interface Id. Unfortunately it is set to 0 in my test program.
Anybody know of a way to find out this information?
dwc is right, IPV6_PKTINFO will work for IPv6 on Linux.
Moreover, IP_PKTINFO will work for IPv4 — you can see details in manpage ip(7)
I've constructed an example that extracts the source, destination and interface addresses. For brevity, no error checking is provided. See this duplicate: Get destination address of a received UDP packet.
// sock is bound AF_INET socket, usually SOCK_DGRAM
// include struct in_pktinfo in the message "ancilliary" control data
setsockopt(sock, IPPROTO_IP, IP_PKTINFO, &opt, sizeof(opt));
// the control data is dumped here
char cmbuf[0x100];
// the remote/source sockaddr is put here
struct sockaddr_in peeraddr;
// if you want access to the data you need to init the msg_iovec fields
struct msghdr mh = {
.msg_name = &peeraddr,
.msg_namelen = sizeof(peeraddr),
.msg_control = cmbuf,
.msg_controllen = sizeof(cmbuf),
};
recvmsg(sock, &mh, 0);
for ( // iterate through all the control headers
struct cmsghdr *cmsg = CMSG_FIRSTHDR(&mh);
cmsg != NULL;
cmsg = CMSG_NXTHDR(&mh, cmsg))
{
// ignore the control headers that don't match what we want
if (cmsg->cmsg_level != IPPROTO_IP ||
cmsg->cmsg_type != IP_PKTINFO)
{
continue;
}
struct in_pktinfo *pi = CMSG_DATA(cmsg);
// at this point, peeraddr is the source sockaddr
// pi->ipi_spec_dst is the destination in_addr
// pi->ipi_addr is the receiving interface in_addr
}
Apart from binding to each interface, I'm not aware of a way with IPv4, per se.
IPv6 has added the IPV6_PKTINFO socket option to address this shortcoming. With that option in effect, a struct in6_pktinfo will be returned as ancillary data.
Its been a while since I've been doing C/C++ TCP/IP coding but as far as I remember on every message (or derived socket) you can get into the IP headers information. These headers should include the receiving address which will be the IP of the interface you are asking about.
Outside of opening a separate socket on each interface as Glomek suggested, the only way I know to do this definitively on Windows is to use a raw socket, e.g.,
SOCKET s = socket(AF_INET, SOCK_RAW, IPPROTO_IP);
Each receive from this socket will be an IP packet, which contains both the source and destination addresses. The program I work on requires me to put the socket in promiscuous mode using the SIO_RCVALL option. Doing this means I get every IP packet the interface "sees" on the network. To extract packets expressly for my application requires me to filter the data using the addresses and ports in the IP and TCP/UDP headers. Obviously, that's probably more overhead than you're interested in. I only mention it to say this - I've never used a raw socket without putting it in promiscuous mode. So I'm not sure if you can bind it to INADDR_ANY and just use it as a regular socket from that point forward or not. It would seem to me that you can; I've just never tried it.
EDIT: Read this article for limitations regarding raw sockets on Windows. This biggest hurdle I faced on my project was that one has to be a member of the Administrators group to open a raw socket on Windows 2000 and later.

Resources