Catching and responding to the Connman 'RequestInput' method call with QtDBus - qt

I'm building a simple Qt-based application for monitoring and connecting to WiFi networks. I'm interfacing with Connman via its D-Bus APIs, and am able to scan for available networks, turn on/off technologies and register an agent as expected. I'm currently unable to provide the requested passphrase when the Connman RequestInput method is called (when attempting to connect to a protected/secure network), as I'm unsure how to bind the RequestInput method with a function in Qt.
Below is some indicative code which outlines the approach:
//Create a QDBusConnection systemBus() object
QDBusConnection connection = QDBusConnection::systemBus();
//Ensure the systemBus() connection is established
if (!connection.isConnected()) {
qDebug() << "Connection error.";
}
//Create a Connman Manager D-Bus API interface object
QDBusInterface manager("net.connman", "/", "net.connman.Manager", connection);
//Register an agent with the Connman Manager API
manager.call("RegisterAgent", QVariant::fromValue(QDBusObjectPath("/test/agent")));
//Attempt to bind the mySlot() function with the net.connman.Agent RequestInput method
//This does not currently work
connection.connect("",
"/test/agent",
"net.connman.Agent",
"RequestInput",
this,
SLOT(mySlot(QDBusObjectPath, QVariantMap)));
//Create a Connman Service D-Bus API interface object (for a specific WiFi Service)
QDBusInterface service("net.connman",
"/net/connman/service/[WIFI SERVICE]",
"net.connman.Service",
connection);
//Attempt to connect to the secure WiFi network
//Note: this network has not previously been connected, so the RequestInput method is guaranteed to be called
service.call("Connect");
QVariantMap myClass::mySlot(const QDBusObjectPath &path, const QVariantMap &map)
{
//Connman Agent RequestInput() method received
}
As commented above, the attempted binding of the /test/agent path, net.connman.Agent interface and RequestInput method to the mySlot() function does not work; there are no errors reported but the mySlot() function is never called. If I enable debugging with the QDBUS_DEBUG environment variable, I receive the following:
QDBusConnectionPrivate(0xffff74003a00) got message (signal): QDBusMessage(type=MethodCall, service=":1.3", path="/test/agent", interface="net.connman.Agent", member="RequestInput", signature="oa{sv}", contents=([ObjectPath: /net/connman/service/[WIFI SERVICE]], [Argument: a{sv} {"Passphrase" = [Variant: [Argument: a{sv} {"Type" = [Variant(QString): "psk"], "Requirement" = [Variant(QString): "mandatory"]}]]}]) )
The above is exactly what I'd expect; the RequestInput method is being called for the /test/agent path on the net.connman.Agent interface with the oa{sv} signature.
My questions:
How do I 'connect' to the RequestInput method call, such that my mySlot() function can parse the RequestInput method data?
How do I return the required QVariantMap from within mySlot()?

From the debug output it appears that ConnMan is doing a MethodCall, but QDBusConnection::connect() is for handling DBus singals, which is why your slot is not invoked.
You need to register an object implementing the net.connman.Agent interface onto the corresponding path, so that ConnMan can invoke your methods:
class ConnManAgent : public QObject {
Q_OBJECT
Q_CLASSINFO("D-Bus Interface", "net.connman.Agent")
public:
ConnManAgent(QObject *parent = nullptr);
Q_INVOKABLE QVariantMap RequestInput(const QDBusObjectPath &, const QVariantMap &);
// ... Rest of the net.connman.Agent interface
};
and then register it on the respective path:
connection.registerObject(
QStringLiteral("/test/agent"),
new ConnManAgent(this),
QDBusConnection::ExportAllInvokables);
This exports all methods marked with Q_INVOKABLE to DBus. You might also mark them as Q_SLOTS and use ExportAllSlots, that's mostly up to you.

Related

Actually what is the init parameter in servlet?

Friends tell me what is the core meaning of init parameter in case of a servlet.
I know that how to initialize it in a web.xml but I don't know what is the actual purpose of it why it is required? Please tell me with a good example.
The Javadoc says: "A convenience method which can be overridden so that there's no need to call super.init(config)."
The init method's main purpose is to allow customization while you are initializing the servlet.
The simplest implementation is when you don't want to do any customization according to your application you can always call super.init method.
To understand meaning of what different init params can be there and how init method is useful:
Imagine a system Of BookManagement system, here for adding books and removing books from db you will be needing Database connection over which you can access the data. Now as Servlet's init method is called for the first request and database connection also needs be created only once(or n number of time if doing connection pooling) then initializing the database connection is something that you should do in init method.
A code snippet from Softlab example , let's assume that getInitParameter method reads the databaseUrl and other properties from web.xml
public class DBServlet ... {
Connection connection = null;
public void init() throws ServletException {
// Open a database connection to prepare for requests
try {
databaseUrl = getInitParameter("databaseUrl");
... // get user and password parameters the same way
connection = DriverManager.getConnection(databaseUrl,
user, password);
} catch(Exception e) {
throw new UnavailableException (this,
"Could not open a connection to the database");
}
}
...
}
One more example of counting the number of time servlet was accessed: https://docstore.mik.ua/orelly/java-ent/servlet/ch03_03.htm
So in Summary: To do customization like read the initial values of variable or to initialize resources(like db connection) you can use init method.
Below is the source code of init methods :
public void init(ServletConfig config)throws ServletException
{
this.config = config;
int();
}
public void init() throws ServletException;
It is recommended to override to init() method, not init(ServletConfig).
When overriding init(ServletConfig), the first thing that must be done is to call:
super.init(config);
If you do this then calling directly to getServletContext() in your method will no longer result in an NPE.

Alljoyn: LampStateChange callback is not received from MessageReceiver

I am using About+session Listener to control my lamp device. To receive the lampstatechange notification i have registered the signal handler for lampstatechange at announce (after introspect is success). But my application is not receiving the state change notification. Following are the code snippet i did to register lamp state signal. I am not able to understand what is happening why the callback is not receiving!
const InterfaceDescription* uniqueId = bus.GetInterface(LampServiceStateInterfaceName);
const InterfaceDescription::Member* sig = uniqueId->GetMember("LampStateChanged");
if (sig) {
QStatus sstatus = bus.RegisterSignalHandler(this, static_cast<MessageReceiver::SignalHandler>(&AJDeviceHandler::LampsStateChagedHandler), sig, "/org/allseen/LSF/Lamp");
printf("\n RegisterSignalHandler %s \n",QCC_StatusText(sstatus));
}
I have inherited the following classes of Alljoyn:
class AJDeviceHandler : public AboutListener, public SessionListener, public lsf::Thread, public PingListener, public MessageReceiver
[Note: The state change callback receives perfect when i run lighting_controller_service].

Downloading file over HTTPS using Qt behind authenticating proxy

I am trying to download a file, publicly available over an HTTPS URL, using Qt 4.8. I am behind a corporate authenticating proxy (over which I have no control).
I am using QNetworkAccessManager, as shown below:
bool FileDownloader::download(const QString& fileUrl, const QString& fileName)
{
QString outputFileName = fileName.isEmpty() ? fileNameFromUrl(fileUrl) : fileName;
_file.setFileName(outputFileName);
_file.open(QIODevice::WriteOnly);
QUrl url(fileUrl);
QNetworkReply* pReply = _networkAccessManager.get(QNetworkRequest(url));
pReply->ignoreSslErrors();
connect(pReply, SIGNAL(finished()), _pEventLoop, SLOT(quit()));
connect(pReply, SIGNAL(readyRead()), this, SLOT(onReadyRead()));
connect(pReply, SIGNAL(sslErrors(const QList<QSslError>&)), this, SLOT(onSslErrors(const QList<QSslError>&)));
connect(pReply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(onError(QNetworkReply::NetworkError)));
_pEventLoop->exec();
return true;
}
As soon as I call QNetworkAccessManager::get(), and receive a QNetworkReply object, I connect to its sslErrors signal as mentioned in the docs. Following the same docs, I'm also calling ignoreSslErrors() in the slot connected to that signal:
void FileDownloader::onSslErrors(const QList<QSslError>& sslErrors)
{
QNetworkReply* pReply = (QNetworkReply*)(sender());
pReply->ignoreSslErrors(sslErrors);
}
However, I never receive an sslErrors signal, I always get an error signal, which I'm handling in the onError slot, and which always says:
SSL handshake failed
I'm calling the download functionality thus:
FileDownloader fileDownloader;
fileDownloader.setProxy("http://username:password#proxyserver:8080");
fileDownloader.download(
"https://679cc07dd5c2e4623d32-c8530501a6bee9a6c1860bbdab5cb6f1.ssl.cf2.rackcdn.com/9807/05377d04583309a88e808df5a1758e4e.png",
"f:\\temp\\test.png"
I do not want to use other libraries like libcurl because I don't want to introduce dependencies.
So how can I download the file over HTTPS using Qt?

SocketDescriptor of QTcpSocket is -1

I am designing server/clients system for my own. I create a class with extending from QTcpServer and define QMap <ClientName, int> sockets to handle connected clients. Clients can connect to server when sockets map doesn't contains socket with same ClientName as new client. So, when new socket connects to server, I store client Pair <ClientName, SocketDescriptor> in qmap. With these explanation, I should remove client descriptor from qmap when client disconnects from server. So, I create slot void disconnected() and implement it as follow:
void MyServer::disconnected()
{
QTcpSocket* socket = (QTcpSocket*) sender();
ClientType socketType = ClientTypeNone;
foreach(ClientType key, _sockets.keys())
{
if (sockets.value(key) == socket.socketDescriptor())
{
socketType = key;
break;
}
}
if (socketType != ClientTypeNone)
{
sockets.remove(socketType);
}
}
But, socket.socketDescriptor is -1, while I've set it in below code:
void MyServer::inComingConnection(qintptr socketDescriptor)
{
QTcpSocket* socket = nextPendingConnection();
connect(s, SIGNAL(readyRead()), this, SLOT(readyRead());
connect(s, SIGNAL(disconnected()), this, SLOT(disconnected());
socket->setSocketDescriptor(socketDescriptor);
}
What was it wrong ?
This is the QT Assistant answer,maybe help,
qintptr QTcpServer::socketDescriptor() const
Returns the native socket descriptor the server uses to listen for incoming instructions, or -1 if the server is not listening.
If the server is using QNetworkProxy, the returned descriptor may not be usable with native socket functions.
I think your function inComingConnection should be renamed to incomingConnection to become a valid override one.
But why you're not let Qt setting the descriptor for you?
Accordingly to the Qt Documentation:
void QTcpServer::incomingConnection(qintptr socketDescriptor)
... The base implementation creates a QTcpSocket, sets the socket
descriptor and then stores the QTcpSocket in an internal list of
pending connections. Finally newConnection() is emitted. ...
so that you could simply use addPendingConnection instead:
void MyServer::addPendingConnection(QTcpSocket *s)
{
QTcpServer::addPendingConnection(s);
connect(s, SIGNAL(readyRead()), this, SLOT(readyRead());
connect(s, SIGNAL(disconnected()), this, SLOT(disconnected());
}

Serializing/deserializing derived objects in SignalR

I am using SignalR 1.1 with .NET clients.
I have a single method in my hub that accepts an object of BaseMessage class and broadcasts it to all clients:
public void SendMessage(BaseMessage message)
{
Clients.All.BroadCastMessage(message);
}
Clients will pass derived messages into this method:
_hub.Invoke("SendMessage", new ErrorMessage("Some Error")).Wait();
The client has a single message handler:
_hub.On<BaseMessage>("BroadCastMessage", OnMessageReceived);
I've specified TypeNameHandling.All serializer settings at application startup:
var settings = new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.All};
var serializer = new JsonNetSerializer(settings);
GlobalHost.DependencyResolver.Register(typeof(IJsonSerializer), () => serializer);
But when the client sends a derived message, the server receives a base message.
How should I configure serializer to be able to receive derived messages?
Note: I can do serialization/deserialization manually and pass strings to the server, but this causes double serialization.
SignalR is not supporting this scenario as it would require your JSON payload to contain information about the derived type and assembly. See this sample.
Adding type information in your payload would not play well with browsers. I suggest you create individual hub methods to handle each of your derived types.

Resources