SocketDescriptor of QTcpSocket is -1 - qt

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());
}

Related

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

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.

Send data from a Javafx-Client over Websockets to EventBus

I have a Socket handler in Vert.x and I know how to send data through the EventBus in a client-to-server (from Web Browser to Web Server) and server-component-to-server-component fashions.
Now I have a JavaFX-Client connected to the Vert.x Socket handler through websockets:
public void start() {
vertx.createHttpClient()
.setHost(Main.SOCKET_SERVER)
.setPort(8080)
.connectWebsocket("/chat/service", new Handler<WebSocket>() {
#Override
public void handle(WebSocket websocket) {
ws = websocket;
websocket.dataHandler(new Handler<Buffer>() {
#Override
public void handle(Buffer data) {
System.out.println("Received Data");
}
});
//...
// use ws for authentification
ws.writeTextFrame("doAuthentification");
//...
}
}
}
The Socket is connected to "/chat/service".
Now I want to use this Websocket to call different Services from Vert.x. I know that EventBus is not working from JavaFX-Client.
On the server:
ws.dataHandler(new Handler<Buffer>() {
#Override
public void handle(final Buffer data) {
String text = data.toString();
if(text.contentEquals("doAuthentification")){
logger.info("doAuthentification()");
doAuthentification();
}
// ...
}
}
I can now send "commands" like doAuthentification through the WebSocket, then, on server side and when that command is received, I can use the EventBus to process it further.
What would be the correct way using it from a client. Ideas?
Since you application is packaged as a standalone application is not deployed as in a Vert.x instance, you won't be able to call the event-bus since it is a Vert.x specific feature.
Your method to go would be, as you already tyried, to communicate to your Vert.x application in a standard way, through socket, or http for example (I would recommend HTTP and a RESTful application style), and send messages through an entry point that will be later on transferred to the appropriate verticles.
You may need to configure many path based handlers, maybe using a regex capture group inside, and let each handler choose the appropriate schema to delegate events, instead of having a single handler based on hardcoded messages.

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?

QTcpServer never reach incomingConnection

I try to implement my own server class inheriting QTcpServer.
here is the simple code i try to run :
server.cpp
MyServer::MyServer(QObject *parent) :
QTcpServer(parent)
{
}
void MyServer::incomingConnection(qintptr handle)
{
qDebug() << "Incomming";
SecureSocket * socket = new SecureSocket(this);
connect(socket, SIGNAL(StatusMessage(QString)), SIGNAL(StatusMessage(QString)));
socket->Process(handle);
}
main.cpp
MyServer serv;
if(serv.listen(QHostAddress::Any,1080))
console.WriteLine("Listenning on port 1080..."); //Console it's just a class to display message (here it's a simple qDebug())
else {
console.WriteLine("Unable to start server");
}
QThread serverThread;
QObject::connect(&serverThread,SIGNAL(finished()),&serverThread,SLOT(deleteLater()));
serv.moveToThread(&serverThread);
My problem is that I never reach the incommingConnection (I try a https://localhost:1080 in my browser as test client) and I actually don't understand why. The server seems to listen properly because as long as the application run, my browser try to load the page, and set a loading error when I quit the application.
P.S. : It's a console application

Blocking a Qt application during downloading a short file

I'm writing an application using Qt4.
I need to download a very short text file from a given http address.
The file is short and is needed for my app to be able to continue, so I would like to make sure the download is blocking (or will timeout after a few seconds if the file in not found/not available).
I wanted to use QHttp::get(), but this is a non-blocking method.
I thought I could use a thread : my app would start it, and wait for it to finish. The thread would handle the download and quit when the file is downloaded or after a timeout.
But I cannot make it work :
class JSHttpGetterThread : public QThread
{
Q_OBJECT
public:
JSHttpGetterThread(QObject* pParent = NULL);
~JSHttpGetterThread();
virtual void run()
{
m_pHttp = new QHttp(this);
connect(m_pHttp, SIGNAL(requestFinished(int, bool)), this, SLOT(onRequestFinished(int, bool)));
m_pHttp->setHost("127.0.0.1");
m_pHttp->get("Foo.txt", &m_GetBuffer);
exec();
}
const QString& getDownloadedFileContent() const
{
return m_DownloadedFileContent;
}
private:
QHttp* m_pHttp;
QBuffer m_GetBuffer;
QString m_DownloadedFileContent;
private slots:
void onRequestFinished(int Id, bool Error)
{
m_DownloadedFileContent = "";
m_DownloadedFileContent.append(m_GetBuffer.buffer());
}
};
In the method creating the thread to initiate the download, here is what I'm doing :
JSHttpGetterThread* pGetter = new JSHttpGetterThread(this);
pGetter->start();
pGetter->wait();
But that doesn't work and my app keeps waiting. It looks lit the slot 'onRequestFinished' is never called.
Any idea ?
Is there a better way to do what I'm trying to do ?
Instead of using a thread you can just go into a loop which calls processEvents:
while (notFinished) {
qApp->processEvents(QEventLoop::WaitForMore | QEventLoop::ExcludeUserInput);
}
Where notFinished is a flag which can be set from the onRequestFinished slot.
The ExcludeUserInput will ensure that GUI related events are ignored while waiting.
A little late but:
Do not use these wait loops, the correct way is to use the done() signal from QHttp.
The requestFinished signal from what I have seen is just for when your application has finished the request, the data may still be on its way down.
You do not need a new thread, just setup the qhttp:
httpGetFile= new QHttp();
connect(httpGetFile, SIGNAL(done(bool)), this, SLOT(processHttpGetFile(bool)));
Also do not forget to flush the file in processHttpGetFile as it might not all be on the disk.
you have to call QThread::quit() or exit() if you are done - otherwise your thread will run forever...
I chose to implement David's solution, which seemed to be the easiest.
However, I had handle a few more things :
I had to adapt the QEventLoop enum values for Qt4.3.3 (the version I'm using);
I had to track the request Id, to make sure to exit the while loop when the download request is finished, and not when another request is finished;
I added a timeout, to make sure to exit the while loop if there is any problem.
Here is the result as (more or less) pseudo-code :
class BlockingDownloader : public QObject
{
Q_OBJECT
public:
BlockingDownloaderBlockingDownloader()
{
m_pHttp = new QHttp(this);
connect(m_pHttp, SIGNAL(requestFinished(int, bool)), this, SLOT(onRequestFinished(int, bool)));
}
~BlockingDownloader()
{
delete m_pHttp;
}
QString getFileContent()
{
m_pHttp->setHost("www.xxx.com");
m_DownloadId = m_pHttp->get("/myfile.txt", &m_GetBuffer);
QTimer::singleShot(m_TimeOutTime, this, SLOT(onTimeOut()));
while (!m_FileIsDownloaded)
{
qApp->processEvents(QEventLoop::WaitForMoreEvents | QEventLoop::ExcludeUserInputEvents);
}
return m_DownloadedFileContent;
}
private slots:
void BlockingDownloader::onRequestFinished(int Id, bool Error)
{
if (Id == m_DownloadId)
{
m_DownloadedFileContent = "";
m_DownloadedFileContent.append(m_GetBuffer.buffer());
m_FileIsDownloaded = true;
}
}
void BlockingDownloader::onTimeOut()
{
m_FileIsDownloaded = true;
}
private:
QHttp* m_pHttp;
bool m_FileIsDownloaded;
QBuffer m_GetBuffer;
QString m_DownloadedFileContent;
int m_DownloadId;
};
I used QNetworkAccsessManager for same necessity. Because this class managing connections RFC base (6 proccess same time) and non-blocking.
http://qt-project.org/doc/qt-4.8/qnetworkaccessmanager.html
How about giving the GUI some amount of time to wait on the thread and then give up.
Something like:
JSHttpGetterThread* pGetter = new JSHttpGetterThread(this);
pGetter->start();
pGetter->wait(10000); //give the thread 10 seconds to download
Or...
Why does the GUI thread have to wait for the "downloader thread" at all? When the app fires up create the downloader thread, connect the finished() signal to some other object, start the downloader thread, and return. When the thread has finished, it will signal the other object which can resume your process.

Resources