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 "proto/main.pb.h"
7#include "protocol/jsonl_server.h"
8
9#include "net/ethernet.h"
10#include "protocol/protocol.h"
11#include "utils/logging.h"
12
13void msg::ApplicationServer::begin() {
14 server.begin(net::StartupConfig::get().jsonl_port);
15}
16
17void msg::ApplicationServer::_accept_clients() {
18 net::EthernetClient client_socket = server.accept();
19
20 if (!client_socket) return;
21 auto remote_ip = client_socket.remoteIP();
22
23 // note there is also net::EthernetClient::maxSockets(), which is dominated by basic system constraints.
24 // This limit here is rather dominated by application level constraints and can probably be a counter
25 // measure against ddos attacks.
26 if (clients.size() == net::StartupConfig::get().max_connections) {
27 LOG5("Cannot accept client from ", remote_ip, " because maximum number of connections (",
28 net::StartupConfig::get().max_connections, ") already reached.");
29 client_socket.stop();
30 return;
31 }
32
33
34 // note that the following code copies "socket" object multiple times. When using pointers into
35 // the struct, do not use the pointer to the wrong version.
36 // TODO: Clean up code.
37 auto socket = std::make_shared<net::EthernetClient>(std::move(client_socket));
38
39 LOG4("Client ", static_cast<unsigned>(clients.size()), " connected from ", remote_ip);
40 auto& client = clients.emplace_back(ApplicationClient{
41 .socket = socket,
42 .transport = transport::Transport(
43 std::make_shared<transport::DelimitedInputStream<std::shared_ptr<Client>>>(socket),
44 std::make_shared<transport::DelimitedMessageOutputStream<std::shared_ptr<Client>>>(socket),
45 std::make_shared<transport::DelimitedMessageOutputStream<std::shared_ptr<Client>>>(socket),
46 remote_ip
47 ),
48 });
49
50 client.user_context.set_remote_identifier(net::auth::RemoteIdentifier{remote_ip});
51}
52
53void msg::ApplicationServer::_handle_clients() {
54 // using iterator instead range-based loop because EthernetClient lacks == operator
55 // so we use list::erase instead of list::remove.
56 for (auto it = clients.begin(); it != clients.end(); ++it) {
57 auto& client = *it;
58 auto& socket = client.socket;
59
60 if (socket->connected()) {
61 if (socket->available() > 0) {
62 Broker::get().process(client.transport);
63 client.last_contact.reset();
64 } else if (client.last_contact.expired(net::StartupConfig::get().connection_timeout_ms)) {
65 LOG3("Client timed out after ",
66 net::StartupConfig::get().connection_timeout_ms, " ms of idling");
67 socket->stop();
68 }
69 } else {
70 LOG3("Client was ", client.user_context, ", disconnected");
71 socket->stop(); // important, stop waits
72 clients.erase(it);
73 return; // iterator invalidated, better start loop() freshly.
74 }
75 }
76}
77
78
79void msg::ApplicationServer::loop() {
80 _accept_clients();
81 _handle_clients();
82 delay(100);
83}