NetworkManager and Qt Problem - c++

I am still new to using Qt4/Dbus, and i am trying to get a list of acccess points with Qt API to send/receive Dbus messeges.
I got the following error:
org.freedesktop.DBus.Error.UnknownMethod
Method "GetAccessPoint" with signature "" on interface "org.freedesktop.NetworkManager.Device.Wireless" doesn't exist
The code is:
QStringList *netList = new QStringList();
QDBusConnection sysbus = QDBusConnection::systemBus();
QDBusInterface callNM("org.freedesktop.NetworkManager","/org/freedesktop/NetworkManager","org.freedesktop.NetworkManager.Device.Wireless",sysbus);
if(callNM.isValid())
{
QDBusMessage query= callNM.call("GetAccessPoints");
if(query.type() == QDBusMessage::ReplyMessage)
{
QDBusArgument arg = query.arguments().at(0).value<QDBusArgument>();
arg.beginArray();
while(!arg.atEnd())
{
QString element = qdbus_cast<QString>(arg);
netList->append(element);
}
arg.endArray();
}else{
std::cout<< query.errorName().toStdString() << std::endl;
std::cout<< query.errorMessage().toStdString() << std::endl;
}
int x= netList->size();
for(int y=0; y< x ;y++)
{
widget.avail_nets->addItem(netList->at(y)); // just print it to my gui from the stringlist array
}
}else{
std::cout<<"fail" << std::endl;
}
Whats wrong?My naming was correct and I am following the exact specs from here

The method name is GetAccessPoints.
While your error is:
org.freedesktop.DBus.Error.UnknownMethod
Method "GetAccessPoint" with signature
"" on interface
"org.freedesktop.NetworkManager.Device.Wireless"
doesn't exist
Highlight on "GetAccessPoint". Thus you might have misspelled the method name in the code, although the code you pasted here uses the correct method name, maybe you fixed it and forgot to rebuild or clean the project?

I had the same issue, but then I noticed that it only happened when I called the GetAccessPoints method on a wired device. Make sure the device is a wireless device (i.e. DeviceType equals NM_DEVICE_TYPE_WIFI), and everything should work fine.

i modify this and works for me
QDBusInterface callNM("org.freedesktop.NetworkManager","/org/freedesktop/NetworkManager/Devices/0","org.freedesktop.NetworkManager.Device.Wireless",sysbus);
and the result is
"/org/freedesktop/NetworkManager/AccessPoint/2"
"/org/freedesktop/NetworkManager/AccessPoint/1"
i think /org/freedesktop/NetworkManager is not correct path for specific device (wireless devices).

QDBusInterface dbus_iface("org.freedesktop.NetworkManager", "/org/freedesktop/NetworkManager/Devices/0", "org.freedesktop.NetworkManager.Device.Wireless", bus);
QDBusMessage query = dbus_iface.call("GetAccessPoints");
if(query.type() == QDBusMessage::ReplyMessage) {
QDBusArgument arg = query.arguments().at(0).value<QDBusArgument>();
arg.beginArray();
while(!arg.atEnd()) {
QString element = qdbus_cast<QString>(arg);
netList->append(element);
showAccessPointProperties(element);
}
arg.endArray();
} else {
qDebug() << "got dbus error: " << query.errorName();
qDebug() << "check the parameters like service, path, interface and method name !!!";
}
Hope this will help.

Related

Azure IoT Edge C++ module not sending device to cloud telemetry

I have written an IoT Edge C++ module that is sending the event output using the following function call:
bool IoTEdgeClient::sendMessageAsync(std::string message)
{
bool retVal = false;
LOGGER_TRACE(IOT_CONNECTION_LOG, className + "::sendMessageAsync(...) START");
LOGGER_DEBUG(IOT_CONNECTION_LOG, className + "::sendMessageAsync(...) message : " << message);
Poco::Mutex::ScopedLock lock(_accessMutex);
MESSAGE_INSTANCE *messageInstance = CreateMessageInstance(message);
IOTHUB_CLIENT_RESULT clientResult = IoTHubModuleClient_LL_SendEventToOutputAsync(_iotHubModuleClientHandle, messageInstance->messageHandle, "output1", SendConfirmationCallback, messageInstance);
if (clientResult != IOTHUB_CLIENT_OK)
{
LOGGER_ERROR(IOT_CONNECTION_LOG, className + "::sendMessageAsync(...) ERROR : " << message << " Message id: " << messageInstance->messageTrackingId);
retVal = false;
}
else
{
retVal = true;
}
LOGGER_TRACE(IOT_CONNECTION_LOG, className + "::sendMessageAsync(...) END");
return retVal;
}
The result of the function call IoTHubModuleClient_LL_SendEventToOutputAsync is always coming as IOTHUB_CLIENT_OK. My module name is MicroServer and the route configured is:
FROM /messages/modules/MicroServer/outputs/output1 INTO $upstream
I do not see the SendConfirmationCallback function being called. Also, I do not see any device to cloud message appearing in the IoT hub. Any ideas why this is happening and how to fix it?
It turned out that I need to call this function atleast a couple of times per second
IoTHubModuleClient_LL_DoWork(_iotHubModuleClientHandle);
which I was not doing. As a result the code was not working properly. Once I started doing it. The code just worked.

findAndGetString() in DCMTK returns null for the tag

I am developing a quick DICOM viewer using DCMTK library and I am following the example provided in this link.
The buffer from the API always returns null for any tag ID, eg: DCM_PatientName.
But the findAndGetOFString() API works fine but returns only the first character of the tag in ASCII, is this how this API should work?
Can someone let me know why the buffer is empty the former API?
Also the DicomImage API also the same issue.
Snippet 1:
DcmFileFormat fileformat;
OFCondition status = fileformat.loadFile(test_data_file_path.toStdString().c_str());
if (status.good())
{
OFString patientName;
char* name;
if (fileformat.getDataset()->findAndGetOFString(DCM_PatientName, patientName).good())
{
name = new char[patientName.length()];
strcpy(name, patientName.c_str());
}
else
{
qDebug() << "Error: cannot access Patient's Name!";
}
}
else
{
qDebug() << "Error: cannot read DICOM file (" << status.text() << ")";
}
In the above snippet name has the ASCII value "50" and the actual name is "PATIENT".
Snippet 2:
DcmFileFormat file_format;
OFCondition status = file_format.loadFile(test_data_file_path.toStdString().c_str());
std::shared_ptr<DcmDataset> dataset(file_format.getDataset());
qDebug() << "\nInformation extracted from DICOM file: \n";
const char* buffer = nullptr;
DcmTagKey key = DCM_PatientName;
dataset->findAndGetString(key,buffer);
std::string tag_value = buffer;
qDebug() << "Patient name: " << tag_value.c_str();
In the above snippet, the buffer is null. It doesn't read the name.
NOTE:
This is only a sample. I am just playing around the APIs for learning
purpose.
The following sample method reads the patient name from a DcmDataset object:
std::string getPatientName(DcmDataset& dataset)
{
// Get the tag's value in ofstring
OFString ofstring;
OFCondition condition = dataset.findAndGetOFString(DCM_PatientName, ofstring);
if(condition.good())
{
// Tag found. Put it in a std::string and return it
return std::string(ofstring.c_str());
}
// Tag not found
return ""; // or throw if you need the tag
}
I have tried your code with your datasets. I just replaced the output to QT console classes to std::cout. It works for me - i.e. it prints the correct patient name (e.g. "PATIENT2" for scan2.dcm). Everything seems correct, except for the fact that you apparently want to transfer the ownership for the dataset to a smart pointer.
To obtain the ownership for the DcmDataset from the DcmFileFormat, you must call getAndRemoveDataset() instead of getDataset(). However, I do not think that your issue is related that. You may want to try my modified snippet:
DcmFileFormat file_format;
OFCondition status = file_format.loadFile("d:\\temp\\StackOverflow\\scan2.dcm");
std::shared_ptr<DcmDataset> dataset(file_format.getAndRemoveDataset());
std::cout << "\nInformation extracted from DICOM file: \n";
const char* buffer = nullptr;
DcmTagKey key = DCM_PatientName;
dataset->findAndGetString(key, buffer);
std::string tag_value = buffer;
std::cout << "Patient name: " << tag_value.c_str();
It probably helps you to know that your code and the dcmtk methods you use are correct, but that does not solve your problem. Another thing I would recommend is to verify the result returned by file_format.loadFile(). Maybe there is a surprise in there.
Not sure if I can help you more, but my next step would be to verify your build environment, e.g. the options that you use for building dcmtk. Are you using CMake to build dcmtk?

QMYSQL query failing

I'm currently working on my project within C++ using Qt. I have MySQL as database storage and the idea is to make a small messenger like MSN and Skype.
However, my MySQL queries are failing. It simply gets no results or gives me an error. There's loads of code coming up, I'm sorry for that.
This is my mysql.cpp which creates and opens the database connection:
#include "mysql.h"
mysql::mysql()
{
this->db = QSqlDatabase::addDatabase("QMYSQL", "QMYSQL");
this->db.setHostName("localhost");
this->db.setUserName("root");
this->db.setPassword("Eequi4");
this->db.setDatabaseName("test");
this->db.open();
}
mysql::~mysql()
{
}
mysql_result mysql::create_result(QString query)
{
return mysql_result(this->db.exec(query));
}
QSqlError mysql::error()
{
return this->db.lastError();
}
The connection is opened. That works correctly.
This is my mysql_result.cpp, the file I use to add parameters, insert, get results etc:
#include "mysql_result.h"
mysql_result::mysql_result(QSqlQuery query)
{
this->query = query;
}
void mysql_result::add_parameter(QVariant value)
{
this->query.addBindValue(value);
}
void mysql_result::add_parameter(QString key, QVariant value)
{
this->query.bindValue(key, value);
}
int mysql_result::get_last_id()
{
return this->query.lastInsertId().toInt();
}
void mysql_result::execute()
{
this->query.execBatch();
}
QSqlQuery mysql_result::get_query()
{
return this->query;
}
mysql_result::~mysql_result()
{
}
Okay, this should work. If I have the following code, it correctly returns all member first_name's from the database:
mysql_result res = _mysql->create_result("SELECT * FROM members");
QSqlQuery qry = res.get_query();
while (qry.next())
{
qDebug() << qry.value("first_name");
}
In member_controller.cpp (the class I use to retrieve members by name/id), I got this:
member* member_controller::get_member(int id)
{
mysql_result result = engine::get_mysql().create_result("SELECT * FROM members WHERE member_id = :ID");
result.add_parameter(":ID", id);
QSqlQuery query = result.get_query();
if (query.exec() && query.next())
{
return new member(id, query.value("first_name").toString(), query.value("second_name").toString(), query.value("screen_name").toString(), query.value("email").toString(), query.value("status").toString());
}
else
{
qDebug() << engine::get_mysql().error() << "\n";
qDebug() << query.lastError() << "\n";
}
return new member(0, "", "", "", "", "");
}
What it does it will go to the else, and I get the error invalid syntax near :ID. If I replace :ID with #ID (just like in C#), it will go to the else without error code.. I don't know what the problem is.
Two things. The code needs to be optimized a bit and made easier, I'm gonna work on that. Also, is it possible/allowed to put code in a pastebin and paste the URL rather than put the code here?
Try changing your query to this:
"SELECT * FROM members WHERE member_id = ?"
and add your param like this:
result.add_parameter(0, id);
I'd also suspect, if (query.exec() && query.next()) is incorrect, and the check for .next() should be removed as I'd imagine that requires another record to exist in the result set.

MySQL call procedure with output parameter from C++ mysqlpp

I need help with the C++ mysqlpp driver calling a stored procedure and retrieving its output parameter. The queries seem to pass successfully but trying to get the stored value causes segmentation fault. My current pseudo code is:
mysqlpp::Connection* connection; // the connection type I am bound to use, no createStatement, prepareStatement methods
Query query = connection->query();
Query transactionQuery = connection->query();
query << "CALL sp_get_transactions_count(" << inputId << ", #transactionsCount);";
transactionQuery << "SELECT #transactionsCount as combinations;";
ClearQuerySentry cleanUpQuery(transactionQuery);
query.exec();
mysqlpp::StoreQueryResult transactionsResult = transactionQuery.store();
if (!transactionsResult || transactionsResult.num_rows() == 0)
{
logWarning(....);
}
else
{
const mysqlpp::Row& transactionRecord = result[0];
environment.pairTransactionsCount = verboseLexicalCast<int>(transactionRecord, "combinations"); // segfault on trying to cast static_cast<const char*>(row[fieldName.c_str()]))
}
I am not very experienced with mysqlpp and MySQL as a whole so it is possible my perception of the solution to be wrong. Thanks in advance.

net-snmp is not changing auth and priv protocol correctly

I'm using the net-snmp library (version 5.7.1) in a c++ programm under Linux. I have a Web-Frontend where a user can choose a SNMP-Version and configure it. SNMPv1 and SNMPv2 are working just fine, but I got some issues with SNMPv3.
Here is a picture of the frontend: Screenshot of Webinterface (Sorry for not uploading it directly here, but I need at least 10 reputation to do this)
When I start the c++ backend and enter all needed SNMPv3 credentials correctly, everything is working fine and the device is reachable. If I change for example the Auth Protocol from MD5 to SHA, but leave the rest of the credentials the same, I would expect that the device is not reachable anymore. In real it stays reachable. After restarting the backend the device is (as expected) not reachable anymore with the same settings.
After discovering this issue, I ran some tests. For the test I used different users and different settings. They were run with three different devices of different vendors and I got every time the same result. So it can not be device realated issue. The results can be seen here: Test results
My conclusion after testing was, that net-snmp seems to cache the selected auth and priv protocol for one user name. This can be seen very good at Test 2. The first time I use an user name with a specific protocol I get the expected result. After changing the protocol
a different result is expected, but I get still the same result as before.
At the end some information how the SNMP-calls are made:
There is a class called SNMPWrapper, which handels the whole SNMP-communication
Inside the constructor I call init_snmp() to init net-snmp
From the outside I can call only get(), set() and walk(). Every time one of these methods is called, a new SNMP-Session is created (First I create a new Session with snmp_sess_init(), than I set up the things needed and finally I open the session with snmp_sess_open()
After I made the request and received my answer I close the session with snmp_sess_close()
Question: Do I have to do any other clean up before changing a protocol in order to get it work correctly?
Edit: I added some code, that shows the described behaviour
int main(int argc, char** argv) {
struct snmp_session session, session1, *ss, *ss1;
struct snmp_pdu *pdu, *pdu1;
struct snmp_pdu *response, *response1;
oid anOID[MAX_OID_LEN];
size_t anOID_len = MAX_OID_LEN;
struct variable_list *vars;
int status, status1;
init_snmp("snmpapp");
const char* user = "md5";
string authpw = "123123123";
string privpw = "";
string ipString = "192.168.15.32";
char ip[16];
memset(&ip, 0, sizeof (ip));
ipString.copy(ip, sizeof (ip) - 1, 0);
/*
* First request: AuthProto is MD5, no PrivProto is used. The snmp-get
* request is successful
*/
snmp_sess_init(&session); /* set up defaults */
session.peername = ip;
session.version = SNMP_VERSION_3;
/* set the SNMPv3 user name */
session.securityName = strdup(user);
session.securityNameLen = strlen(session.securityName);
// set the authentication method to MD5
session.securityLevel = SNMP_SEC_LEVEL_AUTHNOPRIV;
session.securityAuthProto = usmHMACMD5AuthProtocol;
session.securityAuthProtoLen = USM_AUTH_PROTO_MD5_LEN;
session.securityAuthKeyLen = USM_AUTH_KU_LEN;;
if (generate_Ku(session.securityAuthProto,
session.securityAuthProtoLen,
(u_char *) authpw.c_str(), strlen(authpw.c_str()),
session.securityAuthKey,
&session.securityAuthKeyLen) != SNMPERR_SUCCESS) {
//if code reaches here, the creation of the security key was not successful
}
cout << "SecurityAuthProto - session: " << session.securityAuthProto[9] << " / SecurityAuthKey - session: " << session.securityAuthKey << endl;
ss = snmp_open(&session); /* establish the session */
if (!ss) {
cout << "Couldn't open session1 correctly";
exit(2);
}
cout << "SecurityAuthProto - ss: " << ss->securityAuthProto[9] << " / SecurityAuthKey - ss: " << ss->securityAuthKey << endl;
//send message
pdu = snmp_pdu_create(SNMP_MSG_GET);
read_objid(".1.3.6.1.2.1.1.1.0", anOID, &anOID_len);
snmp_add_null_var(pdu, anOID, anOID_len);
status = snmp_synch_response(ss, pdu, &response);
/*
* Process the response.
*/
if (status == STAT_SUCCESS && response->errstat == SNMP_ERR_NOERROR) {
cout << "SNMP-read success" << endl;
} else {
cout << "SNMP-read fail" << endl;
}
if (response)
snmp_free_pdu(response);
if (!snmp_close(ss))
cout << "Snmp closing failed" << endl;
/*
* Second request: Only the authProto is changed from MD5 to SHA1. I expect,
* that the snmp-get fails, but it still succeeds.
*/
snmp_sess_init(&session1);
session1.peername = ip;
session1.version = SNMP_VERSION_3;
/* set the SNMPv3 user name */
session1.securityName = strdup(user);
session1.securityNameLen = strlen(session1.securityName);
// set the authentication method to SHA1
session1.securityLevel = SNMP_SEC_LEVEL_AUTHNOPRIV;
session1.securityAuthProto = usmHMACSHA1AuthProtocol;
session1.securityAuthProtoLen = USM_AUTH_PROTO_SHA_LEN;
session1.securityAuthKeyLen = USM_AUTH_KU_LEN;
if (generate_Ku(session1.securityAuthProto,
session1.securityAuthProtoLen,
(u_char *) authpw.c_str(), strlen(authpw.c_str()),
session1.securityAuthKey,
&session1.securityAuthKeyLen) != SNMPERR_SUCCESS) {
//if code reaches here, the creation of the security key was not successful
}
cout << "SecurityAuthProto - session1: " << session1.securityAuthProto[9] << " / SecurityAuthKey - session1: " << session1.securityAuthKey << endl;
ss1 = snmp_open(&session1); /* establish the session */
if (!ss1) {
cout << "Couldn't open session1 correctly";
exit(2);
}
cout << "SecurityAuthProto - ss1: " << ss1->securityAuthProto[9] << " / SecurityAuthKey - ss1: " << ss1->securityAuthKey << endl;
//send message
pdu1 = snmp_pdu_create(SNMP_MSG_GET);
read_objid(".1.3.6.1.2.1.1.1.0", anOID, &anOID_len);
snmp_add_null_var(pdu1, anOID, anOID_len);
status1 = snmp_synch_response(ss1, pdu1, &response1);
/*
* Process the response.
*/
if (status1 == STAT_SUCCESS && response1->errstat == SNMP_ERR_NOERROR) {
cout << "SNMP-read success" << endl;
} else {
cout << "SNMP-read fail" << endl;
}
if (response1)
snmp_free_pdu(response1);
snmp_close(ss1);
return 0;
}
I found the solution by myself:
net-snmp caches for every EngineId (device) the users. If there is an existing user for an engineID and you try to open a new session with this user, net-snmp will use the cached one. So the solution was to clear the list with cached users.
With this code snippet I could resolve my problem:
usmUser* actUser = usm_get_userList();
while (actUser != NULL) {
usmUser* dummy = actUser;
usm_remove_user(actUser);
actUser = dummy->next;
}
I hope I can help somebody else with this.
You can also update password for an existing user:
for (usmUser* actUser = usm_get_userList(); actUser != NULL; actUser = actUser->next) {
if (strcmp(actUser->secName, user) == 0) {
//this method calls generate_Ku with previous security data but with specified password
usm_set_user_password(actUser, "userSetAuthPass", authpw.c_str());
break;
}
}