Skip to content

Commit

Permalink
implementation of dynamically allocated UDP buffers
Browse files Browse the repository at this point in the history
  • Loading branch information
m-mcgowan committed Jun 14, 2015
1 parent 51ccb43 commit 8ce95c0
Show file tree
Hide file tree
Showing 2 changed files with 155 additions and 43 deletions.
95 changes: 89 additions & 6 deletions wiring/inc/spark_wiring_udp.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,37 +32,120 @@
#include "spark_wiring_stream.h"
#include "socket_hal.h"

#define RX_BUF_MAX_SIZE 512

class UDP : public Stream, public Printable {
private:
/**
* The underlying socket handle from the HAL.
*/
sock_handle_t _sock;

/**
* The local port this UDP socket is bound to.
*/
uint16_t _port;

/**
* The IP address of the peer that sent the received packet.
* Available after parsePacket().
*/
IPAddress _remoteIP;

/**
* The port of the peer that send the received packet.
* Available after parsePacket().
*/
uint16_t _remotePort;
sockaddr_t _remoteSockAddr;
socklen_t _remoteSockAddrLen;
uint8_t _buffer[RX_BUF_MAX_SIZE];

/**
* The current read/write offset in the buffer. Set to 0 after
* parsePacket(), incremented during write()
*/
uint16_t _offset;

/**
* The number of bytes in the buffer. Available after parsePacket()
*/
uint16_t _total;

/**
* The dynamically allocated buffer to store the packet that has been read or
* the packet that is being written.
*/
uint8_t* _buffer;

/**
* The size of the buffer.
*/
size_t _buffer_size;

/**
* The network interface this UDP socket should bind to.
*/
network_interface_t _nif;

/**
* Set to non-zero if the buffer was dynamically allocated by this class.
*/
uint8_t _buffer_allocated;



public:
UDP();

virtual uint8_t begin(uint16_t, network_interface_t nif=0);
/**
*
* @param port
* @param nif
* @param buffer_size The size of the read/write buffer. Can be 0 if
* only `readPacket()` and `sendPacket()` are used, as these methods
* use client-provided buffers.
* @param buffer A pre-allocated buffer. This is optional, and if not specified
* the UDP class will allocate the buffer dynamically.
* @return non-zero on success
*/
virtual uint8_t begin(uint16_t port, network_interface_t nif=0, size_t buffer_size=512, uint8_t* buffer=NULL);

virtual void stop();


virtual int sendPacket(const uint8_t* buffer, size_t buffer_size, IPAddress ip, uint16_t port);
#if 0
virtual int sendPacket(const uint8_t* buffer, size_t size, IPAddress destination, uint16_t port);
virtual int sendPacket(const uint8_t* buffer, size_t size, const char*, uint16_t port);

/**
* Retrieves a whole packet to a buffer. If the buffer is not large enough
* for the packet, the remainder that doesn't fit is discarded.
*
* The size of the packet can be determined via available()
* @param buffer
* @param buf_size
* @return
*/
virtual int readPacket(uint8_t* buffer, size_t buf_size);
#endif

virtual int beginPacket(IPAddress ip, uint16_t port);
virtual int beginPacket(const char *host, uint16_t port);
virtual int endPacket();
virtual size_t write(uint8_t);
virtual size_t write(const uint8_t *buffer, size_t size);
virtual int parsePacket();
virtual int available();

/**
* Read a single byte from the read buffer. Available after parsePacket().
* @return
*/
virtual int read();
virtual int read(unsigned char* buffer, size_t len);

virtual int read(char* buffer, size_t len) { return read((unsigned char*)buffer, len); };
virtual int peek();
virtual void flush();


virtual IPAddress remoteIP() { return _remoteIP; };
virtual uint16_t remotePort() { return _remotePort; };

Expand Down
103 changes: 66 additions & 37 deletions wiring/src/spark_wiring_udp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
* @date 13-Nov-2013
*
* Updated: 14-Feb-2014 David Sidrane <[email protected]>
* @brief
* @brief
******************************************************************************
Copyright (c) 2013-2015 Particle Industries, Inc. All rights reserved.
Copyright (c) 2008 Bjoern Hartmann
Expand Down Expand Up @@ -39,12 +39,11 @@ static bool inline isOpen(sock_handle_t sd)
return sd != socket_handle_invalid();
}

UDP::UDP() : _sock(socket_handle_invalid())
UDP::UDP() : _sock(socket_handle_invalid()), _offset(0), _total(0), _buffer(0), _buffer_size(0)
{

}

uint8_t UDP::begin(uint16_t port, network_interface_t nif)
uint8_t UDP::begin(uint16_t port, network_interface_t nif, size_t buf_size, uint8_t* buffer)
{
bool bound = 0;
if(Network.from(nif).ready())
Expand All @@ -53,15 +52,28 @@ uint8_t UDP::begin(uint16_t port, network_interface_t nif)
DEBUG("socket=%d",_sock);
if (socket_handle_valid(_sock))
{
_buffer = buffer;
if (!_buffer && buf_size) {
_buffer = new uint8_t[buf_size];
_buffer_allocated = true;
}
if (_buffer || !buf_size) {
_buffer_size = buf_size;
flush();
_port = port;
_nif = nif;
bound = true;
}
else {
stop();
bound = false;
}
}
}
return bound;
}

int UDP::available()
int UDP::available()
{
return _total - _offset;
}
Expand All @@ -71,9 +83,16 @@ void UDP::stop()
DEBUG("_sock %d closesocket", _sock);
if (isOpen(_sock))
{
socket_close(_sock);
socket_close(_sock);
}
_sock = socket_handle_invalid();

if (_buffer && _buffer_allocated) {
delete[] _buffer;
_buffer = 0;
_buffer_size = 0;
_buffer_allocated = false;
}
}

int UDP::beginPacket(const char *host, uint16_t port)
Expand All @@ -95,25 +114,31 @@ int UDP::beginPacket(IPAddress ip, uint16_t port)
{
_remoteIP = ip;
_remotePort = port;
flush();
return 1;
}

_remoteSockAddr.sa_family = AF_INET;

_remoteSockAddr.sa_data[0] = (_remotePort & 0xFF00) >> 8;
_remoteSockAddr.sa_data[1] = (_remotePort & 0x00FF);
int UDP::endPacket()
{
return sendPacket(_buffer, _offset, _remoteIP, _remotePort);
}

_remoteSockAddr.sa_data[2] = _remoteIP[0];
_remoteSockAddr.sa_data[3] = _remoteIP[1];
_remoteSockAddr.sa_data[4] = _remoteIP[2];
_remoteSockAddr.sa_data[5] = _remoteIP[3];
int UDP::sendPacket(const uint8_t* buffer, size_t buffer_size, IPAddress remoteIP, uint16_t port)
{
sockaddr_t remoteSockAddr;
remoteSockAddr.sa_family = AF_INET;

_remoteSockAddrLen = sizeof(_remoteSockAddr);
remoteSockAddr.sa_data[0] = (port & 0xFF00) >> 8;
remoteSockAddr.sa_data[1] = (port & 0x00FF);

return 1;
}
remoteSockAddr.sa_data[2] = remoteIP[0];
remoteSockAddr.sa_data[3] = remoteIP[1];
remoteSockAddr.sa_data[4] = remoteIP[2];
remoteSockAddr.sa_data[5] = remoteIP[3];

int UDP::endPacket()
{
return 1;
int rv = socket_sendto(_sock, buffer, buffer_size, 0, &remoteSockAddr, sizeof(remoteSockAddr));
DEBUG("sendto(buffer=%lx, size=%d)=%d",buffer, size , rv);
return rv;
}

size_t UDP::write(uint8_t byte)
Expand All @@ -123,29 +148,34 @@ size_t UDP::write(uint8_t byte)

size_t UDP::write(const uint8_t *buffer, size_t size)
{
int rv = socket_sendto(_sock, buffer, size, 0, &_remoteSockAddr, _remoteSockAddrLen);
DEBUG("sendto(buffer=%lx, size=%d)=%d",buffer, size , rv);
return rv;
size_t available = _buffer_size - _offset;
if (size>available)
size = available;
memcpy(_buffer+_offset, buffer, size);
_offset += size;
return size;
}

int UDP::parsePacket()
{
// No data buffered
if(available() == 0 && Network.from(_nif).ready() && isOpen(_sock))
flush(); // start a new read - discard the old data
if(Network.from(_nif).ready() && isOpen(_sock) && _buffer)
{
int ret = socket_receivefrom(_sock, _buffer, arraySize(_buffer), 0, &_remoteSockAddr, &_remoteSockAddrLen);
if (ret > 0)
sockaddr_t remoteSockAddr;
socklen_t remoteSockAddrLen = sizeof(remoteSockAddr);

int ret = socket_receivefrom(_sock, _buffer, _buffer_size, 0, &remoteSockAddr, &remoteSockAddrLen);
if (ret >= 0)
{
_remotePort = _remoteSockAddr.sa_data[0] << 8 | _remoteSockAddr.sa_data[1];

_remoteIP[0] = _remoteSockAddr.sa_data[2];
_remoteIP[1] = _remoteSockAddr.sa_data[3];
_remoteIP[2] = _remoteSockAddr.sa_data[4];
_remoteIP[3] = _remoteSockAddr.sa_data[5];
_remotePort = remoteSockAddr.sa_data[0] << 8 | remoteSockAddr.sa_data[1];
_remoteIP[0] = remoteSockAddr.sa_data[2];
_remoteIP[1] = remoteSockAddr.sa_data[3];
_remoteIP[2] = remoteSockAddr.sa_data[4];
_remoteIP[3] = remoteSockAddr.sa_data[5];

_offset = 0;
_total = ret;
}
}
}
return available();
}
Expand All @@ -160,7 +190,7 @@ int UDP::read(unsigned char* buffer, size_t len)
int read = -1;
if (available())
{
read = (len > (size_t) available()) ? available() : len;
read = min(int(len), available());
memcpy(buffer, &_buffer[_offset], read);
_offset += read;
}
Expand All @@ -176,7 +206,6 @@ void UDP::flush()
{
_offset = 0;
_total = 0;

}

size_t UDP::printTo(Print& p) const
Expand Down

0 comments on commit 8ce95c0

Please sign in to comment.