Comments (1)
Agreed, this is not a clean encapsulation. As you pointed out the limitation is that we cannot rely on the heap (I donβt think we have a malloc on ArduinoZero right?), but moreover this library has to support ArduinoUno where memory space is really limited.
Your modification looks good to me.
Thibault Richard.
From: Jesse Frush [mailto:[email protected]]
Sent: Tuesday, December 29, 2015 11:19 AM
To: arduino-libraries/WiFi101
Subject: [WiFi101] Copy-assignment operator needed in WiFiClient (#15)
Pretext:
- WiFiServer::available(uint8_t*) returns WiFiClient as an object, not a pointer to an object.
- WiFiClass maintains WiFiClient* _client[] cache of pointers to WiFiClient objects, indexed by client socket.
- valid WiFiClient constructors (two of the three) assign WiFi._client[_socket] to this, attempting to cache the address for the most recently constructed WiFiClient object for a given socket.
- WiFiClient::available(), read(), and other functions use m2m_wifi_handle_events(NULL); to load data into a buffer for the client, as stored by WiFiClass cache described above.
Problem
No existing copy-assignment constructor means that the caching in WiFiClass member WiFiClient* _client[] is not always valid. Default implementation of this operator performs memory copy only. Examples provided below.
Examples::
A) WiFiClient object is stored as a global variable in a sketch
WiFiClient client; //stack memory allocated, default ctor invoked
WiFiServer server(23);
setup() { ... }
loop() {
client = server.available(); //(1) (2)
if( client.available() ) //(3)
{
...
}
}
(1) compiler optimization will invoke WiFiClient(uint8_t sock, uint8_t parentsock) ctor here when client is first created (as returned by WiFiServer.available()), this constructor will set WiFi._client[socket] = this. However, since client object is a global object, memory already exists for this object, and copy-assignment operator is invoked. WiFiClass _client cache is now invalid.
(2) Subsequent calls to server.available() will return the cached object, in which the copy-assignment operator will be invoked instead of the copy constructor. WiFiClass cache is invalidated.
(3) this line will update the buffers in the cached WiFiClient object via m2m_wifi_handle_events(NULL);, which is not the same as this client object. When m2m_wifi_handle_events(NULL); finishes, the return value of this client object is _head - _tail, which have not been updated for this object. return value is always 0, even when data has been placed into the cached object.
B) WiFiClient is stored as a member of another class
class WiFi101Stream : public Stream {
private:
WiFiServer _server = WiFiServer(23);
WiFiClient _client;
public:
inline int connect_client()
{
if( !( _client && _client.connected() ) ) {
WiFiClient newClient = _server.available(); //(1) (2)
if( !newClient )
{
return 0;
}
_client = newClient; //(4)
}
return 1;
}
}
(4) Copy constructor is not invoked, only copy-assignment operator. WiFiClass cache still invalid.
Solution
I'd first like to ask why this WiFiClient caching design was used? Inter-dependent classes messing with a common cache in WiFiClass is spaghetti code, proper member encapsulation is not exercised. I imagine it was done to prevent WiFiClient objects from existing on the heap, but I doubt that a class of this very small size would cause issues if the buffers are maintained in a cleanly manner.
I have successfully tested a solution in which the WiFiServer::available() function is converted from a WiFiClient return type to WiFiClient*, in which a newly-constructed client object is first assigned to the WiFiClass _client cache and then returned. Subsequent calls to WiFiServer::available return this cached pointer. This still requires the WiFiClass _client cache to be updated by WiFiServer::available(), but at least the stored address does not have to be overwritten each time this object is passed from function to function, stored as a global object in a sketch, or encapsulated in another class as a member variable. This also prevents the copy-constructor from being invoked during every loop() (as in all of the example sketches).
However, I've assumed the existing design should not be changed (APIs/example sketches would be modified by the above change). I've instead implemented a fix by moving the logic inside the WiFiClient copy constructor to a new setMembersAndWiFiCache(const WiFiClient& other); (disclaimer: naming things is hard) function and adding a copy-assignment operator to this class, which will also call this new function. This will guarantee that if the WiFiClient object is stored in any other way than a scoped variable, the library will function properly. I will create the pull request shortly after this post is submitted and I will add a link in a comment below. I invite you to critique the naming of the new function or any other details.
β
Reply to this email directly or view it on GitHubhttps://github.com//issues/15.
from wifi101.
Related Issues (20)
- Compiler warning about buffer overflow in firmwareVersion() HOT 1
- 'if' statement at WifiClient.cpp:149 is useless HOT 1
- Wifi101 doesn't work once add the freeRTOS library HOT 3
- AP mode with WPA
- Modernize CI system
- HTTPS to sites using LetsEncrypt certificates with MKR1000 fails HOT 1
- Progressively slower transmission and potential buffer handling issue. HOT 5
- AP SSID goes back to default wifi101-xxxx after re-entering provision mode
- Add GitHub Actions workflow to synchronise with shared repository labels
- WiFi.ping(ip) freezes mkr1000 if WiFiUdp.h included
- Infinite stall on WiFiWebServer sample / MKR 1000 HOT 1
- WiFiServer simple improvements
- WiFi.hostname("MKR1000") function has no effects
- Multiple compilation problems on ESP8266 HOT 4
- Library does not work with WINC1500 and Mega2560 HOT 9
- Adafruit Feather M0 WiFi with uFL - ATSAMD21 + ATWINC1500 - fw 19.4.4
- Tx Power Mode
- Turn on WiFi hardware once turned off with WiFi.end()
- MKR1000 no connection with SSL (https) HOT 1
- ATWINC1500 with WiFi101 with MQTT always leads to a dead connection after some time HOT 2
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
π Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. πππ
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google β€οΈ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from wifi101.