Skip to content

Commit

Permalink
Socket layer rewrite (work in progress - currently broken)
Browse files Browse the repository at this point in the history
  • Loading branch information
PaulStoffregen committed Jan 1, 2016
1 parent db174a2 commit 4d50903
Show file tree
Hide file tree
Showing 10 changed files with 252 additions and 254 deletions.
6 changes: 2 additions & 4 deletions Ethernet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,8 @@
#include "Dhcp.h"

// XXX: don't make assumptions about the value of MAX_SOCK_NUM.
uint8_t EthernetClass::_state[MAX_SOCK_NUM] = {
0, 0, 0, 0 };
uint16_t EthernetClass::_server_port[MAX_SOCK_NUM] = {
0, 0, 0, 0 };
//uint16_t EthernetClass::_server_port[MAX_SOCK_NUM] = {
// 0, 0, 0, 0 };

int EthernetClass::begin(uint8_t *mac_address, unsigned long timeout, unsigned long responseTimeout)
{
Expand Down
3 changes: 1 addition & 2 deletions Ethernet.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,7 @@ class EthernetClass {
IPAddress _dnsServerAddress;
DhcpClass* _dhcp;
public:
static uint8_t _state[MAX_SOCK_NUM];
static uint16_t _server_port[MAX_SOCK_NUM];
//static uint16_t _server_port[MAX_SOCK_NUM];
// Initialise the Ethernet shield to use the provided MAC address and gain the rest of the
// configuration through DHCP.
// Returns 0 if the DHCP configuration failed, and 1 if it succeeded
Expand Down
96 changes: 25 additions & 71 deletions EthernetClient.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,7 @@ extern "C" {
#include "EthernetServer.h"
#include "Dns.h"

uint16_t EthernetClient::_srcport = 49152; //Use IANA recommended ephemeral port range 49152-65535

EthernetClient::EthernetClient() : _sock(MAX_SOCK_NUM) {
}

EthernetClient::EthernetClient(uint8_t sock) : _sock(sock) {
}
uint16_t EthernetClient::srcport = 49152; //Use IANA recommended ephemeral port range 49152-65535

int EthernetClient::connect(const char* host, uint16_t port) {
// Look up the host first
Expand All @@ -36,37 +30,15 @@ int EthernetClient::connect(const char* host, uint16_t port) {
}

int EthernetClient::connect(IPAddress ip, uint16_t port) {
if (_sock != MAX_SOCK_NUM)
return 0;

for (int i = 0; i < MAX_SOCK_NUM; i++) {
uint8_t s = socketStatus(i);
if (s == SnSR::CLOSED || s == SnSR::FIN_WAIT || s == SnSR::CLOSE_WAIT) {
_sock = i;
break;
}
}

if (_sock == MAX_SOCK_NUM)
return 0;

_srcport++;
if (_srcport == 0) _srcport = 49152; //Use IANA recommended ephemeral port range 49152-65535
socket(_sock, SnMR::TCP, _srcport, 0);

if (!::connect(_sock, rawIPAddress(ip), port)) {
_sock = MAX_SOCK_NUM;
return 0;
}
if (ip == IPAddress(0ul) || ip == IPAddress(0xFFFFFFFFul)) return 0;
if (++srcport == 0) srcport = 49152; // IANA recommended ephemeral port range 49152-65535

if (!sock.begin(SnMR::TCP, srcport)) return 0;
sock.connect(rawIPAddress(ip), port);
while (status() != SnSR::ESTABLISHED) {
if (!sock) return 0;
delay(1);
if (status() == SnSR::CLOSED) {
_sock = MAX_SOCK_NUM;
return 0;
}
}

return 1;
}

Expand All @@ -75,99 +47,81 @@ size_t EthernetClient::write(uint8_t b) {
}

size_t EthernetClient::write(const uint8_t *buf, size_t size) {
if (_sock == MAX_SOCK_NUM) {
setWriteError();
return 0;
}
if (!send(_sock, buf, size)) {
if (!sock || !sock.send(buf, size)) {
setWriteError();
return 0;
}
return size;
}

int EthernetClient::available() {
if (_sock != MAX_SOCK_NUM)
return recvAvailable(_sock);
return 0;
if (!sock) return 0;
return sock.recvAvailable();
}

int EthernetClient::read() {
if (!sock) return -1;
uint8_t b;
if ( recv(_sock, &b, 1) > 0 )
{
if (sock.recv(&b, 1) > 0 ) {
// recv worked
return b;
}
else
{
} else {
// No data available
return -1;
}
}

int EthernetClient::read(uint8_t *buf, size_t size) {
return recv(_sock, buf, size);
return sock.recv(buf, size);
}

int EthernetClient::peek() {
uint8_t b;
// Unlike recv, peek doesn't check to see if there's any data available, so we must
if (!available())
return -1;
::peek(_sock, &b);
if (!sock || !available()) return -1;
uint8_t b;
sock.peek(&b);
return b;
}

void EthernetClient::flush() {
::flush(_sock);
sock.flush();
}

void EthernetClient::stop() {
if (_sock == MAX_SOCK_NUM)
return;
if (!sock) return;

// attempt to close the connection gracefully (send a FIN to other side)
disconnect(_sock);
sock.disconnect();
unsigned long start = millis();

// wait up to a second for the connection to close
uint8_t s;
do {
s = status();
if (s == SnSR::CLOSED)
break; // exit the loop
if (s == SnSR::CLOSED) break; // exit the loop
delay(1);
} while (millis() - start < 1000);

// if it hasn't closed, close it forcefully
if (s != SnSR::CLOSED)
close(_sock);

EthernetClass::_server_port[_sock] = 0;
_sock = MAX_SOCK_NUM;
if (s != SnSR::CLOSED) sock.close();
}

uint8_t EthernetClient::connected() {
if (_sock == MAX_SOCK_NUM) return 0;
if (!sock) return 0;

uint8_t s = status();
return !(s == SnSR::LISTEN || s == SnSR::CLOSED || s == SnSR::FIN_WAIT ||
(s == SnSR::CLOSE_WAIT && !available()));
}

uint8_t EthernetClient::status() {
if (_sock == MAX_SOCK_NUM) return SnSR::CLOSED;
return socketStatus(_sock);
if (!sock) return SnSR::CLOSED;
return sock.socketStatus();
}

// the next function allows us to use the client returned by
// EthernetServer::available() as the condition in an if-statement.

EthernetClient::operator bool() {
return _sock != MAX_SOCK_NUM;
}

bool EthernetClient::operator==(const EthernetClient& rhs) {
return _sock == rhs._sock && _sock != MAX_SOCK_NUM && rhs._sock != MAX_SOCK_NUM;
return sock && rhs.sock && getSocketNumber() == rhs.getSocketNumber();
}
13 changes: 7 additions & 6 deletions EthernetClient.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,13 @@
#include "Print.h"
#include "Client.h"
#include "IPAddress.h"
#include "utility/socket.h"

class EthernetClient : public Client {

public:
EthernetClient();
EthernetClient(uint8_t sock);
EthernetClient() { };
EthernetClient(W5000socket &socket) { sock.moveTo(socket); }

uint8_t status();
virtual int connect(IPAddress ip, uint16_t port);
Expand All @@ -23,20 +24,20 @@ class EthernetClient : public Client {
virtual void flush();
virtual void stop();
virtual uint8_t connected();
virtual operator bool();
virtual operator bool() { return (bool)sock; }
virtual bool operator==(const bool value) { return bool() == value; }
virtual bool operator!=(const bool value) { return bool() != value; }
virtual bool operator==(const EthernetClient&);
virtual bool operator!=(const EthernetClient& rhs) { return !this->operator==(rhs); };
uint8_t getSocketNumber() { return _sock; }
uint8_t getSocketNumber() const { return sock.getSocketNumber(); }

friend class EthernetServer;

using Print::write;

private:
static uint16_t _srcport;
uint8_t _sock;
static uint16_t srcport;
W5000socket sock;
};

#endif
59 changes: 32 additions & 27 deletions EthernetServer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,43 +15,38 @@ EthernetServer::EthernetServer(uint16_t port)

void EthernetServer::begin()
{
for (int sock = 0; sock < MAX_SOCK_NUM; sock++) {
EthernetClient client(sock);
if (client.status() == SnSR::CLOSED) {
socket(sock, SnMR::TCP, _port, 0);
listen(sock);
EthernetClass::_server_port[sock] = _port;
break;
}
}
sock.begin(SnMR::TCP, _port);
if (sock) sock.listen();
}

void EthernetServer::accept()
{
int listening = 0;

for (int sock = 0; sock < MAX_SOCK_NUM; sock++) {
EthernetClient client(sock);

if (EthernetClass::_server_port[sock] == _port) {
if (client.status() == SnSR::LISTEN) {
listening = 1;
}
else if (client.status() == SnSR::CLOSE_WAIT && !client.available()) {
client.stop();
}
}
}
bool listening = false;

if (!listening) {
begin();
if (sock) {
uint8_t status = sock.socketStatus();
if (status == SnSR::LISTEN) {
listening = true;
} else if (status == SnSR::CLOSE_WAIT && sock.recvAvailable() <= 0) {
sock.disconnect();
// TODO: wait?
}
}
if (!listening) begin();
}

EthernetClient EthernetServer::available()
{
accept();

if (sock) {
uint8_t stat = sock.socketStatus();
if (stat == SnSR::ESTABLISHED || (stat == SnSR::CLOSE_WAIT && sock.recvAvailable() > 0)) {
EthernetClient client(sock);
return client;
}
}
return EthernetClient();
/*
for (int sock = 0; sock < MAX_SOCK_NUM; sock++) {
EthernetClient client(sock);
if (EthernetClass::_server_port[sock] == _port) {
Expand All @@ -66,6 +61,7 @@ EthernetClient EthernetServer::available()
}
return EthernetClient(MAX_SOCK_NUM);
*/
}

size_t EthernetServer::write(uint8_t b)
Expand All @@ -78,7 +74,15 @@ size_t EthernetServer::write(const uint8_t *buffer, size_t size)
size_t n = 0;

accept();

if (sock) {
uint8_t stat = sock.socketStatus();
if (stat == SnSR::ESTABLISHED) {
return sock.send(buffer, size);
}
}
return 0;
}
/*
for (int sock = 0; sock < MAX_SOCK_NUM; sock++) {
EthernetClient client(sock);
Expand All @@ -90,3 +94,4 @@ size_t EthernetServer::write(const uint8_t *buffer, size_t size)
return n;
}
*/
2 changes: 2 additions & 0 deletions EthernetServer.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@
#define ethernetserver_h

#include "Server.h"
#include "utility/socket.h"

class EthernetClient;

class EthernetServer :
public Server {
private:
uint16_t _port;
W5000socket sock;
void accept();
public:
EthernetServer(uint16_t);
Expand Down
Loading

0 comments on commit 4d50903

Please sign in to comment.