Skip to content

Commit 27e2886

Browse files
do not terminate if a single connection fails
1 parent 60eb742 commit 27e2886

File tree

6 files changed

+85
-41
lines changed

6 files changed

+85
-41
lines changed

libs/libmodbus

Submodule libmodbus updated 137 files

src/CMakeLists.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ target_sources(${Target} PRIVATE modbus_shm.cpp)
66
target_sources(${Target} PRIVATE Modbus_TCP_Client_poll.cpp)
77
target_sources(${Target} PRIVATE license.cpp)
88
target_sources(${Target} PRIVATE sa_to_str.cpp)
9+
target_sources(${Target} PRIVATE Print_Time.cpp)
910

1011

1112
# ---------------------------------------- header files (*.jpp, *.h, ...) ----------------------------------------------
@@ -14,7 +15,7 @@ target_sources(${Target} PRIVATE modbus_shm.hpp)
1415
target_sources(${Target} PRIVATE Modbus_TCP_Client_poll.hpp)
1516
target_sources(${Target} PRIVATE license.hpp)
1617
target_sources(${Target} PRIVATE sa_to_str.hpp)
17-
18+
target_sources(${Target} PRIVATE Print_Time.hpp)
1819

1920

2021
# ---------------------------------------- subdirectories --------------------------------------------------------------

src/Modbus_TCP_Client_poll.cpp

Lines changed: 15 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
#include "Modbus_TCP_Client_poll.hpp"
77

8+
#include "Print_Time.hpp"
89
#include "sa_to_str.hpp"
910

1011
#include <iostream>
@@ -299,11 +300,9 @@ Client_Poll::run_t Client_Poll::run(int signal_fd, bool reconnect, int timeout)
299300

300301
if (fd.revents) {
301302
if (fd.revents & POLLNVAL) throw std::logic_error("poll (server socket) returned POLLNVAL");
302-
else if (fd.revents & POLLERR)
303-
throw std::logic_error("poll (server socket) returned POLLERR");
304303
else if (fd.revents & POLLHUP)
305304
throw std::logic_error("poll (server socket) returned POLLHUP");
306-
else if (fd.revents & POLLIN) {
305+
else if (fd.revents & POLLIN || fd.revents & POLLERR) {
307306
tmp = modbus_tcp_pi_accept(modbus, &server_socket);
308307
if (tmp < 0) {
309308
const std::string error_msg = modbus_strerror(errno);
@@ -328,7 +327,7 @@ Client_Poll::run_t Client_Poll::run(int signal_fd, bool reconnect, int timeout)
328327
sstr << ':' << htons(reinterpret_cast<const struct sockaddr_in *>(&peer_addr)->sin_port);
329328

330329
client_addrs[client_socket] = sstr.str();
331-
std::cerr << '[' << active_clients + 1 << "] Modbus Server (" << sstr.str()
330+
std::cerr << Print_Time::iso << " INFO: [" << active_clients + 1 << "] Modbus Server (" << sstr.str()
332331
<< ") established connection." << std::endl;
333332
} else {
334333
std::ostringstream sstr;
@@ -343,8 +342,8 @@ Client_Poll::run_t Client_Poll::run(int signal_fd, bool reconnect, int timeout)
343342

344343
auto close_con = [&fd](auto &client_addrs) {
345344
close(fd.fd);
346-
std::cerr << '[' << client_addrs.size() - 1 << "] Modbus server (" << client_addrs[fd.fd]
347-
<< ") closed connection." << std::endl;
345+
std::cerr << Print_Time::iso << " INFO: [" << client_addrs.size() - 1 << "] Modbus server ("
346+
<< client_addrs[fd.fd] << ") connection closed." << std::endl;
348347
client_addrs.erase(fd.fd);
349348
};
350349

@@ -355,15 +354,9 @@ Client_Poll::run_t Client_Poll::run(int signal_fd, bool reconnect, int timeout)
355354
throw std::logic_error(sstr.str());
356355
}
357356

358-
if (fd.revents & POLLERR) {
359-
std::ostringstream sstr;
360-
sstr << "poll (client socket: " << client_addrs.at(fd.fd) << ") returned POLLERR";
361-
throw std::runtime_error(sstr.str());
362-
}
363-
364-
if (fd.revents & POLLHUP) { close_con(client_addrs); }
365-
366-
if (fd.revents & POLLIN) {
357+
if (fd.revents & POLLHUP & !(fd.revents & POLLERR)) {
358+
close_con(client_addrs);
359+
} else if (fd.revents & POLLIN || fd.revents & POLLERR) {
367360
modbus_set_socket(modbus, fd.fd);
368361

369362
uint8_t query[MODBUS_TCP_MAX_ADU_LENGTH];
@@ -378,16 +371,16 @@ Client_Poll::run_t Client_Poll::run(int signal_fd, bool reconnect, int timeout)
378371
// handle request
379372
int ret = modbus_reply(modbus, query, rc, mapping);
380373
if (ret == -1) {
381-
const std::string error_msg = modbus_strerror(errno);
382-
throw std::runtime_error("modbus_reply failed: " + error_msg + ' ' + std::to_string(errno));
374+
std::cerr << Print_Time::iso << " ERROR: modbus_reply failed: " << modbus_strerror(errno)
375+
<< std::endl;
376+
close_con(client_addrs);
383377
}
384378
} else if (rc == -1) {
385-
if (errno == ECONNRESET) {
386-
close_con(client_addrs);
387-
} else {
388-
const std::string error_msg = modbus_strerror(errno);
389-
throw std::runtime_error("modbus_receive failed: " + error_msg + ' ' + std::to_string(errno));
379+
if (errno != ECONNRESET) {
380+
std::cerr << Print_Time::iso << " ERROR: modbus_receive failed: " << modbus_strerror(errno)
381+
<< std::endl;
390382
}
383+
close_con(client_addrs);
391384
} else { // rc == 0
392385
close_con(client_addrs);
393386
}

src/Print_Time.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
/*
2+
* Copyright (C) 2022 Nikolas Koesling <nikolas@koesling.info>.
3+
* This program is free software. You can redistribute it and/or modify it under the terms of the MIT License.
4+
*/
5+
6+
#include "Print_Time.hpp"
7+
8+
#include <ctime>
9+
10+
Print_Time Print_Time::iso("%F_%T");
11+
12+
std::ostream &operator<<(std::ostream &o, const Print_Time &p) {
13+
auto now = time(nullptr);
14+
char buf[sizeof "1234-25-78T90:12:34Z"];
15+
strftime(buf, sizeof buf, p.format.c_str(), gmtime(&now));
16+
o << buf;
17+
return o;
18+
}

src/Print_Time.hpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
/*
2+
* Copyright (C) 2022 Nikolas Koesling <nikolas@koesling.info>.
3+
* This program is free software. You can redistribute it and/or modify it under the terms of the MIT License.
4+
*/
5+
6+
#pragma once
7+
8+
#include <ostream>
9+
#include <string>
10+
11+
class Print_Time {
12+
public:
13+
static Print_Time iso;
14+
15+
private:
16+
std::string format;
17+
18+
public:
19+
explicit Print_Time(std::string format) : format(std::move(format)) {}
20+
21+
friend std::ostream &operator<<(std::ostream &o, const Print_Time &p);
22+
};

src/main.cpp

Lines changed: 27 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,11 @@
3434
#endif
3535

3636
#include "Modbus_TCP_Client_poll.hpp"
37+
#include "Print_Time.hpp"
3738
#include "license.hpp"
3839
#include "modbus_shm.hpp"
3940

41+
4042
//! Maximum number of registers per type
4143
constexpr size_t MODBUS_MAX_REGS = 0x10000;
4244

@@ -77,7 +79,9 @@ int main(int argc, char **argv) {
7779
};
7880

7981
auto euid = geteuid();
80-
if (!euid) std::cerr << "!!!! WARNING: You should not execute this program with root privileges !!!!" << std::endl;
82+
if (!euid)
83+
std::cerr << Print_Time::iso << " WARNING: !!!! You should not execute this program with root privileges !!!!"
84+
<< std::endl;
8185

8286
#ifdef COMPILER_CLANG
8387
# pragma clang diagnostic push
@@ -179,7 +183,7 @@ int main(int argc, char **argv) {
179183
try {
180184
args = options.parse(argc, argv);
181185
} catch (cxxopts::OptionParseException &e) {
182-
std::cerr << "Failed to parse arguments: " << e.what() << '.' << std::endl;
186+
std::cerr << Print_Time::iso << " ERROR: Failed to parse arguments: " << e.what() << '.' << std::endl;
183187
return exit_usage();
184188
}
185189

@@ -222,35 +226,40 @@ int main(int argc, char **argv) {
222226

223227
// check arguments
224228
if (args["do-registers"].as<std::size_t>() > MODBUS_MAX_REGS) {
225-
std::cerr << "to many do-registers (maximum: " << MODBUS_MAX_REGS << ")." << std::endl;
229+
std::cerr << Print_Time::iso << " ERROR: to many do-registers (maximum: " << MODBUS_MAX_REGS << ")."
230+
<< std::endl;
226231
return exit_usage();
227232
}
228233

229234
if (args["di-registers"].as<std::size_t>() > MODBUS_MAX_REGS) {
230-
std::cerr << "to many di-registers (maximum: " << MODBUS_MAX_REGS << ")." << std::endl;
235+
std::cerr << Print_Time::iso << " ERROR: to many di-registers (maximum: " << MODBUS_MAX_REGS << ")."
236+
<< std::endl;
231237
return exit_usage();
232238
}
233239

234240
if (args["ao-registers"].as<std::size_t>() > MODBUS_MAX_REGS) {
235-
std::cerr << "to many ao-registers (maximum: " << MODBUS_MAX_REGS << ")." << std::endl;
241+
std::cerr << Print_Time::iso << " ERROR: to many ao-registers (maximum: " << MODBUS_MAX_REGS << ")."
242+
<< std::endl;
236243
return exit_usage();
237244
}
238245

239246
if (args["ai-registers"].as<std::size_t>() > MODBUS_MAX_REGS) {
240-
std::cerr << "to many ai-registers (maximum: " << MODBUS_MAX_REGS << ")." << std::endl;
247+
std::cerr << Print_Time::iso << " ERROR: to many ai-registers (maximum: " << MODBUS_MAX_REGS << ")."
248+
<< std::endl;
241249
return exit_usage();
242250
}
243251

244252
const auto CONNECTIONS = args["connections"].as<std::size_t>();
245253
if (CONNECTIONS == 0) {
246-
std::cerr << "The number of connections must not be 0" << std::endl;
254+
std::cerr << Print_Time::iso << " ERROR: The number of connections must not be 0" << std::endl;
247255
return exit_usage();
248256
}
249257

250258
const auto SEPARATE = args.count("separate");
251259
const auto SEPARATE_ALL = args.count("separate-all");
252260
if (SEPARATE && SEPARATE_ALL) {
253-
std::cerr << "The options --separate and --separate-all cannot be used together." << std::endl;
261+
std::cerr << Print_Time::iso << " ERROR: The options --separate and --separate-all cannot be used together."
262+
<< std::endl;
254263
return EX_USAGE;
255264
}
256265

@@ -267,7 +276,7 @@ int main(int argc, char **argv) {
267276
args["name-prefix"].as<std::string>(),
268277
FORCE_SHM);
269278
} catch (const std::system_error &e) {
270-
std::cerr << e.what() << std::endl;
279+
std::cerr << Print_Time::iso << " ERROR: " << e.what() << std::endl;
271280
return EX_OSERR;
272281
}
273282
}
@@ -290,7 +299,7 @@ int main(int argc, char **argv) {
290299
FORCE_SHM));
291300
mb_mappings[i] = separate_mappings.back()->get_mapping();
292301
} catch (const std::system_error &e) {
293-
std::cerr << e.what() << std::endl;
302+
std::cerr << Print_Time::iso << " ERROR: " << e.what() << std::endl;
294303
return EX_OSERR;
295304
}
296305
}
@@ -317,7 +326,7 @@ int main(int argc, char **argv) {
317326
FORCE_SHM));
318327
mb_mappings[a] = separate_mappings.back()->get_mapping();
319328
} catch (const std::system_error &e) {
320-
std::cerr << e.what() << std::endl;
329+
std::cerr << Print_Time::iso << " ERROR: " << e.what() << std::endl;
321330
return EX_OSERR;
322331
}
323332
}
@@ -338,7 +347,7 @@ int main(int argc, char **argv) {
338347
CONNECTIONS);
339348
client->set_debug(args.count("monitor"));
340349
} catch (const std::runtime_error &e) {
341-
std::cerr << e.what() << std::endl;
350+
std::cerr << Print_Time::iso << " ERROR: " << e.what() << std::endl;
342351
return EX_SOFTWARE;
343352
}
344353
socket = client->get_socket();
@@ -349,13 +358,14 @@ int main(int argc, char **argv) {
349358

350359
if (args.count("byte-timeout")) { client->set_byte_timeout(args["byte-timeout"].as<double>()); }
351360
} catch (const std::runtime_error &e) {
352-
std::cerr << e.what() << std::endl;
361+
std::cerr << Print_Time::iso << " ERROR: " << e.what() << std::endl;
353362
return EX_SOFTWARE;
354363
}
355364

356365
auto RECONNECT = args.count("reconnect") != 0;
357366

358-
std::cerr << "Listening on " << client->get_listen_addr() << " for connections." << std::endl;
367+
std::cerr << Print_Time::iso << " INFO: Listening on " << client->get_listen_addr() << " for connections."
368+
<< std::endl;
359369

360370
try {
361371
[&]() {
@@ -366,16 +376,16 @@ int main(int argc, char **argv) {
366376
case Modbus::TCP::Client_Poll::run_t::ok: continue;
367377
case Modbus::TCP::Client_Poll::run_t::term_signal: return;
368378
case Modbus::TCP::Client_Poll::run_t::term_nocon:
369-
std::cerr << "No more active connections." << std::endl;
379+
std::cerr << Print_Time::iso << " INFO: No more active connections." << std::endl;
370380
return;
371381
case Modbus::TCP::Client_Poll::run_t::timeout:
372382
case Modbus::TCP::Client_Poll::run_t::interrupted: continue;
373383
}
374384
}
375385
}();
376386
} catch (const std::exception &e) {
377-
if (!terminate) std::cerr << e.what() << std::endl;
387+
if (!terminate) std::cerr << Print_Time::iso << " ERROR: " << e.what() << std::endl;
378388
}
379389

380-
std::cerr << "Terminating..." << std::endl;
390+
std::cerr << Print_Time::iso << " INFO: Terminating..." << std::endl;
381391
}

0 commit comments

Comments
 (0)