Description
I observed crosstalk between clients. For example, a response to a local FTP command was seen on a client doing an HTTP GET.
This crosstalk occurred after a loss of WiFi and subsequent reconnection.
I have limited understanding of the WiFiNINA software and even less understanding of the associated firmware. In reviewing that code, it seemed that the observed crosstalk could happen if multiple WiFi clients were using the same socket to communicate with the WiFi module. The sketch below shows that duplicate assignment of sockets can occur.
#include "arduino_secrets.h" // defines SECRET_SSID and SECRET_PASS
#include <Arduino_ConnectionHandler.h>
WiFiConnectionHandler conMan(SECRET_SSID, SECRET_PASS);
// 'printf' style macro
#define dbprintf(fmt, ...) _dbprintf(fmt, ##__VA_ARGS__)
#define DB_BUF_LEN 256
static char dbBufIn[DB_BUF_LEN] = "";
void _dbprintf(const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
vsnprintf(dbBufIn, DB_BUF_LEN, fmt, ap);
Serial.write(dbBufIn, strlen(dbBufIn));
va_end(ap);
}
#define M2MS 60000 // minutes to ms
uint32_t eventTime[5] {1*M2MS, 2*M2MS, 3*M2MS, 4*M2MS, 5*M2MS}; // events at 1, 2, 3, 4, 5 minutes
bool eventDone[5] {false, false, false, false, false};
/////////////// WiFi users
WiFiClient gclient;
constexpr char gHost[] {"script.google.com"};
constexpr uint16_t gPort {443};
WiFiClient yclient;
constexpr char yHost[] {"yahoo.com"};
constexpr uint16_t yPort {80};
///////////////
void setup() {
Serial.begin(115200);
delay(2000); // routinely takes 1.5 s to begin Serial so just wait 2 s
if (Serial)
dbprintf("\nSuccessfully started serial connection\n");
// part of Arduino_DebugUtils included by Arduino_ConnectionHandler
setDebugMessageLevel(DBG_WARNING); // equals Debug.setDebugLevel
Debug.timestampOn();
conMan.addCallback(NetworkConnectionEvent::CONNECTED, onNetworkConnect);
conMan.addCallback(NetworkConnectionEvent::DISCONNECTED, onNetworkDisconnect);
conMan.addCallback(NetworkConnectionEvent::ERROR, onNetworkError);
// start WiFi
for (uint8_t i=0; i<5; i++) {
delay(500);
conMan.check();
}
// start the WiFi clients
gclient.connect(gHost, gPort);
dbprintf("\t\t\tbegan gclient with socket %u at %u ms\n", gclient._sock, millis());
yclient.connect(yHost, yPort);
dbprintf("\t\t\tbegan yclient with socket %u at %u ms\n", yclient._sock, millis());
printSockets();
} // setup()
void loop() {
if (!eventDone[0] && millis() > eventTime[0]) {
eventDone[0] = true;
dbprintf("\tending WiFi to simulate loss of connection at %u ms\n", millis());
// WiFi.end();
WiFi.disconnect();
delay(5000);
printSockets();
}
if (!eventDone[1] && millis() > eventTime[1]) {
eventDone[1] = true;
dbprintf("\nreconnect (1) clients in reverse order\n");
yclient.connect(yHost, yPort);
dbprintf("\t\t\tbegan yclient with socket %u at %u ms\n", yclient._sock, millis());
gclient.connect(gHost, gPort);
dbprintf("\t\t\tbegan gclient with socket %u at %u ms\n", gclient._sock, millis());
printSockets();
}
conMan.check();
} // loop
void printSockets() {
dbprintf("gclient using socket %u at %6u. Status: %d.\n", gclient._sock, millis(), gclient.status());
dbprintf("yclient using socket %u at %6u. Status: %d.\n", yclient._sock, millis(), yclient.status());
}
void onNetworkConnect() {
Serial.println(">>>>> WiFi CONNECTED to network");
RGB(0, 0, 8);
}
void onNetworkDisconnect() {
Serial.println(">>>>> WiFi DISCONNECTED from network");
Serial.print(">>>>> DISCONNECT reason code: ");
Serial.println(WiFi.reasonCode());
RGB(32, 16, 8);
}
void onNetworkError() {
Serial.println(">>>>> WiFi ERROR");
Serial.print(">>>>> ERROR reason code: ");
Serial.println(WiFi.reasonCode());
RGB(32, 0, 0);
}
void RGB(uint8_t r, uint8_t g, uint8_t b) {
WiFiDrv::pinMode(25, OUTPUT); //GREEN
WiFiDrv::pinMode(26, OUTPUT); //RED
WiFiDrv::pinMode(27, OUTPUT); //BLUE
WiFiDrv::analogWrite(25, g);
WiFiDrv::analogWrite(26, r);
WiFiDrv::analogWrite(27, b);
}
This sketch was executed on a MKR WiFi 1010 using version 1.8.8 of the WiFiNINA library. To see what sockets were being assigned the "_sock" variable in WiFiClient.h was changed from private to public.
Here's an output from the sketch.
Successfully started serial connection
[ 3383 ] Current WiFi Firmware: 1.4.4
>>>>> WiFi CONNECTED to network
began gclient with socket 0 at 7201 ms
began yclient with socket 1 at 7575 ms
gclient using socket 0 at 7575. Status: 4.
yclient using socket 1 at 7575. Status: 4.
ending WiFi to simulate loss of connection at 60001 ms
gclient using socket 0 at 65014. Status: 0.
yclient using socket 1 at 65015. Status: 0.
[ 65015 ] Connection to "Guest" lost.
[ 65015 ] Attempting reconnection
>>>>> WiFi DISCONNECTED from network
>>>>> DISCONNECT with reason code: 8
[ 66877 ] Current WiFi Firmware: 1.4.4
[ 69434 ] Connection to "Guest" failed
>>>>> WiFi CONNECTED to network
reconnect (1) clients in reverse order
began yclient with socket 0 at 120251 ms
began gclient with socket 0 at 120335 ms
gclient using socket 0 at 120335. Status: 4.
yclient using socket 0 at 120335. Status: 4.
Note that at the end both gclient and yclient are using socket 0.
It seems that the WiFiNINA library and the NINA firmware get out of sync on socket assignments.
A partial sequence of events:
restarting WiFi clears all socket assignments;
reconnecting 'yclient' assigns socket 0 to 'gclient'; and
reconnecting 'gclient' results in duplicate assignment of socket 0 because
WiFiClient::connect calls WiFiClient::stop because gclient._sock is 0 indicating that socket 0 is still assigned to 'gclient',
WiFiClient::stop clears the assignment of socket 0, and
socket 0 then gets assigned to 'gclient'.
Any suggestions on how to prevent this issue would be appreciated.