Arduino :
http://www.musically.me.uk/DHCP_Web_Server_12.pde
// DHCP Web Server 12
#include <avr/pgmspace.h>
#include <Ethernet.h>
#include <SPI.h>
#include <Udp.h>
//#define DEBUG
#define zap(x) if(x){free(x); x=0;}
#define refreshTIME 200
#define dhcpSIZE 240
#define bufferSIZE 128
#define serverName "My DHCP Server"
#define myDomainName "MYPLACE"
/* 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
/**
* @brief DHCP option and value (cf. RFC1533)
*/
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
};
// Read Only strings
prog_char line_00[] PROGMEM = "HTTP/1.1 200 OK" ;
prog_char line_01[] PROGMEM = "Content-Type: text/html\n\n" ;
prog_char line_02[] PROGMEM = "<html><head>" ;
prog_char line_03[] PROGMEM = "<script type='text/javascript'>\n" ;
prog_char line_04[] PROGMEM = "var xD;" ;
prog_char line_05[] PROGMEM = "var dB=new Array();\n" ;
prog_char line_06[] PROGMEM = "function fetch(I){" ;
prog_char line_07[] PROGMEM = "xD=getXdO();\n" ;
prog_char line_08[] PROGMEM = "if(xD==null){" ;
prog_char line_09[] PROGMEM = "alert('No AJAX');" ;
prog_char line_10[] PROGMEM = "return}\n" ;
prog_char line_11[] PROGMEM = "xD.onreadystatechange=stateChanged;" ;
prog_char line_12[] PROGMEM = "xD.open('post',I,true);" ;
prog_char line_13[] PROGMEM = "xD.send(null)}\n" ;
prog_char line_14[] PROGMEM = "function stateChanged(){\n" ;
prog_char line_15[] PROGMEM = "if(xD.readyState==4){" ;
prog_char line_16[] PROGMEM = "dB = xD.responseText.split(',');\n" ;
prog_char line_17[] PROGMEM = "if(dB[" ;
prog_char line_18[] PROGMEM = "]){document.getElementById('D" ;
prog_char line_19[] PROGMEM = "').innerHTML=dB[" ;
prog_char line_20[] PROGMEM = "]}\n" ;
prog_char line_21[] PROGMEM ="}}\n" ;
prog_char line_22[] PROGMEM = "function getXdO(){var xD=null;\n" ;
prog_char line_23[] PROGMEM = "try{" ;
prog_char line_24[] PROGMEM = "xD=new XMLHttpRequest()}\n" ;
prog_char line_25[] PROGMEM = "catch (e){\n" ;
prog_char line_26[] PROGMEM = "try{" ;
prog_char line_27[] PROGMEM = "xD=new ActiveXObject(\"Msxml2.XMLHTTP\")}\n" ;
prog_char line_28[] PROGMEM = "catch (e){" ;
prog_char line_29[] PROGMEM = "xD=new ActiveXObject(\"Microsoft.XMLHTTP\")}}" ;
prog_char line_30[] PROGMEM = "return xD}\n" ;
prog_char line_31[] PROGMEM = "function A(){" ;
prog_char line_32[] PROGMEM = "setTimeout('A()'," ;
prog_char line_33[] PROGMEM = ");" ;
prog_char line_34[] PROGMEM = "fetch('@')}\n" ;
prog_char line_35[] PROGMEM = "</script></head>" ;
prog_char line_36[] PROGMEM = "<body onload='A()'>\n" ;
prog_char line_37[] PROGMEM = "<input type='button' value='Send One' onClick=\"fetch('1')\"><br>\n" ;
prog_char line_38[] PROGMEM = "<input type='button' value='Send Two' onClick=\"fetch('2')\"><br>\n" ;
prog_char line_39[] PROGMEM = "Analog " ;
prog_char line_40[] PROGMEM = " <span id='D" ;
prog_char line_41[] PROGMEM = "'></span><br>\n" ;
prog_char line_42[] PROGMEM = "</body></html>\n" ;
PROGMEM const char *string_table[] = {
line_00,
line_01,
line_02,
line_03,
line_04,
line_05,
line_06,
line_07,
line_08,
line_09,
line_10,
line_11,
line_12,
line_13,
line_14,
line_15,
line_16,
line_17,
line_18,
line_19,
line_20,
line_21,
line_22,
line_23,
line_24,
line_25,
line_26,
line_27,
line_28,
line_29,
line_30,
line_31,
line_32,
line_33,
line_34,
line_35,
line_36,
line_37,
line_38,
line_39,
line_40,
line_41,
line_42
};
//Constants
byte mac[] = { 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC };
byte servIP[] = { 192, 168, 0, 129 };
// TODO: Dynamic IP configuration
byte targetIP[] = { 192, 168, 0, 130 };
byte highIP[] = { 255, 255, 255, 255 };
byte zeroIP[] = { 0, 0, 0, 0 };
byte broadcastIP[] = { 255, 255, 255, 255 };
byte subnet[] = { 255, 255, 255, 0 };
//byte gateway[] = { 192, 168, 1, 1 };
byte leaseTime[] = { 0, 0, 2, 88 }; // 10 minutes
byte leaseRenew[] = { 0, 0, 1, 44 };
byte leaseRebind[] = { 0, 0, 1, 194 };
Server server(80);
/**
* @brief for the DHCP message
*/
typedef struct RIP_MSG{
byte op;
byte htype;
byte hlen;
byte hops;
unsigned long xid;
unsigned int secs;
unsigned int flags;
byte ciaddr[4];
byte yiaddr[4];
byte siaddr[4];
byte giaddr[4];
byte chaddr[16];
byte sname[64];
byte file[128];
byte magic[4];
byte OPT[];
};
// #########
void setup(){
Serial.begin(9600);
Ethernet.begin(mac,servIP);
Udp.begin(DHCP_SERVER_PORT);
server.begin();
#ifdef DEBUG
Serial.println("All started");
#endif
}
// #########
void dhcpServ(){
// Get packet size and allocate memory
int packetSize = Udp.available()-8; // why is there a -8 ?
RIP_MSG *packet = (RIP_MSG *)malloc(packetSize * sizeof(byte *));
Udp.readPacket((byte *)packet,packetSize);
// Find real size and make copy of incoming options
// Attempt to handle missing 'endOption' - corrupted line?
int optLoc = 0;
while(packet->OPT[optLoc] != endOption && optLoc < packetSize-dhcpSIZE){
optLoc = 2+optLoc+packet->OPT[optLoc+1];
}
int optSize = optLoc;
byte *options = (byte *)malloc(optSize * sizeof(byte *));
memcpy( options , packet->OPT , optSize);
#ifdef DEBUG
Serial.print("Packet size ");
Serial.println(packetSize, DEC);
Serial.print("Options size ");
Serial.println(optSize, DEC);
Serial.println("Fetched");
for(int i = 0;i < (optSize);i++){
Serial.print(options
, DEC);
Serial.print(" ");
}
Serial.println();
#endif
packet->op = DHCP_BOOTREPLY;
strcpy((char *)packet->sname, serverName);
memcpy(packet->siaddr, servIP, 4);
memcpy(packet->yiaddr, targetIP, 4);
optLoc = 0;
int currLoc = 0;
int messLoc = 0;
byte optType = options[optLoc];
while(optLoc < optSize){
#ifdef DEBUG
Serial.println();
Serial.print(optType);
#endif
switch(optType){
case dhcpMessageType:
currLoc+=2;
messLoc = currLoc;
if(options[optLoc+2] == DHCP_DISCOVER){
#ifdef DEBUG
Serial.print(" Discover");
#endif
packet->OPT[currLoc++] = DHCP_OFFER;
}
else if(options[optLoc+2] == DHCP_REQUEST){
#ifdef DEBUG
Serial.print(" Request");
#endif
packet->OPT[currLoc++] = DHCP_ACK;
}
else{
#ifdef DEBUG
Serial.print(" Other");
#endif
packet->OPT[currLoc++] = DHCP_NAK;
}
break;
case dhcpRequestedIPaddr:
// maybe use this to decline a duplicate IP request
// when dynamic IPs done?
case hostName:
// dunno?
break;
case dhcpServerIdentifier:
packet->OPT[currLoc++] = optType;
packet->OPT[currLoc++] = 4;
memcpy(packet->OPT+currLoc, servIP, 4);
currLoc += 4;
break;
case dhcpParamRequest:
for(int i = 0;i < options[optLoc+1];i++){
switch (options[optLoc+i+2]){
case subnetMask:
packet->OPT[currLoc++] = subnetMask;
packet->OPT[currLoc++] = 4;
memcpy(packet->OPT+currLoc,subnet,4);
currLoc += 4;
break;
case routersOnSubnet:
packet->OPT[currLoc++] = routersOnSubnet;
packet->OPT[currLoc++] = 4;
memcpy(packet->OPT+currLoc,servIP,4);
currLoc += 4;
break;
case dns: // would like to follow up on this
packet->OPT[currLoc++] = dns;
packet->OPT[currLoc++] = 4;
memcpy(packet->OPT+currLoc,servIP,4);
currLoc += 4;
break;
case logServer:
packet->OPT[currLoc++] = optType;
packet->OPT[currLoc++] = 4;
memcpy(packet->OPT+currLoc,zeroIP,4);
currLoc += 4;
break;
case domainName:
packet->OPT[currLoc++] = optType;
packet->OPT[currLoc++] = sizeof(myDomainName);
memcpy(packet->OPT+currLoc, myDomainName, sizeof(myDomainName));
currLoc += sizeof(myDomainName);
break;
}
}
break;
}
optLoc = 2+optLoc+options[optLoc+1];
optType = options[optLoc];
}
packet->OPT[currLoc++] = dhcpIPaddrLeaseTime;
packet->OPT[currLoc++] = 4;
memcpy(packet->OPT+currLoc,leaseTime,4);
currLoc += 4;
packet->OPT[currLoc++] = dhcpT1value;
packet->OPT[currLoc++] = 4;
memcpy(packet->OPT+currLoc,leaseRenew,4);
currLoc += 4;
packet->OPT[currLoc++] = dhcpT2value;
packet->OPT[currLoc++] = 4;
memcpy(packet->OPT+currLoc,leaseRebind,4);
currLoc += 4;
packet->OPT[currLoc++] = endOption;
#ifdef DEBUG
Serial.println();
Serial.println();
Serial.println("Sent");
for(int i = 0;i<(currLoc);i++){
Serial.print(packet->OPT, DEC);
Serial.print(" ");
}
Serial.println();
#endif
// Send Packet
Udp.sendPacket((byte *)packet,dhcpSIZE+currLoc,broadcastIP,DHCP_CLIENT_PORT);
// Disposal code
zap(options);
zap(packet);
}
// #########
int getline(Client client, char *buffer){
int i = 0;
char c;
buffer[i++] = client.read();
buffer[i++] = client.read();
while (buffer[i-2] != '\r' && buffer[i-1] != '\n' && client.available()) {
c = client.read();
if (i < bufferSIZE){
buffer = c;
i ++;
}
}
return i;
}
// #########
// send a web page complete with javascript
void makepage(Client client, char *buffer){
for (int i = 0; i < 17; i++){
strcpy_P(buffer, (char*)pgm_read_word(&(string_table)));
client.print(buffer);
}
for (int i = 0 ; i < 6 ; i ++){
strcpy_P(buffer, (char*)pgm_read_word(&(string_table[17])));
client.print(buffer);
client.print(i);
strcpy_P(buffer, (char*)pgm_read_word(&(string_table[18])));
client.print(buffer);
client.print(i);
strcpy_P(buffer, (char*)pgm_read_word(&(string_table[19])));
client.print(buffer);
client.print(i);
strcpy_P(buffer, (char*)pgm_read_word(&(string_table[20])));
client.print(buffer);
}
for (int i = 21; i < 33; i++){
strcpy_P(buffer, (char*)pgm_read_word(&(string_table)));
client.print(buffer);
}
client.print(refreshTIME);
for (int i = 33; i < 39; i++){
strcpy_P(buffer, (char*)pgm_read_word(&(string_table)));
client.print(buffer);
}
for (int i = 0 ; i < 6 ; i ++){
strcpy_P(buffer, (char*)pgm_read_word(&(string_table[39])));
client.print(buffer);
client.print(i);
strcpy_P(buffer, (char*)pgm_read_word(&(string_table[40])));
client.print(buffer);
client.print(i);
strcpy_P(buffer, (char*)pgm_read_word(&(string_table[41])));
client.print(buffer);
}
strcpy_P(buffer, (char*)pgm_read_word(&(string_table[42])));
client.print(buffer);
}
// #########
void webServ(Client client){
char *buffer = (char *)malloc(bufferSIZE * sizeof(char *));
while (client.connected()) {
if (client.available()) {
int len = getline(client, buffer);
#ifdef DEBUG
Serial.print(">>");
int i = 0;
while (buffer >= 32){
Serial.print(buffer);
i++;
}
Serial.println();
#endif
if (len > 2) {
if (!memcmp(buffer,"GET / HTTP",10)){
makepage(client, buffer);
}
else if (!memcmp(buffer,"POST /",6)){
// look for returned values - crude but it works!
switch(buffer[6]){
case '1':
Serial.println("Got number 1");
break;
case '2':
Serial.println("2nd button pressed");
break;
// send the value of each analog input pin - comma separated
case '@':
client.print(analogRead(0));
for (int i = 1 ; i < 6 ; i ++){
client.print(',');
client.print(analogRead(i));
}
break;
}
}
break;
}
}
}
// give the web browser time to receive the data
delay(1);
client.stop();
zap(buffer);
}
// #########
// put everything in functions to make the loop clearer
void loop(){
if(Udp.available()){
dhcpServ();
}
Client client = server.available();
if (client) {
webServ(client);
}
}
*****
YMMV
++
http://www.aether-hemera.com/blog/default.asp?PostId=30