The arduino script is:
boolean CONNECTED = false;
char sending = 65;
String msg = "AAAAAAAAAAAAAAAAAAAAAA";
#define SHA1_K0 0x5a827999
#define SHA1_K20 0x6ed9eba1
#define SHA1_K40 0x8f1bbcdc
#define SHA1_K60 0xca62c1d6
#define w6 0x32353845
#define w7 0x41464135
#define w8 0x2d453931
#define w9 0x342d3437
#define w10 0x44412d39
#define w11 0x3543412d
#define w12 0x43354142
#define w13 0x30444338
#define w14 0x35423131
#define w15 0x80000000
void setup() {
Serial.begin(9600); //open connection to wifi module
}
void loop() {
if (CONNECTED) {
char toSend[] = {0x81, 1, sending++};
Serial.print(toSend);
delay(1000);
}
if(serverRequest()){
String path = getRequestPath();
if(path == F("/WS")){
Serial.find("Key: ");
msg = Serial.readStringUntil('==');
Serial.flush();
Serial.print(F("HTTP/1.1 101 Switching"));
Serial.print(F(" Protocols\r\nUpgrade: "));
Serial.print(F("Websocket\r\nConnection: "));
Serial.print(F("Upgrade\r\nSec-WebSocket-Accept: "));
generateResponse();
Serial.print(F("=\r\n\r\n"));
CONNECTED = true;
}
else{
Serial.flush();
}
}
}
bool serverRequest(){
if(Serial.available()>4){
return Serial.find("GET ");
}
return false;
}
String getRequestPath(){
String path = Serial.readStringUntil(' ');
return path;
}
void sendResponse(String response){
sendResponseStart();
sendResponseChunk(response);
sendResponseEnd();
}
void sendResponseStart(){
//sends a chunked response
Serial.println(F("HTTP/1.1 200 OK"));
Serial.println(F("Content-Type: text/html"));
Serial.println(F("Connection: close"));
Serial.println(F("Transfer-Encoding: chunked"));
Serial.println();
}
void sendResponseChunk(String response){
Serial.println(response.length()+2,HEX);
Serial.println(response);
Serial.println();
}
void sendResponseEnd(){
Serial.println(F("0"));
Serial.println();
}
void generateResponse() {
// this main function has the initial hash variables, fills the w array, then makes two passes through the sha-1 function
uint32_t H[] = {0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0}; // Initial H values
uint32_t H1[5] = {0,0,0,0,0};
uint32_t w[16];
getMessage(w);
getHash(w, H, H1);
for (int w_cntr = 0; w_cntr<16; w_cntr++) { w[w_cntr] = 0; }
w[15]=480 & 0xffff;
getHash(w, H1, H1);
convertBase64(H1);
}
void getMessage(uint32_t* w_out){ // takes the websocket key (msg) and fills up the w array
uint8_t temp;
int k=0;
for (int j=0; j<6; j++){
w_out[j]=0x00;
for (int i=0; i<4; i++) {
temp = msg[k++] ;
if (k>22) temp=0x3d; //this adds thetwo '=' to the key
w_out[j] = (w_out[j] <<8) | (temp);
}
}
w_out[6] = w6; // the last 10 w's are constant
w_out[7] = w7;
w_out[8] = w8;
w_out[9] = w9;
w_out[10] = w10;
w_out[11] = w11;
w_out[12] = w12;
w_out[13] = w13;
w_out[14] = w14;
w_out[15] = w15;
}
uint32_t ROTL(uint32_t number, uint8_t bits) {
return ((number << bits) | (number >> (32-bits)));
}
char b64(int in) {
//I used this instead of the huge 64 byte string
// char b64[64]="ABCDEFGHIJKLMNOP...
if (in > 62) {return '/';}
else if (in > 61) {return '+';}
else if (in > 51) {return (char)(in + -4 );}
else if (in > 25) {return (char)(in + 71 );}
else {return (char)(in + 65);}
}
void convertBase64(uint32_t input_msg[]) {
//This takes the final hash digest and prints out the base64 conversion
int j = 0;
for (int i=26; i>0; i-=6) {
Serial.print(b64(input_msg[j]>>i&63));
}
Serial.print(b64( (input_msg[j]<<4 | input_msg[j+1]>>28)&63));
j=1;
for (int i=22; i>0; i-=6) {
Serial.print(b64(input_msg[j]>>i&63));
}
Serial.print(b64( (input_msg[j]<<2 | input_msg[j+1]>>30)&63));
j=2;
for (int i=24; i>=0; i-=6) {
Serial.print(b64(input_msg[j]>>i&63));
}
j=3;
for (int i=26; i>0; i-=6) {
Serial.print(b64(input_msg[j]>>i&63));
}
Serial.print(b64( (input_msg[j]<<4 | input_msg[j+1]>>28)&63));
j=4;
for (int i=22; i>=0; i-=6) {
Serial.print(b64(input_msg[j]>>i&63));
}
Serial.print(b64( (input_msg[j]<<2)&63));
// technically it still needs to add '=' to the end, but that is done after the getresponse() call
}
void getHash(uint32_t* W, uint32_t* hash, uint32_t* hash1) {
// this is the main sha-1 conversion takes in the 16 word array 'w' along with the initial hash and returns the new hash
// it is called twice, first with the initial hash constants and the full w, then with the generated hash values
// and the mostly empty w
uint32_t a = hash[0];
uint32_t b = hash[1];
uint32_t c = hash[2];
uint32_t d = hash[3];
uint32_t e = hash[4];
uint32_t temp = 0;
uint32_t k = 0;
uint32_t t;
for (uint32_t i=0; i<80; i++) { //I don't htink I needs to be 32, probably just int or 8
if (i>=16) {
t = W[(i+13)&15] ^ W[(i+8)&15] ^ W[(i+2)&15] ^ W[i&15];
W[i&15] = ROTL(t,1);
}
if (i<20) {
t = (d ^ (b & (c ^ d))) + SHA1_K0;
} else if (i<40) {
t = (b ^ c ^ d) + SHA1_K20;
} else if (i<60) {
t = ((b & c) | (d & (b | c))) + SHA1_K40;
} else {
t = (b ^ c ^ d) + SHA1_K60;
}
t+=ROTL(a,5) + e + W[i&15];
e=d;
d=c;
c=ROTL(b,30);
b=a;
a=t;
}
hash1[0] = hash[0] + a;
hash1[1] = hash[1] + b;
hash1[2] = hash[2] + c;
hash1[3] = hash[3] + d;
hash1[4] = hash[4] + e;
}
void webPage() {
//This would generate the webpage, but I can't get it to send
sendResponseStart();
sendResponseChunk(F("<!DOCTYPE HTML><html><head>"));
sendResponseChunk(F("<script type=\"text/javascript\">"));
sendResponseChunk(F("function WebSocketTest(){"));
sendResponseChunk(F("var ws = new WebSocket(\"ws://10.0.0.9:8080/WS\");")); // change the address to match your pro
sendResponseChunk(F("ws.onopen = function(){"));
sendResponseChunk(F("alert(\"open\");};"));
sendResponseChunk(F("ws.onmessage = function (evt) { "));
sendResponseChunk(F("alert(evt.data);};"));
sendResponseChunk(F("ws.onclose = function(){ "));
sendResponseChunk(F("alert(\"closed\");};}"));
sendResponseChunk(F("</script></head><body>"));
sendResponseChunk(F("<a href=\"javascript:WebSocketTest()\">Run</a>"));
sendResponseChunk(F("</body></html>"));
sendResponseEnd();
}
And the webpage required is:
<!DOCTYPE html>
<meta charset="utf-8" />
<title>WebSocket Test</title>
<script language="javascript" type="text/javascript">
function init()
{
document.myform.url.value = "ws://localhost:8080/WS"
document.myform.inputtext.value = "Hello World!"
document.myform.disconnectButton.disabled = true;
}
function doConnect()
{
websocket = new WebSocket(document.myform.url.value);
websocket.onopen = function(evt) { onOpen(evt) };
websocket.onclose = function(evt) { onClose(evt) };
websocket.onmessage = function(evt) { onMessage(evt) };
websocket.onerror = function(evt) { onError(evt) };
}
function onOpen(evt)
{
writeToScreen("connected\n");
document.myform.connectButton.disabled = true;
document.myform.disconnectButton.disabled = false;
}
function onClose(evt)
{
writeToScreen("disconnected\n");
document.myform.connectButton.disabled = false;
document.myform.disconnectButton.disabled = true;
}
function onMessage(evt)
{
writeToScreen("response: " + evt.data + '\n');
}
function onError(evt)
{
writeToScreen('error: ' + evt.data + '\n');
websocket.close();
document.myform.connectButton.disabled = false;
document.myform.disconnectButton.disabled = true;
}
function doSend(message)
{
writeToScreen("sent: " + message + '\n');
websocket.send(message);
}
function writeToScreen(message)
{
document.myform.outputtext.value += message
document.myform.outputtext.scrollTop = document.myform.outputtext.scrollHeight;
}
window.addEventListener("load", init, false);
function sendText() {
doSend( document.myform.inputtext.value );
}
function clearText() {
document.myform.outputtext.value = "";
}
function doDisconnect() {
websocket.close();
}
</script>
<div id="output"></div>
<form name="myform">
<p>
<textarea name="outputtext" rows="20" cols="50"></textarea>
</p>
<p>
<textarea name="inputtext" cols="50"></textarea>
</p>
<p>
<textarea name="url" cols="50"></textarea>
</p>
<p>
<input type="button" name=sendButton value="Send" onClick="sendText();">
<input type="button" name=clearButton value="Clear" onClick="clearText();">
<input type="button" name=disconnectButton value="Disconnect" onClick="doDisconnect();">
<input type="button" name=connectButton value="Connect" onClick="doConnect();">
</p>
</form>
</html>
Once you get this working, the pro will send "A" to the browser, and increment that every second until it crashes.
Description to follow.