PDA

View Full Version : QSslSocket fails to connect to my server.



LaurentDuroisin
23rd January 2016, 07:23
Hi, I would like to make a secure connection to my server, so I've tried this :

Here is the implementation of the server :



#include "fenserveur.h"
#include <iostream>
FenServeur::FenServeur()

{

serveur = new AncServeur(this);
if (!serveur->listen(QHostAddress::Any, 50885)) // Démarrage du serveur sur toutes les IP disponibles et sur le port 50585
{
std::cout<<"Le serveur n'a pas pu être démarré. Raison :<br />"<<serveur->errorString().toStdString();
}
else
{
// Si le serveur a été démarré correctement
std::cout<<"Le serveur a été démarré sur le port : "<<QString::number(serveur->serverPort()).toStdString()<<" Des clients peuvent maintenant se connecter."<<std::endl;
connect(serveur, SIGNAL(nouveauClient(ClientServeur*)), this, SLOT(nouvelleConnexion(ClientServeur*)));
connect(serveur, SIGNAL(sslErreur(const QString &)),this, SLOT(sslErreur(const QString &)) );
}


}
//on affiche les erreurs ssl
void FenServeur::sslErreur(const QString &erreur)
{
std::cout<<"erreur : "<<erreur.toStdString()<<std::endl;
}
void FenServeur::nouvelleConnexion(ClientServeur* nouveauClient)

{

envoyerATous("Un nouveau client vient de se connecter");

connect(nouveauClient, SIGNAL(readyRead()), this, SLOT(donneesRecues()));

connect(nouveauClient, SIGNAL(disconnected()), this, SLOT(deconnexionClient()));

}


void FenServeur::donneesRecues()

{

// 1 : on reçoit un paquet (ou un sous-paquet) d'un des clients


// On détermine quel client envoie le message (recherche du QTcpSocket du client)

QTcpSocket *socket = qobject_cast<QTcpSocket *>(sender());

if (socket == 0) // Si par hasard on n'a pas trouvé le client à l'origine du signal, on arrête la méthode

return;


// Si tout va bien, on continue : on récupère le message

QDataStream in(socket);


if (tailleMessage == 0) // Si on ne connaît pas encore la taille du message, on essaie de la récupérer

{

if (socket->bytesAvailable() < (int)sizeof(quint16)) // On n'a pas reçu la taille du message en entier

return;


in >> tailleMessage; // Si on a reçu la taille du message en entier, on la récupère

}


// Si on connaît la taille du message, on vérifie si on a reçu le message en entier

if (socket->bytesAvailable() < tailleMessage) // Si on n'a pas encore tout reçu, on arrête la méthode

return;



// Si ces lignes s'exécutent, c'est qu'on a reçu tout le message : on peut le récupérer !

QString message;

in >> message;



// 2 : on renvoie le message à tous les clients

envoyerATous(message);


// 3 : remise de la taille du message à 0 pour permettre la réception des futurs messages

tailleMessage = 0;

}


void FenServeur::deconnexionClient()

{

envoyerATous("Un client vient de se déconnecter");


// On détermine quel client se déconnecte

QTcpSocket *socket = qobject_cast<QTcpSocket *>(sender());

if (socket == 0) // Si par hasard on n'a pas trouvé le client à l'origine du signal, on arrête la méthode

return;


clients.removeOne(socket);


socket->deleteLater();

}


void FenServeur::envoyerATous(const QString &message)

{

// Préparation du paquet

QByteArray paquet;

QDataStream out(&paquet, QIODevice::WriteOnly);


out << (quint16) 0; // On écrit 0 au début du paquet pour réserver la place pour écrire la taille

out << message; // On ajoute le message à la suite

out.device()->seek(0); // On se replace au début du paquet

out << (quint16) (paquet.size() - sizeof(quint16)); // On écrase le 0 qu'on avait réservé par la longueur du message



// Envoi du paquet préparé à tous les clients connectés au serveur

for (int i = 0; i < clients.size(); i++)

{

clients[i]->write(paquet);

}


}


And here, the implementation of my client :



#include "fenclient.h"
#include <iostream>

FenClient::FenClient()

{


//on instancie un QSslSocket

socket = new QSslSocket(this);

//on connect les différents signaux

connect(socket, SIGNAL(encrypted()), this, SLOT(ready()));

connect(socket, SIGNAL(readyRead()), this, SLOT(donneesRecues()));

connect(socket, SIGNAL(connected()), this, SLOT(connecte()));

connect(socket, SIGNAL(disconnected()), this, SLOT(deconnecte()));


//on charge la clé privé du client

QFile file( "client-key.pem" );

if( ! file.open( QIODevice::ReadOnly ) )

{

qDebug() << "la clé du client ne peut pas être chargé" <<"client-key.pem";

return;

}

QSslKey key( &file, QSsl::Rsa, QSsl::Pem, QSsl::PrivateKey, "****************" );

file.close();

socket->setPrivateKey( key );



//on charge le certificat du client

socket-> setLocalCertificate( "client-crt.pem" );



//on charge le certificat de notre ca

if( ! socket->addCaCertificates( "ca/ca.pem" ) )

{

qDebug() << "ouverture du certificat de la ca impossible" << "ca/ca.pem";

return;

}

//on supprime la vérification du serveur

socket->setPeerVerifyMode(QSslSocket::VerifyNone);



//on ignore les erreurs car on a un certificat auto signé

socket->ignoreSslErrors();



// On désactive les connexions précédentes s'il y en a

socket->abort();





}
void FenClient::ready() {
//on se connecte au serveur

socket->connectToHostEncrypted("127.0.0.1", 50885);


//on commence l'encryptage

socket->startClientEncryption();
envoyerMessage("Test");
}

void FenClient::envoyerMessage(const QString& message) {
// Préparation du paquet
QByteArray paquet;

QDataStream out(&paquet, QIODevice::WriteOnly);


out << (quint16) 0; // On écrit 0 au début du paquet pour réserver la place pour écrire la taille

out << message; // On ajoute le message à la suite

out.device()->seek(0); // On se replace au début du paquet

out << (quint16) (paquet.size() - sizeof(quint16)); // On écrase le 0 qu'on avait réservé par la longueur du message

socket->write(paquet);
}

// On a reçu un paquet (ou un sous-paquet)

void FenClient::donneesRecues()

{

/* Même principe que lorsque le serveur reçoit un paquet :

On essaie de récupérer la taille du message

Une fois qu'on l'a, on attend d'avoir reçu le message entier (en se basant sur la taille annoncée tailleMessage)

*/

QDataStream in(socket);


if (tailleMessage == 0)

{

if (socket->bytesAvailable() < (int)sizeof(quint16))

return;


in >> tailleMessage;

}


if (socket->bytesAvailable() < tailleMessage)

return;



// Si on arrive jusqu'à cette ligne, on peut récupérer le message entier

QString messageRecu;

in >> messageRecu;

std::cout<<messageRecu.toStdString()<<std::endl;

// On remet la taille du message à 0 pour pouvoir recevoir de futurs messages

tailleMessage = 0;

}


// Ce slot est appelé lorsque la connexion au serveur a réussi

void FenClient::connecte()

{

std::cout<<"Connection réussie!"<<std::endl;

}


// Ce slot est appelé lorsqu'on est déconnecté du serveur

void FenClient::deconnecte()

{

std::cout<<"Déconnecté du serveur"<<std::endl;

}


// Ce slot est appelé lorsqu'il y a une erreur

void FenClient::erreurSocket(QAbstractSocket::SocketErr or erreur)

{

switch(erreur) // On affiche un message différent selon l'erreur qu'on nous indique

{

case QAbstractSocket::HostNotFoundError:

std::cout<<"ERREUR : le serveur n'a pas pu être trouvé. Vérifiez l'IP et le port."<<std::endl;

break;

case QAbstractSocket::ConnectionRefusedError:

std::cout<<"ERREUR : le serveur a refusé la connexion. Vérifiez si le programme \"serveur\" a bien été lancé. Vérifiez aussi l'IP et le port."<<std::endl;

break;

case QAbstractSocket::RemoteHostClosedError:

std::cout<<"ERREUR : le serveur a coupé la connexion."<<std::endl;

break;

default:

std::cout<<"ERREUR : "<<socket->errorString().toStdString()<<std::endl;

}

}


The server start and listen to the port, but when I want to connect the client, it fails and I get this error message :

QSslSocket : cannot resolve SSLv2_client_method
QSslSocket : cannot resolve SSLv2_server_method

Thanks for your help.

PS : My os is unbuntu 14.04

LaurentDuroisin
23rd January 2016, 09:54
Hi!
Now it's connecting but no data is sent to the server.
Solved, I've just forgotten to initialize the tailleMessage var to 0.