Let us start here, from square one. No, from Zero!
This commit is contained in:
@@ -0,0 +1,169 @@
|
||||
#ifndef SPICEAPI_CONNECTION_H
|
||||
#define SPICEAPI_CONNECTION_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include "rc4.h"
|
||||
|
||||
#ifndef SPICEAPI_INTERFACE
|
||||
#define SPICEAPI_INTERFACE Serial
|
||||
#endif
|
||||
|
||||
namespace spiceapi {
|
||||
|
||||
class Connection {
|
||||
private:
|
||||
uint8_t* receive_buffer;
|
||||
size_t receive_buffer_size;
|
||||
const char* password;
|
||||
RC4* cipher;
|
||||
|
||||
public:
|
||||
Connection(size_t receive_buffer_size, const char* password = "");
|
||||
~Connection();
|
||||
|
||||
void reset();
|
||||
|
||||
bool check();
|
||||
void cipher_alloc(const char *session_key = nullptr);
|
||||
void change_pass(const char* password, bool session = false);
|
||||
const char* request(const char* json, size_t timeout = 1000);
|
||||
const char* request(char* json, size_t timeout = 1000);
|
||||
};
|
||||
}
|
||||
|
||||
spiceapi::Connection::Connection(size_t receive_buffer_size, const char* password) {
|
||||
this->receive_buffer = new uint8_t[receive_buffer_size];
|
||||
this->receive_buffer_size = receive_buffer_size;
|
||||
this->password = password;
|
||||
this->cipher = nullptr;
|
||||
this->reset();
|
||||
}
|
||||
|
||||
spiceapi::Connection::~Connection() {
|
||||
|
||||
// clean up
|
||||
if (this->cipher != nullptr)
|
||||
delete this->cipher;
|
||||
}
|
||||
|
||||
void spiceapi::Connection::reset() {
|
||||
|
||||
// drop all input
|
||||
while (SPICEAPI_INTERFACE.available()) {
|
||||
SPICEAPI_INTERFACE.read();
|
||||
}
|
||||
|
||||
#ifdef SPICEAPI_INTERFACE_WIFICLIENT
|
||||
// reconnect TCP client
|
||||
SPICEAPI_INTERFACE.stop();
|
||||
this->check();
|
||||
#else
|
||||
// 8 zeroes reset the password/session on serial
|
||||
for (size_t i = 0; i < 8; i++) {
|
||||
SPICEAPI_INTERFACE.write((int) 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
// reset password
|
||||
this->cipher_alloc();
|
||||
}
|
||||
|
||||
void spiceapi::Connection::cipher_alloc(const char *session_key) {
|
||||
|
||||
// delete old cipher
|
||||
if (this->cipher != nullptr) {
|
||||
delete this->cipher;
|
||||
this->cipher = nullptr;
|
||||
}
|
||||
|
||||
// create new cipher if password is set
|
||||
session_key = session_key ? session_key : this->password;
|
||||
if (strlen(session_key) > 0) {
|
||||
this->cipher = new RC4(
|
||||
(uint8_t *) session_key,
|
||||
strlen(session_key));
|
||||
}
|
||||
}
|
||||
|
||||
bool spiceapi::Connection::check() {
|
||||
#ifdef SPICEAPI_INTERFACE_WIFICLIENT
|
||||
if (!SPICEAPI_INTERFACE.connected()) {
|
||||
return SPICEAPI_INTERFACE.connect(
|
||||
SPICEAPI_INTERFACE_WIFICLIENT_HOST,
|
||||
SPICEAPI_INTERFACE_WIFICLIENT_PORT);
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
#else
|
||||
// serial is always valid
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
void spiceapi::Connection::change_pass(const char* password, bool session) {
|
||||
if (!session) {
|
||||
this->password = password;
|
||||
}
|
||||
this->cipher_alloc(password);
|
||||
}
|
||||
|
||||
const char* spiceapi::Connection::request(const char* json, size_t timeout) {
|
||||
auto json_len = strlen(json);
|
||||
strncpy((char*) receive_buffer, json, receive_buffer_size);
|
||||
return request((char*) receive_buffer, timeout);
|
||||
}
|
||||
|
||||
const char* spiceapi::Connection::request(char* json_data, size_t timeout) {
|
||||
|
||||
// check connection
|
||||
if (!this->check())
|
||||
return "";
|
||||
|
||||
// crypt
|
||||
auto json_len = strlen(json_data) + 1;
|
||||
if (this->cipher != nullptr)
|
||||
this->cipher->crypt((uint8_t*) json_data, json_len);
|
||||
|
||||
// send
|
||||
auto send_result = SPICEAPI_INTERFACE.write((const char*) json_data, (int) json_len);
|
||||
SPICEAPI_INTERFACE.flush();
|
||||
if (send_result < (int) json_len) {
|
||||
return "";
|
||||
}
|
||||
|
||||
// receive
|
||||
size_t receive_data_len = 0;
|
||||
auto t_start = millis();
|
||||
while (SPICEAPI_INTERFACE) {
|
||||
|
||||
// check for timeout
|
||||
if (millis() - t_start > timeout) {
|
||||
this->reset();
|
||||
return "";
|
||||
}
|
||||
|
||||
// read single byte
|
||||
auto b = SPICEAPI_INTERFACE.read();
|
||||
if (b < 0) continue;
|
||||
receive_buffer[receive_data_len++] = b;
|
||||
|
||||
// check for buffer overflow
|
||||
if (receive_data_len >= receive_buffer_size) {
|
||||
this->reset();
|
||||
return "";
|
||||
}
|
||||
|
||||
// crypt
|
||||
if (this->cipher != nullptr)
|
||||
this->cipher->crypt(&receive_buffer[receive_data_len - 1], 1);
|
||||
|
||||
// check for message end
|
||||
if (receive_buffer[receive_data_len - 1] == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
// return resulting json
|
||||
return (const char*) &receive_buffer[0];
|
||||
}
|
||||
|
||||
#endif //SPICEAPI_CONNECTION_H
|
||||
Reference in New Issue
Block a user