Problem with TScWebSocketClient over TLS and receiving larger data
Posted: Thu 20 May 2021 20:51
We are using TScWebSocketClient to communicate with a specific proprietary software and we have noticed that everything works fine until we need to receive a larger ammount of data - the limit seems to be cca 16KB.
I have managed to recreate the problem with a simple node.js websocket server and I have discovered, that the problem seems to be related to TLS. If I disable TLS on server and do connect with ws:// URL, everything works fine. If I enable TLS and do connect with wss:// URL then it works only for smaller data. For larger data it seems to hang in the FDecryptedBuffer.WaitForData call in :
More specifically it seems to read the frame header, payload length and cca 2048 bytes of data. It also seems that there are cca 14KB more data waiting in FDecryptedBuffer but the call requests even more and the WaitForData timeouts (sidenote: it is interesting that function named ReadNoWait does call WaitForData with some timeout :-) ). Then after a few function returns with result=0 exception is raised: raise SocketException.Create(SConnectionClosed); The onMessage handler is not called at all.
I tried adding a stunnel into the chain and it seems to work with my node.js server (I did not have a opportunity to test it against the real target software). It works that the TScWebsocket is talking without TLS with STUNNEL, the STUNNEL does TLS connect to the websocket server and relays the data. So basically for TScWebsocket it is the same as not using TLS but I do not have the possibility to disable TLS in the real world target software. So this is to chech whether the problem is more probably in TScWebsocket TLS client than in SocketServer TLS server. And hopefully it will work as workaround until I will be able to make TScWebsocket work...
Some details:
I have managed to recreate the problem with a simple node.js websocket server and I have discovered, that the problem seems to be related to TLS. If I disable TLS on server and do connect with ws:// URL, everything works fine. If I enable TLS and do connect with wss:// URL then it works only for smaller data. For larger data it seems to hang in the FDecryptedBuffer.WaitForData call in :
Code: Select all
ScSocketController.pas:178
function TSecureSocketController.ReadNoWait(const Buffer: TValueArr; Offset, Count: integer): integer;
begin
RaiseLastError;
FDecryptedBuffer.WaitForData(1, cardinal(FOptions.Timeout));
Result := FDecryptedBuffer.Read(Buffer, Offset, Count);
if (Result = 0) and not FVio.Connected then
Result := -1;
RaiseLastError;
end;
I tried adding a stunnel into the chain and it seems to work with my node.js server (I did not have a opportunity to test it against the real target software). It works that the TScWebsocket is talking without TLS with STUNNEL, the STUNNEL does TLS connect to the websocket server and relays the data. So basically for TScWebsocket it is the same as not using TLS but I do not have the possibility to disable TLS in the real world target software. So this is to chech whether the problem is more probably in TScWebsocket TLS client than in SocketServer TLS server. And hopefully it will work as workaround until I will be able to make TScWebsocket work...
Some details:
- Delphi 10.3, SecureBridge: 9.5.1 .
- The only specific setting for the websocket is disabling certificate checking
- I've tried setting TLS1.2 and TLS1.3
- I am using asynchronous mode with onMessage but I tried a little the synchronous with Receive and it behaved the same
Code: Select all
const fs = require('fs');
const https = require('https');
const http = require('http');
const WebSocket = require('ws'); //npm install ws
const server = https.createServer({
cert: fs.readFileSync('./ssl.cer'),
key: fs.readFileSync('./ssl.key')
});
//const server = http.createServer({ //uncomment for http
// });
const wss = new WebSocket.Server({ server });
wss.on('connection', function connection(ws,req)
{
console.log ('Connection from %s, url: %s , protocol: %s',req.socket.remoteAddress, req.url, ws.protocol);
ws.on('message', function incoming(message)
{
console.log('received: %s', message);
let resp=60KB of data;
ws.send(JSON.stringify(resp));
});
});
server.listen(31416);