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