1
0
mirror of https://github.com/DCC-EX/CommandStation-EX.git synced 2024-11-27 01:56:14 +01:00

Buffer overflow resilience

And diag output of replies
This commit is contained in:
Asbelos 2020-10-26 12:59:40 +00:00
parent a16b3a1fa6
commit 6833d82789
4 changed files with 51 additions and 8 deletions

View File

@ -28,11 +28,12 @@ RingStream::RingStream( const uint16_t len)
_pos_read=0;
_buffer[0]=0;
_overflow=false;
_mark=0;
}
size_t RingStream::write(uint8_t byte) {
size_t RingStream::write(uint8_t b) {
if (_overflow) return 0;
_buffer[_pos_write] = byte;
_buffer[_pos_write] = b;
++_pos_write;
if (_pos_write>=_len) _pos_write=0;
if (_pos_write==_pos_read) {
@ -63,3 +64,23 @@ int RingStream::count() {
}
return counter;
}
int RingStream::freeSpace() {
if (_pos_read>_pos_write) return _pos_read-_pos_write-2;
else return _len - _pos_write + _pos_read-2;
}
void RingStream::mark() {
_mark=_pos_write;
}
bool RingStream::commit() {
if (_overflow) {
_pos_write=_mark;
_overflow=false;
return false; // commit failed
}
write((uint8_t)0);
return true; // commit worked
}

View File

@ -30,12 +30,16 @@ class RingStream : public Print {
using Print::write;
int read();
int count();
int freeSpace();
void mark();
bool commit();
private:
int _len;
int _pos_write;
int _pos_read;
bool _overflow;
int _mark;
byte * _buffer;
};

View File

@ -65,9 +65,12 @@ void WifiInboundHandler::loop1() {
cmd[count]=0;
if (Diag::WIFI) DIAG(F("%e\n"),cmd);
outboundRing->mark(); // remember start of outbound data
outboundRing->print(clientId);
CommandDistributor::parse(clientId,cmd,outboundRing);
outboundRing->write((byte)0);
// The commit call will either write the null byte at the end of the output,
// OR rollback to the mark because the commend generated more than fits rthe buffer
outboundRing->commit();
return;
}
}
@ -95,8 +98,11 @@ WifiInboundHandler::INBOUND_STATE WifiInboundHandler::loop2() {
}
if (ch=='>') {
if (Diag::WIFI) DIAG(F("[[XMIT %d]]"),currentReplySize);
for (int i=0;i<currentReplySize;i++) wifiStream->write(outboundRing->read());
for (int i=0;i<currentReplySize;i++) {
int cout=outboundRing->read();
wifiStream->write(cout);
if (Diag::WIFI) StringFormatter::printEscape(cout); // DIAG in disguise
}
outboundRing->read(); // drop the end marker
clientPendingCIPSEND=-1;
pendingCipsend=false;
@ -159,6 +165,12 @@ WifiInboundHandler::INBOUND_STATE WifiInboundHandler::loop2() {
break;
}
if (Diag::WIFI) DIAG(F("\nWifi inbound data(%d:%d):"),runningClientId,dataLength);
if (inboundRing->freeSpace()<=(dataLength+1)) {
// This input would overflow the inbound ring, ignore it
loopState=IPD_IGNORE_DATA;
break;
}
inboundRing->mark();
inboundRing->print(runningClientId); // prefix inbound with client id
loopState=IPD_DATA;
break;
@ -170,11 +182,16 @@ WifiInboundHandler::INBOUND_STATE WifiInboundHandler::loop2() {
inboundRing->write(ch);
dataLength--;
if (dataLength == 0) {
inboundRing->write((byte)0);
inboundRing->commit();
loopState = ANYTHING;
}
break;
case IPD_IGNORE_DATA: // ignoring data that would not fit in inbound ring
dataLength--;
if (dataLength == 0) loopState = ANYTHING;
break;
case GOT_CLIENT_ID: // got x before CLOSE or CONNECTED
loopState=(ch==',') ? GOT_CLIENT_ID2: SKIPTOEND;
break;

View File

@ -32,6 +32,7 @@ class WifiInboundHandler {
IPD5, // got +IPD,c
IPD6_LENGTH, // got +IPD,c, reading length
IPD_DATA, // got +IPD,c,ll,: collecting data
IPD_IGNORE_DATA, // got +IPD,c,ll,: ignoring the data that won't fit inblound Ring
GOT_CLIENT_ID, // clientid prefix to CONNECTED / CLOSED
GOT_CLIENT_ID2, // clientid prefix to CONNECTED / CLOSED
@ -44,8 +45,8 @@ class WifiInboundHandler {
INBOUND_STATE loop2();
Stream * wifiStream;
static const int INBOUND_RING = 200;
static const int OUTBOUND_RING = 1024;
static const int INBOUND_RING = 512;
static const int OUTBOUND_RING = 2048;
RingStream * inboundRing;
RingStream * outboundRing;