1
0
mirror of https://github.com/DCC-EX/CommandStation-EX.git synced 2024-11-23 16:16:13 +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; _pos_read=0;
_buffer[0]=0; _buffer[0]=0;
_overflow=false; _overflow=false;
_mark=0;
} }
size_t RingStream::write(uint8_t byte) { size_t RingStream::write(uint8_t b) {
if (_overflow) return 0; if (_overflow) return 0;
_buffer[_pos_write] = byte; _buffer[_pos_write] = b;
++_pos_write; ++_pos_write;
if (_pos_write>=_len) _pos_write=0; if (_pos_write>=_len) _pos_write=0;
if (_pos_write==_pos_read) { if (_pos_write==_pos_read) {
@ -63,3 +64,23 @@ int RingStream::count() {
} }
return counter; 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; using Print::write;
int read(); int read();
int count(); int count();
int freeSpace();
void mark();
bool commit();
private: private:
int _len; int _len;
int _pos_write; int _pos_write;
int _pos_read; int _pos_read;
bool _overflow; bool _overflow;
int _mark;
byte * _buffer; byte * _buffer;
}; };

View File

@ -65,9 +65,12 @@ void WifiInboundHandler::loop1() {
cmd[count]=0; cmd[count]=0;
if (Diag::WIFI) DIAG(F("%e\n"),cmd); if (Diag::WIFI) DIAG(F("%e\n"),cmd);
outboundRing->mark(); // remember start of outbound data
outboundRing->print(clientId); outboundRing->print(clientId);
CommandDistributor::parse(clientId,cmd,outboundRing); 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; return;
} }
} }
@ -95,8 +98,11 @@ WifiInboundHandler::INBOUND_STATE WifiInboundHandler::loop2() {
} }
if (ch=='>') { if (ch=='>') {
if (Diag::WIFI) DIAG(F("[[XMIT %d]]"),currentReplySize); for (int i=0;i<currentReplySize;i++) {
for (int i=0;i<currentReplySize;i++) wifiStream->write(outboundRing->read()); int cout=outboundRing->read();
wifiStream->write(cout);
if (Diag::WIFI) StringFormatter::printEscape(cout); // DIAG in disguise
}
outboundRing->read(); // drop the end marker outboundRing->read(); // drop the end marker
clientPendingCIPSEND=-1; clientPendingCIPSEND=-1;
pendingCipsend=false; pendingCipsend=false;
@ -159,6 +165,12 @@ WifiInboundHandler::INBOUND_STATE WifiInboundHandler::loop2() {
break; break;
} }
if (Diag::WIFI) DIAG(F("\nWifi inbound data(%d:%d):"),runningClientId,dataLength); 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 inboundRing->print(runningClientId); // prefix inbound with client id
loopState=IPD_DATA; loopState=IPD_DATA;
break; break;
@ -170,11 +182,16 @@ WifiInboundHandler::INBOUND_STATE WifiInboundHandler::loop2() {
inboundRing->write(ch); inboundRing->write(ch);
dataLength--; dataLength--;
if (dataLength == 0) { if (dataLength == 0) {
inboundRing->write((byte)0); inboundRing->commit();
loopState = ANYTHING; loopState = ANYTHING;
} }
break; 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 case GOT_CLIENT_ID: // got x before CLOSE or CONNECTED
loopState=(ch==',') ? GOT_CLIENT_ID2: SKIPTOEND; loopState=(ch==',') ? GOT_CLIENT_ID2: SKIPTOEND;
break; break;

View File

@ -32,6 +32,7 @@ class WifiInboundHandler {
IPD5, // got +IPD,c IPD5, // got +IPD,c
IPD6_LENGTH, // got +IPD,c, reading length IPD6_LENGTH, // got +IPD,c, reading length
IPD_DATA, // got +IPD,c,ll,: collecting data 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_ID, // clientid prefix to CONNECTED / CLOSED
GOT_CLIENT_ID2, // clientid prefix to CONNECTED / CLOSED GOT_CLIENT_ID2, // clientid prefix to CONNECTED / CLOSED
@ -44,8 +45,8 @@ class WifiInboundHandler {
INBOUND_STATE loop2(); INBOUND_STATE loop2();
Stream * wifiStream; Stream * wifiStream;
static const int INBOUND_RING = 200; static const int INBOUND_RING = 512;
static const int OUTBOUND_RING = 1024; static const int OUTBOUND_RING = 2048;
RingStream * inboundRing; RingStream * inboundRing;
RingStream * outboundRing; RingStream * outboundRing;