From a42dc0b455513b9cf3127b9720cc66d0db274b03 Mon Sep 17 00:00:00 2001 From: amcewen Date: Sun, 16 Jan 2011 20:11:50 +0000 Subject: [PATCH] Fix for issue 62, adding DHCP support. New begin() method added to EthernetClass which takes just a MAC address and gets the rest of its configuration information via DHCP. Examples updated to use the IPAddress class and some have been changed to get their config via DHCP. --- libraries/Ethernet/Client.cpp | 4 +- libraries/Ethernet/Client.h | 6 +- libraries/Ethernet/Dhcp.cpp | 341 ++++++++++++++++++ libraries/Ethernet/Dhcp.h | 158 ++++++++ libraries/Ethernet/Ethernet.cpp | 77 +++- libraries/Ethernet/Ethernet.h | 18 +- libraries/Ethernet/IPAddress.cpp | 5 + libraries/Ethernet/IPAddress.h | 15 +- libraries/Ethernet/Udp.cpp | 2 +- .../BarometricPressureWebServer.pde | 9 +- .../examples/ChatServer/ChatServer.pde | 8 +- .../examples/PachubeClient/PachubeClient.pde | 21 +- .../PachubeClientString.pde | 12 +- .../examples/TelnetClient/TelnetClient.pde | 6 +- .../examples/UdpNtpClient/UdpNtpClient.pde | 21 +- .../Ethernet/examples/WebClient/WebClient.pde | 16 +- .../Ethernet/examples/WebServer/WebServer.pde | 4 +- libraries/Ethernet/util.h | 13 + 18 files changed, 662 insertions(+), 74 deletions(-) create mode 100755 libraries/Ethernet/Dhcp.cpp create mode 100755 libraries/Ethernet/Dhcp.h create mode 100644 libraries/Ethernet/util.h diff --git a/libraries/Ethernet/Client.cpp b/libraries/Ethernet/Client.cpp index 96d5c7eed..7ae55d08d 100644 --- a/libraries/Ethernet/Client.cpp +++ b/libraries/Ethernet/Client.cpp @@ -16,7 +16,7 @@ uint16_t Client::_srcport = 1024; Client::Client(uint8_t sock) : _sock(sock) { } -Client::Client(uint8_t *ip, uint16_t port) : _ip(ip), _port(port), _sock(MAX_SOCK_NUM) { +Client::Client(IPAddress& ip, uint16_t port) : _ip(ip), _port(port), _sock(MAX_SOCK_NUM) { } uint8_t Client::connect() { @@ -38,7 +38,7 @@ uint8_t Client::connect() { if (_srcport == 0) _srcport = 1024; socket(_sock, SnMR::TCP, _srcport, 0); - if (!::connect(_sock, _ip, _port)) { + if (!::connect(_sock, _ip.raw_address(), _port)) { _sock = MAX_SOCK_NUM; return 0; } diff --git a/libraries/Ethernet/Client.h b/libraries/Ethernet/Client.h index 8725f158a..e92e90e33 100644 --- a/libraries/Ethernet/Client.h +++ b/libraries/Ethernet/Client.h @@ -7,8 +7,8 @@ class Client : public Stream { public: Client(); - Client(uint8_t); - Client(uint8_t *, uint16_t); + Client(uint8_t sock); + Client(IPAddress& ip, uint16_t port); uint8_t status(); uint8_t connect(); @@ -31,7 +31,7 @@ public: private: static uint16_t _srcport; uint8_t _sock; - uint8_t *_ip; + IPAddress _ip; uint16_t _port; }; diff --git a/libraries/Ethernet/Dhcp.cpp b/libraries/Ethernet/Dhcp.cpp new file mode 100755 index 000000000..8264b435b --- /dev/null +++ b/libraries/Ethernet/Dhcp.cpp @@ -0,0 +1,341 @@ +// DHCP Library v0.3 - April 25, 2009 +// Author: Jordan Terrell - blog.jordanterrell.com + +#include "w5100.h" + +#include +#include +#include "Dhcp.h" +#include "wiring.h" +#include "util.h" + +int DhcpClass::beginWithDHCP(uint8_t *mac, unsigned long timeout, unsigned long responseTimeout) +{ + uint8_t dhcp_state = STATE_DHCP_START; + uint8_t messageType = 0; + + // zero out _dhcpMacAddr, _dhcpSubnetMask, _dhcpGatewayIp, _dhcpLocalIp, _dhcpDhcpServerIp, _dhcpDnsServerIp + memset(_dhcpMacAddr, 0, 26); + + memcpy((void*)_dhcpMacAddr, (void*)mac, 6); + + // Pick an initial transaction ID + _dhcpTransactionId = random(1UL, 2000UL); + _dhcpInitialTransactionId = _dhcpTransactionId; + + if (_dhcpUdpSocket.begin(DHCP_CLIENT_PORT) == 0) + { + // Couldn't get a socket + return 0; + } + + presend_DHCP(); + + int result = 0; + + unsigned long startTime = millis(); + + while(dhcp_state != STATE_DHCP_LEASED) + { + if(dhcp_state == STATE_DHCP_START) + { + _dhcpTransactionId++; + + send_DHCP_MESSAGE(DHCP_DISCOVER, ((millis() - startTime) / 1000)); + dhcp_state = STATE_DHCP_DISCOVER; + } + else if(dhcp_state == STATE_DHCP_DISCOVER) + { + uint32_t respId; + messageType = parseDHCPResponse(responseTimeout, respId); + if(messageType == DHCP_OFFER) + { + // We'll use the transaction ID that the offer came with, + // rather than the one we were up to + _dhcpTransactionId = respId; + send_DHCP_MESSAGE(DHCP_REQUEST, ((millis() - startTime) / 1000)); + dhcp_state = STATE_DHCP_REQUEST; + } + } + else if(dhcp_state == STATE_DHCP_REQUEST) + { + uint32_t respId; + messageType = parseDHCPResponse(responseTimeout, respId); + if(messageType == DHCP_ACK) + { + dhcp_state = STATE_DHCP_LEASED; + result = 1; + } + else if(messageType == DHCP_NAK) + dhcp_state = STATE_DHCP_START; + } + + if(messageType == 255) + { + messageType = 0; + dhcp_state = STATE_DHCP_START; + } + + if(result != 1 && ((millis() - startTime) > timeout)) + break; + } + + // We're done with the socket now + _dhcpUdpSocket.stop(); + _dhcpTransactionId++; + + return result; +} + +void DhcpClass::presend_DHCP() +{ +} + +void DhcpClass::send_DHCP_MESSAGE(uint8_t messageType, uint16_t secondsElapsed) +{ + uint8_t buffer[32]; + memset(buffer, 0, 32); + IPAddress dest_addr( 255, 255, 255, 255 ); // Broadcast address + + if (-1 == _dhcpUdpSocket.beginPacket(dest_addr, DHCP_SERVER_PORT)) + { + // FIXME Need to return errors + return; + } + + buffer[0] = DHCP_BOOTREQUEST; // op + buffer[1] = DHCP_HTYPE10MB; // htype + buffer[2] = DHCP_HLENETHERNET; // hlen + buffer[3] = DHCP_HOPS; // hops + + // xid + unsigned long xid = htonl(_dhcpTransactionId); + memcpy(buffer + 4, &(xid), 4); + + // 8, 9 - seconds elapsed + buffer[8] = ((secondsElapsed & 0xff00) >> 8); + buffer[9] = (secondsElapsed & 0x00ff); + + // flags + unsigned short flags = htons(DHCP_FLAGSBROADCAST); + memcpy(buffer + 10, &(flags), 2); + + // ciaddr: already zeroed + // yiaddr: already zeroed + // siaddr: already zeroed + // giaddr: already zeroed + + //put data in W5100 transmit buffer + _dhcpUdpSocket.write(buffer, 28); + + memset(buffer, 0, 32); // clear local buffer + + memcpy(buffer, _dhcpMacAddr, 6); // chaddr + + //put data in W5100 transmit buffer + _dhcpUdpSocket.write(buffer, 16); + + memset(buffer, 0, 32); // clear local buffer + + // leave zeroed out for sname && file + // put in W5100 transmit buffer x 6 (192 bytes) + + for(int i = 0; i < 6; i++) { + _dhcpUdpSocket.write(buffer, 32); + } + + // OPT - Magic Cookie + buffer[0] = (uint8_t)((MAGIC_COOKIE >> 24)& 0xFF); + buffer[1] = (uint8_t)((MAGIC_COOKIE >> 16)& 0xFF); + buffer[2] = (uint8_t)((MAGIC_COOKIE >> 8)& 0xFF); + buffer[3] = (uint8_t)(MAGIC_COOKIE& 0xFF); + + // OPT - message type + buffer[4] = dhcpMessageType; + buffer[5] = 0x01; + buffer[6] = messageType; //DHCP_REQUEST; + + // OPT - client identifier + buffer[7] = dhcpClientIdentifier; + buffer[8] = 0x07; + buffer[9] = 0x01; + memcpy(buffer + 10, _dhcpMacAddr, 6); + + // OPT - host name + buffer[16] = hostName; + buffer[17] = strlen(HOST_NAME) + 3; // length of hostname + last 3 bytes of mac address + strcpy((char*)&(buffer[18]), HOST_NAME); + + buffer[24] = _dhcpMacAddr[3]; + buffer[25] = _dhcpMacAddr[4]; + buffer[26] = _dhcpMacAddr[5]; + + //put data in W5100 transmit buffer + _dhcpUdpSocket.write(buffer, 27); + + if(messageType == DHCP_REQUEST) + { + buffer[0] = dhcpRequestedIPaddr; + buffer[1] = 0x04; + buffer[2] = _dhcpLocalIp[0]; + buffer[3] = _dhcpLocalIp[1]; + buffer[4] = _dhcpLocalIp[2]; + buffer[5] = _dhcpLocalIp[3]; + + buffer[6] = dhcpServerIdentifier; + buffer[7] = 0x04; + buffer[8] = _dhcpDhcpServerIp[0]; + buffer[9] = _dhcpDhcpServerIp[1]; + buffer[10] = _dhcpDhcpServerIp[2]; + buffer[11] = _dhcpDhcpServerIp[3]; + + //put data in W5100 transmit buffer + _dhcpUdpSocket.write(buffer, 12); + } + + buffer[0] = dhcpParamRequest; + buffer[1] = 0x06; + buffer[2] = subnetMask; + buffer[3] = routersOnSubnet; + buffer[4] = dns; + buffer[5] = domainName; + buffer[6] = dhcpT1value; + buffer[7] = dhcpT2value; + buffer[8] = endOption; + + //put data in W5100 transmit buffer + _dhcpUdpSocket.write(buffer, 9); + + _dhcpUdpSocket.endPacket(); +} + +uint8_t DhcpClass::parseDHCPResponse(unsigned long responseTimeout, uint32_t& transactionId) +{ + uint8_t type = 0; + uint8_t opt_len = 0; + + unsigned long startTime = millis(); + + while(_dhcpUdpSocket.parsePacket() <= 0) + { + if((millis() - startTime) > responseTimeout) + { + return 255; + } + delay(50); + } + // start reading in the packet + RIP_MSG_FIXED fixedMsg; + _dhcpUdpSocket.read((uint8_t*)&fixedMsg, sizeof(RIP_MSG_FIXED)); + + if(fixedMsg.op == DHCP_BOOTREPLY && _dhcpUdpSocket.remotePort() == DHCP_SERVER_PORT) + { + transactionId = ntohl(fixedMsg.xid); + if(memcmp(fixedMsg.chaddr, _dhcpMacAddr, 6) != 0 || (transactionId < _dhcpInitialTransactionId) || (transactionId > _dhcpTransactionId)) + { + // Need to read the rest of the packet here regardless + _dhcpUdpSocket.flush(); + return 0; + } + + memcpy(_dhcpLocalIp, fixedMsg.yiaddr, 4); + + // Skip to the option part + // Doing this a byte at a time so we don't have to put a big buffer + // on the stack (as we don't have lots of memory lying around) + for (int i =0; i < (240 - sizeof(RIP_MSG_FIXED)); i++) + { + _dhcpUdpSocket.read(); // we don't care about the returned byte + } + + while (_dhcpUdpSocket.available() > 0) + { + switch (_dhcpUdpSocket.read()) + { + case endOption : + break; + + case padOption : + break; + + case dhcpMessageType : + opt_len = _dhcpUdpSocket.read(); + type = _dhcpUdpSocket.read(); + break; + + case subnetMask : + opt_len = _dhcpUdpSocket.read(); + _dhcpUdpSocket.read(_dhcpSubnetMask, 4); + break; + + case routersOnSubnet : + opt_len = _dhcpUdpSocket.read(); + _dhcpUdpSocket.read(_dhcpGatewayIp, 4); + break; + + case dns : + opt_len = _dhcpUdpSocket.read(); + _dhcpUdpSocket.read(_dhcpDnsServerIp, 4); + break; + + case dhcpServerIdentifier : + opt_len = _dhcpUdpSocket.read(); + if( *((uint32_t*)_dhcpDhcpServerIp) == 0 || + IPAddress(_dhcpDhcpServerIp) == _dhcpUdpSocket.remoteIP() ) + { + _dhcpUdpSocket.read(_dhcpDhcpServerIp, sizeof(_dhcpDhcpServerIp)); + } + else + { + // Skip over the rest of this option + while (opt_len--) + { + _dhcpUdpSocket.read(); + } + } + break; + + case dhcpIPaddrLeaseTime : + default : + opt_len = _dhcpUdpSocket.read(); + // Skip over the rest of this option + while (opt_len--) + { + _dhcpUdpSocket.read(); + } + break; + } + } + } + + // Need to skip to end of the packet regardless here + _dhcpUdpSocket.flush(); + + return type; +} + +IPAddress DhcpClass::getLocalIp() +{ + return IPAddress(_dhcpLocalIp); +} + +IPAddress DhcpClass::getSubnetMask() +{ + return IPAddress(_dhcpSubnetMask); +} + +IPAddress DhcpClass::getGatewayIp() +{ + return IPAddress(_dhcpGatewayIp); +} + +IPAddress DhcpClass::getDhcpServerIp() +{ + return IPAddress(_dhcpDhcpServerIp); +} + +IPAddress DhcpClass::getDnsServerIp() +{ + return IPAddress(_dhcpDnsServerIp); +} + diff --git a/libraries/Ethernet/Dhcp.h b/libraries/Ethernet/Dhcp.h new file mode 100755 index 000000000..c0034940c --- /dev/null +++ b/libraries/Ethernet/Dhcp.h @@ -0,0 +1,158 @@ +// DHCP Library v0.3 - April 25, 2009 +// Author: Jordan Terrell - blog.jordanterrell.com + +#ifndef Dhcp_h +#define Dhcp_h + +#include "Udp.h" + +/* DHCP state machine. */ +#define STATE_DHCP_START 0 +#define STATE_DHCP_DISCOVER 1 +#define STATE_DHCP_REQUEST 2 +#define STATE_DHCP_LEASED 3 +#define STATE_DHCP_REREQUEST 4 +#define STATE_DHCP_RELEASE 5 + +#define DHCP_FLAGSBROADCAST 0x8000 + +/* UDP port numbers for DHCP */ +#define DHCP_SERVER_PORT 67 /* from server to client */ +#define DHCP_CLIENT_PORT 68 /* from client to server */ + +/* DHCP message OP code */ +#define DHCP_BOOTREQUEST 1 +#define DHCP_BOOTREPLY 2 + +/* DHCP message type */ +#define DHCP_DISCOVER 1 +#define DHCP_OFFER 2 +#define DHCP_REQUEST 3 +#define DHCP_DECLINE 4 +#define DHCP_ACK 5 +#define DHCP_NAK 6 +#define DHCP_RELEASE 7 +#define DHCP_INFORM 8 + +#define DHCP_HTYPE10MB 1 +#define DHCP_HTYPE100MB 2 + +#define DHCP_HLENETHERNET 6 +#define DHCP_HOPS 0 +#define DHCP_SECS 0 + +#define MAGIC_COOKIE 0x63825363 +#define MAX_DHCP_OPT 16 + +#define HOST_NAME "WIZnet" + +enum +{ + padOption = 0, + subnetMask = 1, + timerOffset = 2, + routersOnSubnet = 3, + /* timeServer = 4, + nameServer = 5,*/ + dns = 6, + /*logServer = 7, + cookieServer = 8, + lprServer = 9, + impressServer = 10, + resourceLocationServer = 11,*/ + hostName = 12, + /*bootFileSize = 13, + meritDumpFile = 14,*/ + domainName = 15, + /*swapServer = 16, + rootPath = 17, + extentionsPath = 18, + IPforwarding = 19, + nonLocalSourceRouting = 20, + policyFilter = 21, + maxDgramReasmSize = 22, + defaultIPTTL = 23, + pathMTUagingTimeout = 24, + pathMTUplateauTable = 25, + ifMTU = 26, + allSubnetsLocal = 27, + broadcastAddr = 28, + performMaskDiscovery = 29, + maskSupplier = 30, + performRouterDiscovery = 31, + routerSolicitationAddr = 32, + staticRoute = 33, + trailerEncapsulation = 34, + arpCacheTimeout = 35, + ethernetEncapsulation = 36, + tcpDefaultTTL = 37, + tcpKeepaliveInterval = 38, + tcpKeepaliveGarbage = 39, + nisDomainName = 40, + nisServers = 41, + ntpServers = 42, + vendorSpecificInfo = 43, + netBIOSnameServer = 44, + netBIOSdgramDistServer = 45, + netBIOSnodeType = 46, + netBIOSscope = 47, + xFontServer = 48, + xDisplayManager = 49,*/ + dhcpRequestedIPaddr = 50, + dhcpIPaddrLeaseTime = 51, + /*dhcpOptionOverload = 52,*/ + dhcpMessageType = 53, + dhcpServerIdentifier = 54, + dhcpParamRequest = 55, + /*dhcpMsg = 56, + dhcpMaxMsgSize = 57,*/ + dhcpT1value = 58, + dhcpT2value = 59, + /*dhcpClassIdentifier = 60,*/ + dhcpClientIdentifier = 61, + endOption = 255 +}; + +typedef struct _RIP_MSG_FIXED +{ + uint8_t op; + uint8_t htype; + uint8_t hlen; + uint8_t hops; + uint32_t xid; + uint16_t secs; + uint16_t flags; + uint8_t ciaddr[4]; + uint8_t yiaddr[4]; + uint8_t siaddr[4]; + uint8_t giaddr[4]; + uint8_t chaddr[6]; +}RIP_MSG_FIXED; + +class DhcpClass { +private: + uint32_t _dhcpInitialTransactionId; + uint32_t _dhcpTransactionId; + uint8_t _dhcpMacAddr[6]; + uint8_t _dhcpLocalIp[4]; + uint8_t _dhcpSubnetMask[4]; + uint8_t _dhcpGatewayIp[4]; + uint8_t _dhcpDhcpServerIp[4]; + uint8_t _dhcpDnsServerIp[4]; + UDP _dhcpUdpSocket; + + void presend_DHCP(); + void send_DHCP_MESSAGE(uint8_t, uint16_t); + + uint8_t parseDHCPResponse(unsigned long responseTimeout, uint32_t& transactionId); +public: + IPAddress getLocalIp(); + IPAddress getSubnetMask(); + IPAddress getGatewayIp(); + IPAddress getDhcpServerIp(); + IPAddress getDnsServerIp(); + + int beginWithDHCP(uint8_t *, unsigned long timeout = 60000, unsigned long responseTimeout = 4000); +}; + +#endif diff --git a/libraries/Ethernet/Ethernet.cpp b/libraries/Ethernet/Ethernet.cpp index 91cbacd39..937f5b4f9 100644 --- a/libraries/Ethernet/Ethernet.cpp +++ b/libraries/Ethernet/Ethernet.cpp @@ -1,5 +1,6 @@ #include "w5100.h" #include "Ethernet.h" +#include "Dhcp.h" // XXX: don't make assumptions about the value of MAX_SOCK_NUM. uint8_t EthernetClass::_state[MAX_SOCK_NUM] = { @@ -7,30 +8,78 @@ uint8_t EthernetClass::_state[MAX_SOCK_NUM] = { uint16_t EthernetClass::_server_port[MAX_SOCK_NUM] = { 0, 0, 0, 0 }; -void EthernetClass::begin(uint8_t *mac, uint8_t *ip) +int EthernetClass::begin(uint8_t *mac_address) { - uint8_t gateway[4]; - gateway[0] = ip[0]; - gateway[1] = ip[1]; - gateway[2] = ip[2]; + DhcpClass dhcp; + + // Initialise the basic info + W5100.init(); + W5100.setMACAddress(mac_address); + W5100.setIPAddress(IPAddress(0,0,0,0).raw_address()); + + // Now try to get our config info from a DHCP server + int ret = dhcp.beginWithDHCP(mac_address); + if(ret == 1) + { + // We've successfully found a DHCP server and got our configuration info, so set things + // accordingly + W5100.setIPAddress(dhcp.getLocalIp().raw_address()); + W5100.setGatewayIp(dhcp.getGatewayIp().raw_address()); + W5100.setSubnetMask(dhcp.getSubnetMask().raw_address()); + _dnsServerAddress = dhcp.getDnsServerIp(); + } + + return ret; +} + +void EthernetClass::begin(uint8_t *mac_address, IPAddress local_ip) +{ + // Assume the gateway will be the machine on the same network as the local IP + // but with last octet being '1' + IPAddress gateway = local_ip; gateway[3] = 1; - begin(mac, ip, gateway); + begin(mac_address, local_ip, gateway); } -void EthernetClass::begin(uint8_t *mac, uint8_t *ip, uint8_t *gateway) +void EthernetClass::begin(uint8_t *mac_address, IPAddress local_ip, IPAddress gateway) { - uint8_t subnet[] = { - 255, 255, 255, 0 }; - begin(mac, ip, gateway, subnet); + IPAddress subnet(255, 255, 255, 0); + begin(mac_address, local_ip, gateway, subnet); } -void EthernetClass::begin(uint8_t *mac, uint8_t *ip, uint8_t *gateway, uint8_t *subnet) +void EthernetClass::begin(uint8_t *mac, IPAddress local_ip, IPAddress gateway, IPAddress subnet) { W5100.init(); W5100.setMACAddress(mac); - W5100.setIPAddress(ip); - W5100.setGatewayIp(gateway); - W5100.setSubnetMask(subnet); + W5100.setIPAddress(local_ip._address); + W5100.setGatewayIp(gateway._address); + W5100.setSubnetMask(subnet._address); +} + +IPAddress EthernetClass::localIP() +{ + IPAddress ret; + W5100.getIPAddress(ret.raw_address()); + return ret; +} + +IPAddress EthernetClass::subnetMask() +{ + IPAddress ret; + W5100.getSubnetMask(ret.raw_address()); + return ret; +} + +IPAddress EthernetClass::gatewayIP() +{ + IPAddress ret; + W5100.getGatewayIp(ret.raw_address()); + return ret; +} + +IPAddress EthernetClass::dnsServerIP() +{ + return _dnsServerAddress; } EthernetClass Ethernet; diff --git a/libraries/Ethernet/Ethernet.h b/libraries/Ethernet/Ethernet.h index a91f1aa17..fdf0b7f39 100644 --- a/libraries/Ethernet/Ethernet.h +++ b/libraries/Ethernet/Ethernet.h @@ -3,6 +3,7 @@ #include //#include "w5100.h" +#include "IPAddress.h" #include "Client.h" #include "Server.h" @@ -10,12 +11,23 @@ class EthernetClass { private: + IPAddress _dnsServerAddress; public: static uint8_t _state[MAX_SOCK_NUM]; static uint16_t _server_port[MAX_SOCK_NUM]; - void begin(uint8_t *, uint8_t *); - void begin(uint8_t *, uint8_t *, uint8_t *); - void begin(uint8_t *, uint8_t *, uint8_t *, uint8_t *); + // Initialise the Ethernet shield to use the provided MAC address and gain the rest of the + // configuration through DHCP. + // Returns 0 if the DHCP configuration failed, and 1 if it succeeded + int begin(uint8_t *mac_address); + void begin(uint8_t *mac_address, IPAddress local_ip); + void begin(uint8_t *mac_address, IPAddress local_ip, IPAddress gateway); + void begin(uint8_t *mac_address, IPAddress local_ip, IPAddress gateway, IPAddress subnet); + + IPAddress localIP(); + IPAddress subnetMask(); + IPAddress gatewayIP(); + IPAddress dnsServerIP(); + friend class Client; friend class Server; }; diff --git a/libraries/Ethernet/IPAddress.cpp b/libraries/Ethernet/IPAddress.cpp index 389329de0..408d518a0 100644 --- a/libraries/Ethernet/IPAddress.cpp +++ b/libraries/Ethernet/IPAddress.cpp @@ -37,3 +37,8 @@ IPAddress& IPAddress::operator=(uint32_t address) return *this; } +bool IPAddress::operator==(const uint8_t* addr) +{ + return memcmp(addr, _address, sizeof(_address)) == 0; +} + diff --git a/libraries/Ethernet/IPAddress.h b/libraries/Ethernet/IPAddress.h index 586385320..1d19bbd22 100644 --- a/libraries/Ethernet/IPAddress.h +++ b/libraries/Ethernet/IPAddress.h @@ -31,6 +31,11 @@ class IPAddress { private: uint8_t _address[4]; // IPv4 address + // Access the raw byte array containing the address. Because this returns a pointer + // to the internal structure rather than a copy of the address this function should only + // be used when you know that the usage of the returned uint8_t* will be transient and not + // stored. + uint8_t* raw_address() { return _address; }; public: // Constructors @@ -41,7 +46,9 @@ public: // Overloaded cast operator to allow IPAddress objects to be used where a pointer // to a four-byte uint8_t array is expected - operator uint8_t*() { return _address; }; + operator uint32_t() { return *((uint32_t*)_address); }; + bool operator==(const IPAddress& addr) { return (*((uint32_t*)_address)) == (*((uint32_t*)addr._address)); }; + bool operator==(const uint8_t* addr); // Overloaded index operator to allow getting and setting individual octets of the address uint8_t operator[](int index) const { return _address[index]; }; @@ -50,6 +57,12 @@ public: // Overloaded copy operators to allow initialisation of IPAddress objects from other types IPAddress& operator=(const uint8_t *address); IPAddress& operator=(uint32_t address); + + friend class EthernetClass; + friend class UDP; + friend class Client; + friend class Server; + friend class DhcpClass; }; #endif diff --git a/libraries/Ethernet/Udp.cpp b/libraries/Ethernet/Udp.cpp index 6ad8aca7e..a8c98c3f4 100644 --- a/libraries/Ethernet/Udp.cpp +++ b/libraries/Ethernet/Udp.cpp @@ -77,7 +77,7 @@ void UDP::stop() int UDP::beginPacket(IPAddress ip, uint16_t port) { _offset = 0; - return startUDP(_sock, ip, port); + return startUDP(_sock, ip.raw_address(), port); } int UDP::endPacket() diff --git a/libraries/Ethernet/examples/BarometricPressureWebServer/BarometricPressureWebServer.pde b/libraries/Ethernet/examples/BarometricPressureWebServer/BarometricPressureWebServer.pde index a58433fed..3f43d96db 100644 --- a/libraries/Ethernet/examples/BarometricPressureWebServer/BarometricPressureWebServer.pde +++ b/libraries/Ethernet/examples/BarometricPressureWebServer/BarometricPressureWebServer.pde @@ -31,12 +31,9 @@ byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED}; // assign an IP address for the controller: -byte ip[] = { - 192,168,1,20 }; -byte gateway[] = { - 192,168,1,1}; -byte subnet[] = { - 255, 255, 255, 0 }; +IPAddress ip(192,168,1,20); +IPAddress gateway(192,168,1,1); +IPAddress subnet(255, 255, 255, 0); // Initialize the Ethernet server library diff --git a/libraries/Ethernet/examples/ChatServer/ChatServer.pde b/libraries/Ethernet/examples/ChatServer/ChatServer.pde index 50ae01408..8267a5dd4 100644 --- a/libraries/Ethernet/examples/ChatServer/ChatServer.pde +++ b/libraries/Ethernet/examples/ChatServer/ChatServer.pde @@ -24,9 +24,9 @@ // The IP address will be dependent on your local network. // gateway and subnet are optional: byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; -byte ip[] = { 192,168,1, 177 }; -byte gateway[] = { 192,168,1, 1 }; -byte subnet[] = { 255, 255, 0, 0 }; +IPAddress ip(192,168,1, 177); +IPAddress gateway(192,168,1, 1); +IPAddress subnet(255, 255, 0, 0); // telnet defaults to port 23 Server server(23); @@ -60,4 +60,4 @@ void loop() { // echo the bytes to the server as well: Serial.print(thisChar); } -} \ No newline at end of file +} diff --git a/libraries/Ethernet/examples/PachubeClient/PachubeClient.pde b/libraries/Ethernet/examples/PachubeClient/PachubeClient.pde index fe94541e1..687fa437e 100644 --- a/libraries/Ethernet/examples/PachubeClient/PachubeClient.pde +++ b/libraries/Ethernet/examples/PachubeClient/PachubeClient.pde @@ -23,20 +23,13 @@ #include // assign a MAC address for the ethernet controller. +// Newer Ethernet shields have a MAC address printed on a sticker on the shield // fill in your address here: byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED}; -// assign an IP address for the controller: -byte ip[] = { - 192,169,1,20 }; -byte gateway[] = { - 192,168,1,1}; -byte subnet[] = { - 255, 255, 255, 0 }; // The address of the server you want to connect to (pachube.com): -byte server[] = { - 209,40,205,190 }; +IPAddress server(209,40,205,190); // initialize the library instance: Client client(server, 80); @@ -46,9 +39,15 @@ boolean lastConnected = false; // state of the connection last time through const int postingInterval = 10000; //delay between updates to Pachube.com void setup() { - // start the ethernet connection and serial port: - Ethernet.begin(mac, ip); + // start serial port: Serial.begin(9600); + // start the Ethernet connection: + if (Ethernet.begin(mac) == 0) { + Serial.println("Failed to configure Ethernet using DHCP"); + // no point in carrying on, so do nothing forevermore: + for(;;) + ; + } // give the ethernet module time to boot up: delay(1000); } diff --git a/libraries/Ethernet/examples/PachubeClientString/PachubeClientString.pde b/libraries/Ethernet/examples/PachubeClientString/PachubeClientString.pde index 225823ac1..0db6e219a 100644 --- a/libraries/Ethernet/examples/PachubeClientString/PachubeClientString.pde +++ b/libraries/Ethernet/examples/PachubeClientString/PachubeClientString.pde @@ -29,16 +29,12 @@ byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED}; // assign an IP address for the controller: -byte ip[] = { - 192,169,1,20 }; -byte gateway[] = { - 192,168,1,1}; -byte subnet[] = { - 255, 255, 255, 0 }; +IPAddress ip(192,169,1,20); +IPAddress gateway(192,168,1,1); +IPAddress subnet(255, 255, 255, 0); // The address of the server you want to connect to (pachube.com): -byte server[] = { - 209,40,205,190 }; +IPAddress server(209,40,205,190); // initialize the library instance: Client client(server, 80); diff --git a/libraries/Ethernet/examples/TelnetClient/TelnetClient.pde b/libraries/Ethernet/examples/TelnetClient/TelnetClient.pde index aca1fa9ad..95756d076 100644 --- a/libraries/Ethernet/examples/TelnetClient/TelnetClient.pde +++ b/libraries/Ethernet/examples/TelnetClient/TelnetClient.pde @@ -24,12 +24,10 @@ // The IP address will be dependent on your local network: byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; -byte ip[] = { - 192,168,1,177 }; +IPAddress ip(192,168,1,177); // Enter the IP address of the server you're connecting to: -byte server[] = { - 1,1,1,1 }; +IPAddress server(1,1,1,1); // Initialize the Ethernet client library // with the IP address and port of the server diff --git a/libraries/Ethernet/examples/UdpNtpClient/UdpNtpClient.pde b/libraries/Ethernet/examples/UdpNtpClient/UdpNtpClient.pde index cfb5a2bc1..7c2d3ea9e 100644 --- a/libraries/Ethernet/examples/UdpNtpClient/UdpNtpClient.pde +++ b/libraries/Ethernet/examples/UdpNtpClient/UdpNtpClient.pde @@ -20,13 +20,11 @@ #include #include -// Enter a MAC address and IP address for your controller below. -// The IP address will be dependent on your local network: +// Enter a MAC address for your controller below. +// Newer Ethernet shields have a MAC address printed on a sticker on the shield byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; -IPAddress ip(192, 168, 1, 177); - unsigned int localPort = 8888; // local port to listen for UDP packets IPAddress timeServer(192, 43, 244, 18); // time.nist.gov NTP server @@ -40,11 +38,16 @@ UDP Udp; void setup() { - // start Ethernet and UDP - Ethernet.begin(mac,ip); - Udp.begin(localPort); - Serial.begin(9600); + + // start Ethernet and UDP + if (Ethernet.begin(mac) == 0) { + Serial.println("Failed to configure Ethernet using DHCP"); + // no point in carrying on, so do nothing forevermore: + for(;;) + ; + } + Udp.begin(localPort); } void loop() @@ -99,7 +102,7 @@ void loop() } // send an NTP request to the time server at the given address -unsigned long sendNTPpacket(byte *address) +unsigned long sendNTPpacket(IPAddress& address) { // set all bytes in the buffer to 0 memset(packetBuffer, 0, NTP_PACKET_SIZE); diff --git a/libraries/Ethernet/examples/WebClient/WebClient.pde b/libraries/Ethernet/examples/WebClient/WebClient.pde index a2d350311..74d34e0ce 100644 --- a/libraries/Ethernet/examples/WebClient/WebClient.pde +++ b/libraries/Ethernet/examples/WebClient/WebClient.pde @@ -15,11 +15,10 @@ #include #include -// Enter a MAC address and IP address for your controller below. -// The IP address will be dependent on your local network: +// Enter a MAC address for your controller below. +// Newer Ethernet shields have a MAC address printed on a sticker on the shield byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; -byte ip[] = { 192,168,1,177 }; -byte server[] = { 173,194,33,104 }; // Google +IPAddress server(173,194,33,104); // Google // Initialize the Ethernet client library // with the IP address and port of the server @@ -27,10 +26,15 @@ byte server[] = { 173,194,33,104 }; // Google Client client(server, 80); void setup() { - // start the Ethernet connection: - Ethernet.begin(mac, ip); // start the serial library: Serial.begin(9600); + // start the Ethernet connection: + if (Ethernet.begin(mac) == 0) { + Serial.println("Failed to configure Ethernet using DHCP"); + // no point in carrying on, so do nothing forevermore: + for(;;) + ; + } // give the Ethernet shield a second to initialize: delay(1000); Serial.println("connecting..."); diff --git a/libraries/Ethernet/examples/WebServer/WebServer.pde b/libraries/Ethernet/examples/WebServer/WebServer.pde index 77bcb204e..c69a56a40 100644 --- a/libraries/Ethernet/examples/WebServer/WebServer.pde +++ b/libraries/Ethernet/examples/WebServer/WebServer.pde @@ -21,7 +21,7 @@ // Enter a MAC address and IP address for your controller below. // The IP address will be dependent on your local network: byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; -byte ip[] = { 192,168,1, 177 }; +IPAddress ip(192,168,1, 177); // Initialize the Ethernet server library // with the IP address and port you want to use @@ -79,4 +79,4 @@ void loop() // close the connection: client.stop(); } -} \ No newline at end of file +} diff --git a/libraries/Ethernet/util.h b/libraries/Ethernet/util.h new file mode 100644 index 000000000..220011b8f --- /dev/null +++ b/libraries/Ethernet/util.h @@ -0,0 +1,13 @@ +#ifndef UTIL_H +#define UTIL_H + +#define htons(x) ( (x)<<8 | ((x)>>8)&0xFF ) +#define ntohs(x) htons(x) + +#define htonl(x) ( ((x)<<24 & 0xFF000000UL) | \ + ((x)<< 8 & 0x00FF0000UL) | \ + ((x)>> 8 & 0x0000FF00UL) | \ + ((x)>>24 & 0x000000FFUL) ) +#define ntohl(x) htonl(x) + +#endif