1
0
mirror of https://github.com/esp8266/Arduino.git synced 2025-06-17 22:23:10 +03:00

Fixing (maybe) a bug involving multiple received UDP packets.

http://code.google.com/p/arduino/issues/detail?id=669
This commit is contained in:
David A. Mellis
2012-02-14 16:41:22 -08:00
parent 6ab18ea1cc
commit 561cd7054d
2 changed files with 55 additions and 19 deletions

View File

@ -52,15 +52,16 @@ uint8_t EthernetUDP::begin(uint16_t port) {
return 0; return 0;
_port = port; _port = port;
_remaining = 0;
socket(_sock, SnMR::UDP, _port, 0); socket(_sock, SnMR::UDP, _port, 0);
return 1; return 1;
} }
/* Is data available in rx buffer? Returns 0 if no, number of available bytes if yes. /* return number of bytes available in the current packet,
* returned value includes 8 byte UDP header!*/ will return zero if parsePacket hasn't been called yet */
int EthernetUDP::available() { int EthernetUDP::available() {
return W5100.getRXReceivedSize(_sock); return _remaining;
} }
/* Release any resources being used by this EthernetUDP instance */ /* Release any resources being used by this EthernetUDP instance */
@ -116,7 +117,10 @@ size_t EthernetUDP::write(const uint8_t *buffer, size_t size)
int EthernetUDP::parsePacket() int EthernetUDP::parsePacket()
{ {
if (available() > 0) // discard any remaining bytes in the last packet
flush();
if (W5100.getRXReceivedSize(_sock) > 0)
{ {
//HACK - hand-parse the UDP packet using TCP recv method //HACK - hand-parse the UDP packet using TCP recv method
uint8_t tmpBuf[8]; uint8_t tmpBuf[8];
@ -128,8 +132,11 @@ int EthernetUDP::parsePacket()
_remoteIP = tmpBuf; _remoteIP = tmpBuf;
_remotePort = tmpBuf[4]; _remotePort = tmpBuf[4];
_remotePort = (_remotePort << 8) + tmpBuf[5]; _remotePort = (_remotePort << 8) + tmpBuf[5];
_remaining = tmpBuf[6];
_remaining = (_remaining << 8) + tmpBuf[7];
// When we get here, any remaining bytes are the data // When we get here, any remaining bytes are the data
ret = available(); ret = _remaining;
} }
return ret; return ret;
} }
@ -140,34 +147,58 @@ int EthernetUDP::parsePacket()
int EthernetUDP::read() int EthernetUDP::read()
{ {
uint8_t byte; uint8_t byte;
if (recv(_sock, &byte, 1) > 0)
if ((_remaining > 0) && (recv(_sock, &byte, 1) > 0))
{ {
// We read things without any problems // We read things without any problems
_remaining--;
return byte; return byte;
} }
// If we get here, there's no data available // If we get here, there's no data available
return -1; return -1;
} }
int EthernetUDP::read(unsigned char* buffer, size_t len) int EthernetUDP::read(unsigned char* buffer, size_t len)
{ {
/* In the readPacket that copes with truncating packets, the buffer was
filled with this code. Not sure why it loops round reading out a byte if (_remaining > 0)
at a time. {
int i;
for(i=0;i<(int)bufLen;i++) { int got;
recv(_sock,tmpBuf,1);
buf[i]=tmpBuf[0]; if (_remaining <= len)
{
// data should fit in the buffer
got = recv(_sock, buffer, _remaining);
}
else
{
// too much data for the buffer,
// grab as much as will fit
got = recv(_sock, buffer, len);
}
if (got > 0)
{
_remaining -= got;
return got;
}
} }
*/
return recv(_sock, buffer, len); // If we get here, there's no data available or recv failed
return -1;
} }
int EthernetUDP::peek() int EthernetUDP::peek()
{ {
uint8_t b; uint8_t b;
// Unlike recv, peek doesn't check to see if there's any data available, so we must // Unlike recv, peek doesn't check to see if there's any data available, so we must.
if (!available()) // If the user hasn't called parsePacket yet then return nothing otherwise they
// may get the UDP header
if (!_remaining)
return -1; return -1;
::peek(_sock, &b); ::peek(_sock, &b);
return b; return b;
@ -175,7 +206,11 @@ int EthernetUDP::peek()
void EthernetUDP::flush() void EthernetUDP::flush()
{ {
while (available()) // could this fail (loop endlessly) if _remaining > 0 and recv in read fails?
// should only occur if recv fails after telling us the data is there, lets
// hope the w5100 always behaves :)
while (_remaining)
{ {
read(); read();
} }

View File

@ -48,6 +48,7 @@ private:
IPAddress _remoteIP; // remote IP address for the incoming packet whilst it's being processed IPAddress _remoteIP; // remote IP address for the incoming packet whilst it's being processed
uint16_t _remotePort; // remote port for the incoming packet whilst it's being processed uint16_t _remotePort; // remote port for the incoming packet whilst it's being processed
uint16_t _offset; // offset into the packet being sent uint16_t _offset; // offset into the packet being sent
uint16_t _remaining; // remaining bytes of incoming packet yet to be processed
public: public:
EthernetUDP(); // Constructor EthernetUDP(); // Constructor