PDA

View Full Version : QSslSocket: connecting SIGNAL and SLOT



Mobility
6th December 2012, 11:05
Hi,

I cannot figure out what is wrong with following code. Code won't compile. I've got a feeling I'm somehow creating the whole connection object wrong, but I guess you guys notice it right away if that's the case. It's interesting that I've seen at least dozen snapshots of code where the socket is created just like this. That's why I'm suspecting the mainwindow.cpp part (below).

Compiling errors:

..\muutoshallinta\client_connection.cpp: In member function 'bool client_connection::init_connection()':
..\muutoshallinta\client_connection.cpp:21: error: invalid conversion from 'QSslSocket*' to 'SOCKET'
..\muutoshallinta\client_connection.cpp:21: error: cannot convert 'const char*' to 'const sockaddr*' for argument '2' to 'int connect(SOCKET, const sockaddr*, int)'
..\muutoshallinta\client_connection.cpp:22: error: invalid conversion from 'QSslSocket*' to 'SOCKET'
..\muutoshallinta\client_connection.cpp:22: error: cannot convert 'const char*' to 'const sockaddr*' for argument '2' to 'int connect(SOCKET, const sockaddr*, int)'

client_connection.cpp:

#include "client_connection.h"
#include "common.h"
#include <QtNetwork>
#include <stdlib.h>
#include "mainwindow.h"

client_connection::client_connection()
{
}

bool client_connection::init_connection()
{
if (!QSslSocket::supportsSsl()) {
return false;
}
ptr_socket = new QSslSocket();

if (!ptr_socket) {

connect(ptr_socket, SIGNAL(encrypted()), this, SLOT(connection_encrypted()));
connect(ptr_socket, SIGNAL(encrypted()), this, SLOT(connection_disconnected()));
/* connect(socket, SIGNAL(readyRead()), this, SLOT(socketReadyRead()));*/
}

ptr_socket->connectToHostEncrypted("localhost", 555);

return true;
}


client_connection.h

#ifndef CLIENT_CONNECTION_H
#define CLIENT_CONNECTION_H
#include <QtNetwork>


class client_connection
{
public:
client_connection();

bool init_connection();


private slots:
void connection_encrypted();
void connection_disconnected();

private:
QSslSocket *ptr_socket;
};

#endif // CLIENT_CONNECTION_H


I'm creating the connection object in mainwindow.cpp:


#ifdef FEA_CLIENT
client_connection *ptr_connection = new client_connection();
if(ptr_connection->init_connection())
{
//connection ready
}
#endif

Thanks in advance!

Lesiok
6th December 2012, 11:52
client_connection must be QObject or use QObject::connect

amleto
6th December 2012, 12:42
cant simply use QObject::connect because client_connection contains slots - these slots won't be correctly moc'd without inheriting from QObject and using Q_OBJECT macro.

Lesiok
6th December 2012, 12:55
My mistake, client_connection must be inherited from QObject.

Mobility
16th December 2012, 17:23
Ok, so I was doing something wrong in the mainwindow while creating the object. Can't just figure out how to do this correctly. Could you guys push me to the right direction with some code?

Thanks for your time!

Edit. Some progress finally:

After editing the client_connection.h like this, it now compiles. Is this what you meant?


#ifndef CLIENT_CONNECTION_H
#define CLIENT_CONNECTION_H
#include <QtNetwork>


class client_connection : public QObject
{
public:
client_connection( ) : QObject( )
{
}

bool init_connection();

private slots:
void connection_encrypted();
void connection_disconnected();

private:
QSslSocket *ptr_socket;
};

#endif // CLIENT_CONNECTION_H

However, now the problem is that I cannot get the encrypted signal. Is it correctly defined, in client_connection.c?

Lesiok
16th December 2012, 18:31
Forgot about the Q_OBJECT macro. Between lines 7 and 8 put :
Q_OBJECT

Mobility
16th December 2012, 18:43
Tried that but getting following error while running:


./debug\mainwindow.o:mainwindow.cpp:(.text$_ZN17clie nt_connectionC1Ev[client_connection::client_connection()]+0x20): undefined reference to `vtable for client_connection'
collect2: ld returned 1 exit status

I'm now wondering if the connection even gets encrypted. The following returns always false saying that connection would not get encrypted...


bool client_connection::init_connection()
{
ptr_socket = new QSslSocket();

if (!ptr_socket) {
// connect(ptr_socket, SIGNAL(encrypted()), this, SLOT(connection_encrypted()));
}

ptr_socket->connectToHostEncrypted("localhost", 555);
if(ptr_socket->waitForEncrypted(2000))
{
return true;
}
return false;
}

wysota
16th December 2012, 23:37
Tried that but getting following error while running:


./debug\mainwindow.o:mainwindow.cpp:(.text$_ZN17clie nt_connectionC1Ev[client_connection::client_connection()]+0x20): undefined reference to `vtable for client_connection'
collect2: ld returned 1 exit status

Run QMake after adding the macro.

Mobility
17th December 2012, 17:23
Ok, QMake did the trick. But the signals are still not working. After debugging a while, I noticed from server side traces that connection - socket - seems to be deleted right after connection is created. Just for a moment, server thinks that connection is fine, but then it finds out that connection is lost. So my thinking is that I'm still not correctly setting up the client_connection as it seems that after running the init_connection() function the socket is lost. How should I set up the connection so that it does not get deleted? Thanks!

Edit after couple of hours...

It really seems that the encryption just fails. I've tried to simplify this as much as possible by putting everything to the mainwindow and not using any slots for the connection:


socket = new QSslSocket();
socket->connectToHostEncrypted("localhost", 555);
if(socket->waitForEncrypted(1000))
{
TRACE("Connected!");
}

Still I don't get the "Connected!" trace. My understanding is that it should not need anything else to get it connected. Right? Still from tester side I can see that connection is set up for a moment. What's wrong here??

ChrisW67
17th December 2012, 23:32
Well:

there may be nothing listening at port 555 on your machine,
something is listening but may not support SSL,
something is listening but it may not complete a full SSL handshake in less than 1 second,
your certificates may be missing/broken/expired/unverifiable,
you may not have the relevant OpenSSL DLL available for on-demand load by your client,
any of a jillion other things.


Have you looked at sslErrors() or error() ?

Mobility
18th December 2012, 06:43
Cheers!

There is a server running. I've tried to use the existing fortuna SSL server example in addition to my own server. And if I use the fortuna client (SSL version) against either one of them, connection succeeds. This implies that the problem is with this client I'm implementing now. My understanding is that certificates are not needed in client side if the server is not requesting them. Anyway I'll have to take a look at the errors you mentioned.

ChrisW67
18th December 2012, 23:43
Client certificates are rarely required, but I was thinking about the server cert. If the server is offering a self-signed certificate (or one signed by an unrecognised CA) then the client cannot verify the server and the connection will not proceed by default.

Mobility
19th December 2012, 11:54
Actually server certificate is self-signed one (created by myself), but I just cannot see why the problem is seen only with the client under implementation. Why the fortuna secure client works fine?

Yesterday I checked the sslErrors() on client side and this was what I found: "The host name did not match any of the valid hosts for this certificate". I have not yet figured out what does that exactly mean in this case. I thought that in this basic scenario on client side it would not check any certificates...

wysota
19th December 2012, 17:40
Actually server certificate is self-signed one (created by myself), but I just cannot see why the problem is seen only with the client under implementation. Why the fortuna secure client works fine?
Because it ignores the error.

See the docs for QSslSocket::ignoreSslErrors().

Mobility
1st January 2013, 17:59
Thanks guys! I did miss that one line which can be used to ignore the SSL errors. After getting the connection working, I managed (with your help) to get also the client_connection class working and now I'm able to send & receive data as planned from any existing class in my program. Thanks again!