This code reproduces the problem:
I'm trying to use EthernetClient::connectNoWait() to establish connections non-blocking. It seemed reasonable that EthernetClient::connected() would be a way to poll for completion of the connection. Except EthernetClient::connected() permanently returns false, even when use of WireShark clearly shows the SYN/SYN-ACK/ACK flow on the wire. And when connecting to my PC on the LAN, a test server application registers that a connection has been accepted. EthernetClient:
perator bool() suffers the same problem, even though its logic is slightly different.
So I did a bit of digging into EthernetClient::connected(), and added a debug line to it as follows:
As expected, the debug line was executed, indicating that conn_->remaining is indeed empty. Hardly a surprise, it appears that the remaining vector is part of the read logic, and I'd expect it to be empty if the connection hasn't yet been established.
Modifying EthernetClient::connected() as follows causes the test program above and my main application to start working at lease as far as EthernetClient::connectNoWait() is concerned, but that's a change that I can't make for the long term, because 40+ years of programming experience tells me that doing so will almost certainly break something else.
The solution I'd use is to change the first line so that instead of just blindly testing !conn_->connected, that test is also guarded by something that determines we don't yet have a connection because the initial three-way handshake hasn't completed. Only if that condition is true would we check for !conn_->connected. I just don't know how to do that. Once that change is made, the commented out logic can be restored, and the routine should then continue to work correctly.
Code:
#include <QNEthernet.h>
using namespace qindesign::network;
EthernetClient client;
bool connected = false;
void PrintString(char const *s)
{
Serial.print(s);
}
// the setup routine runs once when you press reset:
void setup()
{
Serial.print("Starting ...");
Ethernet.begin();
IPAddress ipAddress;
for (int i = 0; i < 300; i++)
{
ipAddress = Ethernet.localIP();
if (ipAddress)
{
Serial.println(".");
break;
}
Serial.print(".");
delay(100);
}
Serial.printf("IP Address: %d.%d.%d.%d\r\n", ipAddress[0], ipAddress[1], ipAddress[2], ipAddress[3]);
uint8_t mac[6];
Ethernet.macAddress(mac);
Serial.printf("Mac Address: %02x:%02x:%02x:%02x:%02x:%02x\r\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
ipAddress = IPAddress(52, 250, 42, 157); // IP Address of duckduckgo.com: 52.250.42.157
client.connectNoWait(ipAddress, 443); // Connect to SSL port.
}
// the loop routine runs over and over again forever:
void loop()
{
if (!connected && client.connected())
{
connected = true;
Serial.print("Connection has been established\r\n");
}
delay(1);
}
I'm trying to use EthernetClient::connectNoWait() to establish connections non-blocking. It seemed reasonable that EthernetClient::connected() would be a way to poll for completion of the connection. Except EthernetClient::connected() permanently returns false, even when use of WireShark clearly shows the SYN/SYN-ACK/ACK flow on the wire. And when connecting to my PC on the LAN, a test server application registers that a connection has been accepted. EthernetClient:
So I did a bit of digging into EthernetClient::connected(), and added a debug line to it as follows:
Code:
uint8_t EthernetClient::connected() {
if (conn_ == nullptr) {
return false;
}
if (!conn_->connected && conn_->remaining.empty()) {
PrintString("EthernetClient::connected() setting conn_ to nullptr\r\n"); // This line added
conn_ = nullptr;
return false;
}
Ethernet.loop(); // Allow information to come in
return true;
}
As expected, the debug line was executed, indicating that conn_->remaining is indeed empty. Hardly a surprise, it appears that the remaining vector is part of the read logic, and I'd expect it to be empty if the connection hasn't yet been established.
Modifying EthernetClient::connected() as follows causes the test program above and my main application to start working at lease as far as EthernetClient::connectNoWait() is concerned, but that's a change that I can't make for the long term, because 40+ years of programming experience tells me that doing so will almost certainly break something else.
Code:
uint8_t EthernetClient::connected() {
if (conn_ == nullptr || !conn_->connected) {
return false;
}
//if (!conn_->connected && conn_->remaining.empty()) {
// SPS("EthernetClient::connected() setting conn_ to nullptr\r\n");
// conn_ = nullptr;
// return false;
//}
Ethernet.loop(); // Allow information to come in
return true;
}
The solution I'd use is to change the first line so that instead of just blindly testing !conn_->connected, that test is also guarded by something that determines we don't yet have a connection because the initial three-way handshake hasn't completed. Only if that condition is true would we check for !conn_->connected. I just don't know how to do that. Once that change is made, the commented out logic can be restored, and the routine should then continue to work correctly.