Skip to content

Commit b3174a6

Browse files
committed
Move ClientContext write behaviour into strategies
1 parent 3b2ea52 commit b3174a6

File tree

7 files changed

+350
-97
lines changed

7 files changed

+350
-97
lines changed

libraries/ESP8266WebServer/src/ESP8266WebServer.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ template<typename T> size_t streamFile(T &file, const String& contentType){
125125
sendHeader("Content-Encoding", "gzip");
126126
}
127127
send(200, contentType, "");
128-
return _currentClient.write(file, HTTP_DOWNLOAD_UNIT_SIZE);
128+
return _currentClient.write(file);
129129
}
130130

131131
protected:

libraries/ESP8266WiFi/src/WiFiClient.cpp

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ extern "C"
4040
#include "lwip/netif.h"
4141
#include "include/ClientContext.h"
4242
#include "c_types.h"
43+
#include "include/DataStrategyImpl.h"
4344

4445
uint16_t WiFiClient::_localPort = 0;
4546

@@ -172,35 +173,34 @@ size_t WiFiClient::write(const uint8_t *buf, size_t size)
172173
{
173174
return 0;
174175
}
176+
BufferStrategy strategy(buf, size, _timeout);
177+
return _client->write(strategy);
178+
}
175179

176-
return _client->write(reinterpret_cast<const char*>(buf), size);
180+
size_t WiFiClient::write(Stream& stream, size_t unused)
181+
{
182+
return WiFiClient::write(stream);
177183
}
178184

179-
size_t WiFiClient::write_P(PGM_P buf, size_t size)
185+
size_t WiFiClient::write(Stream& stream)
180186
{
181-
if (!_client || !size)
187+
if (!_client || !stream.available())
182188
{
183189
return 0;
184190
}
191+
ChunkedStrategy<Stream> strategy(stream, stream.available(), _timeout);
192+
return _client->write(strategy);
193+
}
185194

186-
char chunkUnit[WIFICLIENT_MAX_PACKET_SIZE + 1];
187-
chunkUnit[WIFICLIENT_MAX_PACKET_SIZE] = '\0';
188-
size_t remaining_size = size;
189-
190-
while (buf != NULL && remaining_size > 0) {
191-
size_t chunkUnitLen = WIFICLIENT_MAX_PACKET_SIZE;
192-
193-
if (remaining_size < WIFICLIENT_MAX_PACKET_SIZE) chunkUnitLen = remaining_size;
194-
// due to the memcpy signature, lots of casts are needed
195-
memcpy_P((void*)chunkUnit, (PGM_VOID_P)buf, chunkUnitLen);
196-
197-
buf += chunkUnitLen;
198-
remaining_size -= chunkUnitLen;
199-
200-
// write is so overloaded, had to use the cast to get it pick the right one
201-
_client->write((const char*)chunkUnit, chunkUnitLen);
195+
size_t WiFiClient::write_P(PGM_P buf, size_t size)
196+
{
197+
if (!_client || !size)
198+
{
199+
return 0;
202200
}
203-
return size;
201+
ProgmemSource ps(buf, size);
202+
ChunkedStrategy<ProgmemSource> strategy(ps, size, _timeout);
203+
return _client->write(strategy);
204204
}
205205

206206
int WiFiClient::available()

libraries/ESP8266WiFi/src/WiFiClient.h

Lines changed: 4 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,10 @@ class WiFiClient : public Client, public SList<WiFiClient> {
4949
virtual size_t write(uint8_t);
5050
virtual size_t write(const uint8_t *buf, size_t size);
5151
size_t write_P(PGM_P buf, size_t size);
52-
template <typename T>
53-
size_t write(T& source, size_t unitSize);
52+
size_t write(Stream& stream);
53+
54+
// This one is deprecated, use write(Stream& instead)
55+
size_t write(Stream& stream, size_t unitSize) __attribute__ ((deprecated));
5456

5557
virtual int available();
5658
virtual int read();
@@ -73,28 +75,6 @@ class WiFiClient : public Client, public SList<WiFiClient> {
7375
void setNoDelay(bool nodelay);
7476
static void setLocalPortStart(uint16_t port) { _localPort = port; }
7577

76-
template<typename T> size_t write(T &src){
77-
uint8_t obuf[WIFICLIENT_MAX_PACKET_SIZE];
78-
size_t doneLen = 0;
79-
size_t sentLen;
80-
int i;
81-
82-
while (src.available() > WIFICLIENT_MAX_PACKET_SIZE){
83-
src.read(obuf, WIFICLIENT_MAX_PACKET_SIZE);
84-
sentLen = write(obuf, WIFICLIENT_MAX_PACKET_SIZE);
85-
doneLen = doneLen + sentLen;
86-
if(sentLen != WIFICLIENT_MAX_PACKET_SIZE){
87-
return doneLen;
88-
}
89-
}
90-
91-
uint16_t leftLen = src.available();
92-
src.read(obuf, leftLen);
93-
sentLen = write(obuf, leftLen);
94-
doneLen = doneLen + sentLen;
95-
return doneLen;
96-
}
97-
9878
friend class WiFiServer;
9979

10080
using Print::write;
@@ -114,24 +94,4 @@ class WiFiClient : public Client, public SList<WiFiClient> {
11494
static uint16_t _localPort;
11595
};
11696

117-
118-
template <typename T>
119-
inline size_t WiFiClient::write(T& source, size_t unitSize) {
120-
std::unique_ptr<uint8_t[]> buffer(new uint8_t[unitSize]);
121-
size_t size_sent = 0;
122-
while(true) {
123-
size_t left = source.available();
124-
if (!left)
125-
break;
126-
size_t will_send = (left < unitSize) ? left : unitSize;
127-
source.read(buffer.get(), will_send);
128-
size_t cb = write(buffer.get(), will_send);
129-
size_sent += cb;
130-
if (cb != will_send) {
131-
break;
132-
}
133-
}
134-
return size_sent;
135-
}
136-
13797
#endif

libraries/ESP8266WiFi/src/WiFiClientSecure.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ extern "C"
3939
#include "lwip/netif.h"
4040
#include "include/ClientContext.h"
4141
#include "c_types.h"
42+
#include "include/DataStrategyImpl.h"
4243

4344
#ifdef DEBUG_ESP_SSL
4445
#define DEBUG_SSL
@@ -468,7 +469,10 @@ extern "C" int ax_port_write(int fd, uint8_t* buffer, size_t count) {
468469
errno = EIO;
469470
return -1;
470471
}
471-
size_t cb = _client->write((const char*) buffer, count);
472+
473+
// TODO: add a way to pass timeout here (e.g. through ClientContext?)
474+
BufferStrategy strategy(buffer, count, 5000);
475+
size_t cb = _client->write(strategy);
472476
if (cb != count) {
473477
errno = EAGAIN;
474478
}

libraries/ESP8266WiFi/src/include/ClientContext.h

Lines changed: 34 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -29,15 +29,18 @@ typedef void (*discard_cb_t)(void*, ClientContext*);
2929
extern "C" void esp_yield();
3030
extern "C" void esp_schedule();
3131

32+
#include "DataStrategy.h"
33+
3234
class ClientContext {
3335
public:
3436
ClientContext(tcp_pcb* pcb, discard_cb_t discard_cb, void* discard_cb_arg) :
35-
_pcb(pcb), _rx_buf(0), _rx_buf_offset(0), _discard_cb(discard_cb), _discard_cb_arg(discard_cb_arg), _refcnt(0), _next(0), _send_waiting(false) {
37+
_pcb(pcb), _rx_buf(0), _rx_buf_offset(0), _discard_cb(discard_cb), _discard_cb_arg(discard_cb_arg), _refcnt(0), _next(0) {
3638
tcp_setprio(pcb, TCP_PRIO_MIN);
3739
tcp_arg(pcb, this);
3840
tcp_recv(pcb, (tcp_recv_fn) &_s_recv);
3941
tcp_sent(pcb, &_s_sent);
4042
tcp_err(pcb, &_s_error);
43+
tcp_poll(pcb, &_s_poll, 1);
4144
}
4245

4346
err_t abort(){
@@ -47,6 +50,7 @@ class ClientContext {
4750
tcp_sent(_pcb, NULL);
4851
tcp_recv(_pcb, NULL);
4952
tcp_err(_pcb, NULL);
53+
tcp_poll(_pcb, NULL, 0);
5054
tcp_abort(_pcb);
5155
_pcb = 0;
5256
}
@@ -61,6 +65,7 @@ class ClientContext {
6165
tcp_sent(_pcb, NULL);
6266
tcp_recv(_pcb, NULL);
6367
tcp_err(_pcb, NULL);
68+
tcp_poll(_pcb, NULL, 0);
6469
err = tcp_close(_pcb);
6570
if(err != ERR_OK) {
6671
DEBUGV(":tc err %d\r\n", err);
@@ -211,40 +216,38 @@ class ClientContext {
211216
return _pcb->state;
212217
}
213218

214-
size_t write(const char* data, size_t size) {
215-
if(!_pcb) {
216-
DEBUGV(":wr !_pcb\r\n");
219+
size_t getSendBufferSize()
220+
{
221+
if (!_pcb) {
217222
return 0;
218223
}
224+
return tcp_sndbuf(_pcb);
225+
}
219226

220-
if(size == 0) {
221-
return 0;
222-
}
223-
224-
size_t room = tcp_sndbuf(_pcb);
225-
size_t will_send = (room < size) ? room : size;
226-
err_t err = tcp_write(_pcb, data, will_send, 0);
227-
if(err != ERR_OK) {
228-
DEBUGV(":wr !ERR_OK\r\n");
229-
return 0;
227+
bool write(const uint8_t* data, size_t size)
228+
{
229+
if (!_pcb) {
230+
return false;
230231
}
232+
err_t err = tcp_write(_pcb, data, size, 0);
233+
tcp_output(_pcb);
234+
return err == ERR_OK;
235+
}
231236

232-
_size_sent = will_send;
233-
DEBUGV(":wr\r\n");
234-
tcp_output( _pcb );
235-
_send_waiting = true;
236-
delay(5000); // max send timeout
237-
_send_waiting = false;
238-
DEBUGV(":ww\r\n");
239-
return will_send - _size_sent;
237+
size_t write(DataStrategy& strategy) {
238+
_strategy = &strategy;
239+
auto ret = strategy.write(*this);
240+
_strategy = nullptr;
241+
return ret;
240242
}
241243

242244
private:
243245

244246
err_t _sent(tcp_pcb* pcb, uint16_t len) {
245247
DEBUGV(":sent %d\r\n", len);
246-
_size_sent -= len;
247-
if(_size_sent == 0 && _send_waiting) esp_schedule();
248+
if (_strategy) {
249+
_strategy->on_sent(*this, len);
250+
}
248251
return ERR_OK;
249252
}
250253

@@ -279,8 +282,6 @@ class ClientContext {
279282
}
280283

281284
if(_rx_buf) {
282-
// there is some unread data
283-
// chain the new pbuf to the existing one
284285
DEBUGV(":rch %d, %d\r\n", _rx_buf->tot_len, pb->tot_len);
285286
pbuf_cat(_rx_buf, pb);
286287
} else {
@@ -292,18 +293,21 @@ class ClientContext {
292293
}
293294

294295
void _error(err_t err) {
295-
DEBUGV(":er %d %d %d\r\n", err, _size_sent, _send_waiting);
296+
DEBUGV(":er %d %08x\r\n", err, (uint32_t) _strategy);
296297
tcp_arg(_pcb, NULL);
297298
tcp_sent(_pcb, NULL);
298299
tcp_recv(_pcb, NULL);
299300
tcp_err(_pcb, NULL);
300301
_pcb = NULL;
301-
if(_size_sent && _send_waiting) {
302-
esp_schedule();
302+
if (_strategy) {
303+
_strategy->on_error(*this);
303304
}
304305
}
305306

306307
err_t _poll(tcp_pcb* pcb) {
308+
if (_strategy) {
309+
_strategy->on_poll(*this);
310+
}
307311
return ERR_OK;
308312
}
309313

@@ -335,8 +339,7 @@ class ClientContext {
335339
int _refcnt;
336340
ClientContext* _next;
337341

338-
size_t _size_sent;
339-
bool _send_waiting;
342+
DataStrategy* _strategy = nullptr;
340343
};
341344

342345
#endif//CLIENTCONTEXT_H
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/* DataStrategy.h - interface for writing data to ClientContext
2+
* Copyright (c) 2016 Ivan Grokhotkov. All rights reserved.
3+
* This file is distributed under MIT license.
4+
*/
5+
6+
#ifndef DATASTRATEGY_H
7+
#define DATASTRATEGY_H
8+
9+
10+
#include "ClientContext.h"
11+
12+
class DataStrategy
13+
{
14+
public:
15+
virtual ~DataStrategy() {}
16+
virtual size_t write(ClientContext& ctx) = 0;
17+
virtual void on_sent(ClientContext& ctx, size_t size) = 0;
18+
virtual void on_error(ClientContext& ctx) = 0;
19+
virtual void on_poll(ClientContext& ctx) = 0;
20+
};
21+
22+
/// in DataStrategyImpl.h
23+
24+
25+
#endif//DATASTRATEGY_H

0 commit comments

Comments
 (0)