Skip to content

Commit 2e6a51d

Browse files
authored
Merge pull request #37 from connectivecpp/TG
Tg
2 parents 634b8de + 63bb8e2 commit 2e6a51d

File tree

3 files changed

+417
-1
lines changed

3 files changed

+417
-1
lines changed

example/CMakeLists.txt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,9 @@ set ( example_sources
1616
"${example_source_dir}/chat_server_demo.cpp"
1717
"${example_source_dir}/simple_chat_demo.cpp"
1818
"${example_source_dir}/echo_binary_text_server_demo.cpp"
19-
"${example_source_dir}/echo_binary_text_client_demo.cpp" )
19+
"${example_source_dir}/echo_binary_text_client_demo.cpp"
20+
"${example_source_dir}/udp_broadcast_demo.cpp"
21+
"${example_source_dir}/udp_receiver_demo.cpp" )
2022

2123
set ( OPTIONS "" )
2224
set ( DEFINITIONS "" )

example/udp_broadcast_demo.cpp

Lines changed: 246 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,246 @@
1+
/**
2+
* @fille
3+
*
4+
* @ingroup example_module
5+
*
6+
* @brief UDP broadcast demo. Text messages are sent to the local network
7+
* UDP broadcast address.
8+
*
9+
* @author Thurman Gillespy
10+
*
11+
* @copyright (c) Thurman Gillespy
12+
* 7/16/19
13+
*
14+
* Distributed under the Boost Software License, Version 1.0.
15+
* (See accompanying file LICENSE.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
16+
*
17+
* Sample make file. Assumes all repositories are in some directory.
18+
19+
g++ -std=c++17 -Wall -Werror \
20+
-I ../include \
21+
-I ../../utility-rack/include/ \
22+
-I ../../asio/asio/include/ \
23+
-I ../../boost* \
24+
udp_broadcast_demo.cpp -lpthread -o udp_broad
25+
26+
*/
27+
28+
#include <iostream>
29+
#include <cstdlib> // EXIT_SUCCESS
30+
#include <string>
31+
#include <thread>
32+
#include <exception>
33+
#include <cassert>
34+
35+
#include "net_ip/net_ip.hpp"
36+
#include "net_ip/basic_net_entity.hpp"
37+
#include "net_ip/component/worker.hpp"
38+
39+
const std::string HELP_PRM = "-h";
40+
const std::string ERR_PRM = "-e";
41+
const std::string BROAD_PRM = "-b";
42+
43+
auto print_useage = [] () {
44+
const std::string USEAGE = \
45+
"usage:\n"
46+
" ./udp_broad [-h] Print useage\n"
47+
" ./udp_broad [-e] <IP address> [subnet mask] [port]\n"
48+
" -e Print errors and system messages\n"
49+
" IP address IP address of this machine\n"
50+
" subnet mask Default: 255.255.255.0\n"
51+
" port Default: 5005\n"
52+
" ./udp_broad [-e] -b <broadcast address> [port]\n"
53+
" -e Print errors and system messages\n"
54+
" -b broadcast address\n"
55+
" known broadcast address for this machine\n"
56+
" ex: 192.168.1.255, 172.145.255.255\n"
57+
" port Default: 5005";
58+
59+
std::cout << USEAGE << std::endl;
60+
};
61+
62+
// process comannand line process_args
63+
bool process_args(int argc, char* argv[], bool& print_errors, std::string& ip_address,
64+
std::string& net_mask, int& port, std::string& broadcast_addr) {
65+
66+
int offset = 0;
67+
68+
using addr4 = asio::ip::address_v4;
69+
70+
if (argc == 1 || argv[1] == HELP_PRM) {
71+
print_useage();
72+
return EXIT_FAILURE;
73+
}
74+
75+
if (argv[1] == ERR_PRM) {
76+
print_errors = true;
77+
offset = 1;
78+
}
79+
80+
if (argc <= 1 + offset) {
81+
print_useage();
82+
return EXIT_FAILURE;
83+
}
84+
85+
try {
86+
87+
if (argv[1 + offset] == BROAD_PRM) {
88+
if (argc <= 2 + offset) {
89+
print_useage();
90+
return EXIT_FAILURE;
91+
}
92+
broadcast_addr = argv[2 + offset];
93+
// check address not malformed or empty
94+
try {
95+
addr4 t = asio::ip::make_address_v4(broadcast_addr);
96+
assert( t.to_string() != "");
97+
}
98+
99+
catch (...) { throw; }
100+
101+
if (argc == 4 + offset) {
102+
port = std::stoi(argv[3 + offset]);
103+
}
104+
} else {
105+
// get ip address
106+
ip_address = argv[1 + offset];
107+
// subnet mask
108+
if (argc >= 3 + offset) {
109+
net_mask = argv[2 + offset];
110+
}
111+
// port
112+
if (argc >= 4 + offset) {
113+
port = std::stoi(argv[3 + offset]);
114+
}
115+
// too many params?
116+
if (argc >= 5 + offset) {
117+
std::cout << "too many parameters" << std::endl;
118+
print_useage();
119+
return EXIT_FAILURE;
120+
}
121+
// create broadcast address
122+
try {
123+
124+
addr4 asaddr = asio::ip::make_address_v4(ip_address);
125+
addr4 asnetm = asio::ip::make_address_v4(net_mask);
126+
addr4 asbroad = addr4::broadcast(asaddr, asnetm);
127+
128+
broadcast_addr = asbroad.to_string();
129+
}
130+
131+
catch (...) { throw; }
132+
} // end else
133+
} // end try
134+
135+
catch (std::exception& e) {
136+
std::cout << "malformed ipv4 address or network mask" << std::endl;
137+
std::cout << " what: " << e.what() << std::endl << std::endl;
138+
print_useage();
139+
return EXIT_FAILURE;
140+
}
141+
142+
return EXIT_SUCCESS;
143+
}
144+
145+
int main(int argc, char* argv[]) {
146+
std::string ip_address = "";
147+
std::string broadcast_addr = "";
148+
std::string net_mask = "255.255.255.0";
149+
const int PORT = 5005;
150+
bool print_errors = false;
151+
int port = PORT;
152+
153+
chops::net::udp_io_interface udp_iof;
154+
155+
if (process_args(argc, argv, print_errors, ip_address, net_mask, port,
156+
broadcast_addr) == EXIT_FAILURE) {
157+
return EXIT_FAILURE;
158+
}
159+
assert(broadcast_addr != "");
160+
161+
/**** lambda callbacks ****/
162+
// io state change handler
163+
auto io_state_chng_hndlr = [&udp_iof, &port, &broadcast_addr, print_errors]
164+
(chops::net::udp_io_interface iof, std::size_t n, bool flag) {
165+
166+
if (flag) {
167+
if (print_errors) {
168+
std::cout << "io state change: start_io" << std::endl;
169+
}
170+
171+
// set socket flag for UPD broadcast
172+
auto& sock = iof.get_socket();
173+
asio::socket_base::broadcast opt(true);
174+
sock.set_option(opt);
175+
// set default endpoint broadcast address for this subnet
176+
asio::ip::udp::endpoint ep;
177+
// set tha ip address and port
178+
ep.address(asio::ip::make_address_v4(broadcast_addr));
179+
ep.port(port);
180+
// start the io_interface
181+
iof.start_io(ep);
182+
udp_iof = iof; // return iof to main, used later to send text
183+
} else {
184+
if (print_errors) {
185+
std::cout << "io state change: stop_io" << std::endl;
186+
}
187+
iof.stop_io();
188+
}
189+
190+
};
191+
192+
// error handler
193+
auto err_func = [&print_errors] (chops::net::udp_io_interface iof, std::error_code err) {
194+
if (print_errors) {
195+
std::string err_text = err.category().name();
196+
err_text += ": " + std::to_string(err.value()) + ", " +
197+
err.message();
198+
std::cerr << err_text << std::endl;
199+
}
200+
};
201+
202+
// begin
203+
std::cout << "chops-net-ip UDP broadcast demo" << std::endl;
204+
if (ip_address != "") {
205+
std::cout << " IP address:net mask = " << ip_address << ":" << net_mask << std::endl;
206+
}
207+
std::cout << " broadcast address:port = " << broadcast_addr << ":" << port << std::endl;
208+
std::cout << " print errors and system messages: ";
209+
std::cout << (print_errors ? "ON" : "OFF") << std::endl;
210+
std::cout << std::endl;
211+
std::cout << "Enter text for UDP broadcast on this subnet" << std::endl;
212+
std::cout << "Enter \'quit\' or empty string to exit proggram" << std::endl;
213+
214+
// work guard - handles @c std::thread and @c asio::io_context management
215+
chops::net::worker wk;
216+
wk.start();
217+
218+
// create @c net_ip instance
219+
chops::net::net_ip udp_broad(wk.get_io_context());
220+
221+
// create a @c network_entitiy
222+
chops::net::udp_net_entity udpne;
223+
udpne = udp_broad.make_udp_sender(); // send only, no reads
224+
assert(udpne.is_valid());
225+
// start it, emplace handlers
226+
udpne.start(io_state_chng_hndlr, err_func);
227+
228+
// get text from user, send to UDP broadcast address
229+
bool finished = false;
230+
while (!finished) {
231+
std::string s;
232+
getline(std::cin, s);
233+
if (s == "quit" || s == "") {
234+
finished = true;
235+
continue;
236+
}
237+
assert(udp_iof.is_valid());
238+
udp_iof.send(s.data(), s.size());
239+
}
240+
241+
// cleanup
242+
udpne.stop();
243+
wk.stop();
244+
245+
return EXIT_SUCCESS;
246+
}

0 commit comments

Comments
 (0)