From 2d63374690f4e67096c17f6c151d10fdac64a357 Mon Sep 17 00:00:00 2001 From: Dave Date: Thu, 31 Oct 2019 18:03:27 +0100 Subject: [PATCH 1/6] Update PusherClient.cpp switched to eu server updated to correct PROGMEM calls --- PusherClient.cpp | 35 +++++++++++++++++------------------ 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/PusherClient.cpp b/PusherClient.cpp index 3ac4958..0bb0b03 100644 --- a/PusherClient.cpp +++ b/PusherClient.cpp @@ -33,22 +33,21 @@ typedef void (*EventDelegate)(String data); static EventDelegate _bindAllDelegate; static HashMap _bindMap = HashMap(); -prog_char stringVar0[] PROGMEM = "{0}"; -prog_char stringVar1[] PROGMEM = "{1}"; -prog_char stringVar2[] PROGMEM = "{2}"; -prog_char pusherPath[] PROGMEM = "/app/{0}?client=js&version=2.1&protocol=7"; -prog_char pusherHostname[] PROGMEM = "ws.pusherapp.com"; -prog_char subscribeEventName[] PROGMEM = "pusher:subscribe"; -prog_char subscribeMessage1[] PROGMEM = "{\"channel\": \"{0}\" }"; -prog_char subscribeMessage2[] PROGMEM = "{\"channel\": \"{0}\", \"auth\": \"{1}\" }"; -prog_char subscribeMessage3[] PROGMEM = "{\"channel\": \"{0}\", \"auth\": \"{1}\", \"channel_data\": { \"user_id\": {2} } }"; -prog_char unsubscribeMessage[] PROGMEM = "{\"channel\": \"{0}\" }"; -prog_char triggerEventMessage[] PROGMEM = "{\"event\": \"{0}\", \"data\": {1} }"; -prog_char eventNameStart[] PROGMEM = "event"; -prog_char unsubscribeEventName[] PROGMEM = "pusher:unsubscribe"; - - -PROGMEM const char *stringTable[] = +const char stringVar0[] PROGMEM = "{0}"; +const char stringVar1[] PROGMEM = "{1}"; +const char stringVar2[] PROGMEM = "{2}"; +const char pusherPath[] PROGMEM = "/app/{0}?client=js&version=2.2.3&flash=false&protocol=7"; +const char pusherHostname[] PROGMEM = "ws-eu.pusherapp.com"; +const char subscribeEventName[] PROGMEM = "pusher:subscribe"; +const char subscribeMessage1[] PROGMEM = "{\"channel\": \"{0}\" }"; +const char subscribeMessage2[] PROGMEM = "{\"channel\": \"{0}\", \"auth\": \"{1}\" }"; +const char subscribeMessage3[] PROGMEM = "{\"channel\": \"{0}\", \"auth\": \"{1}\", \"channel_data\": { \"user_id\": {2} } }"; +const char unsubscribeMessage[] PROGMEM = "{\"channel\": \"{0}\" }"; +const char triggerEventMessage[] PROGMEM = "{\"event\": \"{0}\", \"data\": {1} }"; +const char eventNameStart[] PROGMEM = "event"; +const char unsubscribeEventName[] PROGMEM = "pusher:unsubscribe"; + +PGM_P const stringTable[] PROGMEM = { stringVar0, stringVar1, @@ -83,8 +82,8 @@ bool PusherClient::connect(String appId) { char pathData[path.length() + 1]; path.toCharArray(pathData, path.length() + 1); - - return _client.connect("ws.pusherapp.com", pathData, 80); + + return _client.connect("ws-eu.pusher.com", pathData, 80); } bool PusherClient::connected() { From 739bd0c3f1492d5031cb44eafa5477f7ff11fdf0 Mon Sep 17 00:00:00 2001 From: Dave Date: Thu, 31 Oct 2019 18:04:52 +0100 Subject: [PATCH 2/6] using correct way of PROGMEM --- WebSocketClient.cpp | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/WebSocketClient.cpp b/WebSocketClient.cpp index 335329b..8db4839 100644 --- a/WebSocketClient.cpp +++ b/WebSocketClient.cpp @@ -27,15 +27,15 @@ #include #include -prog_char stringVar[] PROGMEM = "{0}"; -prog_char clientHandshakeLine1[] PROGMEM = "GET {0} HTTP/1.1"; -prog_char clientHandshakeLine2[] PROGMEM = "Upgrade: WebSocket"; -prog_char clientHandshakeLine3[] PROGMEM = "Connection: Upgrade"; -prog_char clientHandshakeLine4[] PROGMEM = "Host: {0}"; -prog_char clientHandshakeLine5[] PROGMEM = "Origin: ArduinoWebSocketClient"; -prog_char serverHandshake[] PROGMEM = "HTTP/1.1 101"; - -PROGMEM const char *WebSocketClientStringTable[] = +const char stringVar[] PROGMEM = "{0}"; +const char clientHandshakeLine1[] PROGMEM = "GET {0} HTTP/1.1"; +const char clientHandshakeLine2[] PROGMEM = "Upgrade: WebSocket"; +const char clientHandshakeLine3[] PROGMEM = "Connection: Upgrade"; +const char clientHandshakeLine4[] PROGMEM = "Host: {0}"; +const char clientHandshakeLine5[] PROGMEM = "Origin: ArduinoWebSocketClient"; +const char serverHandshake[] PROGMEM = "HTTP/1.1 101"; + +PGM_P const WebSocketClientStringTable[] PROGMEM = { stringVar, clientHandshakeLine1, @@ -46,7 +46,7 @@ PROGMEM const char *WebSocketClientStringTable[] = serverHandshake }; -String WebSocketClient::getStringTableItem(int index) { +String WebSocketClient::getStringSocketClientTableItem(int index) { char buffer[35]; strcpy_P(buffer, (char*)pgm_read_word(&(WebSocketClientStringTable[index]))); return String(buffer); @@ -54,7 +54,7 @@ String WebSocketClient::getStringTableItem(int index) { bool WebSocketClient::connect(char hostname[], char path[], int port) { bool result = false; - + if (_client.connect(hostname, port)) { sendHandshake(hostname, path); result = readHandshake(); @@ -72,7 +72,7 @@ void WebSocketClient::disconnect() { _client.stop(); } -void WebSocketClient::monitor () { +void WebSocketClient::monitor() { char character; if (_client.available() > 0 && (character = _client.read()) == 0) { @@ -99,16 +99,17 @@ void WebSocketClient::setDataArrivedDelegate(DataArrivedDelegate dataArrivedDele void WebSocketClient::sendHandshake(char hostname[], char path[]) { - String stringVar = getStringTableItem(0); - String line1 = getStringTableItem(1); - String line2 = getStringTableItem(2); - String line3 = getStringTableItem(3); - String line4 = getStringTableItem(4); - String line5 = getStringTableItem(5); + String stringVar = getStringSocketClientTableItem(0); + + String line1 = getStringSocketClientTableItem(1); + String line2 = getStringSocketClientTableItem(2); + String line3 = getStringSocketClientTableItem(3); + String line4 = getStringSocketClientTableItem(4); + String line5 = getStringSocketClientTableItem(5); line1.replace(stringVar, path); line4.replace(stringVar, hostname); - + _client.println(line1); _client.println(line2); _client.println(line3); @@ -133,7 +134,7 @@ bool WebSocketClient::readHandshake() { handshake += line + '\n'; } - String response = getStringTableItem(6); + String response = getStringSocketClientTableItem(6); result = handshake.indexOf(response) != -1; if(!result) { @@ -161,4 +162,3 @@ void WebSocketClient::send (String data) { _client.print(data); _client.print((char)255); } - From 63779dcb1d960fc49f7e8bdac224d379b8ddeb23 Mon Sep 17 00:00:00 2001 From: Dave Date: Thu, 31 Oct 2019 18:07:05 +0100 Subject: [PATCH 3/6] Update WebSocketClient.h renamed while debugging --- WebSocketClient.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WebSocketClient.h b/WebSocketClient.h index ab4ff77..0380113 100644 --- a/WebSocketClient.h +++ b/WebSocketClient.h @@ -44,7 +44,7 @@ class WebSocketClient { void setDataArrivedDelegate(DataArrivedDelegate dataArrivedDelegate); void send(String data); private: - String getStringTableItem(int index); + String getStringSocketClientTableItem(int index); void sendHandshake(char hostname[], char path[]); EthernetClient _client; DataArrivedDelegate _dataArrivedDelegate; From aff6712315874280c1da20841de81c3d7b35f0e1 Mon Sep 17 00:00:00 2001 From: Dave Date: Thu, 17 Feb 2022 12:27:39 +0100 Subject: [PATCH 4/6] marco branch --- HashMap/HashMap.h | 12 +- Logger.h | 73 +++ PusherClient.cpp | 445 +++++++++++++----- PusherClient.h | 69 ++- README.md | 43 +- WebSocketClient.cpp | 302 +++++++----- WebSocketClient.h | 30 +- .../private_channels/private_channels.ino | 46 ++ sha256.cpp | 176 +++++++ sha256.h | 42 ++ 10 files changed, 970 insertions(+), 268 deletions(-) create mode 100644 Logger.h create mode 100644 examples/private_channels/private_channels.ino create mode 100644 sha256.cpp create mode 100644 sha256.h diff --git a/HashMap/HashMap.h b/HashMap/HashMap.h index a1933c0..835a0a7 100644 --- a/HashMap/HashMap.h +++ b/HashMap/HashMap.h @@ -62,7 +62,7 @@ class HashMap || || @return The key at index idx */ - K keyAt(unsigned int idx) + const K& keyAt(unsigned int idx) { return keys[idx]; } @@ -104,7 +104,7 @@ class HashMap || || @return The const value for key */ - const V& operator[](const K key) const + const V& operator[](const K& key) const { return operator[](key); } @@ -120,7 +120,7 @@ class HashMap || || @return The value for key */ - V& operator[](const K key) + V& operator[](const K& key) { if (contains(key)) { @@ -145,7 +145,7 @@ class HashMap || || @return The index of the key, or -1 if key does not exist */ - unsigned int indexOf(K key) + unsigned int indexOf(const K& key) { for (int i = 0; i < currentIndex; i++) { @@ -176,7 +176,7 @@ class HashMap || || @return true if it is contained in this HashMap */ - bool contains(K key) + bool contains(const K& key) { for (int i = 0; i < currentIndex; i++) { @@ -205,7 +205,7 @@ class HashMap || || @parameter key the key to remove from this HashMap */ - void remove(K key) + void remove(const K& key) { int index = indexOf(key); if (contains(key)) diff --git a/Logger.h b/Logger.h new file mode 100644 index 0000000..03f1311 --- /dev/null +++ b/Logger.h @@ -0,0 +1,73 @@ +#ifndef LOGGER_H +#define LOGGER_H + +#define LOGGER_ENABLED 1 + +#if LOGGER_ENABLED +inline void LogPrint(PROGMEM const char** table, int index) +{ + char* ptr = (char*)pgm_read_word(&(table[index])); + int len = strlen_P(ptr); + char buffer[len+1]; + strcpy_P(buffer, ptr); + + Serial.print(buffer); +} + +inline void LogPrintLn(PROGMEM const char** table, int index) +{ + char* ptr = (char*)pgm_read_word(&(table[index])); + int len = strlen_P(ptr); + char buffer[len+1]; + strcpy_P(buffer, ptr); + + Serial.println(buffer); + Serial.flush(); +} + +inline void LogPrint(const String& text) +{ + Serial.print(text); +} + +inline void LogPrintLn(const String& text) +{ + Serial.println(text); + Serial.flush(); +} + +inline void LogPrint(const char text[]) +{ + Serial.print(text); +} + +inline void LogPrintLn(const char text[]) +{ + Serial.println(text); + Serial.flush(); +} + +inline void LogPrint(const int value) +{ + Serial.print(value); +} + +inline void LogPrintLn(const int value) +{ + Serial.println(value); + Serial.flush(); +} + +#else + +inline void LogPrint(...) +{ +} + +inline void LogPrintLn(...) +{ +} + +#endif +#endif + diff --git a/PusherClient.cpp b/PusherClient.cpp index 0bb0b03..2b93a19 100644 --- a/PusherClient.cpp +++ b/PusherClient.cpp @@ -22,170 +22,278 @@ THE SOFTWARE. */ -#include -#include -#include -#include -#include +#include "PusherClient.h" +#if (ENABLE_AUTH == 1) +#include "sha256.h" const byte HASH_SIZE = 10; -typedef void (*EventDelegate)(String data); static EventDelegate _bindAllDelegate; static HashMap _bindMap = HashMap(); +void connectionEstablished(const String& eventName, const String& eventData); +#endif -const char stringVar0[] PROGMEM = "{0}"; -const char stringVar1[] PROGMEM = "{1}"; -const char stringVar2[] PROGMEM = "{2}"; -const char pusherPath[] PROGMEM = "/app/{0}?client=js&version=2.2.3&flash=false&protocol=7"; -const char pusherHostname[] PROGMEM = "ws-eu.pusherapp.com"; -const char subscribeEventName[] PROGMEM = "pusher:subscribe"; -const char subscribeMessage1[] PROGMEM = "{\"channel\": \"{0}\" }"; -const char subscribeMessage2[] PROGMEM = "{\"channel\": \"{0}\", \"auth\": \"{1}\" }"; -const char subscribeMessage3[] PROGMEM = "{\"channel\": \"{0}\", \"auth\": \"{1}\", \"channel_data\": { \"user_id\": {2} } }"; -const char unsubscribeMessage[] PROGMEM = "{\"channel\": \"{0}\" }"; -const char triggerEventMessage[] PROGMEM = "{\"event\": \"{0}\", \"data\": {1} }"; -const char eventNameStart[] PROGMEM = "event"; -const char unsubscribeEventName[] PROGMEM = "pusher:unsubscribe"; - -PGM_P const stringTable[] PROGMEM = +prog_char pusherAppId[] PROGMEM = ""; //INSERT YOU API ID HERE +prog_char pusherKey[] PROGMEM = ""; //INSERT YOU API KEY HERE +prog_char pusherSecret[] PROGMEM = ""; //INSERT YOU API SECRET HERE +PROGMEM const char* pusherInfos[] = { - stringVar0, - stringVar1, - stringVar2, - pusherPath, - pusherHostname, - subscribeEventName, - subscribeMessage1, - subscribeMessage2, - subscribeMessage3, - unsubscribeMessage, - triggerEventMessage, - eventNameStart, - unsubscribeEventName + pusherAppId, //0 + pusherKey, //1 + pusherSecret, //2 }; -String PusherClient::getStringTableItem(int index) { - char buffer[85]; - strcpy_P(buffer, (char*)pgm_read_word(&(stringTable[index]))); - return String(buffer); +prog_char stringVar0[] PROGMEM = "#1"; +prog_char stringVar1[] PROGMEM = "#2"; +prog_char stringVar2[] PROGMEM = "#3"; +prog_char pusherPath[] PROGMEM = "/app/#1?client=js&version=1.9.0"; +prog_char pusherHostname[] PROGMEM = "ws.pusherapp.com"; +prog_char subscribeEventName[] PROGMEM = "pusher:subscribe"; +prog_char subscribeMessage1[] PROGMEM = "{\"channel\":\"#1\"}"; +prog_char subscribeMessage2[] PROGMEM = "{\"channel\":\"#1\",\"auth\":\"#2\"}"; +prog_char subscribeMessage3[] PROGMEM = "{\"channel\":\"#1\",\"auth\":\"#2\",\"channel_data\":{\"user_id\":#3}}"; +prog_char unsubscribeMessage[] PROGMEM = "{\"channel\":\"#1\"}"; +prog_char triggerEventMessage[] PROGMEM = "{\"event\":\"#1\",\"data\":#2}"; +prog_char triggerEventChannelMessage[] PROGMEM = "{\"event\":\"#1\",\"channel\":\"#3\",\"data\":#2}"; +prog_char eventNameStart[] PROGMEM = "\"event\""; +prog_char dataNameStart[] PROGMEM = "\"data\""; +prog_char unsubscribeEventName[] PROGMEM = "pusher:unsubscribe"; +prog_char pingEvent[] PROGMEM = "{\"event\":\"pusher:ping\",\"data\":\"\"}"; +prog_char emptyEventData[] PROGMEM = "\"\""; +prog_char connectionEstablishedEventName[] PROGMEM = "pusher:connection_established"; +prog_char socketIdName[] PROGMEM = "\"socket_id\""; +prog_char hexCharacters[] PROGMEM = "0123456789abcdef"; + +#define STRING_BUFFER_SIZE 85 +#define DEFINE_STRING_BUFFER(name) char name[STRING_BUFFER_SIZE]; + +prog_char logConnectionFailedPC[] PROGMEM = "Connection to Pusher failed."; +prog_char logConnectionSuccessPC[] PROGMEM = "Connection to Pusher completed."; +prog_char logBindEventPC[] PROGMEM = "Bound to event "; +prog_char logSubscribeChannelPC[] PROGMEM = "Subscribed to channel "; +prog_char logAnswerToPing[] PROGMEM = "Sending pong event"; +prog_char logTriggeringEvent[] PROGMEM = "Triggering event "; + +PROGMEM const char* stringTablePusherClient[] = +{ + stringVar0, //0 + stringVar1, //1 + stringVar2, //2 + pusherPath, //3 + pusherHostname, //4 + subscribeEventName, //5 + subscribeMessage1, //6 + subscribeMessage2, //7 + subscribeMessage3, //8 + unsubscribeMessage, //9 + triggerEventMessage, //10 + eventNameStart, //11 + unsubscribeEventName, //12 + dataNameStart, //13 + triggerEventChannelMessage, //14 + pingEvent, //15 + emptyEventData, //16 + connectionEstablishedEventName, //17 + socketIdName, //18 + hexCharacters, //19 +}; + +PROGMEM const char* logMessageTablePusherClient[] = +{ + logConnectionFailedPC, //0 + logConnectionSuccessPC, //1 + logBindEventPC, //2 + logSubscribeChannelPC, //3 + logAnswerToPing, //4 + logTriggeringEvent, //5 +}; + +void PusherClient::getStringTableItem(int index, String& text) +{ + char* ptr = (char*)pgm_read_word(&(stringTablePusherClient[index])); + int len = strlen_P(ptr); + char buffer[len+1]; + strcpy_P(buffer, ptr); + text = buffer; +} + +void PusherClient::getPusherInfoItem(int index, String& text) +{ + char* ptr = (char*)pgm_read_word(&(pusherInfos[index])); + int len = strlen_P(ptr); + char buffer[len+1]; + strcpy_P(buffer, ptr); + text = buffer; } PusherClient::PusherClient() { - _client.setDataArrivedDelegate(dataArrived); + String eventName; + getStringTableItem(17, eventName); + bind(eventName, connectionEstablished); + + _client.setDataArrivedDelegate(dataArrived); + lastPingTime = millis(); } -bool PusherClient::connect(String appId) { - String stringVar0 = getStringTableItem(0); - String path = getStringTableItem(3); - path.replace(stringVar0, appId); - - char pathData[path.length() + 1]; - path.toCharArray(pathData, path.length() + 1); +bool PusherClient::connect() +{ + String stringVar0; + String path; + String host; + String key; + + getStringTableItem(0, stringVar0); + getStringTableItem(3, path); + getStringTableItem(4, host); + getPusherInfoItem(1, key); + path.replace(stringVar0, key); - return _client.connect("ws-eu.pusher.com", pathData, 80); + if (!_client.connect(host, path, 80)) + { + LogPrintLn(logMessageTablePusherClient, 0); + return false; + } + +#if (ENABLE_AUTH == 1) + while(_socketid.length() == 0) + { + delay(100); + monitor(); + } +#endif + + LogPrintLn(logMessageTablePusherClient, 1); + return true; } -bool PusherClient::connected() { +bool PusherClient::connected() +{ return _client.connected(); } -void PusherClient::disconnect() { +void PusherClient::disconnect() +{ _client.disconnect(); } -void PusherClient::monitor () { +void PusherClient::monitor() +{ _client.monitor(); + + if (_client.connected()) + { + const unsigned long timeout = 60000; + + unsigned long time = millis(); + + if (time > lastPingTime + timeout) + { + KeepConnectionAlive(); + lastPingTime = time; + } + } } -void PusherClient::bindAll(EventDelegate delegate) { +void PusherClient::bindAll(EventDelegate delegate) +{ _bindAllDelegate = delegate; } -void PusherClient::bind(String eventName, EventDelegate delegate) { +void PusherClient::bind(const String& eventName, EventDelegate delegate) +{ _bindMap[eventName] = delegate; } -void PusherClient::subscribe(String channel) { - String subscribeEventName = getStringTableItem(5); - String stringVar0 = getStringTableItem(0); - String message = getStringTableItem(6); +void PusherClient::subscribe(const String& channel) +{ + if (!_client.connected()) + return; + + String subscribeEventName; + String stringVar0; + String message; + + getStringTableItem(5, subscribeEventName); + getStringTableItem(0, stringVar0); + getStringTableItem(6, message); + message.replace(stringVar0, channel); - triggerEvent(subscribeEventName, message); -} - -void PusherClient::subscribe(String channel, String auth) { - String subscribeEventName = getStringTableItem(5); - String stringVar0 = getStringTableItem(0); - String stringVar1 = getStringTableItem(1); - String message = getStringTableItem(7); - message.replace(stringVar0, channel); - message.replace(stringVar1, auth); - triggerEvent(subscribeEventName, message); -} + + triggerEvent(subscribeEventName, message); -void PusherClient::subscribe(String channel, String auth, String userId) { - String subscribeEventName = getStringTableItem(5); - String stringVar0 = getStringTableItem(0); - String stringVar1 = getStringTableItem(1); - String stringVar2 = getStringTableItem(2); - String message = getStringTableItem(8); - message.replace(stringVar0, channel); - message.replace(stringVar1, auth); - message.replace(stringVar2, userId); - triggerEvent(subscribeEventName, message); + LogPrint(logMessageTablePusherClient, 3); + LogPrintLn(channel); } -void PusherClient::unsubscribe(String channel) { - String unsubscribeEventName = getStringTableItem(12); - String stringVar0 = getStringTableItem(0); - String message = getStringTableItem(9); +void PusherClient::unsubscribe(const String& channel) +{ + String unsubscribeEventName; + String stringVar0; + String message; + + getStringTableItem(12, unsubscribeEventName); + getStringTableItem(0, stringVar0); + getStringTableItem(9, message); + message.replace(stringVar0, channel); + triggerEvent(unsubscribeEventName, message); } -void PusherClient::triggerEvent(String eventName, String eventData) { - String stringVar0 = getStringTableItem(0); - String stringVar1 = getStringTableItem(1); - String message = getStringTableItem(10); - - message.replace(stringVar0, eventName); - message.replace(stringVar1, eventData); - - _client.send(message); +void PusherClient::KeepConnectionAlive() +{ + String pingEvent; + getStringTableItem(15, pingEvent); + _client.send(pingEvent); } - -void PusherClient::dataArrived(WebSocketClient client, String data) { - String eventNameStart = getStringTableItem(11); - String eventName = parseMessageMember(eventNameStart, data); +void PusherClient::dataArrived(const String& message) +{ + String paramName; + String eventName; + String eventData; + + getStringTableItem(11, paramName); + parseMessageMember(message, paramName, eventName); + + getStringTableItem(13, paramName); + parseMessageMember(message, paramName, eventData); if (_bindAllDelegate != NULL) { - _bindAllDelegate(data); + _bindAllDelegate(eventName, eventData); } EventDelegate delegate = _bindMap[eventName]; if (delegate != NULL) { - delegate(data); + delegate(eventName, eventData); } } -String PusherClient::parseMessageMember(String memberName, String data) { - memberName = "\"" + memberName + "\""; - int memberDataStart = data.indexOf(memberName) + memberName.length(); +void PusherClient::parseMessageMember(const String& message, const String& name, String& value) +{ + //name must be in the "name" format + + int memberNameStart = message.indexOf(name); + if (memberNameStart == -1) + { + value = ""; + return; + } + + int memberDataStart = memberNameStart + name.length(); char currentCharacter; do { memberDataStart++; - currentCharacter = data.charAt(memberDataStart); + currentCharacter = message.charAt(memberDataStart); } while (currentCharacter == ' ' || currentCharacter == ':' || currentCharacter == '\"'); - - int memberDataEnd = memberDataStart; - bool isString = data.charAt(memberDataStart-1) == '\"'; + + int memberDataEnd = memberDataStart; + bool isString = message.charAt(memberDataStart-1) == '\"'; if (!isString) { do { memberDataEnd++; - currentCharacter = data.charAt(memberDataEnd); + currentCharacter = message.charAt(memberDataEnd); } while (currentCharacter != ' ' && currentCharacter != ','); } else { @@ -194,11 +302,130 @@ String PusherClient::parseMessageMember(String memberName, String data) { do { memberDataEnd++; previousCharacter = currentCharacter; - currentCharacter = data.charAt(memberDataEnd); + currentCharacter = message.charAt(memberDataEnd); } while (currentCharacter != '"' || previousCharacter == '\\'); } + + value = message.substring(memberDataStart, memberDataEnd); + value.replace("\\\"", "\""); +} + +#if (ENABLE_AUTH == 1) +void connectionEstablished(const String& eventName, const String& eventData) +{ + Pusher.acquireSocketId(eventData); +} + +void PusherClient::acquireSocketId(const String& eventData) +{ + String socketIdName; + getStringTableItem(18, socketIdName); + parseMessageMember(eventData, socketIdName, _socketid); +} + +void PusherClient::triggerEvent(const String& eventName, const String& eventData) +{ + String stringVar; + String message; - String result = data.substring(memberDataStart, memberDataEnd); - result.replace("\\\"", "\""); - return result; + getStringTableItem(10, message); + + getStringTableItem(0, stringVar); + message.replace(stringVar, eventName); + + getStringTableItem(1, stringVar); + message.replace(stringVar, eventData); + + _client.send(message); + + LogPrint(logMessageTablePusherClient, 5); + LogPrintLn(eventName); } + +void PusherClient::getAuthString(const String& channel, String& auth) +{ + Sha256Class sha256; + + //Sha init with secret key + { + String secret; + getPusherInfoItem(2, secret); + sha256.initHmac((uint8_t*)&secret[0], secret.length()); + } + + //Set the data to encrypt + { + String text; + text.reserve(_socketid.length() + 1 + channel.length()); + text = _socketid; + text += ':'; + text += channel; + sha256.print(text); + } + + uint8_t* result = sha256.resultHmac(); + + String hexChars; + getStringTableItem(19, hexChars); + + auth.reserve(21 /*key*/ + 1 + 64 /*sha256*/); + getPusherInfoItem(1, auth); //key + auth += ':'; + for (int i=0; i<32; i++) + { + auth += hexChars.charAt(result[i]>>4); + auth += hexChars.charAt(result[i]&0xf); + } +} + +void PusherClient::subscribePrivate(const String& channel) +{ + String message; + getStringTableItem(7, message); + + { + String stringVar; + + { + String auth; + getStringTableItem(1, stringVar); + getAuthString(channel, auth); + message.replace(stringVar, auth); + LogPrintLn(message); + } + + getStringTableItem(0, stringVar); + message.replace(stringVar, channel); + LogPrintLn(message); + } + + String subscribeEventName; + getStringTableItem(5, subscribeEventName); + triggerEvent(subscribeEventName, message); +} + +void PusherClient::triggerPrivateEvent(const String& channelName, const String& eventName, const String& eventData) +{ + String stringVar0; + String stringVar1; + String stringVar2; + String message; + + getStringTableItem(0, stringVar0); + getStringTableItem(1, stringVar1); + getStringTableItem(2, stringVar2); + getStringTableItem(14, message); + + message.replace(stringVar0, eventName); + message.replace(stringVar1, eventData); + message.replace(stringVar2, channelName); + + _client.send(message); + + LogPrint(logMessageTablePusherClient, 5); + LogPrintLn(eventName); +} + +#endif + +PusherClient Pusher; diff --git a/PusherClient.h b/PusherClient.h index f679128..ff1112e 100644 --- a/PusherClient.h +++ b/PusherClient.h @@ -28,36 +28,63 @@ #include #include -#include -#include "Arduino.h" -#include +#include -//Uncomment this to use WIFLY Client -//#define WIFLY true +#include "HashMap/HashMap.h" +#include "WebSocketClient.h" +#include "Logger.h" -class PusherClient { +//Define ENABLE_AUTH as 1 to subscribe to private channels and send client events. +//Client events must be enabled from the pusher web configuration page. +#define ENABLE_AUTH 1 +typedef void (*EventDelegate)(const String& name, const String& data); + +class PusherClient +{ public: PusherClient(); - typedef void (*EventDelegate)(String data); - bool connect(String appId); - bool connected(); - void disconnect(); + + bool connect(); void monitor(); + + bool connected(); + void disconnect(); + + void bind(const String& eventName, EventDelegate delegate); void bindAll(EventDelegate delegate); - void bind(String eventName, EventDelegate delegate); - void subscribe(String channel); - void subscribe(String channel, String auth); - void subscribe(String channel, String auth, String userId); - void triggerEvent(String eventName, String eventData); - void unsubscribe(String channel); - private: - String _appId; + + void subscribe(const String& channel); + void unsubscribe(const String& channel); + + void triggerEvent(const String& eventName, const String& eventData); + +#if (ENABLE_AUTH == 1) + void acquireSocketId(const String& eventData); + void subscribePrivate(const String& channel); + void triggerPrivateEvent(const String& channelName, const String& eventName, const String& eventData); +#endif + + void KeepConnectionAlive(); + + private: + static void getStringTableItem(int index, String& text); + static void getPusherInfoItem(int index, String& text); + static void dataArrived(const String& data); + static void parseMessageMember(const String& message, const String& name, String& value); + + private: WebSocketClient _client; - static String getStringTableItem(int index); - static void dataArrived(WebSocketClient client, String data); - static String parseMessageMember(String memberName, String data); + unsigned long lastPingTime; + +#if (ENABLE_AUTH == 1) + void getAuthString(const String& channel, String& auth); + void computeSha256(const String& text, String& sha); + String _socketid; +#endif + }; +extern PusherClient Pusher; #endif diff --git a/README.md b/README.md index 10a5f52..126420b 100644 --- a/README.md +++ b/README.md @@ -3,30 +3,45 @@ Blog: [World Domination Using Arduinos And Websockets](http://kevinrohling.wordp [Pusher] (http://www.pusherapp.com) is a Push Notification service that uses Websockets for relaying messages back and forth between clients. This allows real time messaging between a diverse range of applications running on Web browsers, mobile devices and now Arduinos. It is my hope that allowing devices to easily send information about themselves as well as respond to messages received from applications and other devices will result in some interesting applications. +This fork adds support for private channel subscription (the auth string is computed internally), client event triggering, ping-pong events (to keep connection alive). + +Since Arduino has very little RAM, remember to reduce memory allocations and fragmentation as much as possible. Each variable of type String should be passed by reference if possible. So function "void function(const String& i_param)" is ok, while "void function(String i_param)" is not (since it will cause Arduino to allocate a new String). + ## Installation instructions Once you've cloned this repo locally, copy the ArduinoPusherClient directory into your Arduino Sketchbook directory under Libraries then restart the Arduino IDE so that it notices the new library. Now, under File\Examples you should see ArduinoPusherClient. To use the library in your app, select Sketch\Import Library\ArduinoPusherClient. +Remember to add your api id, key and secret inside pusherAppId, pusherKey and pusherSecret in PusherClient.cpp. + ## Examples -Included with this library is an example, called RobotExample, that uses Pusher events to drive two Servos. This example connects to a channel named "robot_channel" and binds to 5 events: forward, backward, turn_left, turn_right, and stop. When the events are received the appropriate method gets called and adjusts the angle of the servo motors, driving the robot. +Included with this library are 2 example: +1) RobotExample, that uses Pusher events to drive two Servos. This example connects to a channel named "robot_channel" and binds to 5 events: forward, backward, turn_left, turn_right, and stop. When the events are received the appropriate method gets called and adjusts the angle of the servo motors, driving the robot. +2) private_channels, that register the client to a private channel, triggering client events into it. ## How To Use This Library ### Connecting to Pusher -``` -PusherClient client; +Include the main header file: +#include -if(client.connect("your-api-key-here")) { - //Connected! +Initialize Serial (for logging) and the ethernet lib: +Serial.begin(9600); +byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; +if (!Ethernet.begin(mac)) { + //error } -else { - //Uh oh. + + +Initialize the pusher lib: +if(!Pusher.connect()) { + //error } +Add the monitor function inside the loop function. void loop() { - client.monitor(); //Must have a call to monitor() inside loop() + Pusher.monitor(); //Must have a call to monitor() inside loop() } ``` @@ -38,10 +53,7 @@ void loop() { client.subscribe("my-channel"); //Subscribing to a Private Channel -client.subscribe("private-my-channel", "my-auth-token"); - -//Subscribing to a Presence Channel -client.subscribe("presence-my-channel", "my-auth-token", "my-user-id"); +client.subscribePrivate("private-my-channel"); //Unsubscribing to a Channel client.unsubscribe("my-channel"); @@ -52,6 +64,7 @@ client.unsubscribe("my-channel"); ``` client.triggerEvent("my-event", "some data about my-event"); +client.triggerPrivateEvent("private-my-channel", "client-my-event", "some data about my-event"); ``` ### Binding to Events @@ -59,7 +72,7 @@ client.triggerEvent("my-event", "some data about my-event"); ``` client.bind("my-event", handleMyEvent); -void handleMyEvent(String data) { +void handleMyEvent(const String& eventName, const String& eventData) { //Do stuff here } ``` @@ -70,11 +83,11 @@ void handleMyEvent(String data) { ``` client.bindAll(handleAllEvents); -void handleAllEvents(String data) { +void handleAllEvents(const String& eventName, const String& eventData) { //Do stuff here } ``` ## Credits -Arduino Pusher Client uses the [HashMap](http://www.arduino.cc/playground/Code/HashMap) library developed by Alexander Brevig. \ No newline at end of file +Arduino Pusher Client uses the [HashMap](http://www.arduino.cc/playground/Code/HashMap) library developed by Alexander Brevig. diff --git a/WebSocketClient.cpp b/WebSocketClient.cpp index 8db4839..d9688e6 100644 --- a/WebSocketClient.cpp +++ b/WebSocketClient.cpp @@ -22,143 +22,235 @@ THE SOFTWARE. */ -#include -#include -#include -#include - -const char stringVar[] PROGMEM = "{0}"; -const char clientHandshakeLine1[] PROGMEM = "GET {0} HTTP/1.1"; -const char clientHandshakeLine2[] PROGMEM = "Upgrade: WebSocket"; -const char clientHandshakeLine3[] PROGMEM = "Connection: Upgrade"; -const char clientHandshakeLine4[] PROGMEM = "Host: {0}"; -const char clientHandshakeLine5[] PROGMEM = "Origin: ArduinoWebSocketClient"; -const char serverHandshake[] PROGMEM = "HTTP/1.1 101"; - -PGM_P const WebSocketClientStringTable[] PROGMEM = +#include "WebSocketClient.h" + +prog_char stringVar[] PROGMEM = "$"; +prog_char clientHandshakeLine1[] PROGMEM = "GET $ HTTP/1.1"; +prog_char clientHandshakeLine2[] PROGMEM = "Upgrade: WebSocket"; +prog_char clientHandshakeLine3[] PROGMEM = "Connection: Upgrade"; +prog_char clientHandshakeLine4[] PROGMEM = "Host: $"; +prog_char clientHandshakeLine5[] PROGMEM = "Origin: ArduinoWebSocketClient"; +prog_char serverHandshake[] PROGMEM = "HTTP/1.1 101"; + +prog_char logConnectingWS[] PROGMEM = "Connecting to host."; +prog_char logConnectionFailedWS[] PROGMEM = "Connection to host failed."; +prog_char logHandShakingWS[] PROGMEM = "Handshaking."; +prog_char logHandShakingFailedWS[] PROGMEM = "Handshaking failed."; +prog_char logSendingData[] PROGMEM = "Sending data: "; +prog_char logReceivedData[] PROGMEM = "Received data: "; + +PROGMEM const char* stringTableWebSocket[] = { - stringVar, - clientHandshakeLine1, - clientHandshakeLine2, - clientHandshakeLine3, - clientHandshakeLine4, - clientHandshakeLine5, - serverHandshake + stringVar, //0 + clientHandshakeLine1, //1 + clientHandshakeLine2, //2 + clientHandshakeLine3, //3 + clientHandshakeLine4, //4 + clientHandshakeLine5, //5 + serverHandshake //6 }; -String WebSocketClient::getStringSocketClientTableItem(int index) { - char buffer[35]; - strcpy_P(buffer, (char*)pgm_read_word(&(WebSocketClientStringTable[index]))); - return String(buffer); -} +PROGMEM const char* logMessageTableWebSocket[] = +{ + logConnectingWS, //0 + logConnectionFailedWS, //1 + logHandShakingWS, //2 + logHandShakingFailedWS, //3 + logSendingData, //4 + logReceivedData, //5 +}; -bool WebSocketClient::connect(char hostname[], char path[], int port) { - bool result = false; - - if (_client.connect(hostname, port)) { - sendHandshake(hostname, path); - result = readHandshake(); - } - - return result; +void WebSocketClient::getStringTableItem(int index, String& text) +{ + char* ptr = (char*)pgm_read_word(&(stringTableWebSocket[index])); + int len = strlen_P(ptr); + char buffer[len+1]; + strcpy_P(buffer, ptr); + text = buffer; } +bool WebSocketClient::connect(const String& hostname, const String& path, int port) +{ + LogPrintLn(logMessageTableWebSocket, 0); + char hostNameArray[32]; + hostname.toCharArray(hostNameArray, 32); + if (!_client.connect(hostNameArray, port)) + { + LogPrintLn(logMessageTableWebSocket, 1); + return false; + } + + LogPrintLn(logMessageTableWebSocket, 2); + if (!Handshake(hostname, path)) + { + LogPrintLn(logMessageTableWebSocket, 3); + return false; + } + + return true; +} -bool WebSocketClient::connected() { +bool WebSocketClient::connected() +{ return _client.connected(); } -void WebSocketClient::disconnect() { +void WebSocketClient::disconnect() +{ _client.stop(); } -void WebSocketClient::monitor() { - char character; - - if (_client.available() > 0 && (character = _client.read()) == 0) { - String data = ""; - bool endReached = false; - while (!endReached) { - character = _client.read(); - endReached = character == -1; - - if (!endReached) { - data += character; - } - } - - if (_dataArrivedDelegate != NULL) { - _dataArrivedDelegate(*this, data); - } - } +void WebSocketClient::setDataArrivedDelegate(DataArrivedDelegate dataArrivedDelegate) +{ + _dataArrivedDelegate = dataArrivedDelegate; } -void WebSocketClient::setDataArrivedDelegate(DataArrivedDelegate dataArrivedDelegate) { - _dataArrivedDelegate = dataArrivedDelegate; +bool WebSocketClient::Handshake(const String& hostname, const String& path) +{ + if (!SendHandshake(hostname, path)) + return false; + + if (!WaitHandshake(hostname, path)) + return false; + + return true; } +bool WebSocketClient::WaitHandshake(const String& hostname, const String& path) +{ + bool foundHandShake = false; + String line; + String param; -void WebSocketClient::sendHandshake(char hostname[], char path[]) { - String stringVar = getStringSocketClientTableItem(0); + //LogPrintLn("Wait to receive handshake"); + + int maxAttempts = 50, attempts; + for(attempts = 0; attempts < maxAttempts; attempts++) + { + if (_client.available()) + break; + + delay(100); + } + if (attempts == maxAttempts) + { + //LogPrintLn("Max attempts reached"); + return false; + } + + getStringTableItem(6, param); + while(readLine(line), line.length()!=0) + { + if (line.indexOf( param ) != -1) + foundHandShake = true; - String line1 = getStringSocketClientTableItem(1); - String line2 = getStringSocketClientTableItem(2); - String line3 = getStringSocketClientTableItem(3); - String line4 = getStringSocketClientTableItem(4); - String line5 = getStringSocketClientTableItem(5); - - line1.replace(stringVar, path); - line4.replace(stringVar, hostname); - - _client.println(line1); - _client.println(line2); - _client.println(line3); - _client.println(line4); - _client.println(line5); - _client.println(); + } + if (!foundHandShake) + return false; + + //LogPrintLn("Handshaking completed"); + return true; } -bool WebSocketClient::readHandshake() { - bool result = false; - char character; - String handshake = "", line; - int maxAttempts = 300, attempts = 0; - - while(_client.available() == 0 && attempts < maxAttempts) - { - delay(100); - attempts++; - } - - while((line = readLine()) != "") { - handshake += line + '\n'; - } - - String response = getStringSocketClientTableItem(6); - result = handshake.indexOf(response) != -1; +bool WebSocketClient::SendHandshake(const String& hostname, const String& path) +{ + String line; + String param; - if(!result) { - _client.stop(); - } - - return result; + //LogPrintLn("Sending first handshake"); + + getStringTableItem(0, param); + + //line 1 + getStringTableItem(1, line); + line.replace(param, path); + _client.println(line); + + //line 2 + getStringTableItem(2, line); + _client.println(line); + + //line 3 + getStringTableItem(3, line); + _client.println(line); + + //line 4 + getStringTableItem(4, line); + line.replace(param, hostname); + _client.println(line); + + //line 5 + getStringTableItem(5, line); + _client.println(line); + + //end of line + _client.println(); + _client.flush(); + + return true; } -String WebSocketClient::readLine() { - String line = ""; +void WebSocketClient::readLine(String& line) +{ char character; - while(_client.available() > 0 && (character = _client.read()) != '\n') { - if (character != '\r' && character != -1) { + line = ""; + + while(_client.available() > 0 && (character = _client.read()) != '\n') + { + if (character != '\r' && character != -1) + { line += character; } } - - return line; } -void WebSocketClient::send (String data) { +void WebSocketClient::send(const String& data) +{ + _client.print((char)0); + _client.print(data); + _client.print((char)255); + _client.flush(); + + LogPrint(logMessageTableWebSocket, 4); + LogPrintLn(data); +} + +void WebSocketClient::send(const char data[]) +{ _client.print((char)0); _client.print(data); _client.print((char)255); + _client.flush(); + + LogPrint(logMessageTableWebSocket, 4); + LogPrintLn(data); } + +void WebSocketClient::monitor() +{ + if (_client.available() > 0) + { + if (_client.read() == 0) + { + String message; + char character; + + message.reserve(128); + + while(character = _client.read(), character != -1) + { + message += character; + } + + LogPrint(logMessageTableWebSocket, 5); + LogPrintLn(message); + + if (_dataArrivedDelegate != NULL) + { + _dataArrivedDelegate(message); + } + } + } +} + diff --git a/WebSocketClient.h b/WebSocketClient.h index 0380113..107ad09 100644 --- a/WebSocketClient.h +++ b/WebSocketClient.h @@ -27,29 +27,35 @@ #include #include -#include #include -#include "Arduino.h" +#include -//Uncomment this to use WIFLY Client -#define WIFLY true +#include "Logger.h" class WebSocketClient { public: - typedef void (*DataArrivedDelegate)(WebSocketClient client, String data); - bool connect(char hostname[], char path[] = "/", int port = 80); + typedef void (*DataArrivedDelegate)(const String& data); + + bool connect(const String& hostname, const String& path, int port = 80); bool connected(); void disconnect(); void monitor(); void setDataArrivedDelegate(DataArrivedDelegate dataArrivedDelegate); - void send(String data); + + void send(const String& data); + void send(const char data[]); + private: - String getStringSocketClientTableItem(int index); - void sendHandshake(char hostname[], char path[]); - EthernetClient _client; + static void getStringTableItem(int index, String& text); + + bool Handshake(const String& hostname, const String& path); + bool SendHandshake(const String& hostname, const String& path); + bool WaitHandshake(const String& hostname, const String& path); + void readLine(String& line); + + private: + EthernetClient _client; DataArrivedDelegate _dataArrivedDelegate; - bool readHandshake(); - String readLine(); }; diff --git a/examples/private_channels/private_channels.ino b/examples/private_channels/private_channels.ino new file mode 100644 index 0000000..99d85a8 --- /dev/null +++ b/examples/private_channels/private_channels.ino @@ -0,0 +1,46 @@ +#include +#include + +#include + +void setup() +{ + Serial.begin(9600); + + byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; + if (Ethernet.begin(mac) == 0) + { + for(;;); + } + + if (!Pusher.connect()) + { + for(;;); + } + + Pusher.subscribePrivate("private-ChannelName"); + Pusher.triggerPrivateEvent("private-ChannelName", "client-eventName", "\"\""); +} + +unsigned long lasttime; +bool toggle; + +void loop() +{ + Pusher.monitor(); + + unsigned long time = millis(); + if (time > lasttime + 1000) + { + signalActualState(); + lasttime = time; + } +} + +void signalActualState() +{ + if (toggle) + Pusher.triggerPrivateEvent("private-ChannelName", "client-eventName", "\"1\""); + else + Pusher.triggerPrivateEvent("private-ChannelName", "client-eventName", "\"0\""); +} diff --git a/sha256.cpp b/sha256.cpp new file mode 100644 index 0000000..806c5c6 --- /dev/null +++ b/sha256.cpp @@ -0,0 +1,176 @@ +#include +#include +#include +#include "sha256.h" + +//#include "debugstuff.c" + +uint32_t sha256K[] PROGMEM = { + 0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5,0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5, + 0xd807aa98,0x12835b01,0x243185be,0x550c7dc3,0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174, + 0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc,0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da, + 0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7,0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967, + 0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13,0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85, + 0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3,0xd192e819,0xd6990624,0xf40e3585,0x106aa070, + 0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5,0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3, + 0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208,0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2 +}; + +#define BUFFER_SIZE 64 + +uint8_t sha256InitState[] PROGMEM = { + 0x67,0xe6,0x09,0x6a, // H0 + 0x85,0xae,0x67,0xbb, // H1 + 0x72,0xf3,0x6e,0x3c, // H2 + 0x3a,0xf5,0x4f,0xa5, // H3 + 0x7f,0x52,0x0e,0x51, // H4 + 0x8c,0x68,0x05,0x9b, // H5 + 0xab,0xd9,0x83,0x1f, // H6 + 0x19,0xcd,0xe0,0x5b // H7 +}; + +void Sha256Class::init(void) { + memcpy_P(state.b,sha256InitState,32); + byteCount = 0; + bufferOffset = 0; +} + +uint32_t Sha256Class::ror32(uint32_t number, uint8_t bits) { + return ((number << (32-bits)) | (number >> bits)); +} + +void Sha256Class::hashBlock() { + // Sha256 only for now + uint8_t i; + uint32_t a,b,c,d,e,f,g,h,t1,t2; + + a=state.w[0]; + b=state.w[1]; + c=state.w[2]; + d=state.w[3]; + e=state.w[4]; + f=state.w[5]; + g=state.w[6]; + h=state.w[7]; + + for (i=0; i<64; i++) { + if (i>=16) { + t1 = buffer.w[i&15] + buffer.w[(i-7)&15]; + t2 = buffer.w[(i-2)&15]; + t1 += ror32(t2,17) ^ ror32(t2,19) ^ (t2>>10); + t2 = buffer.w[(i-15)&15]; + t1 += ror32(t2,7) ^ ror32(t2,18) ^ (t2>>3); + buffer.w[i&15] = t1; + } + t1 = h; + t1 += ror32(e,6) ^ ror32(e,11) ^ ror32(e,25); // ∑1(e) + t1 += g ^ (e & (g ^ f)); // Ch(e,f,g) + t1 += pgm_read_dword(sha256K+i); // Ki + t1 += buffer.w[i&15]; // Wi + t2 = ror32(a,2) ^ ror32(a,13) ^ ror32(a,22); // ∑0(a) + t2 += ((b & c) | (a & (b | c))); // Maj(a,b,c) + h=g; g=f; f=e; e=d+t1; d=c; c=b; b=a; a=t1+t2; + } + state.w[0] += a; + state.w[1] += b; + state.w[2] += c; + state.w[3] += d; + state.w[4] += e; + state.w[5] += f; + state.w[6] += g; + state.w[7] += h; +} + +void Sha256Class::addUncounted(uint8_t data) { + buffer.b[bufferOffset ^ 3] = data; + bufferOffset++; + if (bufferOffset == BUFFER_SIZE) { + hashBlock(); + bufferOffset = 0; + } +} + +size_t Sha256Class::write(uint8_t data) { + ++byteCount; + addUncounted(data); + return 0; +} + +void Sha256Class::pad() { + // Implement SHA-256 padding (fips180-2 §5.1.1) + + // Pad with 0x80 followed by 0x00 until the end of the block + addUncounted(0x80); + while (bufferOffset != 56) addUncounted(0x00); + + // Append length in the last 8 bytes + addUncounted(0); // We're only using 32 bit lengths + addUncounted(0); // But SHA-1 supports 64 bit lengths + addUncounted(0); // So zero pad the top bits + addUncounted(byteCount >> 29); // Shifting to multiply by 8 + addUncounted(byteCount >> 21); // as SHA-1 supports bitstreams as well as + addUncounted(byteCount >> 13); // byte. + addUncounted(byteCount >> 5); + addUncounted(byteCount << 3); +} + + +uint8_t* Sha256Class::result(void) { + // Pad to complete the last block + pad(); + + // Swap byte order back + for (int i=0; i<8; i++) { + uint32_t a,b; + a=state.w[i]; + b=a<<24; + b|=(a<<8) & 0x00ff0000; + b|=(a>>8) & 0x0000ff00; + b|=a>>24; + state.w[i]=b; + } + + // Return pointer to hash (20 characters) + return state.b; +} + + +#define HMAC_IPAD 0x36 +#define HMAC_OPAD 0x5c + +uint8_t keyBuffer[BLOCK_LENGTH]; // K0 in FIPS-198a +uint8_t innerHash[HASH_LENGTH]; + +void Sha256Class::initHmac(const uint8_t* key, int keyLength) { + uint8_t i; + memset(keyBuffer,0,BLOCK_LENGTH); + if (keyLength > BLOCK_LENGTH) { + // Hash long keys + init(); + for (;keyLength--;) write(*key++); + memcpy(keyBuffer,result(),HASH_LENGTH); + } else { + // Block length keys are used as is + memcpy(keyBuffer,key,keyLength); + } + //for (i=0; i +#include "Print.h" + +#define HASH_LENGTH 32 +#define BLOCK_LENGTH 64 + +union _buffer { + uint8_t b[BLOCK_LENGTH]; + uint32_t w[BLOCK_LENGTH/4]; +}; +union _state { + uint8_t b[HASH_LENGTH]; + uint32_t w[HASH_LENGTH/4]; +}; + +class Sha256Class : public Print +{ + public: + void init(void); + void initHmac(const uint8_t* secret, int secretLength); + uint8_t* result(void); + uint8_t* resultHmac(void); + virtual size_t write(uint8_t); + using Print::write; + private: + void pad(); + void addUncounted(uint8_t data); + void hashBlock(); + uint32_t ror32(uint32_t number, uint8_t bits); + _buffer buffer; + uint8_t bufferOffset; + _state state; + uint32_t byteCount; + uint8_t keyBuffer[BLOCK_LENGTH]; + uint8_t innerHash[HASH_LENGTH]; +}; +//extern Sha256Class Sha256; + +#endif From e1de80645c7fa31cd2050149bf4ee8c637a0681f Mon Sep 17 00:00:00 2001 From: Dave Date: Thu, 17 Feb 2022 12:50:29 +0100 Subject: [PATCH 5/6] removed all pgm stuff as the RP2040 can't work with that --- Logger.h | 15 ++++----- PusherClient.cpp | 75 ++++++++++++++++++++++----------------------- WebSocketClient.cpp | 39 ++++++++++++----------- sha256.cpp | 12 ++++---- 4 files changed, 68 insertions(+), 73 deletions(-) diff --git a/Logger.h b/Logger.h index 03f1311..0308cae 100644 --- a/Logger.h +++ b/Logger.h @@ -4,22 +4,19 @@ #define LOGGER_ENABLED 1 #if LOGGER_ENABLED -inline void LogPrint(PROGMEM const char** table, int index) +inline void LogPrint(const char** table, int index) { - char* ptr = (char*)pgm_read_word(&(table[index])); - int len = strlen_P(ptr); + int len = strlen(table[index]); char buffer[len+1]; - strcpy_P(buffer, ptr); - + strcpy(buffer, table[index]); Serial.print(buffer); } -inline void LogPrintLn(PROGMEM const char** table, int index) +inline void LogPrintLn(const char** table, int index) { - char* ptr = (char*)pgm_read_word(&(table[index])); - int len = strlen_P(ptr); + int len = strlen(table[index]); char buffer[len+1]; - strcpy_P(buffer, ptr); + strcpy(buffer, table[index]); Serial.println(buffer); Serial.flush(); diff --git a/PusherClient.cpp b/PusherClient.cpp index 2b93a19..8a059a7 100644 --- a/PusherClient.cpp +++ b/PusherClient.cpp @@ -32,48 +32,48 @@ static HashMap _bindMap = HashMap -#include -#include +// #include +// #include #include "sha256.h" //#include "debugstuff.c" -uint32_t sha256K[] PROGMEM = { +uint32_t sha256K[] = { 0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5,0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5, 0xd807aa98,0x12835b01,0x243185be,0x550c7dc3,0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174, 0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc,0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da, @@ -18,7 +18,7 @@ uint32_t sha256K[] PROGMEM = { #define BUFFER_SIZE 64 -uint8_t sha256InitState[] PROGMEM = { +uint8_t sha256InitState[] = { 0x67,0xe6,0x09,0x6a, // H0 0x85,0xae,0x67,0xbb, // H1 0x72,0xf3,0x6e,0x3c, // H2 @@ -30,7 +30,7 @@ uint8_t sha256InitState[] PROGMEM = { }; void Sha256Class::init(void) { - memcpy_P(state.b,sha256InitState,32); + memcpy(state.b,sha256InitState, 32); byteCount = 0; bufferOffset = 0; } @@ -65,7 +65,7 @@ void Sha256Class::hashBlock() { t1 = h; t1 += ror32(e,6) ^ ror32(e,11) ^ ror32(e,25); // ∑1(e) t1 += g ^ (e & (g ^ f)); // Ch(e,f,g) - t1 += pgm_read_dword(sha256K+i); // Ki + t1 += sha256K[i]; // Ki t1 += buffer.w[i&15]; // Wi t2 = ror32(a,2) ^ ror32(a,13) ^ ror32(a,22); // ∑0(a) t2 += ((b & c) | (a & (b | c))); // Maj(a,b,c) From 622509bb5bec4478f974aa41c375d8df6ce5b612 Mon Sep 17 00:00:00 2001 From: Dave Date: Thu, 17 Feb 2022 14:17:29 +0100 Subject: [PATCH 6/6] more debug and resetting socketid --- PusherClient.cpp | 17 ++++++++++++----- WebSocketClient.cpp | 9 +++++---- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/PusherClient.cpp b/PusherClient.cpp index 8a059a7..249a40c 100644 --- a/PusherClient.cpp +++ b/PusherClient.cpp @@ -45,8 +45,8 @@ const char* pusherInfos[] = const char stringVar0[] = "#1"; const char stringVar1[] = "#2"; const char stringVar2[] = "#3"; -const char pusherPath[] = "/app/#1?client=js&version=1.9.0"; -const char pusherHostname[] = "ws.pusherapp.com"; +const char pusherPath[] = "/app/#1?client=js&version=2.2.3&flash=false&protocol=7"; // "/app/#1?client=js&version=1.9.0"; +const char pusherHostname[] = "ws-eu.pusher.com"; const char subscribeEventName[] = "pusher:subscribe"; const char subscribeMessage1[] = "{\"channel\":\"#1\"}"; const char subscribeMessage2[] = "{\"channel\":\"#1\",\"auth\":\"#2\"}"; @@ -147,15 +147,20 @@ bool PusherClient::connect() getPusherInfoItem(1, key); path.replace(stringVar0, key); + Serial.println(host); + Serial.println(path); + if (!_client.connect(host, path, 80)) { LogPrintLn(logMessageTablePusherClient, 0); return false; } + #if (ENABLE_AUTH == 1) while(_socketid.length() == 0) - { + { + Serial.println(_socketid); delay(100); monitor(); } @@ -170,8 +175,9 @@ bool PusherClient::connected() return _client.connected(); } -void PusherClient::disconnect() +void PusherClient::disconnect() { + _socketid = ""; _client.disconnect(); } @@ -271,7 +277,7 @@ void PusherClient::dataArrived(const String& message) void PusherClient::parseMessageMember(const String& message, const String& name, String& value) { //name must be in the "name" format - + Serial.println(message); int memberNameStart = message.indexOf(name); if (memberNameStart == -1) { @@ -312,6 +318,7 @@ void PusherClient::parseMessageMember(const String& message, const String& name, #if (ENABLE_AUTH == 1) void connectionEstablished(const String& eventName, const String& eventData) { + Serial.println("connectionEstablished"); Pusher.acquireSocketId(eventData); } diff --git a/WebSocketClient.cpp b/WebSocketClient.cpp index c9dd750..b645f62 100644 --- a/WebSocketClient.cpp +++ b/WebSocketClient.cpp @@ -121,7 +121,7 @@ bool WebSocketClient::WaitHandshake(const String& hostname, const String& path) String line; String param; - //LogPrintLn("Wait to receive handshake"); + LogPrintLn("Wait to receive handshake"); int maxAttempts = 50, attempts; for(attempts = 0; attempts < maxAttempts; attempts++) @@ -133,7 +133,7 @@ bool WebSocketClient::WaitHandshake(const String& hostname, const String& path) } if (attempts == maxAttempts) { - //LogPrintLn("Max attempts reached"); + LogPrintLn("Max attempts reached"); return false; } @@ -147,7 +147,7 @@ bool WebSocketClient::WaitHandshake(const String& hostname, const String& path) if (!foundHandShake) return false; - //LogPrintLn("Handshaking completed"); + LogPrintLn("Handshaking completed"); return true; } @@ -156,13 +156,14 @@ bool WebSocketClient::SendHandshake(const String& hostname, const String& path) String line; String param; - //LogPrintLn("Sending first handshake"); + LogPrintLn("Sending first handshake"); getStringTableItem(0, param); //line 1 getStringTableItem(1, line); line.replace(param, path); + _client.println(line); //line 2