REDAC HybridController
Firmware for LUCIDAC/REDAC Teensy
Loading...
Searching...
No Matches
jsonl_server.cpp
Go to the documentation of this file.
1// Copyright (c) 2024 anabrid GmbH
2// Contact: https://www.anabrid.com/licensing/
3//
4// SPDX-License-Identifier: MIT OR GPL-2.0-or-later
5
6#include "protocol/jsonl_server.h"
7
8#include "net/ethernet.h"
9#include "protocol/protocol.h"
10#include "utils/logging.h"
11
12void msg::JsonlServer::begin() { server.begin(net::StartupConfig::get().jsonl_port); }
13
14void msg::JsonlServer::loop() {
15 net::EthernetClient client_socket = server.accept();
16
17 if (client_socket) {
18 // note that the following code copies "socket" object multiple times. When using pointers into
19 // the struct, do not use the pointer to the wrong version.
20 // TODO: Clean up code.
21 Client client;
22 client.user_context.set_remote_identifier(net::auth::RemoteIdentifier{client_socket.remoteIP()});
23 client.socket = std::move(client_socket);
24
25 // note there is also net::EthernetClient::maxSockets(), which is dominated by basic system constraints.
26 // This limit here is rather dominated by application level constraints and can probably be a counter
27 // measure against ddos attacks.
28 if (clients.size() == net::StartupConfig::get().max_connections) {
29 LOG5("Cannot accept client from ", client.socket.remoteIP(), " because maximum number of connections (",
30 net::StartupConfig::get().max_connections, ") already reached.");
31 client.socket.stop();
32 } else {
33 LOG4("Client ", static_cast<unsigned>(clients.size()), " connected from ", client.socket.remoteIP());
34 clients.push_back(std::move(client));
35 msg::JsonLinesProtocol::get().broadcast.add(&(std::prev(clients.end())->socket));
36 }
37 }
38
39 // using iterator instead range-based loop because EthernetClient lacks == operator
40 // so we use list::erase instead of list::remove.
41 for (auto client = clients.begin(); client != clients.end(); ++client) {
42 const auto client_idx = std::distance(clients.begin(), client);
43 if (client->socket.connected()) {
44 if (client->socket.available() > 0) {
45 msg::JsonLinesProtocol::get().process_tcp_input(client->socket, client->user_context);
46 client->last_contact.reset();
47 } else if (client->last_contact.expired(net::StartupConfig::get().connection_timeout_ms)) {
48 LOG5("Client ", static_cast<unsigned>(client_idx), ", timed out after ",
49 net::StartupConfig::get().connection_timeout_ms, " ms of idling");
50 client->socket.stop();
51 }
52 } else {
53 LOG5("Client ", static_cast<unsigned>(client_idx), ", was ", client->user_context, ", disconnected");
54 msg::JsonLinesProtocol::get().broadcast.remove(&client->socket);
55 client->socket.stop(); // important, stop waits
56 clients.erase(client);
57 return; // iterator invalidated, better start loop() freshly.
58 }
59 }
60}