-
-
Notifications
You must be signed in to change notification settings - Fork 3
/
comm_tcp_socket_server.cpp
260 lines (203 loc) · 5.51 KB
/
comm_tcp_socket_server.cpp
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
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
// (C) 2024 by Folkert van Heusden
// Released under MIT license
#include "gen.h"
#if defined(ESP32)
#include <Arduino.h>
#endif
#if defined(ESP32)
#include <lwip/sockets.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <driver/uart.h>
#elif defined(_WIN32)
#include <ws2tcpip.h>
#include <winsock2.h>
#else
#include <poll.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#endif
#include <cstring>
#if IS_POSIX
#include <errno.h>
#include <fcntl.h>
#include <termios.h>
#include <thread>
#include <unistd.h>
#endif
#include "comm_tcp_socket_server.h"
#include "log.h"
#include "utils.h"
static bool setup_telnet_session(const int fd)
{
uint8_t dont_auth[] = { 0xff, 0xf4, 0x25 };
uint8_t suppress_goahead[] = { 0xff, 0xfb, 0x03 };
uint8_t dont_linemode[] = { 0xff, 0xfe, 0x22 };
uint8_t dont_new_env[] = { 0xff, 0xfe, 0x27 };
uint8_t will_echo[] = { 0xff, 0xfb, 0x01 };
uint8_t dont_echo[] = { 0xff, 0xfe, 0x01 };
uint8_t noecho[] = { 0xff, 0xfd, 0x2d };
// uint8_t charset[] = { 0xff, 0xfb, 0x01 };
if (write(fd, dont_auth, sizeof dont_auth) != sizeof dont_auth)
return false;
if (write(fd, suppress_goahead, sizeof suppress_goahead) != sizeof suppress_goahead)
return false;
if (write(fd, dont_linemode, sizeof dont_linemode) != sizeof dont_linemode)
return false;
if (write(fd, dont_new_env, sizeof dont_new_env) != sizeof dont_new_env)
return false;
if (write(fd, will_echo, sizeof will_echo) != sizeof will_echo)
return false;
if (write(fd, dont_echo, sizeof dont_echo) != sizeof dont_echo)
return false;
if (write(fd, noecho, sizeof noecho) != sizeof noecho)
return false;
return true;
}
comm_tcp_socket_server::comm_tcp_socket_server(const int port) : port(port)
{
}
comm_tcp_socket_server::~comm_tcp_socket_server()
{
stop_flag = true;
if (th) {
th->join();
delete th;
}
if (fd != INVALID_SOCKET)
close(fd);
if (cfd != INVALID_SOCKET)
close(cfd);
DOLOG(debug, false, "comm_tcp_socket_server: destructor for port %d finished", port);
}
bool comm_tcp_socket_server::begin()
{
th = new std::thread(std::ref(*this));
return true;
}
bool comm_tcp_socket_server::is_connected()
{
std::unique_lock<std::mutex> lck(cfd_lock);
return cfd != INVALID_SOCKET;
}
bool comm_tcp_socket_server::has_data()
{
std::unique_lock<std::mutex> lck(cfd_lock);
#if defined(_WIN32)
WSAPOLLFD fds[] { { cfd, POLLIN, 0 } };
int rc = WSAPoll(fds, 1, 0);
#else
pollfd fds[] { { cfd, POLLIN, 0 } };
int rc = poll(fds, 1, 0);
#endif
return rc == 1;
}
uint8_t comm_tcp_socket_server::get_byte()
{
int use_fd = -1;
{
std::unique_lock<std::mutex> lck(cfd_lock);
use_fd = cfd;
}
uint8_t c = 0;
if (read(use_fd, &c, 1) <= 0) {
DOLOG(warning, false, " comm_tcp_socket_server::get_byte failed");
std::unique_lock<std::mutex> lck(cfd_lock);
close(cfd);
cfd = INVALID_SOCKET;
}
return c;
}
void comm_tcp_socket_server::send_data(const uint8_t *const in, const size_t n)
{
const uint8_t *p = in;
size_t len = n;
while(len > 0) {
std::unique_lock<std::mutex> lck(cfd_lock);
int rc = write(cfd, p, len);
if (rc <= 0) { // TODO error checking
DOLOG(warning, false, " comm_tcp_socket_server::send_data failed");
close(cfd);
cfd = INVALID_SOCKET;
break;
}
p += rc;
len -= rc;
}
}
void comm_tcp_socket_server::operator()()
{
set_thread_name("kek:COMMTCPS");
DOLOG(info, true, "TCP comm thread started for port %d", port);
fd = socket(AF_INET, SOCK_STREAM, 0);
int reuse_addr = 1;
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast<char *>(&reuse_addr), sizeof(reuse_addr)) == -1) {
close(fd);
fd = INVALID_SOCKET;
DOLOG(warning, true, "Cannot set reuseaddress for port %d (comm_tcp_socket_server)", port);
return;
}
set_nodelay(fd);
sockaddr_in listen_addr;
memset(&listen_addr, 0, sizeof(listen_addr));
listen_addr.sin_family = AF_INET;
listen_addr.sin_addr.s_addr = htonl(INADDR_ANY);
listen_addr.sin_port = htons(port);
if (bind(fd, reinterpret_cast<struct sockaddr *>(&listen_addr), sizeof(listen_addr)) == -1) {
DOLOG(warning, true, "Cannot bind to port %d (send_datacomm_tcp_socket_server): %s", port, strerror(errno));
close(fd);
fd = INVALID_SOCKET;
return;
}
if (listen(fd, SOMAXCONN) == -1) {
close(fd);
fd = INVALID_SOCKET;
DOLOG(warning, true, "Cannot listen on port %d (comm_tcp_socket_server)", port);
return;
}
#if defined(_WIN32)
WSAPOLLFD fds[] { { fd, POLLIN, 0 } };
#else
pollfd fds[] { { fd, POLLIN, 0 } };
#endif
while(!stop_flag) {
#if defined(_WIN32)
int rc = WSAPoll(fds, 1, 100);
#else
int rc = poll(fds, 1, 100);
#endif
if (rc == 0)
continue;
std::unique_lock<std::mutex> lck(cfd_lock);
// disconnect any existing client session
// yes, one can 'DOS' with this
if (cfd != INVALID_SOCKET) {
close(cfd);
DOLOG(info, false, "Restarting session for port %d", port);
}
cfd = accept(fd, nullptr, nullptr);
if (cfd != INVALID_SOCKET) {
set_nodelay(cfd);
DOLOG(info, false, "Connected with %s", get_endpoint_name(cfd).c_str());
}
#if 0
if (setup_telnet_session(cfd) == false) {
close(cfd);
cfd = INVALID_SOCKET;
}
#endif
}
DOLOG(info, true, "comm_tcp_socket_server thread terminating");
}
JsonDocument comm_tcp_socket_server::serialize() const
{
JsonDocument j;
j["comm-backend-type"] = "tcp-server";
j["port"] = port;
return j;
}
comm_tcp_socket_server *comm_tcp_socket_server::deserialize(const JsonVariantConst j)
{
comm_tcp_socket_server *r = new comm_tcp_socket_server(j["port"].as<int>());
return r;
}