scc 2026.07
SystemC components library
client.h
1/*******************************************************************************
2 * Copyright 2026 MINRES Technologies GmbH
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *******************************************************************************/
16
17#ifndef TLM_SCC_TCP_DETAIL_CLIENT_H_
18#define TLM_SCC_TCP_DETAIL_CLIENT_H_
19
20#include "serialized_connection.h"
21#include <boost/asio.hpp>
22#include <boost/lexical_cast.hpp>
23#include <thread>
24
25namespace scc {
26namespace tcp4tlm {
27
28template <typename REQ, typename RESP> class client {
29public:
30 client();
31 virtual ~client();
32
33 void configure(std::string host, unsigned port_nr) {
34 this->host = host;
35 this->port = port_nr;
36 }
37
38 void connect();
39
40 bool is_remote_connected() { return is_connected; }
41
42 connection<REQ, RESP>& client_connection(unsigned short retry_count = 0) {
43 if(!is_connected)
44 connect();
45 while(!is_connected && retry_count > 0) {
46 CPPLOG(INFO, "tcp4tlm::client") << "retrying connection for " << retry_count-- << " times";
47 connect();
48 }
49 if(!is_connected)
50 throw std::runtime_error("Retry count exceeded!");
51 return *trace_conn;
52 }
53
54protected:
55 std::string host;
56 unsigned short port;
57 unsigned short retry_count;
58 boost::asio::io_context io_service;
59 typename connection<REQ, RESP>::ptr trace_conn;
60 std::atomic<bool> is_connected;
61 bool local_connection;
62
63#ifdef BOOST_ASIO_HAS_LOCAL_SOCKETS
64 void setup_endpoint(boost::asio::local::stream_protocol::endpoint& ep) {
65 if(port) {
66 std::string s("/tmp/server");
67 s += boost::lexical_cast<std::string>(port ? port : getpid());
68 ep = boost::asio::local::stream_protocol::endpoint(s);
69 } else {
70 ep = boost::asio::local::stream_protocol::endpoint(host);
71 }
72 }
73#endif
74
75 void setup_endpoint(boost::asio::ip::tcp::endpoint& ep) {
76 using boost::asio::ip::tcp;
77 tcp::resolver resolver(io_service);
78 auto results = resolver.resolve(tcp::v4(), host, boost::lexical_cast<std::string>(port));
79 ep = results.begin()->endpoint();
80 }
81
82 void setup_endpoint(boost::asio::ip::udp::endpoint& ep) {
83 using boost::asio::ip::udp;
84 udp::resolver resolver(io_service);
85 auto results = resolver.resolve(udp::v4(), host, boost::lexical_cast<std::string>(port));
86 ep = results.begin()->endpoint();
87 }
88
89 bool is_local_socket(boost::asio::ip::tcp::socket& socket) {
90 return socket.local_endpoint().address() == socket.remote_endpoint().address();
91 }
92
93 bool is_local_socket(boost::asio::ip::udp::socket& socket) {
94 return socket.local_endpoint().address() == socket.remote_endpoint().address();
95 }
96
97#ifdef BOOST_ASIO_HAS_LOCAL_SOCKETS
98 bool is_local_socket(boost::asio::local::stream_protocol::socket& socket) { return true; }
99#endif
100};
101
102template <typename REQ, typename RESP>
103client<REQ, RESP>::client()
104: host("localhost")
105, port(0)
106, retry_count(100)
107, io_service()
108, trace_conn(new connection<REQ, RESP>(io_service))
109, is_connected(false)
110, local_connection(false) {}
111
112template <typename REQ, typename RESP> client<REQ, RESP>::~client() {
113 if(trace_conn->socket().is_open()) {
114 trace_conn->socket().close();
115 }
116}
117
118template <typename REQ, typename RESP> void client<REQ, RESP>::connect() {
119 CPPLOG(INFO, "tcp4tlm::client") << "connect for port " << port << " on host '" << host << "'";
120 typename connection<REQ, RESP>::endpoint_t ep;
121 typename connection<REQ, RESP>::socket_t& socket = trace_conn->socket();
122 setup_endpoint(ep);
123 boost::system::error_code ec;
124 for(unsigned i = 0; i < retry_count; ++i) {
125 socket.connect(ep, ec);
126 if(!ec)
127 break;
128 if(i % 10 == 0) {
129 CPPLOG(INFO, "tcp4tlm::client") << "retrying connection for " << i << " times with code " << ec;
130 }
131 std::this_thread::sleep_for(std::chrono::milliseconds(250));
132 }
133 if(ec) {
134 is_connected = false;
135 local_connection = false;
136 } else {
137 is_connected = true;
138 boost::asio::ip::tcp::no_delay option(true);
139 socket.set_option(option);
140 local_connection = is_local_socket(socket);
141 }
142}
143
144} // namespace tcp4tlm
145} // namespace scc
146
147#endif // TLM_SCC_TCP_DETAIL_CLIENT_H_
The connection class provides FlatBuffers framing primitives on top of a socket.
SCC TLM utilities.