khoih-prog / WebSockets_Generic

WebSocket / Socket.IO Server and Client for Arduino based on RFC6455. Now supporting Adafruit nRF52, Portenta_H7, STM32F/L/H/G/WB/MP1, Teensy, SAM DUE, SAMD21, SAMD51, Arduino SAMD21 (Nano 33 IoT), MKR1000 / MKR1010WiFi, RP2040-based boards using WiFi101, WiFiNINA, WiFi, Ethernet, WT32_ETH01, Teensy 4.1 NativeEthernet/QNEthernet or Portenta_H7 WiFi/Ethernet, etc. so that those boards can be voice-controlled by Alexa. Now supporting websocket only mode for Socket.IO. Ethernet_Generic library is used as default for W5x00
GNU General Public License v3.0
90 stars 22 forks source link

Arduino Portenta not connect to SocketIO example #24

Closed elastra21 closed 2 years ago

elastra21 commented 2 years ago

Arduino Portenta not connect to SocketIO example

I'm trying to connect a Arduino Portenta as SocketIO client to the SocketIO server example in this repo and it keeps disconnecting. After a few tries a check if the problem was the portenta or the library so I ran the same example with a ESP-32 and a ESP-8266 and both works but when I try with Portenta keep Disconnecting and it's weird becuase in the Server logs never shows a connection but with ESP32 or ESP8266 shows each time that a client is Connected.

Steps to Reproduce

Information

Example

Start WebSocketClientSocketIO_WiFi on PORTENTA_H7_M7WebSockets_Generic v2.15.0
Connecting to SSID: Lastra
SSID: Lastra
WebSockets Client IP Address: 192.168.0.107
signal strength (RSSI):-62 dBm
Connecting to WebSockets Server @ IP address: 192.168.0.5, port: 8080
[WS] [WS-Client] beginSocketIO with IPAddress
[WS] [WS-Client] beginSocketIO with const char
[WS] WebSockets_Generic v2.15.0
[WS] [wsIOc] found EIO=4 disable EIO ping on client
[WS] [WS-Client] connectedCb
[WS] [WS-Client][connectedCb] Connected to Host:192.168.0.5, Port:8080
[WS] [WS-Client] [sendHeader] Sending header...
[WS] sendHeader: client->cKey = mrl30JBiab+xRJYPbSZE6A==
[WS] [WS-Client] [sendHeader] Handshake:GET /socket.io/?EIO=4&transport=polling HTTP/1.1
Host: 192.168.0.5:8080
Connection: keep-alive
Authorization: 1234567890
User-Agent: arduino-WebSocket-Client

[WS] [write] n:165, t:20558
[WS] [write] Write, Length :165, Left :0
[WS] [WS-Client] [sendHeader] Sending header... Done (us):1110
[WS] [WS-Client][handleHeader] RX:HTTP/1.1 200 OK
[WS] [WS-Client][handleHeader] RX:Content-Type: text/plain; charset=UTF-8
[WS] [WS-Client][handleHeader] RX:Content-Length: 118
[WS] [WS-Client][handleHeader] RX:Date: Fri, 13 May 2022 19:16:21 GMT
[WS] [WS-Client][handleHeader] RX:Connection: keep-alive
[WS] [WS-Client][handleHeader] Header read fin.
[WS] [WS-Client][handleHeader] Client settings:
[WS] [WS-Client][handleHeader] - cURL:/socket.io/?EIO=4
[WS] [WS-Client][handleHeader] - cKey:mrl30JBiab+xRJYPbSZE6A==
[WS] [WS-Client][handleHeader] Server header:

[WS] [WS-Client][handleHeader] - cCode:200
[WS] [WS-Client][handleHeader] - cIsUpgrade:0
[WS] [WS-Client][handleHeader] - cIsWebsocket:1
[WS] [WS-Client][handleHeader] - cAccept:
[WS] [WS-Client][handleHeader] - cProtocol:arduino
[WS] [WS-Client][handleHeader] - cExtensions:
[WS] [WS-Client][handleHeader] - cVersion:0
[WS] [WS-Client][handleHeader] - cSessionId:
[WS] [WS-Client][handleHeader] Still missing cSessionId try Socket.IO
[WS] [WS-Client][handleHeader] socket.io json: 0{"sid":"uHxZNe6cfsiJuPMGAAAL","upgrades":["websocket"],"pingInterval":25000,"pingTimeout":20000,"maxPayload":1000
[WS] [WS-Client][handleHeader] - cSessionId: uHxZNe6cfsiJuPMGAAAL
[WS] [WS-Client][handleHeader] Header read fin.
[WS] [WS-Client][handleHeader] Client settings:
[WS] [WS-Client][handleHeader] - cURL:/socket.io/?EIO=4
[WS] [WS-Client][handleHeader] - cKey:mrl30JBiab+xRJYPbSZE6A==
[WS] [WS-Client][handleHeader] Server header:
[WS] [WS-Client][handleHeader] - cCode:200
[WS] [WS-Client][handleHeader] - cIsUpgrade:0
[WS] [WS-Client][handleHeader] - cIsWebsocket:1
[WS] [WS-Client][handleHeader] - cAccept:
[WS] [WS-Client][handleHeader] - cProtocol:arduino
[WS] [WS-Client][handleHeader] - cExtensions:
[WS] [WS-Client][handleHeader] - cVersion:0
[WS] [WS-Client][handleHeader] - cSessionId:uHxZNe6cfsiJuPMGAAAL
[WS] [WS-Client][handleHeader] found cSessionId
[WS] [WS-Client] [sendHeader] Sending header...
[WS] sendHeader: client->cKey = DTT5PkIBNTgxX3MUKD/XYg==
[WS] [WS-Client] [sendHeader] Handshake:GET /socket.io/?EIO=4&transport=websocket&sid=uHxZNe6cfsiJuPMGAAAL HTTP/1.1
Host: 192.168.0.5:8080
Connection: Upgrade
Upgrade: websocket
Sec-WebSocket-Version: 13
Sec-WebSocket-Key: DTT5PkIBNTgxX3MUKD/XYg==
Sec-WebSocket-Protocol: arduino
Authorization: 1234567890
User-Agent: arduino-WebSocket-Client

[WS] [write] n:314, t:20585
[WS] [write] Write, Length :314, Left :0
[WS] [WS-Client] [sendHeader] Sending header... Done (us):1368
[WS] [WS-Client][handleHeader] RX:000}HTTP/1.1 101 Switching Protocols
[WS] [WS-Client][handleHeader] Header error:000}HTTP/1.1 101 Switching Protocols
[WS] [WS-Client][handleHeader] RX:Upgrade: websocket
[WS] [WS-Client][handleClientData] Header response timeout.. Disconnecting!
[WS] [WS-Client] client disconnected.
[IOc] Disconnected
[WS] [wsIOc] Disconnected!
["event_name",{"now":30001}]
[WS] [WS-Client] connectedCb
[WS] [WS-Client][connectedCb] Connected to Host:192.168.0.5, Port:8080
[WS] [WS-Client] [sendHeader] Sending header...
[WS] sendHeader: client->cKey = ZqaYvn9TscOSf2OKSewQmg==
[WS] [WS-Client] [sendHeader] Handshake:GET /socket.io/?EIO=4&transport=polling HTTP/1.1
Host: 192.168.0.5:8080
Connection: keep-alive
Authorization: 1234567890
User-Agent: arduino-WebSocket-Client
khoih-prog commented 2 years ago

Arduino IDE Version: 2.0.0-rc6

Try using Arduino IDE v1.8.19, not the beta-and-buggy v2.0.0-rcx

Its was OK here WebSocketClientSocketIO_WiFi on Portenta_H7 using WiFi

khoih-prog commented 2 years ago

FYI, just tested using Arduino IDE v1.8.19 and still OK now.

Start WebSocketClientSocketIO_WiFi on PORTENTA_H7_M7
WebSockets_Generic v2.15.0
Connecting to SSID: HueNet1
SSID: HueNet1
WebSockets Client IP Address: 192.168.2.119
signal strength (RSSI):-29 dBm
Connecting to WebSockets Server @ IP address: 192.168.2.30, port: 8080
[WS] [WS-Client][connectedCb] Connected to Host:192.168.2.30, Port:8080
[WS] [wsIOc] Connected to url:/socket.io/?EIO=4
[IOc] Connected to url: /socket.io/?EIO=4
[WS] [wsIOc] get pong
[IOc] Get PONG
[WS] [wsIOc] connected: len = 30
[WS] [wsIOc] data: {"sid":"dqs_yYqGre5KIQ1QAAAB"}
["event_name",{"now":30001}]
[WS] [wsIOc] get event: len = 53
[WS] [wsIOc] get data: ["Send Message io.emit Broadcasted : ",{"now":30001}]
[IOc] Get event: ["Send Message io.emit Broadcasted : ",{"now":30001}]
[WS] [wsIOc] get event: len = 33
[WS] [wsIOc] get data: ["Send Message : ",{"now":30001}]
[IOc] Get event: ["Send Message : ",{"now":30001}]
[WS] [wsIOc] get ping send pong:3
[IOc] Get PING
Server launched on port 8080
Connected
dqs_yYqGre5KIQ1QAAAB
JWT token test:  {
  host: '192.168.2.30:8080',
  connection: 'keep-alive',
  authorization: '1234567890',
  'user-agent': 'arduino-WebSocket-Client'
}
Message from Client :  { now: 30001 }
Message from Client :  { now: 60002 }
Message from Client :  { now: 90003 }
Message from Client :  { now: 120004 }
elastra21 commented 2 years ago

Thanks for responding, I tried. with the Arduino v1.8.19 to see if works but no, I'm still getting the same error. I don't know what I'm doing wrong. I downloaded the example Server and tested with ESP32 and ESP8266 without problems but this one it's driving me crazy.

Screen Shot 2022-05-13 at 5 52 03 PM

?

khoih-prog commented 2 years ago

It's possible that you haven't applied the patch mentioned in [Portenta_H7] WiFi WebServer extremely slow from core v2.7.2 - v3.0.1 #441

Try to use the fix in Drastically speedup client.read() operation #439 by changing in these 2 files

  1. MbedClient.cpp
  2. MbedClient.h

It's very bad that Arduino is so slow to fix the worst and breaking bugs in the core by releasing a new core version



  1. MbedClient.cpp
#include "MbedClient.h"

#ifndef SOCKET_TIMEOUT
#define SOCKET_TIMEOUT 1500
#endif

arduino::MbedClient::MbedClient()
  : _status(false),
    _timeout(0) {
}

uint8_t arduino::MbedClient::status() {
  return _status;
}

void arduino::MbedClient::readSocket() {
  while (1) {
    event->wait_any(0xFF, 100);
    uint8_t data[SOCKET_BUFFER_SIZE];
    int ret = NSAPI_ERROR_WOULD_BLOCK;
    do {
      if (rxBuffer.availableForStore() == 0) {
        yield();
        continue;
      }
      mutex->lock();
      if (sock == nullptr || (closing && borrowed_socket)) {
        goto cleanup;
      }
      ret = sock->recv(data, rxBuffer.availableForStore());
      if (ret < 0 && ret != NSAPI_ERROR_WOULD_BLOCK) {
        goto cleanup;
      }
      if (ret == NSAPI_ERROR_WOULD_BLOCK || ret == 0) {
        yield();
        mutex->unlock();
        continue;
      }
      for (int i = 0; i < ret; i++) {
        rxBuffer.store_char(data[i]);
      }
      mutex->unlock();
      _status = true;
    } while (ret == NSAPI_ERROR_WOULD_BLOCK || ret > 0);
  }
cleanup:
  _status = false;
  return;
}

void arduino::MbedClient::getStatus() {
  event->set(1);
}

void arduino::MbedClient::setSocket(Socket *_sock) {
  sock = _sock;
  configureSocket(sock);
}

void arduino::MbedClient::configureSocket(Socket *_s) {
  _s->set_timeout(_timeout);
  _s->set_blocking(false);

  if (event == nullptr) {
    event = new rtos::EventFlags;
  }
  if (mutex == nullptr) {
    mutex = new rtos::Mutex;
  }
  mutex->lock();
  if (reader_th == nullptr) {
    reader_th = new rtos::Thread(osPriorityNormal - 2);
    reader_th->start(mbed::callback(this, &MbedClient::readSocket));
  }
  mutex->unlock();
  _s->sigio(mbed::callback(this, &MbedClient::getStatus));
  _status = true;
}

int arduino::MbedClient::connect(SocketAddress socketAddress) {

  if (sock && reader_th) {
    // trying to reuse a connection, let's call stop() to cleanup the state
    char c;
    if (sock->recv(&c, 1) < 0) {
      stop();
    }
  }

  if (sock == nullptr) {
    sock = new TCPSocket();
    _own_socket = true;
  }
  if (sock == nullptr) {
    return 0;
  }

  if (static_cast<TCPSocket *>(sock)->open(getNetwork()) != NSAPI_ERROR_OK) {
    return 0;
  }

  address = socketAddress;
  nsapi_error_t returnCode = static_cast<TCPSocket *>(sock)->connect(socketAddress);
  int ret = 0;

  switch (returnCode) {
    case NSAPI_ERROR_IS_CONNECTED:
    case NSAPI_ERROR_OK:
      {
        ret = 1;
        break;
      }
  }

  if (ret == 1) {
    configureSocket(sock);
    _status = true;
  } else {
    _status = false;
  }

  return ret;
}

int arduino::MbedClient::connect(IPAddress ip, uint16_t port) {
  return connect(SocketHelpers::socketAddressFromIpAddress(ip, port));
}

int arduino::MbedClient::connect(const char *host, uint16_t port) {
  SocketAddress socketAddress = SocketAddress();
  socketAddress.set_port(port);
  getNetwork()->gethostbyname(host, &socketAddress);
  return connect(socketAddress);
}

int arduino::MbedClient::connectSSL(SocketAddress socketAddress) {
  if (sock == nullptr) {
    sock = new TLSSocket();
    _own_socket = true;
  }
  if (sock == nullptr) {
    return 0;
  }

  if (beforeConnect) {
    beforeConnect();
  }

  if (static_cast<TLSSocket *>(sock)->open(getNetwork()) != NSAPI_ERROR_OK) {
    return 0;
  }

  address = socketAddress;

restart_connect:
  nsapi_error_t returnCode = static_cast<TLSSocket *>(sock)->connect(socketAddress);
  int ret = 0;

  switch (returnCode) {
    case NSAPI_ERROR_IS_CONNECTED:
    case NSAPI_ERROR_OK:
      {
        ret = 1;
        break;
      }
    case NSAPI_ERROR_IN_PROGRESS:
    case NSAPI_ERROR_ALREADY:
      {
        delay(100);
        goto restart_connect;
      }
  }

  if (ret == 1) {
    configureSocket(sock);
    _status = true;
  } else {
    _status = false;
  }

  return ret;
}

int arduino::MbedClient::connectSSL(IPAddress ip, uint16_t port) {
  return connectSSL(SocketHelpers::socketAddressFromIpAddress(ip, port));
}

int arduino::MbedClient::connectSSL(const char *host, uint16_t port, bool disableSNI) {
  if (!disableSNI) {
    if (sock == nullptr) {
      sock = new TLSSocket();
      _own_socket = true;
    }
    static_cast<TLSSocket *>(sock)->set_hostname(host);
  }

  SocketAddress socketAddress = SocketAddress();
  socketAddress.set_port(port);
  getNetwork()->gethostbyname(host, &socketAddress);
  return connectSSL(socketAddress);
}

size_t arduino::MbedClient::write(uint8_t c) {
  return write(&c, 1);
}

size_t arduino::MbedClient::write(const uint8_t *buf, size_t size) {
  if (sock == nullptr)
    return 0;

  sock->set_blocking(true);
  sock->set_timeout(SOCKET_TIMEOUT);
  int ret = NSAPI_ERROR_WOULD_BLOCK;
  do {
    ret = sock->send(buf, size);
  } while ((ret != size && ret == NSAPI_ERROR_WOULD_BLOCK) && connected());
  configureSocket(sock);
  return size;
}

int arduino::MbedClient::available() {
  int ret = rxBuffer.available();
  return ret;
}

int arduino::MbedClient::read() {
  mutex->lock();
  if (!available()) {
    mutex->unlock();
    return -1;
  }

  int ret = rxBuffer.read_char();
  mutex->unlock();
  return ret;
}

int arduino::MbedClient::read(uint8_t *data, size_t len) {
  mutex->lock();
  int avail = available();

  if (!avail) {
    mutex->unlock();
    return -1;
  }

  if ((int)len > avail) {
    len = avail;
  }

  for (size_t i = 0; i < len; i++) {
    data[i] = rxBuffer.read_char();
  }
  mutex->unlock();

  return len;
}

int arduino::MbedClient::peek() {
  return rxBuffer.peek();
}

void arduino::MbedClient::flush() {
}

void arduino::MbedClient::stop() {
  if (mutex != nullptr) {
    mutex->lock();
  }
  if (sock != nullptr && borrowed_socket == false) {
    if (_own_socket) {
      delete sock;
    } else {
      sock->close();
    }
    sock = nullptr;
  }
  closing = true;
  if (mutex != nullptr) {
    mutex->unlock();
  }
  if (reader_th != nullptr) {
    reader_th->join();
    delete reader_th;
    reader_th = nullptr;
  }
  if (event != nullptr) {
    delete event;
    event = nullptr;
  }
  if (mutex != nullptr) {
    delete mutex;
    mutex = nullptr;
  }
  _status = false;
}

uint8_t arduino::MbedClient::connected() {
  return _status;
}

IPAddress arduino::MbedClient::remoteIP() {
  return SocketHelpers::ipAddressFromSocketAddress(address);
}

uint16_t arduino::MbedClient::remotePort() {
  return 0;
}

void arduino::MbedClient::setTimeout(unsigned long timeout) {
  _timeout = timeout;
}

  1. MbedClient.h
/*
  MbedClient.h - Client implementation using mbed Sockets
  Copyright (c) 2021 Arduino LLC.  All right reserved.

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.

  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Lesser General Public License for more details.

  You should have received a copy of the GNU Lesser General Public
  License along with this library; if not, write to the Free Software
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*/

#ifndef MBEDCLIENT_H
#define MBEDCLIENT_H

#include "Arduino.h"
#include "SocketHelpers.h"
#include "api/Print.h"
#include "api/Client.h"
#include "api/IPAddress.h"
#include "TLSSocket.h"
#include "TCPSocket.h"
#include "rtos.h"

#ifndef SOCKET_BUFFER_SIZE
#define SOCKET_BUFFER_SIZE 256
#endif

namespace arduino {

class MbedClient : public arduino::Client {
private:
  // Helper for copy constructor and assignment operator
  void copyClient(const MbedClient& orig) {
    auto _sock = orig.sock;
    auto _m = (MbedClient*)&orig;
    _m->borrowed_socket = true;
    _m->stop();
    this->setSocket(_sock);
  }

public:
  MbedClient();

  // Copy constructor, to be used when a Client returned by server.available()
  // needs to "survive" event if it goes out of scope
  // Sample usage: Client* new_client = new Client(existing_client)
  MbedClient(const MbedClient& orig) {
    copyClient(orig);
  }

  MbedClient& operator=(const MbedClient& orig) {
    copyClient(orig);
    return *this;
  }  

  virtual ~MbedClient() {
    stop();
  }

  uint8_t status();
  int connect(SocketAddress socketAddress);
  int connect(IPAddress ip, uint16_t port);
  int connect(const char* host, uint16_t port);
  int connectSSL(SocketAddress socketAddress);
  int connectSSL(IPAddress ip, uint16_t port);
  int connectSSL(const char* host, uint16_t port, bool disableSNI = false);
  size_t write(uint8_t);
  size_t write(const uint8_t* buf, size_t size) override;
  int available();
  int read();
  int read(uint8_t* buf, size_t size);
  int peek();
  void flush();
  void stop();
  uint8_t connected();
  operator bool() {
    return sock != nullptr;
  }

  void setSocket(Socket* _sock);
  Socket* getSocket() { return sock; };

  void configureSocket(Socket* _s);

  IPAddress remoteIP();
  uint16_t remotePort();

  void setTimeout(unsigned long timeout);

  friend class MbedServer;
  friend class MbedSSLClient;
  friend class MbedSocketClass;

  using Print::write;

protected:
  virtual NetworkInterface* getNetwork() = 0;
  Socket* sock = nullptr;

  void onBeforeConnect(mbed::Callback<int(void)> cb) {
    beforeConnect = cb;
  }

private:
  RingBufferN<SOCKET_BUFFER_SIZE> rxBuffer;
  bool _status = false;
  bool borrowed_socket = false;
  bool _own_socket = false;
  bool closing = false;
  mbed::Callback<int(void)> beforeConnect;
  SocketAddress address;
  rtos::Thread* reader_th = nullptr;
  rtos::EventFlags* event = nullptr;
  rtos::Mutex* mutex = nullptr;
  unsigned long _timeout;

  void readSocket();
  void getStatus();
};

}

#endif
khoih-prog commented 2 years ago

Also check the following Arduino Forum thread

Portenta H7 WebServer is very slowly

khoih-prog commented 2 years ago

Be sure that you're using WiFiWebServer releases v1.8.0

khoih-prog commented 2 years ago

Good news.

It's very bad that Arduino is so slow to fix the worst and breaking bugs in the core by releasing a new core version

The new ArduinoCore-mbed releases v3.1.1 has just been released to fix the issues.

You can use that new release without manually applying the patch yourself.

elastra21 commented 2 years ago

Thank you verry much for the support, it works with the ArduinoCore-mbed v3.1.1, I didn't tried the the manual patch but the new release work perfect.

And again thank you so much for your time.