-
Notifications
You must be signed in to change notification settings - Fork 1
/
connection.h
173 lines (140 loc) · 4.23 KB
/
connection.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
#ifndef SPICEAPI_CONNECTION_H
#define SPICEAPI_CONNECTION_H
#include <stdint.h>
#include "rc4.h"
#ifndef SPICEAPI_INTERFACE
#define SPICEAPI_INTERFACE Serial
#endif
#ifndef SPICEDEBUG_INTERFACE
#define SPICEDEBUG_INTERFACE Serial1
#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(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