|
5 | 5 |
|
6 | 6 | #include "Modbus_TCP_Slave.hpp"
|
7 | 7 |
|
| 8 | +#include <algorithm> |
8 | 9 | #include <netinet/in.h>
|
9 | 10 | #include <netinet/tcp.h>
|
10 | 11 | #include <stdexcept>
|
@@ -48,32 +49,38 @@ Slave::Slave(const std::string &ip, unsigned short port, modbus_mapping_t *mappi
|
48 | 49 | }
|
49 | 50 |
|
50 | 51 | // set socket options
|
| 52 | + // enable socket keepalive (--> fail if connection partner is not reachable) |
51 | 53 | int keepalive = 1;
|
52 | 54 | int tmp = setsockopt(socket, SOL_SOCKET, SO_KEEPALIVE, &keepalive, sizeof(keepalive));
|
53 | 55 | if (tmp != 0) {
|
54 | 56 | throw std::system_error(errno, std::generic_category(), "Failed to set socket option SO_KEEPALIVE");
|
55 | 57 | }
|
56 | 58 |
|
| 59 | + // this block makes this source file linux only :( |
57 | 60 | if (tcp_timeout) {
|
| 61 | + // set user timeout (~= timeout for tcp connection) |
58 | 62 | unsigned user_timeout = static_cast<unsigned>(tcp_timeout) * 1000;
|
59 | 63 | tmp = setsockopt(socket, IPPROTO_TCP, TCP_USER_TIMEOUT, &user_timeout, sizeof(keepalive));
|
60 | 64 | if (tmp != 0) {
|
61 | 65 | throw std::system_error(errno, std::generic_category(), "Failed to set socket option TCP_USER_TIMEOUT");
|
62 | 66 | }
|
63 | 67 |
|
| 68 | + // start sending keepalive request after one second without request |
64 | 69 | unsigned keepidle = 1;
|
65 | 70 | tmp = setsockopt(socket, IPPROTO_TCP, TCP_KEEPIDLE, &keepidle, sizeof(keepidle));
|
66 | 71 | if (tmp != 0) {
|
67 | 72 | throw std::system_error(errno, std::generic_category(), "Failed to set socket option TCP_KEEPIDLE");
|
68 | 73 | }
|
69 | 74 |
|
70 |
| - unsigned keepintvl = 1; |
| 75 | + // send up to 5 keepalive requests during the timeout time, but not more than one per second |
| 76 | + unsigned keepintvl = std::max(static_cast<unsigned>(tcp_timeout / 5), 1u); |
71 | 77 | tmp = setsockopt(socket, IPPROTO_TCP, TCP_KEEPINTVL, &keepintvl, sizeof(keepintvl));
|
72 | 78 | if (tmp != 0) {
|
73 | 79 | throw std::system_error(errno, std::generic_category(), "Failed to set socket option TCP_KEEPINTVL");
|
74 | 80 | }
|
75 | 81 |
|
76 |
| - unsigned keepcnt = static_cast<unsigned>(tcp_timeout); |
| 82 | + // 5 keepalive requests if the timeout time is >= 5s; else send one request each second |
| 83 | + unsigned keepcnt = std::min(static_cast<unsigned>(tcp_timeout), 5u); |
77 | 84 | tmp = setsockopt(socket, IPPROTO_TCP, TCP_KEEPCNT, &keepcnt, sizeof(keepcnt));
|
78 | 85 | if (tmp != 0) {
|
79 | 86 | throw std::system_error(errno, std::generic_category(), "Failed to set socket option TCP_KEEPCNT");
|
|
0 commit comments