Ssl Server using QSslSocket in Qt - qt

I have implemented a ssl server using QSslSocket and run it correctly. But I have some problem with it that I couldn't solve them immediately.
I thought that just connecting readyRead() signal to a slot for reading buffer is sufficient to do that but I have recognized that the readyRead() does not emit at all in this situation and I must also use waitForReadyRead() function in my code. But the problem is using this function cause blocking read the buffer. Actually I want to know how I can read buffer when data has arrived without blocking?
Bellow is my implemented ssl server:
#include "sslserver.h"
#include <QtNetwork/QTcpServer>
#include <QtNetwork/QTcpSocket>
#include <QFile>
#include <QtNetwork/QSslKey>
#include <QtNetwork/QSslConfiguration>
#include <QtNetwork/QSslError>
SslServer::SslServer(QObject *parent) : QTcpServer(parent)
{
server = new QTcpServer(this);
if(!server->listen(QHostAddress::Any, 9996))
{
qDebug() << "Server could not start";
}
else
{
qDebug() << "Server started!";
}
connect(server, SIGNAL(newConnection()), this, SLOT(newConnectionRecognized()));
}
void SslServer::showErrors()
{
this-> err = socket->sslErrors();
for(int i=0;i<err.size();i++)
qDebug() << err[i];
}
SslServer::~SslServer()
{
}
void SslServer::newConnectionRecognized()
{
incomingConnection(server->nextPendingConnection()->socketDescriptor());
}
void SslServer::incomingConnection(qintptr socketDescriptor)
{
socket = new QSslSocket(this);
socket->setProtocol(QSsl::SslV3);
connect(socket, SIGNAL(sslErrors(QList<QSslError>)), this, SLOT(showErrors()));
connect(socket, SIGNAL(encrypted()), this, SLOT(ready()));
connect(socket, SIGNAL(readyRead()), this, SLOT(readChannel()));
// Read Key from file
QByteArray key;
QFile KeyFile("server.key");
if(KeyFile.open(QIODevice::ReadOnly))
{
key = KeyFile.readAll();
KeyFile.close();
}
else
{
qDebug() << KeyFile.errorString();
}
QSslKey sslKey(key, QSsl::Rsa);
socket->setPrivateKey(sslKey);
// Load server ssl certificate from file
QByteArray cert;
QFile CertFile("server.csr");
if(CertFile.open(QIODevice::ReadOnly))
{
cert = CertFile.readAll();
CertFile.close();
}
else
{
qDebug() << CertFile.errorString();
}
QSslCertificate sslCert(cert);
socket->setLocalCertificate(sslCert);
QSslConfiguration cfg = socket->sslConfiguration();
cfg.caCertificates();
if (!socket->setSocketDescriptor(socketDescriptor))ee
{
qDebug() << ("! Couldn't set socket descriptor");
delete socket;
return;
}
socket->startServerEncryption();
if (socket->isEncrypted())
emit socket->encrypted();
if(!socket->waitForEncrypted(3000)) {
qDebug("Wait for encrypted!!!!");
return;
}
while (true) {
socket->waitForReadyRead();
}
}
void SslServer::readChannel()
{
QByteArray qstrbytes = socket->readLine();
qDebug() << qstrbytes;
}
void SslServer::ready()
{
qDebug() << "Encrypted";
}

I have found the problem when I implement another client/server but this time with QTcpSocket. I dont know exactly why but I guess the problem is because of using socketDescriptor for creating a QSslSocket. When I created client and server with QTcpSocket they works perfectly without any event loop and only by connecting readyRead() signal to an slot. After that in order to testing some situation I have create QTcpSocket using socketDescriptor. Then I found the problem is from creating socket using socketDescriptor because this time the readyRead() signal doesn't work as before.

Related

problem with QLocalSocket sending continues data to QLocalServer

I'm trying to send some data from QLocalSocket to QLocalSever in a loop. Sever only gets the first data and not receiving subsequent data, but if I introduce 1 mec delay between each call from the client then the server starts to receive everything. Please check out the below Client & Server code.
client.cpp
#include "client.h"
#include "QDataStream"
#include <QTest>
TestClient::TestClient() : m_socket{new QLocalSocket(this)}{
m_socket->connectToServer("TestServer");
if (m_socket->waitForConnected(1000)) {
qDebug("socket Connected!");
}
connect(m_socket, &QLocalSocket::readyRead, this, &TestClient::onNewData);
}
void TestClient::onNewData() {
qCritical() << "data received from server";
}
void TestClient::sendDataToServer() {
QByteArray block;
QDataStream out(&block, QIODevice::WriteOnly);
out.setVersion(QDataStream::Qt_5_10);
QString testString = "test data";
out << quint32(testString.size());
out << testString;
m_socket->write(block);
m_socket->flush();
}
void TestClient::startClient() {
for(int i = 0; i < 5; i++) {
//QTest::qWait(1); //works if I uncomment this line
sendDataToServer();
}
}
server.cpp
#include "server.h"
TestServer::TestServer() : m_server{new QLocalServer(this)} {
QLocalServer::removeServer("TestServer");
if (!m_server->listen("TestServer")) {
qCritical() << "couldn't connect to server";
}
connect(m_server, &QLocalServer::newConnection, this, &TestServer::onNewConnection);
}
void TestServer::onNewConnection() {
m_socket = m_server->nextPendingConnection();
connect(m_socket, &QLocalSocket::readyRead, this,
&TestServer::onNewData);
connect(m_socket, &QLocalSocket::disconnected, m_socket,
&QLocalSocket::deleteLater);
}
void TestServer::onNewData() {
QLocalSocket* client = qobject_cast<QLocalSocket*>(sender());
client->readAll();
qCritical() << "data read by server";
}
from the qt doc, it's stated that
readyRead() is not emitted recursively; if you reenter the event loop
or call waitForReadyRead() inside a slot connected to the readyRead()
signal, the signal will not be reemitted (although waitForReadyRead()
may still return true).
so is this my problem? adding timer is the only solution here?
You can compile this test project -> http://www.filedropper.com/testsocket

QTcpSocket data arrives late

I am using QTCPSockets to talk to a program I've written in Qt for Raspberry Pi. The same software runs on my Mac (or Windows, whatever). The Pi is running a QTCPServer.
I send JSON data to it and most of the time this goes ok.
But sometimes, the Pi is not responding, the data does not seem to arrive. But then, when I send some more data, that data is not being handled, but the previous Json message is! And this stays like this. All the messages are now off by 1. Sending a new messages, triggers the previous one.
It feels a bit connected to this bugreport: https://bugreports.qt.io/browse/QTBUG-58262
But I'm not sure if it is the same.
I've tried waitForBytesWritten and flush and it seemed to work at first, but later I saw the issue again.
I expect that the TCP buffer on the Pi is not being flushed, but I do now know how to make sure that all data is handled right away.
As asked, here is some sourcecode:
This is the client software:
Client::Client() : tcpSocket(new QTcpSocket(this)), in(tcpSocket)
{
connect(tcpSocket, &QIODevice::readyRead, this, &Client::readData);
connect(tcpSocket, &QTcpSocket::connected, this, &Client::connected);
connect(tcpSocket, &QTcpSocket::stateChanged, this, &Client::onConnectionStateChanged);
void (QAbstractSocket:: *sig)(QAbstractSocket::SocketError) = &QAbstractSocket::error;
connect(tcpSocket, sig, this, &Client::error);
}
void Client::connectTo(QString ip, int port) {
this->ip = ip;
this->port = port;
tcpSocket->connectToHost(ip, port);
}
void Client::reconnect() {
connectTo(ip, port);
}
void Client::disconnect()
{
tcpSocket->disconnectFromHost();
}
void Client::connected()
{
qDebug() << TAG << "connected!";
}
void Client::error(QAbstractSocket::SocketError error)
{
qDebug() << TAG << error;
}
void Client::sendData(const QString& data)
{
bool connected = (tcpSocket->state() == QTcpSocket::ConnectedState);
if (!connected) {
qDebug() << TAG << "NOT CONNECTED!";
return;
}
QByteArray block;
QDataStream out(&block, QIODevice::WriteOnly);
out.setVersion(QDataStream::Qt_5_7);
out << data;
tcpSocket->write(block);
tcpSocket->flush();
}
void Client::sendData(const QByteArray& data) {
bool connected = (tcpSocket->state() == QTcpSocket::ConnectedState);
if (!connected) {
qDebug() << TAG << " is NOT connected!";
return;
}
tcpSocket->write(data);
tcpSocket->flush();
}
void Client::readData()
{
in.startTransaction();
QString data;
in >> data;
if (!in.commitTransaction())
{
return;
}
emit dataReceived(data);
}
void Client::onConnectionStateChanged(QAbstractSocket::SocketState state)
{
switch (state) {
case QAbstractSocket::UnconnectedState:
connectionState = "Not connected";
break;
case QAbstractSocket::ConnectingState:
connectionState = "connecting";
break;
case QAbstractSocket::ConnectedState:
connectionState = "connected";
break;
default:
connectionState = QString::number(state);
}
qDebug() << TAG << " connecting state: " << state;
emit connectionStateChanged(connectionState);
if (state == QAbstractSocket::UnconnectedState) {
QTimer::singleShot(1000, this, &Client::reconnect);
}
}
and here the server part:
Server::Server()
{
tcpServer = new QTcpServer(this);
connect(tcpServer, &QTcpServer::newConnection, this, &Server::handleConnection);
tcpServer->listen(QHostAddress::Any, 59723);
QString ipAddress;
QList<QHostAddress> ipAddressesList = QNetworkInterface::allAddresses();
// use the first non-localhost IPv4 address
for (int i = 0; i < ipAddressesList.size(); ++i) {
if (ipAddressesList.at(i) != QHostAddress::LocalHost &&
ipAddressesList.at(i).toIPv4Address()) {
ipAddress = ipAddressesList.at(i).toString();
break;
}
}
// if we did not find one, use IPv4 localhost
if (ipAddress.isEmpty())
ipAddress = QHostAddress(QHostAddress::LocalHost).toString();
qDebug() << TAG << "ip " << ipAddress << " serverport: " << tcpServer->serverPort();
}
void Server::clientDisconnected()
{
QTcpSocket *client = qobject_cast<QTcpSocket *>(QObject::sender());
int idx = clients.indexOf(client);
if (idx != -1) {
clients.removeAt(idx);
}
qDebug() << TAG << "client disconnected: " << client;
client->deleteLater();
}
void Server::handleConnection()
{
qDebug() << TAG << "incoming!";
QTcpSocket* clientConnection = tcpServer->nextPendingConnection();
connect(clientConnection, &QAbstractSocket::disconnected, this, &Server::clientDisconnected);
connect(clientConnection, &QIODevice::readyRead, this, &Server::readData);
clients.append(clientConnection);
broadcastUpdate(Assets().toJson());
}
void Server::readData()
{
QTcpSocket *client = qobject_cast<QTcpSocket *>(QObject::sender());
QDataStream in(client);
in.startTransaction();
QString data;
in >> data;
if (!in.commitTransaction())
{
return;
}
...
// here I do something with the data. I removed that code as it is
// not necessary for this issue
...
broadcastUpdate(data);
}
void Server::broadcastUpdate(const QString& data)
{
QByteArray block;
QDataStream out(&block, QIODevice::WriteOnly);
out.setVersion(QDataStream::Qt_5_7);
out << data;
foreach(QTcpSocket* client, clients) {
bool connected = (client->state() == QTcpSocket::ConnectedState);
if (!connected) {
qDebug() << TAG << client << " is NOT connected!";
continue;
}
client->write(block);
}
}
I think the problem is with your void Client::readData(): you have to write it in such a way that you read all available data from the socket inside it (usually it's written with while (socket->bytesAvailable() > 0) { ... } loop).
It is because of the way the readyRead() signal is emitted: the remote peer may send any non-zero number of packets to you, and your socket will emit any non-zero number of readyRead() signals. In your case, it seems that the server sends two messages but they only cause one readyRead() signal to be emitted on the client.

QT QTcpServer::incomingConnection(qintptr handle) not firing?

I'm trying to create a multithreaded server using Qt for the first time. Normally one would use the socket pointer returned by the QTcpServer::nextPendingConnection() with the socket handle already baked in - but since I'm interfacing with the connecting client on a separate thread, I need to create the socket separately using the qintptr handle from QTcpServer::incomingConnection(qintptr handle). After a very dreary, error-packed debugging session I managed to track down the problem to the QTcpServer::incomingConnection() never being fired?
Has anyone had a similar problem - has something changed over recent versions Qt?
These are the ones I've tried:
QTcpServer::incomingConnection(qintptr handle)
QTcpServer::incomingConnection(qintptr socketDescriptor)
QTcpServer::incomingConnection(int handle)
EDIT:
Creating instance of server:
TestServer *myServer = new TestServer();
myServer->initializeServer(1234);
Which calls:
void TestServer::initializeServer(quint16 port)
{
mainServer = new QTcpServer(this);
mainServer->listen(QHostAddress::Any, port);
qDebug() << "Listening for connections on port: " << port;
}
Server is now listening. When a client connects incomingConnection(qintptr handle) is supposed to be called:
void TestServer::incomingConnection(qintptr socketDescriptor){
TestClient *client = new TestClient(this);
client->setSocket(socketDescriptor);
}
Which calls:
void TestClient::setSocket(quint16 socketDescr)
{
socket = new QTcpSocket(this);
socket->setSocketDescriptor(socketDescr);
connect(socket, SIGNAL(connected()),this,SLOT(connected()));
connect(socket, SIGNAL(disconnected()),this,SLOT(disconnected()));
connect(socket, SIGNAL(readyRead()),this,SLOT(readyRead()));
}
Called on connect() signal:
void TestClient::connected()
{
qDebug() << "Client connected..."; // This debug never appears in the console, since QTcpServer::incomingConnection isn't being fired.
}
You have some errors at your code:
At TestServer your QTcpServer probably aggregated, but you need to inherit it. At this case you try to override incomingConnection() method, but you haven't base class and you just create new incomingConnection(), not override.
You get qintptr descriptor variable from incomingConnection(), but set quint16 type at setSocket() method.
You probably mix client of server and client of your part, which just get incoming connection and handling socket data.
I write some little example below for your understanding tcp client-server communication.
Server part
Main part is server themselves:
#include <QTcpServer>
class TestServer: public QTcpServer
{
public:
TestServer(QObject *parent = 0);
void incomingConnection(qintptr handle) Q_DECL_OVERRIDE;
};
Just look: I don't aggragate QTcpServer, but inherited it. At this case you can override incomingConnection() method correctly.
At constructor we just start server for listening using listen() method:
TestServer::TestServer(QObject *parent):
QTcpServer(parent)
{
if (this->listen(QHostAddress::Any, 2323)) {
qDebug() << "Server start at port: " << this->serverPort();
} else {
qDebug() << "Start failure";
}
}
Then time for overriding incomingConnection():
void TestServer::incomingConnection(qintptr handle)
{
qDebug() << Q_FUNC_INFO << " new connection";
SocketThread *socket = new SocketThread(handle);
connect(socket, SIGNAL(finished()), socket, SLOT(deleteLater()));
socket->start();
}
I create SocketThread object which handle incoming data:
#include <QThread>
#include <QObject>
class QTcpSocket;
class SocketThread: public QThread
{
Q_OBJECT
public:
SocketThread(qintptr descriptor, QObject *parent = 0);
~SocketThread();
protected:
void run() Q_DECL_OVERRIDE;
private slots:
void onConnected();
void onReadyRead();
void onDisconnected();
private:
QTcpSocket *m_socket;
qintptr m_descriptor;
};
We inherits from QThread for making our server multithreading, so we have to override run() method:
SocketThread::SocketThread(qintptr descriptor, QObject *parent)
: QThread(parent), m_descriptor(descriptor)
{
}
void SocketThread::run()
{
qDebug() << Q_FUNC_INFO;
m_socket = new QTcpSocket;
m_socket->setSocketDescriptor(m_descriptor);
connect(m_socket, SIGNAL(readyRead()), this, SLOT(onReadyRead()), Qt::DirectConnection);
connect(m_socket, SIGNAL(disconnected()), this, SLOT(onDisconnected()), Qt::DirectConnection);
exec();
}
This way we initialize our QTcpSocket, set socket descriptor, connect it with readyRead() and disconnected() signals and start event loop.
void SocketThread::onReadyRead()
{
QDataStream in(m_socket);
in.setVersion(QDataStream::Qt_5_5);
QString message;
in >> message;
qDebug() << message;
m_socket->disconnectFromHost();
}
void SocketThread::onDisconnected()
{
m_socket->close();
// Exit event loop
quit();
}
At onReadyRead() just read some QString from client, write it to console and disconnect from host. At onDisconnected() we close socket connection and exit event loop.
Client part
It is just example and bad-smells style, but i create connection to the server at MainWindow class on QPushButton::clicked signal:
void MainWindow::on_pushButton_clicked()
{
QTcpSocket *client = new QTcpSocket;
connect(client, SIGNAL(connected()), this, SLOT(connected()));
connect(client, SIGNAL(disconnected()), client, SLOT(deleteLater()));
client->connectToHost(QHostAddress::LocalHost, 2323);
client->waitForConnected();
if (client->state() != QAbstractSocket::ConnectedState ) {
qDebug() << Q_FUNC_INFO << " can't connect to host";
delete client;
return;
}
QByteArray block;
QDataStream out(&block, QIODevice::WriteOnly);
out.setVersion(QDataStream::Qt_5_5);
out << QString("Hello");
out.device()->seek(0);
client->write(block);
}
void MainWindow::connected()
{
qDebug() << Q_FUNC_INFO << " client connected";
}
I create new QTcpSocket, connect it to the signals and try to connect to the host(in my case it is localhost). Wait for connected and check socket status. If all is right I write to socket QString - just example.
It is one of possible ways to organized multithreading client-server architecture, i hope it will be helpfull for you and you find yours bugs.

unable to establish two way communication using qt

I have used QTcpSocket and QTcpServer class of qt to establish two way communication. I am able to send data from client to server. But am not getting the response back from server i.e my client.cpp never fires readyRead() signal. I have checked using Wireshark that my data from the server is available in specifed port.
I am posting my client.cpp code( Please help) :
Client::Client(QObject* parent): QObject(parent)
{
socket = new QTcpSocket(this);
connect(socket, SIGNAL(connected()),
this, SLOT(startTransfer()));
connect(socket, SIGNAL(readyRead()),this, SLOT(startRead()));
connect(socket, SIGNAL(error(QAbstractSocket::SocketError)),
this, SLOT(socketError(QAbstractSocket::SocketError)) );
}
Client::~Client()
{
socket->close();
}
void Client::start(QString address, quint16 port)
{
addr.setAddress(address);
socket->connectToHost(addr,port,QTcpSocket::ReadWrite);
}
void Client::startTransfer()
{
printf("Connection established.\n");
char buffer[1024];
forever
{
printf(">> ");
gets(buffer);
int len = strlen(buffer);
buffer[len] = '\n';
buffer[len+1] = '\0';
socket->write(buffer);
socket->flush();
}
}
void Client::startRead()
{
cout<<"inside startRead()<<endl";
while(socket->canReadLine())
{
QByteArray ba = socket->readLine();
if(strcmp(ba.constData(), "!exit\n") == 0)
{
socket->disconnectFromHost();
break;
}
printf(">> %s", ba.constData());
}
}
void Client::socketError(QAbstractSocket::SocketError )
{
qDebug()<<"error" ;
}
Looks like you have forever loop here. This means that your Qt main eventloop never gets the control back after you call startTransfer(). How do you suppose the Qt should run the startRead() code if you block your execution thread with infinite loop?
For Amartel adding the server code:
Server::Server(QObject* parent): QObject(parent)
{
// cout << "Before connect" << endl;
connect(&server, SIGNAL(newConnection()),
this, SLOT(acceptConnection()));
cout << "Listening.." << endl;
server.listen(QHostAddress::Any, 9999);
// cout << "Server started.." << endl;
}
Server::~Server()
{
server.close();
}
void Server::acceptConnection()
{
// cout << "In acceptConnection" << endl;
client = server.nextPendingConnection();
connect(client, SIGNAL(readyRead()),
this, SLOT(startRead()));
}
void Server::startRead()
{
while(client->canReadLine())
{
QByteArray ba = client->readLine();
if(strcmp(ba.constData(), "!exit\n") == 0)
{
client->disconnectFromHost();
break;
}
printf(">> %s", ba.constData());
int result = 0;
bool ack = true;
result = client->write("I Reached");
cout<<result<<endl;
if(result <= 0)
qDebug("Ack NOT sent to client!!!");
else
qDebug("Ack sent to client.");
// client->write("I Reached");
client->flush();
}
}

Qt QUdpSocket readyRead() signal is not triggering

I am trying to write a small UDP server application.
I have a client transmitting to this applications socket and I have verified this is sending ok using a small UDP echo program (which echoes the data received on a port to the screen) and also, I can see the packets received in wireshark.
I am using QUdpSocket and it would appear that this Binds ok on setup - but the readyRead() signal doesn't ever seem to get triggered.
I have included some of my code below - at the minute I am simply trying to emulate the little echo program.
Just to give some context to the below code - a button press on the UI calls 'setupNewSocket' on a port that is typed in on UI.
#include "sockethandler.h"
SocketHandler::SocketHandler(QObject *parent) :
QObject(parent)
{
udpSocket = new QUdpSocket(this);
connect( &w, SIGNAL(openNewUDPSocket(quint16)), this, SLOT(setupNewSocket(quint16)) );
connect( this, SIGNAL(printOnUI(QString,QString,QString)), &w, SLOT(updateUI(QString,QString,QString)) );
w.show();
}
void SocketHandler::readPendingDatagrams()
{
while (udpSocket->hasPendingDatagrams())
{
QByteArray datagram;
datagram.resize(udpSocket->pendingDatagramSize());
QHostAddress sender;
quint16 senderPort;
udpSocket->readDatagram(datagram.data(), datagram.size(), &sender, &senderPort);
QString data = QString( datagram.data() );
QString sender_address = sender.toString();
QString sender_port = QString("%1").arg(senderPort);
emit printOnUI(data, sender_address, sender_port);
}
}
void SocketHandler::setupNewSocket(quint16 port)
{
if( udpSocket->bind(QHostAddress::LocalHost, port) )
{
connect(udpSocket, SIGNAL(readyRead()), this, SLOT(readPendingDatagrams()));
}
else
{
// bind has failed
}
}
QHostAddress::LocalHost binds to 127.0.0.1 .
Probably you need to use QHostAddress::Any which binds to 0.0.0.0.

Resources