PDA

View Full Version : QIODevice read returning 0 bytes on SSL connection



krysak
21st October 2020, 14:01
Hey guys , the issue I have seems similar to this one:
https://www.qtcentre.org/threads/39351-QSslSocket-vs-QTcpSocket-problem

Let me set the context here , we have a client-server application and now we are implementing ssl on its connections.

The implementation seems to work but it is intermitent. During the login process of the application we do many requests for data, problem is that some of them work and some of them don't with no dicerning reason as to why it hangs on a specific part.

The crux of the problem is this method right here:


/**
* \fn tcpClient::readThis( char * data, qint64 maxSize )
* Consumes the bytes from the socket
* @param data buffer that receives the data
* @param maxSize max number of bytes to be read
* @return Returns number of bytes read
*/
qint64 tcpClient::readThis(char * data, qint64 maxSize) {
//debug.dprint( className(), __FUNCTION__, __LINE__, DBG_REDES, " > readThis() %d",maxSize);
qint64 readBuffer,readNow;
char *p;
p = data;
readBuffer = readNow = 0;
while (readBuffer < maxSize) {
disable_rp = true;
readNow=read(p, maxSize - readBuffer);
if (encryptedBytesAvailable() && readNow == 0) {
#ifdef _WIN32
Sleep(1000);
#else
sleep(1);
#endif
}
if (readNow < 0) {
debug.dprint( className(), __FUNCTION__, __LINE__, DBG_REDES, " Grave error reading data from the network!");
return readBuffer;
}
p += readNow;
readBuffer += readNow;
if (readBuffer < maxSize) {

qApp->processEvents();
}
}
disable_rp = false;
return readBuffer;
}




The code eventually gets stuck in this loop due to the fact that this line:


readNow=read(p, maxSize - readBuffer);

Read 0 bytes for no apparent reason.

At some point the maxsize is bigger than 4kb and this bug happens , the first iteration of the loop the readNow reads 4k data then when it starts again to read the rest of the data , readNow gets 0 bytes and we get stuck in a loop.

This code works perfectly without ssl , but when we implemented ssl this happens.

The link I mentioned above seems to be a similar issue that I found on the forums here.

In it I found this:


Your problem is generally the fact that the iodevice has a limited read buffer and your block is larger than it. The approach you are using is generally incorrect, you should be reading the data into your own buffer and only then check the size of your buffer against the size of data you expect.

Either like so:

QByteArray buffer;
while(buffer.size() < blockSize) {
socket->waitForReadyRead();
buffer.append(socket->readAll());
}
doSomethingWith(buffer);

or (better) like so:

QByteArray m_buffer;

void X::onSocketReadyRead(){
m_buffer.append(socket->readAll());
while(m_buffer.size()>=blockSize) processData();
}


Problem is that I'm a relative noob in QT and C++ in general so I would need some guidance on how to use the above code to help me.
What I can say is that we are already using onReadyRead signals , but it's not clear how I can adapt my code to use a buffer and the readAll() method.

ChrisW67
24th October 2020, 01:35
There are two separate parts to the process:

Accumulating the data received
When you have enough data accumulated, do something with it.




QByteArray m_buffer; // <<< this a member variable in the object

void X::onSocketReadyRead(){ // <<< connect to a readyRead() signal, Called if there is some data to read but not necessarily a whole "block"
m_buffer.append(socket->readAll()); // <<< This is Step 1 above
while(m_buffer.size()>=blockSize) // <<< While there is a "block" or more
processData(); // <<< process the data for a block and remove it from m_buffer. Ideally not a long-running process.
// <<< at this point we leave the slot with all complete blocks processed, and less than a whole packet in the buffer. Ready to receive more data
}

Notice that onSocketReadyRead() does not block program flow unless a whole block (or more) has been accumulated.

Anywhere in a "pure" Qt program you see explicit calls to processEvents() or sleep() you are probably polling rather than letting Qt deliver things for you.