1+ /* *
2+ * @file httpd.cpp
3+ * @brief HTTP daemon class for managing HTTP server tasks.
4+ *
5+ * This class handles HTTP requests and integrates with the network and mDNS subsystems.
6+ * It uses placement new to construct and destruct request handlers explicitly.
7+ */
8+ /* Copyright (C) 2025-2026 by Arjan van Vught mailto:info@gd32-dmx.org
9+ *
10+ * Permission is hereby granted, free of charge, to any person obtaining a copy
11+ * of this software and associated documentation files (the "Software"), to deal
12+ * in the Software without restriction, including without limitation the rights
13+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14+ * copies of the Software, and to permit persons to whom the Software is
15+ * furnished to do so, subject to the following conditions:
16+
17+ * The above copyright notice and this permission notice shall be included in
18+ * all copies or substantial portions of the Software.
19+
20+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
26+ * THE SOFTWARE.
27+ */
28+
29+ #include < cassert>
30+ #include < new>
31+
32+ #include " firmware/debug/debug_debug.h"
33+ #include " httpd/httpd.h"
34+ #include " network_tcp.h"
35+ #include " apps/mdns.h"
36+ #include " ../../lib-network/config/net_config.h"
37+
38+ /*
39+ * Define the storage exactly once, outside the header.
40+ *
41+ * gnu::used:
42+ * Ensures that the compiler emits the object.
43+ *
44+ * .httpd:
45+ * Is collected by the linker script into the dedicated HTTP RAM section.
46+ *
47+ * The linker script should contain:
48+ *
49+ * .http (NOLOAD) :
50+ * {
51+ * . = ALIGN(4);
52+ * _shttp = .;
53+ * KEEP(*(.http))
54+ * KEEP(*(.http.*))
55+ * KEEP(*(.httpd))
56+ * KEEP(*(.httpd.*))
57+ * . = ALIGN(4);
58+ * _ehttp = .;
59+ * } > RAM2
60+ */
61+ [[gnu::section(".httpd"), gnu::aligned(alignof(HttpDeamonHandleRequest)), gnu::used]]
62+ HttpDaemon::HandlerStorage HttpDaemon::s_handle_request_storage[TCP_MAX_TCBS_ALLOWED ];
63+
64+ HttpDaemon::HttpDaemon () {
65+ DEBUG_ENTRY ();
66+
67+ assert (!is_listening_);
68+
69+ is_listening_ = network::tcp::Listen (httpd::kPort , Data);
70+ assert (is_listening_);
71+
72+ /*
73+ * Connection handles are global indices into s_Tcbs[].
74+ * Therefore the request-handler table must have one entry for every
75+ * possible global TCB slot.
76+ */
77+ for (uint32_t i = 0 ; i < TCP_MAX_TCBS_ALLOWED ; ++i) {
78+ // Construct exactly one handler in each raw-storage slot.
79+ ::new (static_cast <void *>(s_handle_request_storage[i].data )) HttpDeamonHandleRequest (i);
80+ }
81+
82+ network::apps::mdns::ServiceRecordAdd (nullptr , httpd::kService );
83+
84+ DEBUG_EXIT ();
85+ }
86+
87+ HttpDeamonHandleRequest& HttpDaemon::GetHandler (uint32_t index) {
88+ assert (index < TCP_MAX_TCBS_ALLOWED );
89+
90+ /*
91+ * std::launder is appropriate after constructing an object in raw storage
92+ * and subsequently obtaining a pointer through the storage address.
93+ */
94+ return *std::launder (reinterpret_cast <HttpDeamonHandleRequest*>(s_handle_request_storage[index].data ));
95+ }
96+
97+ void HttpDaemon::Data (network::tcp::ConnHandle conn_handle, const uint8_t * buffer, uint32_t size, [[maybe_unused]] void * context) {
98+ assert (conn_handle < TCP_MAX_TCBS_ALLOWED );
99+ assert (buffer != nullptr );
100+
101+ GetHandler (conn_handle).HandleRequest (size, const_cast <char *>(reinterpret_cast <const char *>(buffer)));
102+ }
0 commit comments