35 cci::cci_param<std::string> p_address;
36 cci::cci_param<bool> p_server;
37 cci::cci_param<bool> p_nowait;
38 cci::cci_param<bool> p_sigquit;
41 asio::io_context m_io_context;
42 tcp::acceptor m_acceptor;
43 tcp::socket m_asio_socket;
44 std::thread m_rcv_thread;
46 tcp::endpoint m_local_endpoint;
48 static constexpr size_t m_buffer_size = 1024;
49 std::array<char, m_buffer_size> m_buffer;
52 const int m_tcp_backlog = 1;
55 std::atomic<bool> m_stop_rcv_thread =
false;
57 const std::chrono::milliseconds m_retry_delay = std::chrono::milliseconds(100);
65 : sc_core::sc_module(name)
66 , p_address(
"address",
"127.0.0.1:4001",
"socket address IP:Port")
67 , p_server(
"server",
true,
"type of socket: true if server - false if client")
68 , p_nowait(
"nowait",
true,
"setting socket in non-blocking mode")
69 , p_sigquit(
"sigquit",
false,
"Interpret 0x1c in the data stream as a sigquit")
70 , m_biflow_socket(
"biflow_socket")
71 , m_acceptor(m_io_context)
72 , m_asio_socket(m_io_context)
74 SCP_TRACE(()) <<
"char_backend_socket constructor";
76 if (!set_endpoint()) {
77 SCP_FATAL(()) <<
"Failed to set local endpoint";
85 void end_of_simulation() { cleanup_receive_thread(); }
87 void cleanup_receive_thread()
89 m_stop_rcv_thread =
true;
95 if (m_rcv_thread.joinable()) m_rcv_thread.join();
101 asio::ip::address
ip;
104 size_t count = std::count(p_address.get_value().begin(), p_address.get_value().end(),
':');
106 size_t first = p_address.get_value().find_first_of(
':');
110 SCP_ERR(()) <<
"malformed address, expecting IP:PORT (e.g. 127.0.0.1:4001)";
117 SCP_ERR(()) <<
"Invalid IP address: " <<
param_ip <<
", error: " <<
ec.message();
123 }
catch (
const std::invalid_argument&
e) {
126 }
catch (
const std::out_of_range&
e) {
131 m_local_endpoint = tcp::endpoint(
ip,
port);
136 void start_of_simulation()
138 SCP_DEBUG(()) <<
"IP: " << m_local_endpoint.address() <<
", PORT: " << m_local_endpoint.port();
144 m_rcv_thread = std::thread(&char_backend_socket::rcv_thread,
this);
149 void setup_tcp_server()
153 m_acceptor.open(m_local_endpoint.protocol(),
ec);
155 SCP_ERR(()) <<
"Failed to open acceptor: " <<
ec.message();
159 m_acceptor.set_option(asio::socket_base::reuse_address(
true),
ec);
161 SCP_ERR(()) <<
"Failed to set reuse_address option: " <<
ec.message();
166 m_acceptor.bind(m_local_endpoint,
ec);
168 SCP_ERR(()) <<
"Failed to bind acceptor: " <<
ec.message();
173 m_acceptor.listen(m_tcp_backlog,
ec);
175 SCP_ERR(()) <<
"Failed to listen on acceptor: " <<
ec.message();
180 m_acceptor.non_blocking(
true,
ec);
182 SCP_ERR(()) <<
"Failed to set acceptor to non-blocking: " <<
ec.message();
188 void writefn(tlm::tlm_generic_payload& txn, sc_core::sc_time&
t)
190 while (!m_asio_socket.is_open()) {
194 SCP_WARN(()) <<
"waiting for socket connection on IP address: " << p_address.get_value();
195 std::this_thread::sleep_for(m_retry_delay);
200 uint8_t* data = txn.get_data_ptr();
205 SCP_WARN(())(
"(Non blocking) socket closed");
208 SCP_WARN(())(
"(Blocking) socket closed.");
217 }
catch (
const asio::system_error&
e) {
218 std::cout <<
"Caught exception: " <<
e.what() << std::endl;
222 void configure_socket()
226 m_asio_socket.non_blocking(
true,
ec);
228 SCP_FATAL(()) <<
" Failed to set non blocking mode: " <<
ec.message();
232 m_asio_socket.set_option(asio::ip::tcp::no_delay(
true));
234 SCP_FATAL(()) <<
" Failed to disable Nagle's Algorithm: " <<
ec.message();
242 while (!m_stop_rcv_thread) {
245 m_acceptor.accept(m_asio_socket,
ec);
246 switch (
ec.value()) {
249 SCP_DEBUG(()) <<
"Accepted connection from " << m_asio_socket.remote_endpoint().address() <<
":"
250 << m_asio_socket.remote_endpoint().port();
252 case asio::error::would_block:
253 SCP_INFO(()) <<
"Accept failed for non blocking:" <<
ec.message();
254 std::this_thread::sleep_for(m_retry_delay);
257 SCP_WARN(()) <<
"Accept connection failed with error:" <<
ec.message();
258 std::this_thread::sleep_for(m_retry_delay);
261 }
else if (!p_server) {
263 m_asio_socket.connect(m_local_endpoint,
ec);
267 SCP_INFO(()) <<
"failed to connect to " << m_local_endpoint.address() <<
":"
268 << m_local_endpoint.port() <<
" " <<
ec.message();
269 m_asio_socket.close();
270 std::this_thread::sleep_for(m_retry_delay);
275 if (m_asio_socket.is_open()) receive_loop();
278 SCP_DEBUG(()) <<
"Leaving receive thread";
285 while (m_asio_socket.is_open()) {
286 size_t read_count = m_asio_socket.read_some(asio::buffer(m_buffer),
ec);
287 switch (
ec.value()) {
289 forward_incoming_data(read_count);
291 case asio::error::would_block:
293 std::this_thread::sleep_for(m_retry_delay);
295 case asio::error::eof:
296 SCP_DEBUG(()) <<
"Remote endpoint disconnected";
297 m_asio_socket.close();
300 SCP_WARN(()) <<
"Read failed: " <<
ec.message();
301 m_asio_socket.close();
312 unsigned char c = m_buffer[
i];
313 if (p_sigquit &&
c == 0x1c) {