WIZ820io(W5200) network interface、EthernetNetIf compatible.
example
#include "WIZ820ioNetIf.h" #include "HTTPClient.h" #include "HTTPServer.h" #if defined(TARGET_KL25Z) WIZ820ioNetIf eth(PTD2,PTD3,PTD1,PTD0,PTD5); #endif HTTPClient http; HTTPStream stream; void callback(HTTPResult r){ printf("callback %d %s\n", r, HTTPClient::ResultStr(r)); } int main() { int err = eth.setup(); if (err < 0) { printf("setup error %d\n", err); exit(-1); } HTTPServer svr; svr.addHandler<SimpleHandler>("/"); svr.bind(80); const char* uri = "http://va009039-mbed.appspot.com/kl25z/"; http.get(uri, &stream, callback); uint8_t buf[256]; int total = 0; stream.readNext(buf, sizeof(buf)); while(1) { if(stream.readable()) { int len = stream.readLen(); total += len; printf("%d %d\n", total, len); stream.readNext(buf, sizeof(buf)); } Net::poll(); } }
Revision 1:22b9052d864d, committed 2013-03-24
- Comitter:
- va009039
- Date:
- Sun Mar 24 11:25:31 2013 +0000
- Parent:
- 0:bdeec5f86894
- Commit message:
- WIZ820io(W8200) ethernet interface, EthernetNetIf compatible.
Changed in this revision
--- a/DHCPClient.cpp Fri Mar 22 11:51:24 2013 +0000 +++ b/DHCPClient.cpp Sun Mar 24 11:25:31 2013 +0000 @@ -1,8 +1,8 @@ // DHCPClient.cpp 2012/4/21 // DHCP Client for WIZ820io(W5200) #include "mbed.h" -#include "w5100.h" -#include "UDPSocket.h" +#include "w5200.h" +//#include "UDPSocket.h" #include "DHCPClient.h" //#define __DEBUG #include "dbg/dbg.h" @@ -33,13 +33,13 @@ xid[2] = t<<8; xid[3] = t; memcpy(buf+DHCP_OFFSET_XID, xid, 4); - W5100.getMACAddress(buf+DHCP_OFFSET_CHADDR); + W5200.getMACAddress(buf+DHCP_OFFSET_CHADDR); const uint8_t options[] = {0x63,0x82,0x53,0x63, // magic cookie 0x35,0x01,0x01, // DHCP DISCOVER 0xff}; memcpy(buf+DHCP_OFFSET_MAGIC_COOKIE, options, sizeof(options)); uint8_t ip[4] = {0,0,0,0}; - W5100.setIPAddress(ip); + W5200.setIPAddress(ip); return DHCP_OFFSET_MAGIC_COOKIE + sizeof(options); } @@ -50,7 +50,7 @@ memcpy(buf, headers, sizeof(headers)); memcpy(buf+DHCP_OFFSET_XID, xid, 4); memcpy(buf+DHCP_OFFSET_YIADDR, yiaddr, 4); - W5100.getMACAddress(buf+DHCP_OFFSET_CHADDR); + W5200.getMACAddress(buf+DHCP_OFFSET_CHADDR); const uint8_t options[] = {0x63,0x82,0x53,0x63, // magic cookie 0x35,0x01,0x03, // DHCP REQUEST 0x32,0x04,0x00,0x00,0x00,0x00, // request IP
--- a/MyNetDnsRequest.cpp Fri Mar 22 11:51:24 2013 +0000 +++ b/MyNetDnsRequest.cpp Sun Mar 24 11:25:31 2013 +0000 @@ -1,10 +1,10 @@ -// MyNetDnsRequest.cpp 2012/4/22 +// MyNetDnsRequest.cpp 2013/3/24 #include "mbed.h" #include "MyNetDnsRequest.h" #include "UDPSocket.h" #include <string> #include "dnsname.h" -#include "W5200NetIf.h" +#include "WIZ820ioNetIf.h" //#define __DEBUG #include "dbg/dbg.h" @@ -134,7 +134,7 @@ IpAddr dns(8,8,8,8); NetIf* pIf = Net::getDefaultIf(); if (pIf) { - dns = ((W5200NetIf*)pIf)->m_dns; + dns = ((WIZ820ioNetIf*)pIf)->m_dns; } Host server(dns, 53); // DNS m_udp->bind(local);
--- a/MyNetTcpSocket.cpp Fri Mar 22 11:51:24 2013 +0000 +++ b/MyNetTcpSocket.cpp Sun Mar 24 11:25:31 2013 +0000 @@ -1,32 +1,18 @@ -// MyNetTcpSocket.cpp 2012/4/22 +// MyNetTcpSocket.cpp 2013/3/24 #include "mbed.h" -#include "w5100.h" +#include "w5200.h" #include "MyNetTcpSocket.h" -//#define __DEBUG -#include "dbg/dbg.h" - -#ifdef __DEBUG -#define DBG2(...) do{ DebugStream::debug("%p %s ", this,__PRETTY_FUNCTION__); DebugStream::debug(__VA_ARGS__); } while(0); -#else -#define DBG2(...) while(0); -#endif //__DEBUG - //#define DEBUG - -#ifdef DEBUG -#include "Utils.h" -#define PRINT_FUNC() printf("%p %d:%s\n", this,__LINE__,__PRETTY_FUNCTION__) -#else //DEBUG -#define PRINT_FUNC() -#endif //DEBUG +//#define DEBUG_LISTEN +#include "w5200debug.h" #define USE_NO_DELAYED_ACK 1 int w5200_new_socket() { for(int i = 0; i < MAX_SOCK_NUM; i++) { - if (W5100.readSnMR(i) == SnMR::CLOSE) { // 0x00 - if (W5100.readSnSR(i) != SnSR::LISTEN) { // 0x14 + if (W5200.readSnMR(i) == SnMR::CLOSE) { // 0x00 + if (W5200.readSnSR(i) != SnSR::LISTEN) { // 0x14 return i; } } @@ -35,62 +21,58 @@ } MyNetTcpSocket::MyNetTcpSocket(int socket) : NetTcpSocket(),_socket(socket),wait_accept(false) { - PRINT_FUNC(); - DBG2("socket: %d\n", socket); + DBG("socket: %d\n", socket); if (_socket == (-1)) { _socket = w5200_new_socket(); } -#ifdef DEBUG - printf("%p socket: %d\n", this, _socket); -#endif //DEBUG + DBG("%p socket: %d\n", this, _socket); if (_socket != (-1)) { uint8_t Sn_MR = SnMR::TCP; // set TCP mode #if USE_NO_DELAYED_ACK Sn_MR |= SnMR::ND; #endif - W5100.writeSnMR(_socket, Sn_MR); + W5200.writeSnMR(_socket, Sn_MR); } } MyNetTcpSocket::~MyNetTcpSocket() { - PRINT_FUNC(); - DBG2("socket=%d\n", _socket); + DBG("socket=%d\n", _socket); close(); if (_socket != (-1)) { - W5100.writeSnMR(_socket, SnMR::CLOSE); + W5200.writeSnMR(_socket, SnMR::CLOSE); } } NetTcpSocketErr MyNetTcpSocket::bind(const Host& me) { - PRINT_FUNC(); if (_socket == (-1)) { return NETTCPSOCKET_MEM; } int port = me.getPort(); - W5100.writeSnPORT(_socket, port); + W5200.writeSnPORT(_socket, port); return NETTCPSOCKET_OK; } NetTcpSocketErr MyNetTcpSocket::listen() { - PRINT_FUNC(); + DBG("%p\n", this); if (_socket == (-1)) { return NETTCPSOCKET_MEM; } - W5100.execCmdSn(_socket, Sock_OPEN); // set OPEN command - W5100.execCmdSn(_socket, Sock_LISTEN); // listen -#ifdef DEBUG + W5200.execCmdSn(_socket, Sock_OPEN); // set OPEN command + W5200.execCmdSn(_socket, Sock_LISTEN); // listen +#ifdef DEBUG_LISTEN + printf("[%s@%d]\n",__PRETTY_FUNCTION__,__LINE__); uint8_t ip[4]; - printf("socket:%d SnMR:%02x SnIR:%02x SnSR:%02x\n", _socket, - W5100.readSnMR(_socket), W5100.readSnIR(_socket), W5100.readSnSR(_socket)); - W5100.getIPAddress(ip); - printf("SIPR: %d.%d.%d.%d Sn_PORT:%d\n", ip[0], ip[1], ip[2], ip[3], W5100.readSnPORT(_socket)); -#endif //DEBUG + printf("socket:%d SnMR:%02x SnIR:%02x SnSR:%02x", _socket, + W5200.readSnMR(_socket), W5200.readSnIR(_socket), W5200.readSnSR(_socket)); + W5200.getIPAddress(ip); + printf(" SIPR: %d.%d.%d.%d Sn_PORT:%d\n", ip[0], ip[1], ip[2], ip[3], W5200.readSnPORT(_socket)); +#endif //DEBUG_LISTEN wait_accept = true; return NETTCPSOCKET_OK; } NetTcpSocketErr MyNetTcpSocket::connect(const Host& host) { - PRINT_FUNC(); + DBG("%p host=%p\n", this, host); if (_socket == (-1)) { return NETTCPSOCKET_MEM; } @@ -100,36 +82,36 @@ ip[2] = host.getIp()[2]; ip[3] = host.getIp()[3]; int port = host.getPort(); - W5100.writeSnDIPR(_socket, ip); - W5100.writeSnDPORT(_socket, port); - if (W5100.readSnPORT(_socket) == 0) { - W5100.writeSnPORT(_socket, 1024 + _socket); + W5200.writeSnDIPR(_socket, ip); + W5200.writeSnDPORT(_socket, port); + if (W5200.readSnPORT(_socket) == 0) { + W5200.writeSnPORT(_socket, 1024 + _socket); } - W5100.execCmdSn(_socket, Sock_OPEN); // set OPEN command - W5100.execCmdSn(_socket, Sock_CONNECT); -#ifdef DEBUG + W5200.execCmdSn(_socket, Sock_OPEN); // set OPEN command + W5200.execCmdSn(_socket, Sock_CONNECT); +#ifdef DEBUG_CONNECT printf("socket:%d SnMR:%02x SnIR:%02x SnSR:%02x\n", _socket, - W5100.readSnMR(_socket), W5100.readSnIR(_socket), W5100.readSnSR(_socket)); - W5100.getIPAddress(ip); - printf("SIPR: %d.%d.%d.%d Sn_PORT:%d\n", ip[0], ip[1], ip[2], ip[3], W5100.readSnPORT(_socket)); - W5100.readSnDIPR(_socket, ip); - printf("Sn_DIPR: %d.%d.%d.%d Sn_DPORT:%d\n", ip[0], ip[1], ip[2], ip[3], W5100.readSnDPORT(_socket)); -#endif //DEBUG + W5200.readSnMR(_socket), W5200.readSnIR(_socket), W5200.readSnSR(_socket)); + W5200.getIPAddress(ip); + printf("SIPR: %d.%d.%d.%d Sn_PORT:%d\n", ip[0], ip[1], ip[2], ip[3], W5200.readSnPORT(_socket)); + W5200.readSnDIPR(_socket, ip); + printf("Sn_DIPR: %d.%d.%d.%d Sn_DPORT:%d\n", ip[0], ip[1], ip[2], ip[3], W5200.readSnDPORT(_socket)); +#endif //DEBUG_CONNECT return NETTCPSOCKET_OK; } NetTcpSocketErr MyNetTcpSocket::accept(Host* pClient, NetTcpSocket** ppNewNetTcpSocket) { - PRINT_FUNC(); + DBG("%p pClient=%p\n", this, pClient); if (_socket == (-1)) { return NETTCPSOCKET_MEM; } uint8_t ip[4]; - W5100.readSnDIPR(_socket, ip); + W5200.readSnDIPR(_socket, ip); pClient->setIp(IpAddr(ip[0],ip[1],ip[2],ip[3])); - int port = W5100.readSnDPORT(_socket); + int port = W5200.readSnDPORT(_socket); pClient->setPort(port); Host me; - me.setPort(W5100.readSnPORT(_socket)); + me.setPort(W5200.readSnPORT(_socket)); MyNetTcpSocket* pNewNetTcpSocket = new MyNetTcpSocket(_socket); if (pNewNetTcpSocket == NULL) { return NETTCPSOCKET_EMPTY; @@ -142,7 +124,7 @@ #if USE_NO_DELAYED_ACK Sn_MR |= SnMR::ND; #endif - W5100.writeSnMR(_socket, Sn_MR); + W5200.writeSnMR(_socket, Sn_MR); bind(me); listen(); } @@ -150,77 +132,68 @@ } int /*if < 0 : NetTcpSocketErr*/ MyNetTcpSocket::send(const char* buf, int len) { - PRINT_FUNC(); -#ifdef DEBUG - printf("buf:%p, len=%d\n", buf, len); - printHex((u8*)buf, len); -#endif //DEBUG + DBG_STR((uint8_t*)buf,len); if (_socket == (-1)) { return NETTCPSOCKET_MEM; } if (len > 0) { - W5100.send_data_processing(_socket, (uint8_t*)buf, len); - W5100.execCmdSn(_socket, Sock_SEND); + W5200.send_data_processing(_socket, (uint8_t*)buf, len); + W5200.execCmdSn(_socket, Sock_SEND); } return len; } int /*if < 0 : NetTcpSocketErr*/ MyNetTcpSocket::recv(char* buf, int len){ - PRINT_FUNC(); if (_socket == (-1)) { return NETTCPSOCKET_MEM; } - int size = W5100.getRXReceivedSize(_socket); + int size = W5200.getRXReceivedSize(_socket); if (size > len) { size = len; } if (size > 0) { - W5100.recv_data_processing(_socket, (uint8_t*)buf, size); - W5100.execCmdSn(_socket, Sock_RECV); + W5200.recv_data_processing(_socket, (uint8_t*)buf, size); + W5200.execCmdSn(_socket, Sock_RECV); } -#ifdef DEBUG - printHex((uint8_t*)buf, size); -#endif //DEBUG + DBG_STR((uint8_t*)buf, size); return size; } NetTcpSocketErr MyNetTcpSocket::close() { - PRINT_FUNC(); - DBG2("m_closed=%d m_refs=%d\n", m_closed, m_refs); + DBG("%p m_closed=%d m_refs=%d\n", this, m_closed, m_refs); if(m_closed) { return NETTCPSOCKET_OK; } m_closed = true; cleanUp(); if (_socket != (-1)) { - W5100.execCmdSn(_socket, Sock_DISCON); - W5100.execCmdSn(_socket, Sock_CLOSE); + W5200.execCmdSn(_socket, Sock_DISCON); + W5200.execCmdSn(_socket, Sock_CLOSE); } return NETTCPSOCKET_OK; } NetTcpSocketErr MyNetTcpSocket::poll(){ - PRINT_FUNC(); NetTcpSocket::flushEvents(); -#ifdef DEBUG +#ifdef DEBUG_POLL printf("%p socket:%d\n", this,_socket); if (_socket != (-1)) { printf("SnMR:%02x SnIR:%02x SnSR:%02x\n", - W5100.readSnMR(_socket), W5100.readSnIR(_socket), W5100.readSnSR(_socket)); + W5200.readSnMR(_socket), W5200.readSnIR(_socket), W5200.readSnSR(_socket)); uint8_t ip[4]; - W5100.readSnDIPR(_socket, ip); - printf("Sn_DIPR: %d.%d.%d.%d Sn_DPORT: %d\n", ip[0], ip[1], ip[2], ip[3], W5100.readSnDPORT(_socket)); + W5200.readSnDIPR(_socket, ip); + printf("Sn_DIPR: %d.%d.%d.%d Sn_DPORT: %d\n", ip[0], ip[1], ip[2], ip[3], W5200.readSnDPORT(_socket)); printf("Sn_RX_RSR:%5d, Sn_RX_RD:%5d, Sn_RX_WR:%5d\n", - W5100.readSnRX_RSR(_socket), W5100.readSnRX_RD(_socket), W5100.readSnRX_WR(_socket)); + W5200.readSnRX_RSR(_socket), W5200.readSnRX_RD(_socket), W5200.readSnRX_WR(_socket)); printf("Sn_TX_FSR:%5d, Sn_TX_RD:%5d, Sn_TX_WR:%5d\n", - W5100.readSnTX_FSR(_socket), W5100.readSnTX_RD(_socket), W5100.readSnTX_WR(_socket)); + W5200.readSnTX_FSR(_socket), W5200.readSnTX_RD(_socket), W5200.readSnTX_WR(_socket)); } wait_ms(200); -#endif //DEBUG +#endif //DEBUG_POLL if (_socket == (-1)) { return NETTCPSOCKET_OK; } - uint8_t Sn_SR = W5100.readSnSR(_socket); + uint8_t Sn_SR = W5200.readSnSR(_socket); if (wait_accept) { if (Sn_SR == 0x17) { queueEvent(NETTCPSOCKET_ACCEPT); @@ -230,12 +203,12 @@ if (Sn_SR == 0x1c) { queueEvent(NETTCPSOCKET_CONRST); } - if (W5100.getRXReceivedSize(_socket) > 0) { + if (W5200.getRXReceivedSize(_socket) > 0) { queueEvent(NETTCPSOCKET_READABLE); } if (Sn_SR == 0x17) { queueEvent(NETTCPSOCKET_CONNECTED); - if (W5100.getTXFreeSize(_socket) > 0) { + if (W5200.getTXFreeSize(_socket) > 0) { queueEvent(NETTCPSOCKET_WRITEABLE); } } @@ -247,13 +220,12 @@ void MyNetTcpSocket::cleanUp() //Flush input buffer { - PRINT_FUNC(); if (_socket == (-1)) { return; } - while(W5100.getRXReceivedSize(_socket) > 0) { + while(W5200.getRXReceivedSize(_socket) > 0) { uint8_t temp[1]; - W5100.recv_data_processing(_socket, temp, 1); - W5100.execCmdSn(_socket, Sock_RECV); + W5200.recv_data_processing(_socket, temp, 1); + W5200.execCmdSn(_socket, Sock_RECV); } }
--- a/MyNetUdpSocket.cpp Fri Mar 22 11:51:24 2013 +0000 +++ b/MyNetUdpSocket.cpp Sun Mar 24 11:25:31 2013 +0000 @@ -1,7 +1,7 @@ // MyNetUdpSocket.cpp 2012/4/16 #include "mbed.h" #include "MyNetUdpSocket.h" -#include "w5100.h" +#include "w5200.h" //#define DEBUG @@ -20,7 +20,7 @@ _socket = w5200_new_socket(); } if (_socket != (-1)) { - W5100.writeSnMR(_socket, SnMR::UDP); // set UDP mode + W5200.writeSnMR(_socket, SnMR::UDP); // set UDP mode } } @@ -28,7 +28,7 @@ PRINT_FUNC(); close(); if (_socket != (-1)) { - W5100.writeSnMR(_socket, SnMR::CLOSE); + W5200.writeSnMR(_socket, SnMR::CLOSE); } } @@ -38,8 +38,8 @@ return NETUDPSOCKET_MEM; } int port = me.getPort(); - W5100.writeSnPORT(_socket, port); - W5100.execCmdSn( _socket, Sock_OPEN); // set OPEN command + W5200.writeSnPORT(_socket, port); + W5200.execCmdSn( _socket, Sock_OPEN); // set OPEN command return NETUDPSOCKET_OK; } @@ -54,16 +54,16 @@ ip[2] = pHost->getIp()[2]; ip[3] = pHost->getIp()[3]; int port = pHost->getPort(); - W5100.writeSnDIPR(_socket, ip); - W5100.writeSnDPORT(_socket, port); - W5100.send_data_processing(_socket, (uint8_t*)buf, len); - W5100.execCmdSn(_socket, Sock_SEND); + W5200.writeSnDIPR(_socket, ip); + W5200.writeSnDPORT(_socket, port); + W5200.send_data_processing(_socket, (uint8_t*)buf, len); + W5200.execCmdSn(_socket, Sock_SEND); #ifdef DEBUG printHex((u8*)buf, len); - W5100.getIPAddress(ip); - printf("SIPR: %d.%d.%d.%d Sn_PORT:%d\n", ip[0], ip[1], ip[2], ip[3], W5100.readSnPORT(_socket)); - W5100.readSnDIPR(_socket, ip); - printf("Sn_DIPR: %d.%d.%d.%d Sn_DPORT:%d\n", ip[0], ip[1], ip[2], ip[3], W5100.readSnDPORT(_socket)); + W5200.getIPAddress(ip); + printf("SIPR: %d.%d.%d.%d Sn_PORT:%d\n", ip[0], ip[1], ip[2], ip[3], W5200.readSnPORT(_socket)); + W5200.readSnDIPR(_socket, ip); + printf("Sn_DIPR: %d.%d.%d.%d Sn_DPORT:%d\n", ip[0], ip[1], ip[2], ip[3], W5200.readSnDPORT(_socket)); #endif //DEBUG return len; } @@ -73,21 +73,21 @@ if (_socket == (-1)) { return NETUDPSOCKET_MEM; } - int size = W5100.getRXReceivedSize(_socket); + int size = W5200.getRXReceivedSize(_socket); if (size < 8) { return -1; } uint8_t info[8]; - W5100.recv_data_processing(_socket, info, 8); - W5100.execCmdSn(_socket, Sock_RECV); + W5200.recv_data_processing(_socket, info, 8); + W5200.execCmdSn(_socket, Sock_RECV); pHost->setIp(IpAddr(info[0],info[1],info[2],info[3])); pHost->setPort(info[4]<<8|info[5]); size -= 8; if (size > len) { size = len; } - W5100.recv_data_processing(_socket, (uint8_t*)buf, size); - W5100.execCmdSn(_socket, Sock_RECV); + W5200.recv_data_processing(_socket, (uint8_t*)buf, size); + W5200.execCmdSn(_socket, Sock_RECV); #ifdef DEBUG printfBytes("UDP PACKET-INFO", (u8*)info, 8); printHex((u8*)buf, size); @@ -105,7 +105,7 @@ } m_closed = true; cleanUp(); - W5100.writeSnMR(_socket, SnMR::CLOSE); + W5200.writeSnMR(_socket, SnMR::CLOSE); return NETUDPSOCKET_OK; } @@ -116,22 +116,22 @@ printf("%p socket:%d\n", this,_socket); if (_socket != (-1)) { printf("SnMR:%02x SnIR:%02x SnSR:%02x\n", - W5100.readSnMR(_socket), W5100.readSnIR(_socket), W5100.readSnSR(_socket)); + W5200.readSnMR(_socket), W5200.readSnIR(_socket), W5200.readSnSR(_socket)); uint8_t ip[4]; - W5100.readSnDIPR(_socket, ip); - printf("Sn_DIPR: %d.%d.%d.%d Sn_DPORT: %d\n", ip[0], ip[1], ip[2], ip[3], W5100.readSnDPORT(_socket)); + W5200.readSnDIPR(_socket, ip); + printf("Sn_DIPR: %d.%d.%d.%d Sn_DPORT: %d\n", ip[0], ip[1], ip[2], ip[3], W5200.readSnDPORT(_socket)); uint8_t mac[6]; - W5100.readSnDHAR(_socket, mac); + W5200.readSnDHAR(_socket, mac); printf("Sn_DHAR: %02x:%02x:%02x:%02x:%02x:%02x\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); printf("Sn_RX_RSR:%5d, Sn_RX_RD:%5d, Sn_RX_WR:%5d\n", - W5100.readSnRX_RSR(_socket), W5100.readSnRX_RD(_socket), W5100.readSnRX_WR(_socket)); + W5200.readSnRX_RSR(_socket), W5200.readSnRX_RD(_socket), W5200.readSnRX_WR(_socket)); printf("Sn_TX_FSR:%5d, Sn_TX_RD:%5d, Sn_TX_WR:%5d\n", - W5100.readSnTX_FSR(_socket), W5100.readSnTX_RD(_socket), W5100.readSnTX_WR(_socket)); + W5200.readSnTX_FSR(_socket), W5200.readSnTX_RD(_socket), W5200.readSnTX_WR(_socket)); } wait_ms(200); #endif //DEBUG if (_socket != (-1)) { - if (W5100.getRXReceivedSize(_socket) > 0) { + if (W5200.getRXReceivedSize(_socket) > 0) { queueEvent(NETUDPSOCKET_READABLE); } } @@ -144,9 +144,9 @@ if (_socket == (-1)) { return; } - while(W5100.getRXReceivedSize(_socket) > 0) { + while(W5200.getRXReceivedSize(_socket) > 0) { uint8_t temp[1]; - W5100.recv_data_processing(_socket, temp, 1); - W5100.execCmdSn(_socket, Sock_RECV); + W5200.recv_data_processing(_socket, temp, 1); + W5200.execCmdSn(_socket, Sock_RECV); } }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/NetServices/api/DNSRequest.cpp Sun Mar 24 11:25:31 2013 +0000 @@ -0,0 +1,115 @@ + +/* +Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#include "DNSRequest.h" +#include "if/net/netdnsrequest.h" + +DNSRequest::DNSRequest() : m_pNetDnsRequest(NULL), m_pCbItem(NULL), m_pCbMeth(NULL), m_pCb(NULL) +{ + +} + +DNSRequest::~DNSRequest() +{ + close(); +} + +DNSRequestErr DNSRequest::resolve(const char* hostname) +{ + if(!m_pNetDnsRequest) + { + m_pNetDnsRequest = Net::dnsRequest(hostname); + if(!m_pNetDnsRequest) + { + return DNS_IF; //Interface did not return a NetDnsRequest (usually because a default interface does not exist) + } + m_pNetDnsRequest->setOnReply(this, &DNSRequest::onNetDnsReply); + return DNS_OK; + } + else + { + return DNS_INUSE; //The previous req has not completed + } +} + +DNSRequestErr DNSRequest::resolve(Host* pHost) +{ + if(!m_pNetDnsRequest) + { + m_pNetDnsRequest = Net::dnsRequest(pHost); + if(!m_pNetDnsRequest) + { + return DNS_IF; //Interface did not return a NetDnsRequest (usually because a default interface does not exist) + } + m_pNetDnsRequest->setOnReply(this, &DNSRequest::onNetDnsReply); + return DNS_OK; + } + else + { + return DNS_INUSE; //The previous req has not completed + } +} + +//Callbacks +void DNSRequest::setOnReply( void (*pMethod)(DNSReply) ) +{ + m_pCb = pMethod; +} + +#if 0 //For doc only +template<class T> +void DNSRequest::setOnReply( T* pItem, void (T::*pMethod)(DNSReply) ) +{ + m_pCbItem = (CDummy*) pItem; + m_pCbMeth = (void (CDummy::*)(DNSReply)) pMethod; +} +#endif + +DNSRequestErr DNSRequest::getResult(IpAddr* pIp) +{ + if(!m_pNetDnsRequest) + { + return DNS_SETUP; + } + m_pNetDnsRequest->getResult(pIp); + return DNS_OK; +} + +DNSRequestErr DNSRequest::close() +{ + if(!m_pNetDnsRequest) + { + return DNS_SETUP; + } + m_pNetDnsRequest->close(); + m_pNetDnsRequest = NULL; + return DNS_OK; +} + +void DNSRequest::onNetDnsReply(NetDnsReply r) +{ + if(m_pCbItem && m_pCbMeth) + (m_pCbItem->*m_pCbMeth)((DNSReply) r); + else if(m_pCb) + m_pCb((DNSReply) r); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/NetServices/api/DNSRequest.h Sun Mar 24 11:25:31 2013 +0000 @@ -0,0 +1,131 @@ + +/* +Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +/** \file +DNS Request header file +*/ + +#ifndef DNSREQUEST_H +#define DNSREQUEST_H + +#include "core/net.h" +#include "core/ipaddr.h" +#include "core/host.h" +//Essentially it is a safe interface to NetDnsRequest + +///DNS Request error codes +enum DNSRequestErr +{ + __DNS_MIN = -0xFFFF, + DNS_SETUP, ///<DNSRequest not properly configured + DNS_IF, ///<Interface has problems, does not exist or is not initialized + DNS_MEM, ///<Not enough mem + DNS_INUSE, ///<Interface / Port is in use + DNS_PROCESSING, ///<Request has not completed +//... + DNS_OK = 0 ///<Success +}; + +///DNS Request Result Events +enum DNSReply +{ + DNS_PRTCL, + DNS_NOTFOUND, ///Hostname is unknown + DNS_ERROR, ///Problem with DNS Service + //... + DNS_FOUND, +}; + +class NetDnsRequest; +enum NetDnsReply; + +///This is a simple DNS Request class +/** + This class exposes an API to deal with DNS Requests +*/ +class DNSRequest +{ +public: + ///Creates a new request + DNSRequest(); + + ///Terminates and closes request + ~DNSRequest(); + + ///Resolves an hostname + /** + @param hostname : hostname to resolve + */ + DNSRequestErr resolve(const char* hostname); + + ///Resolves an hostname + /** + @param host : hostname to resolve, the result will be stored in the IpAddr field of this object + */ + DNSRequestErr resolve(Host* pHost); + + ///Setups callback + /** + The callback function will be called on result. + @param pMethod : callback function + */ + void setOnReply( void (*pMethod)(DNSReply) ); + + class CDummy; + ///Setups callback + /** + The callback function will be called on result. + @param pItem : instance of class on which to execute the callback method + @param pMethod : callback method + */ + template<class T> + void setOnReply( T* pItem, void (T::*pMethod)(DNSReply) ) + { + m_pCbItem = (CDummy*) pItem; + m_pCbMeth = (void (CDummy::*)(DNSReply)) pMethod; + } + + ///Gets IP address once it has been resolved + /** + @param pIp : pointer to an IpAddr instance in which to store the resolved IP address + */ + DNSRequestErr getResult(IpAddr* pIp); + + ///Closes DNS Request before completion + DNSRequestErr close(); + +protected: + void onNetDnsReply(NetDnsReply r); + DNSRequestErr checkInst(); + +private: + NetDnsRequest* m_pNetDnsRequest; + + CDummy* m_pCbItem; + void (CDummy::*m_pCbMeth)(DNSReply); + + void (*m_pCb)(DNSReply); + +}; + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/NetServices/api/TCPSocket.cpp Sun Mar 24 11:25:31 2013 +0000 @@ -0,0 +1,164 @@ + +/* +Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#include "TCPSocket.h" +#include "if/net/nettcpsocket.h" + +TCPSocket::TCPSocket() : m_pNetTcpSocket(NULL), m_pCbItem(NULL), m_pCbMeth(NULL), m_pCb(NULL) +{ + +} + +TCPSocket::TCPSocket(NetTcpSocket* pNetTcpSocket) : m_pNetTcpSocket(pNetTcpSocket), m_pCbItem(NULL), m_pCbMeth(NULL), m_pCb(NULL) +{ + m_pNetTcpSocket->setOnEvent(this, &TCPSocket::onNetTcpSocketEvent); +} + +TCPSocket::~TCPSocket() //close() +{ + close(); +} + +TCPSocketErr TCPSocket::bind(const Host& me) +{ + TCPSocketErr tcpSocketErr = checkInst(); + if(tcpSocketErr) + return tcpSocketErr; + return (TCPSocketErr) m_pNetTcpSocket->bind(me); +} + +TCPSocketErr TCPSocket::listen() +{ + TCPSocketErr tcpSocketErr = checkInst(); + if(tcpSocketErr) + return tcpSocketErr; + return (TCPSocketErr) m_pNetTcpSocket->listen(); +} + +TCPSocketErr TCPSocket::connect(const Host& host) +{ + TCPSocketErr tcpSocketErr = checkInst(); + if(tcpSocketErr) + return tcpSocketErr; + return (TCPSocketErr) m_pNetTcpSocket->connect(host); +} + +TCPSocketErr TCPSocket::accept(Host* pClient, TCPSocket** ppNewTCPSocket) +{ + TCPSocketErr tcpSocketErr = checkInst(); + if(tcpSocketErr) + return tcpSocketErr; + NetTcpSocket* pNewNetTcpSocket; + tcpSocketErr = (TCPSocketErr) m_pNetTcpSocket->accept(pClient, &pNewNetTcpSocket); + if(pNewNetTcpSocket) + *ppNewTCPSocket = new TCPSocket(pNewNetTcpSocket); + return tcpSocketErr; +} + +int /*if < 0 : TCPSocketErr*/ TCPSocket::send(const char* buf, int len) +{ + TCPSocketErr tcpSocketErr = checkInst(); + if(tcpSocketErr) + return tcpSocketErr; + return m_pNetTcpSocket->send(buf, len); +} + +int /*if < 0 : TCPSocketErr*/ TCPSocket::recv(char* buf, int len) +{ + TCPSocketErr tcpSocketErr = checkInst(); + if(tcpSocketErr) + return tcpSocketErr; + return m_pNetTcpSocket->recv(buf, len); +} + +TCPSocketErr TCPSocket::close() +{ + if(!m_pNetTcpSocket) + return TCPSOCKET_SETUP; + m_pNetTcpSocket->resetOnEvent(); + TCPSocketErr tcpSocketErr = (TCPSocketErr) m_pNetTcpSocket->close(); //Close (can already be closed) + Net::releaseTcpSocket(m_pNetTcpSocket); //And release it so it can be freed when properly removed + m_pNetTcpSocket = NULL; + return tcpSocketErr; +} + +//Callbacks +void TCPSocket::setOnEvent( void (*pMethod)(TCPSocketEvent) ) +{ + m_pCb = pMethod; +} + +#if 0 //For info only +template<class T> +void TCPSocket::setOnEvent( T* pItem, void (T::*pMethod)(TCPSocketEvent) ) +{ + m_pCbItem = (CDummy*) pItem; + m_pCbMeth = (void (CDummy::*)(TCPSocketEvent)) pMethod; +} +#endif + +void TCPSocket::resetOnEvent() //Disable callback +{ + m_pCb = NULL; + m_pCbItem = NULL; + m_pCbMeth = NULL; +} + +void TCPSocket::onNetTcpSocketEvent(NetTcpSocketEvent e) +{ + if(m_pCbItem && m_pCbMeth) + (m_pCbItem->*m_pCbMeth)((TCPSocketEvent) e); + else if(m_pCb) + m_pCb((TCPSocketEvent) e); +} + +TCPSocketErr TCPSocket::checkInst() +{ + if(!m_pNetTcpSocket) + { + m_pNetTcpSocket = Net::tcpSocket(); + if(!m_pNetTcpSocket) + { + return TCPSOCKET_IF; //Interface did not return a socket (usually because a default interface does not exist) + } + m_pNetTcpSocket->setOnEvent(this, &TCPSocket::onNetTcpSocketEvent); + } + return TCPSOCKET_OK; +} + +#define CR(EVT) case EVT: return #EVT +char* TCPSocket::EventStr(TCPSocketEvent evt) +{ + switch(evt) { + CR(TCPSOCKET_CONNECTED); ///<Connected to host + CR(TCPSOCKET_ACCEPT); ///<Client is connected, must call accept() to get a new Socket + CR(TCPSOCKET_READABLE); ///<Data in buf + CR(TCPSOCKET_WRITEABLE); ///<Can write data to buf + CR(TCPSOCKET_CONTIMEOUT); ///<Connection timed out + CR(TCPSOCKET_CONRST); ///<Connection was reset by remote host + CR(TCPSOCKET_CONABRT); ///<Connection was aborted + CR(TCPSOCKET_ERROR); ///<Unknown error + CR(TCPSOCKET_DISCONNECTED); ///<Disconnected + } + return ""; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/NetServices/api/TCPSocket.h Sun Mar 24 11:25:31 2013 +0000 @@ -0,0 +1,149 @@ + +/* +Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +/** \file +TCP Socket header file +*/ + +#ifndef TCPSOCKET_H +#define TCPSOCKET_H + +#include "core/net.h" +#include "core/host.h" +//Essentially it is a safe interface to NetTcpSocket + +///TCP Socket error codes +enum TCPSocketErr +{ + __TCPSOCKET_MIN = -0xFFFF, + TCPSOCKET_SETUP, ///<TCPSocket not properly configured + TCPSOCKET_TIMEOUT, ///<Connection timed out + TCPSOCKET_IF, ///<Interface has problems, does not exist or is not initialized + TCPSOCKET_MEM, ///<Not enough mem + TCPSOCKET_INUSE, ///<Interface / Port is in use + TCPSOCKET_EMPTY, ///<Connections queue is empty + TCPSOCKET_RST, ///<Connection was reset by remote host +//... + TCPSOCKET_OK = 0 ///<Success +}; + +///TCP Socket Events +enum TCPSocketEvent +{ + TCPSOCKET_CONNECTED, ///<Connected to host + TCPSOCKET_ACCEPT, ///<Client is connected, must call accept() to get a new Socket + TCPSOCKET_READABLE, ///<Data in buf + TCPSOCKET_WRITEABLE, ///<Can write data to buf + TCPSOCKET_CONTIMEOUT, ///<Connection timed out + TCPSOCKET_CONRST, ///<Connection was reset by remote host + TCPSOCKET_CONABRT, ///<Connection was aborted + TCPSOCKET_ERROR, ///<Unknown error + TCPSOCKET_DISCONNECTED ///<Disconnected +}; + +class NetTcpSocket; +enum NetTcpSocketEvent; + +///This is a simple TCP Socket class +/** + This class exposes an API to deal with TCP Sockets +*/ +class TCPSocket +{ +public: + ///Creates a new socket + TCPSocket(); +protected: + TCPSocket(NetTcpSocket* pNetTcpSocket); +public: + ///Closes if needed and destroys the socket + ~TCPSocket(); //close() + + ///Binds the socket to (local) host + TCPSocketErr bind(const Host& me); + + ///Starts listening + TCPSocketErr listen(); + + ///Connects socket to host + TCPSocketErr connect(const Host& host); + + ///Accepts connection from client and gets connected socket + TCPSocketErr accept(Host* pClient, TCPSocket** ppNewTcpSocket); + + ///Sends data + /* + @return a negative error code or the number of bytes transmitted + */ + int /*if < 0 : TCPSocketErr*/ send(const char* buf, int len); + + ///Receives data + /* + @return a negative error code or the number of bytes received + */ + int /*if < 0 : TCPSocketErr*/ recv(char* buf, int len); + + /* TODO NTH : printf / scanf helpers that call send/recv */ + + ///Closes socket + TCPSocketErr close(); + + //Callbacks + ///Setups callback + /** + @param pMethod : callback function + */ + void setOnEvent( void (*pMethod)(TCPSocketEvent) ); + + class CDummy; + ///Setups callback + /** + @param pItem : instance of class on which to execute the callback method + @param pMethod : callback method + */ + template<class T> + void setOnEvent( T* pItem, void (T::*pMethod)(TCPSocketEvent) ) + { + m_pCbItem = (CDummy*) pItem; + m_pCbMeth = (void (CDummy::*)(TCPSocketEvent)) pMethod; + } + + ///Disables callback + void resetOnEvent(); + + static char* EventStr(TCPSocketEvent evt); +protected: + void onNetTcpSocketEvent(NetTcpSocketEvent e); + TCPSocketErr checkInst(); + +private: + NetTcpSocket* m_pNetTcpSocket; + + CDummy* m_pCbItem; + void (CDummy::*m_pCbMeth)(TCPSocketEvent); + + void (*m_pCb)(TCPSocketEvent); + +}; + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/NetServices/api/UDPSocket.cpp Sun Mar 24 11:25:31 2013 +0000 @@ -0,0 +1,114 @@ + +/* +Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#include "UDPSocket.h" +#include "if/net/netudpsocket.h" + +UDPSocket::UDPSocket() : m_pNetUdpSocket(NULL), m_pCbItem(NULL), m_pCbMeth(NULL), m_pCb(NULL) +{ + +} + +UDPSocket::~UDPSocket() //close() +{ + close(); +} + +UDPSocketErr UDPSocket::bind(const Host& me) +{ + UDPSocketErr udpSocketErr = checkInst(); + if(udpSocketErr) + return udpSocketErr; + return (UDPSocketErr) m_pNetUdpSocket->bind(me); +} + +int /*if < 0 : UDPSocketErr*/ UDPSocket::sendto(const char* buf, int len, Host* pHost) +{ + UDPSocketErr udpSocketErr = checkInst(); + if(udpSocketErr) + return udpSocketErr; + return m_pNetUdpSocket->sendto(buf, len, pHost); +} + +int /*if < 0 : UDPSocketErr*/ UDPSocket::recvfrom(char* buf, int len, Host* pHost) +{ + UDPSocketErr udpSocketErr = checkInst(); + if(udpSocketErr) + return udpSocketErr; + return m_pNetUdpSocket->recvfrom(buf, len, pHost); +} + +UDPSocketErr UDPSocket::close() +{ + if(!m_pNetUdpSocket) + return UDPSOCKET_SETUP; + m_pNetUdpSocket->resetOnEvent(); + UDPSocketErr udpSocketErr = (UDPSocketErr) m_pNetUdpSocket->close(); //Close (can already be closed) + Net::releaseUdpSocket(m_pNetUdpSocket); //And release it so it can be freed when properly removed + m_pNetUdpSocket = NULL; + return udpSocketErr; +} + +//Callbacks +void UDPSocket::setOnEvent( void (*pMethod)(UDPSocketEvent) ) +{ + m_pCb = pMethod; +} + +#if 0 //For info only +template<class T> +void UDPSocket::setOnEvent( T* pItem, void (T::*pMethod)(UDPSocketEvent) ) +{ + m_pCbItem = (CDummy*) pItem; + m_pCbMeth = (void (CDummy::*)(UDPSocketEvent)) pMethod; +} +#endif + +void UDPSocket::resetOnEvent() //Disable callback +{ + m_pCb = NULL; + m_pCbItem = NULL; + m_pCbMeth = NULL; +} + +void UDPSocket::onNetUdpSocketEvent(NetUdpSocketEvent e) +{ + if(m_pCbItem && m_pCbMeth) + (m_pCbItem->*m_pCbMeth)((UDPSocketEvent) e); + else if(m_pCb) + m_pCb((UDPSocketEvent) e); +} + +UDPSocketErr UDPSocket::checkInst() +{ + if(!m_pNetUdpSocket) + { + m_pNetUdpSocket = Net::udpSocket(); + if(!m_pNetUdpSocket) + { + return UDPSOCKET_IF; //Interface did not return a socket (usually because a default interface does not exist) + } + m_pNetUdpSocket->setOnEvent(this, &UDPSocket::onNetUdpSocketEvent); + } + return UDPSOCKET_OK; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/NetServices/api/UDPSocket.h Sun Mar 24 11:25:31 2013 +0000 @@ -0,0 +1,128 @@ + +/* +Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +/** \file +UDP Socket header file +*/ + +#ifndef UDPSOCKET_H +#define UDPSOCKET_H + +#include "core/net.h" +#include "core/host.h" +//Essentially it is a safe interface to NetUdpSocket + +///UDP Socket error codes +enum UDPSocketErr +{ + __UDPSOCKET_MIN = -0xFFFF, + UDPSOCKET_SETUP, ///<UDPSocket not properly configured + UDPSOCKET_IF, ///<Interface has problems, does not exist or is not initialized + UDPSOCKET_MEM, ///<Not enough mem + UDPSOCKET_INUSE, ///<Interface / Port is in use +//... + UDPSOCKET_OK = 0 ///<Success +}; + +///UDP Socket Event(s) +enum UDPSocketEvent //Only one event here for now, but keeps that model in case we need to implement some others +{ + UDPSOCKET_READABLE, ///<Data in buf +}; + +class NetUdpSocket; +enum NetUdpSocketEvent; + +///This is a simple UDP Socket class +/** + This class exposes an API to deal with UDP Sockets +*/ +class UDPSocket +{ +public: + ///Creates a new socket + UDPSocket(); + + ///Closes and destroys socket + ~UDPSocket(); //close() + + ///Binds the socket to local host or a multicast address + UDPSocketErr bind(const Host& me); + + ///Sends data + /* + @param pHost : host to send data to + @return a negative error code or the number of bytes transmitted + */ + int /*if < 0 : UDPSocketErr*/ sendto(const char* buf, int len, Host* pHost); + + ///Receives data + /* + @param pHost : host from which this piece of data comes from + @return a negative error code or the number of bytes received + */ + int /*if < 0 : UDPSocketErr*/ recvfrom(char* buf, int len, Host* pHost); + + /* TODO NTH : printf / scanf helpers that call send/recv */ + + ///Closes socket + UDPSocketErr close(); + + //Callbacks + ///Setups callback + /** + @param pMethod : callback function + */ + void setOnEvent( void (*pMethod)(UDPSocketEvent) ); + + class CDummy; + ///Setups callback + /** + @param pItem : instance of class on which to execute the callback method + @param pMethod : callback method + */ + template<class T> + void setOnEvent( T* pItem, void (T::*pMethod)(UDPSocketEvent) ) + { + m_pCbItem = (CDummy*) pItem; + m_pCbMeth = (void (CDummy::*)(UDPSocketEvent)) pMethod; + } + + ///Disables callback + void resetOnEvent(); + +protected: + void onNetUdpSocketEvent(NetUdpSocketEvent e); + UDPSocketErr checkInst(); + +private: + NetUdpSocket* m_pNetUdpSocket; + + CDummy* m_pCbItem; + void (CDummy::*m_pCbMeth)(UDPSocketEvent); + + void (*m_pCb)(UDPSocketEvent); + +}; + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/NetServices/core/host.h Sun Mar 24 11:25:31 2013 +0000 @@ -0,0 +1,109 @@ + +/* +Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifndef HOST_H +#define HOST_H + +#include "ipaddr.h" +#include <string.h> + +///Host information container +/** +This class is a container for data relative to a connection: +- IP Address +- Port number +- Host Name +*/ +class Host +{ +public: + ///Initiliazes host with null values + Host() : m_ip(0,0,0,0), m_port(0), m_name(NULL) + { + + } + + ///Initializes host + Host(const IpAddr& ip, const int& port, const char* name="" ) : m_ip(ip), m_port(port), m_name(NULL) + { + setName(name); + } + + ~Host() + { + if(m_name) + { + delete[] m_name; + } + } + + ///Returns IP address + const IpAddr& getIp() const + { + return m_ip; + } + + ///Returns port number + const int& getPort() const + { + return m_port; + } + + ///Returns host name + const char* getName() const + { + return m_name; + } + + ///Sets IP address + void setIp(const IpAddr& ip) + { + m_ip = ip; + } + + ///Sets port number + void setPort(int port) + { + m_port = port; + } + + ///Sets host name + void setName(const char* name) + { + if(m_name) + delete[] m_name; + int len = strlen(name); + if(len) + { + m_name = new char[len+1]; + strcpy(m_name, name); + } + } + +private: + IpAddr m_ip; + int m_port; + char* m_name; +}; + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/NetServices/core/ipaddr.cpp Sun Mar 24 11:25:31 2013 +0000 @@ -0,0 +1,104 @@ + +/* +Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#include "ipaddr.h" + +#include "netCfg.h" +#if NET_LWIP_STACK +#include "lwip/ip_addr.h" +#endif + + +#if NET_LWIP_STACK +IpAddr::IpAddr(ip_addr_t* pIp) +{ + *((uint32_t*)m_ip) = pIp->addr; +} +#endif + +///Initializes IP address with provided values +IpAddr::IpAddr(uint8_t ip0, uint8_t ip1, uint8_t ip2, uint8_t ip3) +{ + //We are in LE + m_ip[0] = ip0; + m_ip[1] = ip1; + m_ip[2] = ip2; + m_ip[3] = ip3; +} + +///Initializes IP address with null values +IpAddr::IpAddr() +{ + m_ip[0] = 0; + m_ip[1] = 0; + m_ip[2] = 0; + m_ip[3] = 0; +} + + +#if NET_LWIP_STACK +ip_addr_t IpAddr::getStruct() const +{ + ip_addr_t ip_struct; + ip_struct.addr = *((uint32_t*)m_ip); + return ip_struct; +} +#endif + +uint8_t IpAddr::operator[](unsigned int i) const +{ + uint8_t null = 0; + if( i > 3 ) + return null; + return m_ip[i]; +} + +bool IpAddr::isEq(const IpAddr& b) const +{ + return (*((uint32_t*)m_ip) == *((uint32_t*)(b.m_ip))); +} + +bool IpAddr::operator==(const IpAddr& b) const +{ + return isEq(b); +} + +bool IpAddr::operator!=(const IpAddr& b) const +{ + return !(operator==(b)); +} + +bool IpAddr::isNull() const +{ + return (*((uint32_t*)m_ip) == 0); +} + +bool IpAddr::isBroadcast() const +{ + return (*((uint32_t*)m_ip) == 0xFFFFFFFF); +} + +bool IpAddr::isMulticast() const +{ + return ((m_ip[0] & 0xF0) == 0xE0); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/NetServices/core/ipaddr.h Sun Mar 24 11:25:31 2013 +0000 @@ -0,0 +1,98 @@ + +/* +Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifndef IPADDR_H +#define IPADDR_H + +#include "netCfg.h" +#if NET_LWIP_STACK +typedef struct ip_addr ip_addr_t; +#endif + +#include "stdint.h" + +///IP Address container +/** +This class is a container for an IPv4 address. +*/ +class IpAddr //Basically a C++ frontend to ip_addr_t +{ +public: + #if NET_LWIP_STACK + IpAddr(ip_addr_t* pIp); + #endif + + ///Initializes IP address with provided values + IpAddr(uint8_t ip0, uint8_t ip1, uint8_t ip2, uint8_t ip3); + + ///Initializes IP address with null values + IpAddr(); + + #if NET_LWIP_STACK + ip_addr_t getStruct() const; + #endif + + ///Returns IP address byte # + uint8_t operator[](unsigned int i) const; + + ///Compares too addresses + /** + @return true if the two addresses are equal + */ + bool isEq(const IpAddr& b) const; + + ///Compares too addresses + /** + @return true if the two addresses are equal + */ + bool operator==(const IpAddr& b) const; + + ///Compares too addresses + /** + @return true if the two addresses are different + */ + bool operator!=(const IpAddr& b) const; + + ///Checks whether the address is null + /** + @return true if the address is null + */ + bool isNull() const; + + ///Checks whether the address is a broadcast address + /** + @return true if the address is a broadcast address + */ + bool isBroadcast() const; + + ///Checks whether the address is a multicast address + /** + @return true if the address is a multicast address + */ + bool isMulticast() const; + +private: + uint8_t m_ip[4]; +}; + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/NetServices/core/net.cpp Sun Mar 24 11:25:31 2013 +0000 @@ -0,0 +1,229 @@ + +/* +Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#include "net.h" + +#include "host.h" +#include "ipaddr.h" +#include "netservice.h" +#include "if/net/netif.h" +#include "if/net/nettcpsocket.h" +#include "if/net/netudpsocket.h" +#include "if/net/netdnsrequest.h" + +//#define __DEBUG +#include "dbg/dbg.h" + +Net::Net() : m_defaultIf(NULL), m_lpIf(), m_lpNetTcpSocket(), m_lpNetUdpSocket() +{ + +} + +Net::~Net() +{ + +} + + +void Net::poll() +{ + //DBG("\r\nNet : Services polling\r\n"); + + //Poll Services + NetService::servicesPoll(); + + //DBG("\r\nNet : Interfaces polling\r\n"); + + //Poll Interfaces + list<NetIf*>::iterator pIfIt; + + for ( pIfIt = net().m_lpIf.begin() ; pIfIt != net().m_lpIf.end(); pIfIt++ ) + { + (*pIfIt)->poll(); + } + + //DBG("\r\nNet : Sockets polling\r\n"); + + //Poll Tcp Sockets + list<NetTcpSocket*>::iterator pNetTcpSocketIt; + + for ( pNetTcpSocketIt = net().m_lpNetTcpSocket.begin() ; pNetTcpSocketIt != net().m_lpNetTcpSocket.end(); ) + { + (*pNetTcpSocketIt)->poll(); + + if( (*pNetTcpSocketIt)->m_closed && !((*pNetTcpSocketIt)->m_refs) ) + { + (*pNetTcpSocketIt)->m_removed = true; + delete (*pNetTcpSocketIt); + (*pNetTcpSocketIt) = NULL; + pNetTcpSocketIt = net().m_lpNetTcpSocket.erase(pNetTcpSocketIt); + } + else + { + pNetTcpSocketIt++; + } + } + + //Poll Udp Sockets + list<NetUdpSocket*>::iterator pNetUdpSocketIt; + + for ( pNetUdpSocketIt = net().m_lpNetUdpSocket.begin() ; pNetUdpSocketIt != net().m_lpNetUdpSocket.end(); ) + { + (*pNetUdpSocketIt)->poll(); + + if( (*pNetUdpSocketIt)->m_closed && !((*pNetUdpSocketIt)->m_refs) ) + { + (*pNetUdpSocketIt)->m_removed = true; + delete (*pNetUdpSocketIt); + (*pNetUdpSocketIt) = NULL; + pNetUdpSocketIt = net().m_lpNetUdpSocket.erase(pNetUdpSocketIt); + } + else + { + pNetUdpSocketIt++; + } + } + + +} + +NetTcpSocket* Net::tcpSocket(NetIf& netif) { + NetTcpSocket* pNetTcpSocket = netif.tcpSocket(); + pNetTcpSocket->m_refs++; + return pNetTcpSocket; +} + +NetTcpSocket* Net::tcpSocket() { //NetTcpSocket on default if + if ( net().m_defaultIf == NULL ) + return NULL; + NetTcpSocket* pNetTcpSocket = net().m_defaultIf->tcpSocket(); + pNetTcpSocket->m_refs++; + return pNetTcpSocket; +} + +void Net::releaseTcpSocket(NetTcpSocket* pNetTcpSocket) +{ + pNetTcpSocket->m_refs--; + if(!pNetTcpSocket->m_closed && !pNetTcpSocket->m_refs) + pNetTcpSocket->close(); +} + +NetUdpSocket* Net::udpSocket(NetIf& netif) { + NetUdpSocket* pNetUdpSocket = netif.udpSocket(); + pNetUdpSocket->m_refs++; + return pNetUdpSocket; +} + +NetUdpSocket* Net::udpSocket() { //NetTcpSocket on default if + if ( net().m_defaultIf == NULL ) + return NULL; + NetUdpSocket* pNetUdpSocket = net().m_defaultIf->udpSocket(); + pNetUdpSocket->m_refs++; + return pNetUdpSocket; +} + +void Net::releaseUdpSocket(NetUdpSocket* pNetUdpSocket) +{ + pNetUdpSocket->m_refs--; + if(!pNetUdpSocket->m_closed && !pNetUdpSocket->m_refs) + pNetUdpSocket->close(); +} + +NetDnsRequest* Net::dnsRequest(const char* hostname, NetIf& netif) { + return netif.dnsRequest(hostname); +} + +NetDnsRequest* Net::dnsRequest(const char* hostname) { //Create a new NetDnsRequest object from default if + if ( net().m_defaultIf == NULL ) + return NULL; + return net().m_defaultIf->dnsRequest(hostname); +} + +NetDnsRequest* Net::dnsRequest(Host* pHost, NetIf& netif) +{ + return netif.dnsRequest(pHost); +} + +NetDnsRequest* Net::dnsRequest(Host* pHost) //Creats a new NetDnsRequest object from default if +{ + if ( net().m_defaultIf == NULL ) + return NULL; + return net().m_defaultIf->dnsRequest(pHost); +} + +void Net::setDefaultIf(NetIf& netif) { + net().m_defaultIf = &netif; +} + +void Net::setDefaultIf(NetIf* pIf) +{ + net().m_defaultIf = pIf; +} + +NetIf* Net::getDefaultIf() { + return net().m_defaultIf; +} + +void Net::registerIf(NetIf* pIf) +{ + net().m_lpIf.push_back(pIf); +} + +void Net::unregisterIf(NetIf* pIf) +{ + if( net().m_defaultIf == pIf ) + net().m_defaultIf = NULL; + net().m_lpIf.remove(pIf); +} + +void Net::registerNetTcpSocket(NetTcpSocket* pNetTcpSocket) +{ + net().m_lpNetTcpSocket.push_back(pNetTcpSocket); + DBG("\r\nNetTcpSocket [ + %p ] %d\r\n", (void*)pNetTcpSocket, net().m_lpNetTcpSocket.size()); +} + +void Net::unregisterNetTcpSocket(NetTcpSocket* pNetTcpSocket) +{ + DBG("\r\nNetTcpSocket [ - %p ] %d\r\n", (void*)pNetTcpSocket, net().m_lpNetTcpSocket.size() - 1); + if(!pNetTcpSocket->m_removed) + net().m_lpNetTcpSocket.remove(pNetTcpSocket); +} + +void Net::registerNetUdpSocket(NetUdpSocket* pNetUdpSocket) +{ + net().m_lpNetUdpSocket.push_back(pNetUdpSocket); + DBG("\r\nNetUdpSocket [ + %p ] %d\r\n", (void*)pNetUdpSocket, net().m_lpNetUdpSocket.size()); +} + +void Net::unregisterNetUdpSocket(NetUdpSocket* pNetUdpSocket) +{ + DBG("\r\nNetUdpSocket [ - %p ] %d\r\n", (void*)pNetUdpSocket, net().m_lpNetUdpSocket.size() - 1); + if(!pNetUdpSocket->m_removed) + net().m_lpNetUdpSocket.remove(pNetUdpSocket); +} + +Net& Net::net() +{ + static Net* pInst = new Net(); //Called only once + return *pInst; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/NetServices/core/net.h Sun Mar 24 11:25:31 2013 +0000 @@ -0,0 +1,101 @@ + +/* +Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifndef NET_H +#define NET_H + +class NetIf; +class NetTcpSocket; +class NetUdpSocket; +class NetDnsRequest; + +#include <list> +using std::list; + +/* +#include "host.h" +#include "ipaddr.h" +#include "netservice.h" +#include "if/net/netif.h" +#include "if/net/nettcpsocket.h" +#include "if/net/netudpsocket.h" +#include "if/net/netdnsrequest.h" +*/ + +class Host; +class NetIf; +class NetTcpSocket; +class NetUdpSocket; +class NetDnsRequest; + +class Net +{ +private: + Net(); + ~Net(); +public: + static void poll(); //Poll every if & socket + + static NetTcpSocket* tcpSocket(NetIf& netif); + static NetTcpSocket* tcpSocket(); //Socket on default if + static void releaseTcpSocket(NetTcpSocket* pNetTcpSocket); + + static NetUdpSocket* udpSocket(NetIf& netif); + static NetUdpSocket* udpSocket(); //Socket on default if + static void releaseUdpSocket(NetUdpSocket* pNetUdpSocket); + + static NetDnsRequest* dnsRequest(const char* hostname, NetIf& netif); + static NetDnsRequest* dnsRequest(const char* hostname); //Create a new NetDnsRequest object from default if + + static NetDnsRequest* dnsRequest(Host* pHost, NetIf& netif); + static NetDnsRequest* dnsRequest(Host* pHost); //Create a new NetDnsRequest object from default if + + static void setDefaultIf(NetIf& netif); //Deprecated + static void setDefaultIf(NetIf* pIf); + static NetIf* getDefaultIf(); + +protected: + friend class NetIf; + friend class NetTcpSocket; + friend class NetUdpSocket; + + static void registerIf(NetIf* pIf); + static void unregisterIf(NetIf* pIf); + + static void registerNetTcpSocket(NetTcpSocket* pNetTcpSocket); + static void unregisterNetTcpSocket(NetTcpSocket* pNetTcpSocket); + + static void registerNetUdpSocket(NetUdpSocket* pNetUdpSocket); + static void unregisterNetUdpSocket(NetUdpSocket* pNetUdpSocket); + +private: + static Net& net(); //Return inst of singleton + + NetIf* m_defaultIf; + + list<NetIf*> m_lpIf; + list<NetTcpSocket*> m_lpNetTcpSocket; + list<NetUdpSocket*> m_lpNetUdpSocket; +}; + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/NetServices/core/netservice.cpp Sun Mar 24 11:25:31 2013 +0000 @@ -0,0 +1,88 @@ + +/* +Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#include "netservice.h" +#include "net.h" + +//#define __DEBUG +#include "dbg/dbg.h" + +NetService::NetService(bool owned /*= true*/) : m_closed(false), m_removed(false), m_owned(owned) +{ + NetService::lpServices().push_back(this); + DBG("\r\n[ + %p ] %d\r\n", (void*)this, lpServices().size()); +} + +NetService::~NetService() +{ + // DBG("\r\nService removed\r\n"); +// DBG("\r\nNow %d services running\r\n", lpServices().size()-1); + DBG("\r\n[ - %p ] %d\r\n", (void*)this, lpServices().size()-1); + if((!m_owned) || (!m_removed)) //Destructor was not called by servicesPoll() + { + if(m_owned) + DBG("\r\nWARN!!!Service removed in dtor!!!\r\n"); + NetService::lpServices().remove(this); + } +} + +void NetService::poll() +{ + +} + +void NetService::servicesPoll() //Poll all registered services & destroy closed ones +{ + list<NetService*>::iterator it; + DBG("\r\nServices polling over %d services\r\n", lpServices().size()); + for( it = lpServices().begin(); it != lpServices().end(); ) + { + if( (*it)->m_owned && (*it)->m_closed ) + { + DBG("\r\nService %p is flagged as closed\r\n", (*it)); + (*it)->m_removed = true; + delete (*it); + it = lpServices().erase(it); + } + else + { + //DBG("Service %p polling start\n", (*it)); + (*it)->poll(); + //DBG("Service %p polling end\n", (*it)); + it++; + } + } + +} + +void NetService::close() +{ + DBG("\r\nService %p to be closed (owned = %d)\r\n", this, m_owned); + m_closed = true; +} + +list<NetService*>& NetService::lpServices() +{ + static list<NetService*>* pInst = new list<NetService*>(); //Called only once + return *pInst; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/NetServices/core/netservice.h Sun Mar 24 11:25:31 2013 +0000 @@ -0,0 +1,67 @@ + +/* +Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +/** +\file Net Service base class header file +*/ + +#ifndef NETSERVICE_H +#define NETSERVICE_H + +#include <list> +using std::list; + +///Net Service base class +/** +Each connection-oriented object can register as service (by inheriting this class), so that it is polled regularly. +It notifies the pool when the connection is terminated so that it can be destroyed. +*/ +class NetService +{ +public: + ///Instantiates a new service + /** + @param owned If true the object is owned by the pool and will be destroyed on closure. + */ + NetService(bool owned = true); //Is owned by the pool? + virtual ~NetService(); + + ///This method can be inherited so that it is called on each @a Net::poll() call. + virtual void poll(); + + static void servicesPoll(); //Poll all registered services & destroy closed ones + +protected: + ///This flags the service as to be destructed if owned by the pool. + void close(); + +private: + bool m_closed; + bool m_removed; + bool m_owned; + + static list<NetService*>& lpServices(); //Helper to prevent static initialization fiasco + +}; + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/NetServices/dbg/dbg.cpp Sun Mar 24 11:25:31 2013 +0000 @@ -0,0 +1,63 @@ + +/* +Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#define __LWIP_DEBUG +#define __DEBUG +#include "dbg.h" +#include "mbed.h" +#include <cstdarg> + +void DebugStream::debug(const char* format, ...) +{ + va_list argp; + + va_start(argp, format); + vprintf(format, argp); + va_end(argp); +} + +void DebugStream::release() +{ + +} + +void DebugStream::breakPoint(const char* file, int line) +{ + printf("\r\nBREAK in %s at line %d\r\n", file, line); + fflush(stdout); + getchar(); + fflush(stdin); +} + +/* +int snprintf(char *str, int size, const char *format, ...) +{ + va_list argp; + + va_start(argp, format); + vsprintf(str, format, argp); + va_end(argp); + + return strlen(str); +} +*/
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/NetServices/dbg/dbg.h Sun Mar 24 11:25:31 2013 +0000 @@ -0,0 +1,94 @@ + +/* +Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +/** \file +Debugging helpers header file +*/ + +//#ifdef DBG_H +//#define DBG_H + +#ifdef __LWIP_DEBUG +#define __DEBUG +#endif + +/*! + \def __DEBUG + To define to enable debugging in one file +*/ + +#ifdef __DEBUG + +#ifndef __DEBUGSTREAM +#define __DEBUGSTREAM + + +class DebugStream +{ +public: +static void debug(const char* format, ...); +static void release(); +static void breakPoint(const char* file, int line); +private: + +}; + +#undef DBG +#undef DBG_END +#undef BREAK + +///Debug output (if enabled), same syntax as printf, with heading info +#define DBG(...) do{ DebugStream::debug("[%s:%s@%d] ", __FILE__, __FUNCTION__, __LINE__); DebugStream::debug(__VA_ARGS__); } while(0); + +///Debug output (if enabled), same syntax as printf, no heading info +#define DBGL(...) do{ DebugStream::debug(__VA_ARGS__); } while(0); +#define DBG_END DebugStream::release + +///Break point usin serial debug interface (if debug enbaled) +#define BREAK() DebugStream::breakPoint(__FILE__, __LINE__) +#endif + +#else +#undef DBG +#undef DBG_END +#undef BREAK +#define DBG(...) +#define DBG_END() +#define BREAK() +#endif + +#ifdef __LWIP_DEBUG +#ifndef __SNPRINTF +#define __SNPRINTF +#include "mbed.h" + +//int snprintf(char *str, int size, const char *format, ...); +#endif +#endif + +#ifdef __LWIP_DEBUG +#undef __DEBUG +#endif + +//#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/NetServices/if/net/netdnsrequest.cpp Sun Mar 24 11:25:31 2013 +0000 @@ -0,0 +1,66 @@ + +/* +Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#include "netdnsrequest.h" +#include <string.h> + +NetDnsRequest::NetDnsRequest(const char* hostname) : NetService(), m_ip(0,0,0,0), m_pCbItem(NULL), m_pCbMeth(NULL), m_pHost(NULL), m_closed(false) +{ + m_hostname = new char[strlen(hostname)+1]; + strcpy( m_hostname, hostname ); +} + +NetDnsRequest::NetDnsRequest(Host* pHost) : NetService(), m_ip(0,0,0,0), m_pCbItem(NULL), m_pCbMeth(NULL), m_closed(false) +{ + m_hostname = (char*) pHost->getName(); + m_pHost = pHost; +} + +NetDnsRequest::~NetDnsRequest() +{ + close(); +} + +void NetDnsRequest::getResult(IpAddr* pIp) +{ + if( pIp != NULL ) + *pIp = m_ip; +} + +void NetDnsRequest::close() +{ + if(m_closed) + return; + m_closed = true; + if( !m_pHost ) + delete[] m_hostname; + NetService::close(); +} + +void NetDnsRequest::onReply(NetDnsReply reply) //Must be called by impl when the request completes +{ + if( m_pHost ) + m_pHost->setIp(m_ip); + if(m_pCbItem && m_pCbMeth) + (m_pCbItem->*m_pCbMeth)(reply); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/NetServices/if/net/netdnsrequest.h Sun Mar 24 11:25:31 2013 +0000 @@ -0,0 +1,84 @@ + +/* +Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifndef NETDNSREQUEST_H +#define NETDNSREQUEST_H + +//class Socket; +class Host; +//class NetService; +class NetDnsRequest; + +#include "netservice.h" +#include "ipaddr.h" +#include "host.h" + +enum NetDnsReply +{ + NETDNS_PRTCL, + NETDNS_NOTFOUND, //Hostname is unknown + NETDNS_ERROR, //Problem with DNS Service + //... + NETDNS_FOUND, +}; + +class NetDnsRequest : public NetService +{ +public: + NetDnsRequest(const char* hostname); + NetDnsRequest(Host* pHost); + virtual ~NetDnsRequest(); + + class CDummy; + template<class T> + //Linker bug : Must be defined here :( + void setOnReply( T* pItem, void (T::*pMethod)(NetDnsReply) ) + { + m_pCbItem = (CDummy*) pItem; + m_pCbMeth = (void (CDummy::*)(NetDnsReply)) pMethod; + } + + //Execute request & return OK if found, NOTFOUND or ERROR on error, or PROCESSING if the request has not completed yet + // virtual DnsErr pollState() = 0; + virtual void poll() = 0; //NetService fn + + void getResult(IpAddr* pIp); + + virtual void close(); + +protected: + void onReply(NetDnsReply reply); //Must be called by impl when the request completes + + IpAddr m_ip; + char* m_hostname; + +private: + CDummy* m_pCbItem; + void (CDummy::*m_pCbMeth)(NetDnsReply); + + Host* m_pHost; + + bool m_closed; +}; + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/NetServices/if/net/netif.cpp Sun Mar 24 11:25:31 2013 +0000 @@ -0,0 +1,43 @@ + +/* +Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#include "core/host.h" +#include "netif.h" +#include "core/net.h" + +NetIf::NetIf() : m_ip(0,0,0,0) +{ + Net::registerIf(this); + //Assuming that we only have one if + Net::setDefaultIf(this); +} + +NetIf::~NetIf() +{ + Net::unregisterIf(this); +} + +IpAddr NetIf::getIp() const +{ + return m_ip; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/NetServices/if/net/netif.h Sun Mar 24 11:25:31 2013 +0000 @@ -0,0 +1,64 @@ + +/* +Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifndef NETIF_H +#define NETIF_H + +#include "core/ipaddr.h" +/* +#include "nettcpsocket.h" +#include "netudpsocket.h" +#include "netdnsrequest.h" +*/ +class NetTcpSocket; +class NetUdpSocket; +class NetDnsRequest; + +#if 0 +enum NetifEvent +{ + NETIF_CONNECTED, //Connected, can create & use sockets now + NETIF_DNSREPLY, + NETIF_DISCONNECTED +}; +#endif + +class NetIf +{ +public: + NetIf(); + virtual ~NetIf(); + virtual NetTcpSocket* tcpSocket() = 0; //Create a new tcp socket + virtual NetUdpSocket* udpSocket() = 0; //Create a new udp socket + virtual void poll() = 0; + virtual NetDnsRequest* dnsRequest(const char* hostname) = 0; //Create a new NetDnsRequest object + virtual NetDnsRequest* dnsRequest(Host* pHost) = 0; //Create a new NetDnsRequest object + + //!Returns the IP of the interface once it's connected + IpAddr getIp() const; + +protected: + IpAddr m_ip; +}; + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/NetServices/if/net/nettcpsocket.cpp Sun Mar 24 11:25:31 2013 +0000 @@ -0,0 +1,82 @@ + +/* +Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#include "nettcpsocket.h" + +//#define __DEBUG +#include "dbg/dbg.h" + +NetTcpSocket::NetTcpSocket() : m_host(), m_client(), m_refs(0), m_closed(false), m_removed(false), m_pCbItem(NULL), m_pCbMeth(NULL), m_events() +{ + Net::registerNetTcpSocket(this); +} + +NetTcpSocket::~NetTcpSocket() //close() +{ + Net::unregisterNetTcpSocket(this); +} + + +//Callbacks +#ifdef __LINKER_BUG_SOLVED__ +void NetTcpSocket::setOnEvent() +{ + m_pCbItem = (CDummy*) pItem; + m_pCbMeth = (void (CDummy::*)(NetTcpSocketEvent)) pMethod; +} +#endif + +void NetTcpSocket::resetOnEvent() +{ + m_pCbItem = NULL; + m_pCbMeth = NULL; +} + +void NetTcpSocket::queueEvent(NetTcpSocketEvent e) +{ + m_events.push(e); +} + +void NetTcpSocket::discardEvents() +{ + while( !m_events.empty() ) + { + m_events.pop(); + } +} + +void NetTcpSocket::flushEvents() //To be called during polling +{ + while( !m_events.empty() ) + { + onEvent(m_events.front()); + m_events.pop(); + } +} + +void NetTcpSocket::onEvent(NetTcpSocketEvent e) //To be called during polling +{ + if(m_pCbItem && m_pCbMeth) + (m_pCbItem->*m_pCbMeth)(e); +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/NetServices/if/net/nettcpsocket.h Sun Mar 24 11:25:31 2013 +0000 @@ -0,0 +1,118 @@ + +/* +Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifndef NETTCPSOCKET_H +#define NETTCPSOCKET_H + +#include "net.h" +#include "host.h" + +#include <queue> +using std::queue; + +//Implements a Berkeley-like socket if +//Can be interfaced either to lwip or a Telit module + +enum NetTcpSocketErr +{ + __NETTCPSOCKET_MIN = -0xFFFF, + NETTCPSOCKET_SETUP, //NetTcpSocket not properly configured + NETTCPSOCKET_TIMEOUT, + NETTCPSOCKET_IF, //If has problems + NETTCPSOCKET_MEM, //Not enough mem + NETTCPSOCKET_INUSE, //If/Port is in use + NETTCPSOCKET_EMPTY, //Connections queue is empty + NETTCPSOCKET_RST, // Connection was reset by remote host +//... + NETTCPSOCKET_OK = 0 +}; + +enum NetTcpSocketEvent +{ + NETTCPSOCKET_CONNECTED, //Connected to host, must call accept() if we were listening + NETTCPSOCKET_ACCEPT, //Connected to client + NETTCPSOCKET_READABLE, //Data in buf + NETTCPSOCKET_WRITEABLE, //Can write data to buf + NETTCPSOCKET_CONTIMEOUT, + NETTCPSOCKET_CONRST, + NETTCPSOCKET_CONABRT, + NETTCPSOCKET_ERROR, + NETTCPSOCKET_DISCONNECTED +}; + + +class NetTcpSocket +{ +public: + NetTcpSocket(); + virtual ~NetTcpSocket(); //close() + + virtual NetTcpSocketErr bind(const Host& me) = 0; + virtual NetTcpSocketErr listen() = 0; + virtual NetTcpSocketErr connect(const Host& host) = 0; + virtual NetTcpSocketErr accept(Host* pClient, NetTcpSocket** ppNewNetTcpSocket) = 0; + + virtual int /*if < 0 : NetTcpSocketErr*/ send(const char* buf, int len) = 0; + virtual int /*if < 0 : NetTcpSocketErr*/ recv(char* buf, int len) = 0; + + virtual NetTcpSocketErr close() = 0; + + virtual NetTcpSocketErr poll() = 0; + + class CDummy; + //Callbacks + template<class T> + //Linker bug : Must be defined here :( + void setOnEvent( T* pItem, void (T::*pMethod)(NetTcpSocketEvent) ) + { + m_pCbItem = (CDummy*) pItem; + m_pCbMeth = (void (CDummy::*)(NetTcpSocketEvent)) pMethod; + } + + void resetOnEvent(); //Disable callback + +protected: + void queueEvent(NetTcpSocketEvent e); + void discardEvents(); + void flushEvents(); //to be called during polling + + Host m_host; + Host m_client; + + friend class Net; + int m_refs; + + bool m_closed; + bool m_removed; + +private: + //We do not want to execute user code in interrupt routines, so we queue events until the server is polled + //If we port this to a multithreaded OS, we could avoid this (however some functions here are not thread-safe, so beware ;) ) + void onEvent(NetTcpSocketEvent e); //To be called on poll + CDummy* m_pCbItem; + void (CDummy::*m_pCbMeth)(NetTcpSocketEvent); + queue<NetTcpSocketEvent> m_events; + +}; + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/NetServices/if/net/netudpsocket.cpp Sun Mar 24 11:25:31 2013 +0000 @@ -0,0 +1,82 @@ + +/* +Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#include "netudpsocket.h" + +//#define __DEBUG +#include "dbg/dbg.h" + +NetUdpSocket::NetUdpSocket() : m_host(), m_client(), m_refs(0), m_closed(false), m_removed(false), m_pCbItem(NULL), m_pCbMeth(NULL), m_events() +{ + Net::registerNetUdpSocket(this); +} + +NetUdpSocket::~NetUdpSocket() //close() +{ + Net::unregisterNetUdpSocket(this); +} + + +//Callbacks +#if 0 //Just for info +void NetUdpSocket::setOnEvent() +{ + m_pCbItem = (CDummy*) pItem; + m_pCbMeth = (void (CDummy::*)(NetUdpSocketEvent)) pMethod; +} +#endif + +void NetUdpSocket::resetOnEvent() +{ + m_pCbItem = NULL; + m_pCbMeth = NULL; +} + +void NetUdpSocket::queueEvent(NetUdpSocketEvent e) +{ + m_events.push(e); +} + +void NetUdpSocket::discardEvents() +{ + while( !m_events.empty() ) + { + m_events.pop(); + } +} + +void NetUdpSocket::flushEvents() //To be called during polling +{ + while( !m_events.empty() ) + { + onEvent(m_events.front()); + m_events.pop(); + } +} + +void NetUdpSocket::onEvent(NetUdpSocketEvent e) //To be called during polling +{ + if(m_pCbItem && m_pCbMeth) + (m_pCbItem->*m_pCbMeth)(e); +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/NetServices/if/net/netudpsocket.h Sun Mar 24 11:25:31 2013 +0000 @@ -0,0 +1,106 @@ + +/* +Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifndef NETUDPSOCKET_H +#define NETUDPSOCKET_H + +#include "net.h" +#include "host.h" + +#include <queue> +using std::queue; + +//Implements a Berkeley-like socket if +//Can be interfaced either to lwip or a Telit module + +enum NetUdpSocketErr +{ + __NETUDPSOCKET_MIN = -0xFFFF, + NETUDPSOCKET_SETUP, //NetUdpSocket not properly configured + NETUDPSOCKET_IF, //If has problems + NETUDPSOCKET_MEM, //Not enough mem + NETUDPSOCKET_INUSE, //If/Port is in use +//... + NETUDPSOCKET_OK = 0 +}; + +enum NetUdpSocketEvent //Only one lonely event here... but who knows, maybe some day there'll be another one! +{ + NETUDPSOCKET_READABLE, //Data in buf +}; + + +class NetUdpSocket +{ +public: + NetUdpSocket(); + virtual ~NetUdpSocket(); //close() + + virtual NetUdpSocketErr bind(const Host& me) = 0; + + virtual int /*if < 0 : NetUdpSocketErr*/ sendto(const char* buf, int len, Host* pHost) = 0; + virtual int /*if < 0 : NetUdpSocketErr*/ recvfrom(char* buf, int len, Host* pHost) = 0; + + /* TODO NTH : printf / scanf helpers that call send/recv */ + + virtual NetUdpSocketErr close() = 0; + + virtual NetUdpSocketErr poll() = 0; + + class CDummy; + //Callbacks + template<class T> + //Linker bug : Must be defined here :( + void setOnEvent( T* pItem, void (T::*pMethod)(NetUdpSocketEvent) ) + { + m_pCbItem = (CDummy*) pItem; + m_pCbMeth = (void (CDummy::*)(NetUdpSocketEvent)) pMethod; + } + + void resetOnEvent(); //Disable callback + +protected: + void queueEvent(NetUdpSocketEvent e); + void discardEvents(); + void flushEvents(); //to be called during polling + + Host m_host; + Host m_client; + + friend class Net; + int m_refs; + + bool m_closed; + bool m_removed; + +private: + //We do not want to execute user code in interrupt routines, so we queue events until the server is polled + //If we port this to a multithreaded OS, we could avoid this (however some functions here are not thread-safe, so beware ;) ) + void onEvent(NetUdpSocketEvent e); //To be called on poll + CDummy* m_pCbItem; + void (CDummy::*m_pCbMeth)(NetUdpSocketEvent); + queue<NetUdpSocketEvent> m_events; + +}; + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/NetServices/netCfg.h Sun Mar 24 11:25:31 2013 +0000 @@ -0,0 +1,11 @@ +#ifndef NET_CFG_H +#define NET_GPRS 1 +#define NET_PPP 1 +#define NET_GPRS_MODULE 1 +#define NET_ETH 1 +#define NET_USB_SERIAL 1 +#define NET_CFG_H 1 +#define NET_UMTS 1 +#define NET_USB 1 +#define NET_LWIP_STACK 0 +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/NetServices/services/http/client/HTTPClient.cpp Sun Mar 24 11:25:31 2013 +0000 @@ -0,0 +1,818 @@ + +/* +Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#include "core/netservice.h" +#include "HTTPClient.h" +#include "../util/base64.h" +#include "../util/url.h" + +//#define __DEBUG +//#include "dbg/dbg.h" +//#define DEBUG +#include "w5200debug.h" + +#define HTTP_REQUEST_TIMEOUT 30000//15000 +#define HTTP_PORT 80 + +#define CHUNK_SIZE 256 + +HTTPClient::HTTPClient() : NetService(false) /*Not owned by the pool*/, m_meth(HTTP_GET), m_pCbItem(NULL), m_pCbMeth(NULL), m_pCb(NULL), +m_watchdog(), m_timeout(0), m_pDnsReq(NULL), m_server(), m_path(), +m_closed(true), m_state(HTTP_CLOSED), +m_pDataOut(NULL), m_pDataIn(NULL), m_dataChunked(false), m_dataPos(0), m_dataLen(0), m_httpResponseCode(0), m_blockingResult(HTTP_PROCESSING) + +{ + setTimeout(HTTP_REQUEST_TIMEOUT); + m_buf = new char[CHUNK_SIZE]; + DBG("New HTTPClient %p\n",this); +} + +HTTPClient::~HTTPClient() +{ + close(); + delete[] m_buf; +} + +void HTTPClient::basicAuth(const char* user, const char* password) //Basic Authentification +{ + if(user==NULL) + { + m_reqHeaders.erase("Authorization"); //Remove auth str + return; + } + string auth = "Basic "; + string decStr = user; + decStr += ":"; + decStr += password; + auth.append( Base64::encode(decStr) ); + DBG("Auth str is %s\n", auth.c_str()); + m_reqHeaders["Authorization"] = auth; +} + +//High Level setup functions +HTTPResult HTTPClient::get(const char* uri, HTTPData* pDataIn) //Blocking +{ + doGet(uri, pDataIn); + return blockingProcess(); +} + +HTTPResult HTTPClient::get(const char* uri, HTTPData* pDataIn, void (*pMethod)(HTTPResult)) //Non blocking +{ + setOnResult(pMethod); + doGet(uri, pDataIn); + return HTTP_PROCESSING; +} + +#if 0 //For info only +template<class T> +HTTPResult HTTPClient::get(const char* uri, HTTPData* pDataIn, T* pItem, void (T::*pMethod)(HTTPResult)) //Non blocking +{ + setOnResult(pItem, pMethod); + doGet(uri, pDataIn); + return HTTP_PROCESSING; +} +#endif + +HTTPResult HTTPClient::post(const char* uri, const HTTPData& dataOut, HTTPData* pDataIn) //Blocking +{ + doPost(uri, dataOut, pDataIn); + return blockingProcess(); +} + +HTTPResult HTTPClient::post(const char* uri, const HTTPData& dataOut, HTTPData* pDataIn, void (*pMethod)(HTTPResult)) //Non blocking +{ + setOnResult(pMethod); + doPost(uri, dataOut, pDataIn); + return HTTP_PROCESSING; +} + +#if 0 //For info only +template<class T> +HTTPResult HTTPClient::post(const char* uri, const HTTPData& dataOut, HTTPData* pDataIn, T* pItem, void (T::*pMethod)(HTTPResult)) //Non blocking +{ + setOnResult(pItem, pMethod); + doPost(uri, dataOut, pDataIn); + return HTTP_PROCESSING; +} +#endif + +void HTTPClient::doGet(const char* uri, HTTPData* pDataIn) +{ + m_meth = HTTP_GET; + setup(uri, NULL, pDataIn); +} + +void HTTPClient::doPost(const char* uri, const HTTPData& dataOut, HTTPData* pDataIn) +{ + m_meth = HTTP_POST; + setup(uri, (HTTPData*) &dataOut, pDataIn); +} + +void HTTPClient::setOnResult( void (*pMethod)(HTTPResult) ) +{ + m_pCb = pMethod; + m_pCbItem = NULL; + m_pCbMeth = NULL; +} + +#if 0 //For info only +template<class T> +void HTTPClient::setOnResult( T* pItem, void (T::*pMethod)(NtpResult) ) +{ + m_pCb = NULL; + m_pCbItem = (CDummy*) pItem; + m_pCbMeth = (void (CDummy::*)(NtpResult)) pMethod; +} +#endif + +void HTTPClient::setTimeout(int ms) +{ + m_timeout = ms; + //resetTimeout(); +} + +void HTTPClient::poll() //Called by NetServices +{ + if(m_closed) + { + return; + } + if(m_watchdog.read_ms()>m_timeout) + { + onTimeout(); + } + else if(m_state == HTTP_READ_DATA_INCOMPLETE) + { + readData(); //Try to read more data + if( m_state == HTTP_DONE ) + { + //All data has been read, close w/ success :) + DBG("Done :)!\n"); + onResult(HTTP_OK); + close(); + } + } + +} + +int HTTPClient::getHTTPResponseCode() +{ + return m_httpResponseCode; +} + +void HTTPClient::setRequestHeader(const string& header, const string& value) +{ + m_reqHeaders[header] = value; +} + +string& HTTPClient::getResponseHeader(const string& header) +{ + return m_respHeaders[header]; +} + +void HTTPClient::resetRequestHeaders() +{ + m_reqHeaders.clear(); +} + +void HTTPClient::resetTimeout() +{ + m_watchdog.reset(); + m_watchdog.start(); +} + +void HTTPClient::init() //Create and setup socket if needed +{ + close(); //Remove previous elements + if(!m_closed) //Already opened + return; + m_state = HTTP_WRITE_HEADERS; + m_pTCPSocket = new TCPSocket; + m_pTCPSocket->setOnEvent(this, &HTTPClient::onTCPSocketEvent); + m_closed = false; + m_httpResponseCode = 0; +} + +void HTTPClient::close() +{ + if(m_closed) + return; + m_state = HTTP_CLOSED; + //Now Request headers are kept btw requests unless resetRequestHeaders() is called + //m_reqHeaders.clear(); //Clear headers for next requests + m_closed = true; //Prevent recursive calling or calling on an object being destructed by someone else + m_watchdog.stop(); //Stop timeout + m_watchdog.reset(); + m_pTCPSocket->resetOnEvent(); + m_pTCPSocket->close(); + delete m_pTCPSocket; + m_pTCPSocket = NULL; + if( m_pDnsReq ) + { + m_pDnsReq->close(); + delete m_pDnsReq; + m_pDnsReq = NULL; + } +} + +void HTTPClient::setup(const char* uri, HTTPData* pDataOut, HTTPData* pDataIn) //Setup request, make DNS Req if necessary +{ + init(); //Initialize client in known state, create socket + m_pDataOut = pDataOut; + m_pDataIn = pDataIn; + resetTimeout(); + + //Erase previous headers + //Do NOT clear m_reqHeaders as they might have already set before connecting + m_respHeaders.clear(); + + //Erase response buffer + if(m_pDataIn) + m_pDataIn->clear(); + + //Assert that buffers are initialized properly + m_dataLen = 0; + m_bufRemainingLen = 0; + + Url url; + url.fromString(uri); + + m_path = url.getPath(); + + m_server.setName(url.getHost().c_str()); + + if( url.getPort() > 0 ) + { + m_server.setPort( url.getPort() ); + } + else + { + m_server.setPort( HTTP_PORT ); + } + + DBG("URL parsed,\r\nHost: %s\r\nPort: %d\r\nPath: %s\n", url.getHost().c_str(), url.getPort(), url.getPath().c_str()); + + IpAddr ip; + if( url.getHostIp(&ip) ) + { + m_server.setIp(ip); + connect(); + } + else + { + DBG("DNS Query...\n"); + m_pDnsReq = new DNSRequest(); + m_pDnsReq->setOnReply(this, &HTTPClient::onDNSReply); + m_pDnsReq->resolve(&m_server); + DBG("HTTPClient : DNSRequest %p\n", m_pDnsReq); + } + +} + +void HTTPClient::connect() //Start Connection +{ + resetTimeout(); + DBG("Connecting...\n"); + m_pTCPSocket->connect(m_server); +} + +#define MIN(a,b) ((a)<(b)?(a):(b)) +#define ABS(a) (((a)>0)?(a):0) +int HTTPClient::tryRead() //Try to read data from tcp packet and put in the HTTPData object +{ + int len = 0; + int readLen; + do + { + if(m_state == HTTP_READ_DATA_INCOMPLETE) //First try to complete buffer copy + { + readLen = m_bufRemainingLen; + /* if (readLen == 0) + { + m_state = HTTP_READ_DATA; + continue; + }*/ + } + else + { + readLen = m_pTCPSocket->recv(m_buf, MIN(ABS(m_dataLen-m_dataPos),CHUNK_SIZE)); + if(readLen < 0) //Error + { + return readLen; + } + + DBG("%d bytes read\n", readLen); + + m_pBufRemaining = m_buf; + } + if (readLen == 0) + { + m_state = HTTP_READ_DATA; + return len; + } + + DBG("Trying to write %d bytes\n", readLen); + + int writtenLen = m_pDataIn->write(m_pBufRemaining, readLen); + m_dataPos += writtenLen; + + DBG("%d bytes written\n", writtenLen); + + if(writtenLen<readLen) //Data was not completely written + { + m_pBufRemaining += writtenLen; + m_bufRemainingLen = readLen - writtenLen; + m_state = HTTP_READ_DATA_INCOMPLETE; + return len + writtenLen; + } + else + { + m_state = HTTP_READ_DATA; + } + len += readLen; + } while(readLen>0); + + return len; +} + +void HTTPClient::readData() //Data has been read +{ + if(m_pDataIn == NULL) //Nothing to read (in HEAD for instance, not supported now) + { + m_state = HTTP_DONE; + return; + } + DBG("Reading response...\n"); + int len = 0; + do + { + if(m_dataChunked && (m_state != HTTP_READ_DATA_INCOMPLETE)) + { + if(m_dataLen==0) + { + DBG("Reading chunk length...\n"); + //New block + static char chunkHeader[16]; + //We use m_dataPos to retain the read position in chunkHeader, it has been set to 0 before the first call of readData() + m_dataPos += readLine(chunkHeader + m_dataPos, ABS(16 - m_dataPos)); + if( m_dataPos > 0 ) + { + if( chunkHeader[strlen(chunkHeader)-1] == 0x0d ) + { + sscanf(chunkHeader, "%x%*[^\r\n]", &m_dataLen); + DBG("Chunk length is %d\n", m_dataLen); + m_dataPos = 0; + } + else + { + //Wait for end of line + DBG("Wait for CRLF\n"); + return; + } + } + else + { + DBG("Wait for data\n"); + //Wait for data + return; + } + } + } + + //Proper data recovery + len = tryRead(); + if(len<0) //Error + { + onResult(HTTP_CONN); + return; + } + + if(len>0) + resetTimeout(); + + if(m_state == HTTP_READ_DATA_INCOMPLETE) + return; + + //Chunk Tail + if(m_dataChunked) + { + if(m_dataPos >= m_dataLen) + { + DBG("Chunk read, wait for CRLF\n"); + char chunkTail[3]; + m_dataPos += readLine(chunkTail, 3); + } + + if(m_dataPos >= m_dataLen + 1) //1 == strlen("\n"), + { + DBG("End of chunk\n"); + if(m_dataLen==0) + { + DBG("End of file\n"); + //End of file + m_state = HTTP_DONE; //Done + } + m_dataLen = 0; + m_dataPos = 0; + } + } + + } while(len>0); + + + if(!m_dataChunked && (m_dataPos >= m_dataLen)) //All Data has been received + { + DBG("End of file\n"); + m_state = HTTP_DONE; //Done + } +} + +void HTTPClient::writeData() //Data has been written & buf is free +{ + if(m_pDataOut == NULL) //Nothing to write (in POST for instance) + { + m_dataLen = 0; //Reset Data Length + m_state = HTTP_READ_HEADERS; + return; + } + int len = m_pDataOut->read(m_buf, CHUNK_SIZE); + if( m_dataChunked ) + { + //Write chunk header + char chunkHeader[16]; + sprintf(chunkHeader, "%d\r\n", len); + int ret = m_pTCPSocket->send(chunkHeader, strlen(chunkHeader)); + if(ret < 0)//Error + { + onResult(HTTP_CONN); + return; + } + } + m_pTCPSocket->send(m_buf, len); + m_dataPos+=len; + if( m_dataChunked ) + { + m_pTCPSocket->send("\r\n", 2); //Chunk-terminating CRLF + } + if( ( !m_dataChunked && (m_dataPos >= m_dataLen) ) + || ( m_dataChunked && !len ) ) //All Data has been sent + { + m_dataLen = 0; //Reset Data Length + m_state = HTTP_READ_HEADERS; //Wait for resp + } +} + +void HTTPClient::onTCPSocketEvent(TCPSocketEvent e) +{ + DBG("Event %d in HTTPClient::onTCPSocketEvent()\n", e); + + if(m_closed) + { + DBG("WARN: Discarded\n"); + return; + } + + switch(e) + { + case TCPSOCKET_READABLE: //Incoming data + resetTimeout(); + switch(m_state) + { + case HTTP_READ_HEADERS: + if( !readHeaders() ) + { + return; //Connection has been closed or incomplete data + } + if( m_pDataIn ) + { + //Data chunked? + if(m_respHeaders["Transfer-Encoding"].find("chunked")!=string::npos) + { + m_dataChunked = true; + m_dataPos = 0; + m_dataLen = 0; + DBG("Encoding is chunked, Content-Type is %s\n", m_respHeaders["Content-Type"].c_str() ); + } + else + { + m_dataChunked = false; + int len = 0; + //DBG("Preparing read... len = %s\n", m_respHeaders["Content-Length"].c_str()); + sscanf(m_respHeaders["Content-Length"].c_str(), "%d", &len); + m_pDataIn->setDataLen( len ); + m_dataPos = 0; + m_dataLen = len; + DBG("Content-Length is %d, Content-Type is %s\n", len, m_respHeaders["Content-Type"].c_str() ); + } + m_pDataIn->setDataType( m_respHeaders["Content-Type"] ); + } + case HTTP_READ_DATA: + readData(); + break; + case HTTP_READ_DATA_INCOMPLETE: + break; //We need to handle previously received data first + default: + //Should not receive data now, req is not complete + onResult(HTTP_PRTCL); + } + //All data has been read, close w/ success :) + if( m_state == HTTP_DONE ) + { + DBG("Done :)!\n"); + onResult(HTTP_OK); + } + break; + case TCPSOCKET_CONNECTED: + case TCPSOCKET_WRITEABLE: //We can send data + resetTimeout(); + switch(m_state) + { + case HTTP_WRITE_HEADERS: + //Update headers fields according to m_pDataOut + if( m_pDataOut ) + { + //Data is chunked? + if(m_pDataOut->getIsChunked()) + { + m_dataChunked = true; + m_reqHeaders.erase("Content-Length"); + m_reqHeaders["Transfer-Encoding"] = "chunked"; + } + else + { + m_dataChunked = false; + char c_len[16] = "0"; + int len = m_pDataOut->getDataLen(); + sprintf(c_len, "%d", len); + m_dataPos = 0; + m_dataLen = len; + m_reqHeaders.erase("Transfer-Encoding"); + m_reqHeaders["Content-Length"] = string(c_len); + } + string type = m_pDataOut->getDataType(); + if(!type.empty()) + { + m_reqHeaders["Content-Type"] = type; + } + else + { + m_reqHeaders.erase("Content-Type"); + } + } + if( !writeHeaders() ) + { + return; //Connection has been closed + } + break; //Wait for writeable event before sending payload + case HTTP_WRITE_DATA: + writeData(); + break; + } + //Otherwise request has been sent, now wait for resp + break; + case TCPSOCKET_CONTIMEOUT: + case TCPSOCKET_CONRST: + case TCPSOCKET_CONABRT: + case TCPSOCKET_ERROR: + DBG("Connection error.\n"); + onResult(HTTP_CONN); + case TCPSOCKET_DISCONNECTED: + //There might still be some data available for reading + //So if we are in a reading state, do not close the socket yet + if( (m_state != HTTP_READ_DATA_INCOMPLETE) && (m_state != HTTP_DONE) && (m_state != HTTP_CLOSED) ) + { + onResult(HTTP_CONN); + } + DBG("Connection closed by remote host.\n"); + break; + } +} + +void HTTPClient::onDNSReply(DNSReply r) +{ + if(m_closed) + { + DBG("WARN: Discarded\n"); + return; + } + + if( r != DNS_FOUND ) + { + DBG("Could not resolve hostname.\n"); + onResult(HTTP_DNS); + return; + } + + DBG("DNS Resolved to %d.%d.%d.%d.\n",m_server.getIp()[0],m_server.getIp()[1],m_server.getIp()[2],m_server.getIp()[3]); + //If no error, m_server has been updated by m_pDnsReq so we're set to go ! + m_pDnsReq->close(); + delete m_pDnsReq; + m_pDnsReq = NULL; + connect(); +} + +void HTTPClient::onResult(HTTPResult r) //Called when exchange completed or on failure +{ + if(m_pCbItem && m_pCbMeth) + (m_pCbItem->*m_pCbMeth)(r); + else if(m_pCb) + m_pCb(r); + m_blockingResult = r; //Blocking mode + close(); //FIXME:Remove suppl. close() calls +} + +void HTTPClient::onTimeout() //Connection has timed out +{ + DBG("Timed out.\n"); + onResult(HTTP_TIMEOUT); + close(); +} + +//Headers + +//TODO: Factorize w/ HTTPRequestHandler in a single HTTPHeader class + +HTTPResult HTTPClient::blockingProcess() //Called in blocking mode, calls Net::poll() until return code is available +{ + //Disable callbacks + m_pCb = NULL; + m_pCbItem = NULL; + m_pCbMeth = NULL; + m_blockingResult = HTTP_PROCESSING; + do + { + Net::poll(); + } while(m_blockingResult == HTTP_PROCESSING); + Net::poll(); //Necessary for cleanup + return m_blockingResult; +} + +bool HTTPClient::readHeaders() +{ + static char* line = m_buf; + static char key[128]; + static char value[128]; + if(!m_dataLen) //No incomplete header in buffer, this is the first time we read data + { + if( readLine(line, 128) > 0 ) + { + //Check RC + m_httpResponseCode = 0; + if( sscanf(line, "HTTP/%*d.%*d %d %*[^\r\n]", &m_httpResponseCode) != 1 ) + { + //Cannot match string, error + DBG("Not a correct HTTP answer : %s\n", line); + onResult(HTTP_PRTCL); + close(); + return false; + } + + if(m_httpResponseCode != 200) + { + DBG("Response: error code %d\n", m_httpResponseCode); + HTTPResult res = HTTP_ERROR; + switch(m_httpResponseCode) + { + case 404: + res = HTTP_NOTFOUND; + break; + case 403: + res = HTTP_REFUSED; + break; + default: + res = HTTP_ERROR; + } + onResult(res); + close(); + return false; + } + DBG("Response OK\n"); + } + else + { + //Empty packet, weird! + DBG("Empty packet!\n"); + onResult(HTTP_PRTCL); + close(); + return false; + } + } + bool incomplete = false; + while( true ) + { + int readLen = readLine(line + m_dataLen, 128 - m_dataLen, &incomplete); + m_dataLen = 0; + if( readLen <= 2 ) //if == 1 or 2, it is an empty line = end of headers + { + DBG("All headers read.\n"); + m_state = HTTP_READ_DATA; + break; + } + else if( incomplete == true ) + { + m_dataLen = readLen;//Sets data length available in buffer + return false; + } + //DBG("Header : %s\n", line); + int n = sscanf(line, "%[^:] : %[^\r\n]", key, value); + if ( n == 2 ) + { + DBG("Read header : %s: %s\n", key, value); + m_respHeaders[key] = value; + } + //TODO: Impl n==1 case (part 2 of previous header) + } + + return true; +} + +bool HTTPClient::writeHeaders() //Called at the first writeData call +{ + static char* line = m_buf; + const char* HTTP_METH_STR[] = {"GET", "POST", "HEAD"}; + + //Req + sprintf(line, "%s %s HTTP/1.1\r\nHost: %s\r\n", HTTP_METH_STR[m_meth], m_path.c_str(), m_server.getName()); //Write request + m_pTCPSocket->send(line, strlen(line)); + DBG("Request: %s\n", line); + + DBG("Writing headers:\n"); + map<string,string>::iterator it; + for( it = m_reqHeaders.begin(); it != m_reqHeaders.end(); it++ ) + { + sprintf(line, "%s: %s\r\n", (*it).first.c_str(), (*it).second.c_str() ); + DBG("\r\n%s", line); + m_pTCPSocket->send(line, strlen(line)); + } + m_pTCPSocket->send("\r\n",2); //End of head + m_state = HTTP_WRITE_DATA; + return true; +} + +int HTTPClient::readLine(char* str, int maxLen, bool* pIncomplete /* = NULL*/) +{ + int ret; + int len = 0; + if(pIncomplete) + *pIncomplete = false; + for(int i = 0; i < maxLen - 1; i++) + { + ret = m_pTCPSocket->recv(str, 1); + if(ret != 1) + { + if(pIncomplete) + *pIncomplete = true; + break; + } + if( (len > 1) && *(str-1)=='\r' && *str=='\n' ) + { + break; + } + else if( *str=='\n' ) + { + break; + } + str++; + len++; + } + *str = 0; + return len; +} + +#define CR(R) case R: return #R +char* HTTPClient::ResultStr(HTTPResult r) +{ + switch(r) { + CR(HTTP_OK); ///<Success + CR(HTTP_PROCESSING); ///<Processing + CR(HTTP_PARSE); ///<URI Parse error + CR(HTTP_DNS); ///<Could not resolve name + CR(HTTP_PRTCL); ///<Protocol error + CR(HTTP_NOTFOUND); ///<HTTP 404 Error + CR(HTTP_REFUSED); ///<HTTP 403 Error + CR(HTTP_ERROR); ///<HTTP xxx error + CR(HTTP_TIMEOUT); ///<Connection timeout + CR(HTTP_CONN); ///<Connection error + } + return "Unknown HTTPResult"; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/NetServices/services/http/client/HTTPClient.h Sun Mar 24 11:25:31 2013 +0000 @@ -0,0 +1,307 @@ + +/* +Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +/** \file +HTTP Client header file +*/ + +#ifndef HTTP_CLIENT_H +#define HTTP_CLIENT_H + +class HTTPData; + +#include "core/net.h" +#include "api/TCPSocket.h" +#include "api/DNSRequest.h" +#include "HTTPData.h" +#include "mbed.h" + +#include <string> +using std::string; + +#include <map> +using std::map; + +///HTTP client results +enum HTTPResult +{ + HTTP_OK, ///<Success + HTTP_PROCESSING, ///<Processing + HTTP_PARSE, ///<URI Parse error + HTTP_DNS, ///<Could not resolve name + HTTP_PRTCL, ///<Protocol error + HTTP_NOTFOUND, ///<HTTP 404 Error + HTTP_REFUSED, ///<HTTP 403 Error + HTTP_ERROR, ///<HTTP xxx error + HTTP_TIMEOUT, ///<Connection timeout + HTTP_CONN ///<Connection error +}; + +#include "core/netservice.h" + +///A simple HTTP Client +/** +The HTTPClient is composed of: +- The actual client (HTTPClient) +- Classes that act as a data repository, each of which deriving from the HTTPData class (HTTPText for short text content, HTTPFile for file I/O, HTTPMap for key/value pairs, and HTTPStream for streaming purposes) +*/ +class HTTPClient : protected NetService +{ +public: + ///Instantiates the HTTP client + HTTPClient(); + virtual ~HTTPClient(); + + ///Provides a basic authentification feature (Base64 encoded username and password) + void basicAuth(const char* user, const char* password); //Basic Authentification + + //High Level setup functions + ///Executes a GET Request (blocking) + /** + Executes a GET request on the URI uri + @param uri : URI on which to execute the request + @param pDataIn : pointer to an HTTPData instance that will collect the data returned by the request, can be NULL + Blocks until completion + */ + HTTPResult get(const char* uri, HTTPData* pDataIn); //Blocking + + ///Executes a GET Request (non blocking) + /** + Executes a GET request on the URI uri + @param uri : URI on which to execute the request + @param pDataIn : pointer to an HTTPData instance that will collect the data returned by the request, can be NULL + @param pMethod : callback function + The function returns immediately and calls the callback on completion or error + */ + HTTPResult get(const char* uri, HTTPData* pDataIn, void (*pMethod)(HTTPResult)); //Non blocking + + ///Executes a GET Request (non blocking) + /** + Executes a GET request on the URI uri + @param uri : URI on which to execute the request + @param pDataIn : pointer to an HTTPData instance that will collect the data returned by the request, can be NULL + @param pItem : instance of class on which to execute the callback method + @param pMethod : callback method + The function returns immediately and calls the callback on completion or error + */ + template<class T> + HTTPResult get(const char* uri, HTTPData* pDataIn, T* pItem, void (T::*pMethod)(HTTPResult)) //Non blocking + { + setOnResult(pItem, pMethod); + doGet(uri, pDataIn); + return HTTP_PROCESSING; + } + + ///Executes a POST Request (blocking) + /** + Executes a POST request on the URI uri + @param uri : URI on which to execute the request + @param dataOut : a HTTPData instance that contains the data that will be posted + @param pDataIn : pointer to an HTTPData instance that will collect the data returned by the request, can be NULL + Blocks until completion + */ + HTTPResult post(const char* uri, const HTTPData& dataOut, HTTPData* pDataIn); //Blocking + + ///Executes a POST Request (non blocking) + /** + Executes a POST request on the URI uri + @param uri : URI on which to execute the request + @param dataOut : a HTTPData instance that contains the data that will be posted + @param pDataIn : pointer to an HTTPData instance that will collect the data returned by the request, can be NULL + @param pMethod : callback function + The function returns immediately and calls the callback on completion or error + */ + HTTPResult post(const char* uri, const HTTPData& dataOut, HTTPData* pDataIn, void (*pMethod)(HTTPResult)); //Non blocking + + ///Executes a POST Request (non blocking) + /** + Executes a POST request on the URI uri + @param uri : URI on which to execute the request + @param dataOut : a HTTPData instance that contains the data that will be posted + @param pDataIn : pointer to an HTTPData instance that will collect the data returned by the request, can be NULL + @param pItem : instance of class on which to execute the callback method + @param pMethod : callback method + The function returns immediately and calls the callback on completion or error + */ + template<class T> + HTTPResult post(const char* uri, const HTTPData& dataOut, HTTPData* pDataIn, T* pItem, void (T::*pMethod)(HTTPResult)) //Non blocking + { + setOnResult(pItem, pMethod); + doPost(uri, dataOut, pDataIn); + return HTTP_PROCESSING; + } + + ///Executes a GET Request (non blocking) + /** + Executes a GET request on the URI uri + @param uri : URI on which to execute the request + @param pDataIn : pointer to an HTTPData instance that will collect the data returned by the request, can be NULL + The function returns immediately and calls the previously set callback on completion or error + */ + void doGet(const char* uri, HTTPData* pDataIn); + + ///Executes a POST Request (non blocking) + /** + Executes a POST request on the URI uri + @param uri : URI on which to execute the request + @param dataOut : a HTTPData instance that contains the data that will be posted + @param pDataIn : pointer to an HTTPData instance that will collect the data returned by the request, can be NULL + @param pMethod : callback function + The function returns immediately and calls the previously set callback on completion or error + */ + void doPost(const char* uri, const HTTPData& dataOut, HTTPData* pDataIn); + + ///Setups the result callback + /** + @param pMethod : callback function + */ + void setOnResult( void (*pMethod)(HTTPResult) ); + + ///Setups the result callback + /** + @param pItem : instance of class on which to execute the callback method + @param pMethod : callback method + */ + class CDummy; + template<class T> + void setOnResult( T* pItem, void (T::*pMethod)(HTTPResult) ) + { + m_pCb = NULL; + m_pCbItem = (CDummy*) pItem; + m_pCbMeth = (void (CDummy::*)(HTTPResult)) pMethod; + } + + ///Setups timeout + /** + @param ms : time of connection inactivity in ms after which the request should timeout + */ + void setTimeout(int ms); + + virtual void poll(); //Called by NetServices + + ///Gets last request's HTTP response code + /** + @return The HTTP response code of the last request + */ + int getHTTPResponseCode(); + + ///Sets a specific request header + void setRequestHeader(const string& header, const string& value); + + ///Gets a response header + string& getResponseHeader(const string& header); + + ///Clears request headers + void resetRequestHeaders(); + + static char* ResultStr(HTTPResult r); +protected: + void resetTimeout(); + + void init(); + void close(); + + void setup(const char* uri, HTTPData* pDataOut, HTTPData* pDataIn); //Setup request, make DNS Req if necessary + void connect(); //Start Connection + + int tryRead(); //Read data and try to feed output + void readData(); //Data has been read + void writeData(); //Data has been written & buf is free + + void onTCPSocketEvent(TCPSocketEvent e); + void onDNSReply(DNSReply r); + void onResult(HTTPResult r); //Called when exchange completed or on failure + void onTimeout(); //Connection has timed out + +private: + HTTPResult blockingProcess(); //Called in blocking mode, calls Net::poll() until return code is available + + bool readHeaders(); //Called first when receiving data + bool writeHeaders(); //Called to create req + int readLine(char* str, int maxLen, bool* pIncomplete = NULL); + + enum HTTP_METH + { + HTTP_GET, + HTTP_POST, + HTTP_HEAD + }; + + HTTP_METH m_meth; + + CDummy* m_pCbItem; + void (CDummy::*m_pCbMeth)(HTTPResult); + + void (*m_pCb)(HTTPResult); + + TCPSocket* m_pTCPSocket; + map<string, string> m_reqHeaders; + map<string, string> m_respHeaders; + + Timer m_watchdog; + int m_timeout; + + DNSRequest* m_pDnsReq; + + Host m_server; + string m_path; + + bool m_closed; + + enum HTTPStep + { + // HTTP_INIT, + HTTP_WRITE_HEADERS, + HTTP_WRITE_DATA, + HTTP_READ_HEADERS, + HTTP_READ_DATA, + HTTP_READ_DATA_INCOMPLETE, + HTTP_DONE, + HTTP_CLOSED + }; + + HTTPStep m_state; + + HTTPData* m_pDataOut; + HTTPData* m_pDataIn; + + bool m_dataChunked; //Data is encoded as chunks + int m_dataPos; //Position in data + int m_dataLen; //Data length + char* m_buf; + char* m_pBufRemaining; //Remaining + int m_bufRemainingLen; //Data length in m_pBufRemaining + + int m_httpResponseCode; + + HTTPResult m_blockingResult; //Result if blocking mode + +}; + +//Including data containers here for more convenience +#include "data/HTTPFile.h" +#include "data/HTTPStream.h" +#include "data/HTTPText.h" +#include "data/HTTPMap.h" + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/NetServices/services/http/client/HTTPData.cpp Sun Mar 24 11:25:31 2013 +0000 @@ -0,0 +1,34 @@ + +/* +Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#include "HTTPData.h" + +HTTPData::HTTPData() +{ + +} + +HTTPData::~HTTPData() +{ + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/NetServices/services/http/client/HTTPData.h Sun Mar 24 11:25:31 2013 +0000 @@ -0,0 +1,58 @@ + +/* +Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifndef HTTP_DATA_H +#define HTTP_DATA_H + +#include "core/net.h" + +#include <string> +using std::string; + +class HTTPData //This is a simple interface for HTTP data storage (impl examples are Key/Value Pairs, File, etc...) +{ +public: + HTTPData(); + virtual ~HTTPData(); + + virtual void clear() = 0; + +protected: + friend class HTTPClient; + virtual int read(char* buf, int len) = 0; + virtual int write(const char* buf, int len) = 0; + + virtual string getDataType() = 0; //Internet media type for Content-Type header + virtual void setDataType(const string& type) = 0; //Internet media type from Content-Type header + + virtual bool getIsChunked() = 0; //For Transfer-Encoding header + virtual void setIsChunked(bool chunked) = 0; //From Transfer-Encoding header + + virtual int getDataLen() = 0; //For Content-Length header + virtual void setDataLen(int len) = 0; //From Content-Length header, or if the transfer is chunked, next chunk length + +private: + +}; + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/NetServices/services/http/client/data/HTTPFile.cpp Sun Mar 24 11:25:31 2013 +0000 @@ -0,0 +1,130 @@ + +/* +Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#include "HTTPFile.h" + +//#define __DEBUG +#include "dbg/dbg.h" + +HTTPFile::HTTPFile(const char* path) : HTTPData(), m_fp(NULL), m_path(path), m_len(0), m_chunked(false) +{ + +} + +HTTPFile::~HTTPFile() +{ + closeFile(); +} + +void HTTPFile::clear() +{ + closeFile(); + //Force reopening +} + +int HTTPFile::read(char* buf, int len) +{ + if(!openFile("r")) //File does not exist, or I/O error... + return 0; + len = fread(buf, 1, len, m_fp); + if( feof(m_fp) ) + { + //File read completely, we can close it + closeFile(); + } + return len; +} + +int HTTPFile::write(const char* buf, int len) +{ + if(!openFile("w")) //File does not exist, or I/O error... + return 0; + len = fwrite(buf, 1, len, m_fp); + DBG("Written %d bytes in %d\n", len, m_fp); + if( (!m_chunked && (ftell(m_fp) >= m_len)) || + (m_chunked && !len) ) + { + //File received completely, we can close it + closeFile(); + } + return len; +} + +string HTTPFile::getDataType() //Internet media type for Content-Type header +{ + return ""; //Unknown +} + +void HTTPFile::setDataType(const string& type) //Internet media type from Content-Type header +{ + //Do not really care here +} + +bool HTTPFile::getIsChunked() //For Transfer-Encoding header +{ + return false; +} + +void HTTPFile::setIsChunked(bool chunked) //From Transfer-Encoding header +{ + m_chunked = chunked; +} + +int HTTPFile::getDataLen() //For Content-Length header +{ + return m_len; +} + +void HTTPFile::setDataLen(int len) //From Content-Length header, or if the transfer is chunked, next chunk length +{ + if(!m_chunked) + m_len = len; //Useful so that we can close file when last byte is written +} + +bool HTTPFile::openFile(const char* mode) //true on success, false otherwise +{ + if(m_fp) + return true; + + m_fp = fopen(m_path.c_str(), mode); + if(m_fp && mode[0]=='r') + { + //Seek EOF to get length + fseek(m_fp, 0, SEEK_END); + m_len = ftell(m_fp); + fseek(m_fp, 0, SEEK_SET); //Goto SOF + } + + DBG("fd = %d\n", m_fp); + + if(!m_fp) + return false; + + return true; +} + +void HTTPFile::closeFile() +{ + if(m_fp) + fclose(m_fp); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/NetServices/services/http/client/data/HTTPFile.h Sun Mar 24 11:25:31 2013 +0000 @@ -0,0 +1,81 @@ + +/* +Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +/** \file +HTTP File data source/sink header file +*/ + +#ifndef HTTP_FILE_H +#define HTTP_FILE_H + +#include "../HTTPData.h" +#include "mbed.h" + +///HTTP Client data container for files +/** +This class provides file access/storage for HTTP requests and responses' data payloads. + + +*/ +class HTTPFile : public HTTPData //Read or Write data from a file +{ +public: + ///Instantiates data source/sink with file in param. + /** + Uses file at path @a path. + It will be opened when some data has to be read/written from/to it and closed when this operation is complete or on destruction of the instance. + Note that the file will be opened with mode "w" for writing and mode "r" for reading, so the file will be cleared between each request if you are using it for writing. + + @note + Note that to use this you must instantiate a proper file system (such as the LocalFileSystem or the SDFileSystem). + */ + HTTPFile(const char* path); + virtual ~HTTPFile(); + + ///Forces file closure + virtual void clear(); + +protected: + virtual int read(char* buf, int len); + virtual int write(const char* buf, int len); + + virtual string getDataType(); //Internet media type for Content-Type header + virtual void setDataType(const string& type); //Internet media type from Content-Type header + + virtual bool getIsChunked(); //For Transfer-Encoding header + virtual void setIsChunked(bool chunked); //From Transfer-Encoding header virtual + + virtual int getDataLen(); //For Content-Length header + virtual void setDataLen(int len); //From Content-Length header + +private: + bool openFile(const char* mode); //true on success, false otherwise + void closeFile(); + + FILE* m_fp; + string m_path; + int m_len; + bool m_chunked; +}; + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/NetServices/services/http/client/data/HTTPMap.cpp Sun Mar 24 11:25:31 2013 +0000 @@ -0,0 +1,167 @@ + +/* +Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#include "HTTPMap.h" +#include "../../util/url.h" + +//#define __DEBUG +#include "dbg/dbg.h" + +HTTPMap::HTTPMap(const string& keyValueSep /*= "="*/, const string& pairSep /*= "&"*/) : +HTTPData(), Dictionary(), m_buf(), m_len(0), m_chunked(false), m_keyValueSep(keyValueSep), m_pairSep(pairSep) +{ + +} + +HTTPMap::~HTTPMap() +{ + +} + +void HTTPMap::clear() +{ + m_buf.clear(); +} + +int HTTPMap::read(char* buf, int len) +{ + memcpy( (void*)buf, (void*)m_buf.data(), len ); + m_buf.erase(0, len); //Erase these chars + return len; +} + +int HTTPMap::write(const char* buf, int len) +{ + m_buf.append( buf, len ); + if( ( m_chunked && !len ) || + ( !m_chunked && ( m_buf.length() >= m_len ) ) ) //Last chunk or EOF + { + parseString(); + } + return len; +} + +string HTTPMap::getDataType() //Internet media type for Content-Type header +{ + return "application/x-www-form-urlencoded"; +} + +void HTTPMap::setDataType(const string& type) //Internet media type from Content-Type header +{ + //Do not really care here +} + +int HTTPMap::getDataLen() //For Content-Length header +{ + //This will be called before any read occurs, so let's generate our string object + //Generate string + generateString(); + return m_len; +} + +bool HTTPMap::getIsChunked() //For Transfer-Encoding header +{ + return false; //We don't want to chunk this +} + +void HTTPMap::setIsChunked(bool chunked) //From Transfer-Encoding header +{ + m_chunked = chunked; +} + +void HTTPMap::setDataLen(int len) //From Content-Length header, or if the transfer is chunked, next chunk length +{ + m_len += len; //Useful so that we can parse string when last byte is written if not chunked + m_buf.reserve( m_len ); +} + +void HTTPMap::generateString() +{ + Dictionary::iterator it; + bool first = true; + while( !Dictionary::empty() ) + { + if(!first) + { + m_buf.append( m_pairSep ); + } + else + { + first = false; + } + it = Dictionary::begin(); + m_buf.append( Url::encode( (*it).first ) ); + m_buf.append( m_keyValueSep ); + m_buf.append( Url::encode( (*it).second ) ); + Dictionary::erase(it); //Free memory as we process data + } + m_len = m_buf.length(); + DBG("\r\nData [len %d]:\r\n%s\r\n", m_len, m_buf.c_str()); +} + +void HTTPMap::parseString() +{ + string key; + string value; + + int pos = 0; + + int key_pos; + int key_len; + + int value_pos; + int value_len; + + bool eof = false; + while(!eof) + { + key_pos = pos; + value_pos = m_buf.find(m_keyValueSep, pos); + if(value_pos < 0) + { + //Parse error, break + break; + } + + key_len = value_pos - key_pos; + + value_pos+= m_keyValueSep.length(); + + pos = m_buf.find( m_pairSep, value_pos ); + if(pos < 0) //Not found + { + pos = m_buf.length(); + eof = true; + } + + value_len = pos - value_pos; + + pos += m_pairSep.length(); + + //Append elenent + Dictionary::operator[]( Url::decode( m_buf.substr(key_pos, key_len) ) ) = Url::decode( m_buf.substr(value_pos, value_len) ); + } + + m_buf.clear(); //Free data + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/NetServices/services/http/client/data/HTTPMap.h Sun Mar 24 11:25:31 2013 +0000 @@ -0,0 +1,89 @@ + +/* +Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +/** \file +HTTP Map data source/sink header file +*/ + +#ifndef HTTP_MAP_H +#define HTTP_MAP_H + +#include "../HTTPData.h" +#include "mbed.h" + +#include <map> +using std::map; + +typedef map<string, string> Dictionary; + +///HTTP Client data container for key/value pairs +/** +This class simplifies the use of key/value pairs requests and responses used widely among web APIs. +Note that HTTPMap inherits from std::map<std::string,std::string>. +You can therefore use any public method of that class, including the square brackets operator ( [ ] ) to access a value. + +The data is encoded or decoded to/from a key/value pairs-formatted string, after url-encoding/decoding. +*/ +class HTTPMap : public HTTPData, public Dictionary //Key/Value pairs +{ +public: + ///Instantiates map + /** + @param keyValueSep Key/Value separator (defaults to "=") + @param pairSep Pairs separator (defaults to "&") + */ + HTTPMap(const string& keyValueSep = "=", const string& pairSep = "&"); + virtual ~HTTPMap(); + + /* string& operator[](const string& key); + int count();*/ + + ///Clears the content + virtual void clear(); + +protected: + virtual int read(char* buf, int len); + virtual int write(const char* buf, int len); + + virtual string getDataType(); //Internet media type for Content-Type header + virtual void setDataType(const string& type); //Internet media type from Content-Type header + + virtual bool getIsChunked(); //For Transfer-Encoding header + virtual void setIsChunked(bool chunked); //From Transfer-Encoding header + + virtual int getDataLen(); //For Content-Length header + virtual void setDataLen(int len); //From Content-Length header + +private: + void generateString(); + void parseString(); + //map<string, string> m_map; + string m_buf; + int m_len; + bool m_chunked; + + string m_keyValueSep; + string m_pairSep; +}; + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/NetServices/services/http/client/data/HTTPStream.cpp Sun Mar 24 11:25:31 2013 +0000 @@ -0,0 +1,104 @@ + +/* +Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#include "HTTPStream.h" + +#define MIN(a,b) ((a)<(b)?(a):(b)) + +HTTPStream::HTTPStream() : HTTPData(), m_buf(NULL), m_size(0), m_len(0) +{ + +} + +HTTPStream::~HTTPStream() +{ + +} + + +void HTTPStream::readNext(byte* buf, int size) +{ + m_buf = buf; + m_size = size; + m_len = 0; +} + +bool HTTPStream::readable() +{ + return (m_len>0); +} + +int HTTPStream::readLen() +{ + return m_len; +} + +void HTTPStream::clear() +{ + //Do nothing here since it is a stream and not a buffer +} + +int HTTPStream::read(char* buf, int len) +{ + return 0; //Unsupported yet +} + +int HTTPStream::write(const char* buf, int len) +{ + if(!m_buf) + return 0; + len = MIN( m_size - m_len, len ); + memcpy(m_buf + m_len, buf, len); + m_len += len; + return len; +} + +string HTTPStream::getDataType() //Internet media type for Content-Type header +{ + return ""; +} + +void HTTPStream::setDataType(const string& type) //Internet media type from Content-Type header +{ + //Do not really care here +} + +bool HTTPStream::getIsChunked() //For Transfer-Encoding header +{ + return false; //We don't want to chunk this +} + +void HTTPStream::setIsChunked(bool chunked) //From Transfer-Encoding header +{ + //Nothing to do +} + +int HTTPStream::getDataLen() //For Content-Length header +{ + return 0; +} + +void HTTPStream::setDataLen(int len) //From Content-Length header, or if the transfer is chunked, next chunk length +{ + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/NetServices/services/http/client/data/HTTPStream.h Sun Mar 24 11:25:31 2013 +0000 @@ -0,0 +1,83 @@ + +/* +Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifndef HTTP_STREAM_H +#define HTTP_STREAM_H + +#include "../HTTPData.h" +#include "mbed.h" + +/** \file +HTTP Stream data source/sink header file +*/ + +typedef uint8_t byte; + +///HTTP Client Streaming tool +/** +This class allows you to stream data from the web using a persisting HTTP connection. +To use it properly you must use a non-blocking HTTPClient method. +*/ +class HTTPStream : public HTTPData //Streaming buf +{ +public: + ///Instantiates the object + HTTPStream(); + virtual ~HTTPStream(); + + ///Starts to read into buffer + /** + Passes a buffer of address @a buf and size @a size to the instance. + When it receives data it will be stored in this buffer. + When the buffer is full it throttles the client until this function is called again. + */ + void readNext(byte* buf, int size); + + ///Returns whether there is data available to read + bool readable(); + + ///Returns the actual length of the payload written in the buffer + int readLen(); + + virtual void clear(); + +protected: + virtual int read(char* buf, int len); + virtual int write(const char* buf, int len); + + virtual string getDataType(); //Internet media type for Content-Type header + virtual void setDataType(const string& type); //Internet media type from Content-Type header + + virtual bool getIsChunked(); //For Transfer-Encoding header + virtual void setIsChunked(bool chunked); //From Transfer-Encoding header + + virtual int getDataLen(); //For Content-Length header + virtual void setDataLen(int len); //From Content-Length header, or if the transfer is chunked, next chunk length + +private: + byte* m_buf; + int m_size; //Capacity + int m_len; //Length +}; + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/NetServices/services/http/client/data/HTTPText.cpp Sun Mar 24 11:25:31 2013 +0000 @@ -0,0 +1,108 @@ + +/* +Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#include "HTTPText.h" + + + +#define MIN(a,b) ((a)<(b)?(a):(b)) + +HTTPText::HTTPText(const string& encoding /*= "text/html"*/, int maxSize /*= DEFAULT_MAX_MEM_ALLOC*/) : HTTPData(), m_buf(), m_encoding(encoding), m_maxSize(maxSize) +{ + +} + +HTTPText::~HTTPText() +{ + +} + +const char* HTTPText::gets() const +{ + return m_buf.c_str(); +} + +void HTTPText::puts(const char* str) +{ + m_buf = string(str); +} + +string& HTTPText::get() +{ + return m_buf; +} + +void HTTPText::set(const string& str) +{ + m_buf = str; +} + +void HTTPText::clear() +{ + m_buf.clear(); +} + +int HTTPText::read(char* buf, int len) +{ + len = MIN( len, m_buf.length() ); + memcpy( (void*)buf, (void*)m_buf.data(), len ); + m_buf.erase(0, len); //Erase these chars + return len; +} + +int HTTPText::write(const char* buf, int len) +{ + len = MIN( m_maxSize - m_buf.length(), len ); //Do not go over m_maxSize + m_buf.append( buf, len ); + return len; +} + +string HTTPText::getDataType() //Internet media type for Content-Type header +{ + return m_encoding; +} + +void HTTPText::setDataType(const string& type) //Internet media type from Content-Type header +{ + //Do not really care here +} + +bool HTTPText::getIsChunked() //For Transfer-Encoding header +{ + return false; //We don't want to chunk this +} + +void HTTPText::setIsChunked(bool chunked) //From Transfer-Encoding header +{ + //Nothing to do +} + +int HTTPText::getDataLen() //For Content-Length header +{ + return m_buf.length(); +} + +void HTTPText::setDataLen(int len) //From Content-Length header, or if the transfer is chunked, next chunk length +{ + m_buf.reserve(MIN(m_buf.length() + len,m_maxSize)); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/NetServices/services/http/client/data/HTTPText.h Sun Mar 24 11:25:31 2013 +0000 @@ -0,0 +1,101 @@ + +/* +Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +/** \file +HTTP Text data source/sink header file +*/ + +#ifndef HTTP_TEXT_H +#define HTTP_TEXT_H + +#include "../HTTPData.h" +#include "mbed.h" + +#define DEFAULT_MAX_MEM_ALLOC 512 //Avoid out-of-memory problems + +///HTTP Client data container for text +/** +This is a simple "Text" data repository for HTTP requests. +*/ +class HTTPText : public HTTPData //Simple Text I/O +{ +public: + ///Instantiates the object. + /** + @param encoding encoding of the data, it defaults to text/html. + @param maxSize defines the maximum memory size that can be allocated by the object. It defaults to 512 bytes. + */ + HTTPText(const string& encoding = "text/html", int maxSize = DEFAULT_MAX_MEM_ALLOC); + virtual ~HTTPText(); + + ///Gets text + /** + Returns the text in the container as a zero-terminated char*. + The array returned points to the internal buffer of the object and remains owned by the object. + */ + const char* gets() const; + + //Puts text + /** + Sets the text in the container using a zero-terminated char*. + */ + void puts(const char* str); + + ///Gets text + /** + Returns the text in the container as string. + */ + string& get(); + + ///Puts text + /** + Sets the text in the container as string. + */ + void set(const string& str); + + ///Clears the content. + /** + If this container is used as a data sink, it is cleared by the HTTP Client at the beginning of the request. + */ + virtual void clear(); + +protected: + virtual int read(char* buf, int len); + virtual int write(const char* buf, int len); + + virtual string getDataType(); //Internet media type for Content-Type header + virtual void setDataType(const string& type); //Internet media type from Content-Type header + + virtual bool getIsChunked(); //For Transfer-Encoding header + virtual void setIsChunked(bool chunked); //From Transfer-Encoding header + + virtual int getDataLen(); //For Content-Length header + virtual void setDataLen(int len); //From Content-Length header, or if the transfer is chunked, next chunk length + +private: + string m_buf; + string m_encoding; + int m_maxSize; +}; + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/NetServices/services/http/server/HTTPRequestDispatcher.cpp Sun Mar 24 11:25:31 2013 +0000 @@ -0,0 +1,231 @@ + +/* +Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#include "core/netservice.h" +#include "HTTPRequestDispatcher.h" +#include "HTTPRequestHandler.h" +#include <string.h> + +//#define __DEBUG +#include "dbg/dbg.h" + +HTTPRequestDispatcher::HTTPRequestDispatcher(HTTPServer* pSvr, TCPSocket* pTCPSocket) : NetService(), m_pSvr(pSvr), m_pTCPSocket(pTCPSocket), m_watchdog(), m_closed(false) +{ + m_pTCPSocket->setOnEvent(this, &HTTPRequestDispatcher::onTCPSocketEvent); + m_watchdog.attach_us<HTTPRequestDispatcher>(this, &HTTPRequestDispatcher::onTimeout, HTTP_REQUEST_TIMEOUT * 1000); +} + +HTTPRequestDispatcher::~HTTPRequestDispatcher() +{ + close(); +} + +void HTTPRequestDispatcher::dispatchRequest() +{ + string path; + string meth; + HTTP_METH methCode; + + DBG("Dispatching req\r\n"); + + if( !getRequest(&path, &meth ) ) + { + close(); + return; //Invalid request + } + + if( !meth.compare("GET") ) + { + methCode = HTTP_GET; + } + else if( !meth.compare("POST") ) + { + methCode = HTTP_POST; + } + else if( !meth.compare("HEAD") ) + { + methCode = HTTP_HEAD; + } + else + { + close(); //Parse error + return; + } + + DBG("Looking for a handler\r\n"); + + map< string, HTTPRequestHandler*(*)(const char*, const char*, TCPSocket*) >::iterator it; +// it = m_pSvr->m_lpHandlers.find(rootPath); //We are friends so we can do that +// NEW CODE START: + int root_len = 0; + for (it = m_pSvr->m_lpHandlers.begin(); it != m_pSvr->m_lpHandlers.end(); it++) + { + DBG("Checking %s...\n", (*it).first.c_str()); + root_len = (*it).first.length(); + if ( root_len && + !path.compare( 0, root_len, (*it).first ) && + (path[root_len] == '/' || path[root_len] == '\0')) + { + DBG("Found (%s)\n", (*it).first.c_str()); + // Found! + break; // for + } + } +// NEW CODE END + if((it == m_pSvr->m_lpHandlers.end()) && !(m_pSvr->m_lpHandlers.empty())) + { + DBG("Using default handler\n"); + it = m_pSvr->m_lpHandlers.end(); + it--; //Get the last element + if( ! (((*it).first.length() == 0) || !(*it).first.compare("/")) ) //This is not the default handler + it = m_pSvr->m_lpHandlers.end(); + root_len = 0; + } + if(it == m_pSvr->m_lpHandlers.end()) + { + DBG("No handler found\n"); + close(); //No handler found + return; + } + + DBG("Handler found.\r\n"); + +//HTTPRequestHandler* pHdlr = (*it).second(rootPath.c_str(), subPath.c_str(), m_pTCPSocket); +//NEW CODE 1 LINE: + HTTPRequestHandler* pHdlr = (*it).second((*it).first.c_str(), path.c_str() + root_len, m_pTCPSocket); + m_pTCPSocket = NULL; //We don't own it anymore + + switch(methCode) + { + case HTTP_GET: + pHdlr->doGet(); + break; + case HTTP_POST: + pHdlr->doPost(); + break; + case HTTP_HEAD: + pHdlr->doHead(); + break; + } + + DBG("Req handled (or being handled)\r\n"); + close(); +} + +void HTTPRequestDispatcher::close() //Close socket and destroy data +{ + if(m_closed) + return; + m_closed = true; //Prevent recursive calling or calling on an object being destructed by someone else + m_watchdog.detach(); + if(m_pTCPSocket) //m_pTCPSocket Should only be destroyed if ownership not passed to an handler + { + m_pTCPSocket->resetOnEvent(); + m_pTCPSocket->close(); + delete m_pTCPSocket; //This fn might have been called by this socket (through an event), so DO NOT DESTROY IT HERE + } + NetService::close(); +} + + +void HTTPRequestDispatcher::onTimeout() //Connection has timed out +{ + close(); +} + +bool HTTPRequestDispatcher::getRequest(string* path, string* meth) +{ + char req[128]; + char c_path[128]; + char c_meth[128]; + const int maxLen = 128; + char* p = req; + //Read Line + int ret; + int len = 0; + for(int i = 0; i < maxLen - 1; i++) + { + ret = m_pTCPSocket->recv(p, 1); + if(!ret) + { + break; + } + if( (len > 1) && *(p-1)=='\r' && *p=='\n' ) + { + p--; + len-=2; + break; + } + else if( *p=='\n' ) + { + len--; + break; + } + p++; + len++; + } + *p = 0; + + DBG("Parsing request : %s\r\n", req); + + ret = sscanf(req, "%s %s HTTP/%*d.%*d", c_meth, c_path); + if(ret !=2) + return false; + + *meth = string(c_meth); +// NEW CODE (old code removed): + *path = string(c_path); + return true; +} + + + +void HTTPRequestDispatcher::onTCPSocketEvent(TCPSocketEvent e) +{ + + DBG("\r\nEvent %d\r\n", e); + + if(m_closed) + { + DBG("\r\nWARN: Discarded\r\n"); + return; + } + + switch(e) + { + case TCPSOCKET_READABLE: + m_watchdog.detach(); + m_pTCPSocket->resetOnEvent(); + //Req arrived, dispatch : + dispatchRequest(); + break; + case TCPSOCKET_CONTIMEOUT: + case TCPSOCKET_CONRST: + case TCPSOCKET_CONABRT: + case TCPSOCKET_ERROR: + case TCPSOCKET_DISCONNECTED: + close(); + break; + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/NetServices/services/http/server/HTTPRequestDispatcher.h Sun Mar 24 11:25:31 2013 +0000 @@ -0,0 +1,72 @@ + +/* +Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifndef HTTP_REQUEST_DISPATCHER_H +#define HTTP_REQUEST_DISPATCHER_H + +class HTTPServer; + +#include "api/TCPSocket.h" +#include "HTTPServer.h" +#include "core/netservice.h" + +#include "mbed.h" + +#define HTTP_REQUEST_TIMEOUT 5000 + +#include <string> +using std::string; + +class HTTPRequestDispatcher : public NetService +{ +public: + HTTPRequestDispatcher(HTTPServer* pSvr, TCPSocket* pTCPSocket); + virtual ~HTTPRequestDispatcher(); + +private: + + enum HTTP_METH + { + HTTP_GET, + HTTP_POST, + HTTP_HEAD + }; + + void dispatchRequest(); + + virtual void close(); //Close TCPSocket and destroy data + + void onTCPSocketEvent(TCPSocketEvent e); + + void onTimeout(); //Connection has timed out + + bool getRequest(string* path, string* meth); + + HTTPServer* m_pSvr; + TCPSocket* m_pTCPSocket; + + Timeout m_watchdog; + bool m_closed; +}; + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/NetServices/services/http/server/HTTPRequestHandler.cpp Sun Mar 24 11:25:31 2013 +0000 @@ -0,0 +1,237 @@ + +/* +Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#include "core/netservice.h" +#include "HTTPRequestHandler.h" + +#include <string.h> + +//#define __DEBUG +#include "dbg/dbg.h" + +#define HTTP_REQUEST_TIMEOUT 5000 + +HTTPRequestHandler::HTTPRequestHandler(const char* rootPath, const char* path, TCPSocket* pTCPSocket) : NetService(), +m_pTCPSocket(pTCPSocket), m_reqHeaders(), m_respHeaders(), +m_rootPath(rootPath), m_path(path), m_errc(200), +m_watchdog(), m_timeout(0), m_closed(false), m_headersSent(false) //OK +{ + //Read & parse headers + readHeaders(); + m_pTCPSocket->setOnEvent(this, &HTTPRequestHandler::onTCPSocketEvent); + setTimeout(HTTP_REQUEST_TIMEOUT); +} + +HTTPRequestHandler::~HTTPRequestHandler() +{ + close(); +} + +void HTTPRequestHandler::onTimeout() //Connection has timed out +{ + close(); +} + +void HTTPRequestHandler::close() //Close socket and destroy data +{ + if(m_closed) + return; + m_closed = true; //Prevent recursive calling or calling on an object being destructed by someone else + m_watchdog.detach(); + onClose(); + m_pTCPSocket->resetOnEvent(); + m_pTCPSocket->close(); + delete m_pTCPSocket; //Can safely destroy socket + NetService::close(); +} + +map<string, string>& HTTPRequestHandler::reqHeaders() //const +{ + return m_reqHeaders; +} + +string& HTTPRequestHandler::path() //const +{ + return m_path; +} + +int HTTPRequestHandler::dataLen() const +{ + map<string,string>::iterator it; + it = m_reqHeaders.find("Content-Length"); + if( it == m_reqHeaders.end() ) + { + return 0; + } + return atoi((*it).second.c_str()); //return 0 if parse fails, so that's fine +} + +int HTTPRequestHandler::readData(char* buf, int len) +{ + return m_pTCPSocket->recv(buf, len); +} + +string& HTTPRequestHandler::rootPath() //const +{ + return m_rootPath; +} + +void HTTPRequestHandler::setErrCode(int errc) +{ + m_errc = errc; +} + +void HTTPRequestHandler::setContentLen(int len) +{ + char len_str[6] = {0}; + sprintf(len_str, "%d", len); + respHeaders()["Content-Length"] = len_str; +} + +map<string, string>& HTTPRequestHandler::respHeaders() +{ + return m_respHeaders; +} + +int HTTPRequestHandler::writeData(const char* buf, int len) +{ + if(!m_headersSent) + { + m_headersSent = true; + writeHeaders(); + } + + return m_pTCPSocket->send(buf, len); +} + +void HTTPRequestHandler::setTimeout(int ms) +{ + m_timeout = 1000*ms; + resetTimeout(); +} + +void HTTPRequestHandler::resetTimeout() +{ + m_watchdog.detach(); + m_watchdog.attach_us<HTTPRequestHandler>(this, &HTTPRequestHandler::onTimeout, m_timeout); +} + + +void HTTPRequestHandler::readHeaders() +{ + static char line[128]; + static char key[128]; + static char value[128]; + while( readLine(line, 128) > 0) //if == 0, it is an empty line = end of headers + { + int n = sscanf(line, "%[^:]: %[^\n]", key, value); + if ( n == 2 ) + { + DBG("\r\nRead header : %s : %s\r\n", key, value); + m_reqHeaders[key] = value; + } + //TODO: Impl n==1 case (part 2 of previous header) + } +} + +void HTTPRequestHandler::writeHeaders() //Called at the first writeData call +{ + static char line[128]; + + //Response line + sprintf(line, "HTTP/1.1 %d MbedInfo\r\n", m_errc); //Not a violation of the standard not to include the descriptive text + m_pTCPSocket->send(line, strlen(line)); + + map<string,string>::iterator it; + while( !m_respHeaders.empty() ) + { + it = m_respHeaders.begin(); + sprintf(line, "%s: %s\r\n", (*it).first.c_str(), (*it).second.c_str() ); + DBG("\r\n%s", line); + m_pTCPSocket->send(line, strlen(line)); + m_respHeaders.erase(it); + } + m_pTCPSocket->send("\r\n",2); //End of head +} + +int HTTPRequestHandler::readLine(char* str, int maxLen) +{ + int ret; + int len = 0; + for(int i = 0; i < maxLen - 1; i++) + { + ret = m_pTCPSocket->recv(str, 1); + if(!ret) + { + break; + } + if( (len > 1) && *(str-1)=='\r' && *str=='\n' ) + { + str--; + len-=2; + break; + } + else if( *str=='\n' ) + { + len--; + break; + } + str++; + len++; + } + *str = 0; + return len; +} + +void HTTPRequestHandler::onTCPSocketEvent(TCPSocketEvent e) +{ + + DBG("\r\nEvent %d in HTTPRequestHandler\r\n", e); + + if(m_closed) + { + DBG("\r\nWARN: Discarded\r\n"); + return; + } + + switch(e) + { + case TCPSOCKET_READABLE: + resetTimeout(); + onReadable(); + break; + case TCPSOCKET_WRITEABLE: + resetTimeout(); + onWriteable(); + break; + case TCPSOCKET_CONTIMEOUT: + case TCPSOCKET_CONRST: + case TCPSOCKET_CONABRT: + case TCPSOCKET_ERROR: + case TCPSOCKET_DISCONNECTED: + DBG("\r\nConnection error in handler\r\n"); + close(); + break; + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/NetServices/services/http/server/HTTPRequestHandler.h Sun Mar 24 11:25:31 2013 +0000 @@ -0,0 +1,101 @@ + +/* +Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +/** +HTTP Request Handler header file. +*/ + +#ifndef HTTP_REQUEST_HANDLER_H +#define HTTP_REQUEST_HANDLER_H + +#include "api/TCPSocket.h" +//#include "HTTPServer.h" + +#include "mbed.h" +#include "core/netservice.h" + +#include <string> +using std::string; + +#include <map> +using std::map; + +///HTTP Server's generic request handler +class HTTPRequestHandler : public NetService +{ +public: + ///Instantiated by the HTTP Server + HTTPRequestHandler(const char* rootPath, const char* path, TCPSocket* pTCPSocket); + virtual ~HTTPRequestHandler(); + +//protected: + virtual void doGet() = 0; + virtual void doPost() = 0; + virtual void doHead() = 0; + + virtual void onReadable() = 0; //Data has been read + virtual void onWriteable() = 0; //Data has been written & buf is free + virtual void onTimeout(); //Connection has timed out + virtual void onClose() = 0; //Connection is closing + + virtual void close(); //Close socket and destroy data + +protected: + map<string, string>& reqHeaders() /*const*/; + string& path() /*const*/; + int dataLen() const; + int readData(char* buf, int len); + string& rootPath() /*const*/; + + void setErrCode(int errc); + void setContentLen(int len); + + map<string, string>& respHeaders(); + int writeData(const char* buf, int len); + + void setTimeout(int ms); + void resetTimeout(); + +private: + void readHeaders(); //Called at instanciation + void writeHeaders(); //Called at the first writeData call + void onTCPSocketEvent(TCPSocketEvent e); + + TCPSocket* m_pTCPSocket; + map<string, string> m_reqHeaders; + map<string, string> m_respHeaders; + string m_rootPath; + string m_path; + int m_errc; //Response code + + Timeout m_watchdog; + int m_timeout; + + bool m_closed; + bool m_headersSent; + + int readLine(char* str, int maxLen); + +}; + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/NetServices/services/http/server/HTTPServer.cpp Sun Mar 24 11:25:31 2013 +0000 @@ -0,0 +1,80 @@ + +/* +Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#include "HTTPServer.h" + +//#define __DEBUG +//#include "dbg/dbg.h" +//#define DEBUG +#include "w5200debug.h" + +HTTPServer::HTTPServer() +{ + m_pTCPSocket = new TCPSocket; + m_pTCPSocket->setOnEvent(this, &HTTPServer::onTCPSocketEvent); +} + +HTTPServer::~HTTPServer() +{ + delete m_pTCPSocket; +} + +void HTTPServer::bind(int port /*= 80*/) +{ + DBG("port=%d\n", port); + Host h(IpAddr(127,0,0,1), port, "localhost"); + m_pTCPSocket->bind(h); + m_pTCPSocket->listen(); //Listen +} + +#if 0 //Just for clarity +template<typename T> +void HTTPServer::addHandler(const char* path) +{ + m_lpHandlers[path] = &T::inst; + +} +#endif + +void HTTPServer::onTCPSocketEvent(TCPSocketEvent e) +{ + + DBG("\r\nHTTPServer::onTCPSocketEvent : Event %d %s\r\n", e, TCPSocket::EventStr(e)); + + if(e==TCPSOCKET_ACCEPT) + { + TCPSocket* pTCPSocket; + Host client; + + if( !!m_pTCPSocket->accept(&client, &pTCPSocket) ) + { + DBG("\r\nHTTPServer::onTCPSocketEvent : Could not accept connection.\r\n"); + return; //Error in accept, discard connection + } + + HTTPRequestDispatcher* pDispatcher = new HTTPRequestDispatcher(this, pTCPSocket); //TCPSocket ownership is passed to dispatcher + //The dispatcher object will destroy itself when done, or will be destroyed on Server destruction + + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/NetServices/services/http/server/HTTPServer.h Sun Mar 24 11:25:31 2013 +0000 @@ -0,0 +1,104 @@ + +/* +Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +/** \file +HTTP Server header file +*/ + +#ifndef HTTP_SERVER_H +#define HTTP_SERVER_H + +class HTTPRequestHandler; +class HTTPRequestDispatcher; + +#include "core/net.h" +#include "HTTPRequestHandler.h" +#include "HTTPRequestDispatcher.h" + +#include <string> +using std::string; + +#include <map> +using std::map; + +///A simple HTTP server implementation +/** +The HTTPServer is composed of: +- The actual server (HTTPServer) +- A request dispatcher, instanciated on each request (HTTPRequestDispatcher) +- Request handlers instanciated by the dispatcher(deriving from HTTPRequestHandler) +*/ +class HTTPServer +{ +public: + ///Instantiates the HTTP Server + HTTPServer(); + ~HTTPServer(); + + struct handlersComp //Used to order handlers in the right way + { + bool operator() (const string& handler1, const string& handler2) const + { + //The first handler is longer than the second one + if (handler1.length() > handler2.length()) + return true; //Returns true if handler1 is to appear before handler2 + else if (handler1.length() < handler2.length()) + return false; + else //To avoid the == case, sort now by address + return ((&handler1)>(&handler2)); + } + }; + + ///Adds a handler + /** + Appends a handler to the handlers list + @param T : class which will be instanciated to serve these requests + @param path : requests starting with this path will be served using this handler + */ + template<typename T> + void addHandler(const char* path) //Template decl in header + { m_lpHandlers[path] = &T::inst; } + + ///Starts listening + /** + Binds server to a specific port and starts listening + @param port : port on which to listen for incoming connections + */ + void bind(int port = 80); + +private: + friend class HTTPRequestDispatcher; + + void onTCPSocketEvent(TCPSocketEvent e); + + TCPSocket* m_pTCPSocket; + map< string, HTTPRequestHandler*(*)(const char*, const char*, TCPSocket*), handlersComp > m_lpHandlers; + +}; + +//Including handlers here for more convenience +#include "impl/RPCHandler.h" +#include "impl/FSHandler.h" +#include "impl/SimpleHandler.h" + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/NetServices/services/http/server/impl/FSHandler.cpp Sun Mar 24 11:25:31 2013 +0000 @@ -0,0 +1,160 @@ + +/* +Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#include "FSHandler.h" + +//#define __DEBUG +#include "dbg/dbg.h" + +#define CHUNK_SIZE 128 + +#define DEFAULT_PAGE "/index.htm" + +FSHandler::FSHandler(const char* rootPath, const char* path, TCPSocket* pTCPSocket) : HTTPRequestHandler(rootPath, path, pTCPSocket), m_err404(false) +{} + +FSHandler::~FSHandler() +{ + if(m_fp) + fclose(m_fp); + DBG("\r\nHandler destroyed\r\n"); +} + +//static init +map<string,string> FSHandler::m_lFsPath = map<string,string>(); + +void FSHandler::mount(const string& fsPath, const string& rootPath) +{ + m_lFsPath[rootPath]=fsPath; +} + +void FSHandler::doGet() +{ + DBG("\r\nIn FSHandler::doGet() - rootPath=%s, path=%s\r\n", rootPath().c_str(), path().c_str()); + //FIXME: Translate path to local/path + string checkedRootPath = rootPath(); + if(checkedRootPath.empty()) + checkedRootPath="/"; + string filePath = m_lFsPath[checkedRootPath]; + if (path().size() > 1) + { + filePath += path(); + } + else + { + filePath += DEFAULT_PAGE; + } + + DBG("Trying to open %s\n", filePath.c_str()); + + m_fp = fopen(filePath.c_str(), "r"); //FIXME: if null, error 404 + + if(!m_fp) + { + m_err404 = true; + setErrCode(404); + const char* msg = "File not found."; + setContentLen(strlen(msg)); + respHeaders()["Content-Type"] = "text/html"; + respHeaders()["Connection"] = "close"; + writeData(msg,strlen(msg)); //Only send header + DBG("\r\nExit FSHandler::doGet() w Error 404\r\n"); + return; + } + + //Seek EOF to get length + fseek(m_fp, 0, SEEK_END); + setContentLen( ftell(m_fp) ); + fseek(m_fp, 0, SEEK_SET); //Goto SOF + + respHeaders()["Connection"] = "close"; + onWriteable(); + DBG("\r\nExit SimpleHandler::doGet()\r\n"); +} + +void FSHandler::doPost() +{ + +} + +void FSHandler::doHead() +{ + +} + +void FSHandler::onReadable() //Data has been read +{ + +} + +void FSHandler::onWriteable() //Data has been written & buf is free +{ + DBG("\r\nFSHandler::onWriteable() event\r\n"); + if(m_err404) + { + //Error has been served, now exit + close(); + return; + } + + static char rBuf[CHUNK_SIZE]; + while(true) + { + int len = fread(rBuf, 1, CHUNK_SIZE, m_fp); + if(len>0) + { + int writtenLen = writeData(rBuf, len); + if(writtenLen < 0) //Socket error + { + DBG("FSHandler: Socket error %d\n", writtenLen); + if(writtenLen == TCPSOCKET_MEM) + { + fseek(m_fp, -len, SEEK_CUR); + return; //Wait for the queued TCP segments to be transmitted + } + else + { + //This is a critical error + close(); + return; + } + } + else if(writtenLen < len) //Short write, socket's buffer is full + { + fseek(m_fp, writtenLen - len, SEEK_CUR); + return; + } + } + else + { + close(); //Data written, we can close the connection + return; + } + } +} + +void FSHandler::onClose() //Connection is closing +{ + if(m_fp) + fclose(m_fp); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/NetServices/services/http/server/impl/FSHandler.h Sun Mar 24 11:25:31 2013 +0000 @@ -0,0 +1,61 @@ + +/* +Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifndef FS_HANDLER_H +#define FS_HANDLER_H + +#include "../HTTPRequestHandler.h" +#include "mbed.h" + +#include <map> +using std::map; + +#include <string> +using std::string; + +class FSHandler : public HTTPRequestHandler +{ +public: + FSHandler(const char* rootPath, const char* path, TCPSocket* pTCPSocket); + virtual ~FSHandler(); + + static void mount(const string& fsPath, const string& rootPath); + +//protected: + static inline HTTPRequestHandler* inst(const char* rootPath, const char* path, TCPSocket* pTCPSocket) { return new FSHandler(rootPath, path, pTCPSocket); } //if we ever could do static virtual functions, this would be one + + virtual void doGet(); + virtual void doPost(); + virtual void doHead(); + + virtual void onReadable(); //Data has been read + virtual void onWriteable(); //Data has been written & buf is free + virtual void onClose(); //Connection is closing + +private: + FILE* m_fp; + bool m_err404; + static map<string,string> m_lFsPath; +}; + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/NetServices/services/http/server/impl/RPCHandler.cpp Sun Mar 24 11:25:31 2013 +0000 @@ -0,0 +1,116 @@ + +/* +Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#include "RPCHandler.h" +#include "rpc.h" + +//#define __DEBUG +#include "dbg/dbg.h" + +#define RPC_DATA_LEN 128 + +RPCHandler::RPCHandler(const char* rootPath, const char* path, TCPSocket* pTCPSocket) : HTTPRequestHandler(rootPath, path, pTCPSocket) +{} + +RPCHandler::~RPCHandler() +{ + DBG("\r\nHandler destroyed\r\n"); +} + +void RPCHandler::doGet() +{ + DBG("\r\nIn RPCHandler::doGet()\r\n"); + char resp[RPC_DATA_LEN] = {0}; + char req[RPC_DATA_LEN] = {0}; + + DBG("\r\nPath : %s\r\n", path().c_str()); + DBG("\r\nRoot Path : %s\r\n", rootPath().c_str()); + + //Remove path + strncpy(req, path().c_str(), RPC_DATA_LEN-1); + DBG("\r\nRPC req : %s\r\n", req); + + //Remove %20, +, from req + cleanReq(req); + DBG("\r\nRPC req : %s\r\n", req); + + //Do RPC Call + //mbed::rpc(req, resp); //FIXME: Use bool result + RPC::call(req, resp); //FIXME: Use bool result + + //Response + setContentLen( strlen(resp) ); + + //Make sure that the browser won't cache this request + respHeaders()["Cache-control"]="no-cache;no-store"; + // respHeaders()["Cache-control"]="no-store"; + respHeaders()["Pragma"]="no-cache"; + respHeaders()["Expires"]="0"; + + //Write data + respHeaders()["Connection"] = "close"; + writeData(resp, strlen(resp)); + DBG("\r\nExit RPCHandler::doGet()\r\n"); +} + +void RPCHandler::doPost() +{ + +} + +void RPCHandler::doHead() +{ + +} + + +void RPCHandler::onReadable() //Data has been read +{ + +} + +void RPCHandler::onWriteable() //Data has been written & buf is free +{ + DBG("\r\nRPCHandler::onWriteable() event\r\n"); + close(); //Data written, we can close the connection +} + +void RPCHandler::onClose() //Connection is closing +{ + //Nothing to do +} + +void RPCHandler::cleanReq(char* data) +{ + char* p; + static const char* lGarbage[2] = {"%20", "+"}; + for(int i = 0; i < 2; i++) + { + while( p = strstr(data, lGarbage[i]) ) + { + memset((void*) p, ' ', strlen(lGarbage[i])); + } + } +} + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/NetServices/services/http/server/impl/RPCHandler.h Sun Mar 24 11:25:31 2013 +0000 @@ -0,0 +1,50 @@ + +/* +Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifndef RPC_HANDLER_H +#define RPC_HANDLER_H + +#include "../HTTPRequestHandler.h" + +class RPCHandler : public HTTPRequestHandler +{ +public: + RPCHandler(const char* rootPath, const char* path, TCPSocket* pTCPSocket); + virtual ~RPCHandler(); + +//protected: + static inline HTTPRequestHandler* inst(const char* rootPath, const char* path, TCPSocket* pTCPSocket) { return new RPCHandler(rootPath, path, pTCPSocket); } //if we ever could do static virtual functions, this would be one + + virtual void doGet(); + virtual void doPost(); + virtual void doHead(); + + virtual void onReadable(); //Data has been read + virtual void onWriteable(); //Data has been written & buf is free + virtual void onClose(); //Connection is closing + +protected: + void cleanReq(char* data); +}; + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/NetServices/services/http/server/impl/SimpleHandler.cpp Sun Mar 24 11:25:31 2013 +0000 @@ -0,0 +1,72 @@ + +/* +Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#include "SimpleHandler.h" + +//#define __DEBUG +#include "dbg/dbg.h" + +SimpleHandler::SimpleHandler(const char* rootPath, const char* path, TCPSocket* pTCPSocket) : HTTPRequestHandler(rootPath, path, pTCPSocket) +{} + +SimpleHandler::~SimpleHandler() +{ + DBG("\r\nHandler destroyed\r\n"); +} + +void SimpleHandler::doGet() +{ + DBG("\r\nIn SimpleHandler::doGet()\r\n"); + const char* resp = "Hello world !"; + setContentLen( strlen(resp) ); + respHeaders()["Connection"] = "close"; + writeData(resp, strlen(resp)); + DBG("\r\nExit SimpleHandler::doGet()\r\n"); +} + +void SimpleHandler::doPost() +{ + +} + +void SimpleHandler::doHead() +{ + +} + + +void SimpleHandler::onReadable() //Data has been read +{ + +} + +void SimpleHandler::onWriteable() //Data has been written & buf is free +{ + DBG("\r\nSimpleHandler::onWriteable() event\r\n"); + close(); //Data written, we can close the connection +} + +void SimpleHandler::onClose() //Connection is closing +{ + //Nothing to do +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/NetServices/services/http/server/impl/SimpleHandler.h Sun Mar 24 11:25:31 2013 +0000 @@ -0,0 +1,47 @@ + +/* +Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifndef SIMPLE_HANDLER_H +#define SIMPLE_HANDLER_H + +#include "../HTTPRequestHandler.h" + +class SimpleHandler : public HTTPRequestHandler +{ +public: + SimpleHandler(const char* rootPath, const char* path, TCPSocket* pTCPSocket); + virtual ~SimpleHandler(); + +//protected: + static inline HTTPRequestHandler* inst(const char* rootPath, const char* path, TCPSocket* pTCPSocket) { return new SimpleHandler(rootPath, path, pTCPSocket); } //if we ever could do static virtual functions, this would be one + + virtual void doGet(); + virtual void doPost(); + virtual void doHead(); + + virtual void onReadable(); //Data has been read + virtual void onWriteable(); //Data has been written & buf is free + virtual void onClose(); //Connection is closing +}; + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/NetServices/services/http/util/base64.cpp Sun Mar 24 11:25:31 2013 +0000 @@ -0,0 +1,60 @@ + +/* +Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#include "base64.h" +//Originaly from Rolf's iputil.c + +#ifdef __cplusplus +extern "C" { +#endif + +#include <string.h> + +unsigned int base64enc_len(const char *str) { + return (((strlen(str)-1)/3)+1)<<2; +} + +void base64enc(const char *input, unsigned int length, char *output) { + static const char base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + unsigned int c, c1, c2, c3; + for(unsigned int i = 0, j = 0; i<length; i+=3,j+=4) { + c1 = ((((unsigned char)*((unsigned char *)&input[i])))); + c2 = (length>i+1)?((((unsigned char)*((unsigned char *)&input[i+1])))):0; + c3 = (length>i+2)?((((unsigned char)*((unsigned char *)&input[i+2])))):0; + + c = ((c1 & 0xFC) >> 2); + output[j+0] = base64[c]; + c = ((c1 & 0x03) << 4) | ((c2 & 0xF0) >> 4); + output[j+1] = base64[c]; + c = ((c2 & 0x0F) << 2) | ((c3 & 0xC0) >> 6); + output[j+2] = (length>i+1)?base64[c]:'='; + c = (c3 & 0x3F); + output[j+3] = (length>i+2)?base64[c]:'='; + } + output[(((length-1)/3)+1)<<2] = '\0'; +} + +#ifdef __cplusplus +} +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/NetServices/services/http/util/base64.h Sun Mar 24 11:25:31 2013 +0000 @@ -0,0 +1,57 @@ + +/* +Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifndef BASE64_H +#define BASE64_H + +#include <string> +using std::string; + +#ifdef __cplusplus +extern "C" { +#endif + +//Originaly from Rolf's iputil.h + +unsigned int base64enc_len(const char *str); + +void base64enc(const char *input, unsigned int length, char *output); + +#ifdef __cplusplus +} +#endif + +class Base64 +{ +public: + static string encode(const string& str) + { + char* out = new char[ base64enc_len(str.c_str()) ]; + base64enc(str.c_str(), str.length(), out); + string res(out); + delete[] out; + return res; + } +}; + +#endif /* LWIP_UTILS_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/NetServices/services/http/util/url.cpp Sun Mar 24 11:25:31 2013 +0000 @@ -0,0 +1,151 @@ + +/* +Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#include "url.h" + +Url::Url() : m_port(0) +{ + +} + +string Url::getProtocol() +{ + return m_protocol; +} + +string Url::getHost() +{ + return m_host; +} + +bool Url::getHostIp(IpAddr* ip) +{ + unsigned int ipArr[4] = {0}; + if ( sscanf(m_host.c_str(), "%u.%u.%u.%u", &ipArr[0], &ipArr[1], &ipArr[2], &ipArr[3]) != 4 ) + { + return false; + } + *ip = IpAddr(ipArr[0], ipArr[1], ipArr[2], ipArr[3]); + return true; +} + +uint16_t Url::getPort() +{ + return m_port; +} + +string Url::getPath() +{ + return m_path; +} + +void Url::setProtocol(string protocol) +{ + m_protocol = protocol; +} + +void Url::setHost(string host) +{ + m_host = host; +} + +void Url::setPort(uint16_t port) +{ + m_port = port; +} + +void Url::setPath(string path) +{ + m_path = path; +} + +void Url::fromString(string str) +{ + //URI form [protocol://]host[:port]/path + int pos = 0; + int len = str.find("://"); + if( len > 0) + { + m_protocol = str.substr(0, len); + pos += len + 3; + } + else + { + m_protocol = ""; + } + + bool isPort = false; + int cln_pos = str.find(":", pos); + int slash_pos = str.find("/", pos); + if( slash_pos == -1 ) + { + slash_pos = str.length(); + } + if( (cln_pos != -1) && (cln_pos < slash_pos) ) + { + isPort = true; + len = cln_pos - pos; + } + else + { + len = slash_pos - pos; + } + + m_host = str.substr(pos, len); + + pos += len; + if( isPort ) + { + pos+=1; //Do not keep : + unsigned int port = 0; + sscanf(str.substr(pos, cln_pos-pos).c_str(),"%u", &port); + m_port = (uint16_t)port; + pos = slash_pos; + } + + m_path = str.substr(pos); +} + +string Url::toString() +{ + string url; + if( !m_protocol.empty() ) + { + url.append(m_protocol); + url.append("://"); + } + url.append(m_host); + if( m_port ) + { + char c_port[6] = {0}; + sprintf(c_port, "%d", m_port); + url.append(":"); + url.append(c_port); + } + if(m_path[0]!='/') + { + url.append("/"); + } + url.append(m_path); + return url; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/NetServices/services/http/util/url.h Sun Mar 24 11:25:31 2013 +0000 @@ -0,0 +1,88 @@ + +/* +Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifndef URL_H +#define URL_H + +#include "core/ipaddr.h" + +#include <string> +using std::string; + +#include "mbed.h" + +#ifdef __cplusplus +extern "C" { +#endif + +char *url_encode(char *str); +char *url_decode(char *str); + +#ifdef __cplusplus +} +#endif + +class Url +{ +public: + static string encode(const string& url) + { + char* c_res = url_encode( (char*) url.c_str() ); + string res(c_res); + free(c_res); //Alloc'ed in url_encode() + return res; + } + + static string decode(const string& url) + { + char* c_res = url_decode( (char*) url.c_str() ); + string res(c_res); + free(c_res); //Alloc'ed in url_decode() + return res; + } + + Url(); + + string getProtocol(); + string getHost(); + bool getHostIp(IpAddr* ip); //If host is in IP form, return true & proper object by ptr + uint16_t getPort(); + string getPath(); + + void setProtocol(string protocol); + void setHost(string host); + void setPort(uint16_t port); + void setPath(string path); + + void fromString(string str); + string toString(); + +private: + string m_protocol; + string m_host; + uint16_t m_port; + string m_path; + +}; + +#endif /* LWIP_UTILS_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/NetServices/services/http/util/urlencode.cpp Sun Mar 24 11:25:31 2013 +0000 @@ -0,0 +1,80 @@ + +/* +Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#include "url.h" +#include <stdlib.h> +#include <ctype.h> + +//From http://www.geekhideout.com/urlcode.shtml + +char from_hex(char ch); +char to_hex(char code); + +/* Converts a hex character to its integer value */ +char from_hex(char ch) { + return isdigit(ch) ? ch - '0' : tolower(ch) - 'a' + 10; +} + +/* Converts an integer value to its hex character*/ +char to_hex(char code) { + static char hex[] = "0123456789abcdef"; + return hex[code & 15]; +} + +/* Returns a url-encoded version of str */ +/* IMPORTANT: be sure to free() the returned string after use */ +char *url_encode(char *str) { + char *pstr = str, *buf = (char*)malloc(strlen(str) * 3 + 1), *pbuf = buf; + while (*pstr) { + if (isalnum(*pstr) || *pstr == '-' || *pstr == '_' || *pstr == '.' || *pstr == '~') + *pbuf++ = *pstr; + else if (*pstr == ' ') + *pbuf++ = '+'; + else + *pbuf++ = '%', *pbuf++ = to_hex(*pstr >> 4), *pbuf++ = to_hex(*pstr & 15); + pstr++; + } + *pbuf = '\0'; + return buf; +} + +/* Returns a url-decoded version of str */ +/* IMPORTANT: be sure to free() the returned string after use */ +char *url_decode(char *str) { + char *pstr = str, *buf = (char*)malloc(strlen(str) + 1), *pbuf = buf; + while (*pstr) { + if (*pstr == '%') { + if (pstr[1] && pstr[2]) { + *pbuf++ = from_hex(pstr[1]) << 4 | from_hex(pstr[2]); + pstr += 2; + } + } else if (*pstr == '+') { + *pbuf++ = ' '; + } else { + *pbuf++ = *pstr; + } + pstr++; + } + *pbuf = '\0'; + return buf; +}
--- a/W5200NetIf.cpp Fri Mar 22 11:51:24 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,88 +0,0 @@ -// W5200NetIf.cpp 2012/4/23 -#include "W5200NetIf.h" -#include "DHCPClient.h" -#include "w5100.h" - -extern SPI* pSPI; // w5100.cpp -extern DigitalOut* pCS; // w5100.cpp - -W5200NetIf:: W5200NetIf():MyNetIf(), m_netmask(255,255,255,255), m_gateway(), m_hostname(NULL) { - m_hostname = NULL; - m_useDhcp = true; -} - -W5200NetIf::W5200NetIf(IpAddr ip, IpAddr netmask, IpAddr gateway, IpAddr dns) :MyNetIf(), m_hostname(NULL) { - m_hostname = NULL; - m_ip = ip; - m_netmask = netmask; - m_gateway = gateway; - m_dns = dns; - m_useDhcp = false; -} - -W5200Err W5200NetIf::IPrenew(int timeout_ms) { - if (pSPI == NULL || pCS == NULL) { - return W5200_SETUP_ERR; - } - printf("DHCP Started, waiting for IP...\n"); - DHCPClient dhcp; - int err = dhcp.setup(timeout_ms); - if (err == (-1)) { - printf("Timeout.\n"); - return W5200_TIMEOUT; - } - printf("Connected, IP: %d.%d.%d.%d\n", dhcp.yiaddr[0], dhcp.yiaddr[1], dhcp.yiaddr[2], dhcp.yiaddr[3]); - m_ip = IpAddr(dhcp.yiaddr[0], dhcp.yiaddr[1], dhcp.yiaddr[2], dhcp.yiaddr[3]); - m_netmask = IpAddr(dhcp.netmask[0],dhcp.netmask[1],dhcp.netmask[2],dhcp.netmask[3]); - m_gateway = IpAddr(dhcp.gateway[0],dhcp.gateway[1],dhcp.gateway[2],dhcp.gateway[3]); - uint8_t t[4]; - t[0] = m_ip[0]; - t[1] = m_ip[1]; - t[2] = m_ip[2]; - t[3] = m_ip[3]; - W5100.writeSIPR(t); - t[0] = m_netmask[0]; - t[1] = m_netmask[1]; - t[2] = m_netmask[2]; - t[3] = m_netmask[3]; - W5100.writeSUBR(t); - t[0] = m_gateway[0]; - t[1] = m_gateway[1]; - t[2] = m_gateway[2]; - t[3] = m_gateway[3]; - W5100.writeGAR(t); - m_dns = IpAddr(dhcp.dnsaddr[0],dhcp.dnsaddr[1],dhcp.dnsaddr[2],dhcp.dnsaddr[3]); - return W5200_OK; -} - -W5200Err W5200NetIf::IPrelease(int timeout_ms) { - return W5200_OK; -} - -W5200Err W5200NetIf::setup(int timeout_ms) { - if (pSPI == NULL || pCS == NULL) { - return W5200_SETUP_ERR; - } - MyNetIf::init(); - uint8_t mac[6] = {0x00,0x00,0x5e,0x00,0x01,0x01}; - W5100.setMACAddress(mac); - printf("HW Addr is : %02x:%02x:%02x:%02x:%02x:%02x.\n", mac[0],mac[1],mac[2],mac[3],mac[4],mac[5]); - if(! m_useDhcp) { - return W5200_OK; - } - return IPrenew(timeout_ms); -} - -SPI* W5200NetIf::attachSPI(SPI* spi) { - if (spi) { - pSPI = spi; - } - return pSPI; -} - -DigitalOut* W5200NetIf::attachCS(DigitalOut* cs) { - if (cs) { - pCS = cs; - } - return pCS; -}
--- a/W5200NetIf.h Fri Mar 22 11:51:24 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,46 +0,0 @@ -// W5200NetIf.h 2012/4/19 -/** \file -W5200 network interface header file -*/ -#ifndef W5200_NETIF_H -#define W5200_NETIF_H -#include "MyNetIf.h" - -///W5200 network interface return codes -enum W5200Err -{ - __W5200_MIN = -0xFFFF, - W5200_TIMEOUT, ///<Timeout during setup - W5200_SETUP_ERR, - W5200_OK = 0 ///<Success -}; - -///W5200 network interface -class W5200NetIf : public MyNetIf { -public: - ///Instantiates the Interface and register it against the stack, DHCP will be used - W5200NetIf(); //W/ DHCP - ///Instantiates the Interface and register it against the stack, DHCP will not be used - /** - IpAddr is a container class that can be constructed with either 4 bytes or no parameters for a null IP address. - */ - W5200NetIf(IpAddr ip, IpAddr netmask, IpAddr gateway, IpAddr dns); //W/o DHCP - W5200Err IPrenew(int timeout_ms = 15000); - W5200Err IPrelease(int timeout_ms = 15000); - ///Brings the interface up - /** - Uses DHCP if necessary - @param timeout_ms : You can set the timeout parameter in milliseconds, if not it defaults to 15s - @return : W5200_OK on success or W5200_TIMEOUT on timeout - */ - W5200Err setup(int timeout_ms = 15000); - SPI* attachSPI(SPI* spi); - DigitalOut* attachCS(DigitalOut* cs); - IpAddr m_dns; -private: - bool m_useDhcp; - IpAddr m_netmask; - IpAddr m_gateway; - const char* m_hostname; -}; -#endif //W5200_NETIF_H
--- a/WIZ820ioNetIf.cpp Fri Mar 22 11:51:24 2013 +0000 +++ b/WIZ820ioNetIf.cpp Sun Mar 24 11:25:31 2013 +0000 @@ -1,49 +1,118 @@ -// WIZ820ioNetIf.cpp 2012/4/22 +// WIZ820ioNetIf.cpp 2013/3/24 #include "WIZ820ioNetIf.h" -#include "w5100.h" +#include "DHCPClient.h" +#include "w5200.h" +extern SPI* pSPI; // w5200.cpp +extern DigitalOut* pCS; // w5200.cpp DigitalOut* pRESET = NULL; -void hardware_reset() { - if (!pRESET) { - pRESET = new DigitalOut(p15); - } - if (pRESET) { - pRESET->write(1); - pRESET->write(0); - wait_us(2); - pRESET->write(1); - wait_ms(150); - } +WIZ820ioNetIf::WIZ820ioNetIf(PinName mosi, PinName miso, PinName sclk, PinName cs, PinName reset) + :MyNetIf(), m_netmask(255,255,255,255), m_gateway(), m_hostname(NULL) +{ + m_hostname = NULL; + m_useDhcp = true; + pin_assign(mosi, miso, sclk, cs, reset); +} + +void WIZ820ioNetIf::config(IpAddr ip, IpAddr netmask, IpAddr gateway, IpAddr dns) +{ + m_ip = ip; + m_netmask = netmask; + m_gateway = gateway; + m_dns = dns; + m_useDhcp = false; +} + +void WIZ820ioNetIf::pin_assign(PinName mosi, PinName miso, PinName sclk, PinName cs, PinName reset) +{ + pSPI = new SPI(mosi, miso, sclk); + pCS = new DigitalOut(cs); + if (reset != NC) { + pRESET = new DigitalOut(reset); + } } -bool wait_linkup(int timeout = 5000) { +void hardware_reset() { + if (pRESET) { + pRESET->write(1); + pRESET->write(0); + wait_us(2); + pRESET->write(1); + wait_ms(150); + } +} + +bool wait_linkup(int timeout_ms = 5*1000) { Timer link_t; + link_t.reset(); link_t.start(); - while(link_t.read_ms() < timeout) { - if (0x20 & W5100.readPHYSTATUS()) { + uint8_t status = 0x00; + while(link_t.read_ms() < timeout_ms) { + status = W5200.readPHYSTATUS(); + if (status & 0x20) { + printf("Link Up\n"); return true; } - wait_ms(50); + wait_ms(50); } + printf("Link down\n"); + if (status & 0x08) { + printf("Power down mode\n"); + } return false; } -void WIZ820ioNetIf::reset(PinName _reset) { - pRESET = new DigitalOut(_reset); -} - int WIZ820ioNetIf::setup(int timeout_ms) { hardware_reset(); - if (!attachSPI(NULL)) { - SPI* spi = new SPI(p11, p12, p13); // mosi, miso, sclk - attachSPI(spi); + W5200.init(); + if (!wait_linkup()) { + return W5200_SETUP_ERR_LINK_DOWN; + } + + MyNetIf::init(); + uint8_t mac[6]; + mbed_mac_address((char*)mac); + W5200.setMACAddress(mac); + printf("HW Addr is : %02x:%02x:%02x:%02x:%02x:%02x.\n", mac[0],mac[1],mac[2],mac[3],mac[4],mac[5]); + if(! m_useDhcp) { + return W5200_OK; + } + return IPrenew(timeout_ms); +} + +W5200Err WIZ820ioNetIf::IPrenew(int timeout_ms) { + printf("DHCP Started, waiting for IP...\n"); + DHCPClient dhcp; + int err = dhcp.setup(timeout_ms); + if (err == (-1)) { + printf("Timeout.\n"); + return W5200_TIMEOUT; } - if (!attachCS(NULL)) { - DigitalOut* cs = new DigitalOut(p14); - attachCS(cs); - } - W5100.init(); - wait_linkup(); - return W5200NetIf::setup(timeout_ms); + printf("Connected, IP: %d.%d.%d.%d\n", dhcp.yiaddr[0], dhcp.yiaddr[1], dhcp.yiaddr[2], dhcp.yiaddr[3]); + m_ip = IpAddr(dhcp.yiaddr[0], dhcp.yiaddr[1], dhcp.yiaddr[2], dhcp.yiaddr[3]); + m_netmask = IpAddr(dhcp.netmask[0],dhcp.netmask[1],dhcp.netmask[2],dhcp.netmask[3]); + m_gateway = IpAddr(dhcp.gateway[0],dhcp.gateway[1],dhcp.gateway[2],dhcp.gateway[3]); + uint8_t t[4]; + t[0] = m_ip[0]; + t[1] = m_ip[1]; + t[2] = m_ip[2]; + t[3] = m_ip[3]; + W5200.writeSIPR(t); + t[0] = m_netmask[0]; + t[1] = m_netmask[1]; + t[2] = m_netmask[2]; + t[3] = m_netmask[3]; + W5200.writeSUBR(t); + t[0] = m_gateway[0]; + t[1] = m_gateway[1]; + t[2] = m_gateway[2]; + t[3] = m_gateway[3]; + W5200.writeGAR(t); + m_dns = IpAddr(dhcp.dnsaddr[0],dhcp.dnsaddr[1],dhcp.dnsaddr[2],dhcp.dnsaddr[3]); + return W5200_OK; } + +W5200Err WIZ820ioNetIf::IPrelease(int timeout_ms) { + return W5200_OK; +}
--- a/WIZ820ioNetIf.h Fri Mar 22 11:51:24 2013 +0000 +++ b/WIZ820ioNetIf.h Sun Mar 24 11:25:31 2013 +0000 @@ -1,16 +1,34 @@ -// WIZ820ioNetIf.h 2012/4/23 +// WIZ820ioNetIf.h 2013/3/24 /** \file WIZ820io network interface header file */ -#ifndef WIZ820IO_NETIF_H -#define WIZ820IO_NETIF_H -#include "W5200NetIf.h" +#pragma once +#include "MyNetIf.h" + +///W5200 network interface return codes +enum W5200Err +{ + __W5200_MIN = -0xFFFF, + W5200_TIMEOUT, ///<Timeout during setup + W5200_SETUP_ERR, + W5200_SETUP_ERR_LINK_DOWN, + W5200_OK = 0 ///<Success +}; ///WIZ820io network interface -class WIZ820ioNetIf : public W5200NetIf { +class WIZ820ioNetIf : public MyNetIf { public: - void reset(PinName _reset); + /** Create a WIZ820io ethernet interface + * + * @param mosi SPI mosi pin connected to WIZ820io + * @param miso SPI miso pin conencted to WIZ820io + * @param sclk SPI sclk pin connected to WIZ820io + * @param cs DigitalOut pin used as WIZ820io select + * @param reset DigitalOut pin WIZ820io hardware reset + */ + WIZ820ioNetIf(PinName mosi, PinName miso, PinName sclk, PinName cs, PinName reset); + void config(IpAddr ip, IpAddr netmask, IpAddr gateway, IpAddr dns); //W/o DHCP ///Brings the interface up /** Uses DHCP if necessary @@ -18,5 +36,13 @@ @return : 0 on success or -1 on timeout */ int setup(int timeout_ms = 15000); + W5200Err IPrenew(int timeout_ms = 15000); + W5200Err IPrelease(int timeout_ms = 15000); + IpAddr m_dns; +private: + void pin_assign(PinName mosi, PinName miso, PinName sclk, PinName cs, PinName reset); + bool m_useDhcp; + IpAddr m_netmask; + IpAddr m_gateway; + const char* m_hostname; }; -#endif //WIZ820IO_NETIF_H
--- a/w5100.cpp Fri Mar 22 11:51:24 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,272 +0,0 @@ -/* - * Copyright (c) 2010 by Cristian Maglie <c.maglie@bug.st> - * - * This file is free software; you can redistribute it and/or modify - * it under the terms of either the GNU General Public License version 2 - * or the GNU Lesser General Public License version 2.1, both as - * published by the Free Software Foundation. - */ - -#include <stdio.h> -#include <string.h> -#include "mbed.h" -#include "w5100.h" -#ifndef MBED -#include <avr/interrupt.h> -#endif //MBED - -// W5100 controller instance -W5100Class W5100; - -#define TX_RX_MAX_BUF_SIZE 2048 -#define TX_BUF 0x1100 -#define RX_BUF (TX_BUF + TX_RX_MAX_BUF_SIZE) - -#ifdef W5200 -#define TXBUF_BASE 0x8000 -#define RXBUF_BASE 0xC000 -#else -#define TXBUF_BASE 0x4000 -#define RXBUF_BASE 0x6000 -#endif - -#ifdef MBED - -SPI* pSPI = NULL; -DigitalOut* pCS = NULL; - -inline void delay(int n) { wait_ms(n); } -inline static void initSS(){ pCS->write(1); } -inline static void setSS() { pCS->write(0); } -inline static void resetSS() { pCS->write(1); } - -#endif //MBED - -void W5100Class::init(void) -{ - if (!pSPI) { - pSPI = new SPI(p11, p12, p13); // mosi, miso, sclk - } - if (!pCS) { - pCS = new DigitalOut(p14); - } - initSS(); - writeMR(1<<RST); - -#ifdef W5200 - for (int i=0; i<MAX_SOCK_NUM; i++) { - write((0x4000 + i * 0x100 + 0x001F), 2); - write((0x4000 + i * 0x100 + 0x001E), 2); - } -#else - writeTMSR(0x55); - writeRMSR(0x55); -#endif - - for (int i=0; i<MAX_SOCK_NUM; i++) { - SBASE[i] = TXBUF_BASE + SSIZE * i; - RBASE[i] = RXBUF_BASE + RSIZE * i; - } -} - -uint16_t W5100Class::getTXFreeSize(SOCKET s) -{ - uint16_t val=0, val1=0; - do { - val1 = readSnTX_FSR(s); - if (val1 != 0) - val = readSnTX_FSR(s); - } - while (val != val1); - return val; -} - -uint16_t W5100Class::getRXReceivedSize(SOCKET s) -{ - uint16_t val=0,val1=0; - do { - val1 = readSnRX_RSR(s); - if (val1 != 0) - val = readSnRX_RSR(s); - } - while (val != val1); - return val; -} - - -void W5100Class::send_data_processing(SOCKET s, const uint8_t *data, uint16_t len) -{ - // This is same as having no offset in a call to send_data_processing_offset - send_data_processing_offset(s, 0, data, len); -} - -void W5100Class::send_data_processing_offset(SOCKET s, uint16_t data_offset, const uint8_t *data, uint16_t len) -{ - uint16_t ptr = readSnTX_WR(s); - ptr += data_offset; - uint16_t offset = ptr & SMASK; - uint16_t dstAddr = offset + SBASE[s]; - - if (offset + len > SSIZE) - { - // Wrap around circular buffer - uint16_t size = SSIZE - offset; - write(dstAddr, data, size); - write(SBASE[s], data + size, len - size); - } - else { - write(dstAddr, data, len); - } - - ptr += len; - writeSnTX_WR(s, ptr); -} - - -void W5100Class::recv_data_processing(SOCKET s, uint8_t *data, uint16_t len, uint8_t peek) -{ - uint16_t ptr; - ptr = readSnRX_RD(s); - read_data(s, (uint8_t *)ptr, data, len); - if (!peek) - { - ptr += len; - writeSnRX_RD(s, ptr); - } -} - -void W5100Class::read_data(SOCKET s, volatile uint8_t *src, volatile uint8_t *dst, uint16_t len) -{ - uint16_t size; - uint16_t src_mask; - uint16_t src_ptr; - -#ifdef MBED - src_mask = (int)src & RMASK; -#else - src_mask = (uint16_t)src & RMASK; -#endif //MBED - src_ptr = RBASE[s] + src_mask; - - if( (src_mask + len) > RSIZE ) - { - size = RSIZE - src_mask; - read(src_ptr, (uint8_t *)dst, size); - dst += size; - read(RBASE[s], (uint8_t *) dst, len - size); - } - else - read(src_ptr, (uint8_t *) dst, len); -} - - -uint8_t W5100Class::write(uint16_t _addr, uint8_t _data) -{ - setSS(); - -#ifdef W5200 - pSPI->write(_addr >> 8); - pSPI->write(_addr & 0xFF); - pSPI->write(0x80); - pSPI->write(0x01); -#else - pSPI->write(0xF0); - pSPI->write(_addr >> 8); - pSPI->write(_addr & 0xFF); -#endif - pSPI->write(_data); - resetSS(); - return 1; -} - -uint16_t W5100Class::write(uint16_t _addr, const uint8_t *_buf, uint16_t _len) -{ - -#ifdef W5200 - setSS(); - pSPI->write(_addr >> 8); - pSPI->write(_addr & 0xFF); - pSPI->write((0x80 | ((_len & 0x7F00) >> 8))); - pSPI->write(_len & 0x00FF); - - for (uint16_t i=0; i<_len; i++) - { - pSPI->write(_buf[i]); - - } - resetSS(); -#else - - for (uint16_t i=0; i<_len; i++) - { - setSS(); - pSPI->write(0xF0); - pSPI->write(_addr >> 8); - pSPI->write(_addr & 0xFF); - _addr++; - pSPI->write(_buf[i]); - resetSS(); - } -#endif - - return _len; -} - -uint8_t W5100Class::read(uint16_t _addr) -{ - setSS(); -#ifdef W5200 - pSPI->write(_addr >> 8); - pSPI->write(_addr & 0xFF); - pSPI->write(0x00); - pSPI->write(0x01); -#else - pSPI->write(0x0F); - pSPI->write(_addr >> 8); - pSPI->write(_addr & 0xFF); -#endif - - uint8_t _data = pSPI->write(0); - resetSS(); - return _data; -} - -uint16_t W5100Class::read(uint16_t _addr, uint8_t *_buf, uint16_t _len) -{ -#ifdef W5200 - setSS(); - pSPI->write(_addr >> 8); - pSPI->write(_addr & 0xFF); - pSPI->write((0x00 | ((_len & 0x7F00) >> 8))); - pSPI->write(_len & 0x00FF); - - for (uint16_t i=0; i<_len; i++) - { - _buf[i] = pSPI->write(0); - - } - resetSS(); - -#else - - for (uint16_t i=0; i<_len; i++) - { - setSS(); - pSPI->write(0x0F); - pSPI->write(_addr >> 8); - pSPI->write(_addr & 0xFF); - _addr++; - _buf[i] = pSPI->write(0); - resetSS(); - } -#endif - return _len; -} - -void W5100Class::execCmdSn(SOCKET s, SockCMD _cmd) { - // Send command to socket - writeSnCR(s, _cmd); - // Wait for command to complete - while (readSnCR(s)) - ; -}
--- a/w5100.h Fri Mar 22 11:51:24 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,432 +0,0 @@ -/* - * Copyright (c) 2010 by Cristian Maglie <c.maglie@bug.st> - * - * This file is free software; you can redistribute it and/or modify - * it under the terms of either the GNU General Public License version 2 - * or the GNU Lesser General Public License version 2.1, both as - * published by the Free Software Foundation. - */ - -#ifndef W5100_H_INCLUDED -#define W5100_H_INCLUDED -#define MBED -#ifdef MBED -#include "mbed.h" -typedef unsigned char uint8_t; -typedef unsigned short uint16_t; -#else //MBED -#include <avr/pgmspace.h> -#include <SPI.h> -#endif //MBED -#define W5200 - -#ifdef W5200 -#define MAX_SOCK_NUM 8 -#else -#define MAX_SOCK_NUM 4 -#endif - - -typedef uint8_t SOCKET; - -#ifndef W5200 -#define IDM_OR 0x8000 -#define IDM_AR0 0x8001 -#define IDM_AR1 0x8002 -#define IDM_DR 0x8003 -#endif - -/* -class MR { -public: - static const uint8_t RST = 0x80; - static const uint8_t PB = 0x10; - static const uint8_t PPPOE = 0x08; - static const uint8_t LB = 0x04; - static const uint8_t AI = 0x02; - static const uint8_t IND = 0x01; -}; -*/ -/* -class IR { -public: - static const uint8_t CONFLICT = 0x80; - static const uint8_t UNREACH = 0x40; - static const uint8_t PPPoE = 0x20; - static const uint8_t SOCK0 = 0x01; - static const uint8_t SOCK1 = 0x02; - static const uint8_t SOCK2 = 0x04; - static const uint8_t SOCK3 = 0x08; - static inline uint8_t SOCK(SOCKET ch) { return (0x01 << ch); }; -}; -*/ - -class SnMR { -public: - static const uint8_t CLOSE = 0x00; - static const uint8_t TCP = 0x01; - static const uint8_t UDP = 0x02; - static const uint8_t IPRAW = 0x03; - static const uint8_t MACRAW = 0x04; - static const uint8_t PPPOE = 0x05; - static const uint8_t ND = 0x20; - static const uint8_t MULTI = 0x80; -}; - -enum SockCMD { - Sock_OPEN = 0x01, - Sock_LISTEN = 0x02, - Sock_CONNECT = 0x04, - Sock_DISCON = 0x08, - Sock_CLOSE = 0x10, - Sock_SEND = 0x20, - Sock_SEND_MAC = 0x21, - Sock_SEND_KEEP = 0x22, - Sock_RECV = 0x40 -}; - -/*class SnCmd { -public: - static const uint8_t OPEN = 0x01; - static const uint8_t LISTEN = 0x02; - static const uint8_t CONNECT = 0x04; - static const uint8_t DISCON = 0x08; - static const uint8_t CLOSE = 0x10; - static const uint8_t SEND = 0x20; - static const uint8_t SEND_MAC = 0x21; - static const uint8_t SEND_KEEP = 0x22; - static const uint8_t RECV = 0x40; -}; -*/ - -class SnIR { -public: - static const uint8_t SEND_OK = 0x10; - static const uint8_t TIMEOUT = 0x08; - static const uint8_t RECV = 0x04; - static const uint8_t DISCON = 0x02; - static const uint8_t CON = 0x01; -}; - -class SnSR { -public: - static const uint8_t CLOSED = 0x00; - static const uint8_t INIT = 0x13; - static const uint8_t LISTEN = 0x14; - static const uint8_t SYNSENT = 0x15; - static const uint8_t SYNRECV = 0x16; - static const uint8_t ESTABLISHED = 0x17; - static const uint8_t FIN_WAIT = 0x18; - static const uint8_t CLOSING = 0x1A; - static const uint8_t TIME_WAIT = 0x1B; - static const uint8_t CLOSE_WAIT = 0x1C; - static const uint8_t LAST_ACK = 0x1D; - static const uint8_t UDP = 0x22; - static const uint8_t IPRAW = 0x32; - static const uint8_t MACRAW = 0x42; - static const uint8_t PPPOE = 0x5F; -}; - -class IPPROTO { -public: - static const uint8_t IP = 0; - static const uint8_t ICMP = 1; - static const uint8_t IGMP = 2; - static const uint8_t GGP = 3; - static const uint8_t TCP = 6; - static const uint8_t PUP = 12; - static const uint8_t UDP = 17; - static const uint8_t IDP = 22; - static const uint8_t ND = 77; - static const uint8_t RAW = 255; -}; - -class W5100Class { -public: - void init(); - - /** - * @brief This function is being used for copy the data form Receive buffer of the chip to application buffer. - * - * It calculate the actual physical address where one has to read - * the data from Receive buffer. Here also take care of the condition while it exceed - * the Rx memory uper-bound of socket. - */ - void read_data(SOCKET s, volatile uint8_t * src, volatile uint8_t * dst, uint16_t len); - - /** - * @brief This function is being called by send() and sendto() function also. - * - * This function read the Tx write pointer register and after copy the data in buffer update the Tx write pointer - * register. User should read upper byte first and lower byte later to get proper value. - */ - void send_data_processing(SOCKET s, const uint8_t *data, uint16_t len); - /** - * @brief A copy of send_data_processing that uses the provided ptr for the - * write offset. Only needed for the "streaming" UDP API, where - * a single UDP packet is built up over a number of calls to - * send_data_processing_ptr, because TX_WR doesn't seem to get updated - * correctly in those scenarios - * @param ptr value to use in place of TX_WR. If 0, then the value is read - * in from TX_WR - * @return New value for ptr, to be used in the next call - */ -// FIXME Update documentation - void send_data_processing_offset(SOCKET s, uint16_t data_offset, const uint8_t *data, uint16_t len); - - /** - * @brief This function is being called by recv() also. - * - * This function read the Rx read pointer register - * and after copy the data from receive buffer update the Rx write pointer register. - * User should read upper byte first and lower byte later to get proper value. - */ - void recv_data_processing(SOCKET s, uint8_t *data, uint16_t len, uint8_t peek = 0); - - inline void setGatewayIp(uint8_t *_addr); - inline void getGatewayIp(uint8_t *_addr); - - inline void setSubnetMask(uint8_t *_addr); - inline void getSubnetMask(uint8_t *_addr); - - inline void setMACAddress(uint8_t * addr); - inline void getMACAddress(uint8_t * addr); - - inline void setIPAddress(uint8_t * addr); - inline void getIPAddress(uint8_t * addr); - - inline void setRetransmissionTime(uint16_t timeout); - inline void setRetransmissionCount(uint8_t _retry); - - void execCmdSn(SOCKET s, SockCMD _cmd); - - uint16_t getTXFreeSize(SOCKET s); - uint16_t getRXReceivedSize(SOCKET s); - - - // W5100 Registers - // --------------- -private: - static uint8_t write(uint16_t _addr, uint8_t _data); - static uint16_t write(uint16_t addr, const uint8_t *buf, uint16_t len); - static uint8_t read(uint16_t addr); - static uint16_t read(uint16_t addr, uint8_t *buf, uint16_t len); - -#define __GP_REGISTER8(name, address) \ - static inline void write##name(uint8_t _data) { \ - write(address, _data); \ - } \ - static inline uint8_t read##name() { \ - return read(address); \ - } -#define __GP_REGISTER16(name, address) \ - static void write##name(uint16_t _data) { \ - write(address, _data >> 8); \ - write(address+1, _data & 0xFF); \ - } \ - static uint16_t read##name() { \ - uint16_t res = read(address); \ - res = (res << 8) + read(address + 1); \ - return res; \ - } -#define __GP_REGISTER_N(name, address, size) \ - static uint16_t write##name(uint8_t *_buff) { \ - return write(address, _buff, size); \ - } \ - static uint16_t read##name(uint8_t *_buff) { \ - return read(address, _buff, size); \ - } - -public: - __GP_REGISTER8 (MR, 0x0000); // Mode - __GP_REGISTER_N(GAR, 0x0001, 4); // Gateway IP address - __GP_REGISTER_N(SUBR, 0x0005, 4); // Subnet mask address - __GP_REGISTER_N(SHAR, 0x0009, 6); // Source MAC address - __GP_REGISTER_N(SIPR, 0x000F, 4); // Source IP address - __GP_REGISTER8 (IR, 0x0015); // Interrupt - __GP_REGISTER8 (IMR, 0x0016); // Interrupt Mask - __GP_REGISTER16(RTR, 0x0017); // Timeout address - __GP_REGISTER8 (RCR, 0x0019); // Retry count - - #ifndef W5200 - __GP_REGISTER8 (RMSR, 0x001A); // Receive memory size - __GP_REGISTER8 (TMSR, 0x001B); // Transmit memory size - #endif - __GP_REGISTER8 (PATR, 0x001C); // Authentication type address in PPPoE mode - - __GP_REGISTER8 (VERSIONR,0x001f); // Chip version - - __GP_REGISTER8 (PTIMER, 0x0028); // PPP LCP Request Timer - __GP_REGISTER8 (PMAGIC, 0x0029); // PPP LCP Magic Number - #ifndef W5200 - __GP_REGISTER_N(UIPR, 0x002A, 4); // Unreachable IP address in UDP mode - __GP_REGISTER16(UPORT, 0x002E); // Unreachable Port address in UDP mode -#endif - __GP_REGISTER8 (PHYSTATUS,0x0035); // PHY Status - -#undef __GP_REGISTER8 -#undef __GP_REGISTER16 -#undef __GP_REGISTER_N - - // W5100 Socket registers - // ---------------------- -private: - static inline uint8_t readSn(SOCKET _s, uint16_t _addr); - static inline uint8_t writeSn(SOCKET _s, uint16_t _addr, uint8_t _data); - static inline uint16_t readSn(SOCKET _s, uint16_t _addr, uint8_t *_buf, uint16_t len); - static inline uint16_t writeSn(SOCKET _s, uint16_t _addr, uint8_t *_buf, uint16_t len); - -#ifdef W5200 - static const uint16_t CH_BASE = 0x4000; -#else - static const uint16_t CH_BASE = 0x0400; -#endif - - static const uint16_t CH_SIZE = 0x0100; - -#define __SOCKET_REGISTER8(name, address) \ - static inline void write##name(SOCKET _s, uint8_t _data) { \ - writeSn(_s, address, _data); \ - } \ - static inline uint8_t read##name(SOCKET _s) { \ - return readSn(_s, address); \ - } -#define __SOCKET_REGISTER16(name, address) \ - static void write##name(SOCKET _s, uint16_t _data) { \ - writeSn(_s, address, _data >> 8); \ - writeSn(_s, address+1, _data & 0xFF); \ - } \ - static uint16_t read##name(SOCKET _s) { \ - uint16_t res = readSn(_s, address); \ - res = (res << 8) + readSn(_s, address + 1); \ - return res; \ - } -#define __SOCKET_REGISTER_N(name, address, size) \ - static uint16_t write##name(SOCKET _s, uint8_t *_buff) { \ - return writeSn(_s, address, _buff, size); \ - } \ - static uint16_t read##name(SOCKET _s, uint8_t *_buff) { \ - return readSn(_s, address, _buff, size); \ - } - -public: - __SOCKET_REGISTER8(SnMR, 0x0000) // Mode - __SOCKET_REGISTER8(SnCR, 0x0001) // Command - __SOCKET_REGISTER8(SnIR, 0x0002) // Interrupt - __SOCKET_REGISTER8(SnSR, 0x0003) // Status - __SOCKET_REGISTER16(SnPORT, 0x0004) // Source Port - __SOCKET_REGISTER_N(SnDHAR, 0x0006, 6) // Destination Hardw Addr - __SOCKET_REGISTER_N(SnDIPR, 0x000C, 4) // Destination IP Addr - __SOCKET_REGISTER16(SnDPORT, 0x0010) // Destination Port - __SOCKET_REGISTER16(SnMSSR, 0x0012) // Max Segment Size - __SOCKET_REGISTER8(SnPROTO, 0x0014) // Protocol in IP RAW Mode - __SOCKET_REGISTER8(SnTOS, 0x0015) // IP TOS - __SOCKET_REGISTER8(SnTTL, 0x0016) // IP TTL - __SOCKET_REGISTER16(SnTX_FSR, 0x0020) // TX Free Size - __SOCKET_REGISTER16(SnTX_RD, 0x0022) // TX Read Pointer - __SOCKET_REGISTER16(SnTX_WR, 0x0024) // TX Write Pointer - __SOCKET_REGISTER16(SnRX_RSR, 0x0026) // RX Free Size - __SOCKET_REGISTER16(SnRX_RD, 0x0028) // RX Read Pointer - __SOCKET_REGISTER16(SnRX_WR, 0x002A) // RX Write Pointer (supported?) - -#undef __SOCKET_REGISTER8 -#undef __SOCKET_REGISTER16 -#undef __SOCKET_REGISTER_N - - -private: - static const uint8_t RST = 7; // Reset BIT - -#ifdef W5200 - static const int SOCKETS = 8; -#else - static const int SOCKETS = 4; -#endif - - static const uint16_t SMASK = 0x07FF; // Tx buffer MASK - static const uint16_t RMASK = 0x07FF; // Rx buffer MASK -public: - static const uint16_t SSIZE = 2048; // Max Tx buffer size -private: - static const uint16_t RSIZE = 2048; // Max Rx buffer size - uint16_t SBASE[SOCKETS]; // Tx buffer base address - uint16_t RBASE[SOCKETS]; // Rx buffer base address - -private: -#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) - inline static void initSS() { DDRB |= _BV(4); }; - inline static void setSS() { PORTB &= ~_BV(4); }; - inline static void resetSS() { PORTB |= _BV(4); }; -#elif defined(__AVR_ATmega32U4__) || defined(__AVR_AT90USB1286__) || defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB162__) - inline static void initSS() { DDRB |= _BV(0); }; - inline static void setSS() { PORTB &= ~_BV(0); }; - inline static void resetSS() { PORTB |= _BV(0); }; -#else -#ifndef MBED - inline static void initSS() { DDRB |= _BV(2); }; - inline static void setSS() { PORTB &= ~_BV(2); }; - inline static void resetSS() { PORTB |= _BV(2); }; -#endif //MBED -#endif - -}; - -extern W5100Class W5100; - -uint8_t W5100Class::readSn(SOCKET _s, uint16_t _addr) { - return read(CH_BASE + _s * CH_SIZE + _addr); -} - -uint8_t W5100Class::writeSn(SOCKET _s, uint16_t _addr, uint8_t _data) { - return write(CH_BASE + _s * CH_SIZE + _addr, _data); -} - -uint16_t W5100Class::readSn(SOCKET _s, uint16_t _addr, uint8_t *_buf, uint16_t _len) { - return read(CH_BASE + _s * CH_SIZE + _addr, _buf, _len); -} - -uint16_t W5100Class::writeSn(SOCKET _s, uint16_t _addr, uint8_t *_buf, uint16_t _len) { - return write(CH_BASE + _s * CH_SIZE + _addr, _buf, _len); -} - -void W5100Class::getGatewayIp(uint8_t *_addr) { - readGAR(_addr); -} - -void W5100Class::setGatewayIp(uint8_t *_addr) { - writeGAR(_addr); -} - -void W5100Class::getSubnetMask(uint8_t *_addr) { - readSUBR(_addr); -} - -void W5100Class::setSubnetMask(uint8_t *_addr) { - writeSUBR(_addr); -} - -void W5100Class::getMACAddress(uint8_t *_addr) { - readSHAR(_addr); -} - -void W5100Class::setMACAddress(uint8_t *_addr) { - writeSHAR(_addr); -} - -void W5100Class::getIPAddress(uint8_t *_addr) { - readSIPR(_addr); -} - -void W5100Class::setIPAddress(uint8_t *_addr) { - writeSIPR(_addr); -} - -void W5100Class::setRetransmissionTime(uint16_t _timeout) { - writeRTR(_timeout); -} - -void W5100Class::setRetransmissionCount(uint8_t _retry) { - writeRCR(_retry); -} - -#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/w5200.cpp Sun Mar 24 11:25:31 2013 +0000 @@ -0,0 +1,213 @@ +/* + * Copyright (c) 2010 by Cristian Maglie <c.maglie@bug.st> + * + * This file is free software; you can redistribute it and/or modify + * it under the terms of either the GNU General Public License version 2 + * or the GNU Lesser General Public License version 2.1, both as + * published by the Free Software Foundation. + */ + +#include <stdio.h> +#include <string.h> +#include "mbed.h" +#include "w5200.h" + +SPI* pSPI; +DigitalOut* pCS; +void initSS(){ pCS->write(1); } +void setSS() { pCS->write(0); } +void resetSS() { pCS->write(1); } + +// W5200 controller instance +W5200Class W5200; + +#define TX_RX_MAX_BUF_SIZE 2048 +#define TX_BUF 0x1100 +#define RX_BUF (TX_BUF + TX_RX_MAX_BUF_SIZE) + +#define TXBUF_BASE 0x8000 +#define RXBUF_BASE 0xC000 + +#if defined(TARGET_KL25Z) +#define RESET_PIN PTD5 +#define CS_PIN PTD0 +#define MOSI_PIN PTD2 +#define MISO_PIN PTD3 +#define SCLK_PIN PTD1 +#endif + +void W5200Class::init(void) +{ + if (!pSPI) { + pSPI = new SPI(MOSI_PIN, MISO_PIN, SCLK_PIN); // mosi, miso, sclk + } + if (!pCS) { + pCS = new DigitalOut(CS_PIN); + } + initSS(); + writeMR(1<<RST); + + for (int i=0; i<MAX_SOCK_NUM; i++) { + write((0x4000 + i * 0x100 + 0x001F), 2); + write((0x4000 + i * 0x100 + 0x001E), 2); + } + + for (int i=0; i<MAX_SOCK_NUM; i++) { + SBASE[i] = TXBUF_BASE + SSIZE * i; + RBASE[i] = RXBUF_BASE + RSIZE * i; + } +} + +uint16_t W5200Class::getTXFreeSize(SOCKET s) +{ + uint16_t val=0, val1=0; + do { + val1 = readSnTX_FSR(s); + if (val1 != 0) + val = readSnTX_FSR(s); + } + while (val != val1); + return val; +} + +uint16_t W5200Class::getRXReceivedSize(SOCKET s) +{ + uint16_t val=0,val1=0; + do { + val1 = readSnRX_RSR(s); + if (val1 != 0) + val = readSnRX_RSR(s); + } + while (val != val1); + return val; +} + + +void W5200Class::send_data_processing(SOCKET s, const uint8_t *data, uint16_t len) +{ + // This is same as having no offset in a call to send_data_processing_offset + send_data_processing_offset(s, 0, data, len); +} + +void W5200Class::send_data_processing_offset(SOCKET s, uint16_t data_offset, const uint8_t *data, uint16_t len) +{ + uint16_t ptr = readSnTX_WR(s); + ptr += data_offset; + uint16_t offset = ptr & SMASK; + uint16_t dstAddr = offset + SBASE[s]; + + if (offset + len > SSIZE) + { + // Wrap around circular buffer + uint16_t size = SSIZE - offset; + write(dstAddr, data, size); + write(SBASE[s], data + size, len - size); + } + else { + write(dstAddr, data, len); + } + + ptr += len; + writeSnTX_WR(s, ptr); +} + + +void W5200Class::recv_data_processing(SOCKET s, uint8_t *data, uint16_t len, uint8_t peek) +{ + uint16_t ptr; + ptr = readSnRX_RD(s); + read_data(s, (uint8_t *)ptr, data, len); + if (!peek) + { + ptr += len; + writeSnRX_RD(s, ptr); + } +} + +void W5200Class::read_data(SOCKET s, volatile uint8_t *src, volatile uint8_t *dst, uint16_t len) +{ + uint16_t size; + uint16_t src_mask; + uint16_t src_ptr; + + //src_mask = (uint16_t)src & RMASK; + src_mask = (int)src & RMASK; + src_ptr = RBASE[s] + src_mask; + + if( (src_mask + len) > RSIZE ) + { + size = RSIZE - src_mask; + read(src_ptr, (uint8_t *)dst, size); + dst += size; + read(RBASE[s], (uint8_t *) dst, len - size); + } + else + read(src_ptr, (uint8_t *) dst, len); +} + + +uint8_t W5200Class::write(uint16_t _addr, uint8_t _data) +{ + setSS(); + + pSPI->write(_addr >> 8); + pSPI->write(_addr & 0xFF); + pSPI->write(0x80); + pSPI->write(0x01); + pSPI->write(_data); + resetSS(); + return 1; +} + +uint16_t W5200Class::write(uint16_t _addr, const uint8_t *_buf, uint16_t _len) +{ + setSS(); + pSPI->write(_addr >> 8); + pSPI->write(_addr & 0xFF); + pSPI->write((0x80 | ((_len & 0x7F00) >> 8))); + pSPI->write(_len & 0x00FF); + + for (uint16_t i=0; i<_len; i++) + { + pSPI->write(_buf[i]); + } + resetSS(); + + return _len; +} + +uint8_t W5200Class::read(uint16_t _addr) +{ + setSS(); + pSPI->write(_addr >> 8); + pSPI->write(_addr & 0xFF); + pSPI->write(0x00); + pSPI->write(0x01); + uint8_t _data = pSPI->write(0); + resetSS(); + return _data; +} + +uint16_t W5200Class::read(uint16_t _addr, uint8_t *_buf, uint16_t _len) +{ + setSS(); + pSPI->write(_addr >> 8); + pSPI->write(_addr & 0xFF); + pSPI->write((0x00 | ((_len & 0x7F00) >> 8))); + pSPI->write(_len & 0x00FF); + + for (uint16_t i=0; i<_len; i++) + { + _buf[i] = pSPI->write(0); + } + resetSS(); + return _len; +} + +void W5200Class::execCmdSn(SOCKET s, SockCMD _cmd) { + // Send command to socket + writeSnCR(s, _cmd); + // Wait for command to complete + while (readSnCR(s)) + ; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/w5200.h Sun Mar 24 11:25:31 2013 +0000 @@ -0,0 +1,330 @@ +/* + * Copyright (c) 2010 by Cristian Maglie <c.maglie@bug.st> + * + * This file is free software; you can redistribute it and/or modify + * it under the terms of either the GNU General Public License version 2 + * or the GNU Lesser General Public License version 2.1, both as + * published by the Free Software Foundation. + */ +#include "mbed.h" +#pragma once + +#define MAX_SOCK_NUM 8 + +typedef uint8_t SOCKET; + +class SnMR { +public: + static const uint8_t CLOSE = 0x00; + static const uint8_t TCP = 0x01; + static const uint8_t UDP = 0x02; + static const uint8_t IPRAW = 0x03; + static const uint8_t MACRAW = 0x04; + static const uint8_t PPPOE = 0x05; + static const uint8_t ND = 0x20; + static const uint8_t MULTI = 0x80; +}; + +enum SockCMD { + Sock_OPEN = 0x01, + Sock_LISTEN = 0x02, + Sock_CONNECT = 0x04, + Sock_DISCON = 0x08, + Sock_CLOSE = 0x10, + Sock_SEND = 0x20, + Sock_SEND_MAC = 0x21, + Sock_SEND_KEEP = 0x22, + Sock_RECV = 0x40 +}; + +class SnIR { +public: + static const uint8_t SEND_OK = 0x10; + static const uint8_t TIMEOUT = 0x08; + static const uint8_t RECV = 0x04; + static const uint8_t DISCON = 0x02; + static const uint8_t CON = 0x01; +}; + +class SnSR { +public: + static const uint8_t CLOSED = 0x00; + static const uint8_t INIT = 0x13; + static const uint8_t LISTEN = 0x14; + static const uint8_t SYNSENT = 0x15; + static const uint8_t SYNRECV = 0x16; + static const uint8_t ESTABLISHED = 0x17; + static const uint8_t FIN_WAIT = 0x18; + static const uint8_t CLOSING = 0x1A; + static const uint8_t TIME_WAIT = 0x1B; + static const uint8_t CLOSE_WAIT = 0x1C; + static const uint8_t LAST_ACK = 0x1D; + static const uint8_t UDP = 0x22; + static const uint8_t IPRAW = 0x32; + static const uint8_t MACRAW = 0x42; + static const uint8_t PPPOE = 0x5F; +}; + +class IPPROTO { +public: + static const uint8_t IP = 0; + static const uint8_t ICMP = 1; + static const uint8_t IGMP = 2; + static const uint8_t GGP = 3; + static const uint8_t TCP = 6; + static const uint8_t PUP = 12; + static const uint8_t UDP = 17; + static const uint8_t IDP = 22; + static const uint8_t ND = 77; + static const uint8_t RAW = 255; +}; + +class W5200Class { +public: + void init(); + + /** + * @brief This function is being used for copy the data form Receive buffer of the chip to application buffer. + * + * It calculate the actual physical address where one has to read + * the data from Receive buffer. Here also take care of the condition while it exceed + * the Rx memory uper-bound of socket. + */ + void read_data(SOCKET s, volatile uint8_t * src, volatile uint8_t * dst, uint16_t len); + + /** + * @brief This function is being called by send() and sendto() function also. + * + * This function read the Tx write pointer register and after copy the data in buffer update the Tx write pointer + * register. User should read upper byte first and lower byte later to get proper value. + */ + void send_data_processing(SOCKET s, const uint8_t *data, uint16_t len); + /** + * @brief A copy of send_data_processing that uses the provided ptr for the + * write offset. Only needed for the "streaming" UDP API, where + * a single UDP packet is built up over a number of calls to + * send_data_processing_ptr, because TX_WR doesn't seem to get updated + * correctly in those scenarios + * @param ptr value to use in place of TX_WR. If 0, then the value is read + * in from TX_WR + * @return New value for ptr, to be used in the next call + */ +// FIXME Update documentation + void send_data_processing_offset(SOCKET s, uint16_t data_offset, const uint8_t *data, uint16_t len); + + /** + * @brief This function is being called by recv() also. + * + * This function read the Rx read pointer register + * and after copy the data from receive buffer update the Rx write pointer register. + * User should read upper byte first and lower byte later to get proper value. + */ + void recv_data_processing(SOCKET s, uint8_t *data, uint16_t len, uint8_t peek = 0); + + inline void setGatewayIp(uint8_t *_addr); + inline void getGatewayIp(uint8_t *_addr); + + inline void setSubnetMask(uint8_t *_addr); + inline void getSubnetMask(uint8_t *_addr); + + inline void setMACAddress(uint8_t * addr); + inline void getMACAddress(uint8_t * addr); + + inline void setIPAddress(uint8_t * addr); + inline void getIPAddress(uint8_t * addr); + + inline void setRetransmissionTime(uint16_t timeout); + inline void setRetransmissionCount(uint8_t _retry); + + void execCmdSn(SOCKET s, SockCMD _cmd); + + uint16_t getTXFreeSize(SOCKET s); + uint16_t getRXReceivedSize(SOCKET s); + + + // W5200 Registers + // --------------- +private: + static uint8_t write(uint16_t _addr, uint8_t _data); + static uint16_t write(uint16_t addr, const uint8_t *buf, uint16_t len); + static uint8_t read(uint16_t addr); + static uint16_t read(uint16_t addr, uint8_t *buf, uint16_t len); + +#define __GP_REGISTER8(name, address) \ + static inline void write##name(uint8_t _data) { \ + write(address, _data); \ + } \ + static inline uint8_t read##name() { \ + return read(address); \ + } +#define __GP_REGISTER16(name, address) \ + static void write##name(uint16_t _data) { \ + write(address, _data >> 8); \ + write(address+1, _data & 0xFF); \ + } \ + static uint16_t read##name() { \ + uint16_t res = read(address); \ + res = (res << 8) + read(address + 1); \ + return res; \ + } +#define __GP_REGISTER_N(name, address, size) \ + static uint16_t write##name(uint8_t *_buff) { \ + return write(address, _buff, size); \ + } \ + static uint16_t read##name(uint8_t *_buff) { \ + return read(address, _buff, size); \ + } + +public: + __GP_REGISTER8 (MR, 0x0000); // Mode + __GP_REGISTER_N(GAR, 0x0001, 4); // Gateway IP address + __GP_REGISTER_N(SUBR, 0x0005, 4); // Subnet mask address + __GP_REGISTER_N(SHAR, 0x0009, 6); // Source MAC address + __GP_REGISTER_N(SIPR, 0x000F, 4); // Source IP address + __GP_REGISTER8 (IR, 0x0015); // Interrupt + __GP_REGISTER8 (IMR, 0x0016); // Interrupt Mask + __GP_REGISTER16(RTR, 0x0017); // Timeout address + __GP_REGISTER8 (RCR, 0x0019); // Retry count + __GP_REGISTER8 (RMSR, 0x001A); // Receive memory size + __GP_REGISTER8 (TMSR, 0x001B); // Transmit memory size + __GP_REGISTER8 (PATR, 0x001C); // Authentication type address in PPPoE mode + __GP_REGISTER8 (VERSIONR,0x001f); // Chip version + __GP_REGISTER8 (PTIMER, 0x0028); // PPP LCP Request Timer + __GP_REGISTER8 (PMAGIC, 0x0029); // PPP LCP Magic Number + __GP_REGISTER8 (PHYSTATUS,0x0035); // PHY Status + +#undef __GP_REGISTER8 +#undef __GP_REGISTER16 +#undef __GP_REGISTER_N + + // W5200 Socket registers + // ---------------------- +private: + static inline uint8_t readSn(SOCKET _s, uint16_t _addr); + static inline uint8_t writeSn(SOCKET _s, uint16_t _addr, uint8_t _data); + static inline uint16_t readSn(SOCKET _s, uint16_t _addr, uint8_t *_buf, uint16_t len); + static inline uint16_t writeSn(SOCKET _s, uint16_t _addr, uint8_t *_buf, uint16_t len); + + static const uint16_t CH_BASE = 0x4000; + static const uint16_t CH_SIZE = 0x0100; + +#define __SOCKET_REGISTER8(name, address) \ + static inline void write##name(SOCKET _s, uint8_t _data) { \ + writeSn(_s, address, _data); \ + } \ + static inline uint8_t read##name(SOCKET _s) { \ + return readSn(_s, address); \ + } +#define __SOCKET_REGISTER16(name, address) \ + static void write##name(SOCKET _s, uint16_t _data) { \ + writeSn(_s, address, _data >> 8); \ + writeSn(_s, address+1, _data & 0xFF); \ + } \ + static uint16_t read##name(SOCKET _s) { \ + uint16_t res = readSn(_s, address); \ + res = (res << 8) + readSn(_s, address + 1); \ + return res; \ + } +#define __SOCKET_REGISTER_N(name, address, size) \ + static uint16_t write##name(SOCKET _s, uint8_t *_buff) { \ + return writeSn(_s, address, _buff, size); \ + } \ + static uint16_t read##name(SOCKET _s, uint8_t *_buff) { \ + return readSn(_s, address, _buff, size); \ + } + +public: + __SOCKET_REGISTER8(SnMR, 0x0000) // Mode + __SOCKET_REGISTER8(SnCR, 0x0001) // Command + __SOCKET_REGISTER8(SnIR, 0x0002) // Interrupt + __SOCKET_REGISTER8(SnSR, 0x0003) // Status + __SOCKET_REGISTER16(SnPORT, 0x0004) // Source Port + __SOCKET_REGISTER_N(SnDHAR, 0x0006, 6) // Destination Hardw Addr + __SOCKET_REGISTER_N(SnDIPR, 0x000C, 4) // Destination IP Addr + __SOCKET_REGISTER16(SnDPORT, 0x0010) // Destination Port + __SOCKET_REGISTER16(SnMSSR, 0x0012) // Max Segment Size + __SOCKET_REGISTER8(SnPROTO, 0x0014) // Protocol in IP RAW Mode + __SOCKET_REGISTER8(SnTOS, 0x0015) // IP TOS + __SOCKET_REGISTER8(SnTTL, 0x0016) // IP TTL + __SOCKET_REGISTER16(SnTX_FSR, 0x0020) // TX Free Size + __SOCKET_REGISTER16(SnTX_RD, 0x0022) // TX Read Pointer + __SOCKET_REGISTER16(SnTX_WR, 0x0024) // TX Write Pointer + __SOCKET_REGISTER16(SnRX_RSR, 0x0026) // RX Free Size + __SOCKET_REGISTER16(SnRX_RD, 0x0028) // RX Read Pointer + __SOCKET_REGISTER16(SnRX_WR, 0x002A) // RX Write Pointer (supported?) + +#undef __SOCKET_REGISTER8 +#undef __SOCKET_REGISTER16 +#undef __SOCKET_REGISTER_N + +private: + static const uint8_t RST = 7; // Reset BIT + static const int SOCKETS = 8; + + static const uint16_t SMASK = 0x07FF; // Tx buffer MASK + static const uint16_t RMASK = 0x07FF; // Rx buffer MASK +public: + static const uint16_t SSIZE = 2048; // Max Tx buffer size +private: + static const uint16_t RSIZE = 2048; // Max Rx buffer size + uint16_t SBASE[SOCKETS]; // Tx buffer base address + uint16_t RBASE[SOCKETS]; // Rx buffer base address +}; + +extern W5200Class W5200; + +uint8_t W5200Class::readSn(SOCKET _s, uint16_t _addr) { + return read(CH_BASE + _s * CH_SIZE + _addr); +} + +uint8_t W5200Class::writeSn(SOCKET _s, uint16_t _addr, uint8_t _data) { + return write(CH_BASE + _s * CH_SIZE + _addr, _data); +} + +uint16_t W5200Class::readSn(SOCKET _s, uint16_t _addr, uint8_t *_buf, uint16_t _len) { + return read(CH_BASE + _s * CH_SIZE + _addr, _buf, _len); +} + +uint16_t W5200Class::writeSn(SOCKET _s, uint16_t _addr, uint8_t *_buf, uint16_t _len) { + return write(CH_BASE + _s * CH_SIZE + _addr, _buf, _len); +} + +void W5200Class::getGatewayIp(uint8_t *_addr) { + readGAR(_addr); +} + +void W5200Class::setGatewayIp(uint8_t *_addr) { + writeGAR(_addr); +} + +void W5200Class::getSubnetMask(uint8_t *_addr) { + readSUBR(_addr); +} + +void W5200Class::setSubnetMask(uint8_t *_addr) { + writeSUBR(_addr); +} + +void W5200Class::getMACAddress(uint8_t *_addr) { + readSHAR(_addr); +} + +void W5200Class::setMACAddress(uint8_t *_addr) { + writeSHAR(_addr); +} + +void W5200Class::getIPAddress(uint8_t *_addr) { + readSIPR(_addr); +} + +void W5200Class::setIPAddress(uint8_t *_addr) { + writeSIPR(_addr); +} + +void W5200Class::setRetransmissionTime(uint16_t _timeout) { + writeRTR(_timeout); +} + +void W5200Class::setRetransmissionCount(uint8_t _retry) { + writeRCR(_retry); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/w5200debug.cpp Sun Mar 24 11:25:31 2013 +0000 @@ -0,0 +1,44 @@ +// w5200debug.cpp 2013/3/24 +#include "mbed.h" +#include <ctype.h> + +void print_bytes(FILE* stream, char* s, uint8_t* buf, int len) +{ + fprintf(stream, "%s %d:", s, len); + for(int i = 0; i < len; i++) { + fprintf(stream, " %02X", buf[i]); + } + fprintf(stream, "\n"); +} + +void print_str(FILE* stream, uint8_t* buf, int len) +{ + fprintf(stream, "%p %d:", buf, len); + for(int i = 0; i < len; i++) { + fprintf(stream, " %02X", buf[i]); + } + fprintf(stream, " : "); + for(int i = 0; i < len; i++) { + char c = buf[i]; + if (!isprint(c)) { + c = '.'; + } + fprintf(stream, "%c", c); + } + fprintf(stream, "\n"); +} + +void print_hex(FILE* stream, uint8_t* p, int len) +{ + for(int i = 0; i < len; i++) { + if (i%16 == 0) { + fprintf(stream, "%p:", p); + } + fprintf(stream, " %02X", *p); + p++; + if (i%16 == 15) { + fprintf(stream, "\n"); + } + } + fprintf(stream, "\n"); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/w5200debug.h Sun Mar 24 11:25:31 2013 +0000 @@ -0,0 +1,25 @@ +// w5200debug.h 2013/3/24 +#pragma once + +#ifdef DEBUG +#define DBG(...) do{fprintf(stderr,"[%s@%d] ",__PRETTY_FUNCTION__,__LINE__);fprintf(stderr,__VA_ARGS__);} while(0); +#define DBG_BYTES(A,B,C) do{fprintf(stderr,"[%s@%d] ",__PRETTY_FUNCTION__,__LINE__);print_bytes(stderr,A,B,C);}while(0); +#define DBG_STR(A,B) do{fprintf(stderr,"[%s@%d]\n",__PRETTY_FUNCTION__,__LINE__);print_str(stderr,A,B);}while(0); +#define DBG_HEX(A,B) do{fprintf(stderr,"[%s@%d]\n",__PRETTY_FUNCTION__,__LINE__);print_hex(stderr,A,B);}while(0); +#else +#define DBG_BYTES(A,B,C) while(0); +#define DBG_STR(A,B) while(0); +#define DBG_HEX(A,B) while(0); +#define DBG(...) while(0); +#endif + +#define DEBUG2 +#ifdef DEBUG2 +#define DBG2(...) do{fprintf(stderr,"[%s@%d] ",__PRETTY_FUNCTION__,__LINE__);fprintf(stderr,__VA_ARGS__);} while(0); +#else +#define DBG2(...) while(0); +#endif + +void print_bytes(FILE* stream, char* s, uint8_t* buf, int len); +void print_str(FILE* stream, uint8_t* p, int len); +void print_hex(FILE* stream, uint8_t* p, int len);