Skip to content

Commit 4eebfdd

Browse files
Merge pull request #31 from NikolasK-source/main
update to 1.5.0
2 parents 61e716d + 9071ecc commit 4eebfdd

File tree

7 files changed

+105
-64
lines changed

7 files changed

+105
-64
lines changed

CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ cmake_minimum_required(VERSION 3.13.4 FATAL_ERROR)
44
# ======================================================================================================================
55

66
# project
7-
project(Modbus_TCP_client_shm LANGUAGES CXX VERSION 1.4.0)
7+
project(Modbus_TCP_client_shm LANGUAGES CXX VERSION 1.5.0)
88

99
# settings
1010
set(Target "modbus-tcp-client-shm") # Executable name (without file extension!)

libs/cxxsemaphore

Submodule cxxsemaphore updated 298 files

src/license.cpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -585,4 +585,29 @@ void print_licenses(std::ostream &o) {
585585
o << " LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM," << std::endl;
586586
o << " OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE" << std::endl;
587587
o << " SOFTWARE." << std::endl;
588+
o << std::endl;
589+
o << std::endl;
590+
o << "cxxsemaphore Library (https://github.com/NikolasK-source/cxxsemaphore)" << std::endl;
591+
o << std::endl;
592+
o << " MIT License" << std::endl;
593+
o << std::endl;
594+
o << " Copyright (c) 2023 Nikolas Koesling" << std::endl;
595+
o << std::endl;
596+
o << " Permission is hereby granted, free of charge, to any person obtaining a copy" << std::endl;
597+
o << " of this software and associated documentation files (the \"Software\"), to deal" << std::endl;
598+
o << " in the Software without restriction, including without limitation the rights" << std::endl;
599+
o << " to use, copy, modify, merge, publish, distribute, sublicense, and/or sell" << std::endl;
600+
o << " copies of the Software, and to permit persons to whom the Software is" << std::endl;
601+
o << " furnished to do so, subject to the following conditions:" << std::endl;
602+
o << std::endl;
603+
o << " The above copyright notice and this permission notice shall be included in all" << std::endl;
604+
o << " copies or substantial portions of the Software." << std::endl;
605+
o << std::endl;
606+
o << " THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR" << std::endl;
607+
o << " IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY," << std::endl;
608+
o << " FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE" << std::endl;
609+
o << " AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER" << std::endl;
610+
o << " LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM," << std::endl;
611+
o << " OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE" << std::endl;
612+
o << " SOFTWARE." << std::endl;
588613
}

src/main.cpp

Lines changed: 66 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -110,82 +110,73 @@ int main(int argc, char **argv) {
110110
#endif
111111

112112
// all command line arguments
113-
// clang-format off
114-
options.add_options()("i,host",
115-
"host to listen for incoming connections",
116-
cxxopts::value<std::string>()->default_value("any"))
117-
("p,service",
113+
options.add_options()(
114+
"i,host", "host to listen for incoming connections", cxxopts::value<std::string>()->default_value("any"));
115+
options.add_options()("p,service",
118116
"service or port to listen for incoming connections",
119-
cxxopts::value<std::string>()->default_value("502"))
120-
("n,name-prefix",
121-
"shared memory name prefix",
122-
cxxopts::value<std::string>()->default_value("modbus_"))
123-
("do-registers",
117+
cxxopts::value<std::string>()->default_value("502"));
118+
options.add_options()(
119+
"n,name-prefix", "shared memory name prefix", cxxopts::value<std::string>()->default_value("modbus_"));
120+
options.add_options()("do-registers",
124121
"number of digital output registers",
125-
cxxopts::value<std::size_t>()->default_value("65536"))
126-
("di-registers",
127-
"number of digital input registers",
128-
cxxopts::value<std::size_t>()->default_value("65536"))
129-
("ao-registers",
130-
"number of analog output registers",
131-
cxxopts::value<std::size_t>()->default_value("65536"))
132-
("ai-registers",
133-
"number of analog input registers",
134-
cxxopts::value<std::size_t>()->default_value("65536"))
135-
("m,monitor",
136-
"output all incoming and outgoing packets to stdout")
137-
("c,connections",
122+
cxxopts::value<std::size_t>()->default_value("65536"));
123+
options.add_options()(
124+
"di-registers", "number of digital input registers", cxxopts::value<std::size_t>()->default_value("65536"));
125+
options.add_options()(
126+
"ao-registers", "number of analog output registers", cxxopts::value<std::size_t>()->default_value("65536"));
127+
options.add_options()(
128+
"ai-registers", "number of analog input registers", cxxopts::value<std::size_t>()->default_value("65536"));
129+
options.add_options()("m,monitor", "output all incoming and outgoing packets to stdout");
130+
options.add_options()("c,connections",
138131
"number of allowed simultaneous Modbus Server connections.",
139-
cxxopts::value<std::size_t>()->default_value("1"))
140-
("r,reconnect",
141-
"do not terminate if no Modbus Server is connected anymore.")
142-
("byte-timeout",
132+
cxxopts::value<std::size_t>()->default_value("1"));
133+
options.add_options()("r,reconnect", "do not terminate if no Modbus Server is connected anymore.");
134+
options.add_options()("byte-timeout",
143135
"timeout interval in seconds between two consecutive bytes of the same message. "
144-
"In most cases it is sufficient to set the response timeout. "
145-
"Fractional values are possible.",
146-
cxxopts::value<double>())
147-
("response-timeout",
136+
"In most cases it is sufficient to set the response timeout. "
137+
"Fractional values are possible.",
138+
cxxopts::value<double>());
139+
options.add_options()("response-timeout",
148140
"set the timeout interval in seconds used to wait for a response. "
149141
"When a byte timeout is set, if the elapsed time for the first byte of response is longer "
150142
"than the given timeout, a timeout is detected. "
151143
"When byte timeout is disabled, the full confirmation response must be received before "
152144
"expiration of the response timeout. "
153145
"Fractional values are possible.",
154-
cxxopts::value<double>())
146+
cxxopts::value<double>());
155147
#ifdef OS_LINUX
156-
("t,tcp-timeout",
148+
options.add_options()("t,tcp-timeout",
157149
"tcp timeout in seconds. Set to 0 to use the system defaults (not recommended).",
158-
cxxopts::value<std::size_t>()->default_value("5"))
150+
cxxopts::value<std::size_t>()->default_value("5"));
159151
#endif
160-
("force",
152+
options.add_options()("force",
161153
"Force the use of the shared memory even if it already exists. "
162154
"Do not use this option per default! "
163155
"It should only be used if the shared memory of an improperly terminated instance continues "
164-
"to exist as an orphan and is no longer used.")
165-
("s,separate",
156+
"to exist as an orphan and is no longer used.");
157+
options.add_options()("s,separate",
166158
"Use a separate shared memory for requests with the specified client id. "
167159
"The client id (as hex value) is appended to the shared memory prefix (e.g. modbus_fc_DO)"
168160
". You can specify multiple client ids by separating them with ','. "
169161
"Use --separate-all to generate separate shared memories for all possible client ids.",
170-
cxxopts::value<std::vector<std::uint8_t>>())
171-
("separate-all",
162+
cxxopts::value<std::vector<std::uint8_t>>());
163+
options.add_options()("separate-all",
172164
"like --separate, but for all client ids (creates 1028 shared memory files! "
173-
"check/set 'ulimit -n' before using this option.)")
174-
("semaphore",
165+
"check/set 'ulimit -n' before using this option.)");
166+
options.add_options()("semaphore",
175167
"protect the shared memory with a named semaphore against simultaneous access",
176-
cxxopts::value<std::string>())
177-
("semaphore-force",
168+
cxxopts::value<std::string>());
169+
options.add_options()("semaphore-force",
178170
"Force the use of the semaphore even if it already exists. "
179171
"Do not use this option per default! "
180172
"It should only be used if the semaphore of an improperly terminated instance continues "
181-
"to exist as an orphan and is no longer used.")
182-
("h,help",
183-
"print usage")
184-
("version",
185-
"print version information")
186-
("license",
187-
"show licences");
188-
// clang-format on
173+
"to exist as an orphan and is no longer used.");
174+
options.add_options()("b,permissions",
175+
"permission bits that are applied when creating a shared memory.",
176+
cxxopts::value<std::string>()->default_value("0640"));
177+
options.add_options()("h,help", "print usage");
178+
options.add_options()("version", "print version information");
179+
options.add_options()("license", "show licences");
189180

190181
// parse arguments
191182
cxxopts::ParseResult args;
@@ -213,6 +204,7 @@ int main(int argc, char **argv) {
213204
std::cout << " - cxxopts by jarro2783 (https://github.com/jarro2783/cxxopts)" << std::endl;
214205
std::cout << " - libmodbus by Stéphane Raimbault (https://github.com/stephane/libmodbus)" << std::endl;
215206
std::cout << " - cxxshm (https://github.com/NikolasK-source/cxxshm)" << std::endl;
207+
std::cout << " - cxxsemaphore (https://github.com/NikolasK-source/cxxsemaphore)" << std::endl;
216208
return EX_OK;
217209
}
218210

@@ -274,6 +266,23 @@ int main(int argc, char **argv) {
274266

275267
const auto FORCE_SHM = args.count("force") > 0;
276268

269+
mode_t shm_permissions = 0660;
270+
{
271+
const auto shm_permissions_str = args["permissions"].as<std::string>();
272+
bool fail = false;
273+
std::size_t idx = 0;
274+
try {
275+
shm_permissions = std::stoul(shm_permissions_str, &idx, 0);
276+
} catch (const std::exception &) { fail = true; }
277+
fail = fail || idx != shm_permissions_str.size();
278+
279+
if (fail || (~static_cast<mode_t>(0x1FF) & shm_permissions) != 0) {
280+
std::cerr << Print_Time::iso << " ERROR: Invalid file permissions \"" << shm_permissions_str << '"'
281+
<< std::endl;
282+
return EX_USAGE;
283+
}
284+
}
285+
277286
// check ulimit
278287
std::size_t min_files =
279288
CONNECTIONS + 5; // number of connections + stderr + stdout + stdin + signal_fd + server socket
@@ -303,7 +312,8 @@ int main(int argc, char **argv) {
303312
args["ao-registers"].as<std::size_t>(),
304313
args["ai-registers"].as<std::size_t>(),
305314
args["name-prefix"].as<std::string>(),
306-
FORCE_SHM);
315+
FORCE_SHM,
316+
shm_permissions);
307317
} catch (const std::system_error &e) {
308318
std::cerr << Print_Time::iso << " ERROR: " << e.what() << std::endl;
309319
return EX_OSERR;
@@ -325,7 +335,8 @@ int main(int argc, char **argv) {
325335
args["ao-registers"].as<std::size_t>(),
326336
args["ai-registers"].as<std::size_t>(),
327337
sstr.str(),
328-
FORCE_SHM));
338+
FORCE_SHM,
339+
shm_permissions));
329340
mb_mappings[i] = separate_mappings.back()->get_mapping();
330341
} catch (const std::system_error &e) {
331342
std::cerr << Print_Time::iso << " ERROR: " << e.what() << std::endl;
@@ -352,7 +363,8 @@ int main(int argc, char **argv) {
352363
args["ao-registers"].as<std::size_t>(),
353364
args["ai-registers"].as<std::size_t>(),
354365
sstr.str(),
355-
FORCE_SHM));
366+
FORCE_SHM,
367+
shm_permissions));
356368
mb_mappings[a] = separate_mappings.back()->get_mapping();
357369
} catch (const std::system_error &e) {
358370
std::cerr << Print_Time::iso << " ERROR: " << e.what() << std::endl;

src/modbus_shm.cpp

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@ Shm_Mapping::Shm_Mapping(std::size_t nb_bits,
1919
std::size_t nb_registers,
2020
std::size_t nb_input_registers,
2121
const std::string &prefix,
22-
bool force) {
22+
bool force,
23+
mode_t permissions) {
2324
// check argument ranges
2425
if (nb_bits > 0x10000 || !nb_bits) throw std::invalid_argument("invalid number of digital output registers.");
2526
if (nb_input_bits > 0x10000 || !nb_input_bits)
@@ -36,10 +37,11 @@ Shm_Mapping::Shm_Mapping(std::size_t nb_bits,
3637
mapping.nb_input_registers = static_cast<int>(nb_input_registers);
3738

3839
// create shm objects
39-
shm_data[DO] = std::make_unique<cxxshm::SharedMemory>(prefix + "DO", nb_bits, false, !force);
40-
shm_data[DI] = std::make_unique<cxxshm::SharedMemory>(prefix + "DI", nb_input_bits, false, !force);
41-
shm_data[AO] = std::make_unique<cxxshm::SharedMemory>(prefix + "AO", 2 * nb_registers, false, !force);
42-
shm_data[AI] = std::make_unique<cxxshm::SharedMemory>(prefix + "AI", 2 * nb_input_registers, false, !force);
40+
shm_data[DO] = std::make_unique<cxxshm::SharedMemory>(prefix + "DO", nb_bits, false, !force, permissions);
41+
shm_data[DI] = std::make_unique<cxxshm::SharedMemory>(prefix + "DI", nb_input_bits, false, !force, permissions);
42+
shm_data[AO] = std::make_unique<cxxshm::SharedMemory>(prefix + "AO", 2 * nb_registers, false, !force, permissions);
43+
shm_data[AI] =
44+
std::make_unique<cxxshm::SharedMemory>(prefix + "AI", 2 * nb_input_registers, false, !force, permissions);
4345

4446
// set shm objects as modbus register storage
4547
mapping.tab_bits = static_cast<uint8_t *>(shm_data[DO]->get_addr());

src/modbus_shm.hpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,13 +53,15 @@ class Shm_Mapping final {
5353
* @param nb_input_registers number of analog input registers (AI)
5454
* @param shm_name_prefix name prefix of the created shared memory object
5555
* @param force do not fail if the shared memory exist, but use the existing shared memory
56+
* @param permissions shared memory file permissions
5657
*/
5758
Shm_Mapping(std::size_t nb_bits,
5859
std::size_t nb_input_bits,
5960
std::size_t nb_registers,
6061
std::size_t nb_input_registers,
61-
const std::string &shm_name_prefix = "modbus_",
62-
bool force = false);
62+
const std::string &shm_name_prefix,
63+
bool force,
64+
mode_t permissions);
6365

6466
~Shm_Mapping() = default;
6567

0 commit comments

Comments
 (0)