1212#include < netinet/tcp.h>
1313#include < sstream>
1414#include < stdexcept>
15+ #include < sys/poll.h>
1516#include < sys/socket.h>
1617#include < system_error>
1718#include < unistd.h>
@@ -23,9 +24,15 @@ namespace TCP {
2324
2425static constexpr int MAX_REGS = 0x10000 ;
2526
26- Client::Client (const std::string &ip, unsigned short port, modbus_mapping_t *mapping, std::size_t tcp_timeout) {
27+ Client::Client (const std::string &host,
28+ const std::string &service,
29+ modbus_mapping_t *mapping,
30+ std::size_t tcp_timeout) {
31+ const char *host_str = " ::" ;
32+ if (!(host.empty () || host == " any" )) host_str = host.c_str ();
33+
2734 // create modbus object
28- modbus = modbus_new_tcp (ip .c_str (), static_cast < int >(port ));
35+ modbus = modbus_new_tcp_pi (host_str, service .c_str ());
2936 if (modbus == nullptr ) {
3037 const std::string error_msg = modbus_strerror (errno);
3138 throw std::runtime_error (" failed to create modbus instance: " + error_msg);
@@ -62,9 +69,15 @@ Client::Client(const std::string &ip, unsigned short port, modbus_mapping_t *map
6269#endif
6370}
6471
65- Client::Client (const std::string &ip, unsigned short port, modbus_mapping_t **mappings, std::size_t tcp_timeout) {
72+ Client::Client (const std::string &host,
73+ const std::string &service,
74+ modbus_mapping_t **mappings,
75+ std::size_t tcp_timeout) {
76+ const char *host_str = " ::" ;
77+ if (!(host.empty () || host == " any" )) host_str = host.c_str ();
78+
6679 // create modbus object
67- modbus = modbus_new_tcp (ip .c_str (), static_cast < int >(port ));
80+ modbus = modbus_new_tcp_pi (host_str, service .c_str ());
6881 if (modbus == nullptr ) {
6982 const std::string error_msg = modbus_strerror (errno);
7083 throw std::runtime_error (" failed to create modbus instance: " + error_msg);
@@ -100,10 +113,14 @@ Client::Client(const std::string &ip, unsigned short port, modbus_mapping_t **ma
100113
101114void Client::listen () {
102115 // create tcp socket
103- socket = modbus_tcp_listen (modbus, 1 );
116+ socket = modbus_tcp_pi_listen (modbus, 1 );
104117 if (socket == -1 ) {
105- const std::string error_msg = modbus_strerror (errno);
106- throw std::runtime_error (" failed to create tcp socket: " + error_msg);
118+ if (errno == ECONNREFUSED) {
119+ throw std::runtime_error (" failed to create tcp socket: unknown or invalid service" );
120+ } else {
121+ const std::string error_msg = modbus_strerror (errno);
122+ throw std::runtime_error (" failed to create tcp socket: " + error_msg);
123+ }
107124 }
108125
109126 // set socket options
@@ -147,7 +164,6 @@ void Client::set_tcp_timeout(std::size_t tcp_timeout) {
147164}
148165#endif
149166
150-
151167Client::~Client () {
152168 if (modbus != nullptr ) {
153169 modbus_close (modbus);
@@ -164,32 +180,90 @@ void Client::set_debug(bool debug) {
164180 }
165181}
166182
167- std::string Client::connect_client () {
168- int tmp = modbus_tcp_accept (modbus, &socket);
183+ /* *
184+ * @brief convert socket address to string
185+ * @param sa socket address
186+ * @return sa as string
187+ */
188+ static std::string sockaddr_to_str (const sockaddr_storage &sa) {
189+ char buffer[INET6_ADDRSTRLEN + 1 ];
190+ if (sa.ss_family == AF_INET) {
191+ auto peer_in = reinterpret_cast <const struct sockaddr_in *>(&sa);
192+ inet_ntop (sa.ss_family , &peer_in->sin_addr , buffer, sizeof (buffer));
193+ std::ostringstream sstr;
194+ return buffer;
195+ } else if (sa.ss_family == AF_INET6) {
196+ auto peer_in6 = reinterpret_cast <const struct sockaddr_in6 *>(&sa);
197+ inet_ntop (sa.ss_family , &peer_in6->sin6_addr , buffer, sizeof (buffer));
198+ std::ostringstream sstr;
199+ sstr << ' [' << buffer << ' ]' ;
200+ return sstr.str ();
201+ } else {
202+ return " UNKNOWN" ;
203+ }
204+ }
205+
206+ std::string Client::get_listen_addr () {
207+ struct sockaddr_storage sock_addr;
208+ socklen_t len = sizeof (sock_addr);
209+ int tmp = getsockname (socket, reinterpret_cast <struct sockaddr *>(&sock_addr), &len);
210+
211+ if (tmp < 0 ) {
212+ const std::string error_msg = modbus_strerror (errno);
213+ throw std::runtime_error (" getsockname failed: " + error_msg);
214+ }
215+
216+ std::ostringstream sstr;
217+ sstr << sockaddr_to_str (sock_addr);
218+ // the port entries have the same offset and size in sockaddr_in and sockaddr_in6
219+ sstr << ' :' << htons (reinterpret_cast <const struct sockaddr_in *>(&sock_addr)->sin_port );
220+
221+ return sstr.str ();
222+ }
223+
224+ std::shared_ptr<Connection> Client::connect_client () {
225+ struct pollfd fd;
226+ memset (&fd, 0 , sizeof (fd));
227+ fd.fd = socket;
228+ fd.events = POLL_IN;
229+ do {
230+ int tmp = poll (&fd, 1 , -1 );
231+ if (tmp <= 0 ) {
232+ if (errno == EINTR) continue ;
233+ throw std::system_error (errno, std::generic_category (), " Failed to poll server socket" );
234+ } else
235+ break ;
236+ } while (true );
237+
238+ std::lock_guard<decltype (modbus_lock)> guard (modbus_lock);
239+
240+ int tmp = modbus_tcp_pi_accept (modbus, &socket);
169241 if (tmp < 0 ) {
170242 const std::string error_msg = modbus_strerror (errno);
171243 throw std::runtime_error (" modbus_tcp_accept failed: " + error_msg);
172244 }
173245
174- struct sockaddr_in peer_addr;
175- socklen_t len = sizeof (peer_addr);
246+ struct sockaddr_storage peer_addr;
247+ socklen_t len = sizeof (peer_addr);
176248 tmp = getpeername (modbus_get_socket (modbus), reinterpret_cast <struct sockaddr *>(&peer_addr), &len);
177249
178250 if (tmp < 0 ) {
179251 const std::string error_msg = modbus_strerror (errno);
180252 throw std::runtime_error (" getpeername failed: " + error_msg);
181253 }
182254
183- char buffer[INET_ADDRSTRLEN];
184- inet_ntop (peer_addr.sin_family , &peer_addr.sin_addr , buffer, sizeof (buffer));
185-
186255 std::ostringstream sstr;
187- sstr << buffer << ' :' << htons (peer_addr.sin_port );
188256
189- return sstr.str ();
257+ sstr << sockaddr_to_str (peer_addr);
258+ // the port entries have the same offset and size in sockaddr_in and sockaddr_in6
259+ sstr << ' :' << htons (reinterpret_cast <const struct sockaddr_in *>(&peer_addr)->sin_port );
260+
261+ return std::make_shared<Connection>(sstr.str (), modbus_get_socket (modbus), modbus_lock, modbus, mappings);
190262}
191263
192264bool Client::handle_request () {
265+ std::lock_guard<decltype (modbus_lock)> guard (modbus_lock);
266+
193267 // receive modbus request
194268 uint8_t query[MODBUS_TCP_MAX_ADU_LENGTH];
195269 int rc = modbus_receive (modbus, query);
0 commit comments