How to Detect "Network is Unreachable" via Ping using QProcess? - c++

I am having an issue while pinging to Destination / local IP using QProcess. QProcess returns "0" when ping is Successfull while Also when ping gives "Network is Unreachable" error (seen manually on terminal).
Actually I need to check the network connection in my application. To implement it, i used a very simple concept of ping using QProcess. I need to pop up a messagebox if there is any network error otherwise application starts normally without any popup message.
Here is my code for ping :
bool App::pingPcuStatus(void)
{
const QString IP ="192.168.49.44";
bool ret = false;
int status;
if ( IP == "0.0.0.0") {
status = 1;
}
else {
QProcess pingProcess;
QString exec = "ping";
QStringList params;
params << "-c" << "1" << IP;
status = pingProcess.execute(exec, params); //status = 0 , if Ping Successfull
pingProcess.close();
}
ret = (status) ? false : true;
return ret;
}
But while debugging I found, it returns "true" even i am not conected to network. (I tried manual ping with same command on terminal, it gives "Network is Unreachable" error).
This leads to a big bug in my case.
What is the best way to capture this error using QProcess or any other way to resolve it ???
Any Idea or Suggestion are welcome.

Original answer from https://stackoverflow.com/a/2148360/793796:
QProcess pingProcess;
QString exec = "ping";
QStringList params;
params << "-c" << "1" << IP;
pingProcess.start(exec,params,QIODevice::ReadOnly);
pingProcess.waitForFinished(-1);
QString p_stdout = pingProcess.readAllStandardOutput();
QString p_stderr = pingProcess.readAllStandardError();
Then you can parse stdout & stderr.

Related

Check if at least one Wayland session is running

I'm using Qt and want to check if any Wayland session is running.
For now I have this just for test code, that works as expected:
QProcess process;
process.setProgram("bash");
process.setArguments({"-c", "loginctl list-sessions --no-legend | awk '{print $1}'"});
process.start();
process.waitForFinished();
const QByteArrayList sessionsList = process.readAll().split('\n');
foreach (const QByteArray &sessionID, sessionsList) {
if (sessionID.isEmpty())
continue;
process.setArguments({"-c", "loginctl show-session " + sessionID});
process.start();
process.waitForFinished();
if (process.readAll().contains("Type=wayland"))
qDebug() << "At least one Wayland session is running";
}
Is it possible to get rid of QProcess and use Linux C++ API?
You can try to connect to Wayland. If you can connect to a Wayland composer it is running otherwise is not running or someone haven't set the environment variables correctly and not used the default name.
#include <wayland/wayland-client-core.h>
bool isWaylandRunning(){
auto display = wl_display_connect(nullptr);
if (display){
wl_display_disconnect(display);
return true;
} else {
return false;
}
}

Paho MQTT (C++) client fails to connect to Mosquitto

I've got C++ code using the Paho MQTTPacket Embedded C++ library to connect to an MQTT broker. When that broker is io.adafruit.com, it works perfectly fine. But when it's my own Mosquitto instance running on my Raspberry Pi, the connection fails. I've narrowed it down to this line in MQTTClient.h, in the MQTT::Client::connect method:
// this will be a blocking call, wait for the connack
if (waitfor(CONNACK, connect_timer) == CONNACK)
The app hangs here for about 30 seconds, and then gets a result other than CONNACK (specifically 0 rather than 2).
I have tried both protocol version 3 (i.e. 3.1) and 4 (i.e. 3.1.1); same result.
My Mosquitto instance has no authentication or passwords set up. I've tried turning on debug messages in the Mosquitto log, but they're not showing anything useful. I'm at a loss. Why might I be unable to connect to Mosquitto from my C++ Paho code?
EDIT: Here's the client code... again, this works fine with Adafruit, but when I point it to my Mosquitto at localhost, it hangs as described. (I've elided the username and password -- I am sending them, but I really don't think those are the issue, since with mosquitto_pub or mosquitto_sub on the command line, I can connect regardless of this, since mosquitto is configured to allow anonymous connections.)
const char* host = "127.0.0.1";
int port = 1883;
const char* clientId = "ZoomBridge";
const char* username = "...";
const char* password = "...";
MQTT::QoS subsqos = MQTT::QOS2;
ipstack = new IPStack();
client = new MQTT::Client<IPStack, Countdown, 30000>(*ipstack);
MQTTPacket_connectData data = MQTTPacket_connectData_initializer;
data.willFlag = 1;
data.MQTTVersion = 3;
data.clientID.cstring = (char*)clientId;
data.username.cstring = (char*)username;
data.password.cstring = (char*)password;
data.keepAliveInterval = 20;
data.cleansession = 1;
int rc = ipstack->connect(host, port);
if (rc != MQTT::SUCCESS) {
cout << "Failed [1] (result " << rc << ")" << endl;
return rc;
}
rc = client->connect(data);
if (rc != MQTT::SUCCESS) {
cout << "Failed [2] (result " << rc << ")" << endl;
ipstack->disconnect();
return rc;
}
As hashed out in the comments.
It looks like you are setting the flag to indicate you want to set a Last Will and Testament for the client (data.willFlag = 1;) but then not passing any topic or payload for the LWT.
If you don't need the LWT then set the flag to 0 (or remove the line settings flag) as it should default to disabled.
Also worth pointing out to clarity, this is all with the Paho Embedded C++ MQTTPacket client not the full blown Paho C++ client.

Qt: Failed to find out application pid when run from binary using script

I have an aim to obtain the PID of application, when the latter runs.
I wrote a simple function calls pgrep command:
QString Scriptlauncher::getAppProcessId() {
QProcess p;
QString programme("pgrep");
QStringList args = QStringList() << "app_name";
p.start(programme, args);
p.waitForReadyRead();
QByteArray rdata = p.readAllStandardOutput();
qDebug() << "------------- script output rawdata is:" << rdata;
if (!rdata.isEmpty()) {
QString pid(rdata);
pid = pid.left(pid.length() -1); // cut '\n' symbol
qWarning() << "APPLICATION pid is" << pid;
return pid;
}
qWarning() << "failed to find out PID";
return ("-1");
}
When I run the program directly from Qt or using a simple script (call it execute.sh; it exports all needed shared libs and then run app binary, - to run the app from terminal), the codeblock from above returns correct value:
user#host:/standalone_package/ execute.sh
------------- script output rawdata is: "21094\n"
APPLICATION pid is "21094"
But when I run execute.sh from the valgrind heap profiler command, the function returns:
user#host:/standalone_package/ valgrind --tool=massif --trace-children=yes ./execute.sh
------------- script output rawdata is: ""
failed to find out PID
Thanks to Hayt for links! I've found a solution!
The second link offered requires the instance of QProcess object. I have no idea about how to get it.
But using first link, I get the code working both directly from app and under valgrind:
QString Scriptlauncher::getAppProcessId() {
long pid = (long)getpid();
qDebug ("------------- pid is %d", pid);
QString pidstr = QString::number(pid);
return pidstr;
}

QtGui5 not loaded

I am developing an application in C++, winApi and Qt. What this application does is that it communicates through serial COM ports.
A user can open multiple pairs of ports and an opened port listens other port constantly.
To implement this functionality I use windows threads.There is a method named startRead() that reads from other port constantly and changes the text area.
void SendAndReceive::startRead(){
DWORD numRead = 0;
std::string hex;
while (1)
{
char *buffer = (char *)malloc(sizeof(char) * 500);
BOOL ret = ReadFile(portHandler, buffer, 500, &numRead, 0);
if (!ret)
{
std::string errorMessage = "";
}
buffer[numRead] = '\0';
std::string receivedData(buffer);
QString QData(receivedData.c_str());
if (ui->checkBox->isChecked())
{
std::string receivedData(buffer);
hex= stringToHex(receivedData);
QString QData1(hex.c_str());
emit asHex(QData1);
}
QString QData2(receivedData.c_str()) ;
emit finished(QData2);
free(buffer);
}
}
And there is another thread that writes data periodically to other port. For example , if you enter 2 seconds in a text line , the program writes data to other port at every 2 seconds and this method is writePeriodic().
void SendAndReceive::writePeriodic(){
DWORD numWritten;
while (1 && checkWrite == true )
{
Concurrency::wait(timePeriod*1000);
QString QData = ui->textEdit->toPlainText();
std::string data = QData.toStdString();
WriteFile(portHandler, data.c_str(), strlen(data.c_str()), &numWritten, NULL);
}
}
So when I run this program , program runs smoothly for 2 or 3 minutes and then it crashes and I get errors like "Program has stopped working" , "program closed unexpectedly".When I debug program , it says something like "Qt5Core not loaded" or "Qt5Gui not loaded".
Before I ask here , I did some search on the web . First I did not use emit finished(QString) signal , instead I directly manipulated GUI objects inside startRead() method.(I did something like ui->text_edit->setText(some QString)).But after some search I learn that I can not change GUI objects from another thread so I decided to use signal and slot mechanism and it has not solved my problem so far.I get same error again and again.Please tell me what I am doing wrong . If you need further explanation, I will happily give more details.

Linux C++: cannot run "nmcli dev list iface" when not logged in

I have an application in written in Qt C++ which shall gather information about the network connection.
The code to do this, is shown below:
class NetworkHelper {
public:
static void networkInfo(const QString &device, QString &hwaddr, QString &hwdesc, QString &ip, QString &ipmask, QString &gateway, QString &dhcp)
{
FILE *fp;
char buf[512];
QRegularExpression re_vendor("GENERAL.VENDOR:\\s+(?<vendor>.+)");
QRegularExpression re_product("GENERAL.PRODUCT:\\s+(?<product>.+)");
QRegularExpression re_hwaddr("GENERAL.HWADDR:\\s+(?<hwaddr>.+)");
QRegularExpression re_ip_gateway("ip = (?<ip>\\d+.\\d+.\\d+.\\d+)/\\d+, gw = (?<gateway>\\d+.\\d+.\\d+.\\d+)");
QRegularExpression re_ipmask("subnet_mask = (?<ipmask>\\d+.\\d+.\\d+.\\d+)");
QRegularExpression re_dhcp("dhcp_server_identifier = (?<dhcp>\\d+.\\d+.\\d+.\\d+)");
QRegularExpressionMatch match;
hwaddr = QString();
hwdesc = QString();
ip = QString();
ipmask = QString();
gateway = QString();
dhcp = QString();
#ifdef Q_OS_LINUX
const char *cmd = QString("nmcli dev list iface %1").arg(device).toUtf8().constData();
if (!(fp = popen(cmd,"r")))
return;
while (fgets(buf, sizeof(buf), fp) != NULL)
{
match = re_ip_gateway.match(buf);
if (match.hasMatch())
{
ip = match.captured("ip");
gateway = match.captured("gateway");
}
match = re_ipmask.match(buf);
if (match.hasMatch())
ipmask = match.captured("ipmask");
match = re_dhcp.match(buf);
if (match.hasMatch())
dhcp = match.captured("dhcp");
match = re_vendor.match(buf);
if (match.hasMatch())
hwdesc = match.captured("vendor");
match = re_product.match(buf);
if (match.hasMatch())
hwdesc += hwdesc.isEmpty() ? match.captured("product") : " / "+match.captured("product");
match = re_hwaddr.match(buf);
if (match.hasMatch())
hwaddr = match.captured("hwaddr");
}
ret = pclose(fp);
#endif
}
};
The application runs as autostart right after the machine has booted. The problem is that popen() returns code 139, which to my understanding means segfault, and the while-loop is not executed, so I am not able to get the network information.
If I log in and manually start the application, the above code runs fine and I get all the required network information.
Also - another part of the application starts up a HTTP server, which I am able to connect to also when the application runs as autostart, so there doesn't seem to be any network issues.
Does anyone know, how I will be able to run the popen() when the application autostarts?
Found out that my application started up before the network manager (or something like that - not fully sure why I saw the above behaviour as I was able to connect to the http server started by application but not able to run nmcli command).
In my autostart script I added the condition not to start the application before online connectivity is established, which solved my problem