A proxy application which the client side redirect all connections to the server side application.
At the server side, QTcpServer::newConnection() signal is emitted and we connect QTcpSocket::readyRead() signal to our slot which receives the data from client and redirect the data to 3rd party application for handling HTTP/HTTPS requests. readyRead() signal emitted when client sends HTTP request but this does not happen with HTTPS requests.
Tried: Set QTcpServer::proxy() and QTcpSocket::proxy() to QNetworkProxy::NoProxy, use QSslSocket instead of QTcpSocket with ignoreSslErrors().
Code:
Client::Client(QObject *parent, QTcpSocket* clientCon)
: QObject(parent)
{
client = clientCon;
tunnel = new QSslSocket();
if (serverApp) // If application running as server
tunnel->connectToHost("127.0.0.1", 808); // Connect to CCProxy which handle the requests for us
else
{
tunnel->setProxy(QNetworkProxy::NoProxy);
tunnel->ignoreSslErrors();
tunnel->connectToHost(QHostAddress("serverip"), 9090); // Connect to the server side if running as client
}
tunnel->waitForConnected(5000); // 5 seconds timeout
if (tunnel->state() == tunnel->ConnectedState)
{
QObject::connect(client, SIGNAL(readyRead()), this, SLOT(ClientDataReceived()));
QObject::connect(tunnel, SIGNAL(readyRead()), this, SLOT(TunnelDataReceived()));
QObject::connect(client, SIGNAL(disconnected()), this, SLOT(ClientDisconnected()));
QObject::connect(tunnel, SIGNAL(disconnected()), this, SLOT(ClientDisconnected()));
}
}
Client::~Client()
{
}
bool Client::IsTunnelEstablished()
{
return tunnel->state() == tunnel->ConnectedState ? true : false;
}
QString Client::GetTunnelErrorString()
{
return tunnel->errorString();
}
void Client::ClientDataReceived()
{
QByteArray data = client->readAll();
qDebug() << "Client [" << client->peerAddress().toString().remove(" ") << ":" << client->peerPort() << "] Data Received: " << data.size();
qint64 wr = tunnel->write(data, data.size());
if (wr != data.size())
qDebug() << "QTcpSocket::write() failed!"; // Never happened
data.clear();
tunnel->flush();
}
void Client::TunnelDataReceived()
{
QByteArray data = tunnel->readAll();
qDebug() << "Client Tunnel [" << client->peerAddress().toString().remove(" ") << ":" << client->peerPort() << "] Data Received: " << data.size();
client->write(data);
data.clear();
client->flush();
}
void Client::ClientDisconnected()
{
/*if (tunnel->state() == tunnel->ConnectedState)
tunnel->close();*/
qDebug() << "[" << client->peerAddress().toString().remove(" ") << ":" << client->peerPort() << "] Disconnected";
QObject::disconnect(client, SIGNAL(readyRead()), this, SLOT(ClientDataReceived()));
QObject::disconnect(tunnel, SIGNAL(readyRead()), this, SLOT(TunnelDataReceived()));
QObject::disconnect(client, SIGNAL(disconnected()), this, SLOT(ClientDisconnected()));
QObject::disconnect(tunnel, SIGNAL(disconnected()), this, SLOT(ClientDisconnected()));
client->deleteLater();
tunnel->deleteLater();
delete this; // Self delete
}
Server Initialization:
void BaseProtocol::StartServer()
{
server = new QTcpServer();
server->setProxy(QNetworkProxy::NoProxy);
server->listen(QHostAddress("0.0.0.0"), serverApp ? 9090 : 5050); // 9090 for server, 5050 for client
qDebug() << QObject::connect(server, SIGNAL(newConnection()), this, SLOT(ClientConnecting()));
}
void BaseProtocol::ClientConnecting()
{
QTcpSocket *client = server->nextPendingConnection(); // Accept the connection
qDebug() << "Client Connected: " << client->peerAddress().toString() << ":" << client->peerPort();
Client* clientHandler = new Client(this, client);
if (!clientHandler->IsTunnelEstablished())
{
qDebug() << "Tunnel Connection Failed: " << clientHandler->GetTunnelErrorString() << "\n";
client->disconnect();
client->deleteLater();
delete clientHandler;
}
}
As you see the client and server application are the same but start with different ports. The reason why I use a client side application instead of connecting to the server as proxy directly is because I want to encrypt the data between client and server later. (same problem also exist when connecting directly to server side)
This is supposed to be a transparent proxy so there is no need for SSL/TLS at all.
"Internet Options" are used to set the proxy server to "127.0.0.1:5050" at the client side.
Related
I'm having trouble sending data from a server to a client using Qt. Whenever I do QTcpSocket::waitForBytesWritten() after a call to QTcpSocket::write(...), it returns false.
I tried using the bytesWritten signal, but that never gets emitted, presumably because no data is able to be written, and no data is received on the client side.
The writeData method is what is being called in the MainWindow class, but to try and narrow down the cause of the problem, I moved the writing of data to the client into the newConnection method.
The message Connection received is printed to the output window. I'm sending the string Some random data in the newConnection method to the client for testing purposes, but this is not being received by the client (the code to output the received data on the client side is inside Character::readData() method).
The value of the returnValue variable is true, and the code returns from the call to the client->waitForBytesWritten(-1) method. client->errorString() gives Unknown error, and then the message Bytes written is printed (even though, evidently, nothing is written, but I'm just using it as a status message).
Server.cpp
#include "Server.h"
Server::Server(QObject *parent) : QObject(parent)
{
server = new QTcpServer(this);
qDebug() << connect(server, SIGNAL(newConnection()), SLOT(newConnection()));
qDebug() << connect(server, SIGNAL(bytesWritten()), SLOT(bytesWritten()));
qDebug() << "Listening:" << server->listen(QHostAddress::Any, 1451);
server->waitForNewConnection(-1);
}
void Server::newConnection()
{
qDebug("Connection received");
client = server->nextPendingConnection();
client->write("Some random data\n");
bool returnValue = client->flush();
qDebug() << "Return value: " << returnValue;
qDebug() << client->waitForBytesWritten(-1);
qDebug() << "Error: " << client->errorString();
qDebug() << "Bytes written";
}
void Server::bytesWritten(qint64 bytes)
{
qDebug() << "Bytes written: " << QString::number(bytes);
}
void Server::writeData(std::string data)
{
QByteArray byteArray = QByteArray(data.c_str());
qDebug() << "Write data: " << QString::fromStdString(data);
client->write(byteArray);
}
Client.cpp
#include "Client.h"
#include "mainwindow.h"
Client::Client(QObject* parent) : QObject(parent)
{
socket = new QTcpSocket(this);
(void)QObject::connect(socket, SIGNAL(connected()), this, SLOT(connected()));
qDebug() << "Connect signal" << QObject::connect(socket, SIGNAL(readyRead()), this, SLOT(readData()));
}
bool Client::connectToHost(QString host)
{
socket->connectToHost(host, 1451);
socket->waitForConnected();
qDebug() << "Error: " << QString::number(socket->error() == QAbstractSocket::UnknownSocketError);
return true;
}
void Client::connected()
{
qDebug("Socket is connected");
qDebug() << QString::number(socket->state() == QAbstractSocket::ConnectedState);
}
void Client::readData()
{
qDebug("Read data");
QTcpSocket* sender = static_cast<QTcpSocket*>(QObject::sender());
QByteArray data = sender->readAll();
std::string character = data.toStdString();
qDebug() << "Character received: " << QString::fromStdString(character);
MainWindow::characterReceived(character);
}
I would have to send Modbus request for specific data, my problem is that I have to use mobile communication, wifi, connect to a custom electronic card, which is right in Modbus RTU.
My working code connecting to the electronic board:
#include "connessione.h"
#include <QModbusTcpClient>
#include <QVariant>
#include <QModbusDataUnit>
#include <QDebug>
connessione::connessione(QObject *parent) : QObject(parent)
{
qDebug() << "here debug " << "ok";
clientX = new QModbusTcpClient();
clientX->setConnectionParameter(QModbusDevice::NetworkAddressParameter, "192.168.222.1");
clientX->setConnectionParameter(QModbusDevice::NetworkPortParameter, 5555);
if (clientX->connectDevice())
{
qDebug() << "connected: " << clientX->state();
}
else
{
qDebug() << "ERRORE" << clientX->errorString();
}
}
void connessione::clickButton(){
QModbusDataUnit readUnit(QModbusDataUnit::HoldingRegisters, 0, 1); // just read input register 40006
//qDebug() << "readUnit" << readUnit.RegisterType;
qDebug() << "readUnit" << clientX->state();
if (auto *reply = clientX->sendReadRequest(readUnit, 255)) // client id 255
{
if (!reply->isFinished())
{
// connect the finished signal of the request to your read slot
qDebug() << "connected" << reply->errorString();
connect(reply, &QModbusReply::finished, this, &connessione::readReady);
}
else
{
qDebug() << "Errore" << reply->errorString();
delete reply; // broadcast replies return immediately
}
}
else
{
qDebug() << "Errore" << reply->errorString();
// request error
}
}
void connessione::readReady()
{
QModbusReply *reply = qobject_cast<QModbusReply *>(sender());
if (!reply)
return;
if (reply->error() == QModbusDevice::NoError)
{
const QModbusDataUnit unit = reply->result();
int startAddress = unit.startAddress(); // the start address,
int value = unit.value(0); // value of the start address + 0
qDebug() << "NESSUN ERRORE" << reply->errorString();
}
else
{
qDebug() << "Errore readReady" << reply->errorString();
// reply error
}
reply->deleteLater(); // delete the reply
}
log string TCP sent:
D/libmodbusMobile.so( 8042): (null):0 ((null)): qt.modbus: (TCP
client) Sent TCP PDU: 0x0300000001 with tId: 2
this is right: 0x0300000001
But unfortunately, my electronic card, the integrated firmware I can not modify, is right with Modbus RTU, so I should change 0x0300000001 to 0x010300000001C1C2 where C1 and C2 are the checksums.
I believe that QModbusDataUnit generate buffer to send. So how to change it? Exist manual solution where I build the buffer?
how to change it and create custom send buffer like the example?
Thanks
I am using Qt 4.8 GCC 32bit on xUbuntu 14.04.
I have the following piece of code, a TCP server that I use in order to get some remote commands and send back some answers - via TCP socket:
struct _MyRequest
{
unsigned long Request;
unsigned long Data;
} __attribute__((packed));
struct _MyAnswer
{
unsigned long Error;
unsigned long Filler;
} __attribute__((packed));
_MyRequest request;
_MyAnswer answer;
RemoteCmdServer::RemoteCmdServer(QObject * parent)
: QTcpServer(parent)
{
qDebug() << "Server started";
listen(QHostAddress("172.31.250.110"), 5004);
connect(this, SIGNAL(newConnection()), this, SLOT(processPendingRequest()));
}
void RemoteCmdServer::processPendingRequest()
{
qDebug() << "Process request";
QTcpSocket * clientConnection = nextPendingConnection();
connect(clientConnection, SIGNAL(disconnected()), clientConnection, SLOT(deleteLater()));
// get the request
int ret = clientConnection->read((char*)&request, sizeof(request));
qDebug() << "READ: " << ret;
if(ret == sizeof(request))
{
// send answer
clientConnection->write((char*)&answer, sizeof(answer));
}
qDebug() << "Disconnecting...";
clientConnection->disconnectFromHost();
}
I am able to write correctly if I comment the if(ret == sizeof(request)) line.
Yet, I can't read from the socket (I always get 0 bytes).
I am 100% sure that the TCP-tool I use to send packets to my app works ok.
Here is the debug output from my app:
Server started
Process request
READ: 0
Disconnecting...
What am I doing wrong? Please advise!
You should wait for the data either in a non-blocking or blocking way. You can use waitForReadyRead to do it in a blocking way.
void RemoteCmdServer::processPendingRequest()
{
qDebug() << "Process request";
QTcpSocket * clientConnection = nextPendingConnection();
connect(clientConnection, SIGNAL(disconnected()), clientConnection, SLOT(deleteLater()));
if (clientConnection->waitForReadyRead())
{
// get the request
QByteArray message = clientConnection->readAll(); // Read message
qDebug() << "Message:" << QString(message);
}
else
{
qDebug().nospace() << "ERROR: could not receive message (" << qPrintable(clientConnection->errorString()) << ")";
}
qDebug() << "Disconnecting...";
clientConnection->disconnectFromHost();
}
You're trying to read data from the new connection without returning to the Qt event loop -- I don't think that's going to work.
After you've accepted the connect with...
QTcpSocket * clientConnection = nextPendingConnection();
You need to connect to its readyRead signal with something like...
connect(clientConnection, SIGNAL(readyRead()), this, SLOT(my_read_slot()));
Where my_read_slot is the member function that will actually perform the read operation.
I have a server that can handle multiple threads. The server starts and listens, but it is having trouble echoing when an incoming connection is pending.
I am using telnet to open the socket and send data to the server. However, the server only displays that it's listening, but doesn't echo any of the data I type through telnet or signify that there is an incoming connection. I shut off Windows firewall for private networks and still...nothing.
Also tried seeing if the server error string had anything useful to say, but all it is just an empty string.
This is a complete mystery to me and if anyone had anything constructive to note, it'd be much appreciated. Code for the thread and server is below.
server.cpp
#include "myserver.h"
MyServer::MyServer(QObject *parent) :
QTcpServer(parent)
{
}
void MyServer::StartServer()
{
if(!this->listen(QHostAddress::Any,1234))
{
qDebug() << "Could not start server";
}
else
{
qDebug() << "Listening...";
}
}
void MyServer::incomingConnection(int socketDescriptor)
{
qDebug() << socketDescriptor << " Connecting...";
MyThread *thread = new MyThread(socketDescriptor,this);
connect(thread, SIGNAL(finished()),thread, SLOT(deleteLater()));
thread->start();
}
thread.cpp
#include "mythread.h"
MyThread::MyThread(int ID, QObject *parent) :
QThread(parent)
{ this->socketDescriptor = ID;
}
void MyThread::run()
{
qDebug() << socket->errorString();
//thread starts here
qDebug() << socketDescriptor << " Starting thread";
socket = new QTcpSocket();
if(!socket->setSocketDescriptor(this->socketDescriptor))
{
emit error(socket->error());
return;
}
connect(socket,SIGNAL(readyRead()),this,SLOT(readyRead()),Qt::DirectConnection);
connect(socket,SIGNAL(disconnected()),this,SLOT(disconnected()),Qt::DirectConnection);
qDebug() << socketDescriptor << " Client Connected";
exec();
}
void MyThread::readyRead()
{
QByteArray Data = socket->readAll();
qDebug() << socketDescriptor << " Data in: " << Data;
socket->write(Data);
}
void MyThread::disconnected()
{
qDebug() << socketDescriptor << " Disconnected";
socket->deleteLater();
exit(0);
}
Which version of Qt are you using? In Qt 5, the parameter for the function incomingConnection is of type qintptr and not int. Have a look at the following links:
incomingConnection - Qt 5
Qt 5 - Multithreaded server tutorial
I am using QUdpSocket in order to receive data from a server. When i receive data With SFML its working, i can receive data throught SocketUdp but with qt it doesn't work.
void TheClass::Bind()
{
m_sock_receive = new QUdpSocket(this);
if (m_sock_receive->bind(QHostAddress::Any, port))
{
std::cout << "Bind: OK" << std::endl;
connect(m_sock_receive, SIGNAL(readyRead()), this, SLOT(QtReceive()));
}
else
std::cout << "Bind: NOK" << std::endl;
}
void TheClass::QtReceive()
{
std::cout << "Pending data !" << std::endl;
}
I would make the connect before the bind. It's possible that after binding, the readyRead fires before the connect call is completed. If you don't empty the pending datagrams, the readyRead will not fire again.
In order to connect SIGNAL(readyRead()) to any slot, the QUdpSocket must be in a QAbstractSocket::BoundState. Although you call bind before connect, the bind on QUdpSocket makes a non-blocking call, meaning, that the bind might be delayed. To ensure that you connect the SIGNAL(readyRead()) to SLOT(QtReceive()) after the bind has finished and the QUdpSocket is in a bound state, do the following:
void TheClass::Bind()
{
m_sock_receive = new QUdpSocket(this);
connect(m_sock_receive, SIGNAL(stateChanged(QAbstractSocket::SocketState)),
this, SLOT(onSocketStateChange(QAbstractSocket::SocketState)));
if (m_sock_receive->bind(QHostAddress::Any, port))
{
std::cout << "Bind: OK" << std::endl;
}
else
std::cout << "Bind: NOK" << std::endl;
}
void TheClass::QtReceive()
{
std::cout << "Pending data !" << std::endl;
}
void TheClass::onSocketStateChange (QAbstractSocket::SocketState state) {
if ( state == QAbstractSocket::BoundState ) {
connect(m_sock_receive, SIGNAL(readyRead()), this, SLOT(QtReceive()));
}
}