diff --git a/Chapter06/03_tasks_processor_network/03_tasks_processor_network.pro b/Chapter06/03_tasks_processor_network_client/03_tasks_processor_network_client.pro similarity index 59% rename from Chapter06/03_tasks_processor_network/03_tasks_processor_network.pro rename to Chapter06/03_tasks_processor_network_client/03_tasks_processor_network_client.pro index 475fe749..c349ffd1 100644 --- a/Chapter06/03_tasks_processor_network/03_tasks_processor_network.pro +++ b/Chapter06/03_tasks_processor_network_client/03_tasks_processor_network_client.pro @@ -2,11 +2,16 @@ if (!include(../../config.txt)) { error("Failed to open config.txt") } +# We are NOT building an executable +TEMPLATE -= app + +# ... we are building a library. +TEMPLATE = lib + HEADERS += \ ../01_tasks_processor_base/tasks_processor_base.hpp \ ../02_tasks_processor_timers/tasks_processor_timers.hpp \ - tasks_processor_network.hpp + tasks_processor_network_client.hpp -SOURCES += main.cpp +SOURCES += client.cpp QMAKE_CXXFLAGS += $$CPP11FLAG -!msvc:LIBS += -lboost_thread -lboost_system diff --git a/Chapter06/03_tasks_processor_network_client/client.cpp b/Chapter06/03_tasks_processor_network_client/client.cpp new file mode 100644 index 00000000..fa8cbe3d --- /dev/null +++ b/Chapter06/03_tasks_processor_network_client/client.cpp @@ -0,0 +1,54 @@ +// Big part of code for this recipe +// in in this header: +#include "tasks_processor_network_client.hpp" +#include "client.hpp" +using namespace tp_network_client; + +bool g_authed = false; + +void process_server_response( + connection_ptr&& soc, + const boost::system::error_code& err) +{ + if (err && err != boost::asio::error::eof) { + std::cerr << "process_server_response: Client error on receive: " << err.message() << '\n'; + assert(false); + } + + if (soc->data.size() != 2) { + std::cerr << "process_server_response: wrong bytes count\n"; + assert(false); + } + + if (soc->data != "OK") { + std::cerr << "process_server_response: wrong response: " << soc->data << '\n'; + assert(false); + } + + g_authed = true; + soc->shutdown(); + tasks_processor::stop(); +} + +void receive_auth_response(connection_ptr&& soc, const boost::system::error_code& err) { + if (err) { + std::cerr << "receive_auth_response: error on sending data: " << err.message() << '\n'; + assert(false); + } + + async_read_data( + std::move(soc), + &process_server_response, + 2 + ); +} + +void send_auth() { + connection_ptr soc = tasks_processor::create_connection("127.0.0.1", g_port_num); + soc->data = "auth_name"; + + async_write_data( + std::move(soc), + &receive_auth_response + ); +} diff --git a/Chapter06/03_tasks_processor_network_client/client.hpp b/Chapter06/03_tasks_processor_network_client/client.hpp new file mode 100644 index 00000000..7a9a6aa6 --- /dev/null +++ b/Chapter06/03_tasks_processor_network_client/client.hpp @@ -0,0 +1,5 @@ +// Helper heade file +extern bool g_authed; +const unsigned short g_port_num = 65001; + +void send_auth(); diff --git a/Chapter06/03_tasks_processor_network/tasks_processor_network.hpp b/Chapter06/03_tasks_processor_network_client/tasks_processor_network_client.hpp similarity index 55% rename from Chapter06/03_tasks_processor_network/tasks_processor_network.hpp rename to Chapter06/03_tasks_processor_network_client/tasks_processor_network_client.hpp index fcfbb778..2cbd2e07 100644 --- a/Chapter06/03_tasks_processor_network/tasks_processor_network.hpp +++ b/Chapter06/03_tasks_processor_network_client/tasks_processor_network_client.hpp @@ -1,13 +1,12 @@ -#ifndef BOOK_CHAPTER6_TASK_PROCESSOR_NETWORK_HPP -#define BOOK_CHAPTER6_TASK_PROCESSOR_NETWORK_HPP +#ifndef BOOK_CHAPTER6_TASK_PROCESSOR_NETWORK_CLIENT_HPP +#define BOOK_CHAPTER6_TASK_PROCESSOR_NETWORK_CLIENT_HPP #include "../02_tasks_processor_timers/tasks_processor_timers.hpp" #include +#include -#include // std::unique_ptr - -struct connection_with_data { +struct connection_with_data: boost::noncopyable { boost::asio::ip::tcp::socket socket; std::string data; @@ -30,6 +29,9 @@ struct connection_with_data { } }; + +#include // std::unique_ptr + typedef std::unique_ptr connection_ptr; @@ -46,16 +48,22 @@ struct task_wrapped_with_connection { {} void operator()(const boost::system::error_code& error, std::size_t bytes_count) { - const auto task = detail::make_task_wrapped([this, &error, bytes_count]() { + const auto lambda = [this, &error, bytes_count]() { this->c_->data.resize(bytes_count); this->task_unwrapped_(std::move(this->c_), error); - }); + }; + + const auto task = detail::make_task_wrapped(lambda); task(); } }; #include + +template +struct task_wrapped_with_connection; + template void async_write_data(connection_ptr&& c, const Functor& f) { boost::asio::ip::tcp::socket& s = c->socket; @@ -69,6 +77,7 @@ void async_write_data(connection_ptr&& c, const Functor& f) { } #include + template void async_read_data(connection_ptr&& c, const Functor& f, std::size_t at_least_bytes) { c->data.resize(at_least_bytes); @@ -101,78 +110,15 @@ void async_read_dataat_least(connection_ptr&& c, const Functor& f, std::size_t a ); } -#include -namespace tp_network { +namespace tp_network_client { class tasks_processor: public tp_timers::tasks_processor { - typedef boost::asio::ip::tcp::acceptor acceptor_t; - typedef boost::function on_accpet_func_t; - - struct tcp_listener { - acceptor_t acceptor_; - const on_accpet_func_t func_; - connection_ptr new_c_; - - template - tcp_listener( - boost::asio::io_service& io_service, - unsigned short port, - const Functor& task_unwrapped) - : acceptor_(io_service, boost::asio::ip::tcp::endpoint( - boost::asio::ip::tcp::v4(), port - )) - , func_(task_unwrapped) - {} - }; - typedef std::unique_ptr listener_ptr; - - struct handle_accept { - listener_ptr listener; - - explicit handle_accept(listener_ptr&& l) - : listener(std::move(l)) - {} - - void operator()(const boost::system::error_code& error) { - task_wrapped_with_connection task(std::move(listener->new_c_), listener->func_); - if (error) { - std::cerr << error << '\n'; - } - - start_accepting_connection(std::move(listener)); - task(error, 0); - } - }; - - static void start_accepting_connection(listener_ptr&& listener) { - if (!listener->acceptor_.is_open()) { - return; - } - - listener->new_c_.reset( - new connection_with_data(listener->acceptor_.get_io_service()) - ); - - boost::asio::ip::tcp::socket& s = listener->new_c_->socket; - acceptor_t& a = listener->acceptor_; - a.async_accept( - s, - tasks_processor::handle_accept(std::move(listener)) - ); - } + // ... public: - template - static void add_listener(unsigned short port_num, const Functor& f) { - std::unique_ptr listener( - new tcp_listener(get_ios(), port_num, f) - ); - - start_accepting_connection(std::move(listener)); - } - static connection_ptr create_connection(const char* addr, unsigned short port_num) { connection_ptr c( new connection_with_data(get_ios()) ); + c->socket.connect(boost::asio::ip::tcp::endpoint( boost::asio::ip::address_v4::from_string(addr), port_num @@ -182,6 +128,6 @@ class tasks_processor: public tp_timers::tasks_processor { } }; -} // namespace tp_network +} // namespace tp_network_cleint #endif // BOOK_CHAPTER6_TASK_PROCESSOR_NETWORK_HPP diff --git a/Chapter06/04_tasks_processor_network_accept/04_tasks_processor_network_accept.pro b/Chapter06/04_tasks_processor_network_accept/04_tasks_processor_network_accept.pro new file mode 100644 index 00000000..bd61d665 --- /dev/null +++ b/Chapter06/04_tasks_processor_network_accept/04_tasks_processor_network_accept.pro @@ -0,0 +1,17 @@ +if (!include(../../config.txt)) { + error("Failed to open config.txt") +} + +HEADERS += \ + ../01_tasks_processor_base/tasks_processor_base.hpp \ + ../02_tasks_processor_timers/tasks_processor_timers.hpp \ + ../03_tasks_processor_network_client/tasks_processor_network_client.hpp \ + ../03_tasks_processor_network_client/client.hpp \ + 04_tasks_processor_network_accept.hpp + +SOURCES += \ + ../03_tasks_processor_network_client/client.cpp \ + main.cpp + +QMAKE_CXXFLAGS += $$CPP11FLAG +!msvc:LIBS += -lboost_thread -lboost_system diff --git a/Chapter06/03_tasks_processor_network/main.cpp b/Chapter06/04_tasks_processor_network_accept/main.cpp similarity index 55% rename from Chapter06/03_tasks_processor_network/main.cpp rename to Chapter06/04_tasks_processor_network_accept/main.cpp index 1aa72467..7e7a2da5 100644 --- a/Chapter06/03_tasks_processor_network/main.cpp +++ b/Chapter06/04_tasks_processor_network_accept/main.cpp @@ -1,6 +1,7 @@ // Big part of code for this recipe // in in this header: -#include "tasks_processor_network.hpp" +#include "tasks_processor_network_accept.hpp" +#include "../03_tasks_processor_network_client/client.hpp" using namespace tp_network; class authorizer { @@ -43,59 +44,9 @@ class authorizer { } }; -bool g_authed = false; - -void finsh_socket_auth_task( - connection_ptr&& soc, - const boost::system::error_code& err) -{ - if (err && err != boost::asio::error::eof) { - std::cerr << "finsh_socket_auth_task: Client error on recieve: " << err.message() << '\n'; - assert(false); - } - - if (soc->data.size() != 2) { - std::cerr << "finsh_socket_auth_task: wrong bytes count\n"; - assert(false); - } - - if (soc->data != "OK") { - std::cerr << "finsh_socket_auth_task: wrong response: " << soc->data << '\n'; - assert(false); - } - - g_authed = true; - soc->shutdown(); - tasks_processor::stop(); -} - -void recieve_auth_task(connection_ptr&& soc, const boost::system::error_code& err) { - if (err) { - std::cerr << "recieve_auth_task: Client error on recieve: " << err.message() << '\n'; - assert(false); - } - - async_read_data( - std::move(soc), - &finsh_socket_auth_task, - 2 - ); -} - -const unsigned short g_port_num = 65001; - -void send_auth_task() { - connection_ptr soc = tasks_processor::create_connection("127.0.0.1", g_port_num); - soc->data = "auth_name"; - - async_write_data( - std::move(soc), - &recieve_auth_task - ); -} int main() { - tasks_processor::run_delayed(boost::posix_time::seconds(1), &send_auth_task); + tasks_processor::run_delayed(boost::posix_time::seconds(1), &send_auth); tasks_processor::add_listener(g_port_num, &authorizer::on_connection_accpet); assert(!g_authed); diff --git a/Chapter06/04_tasks_processor_network_accept/tasks_processor_network_accept.hpp b/Chapter06/04_tasks_processor_network_accept/tasks_processor_network_accept.hpp new file mode 100644 index 00000000..5722e4e8 --- /dev/null +++ b/Chapter06/04_tasks_processor_network_accept/tasks_processor_network_accept.hpp @@ -0,0 +1,90 @@ +#ifndef BOOK_CHAPTER6_TASK_PROCESSOR_NETWORK_ACCEPT_HPP +#define BOOK_CHAPTER6_TASK_PROCESSOR_NETWORK_ACCEPT_HPP + +#include "../03_tasks_processor_network_client/tasks_processor_network_client.hpp" + +#include +namespace tp_network { + +class tasks_processor: public tp_network_client::tasks_processor { + typedef boost::asio::ip::tcp::acceptor acceptor_t; + typedef boost::function on_accpet_func_t; + + struct tcp_listener { + acceptor_t acceptor_; + const on_accpet_func_t func_; + connection_ptr new_c_; + + template + tcp_listener( + boost::asio::io_service& io_service, + unsigned short port, + const Functor& task_unwrapped) + : acceptor_(io_service, boost::asio::ip::tcp::endpoint( + boost::asio::ip::tcp::v4(), port + )) + , func_(task_unwrapped) + {} + }; + typedef std::unique_ptr listener_ptr; + + struct handle_accept { + listener_ptr listener; + + explicit handle_accept(listener_ptr&& l) + : listener(std::move(l)) + {} + + void operator()(const boost::system::error_code& error) { + task_wrapped_with_connection task(std::move(listener->new_c_), listener->func_); + if (error) { + std::cerr << error << '\n'; + } + + start_accepting_connection(std::move(listener)); + task(error, 0); + } + }; + + static void start_accepting_connection(listener_ptr&& listener) { + if (!listener->acceptor_.is_open()) { + return; + } + + listener->new_c_.reset( + new connection_with_data(listener->acceptor_.get_io_service()) + ); + + boost::asio::ip::tcp::socket& s = listener->new_c_->socket; + acceptor_t& a = listener->acceptor_; + a.async_accept( + s, + tasks_processor::handle_accept(std::move(listener)) + ); + } + +public: + template + static void add_listener(unsigned short port_num, const Functor& f) { + std::unique_ptr listener( + new tcp_listener(get_ios(), port_num, f) + ); + + start_accepting_connection(std::move(listener)); + } + + static connection_ptr create_connection(const char* addr, unsigned short port_num) { + connection_ptr c( new connection_with_data(get_ios()) ); + + c->socket.connect(boost::asio::ip::tcp::endpoint( + boost::asio::ip::address_v4::from_string(addr), + port_num + )); + + return c; + } +}; + +} // namespace tp_network + +#endif // BOOK_CHAPTER6_TASK_PROCESSOR_NETWORK_ACCEPT_HPP diff --git a/Chapter06/05_tasks_processor_multithread/05_tasks_processor_multithread.pro b/Chapter06/05_tasks_processor_multithread/05_tasks_processor_multithread.pro index 37456548..179fc23f 100644 --- a/Chapter06/05_tasks_processor_multithread/05_tasks_processor_multithread.pro +++ b/Chapter06/05_tasks_processor_multithread/05_tasks_processor_multithread.pro @@ -5,7 +5,8 @@ if (!include(../../config.txt)) { HEADERS += \ ../01_tasks_processor_base/tasks_processor_base.hpp \ ../02_tasks_processor_timers/tasks_processor_timers.hpp \ - ../03_tasks_processor_network/tasks_processor_network.hpp \ + ../03_tasks_processor_network_client/tasks_processor_network_client.hpp \ + ../04_tasks_processor_network_accept/tasks_processor_network_accept.hpp \ tasks_processor_multithread.hpp diff --git a/Chapter06/05_tasks_processor_multithread/tasks_processor_multithread.hpp b/Chapter06/05_tasks_processor_multithread/tasks_processor_multithread.hpp index cbee97dc..dd52526a 100644 --- a/Chapter06/05_tasks_processor_multithread/tasks_processor_multithread.hpp +++ b/Chapter06/05_tasks_processor_multithread/tasks_processor_multithread.hpp @@ -1,7 +1,7 @@ #ifndef BOOK_CHAPTER6_TASK_PROCESSOR_MULTITHREAD_HPP #define BOOK_CHAPTER6_TASK_PROCESSOR_MULTITHREAD_HPP -#include "../03_tasks_processor_network/tasks_processor_network.hpp" +#include "../04_tasks_processor_network_accept/tasks_processor_network_accept.hpp" #include diff --git a/Chapter06/Chapter06.pro b/Chapter06/Chapter06.pro index 2d92c2f0..d736e335 100644 --- a/Chapter06/Chapter06.pro +++ b/Chapter06/Chapter06.pro @@ -3,7 +3,8 @@ TEMPLATE = subdirs SUBDIRS += \ 01_tasks_processor_base \ 02_tasks_processor_timers \ - 03_tasks_processor_network \ + 03_tasks_processor_network_client \ + 04_tasks_processor_network_accept \ 05_tasks_processor_multithread \ 06_conveyor \ 07_nonblocking_barrier \ diff --git a/test.py b/test.py index e0b9141a..cfd7a360 100644 --- a/test.py +++ b/test.py @@ -62,6 +62,7 @@ class tester: 'Chapter10/my_library': ('', '', -11), 'Chapter10/no_rtti': ('type_index type_id() [with T = double]', '', 0), 'Chapter11/erasing_files': ('', 'Failed to create a symlink\n', 0), + 'Chapter11/reading_files': ('', "reading_files: main.cpp:14: int main(int, char**): Assertion `argc >= 2' failed.\n", -6), 'Chapter12/gil': ('', "terminate called after throwing an instance of 'std::ios_base::failure'\n what(): file_mgr: failed to open file\n", -6), 'Chapter12/graph': ('Boost\nC++ guru\n', '', 0), 'Chapter12/graph_vis': ('digraph G {\n0 [label="C++"];\n1 [label="STL"];\n2 [label="Boost"];\n3 [label="C++ guru"];\n4 [label="C"];\n0->1 ;\n1->2 ;\n2->3 ;\n4->3 ;\n}\n', '', 0), @@ -93,12 +94,6 @@ def _test_validate(test_name): if tester.outputs[test_name][0] == '' and tester.outputs[test_name][1] == '' and tester.outputs[test_name][2] == 0: return - tester.outputs[test_name] = ( - tester.outputs[test_name][0].replace('\r', ''), - tester.outputs[test_name][1].replace('\r', ''), - tester.outputs[test_name][2], - ) - if test_name not in tester.expected: print '"{}" must not produce output and finish with code 0. Info:'.format(test_name) tester._print_test_output(test_name) @@ -154,7 +149,7 @@ def _test_program_options_short(test_name, path): tester._test(command, test_name + "_70") copyfile( - os.path.join(test_name, "apples_oranges.cfg") + os.path.join(os.path.dirname(path), "apples_oranges.cfg") , "./apples_oranges.cfg" ) command = [path, '--apples=80'] @@ -166,9 +161,6 @@ def _test_program_options_short(test_name, path): @staticmethod def _test_tasks_processor_signals(test_name, path): - if os.name == 'nt': - return # Signals and Windows are not pals! - proc = subprocess.Popen(path, stdout=subprocess.PIPE, stderr=subprocess.PIPE) sleep(1) proc.send_signal(signal.SIGINT) @@ -217,26 +209,6 @@ def _test_regex_replace(test_name, path): tester.outputs[test_name + "_extra"] = (out1, out2, proc.returncode) tester._test_validate(test_name + "_extra") - @staticmethod - def _test_export_import(test_name, path): - try: - copyfile( - "Chapter10/my_library/debug/my_library.dll", - "./my_library.dll" - ) - except: - pass - - try: - copyfile( - "Chapter10/my_library/release/my_library.dll", - "./my_library.dll" - ) - except: - pass - - tester._test(path, test_name) - @staticmethod def _test_gil(test_name, path): command = [path, 'get-boost.png'] @@ -264,31 +236,25 @@ def _test_recipe(path): special_cases = { "Chapter01/01_A_program_options_base": tester._test_program_options_base, "Chapter01/01_B_program_options_short": tester._test_program_options_short, - "Chapter01/05_optional": tester._test_but_ignore_output_diff, # Different rand() implementations - "Chapter01/09_type_index": tester._test_but_ignore_output_diff, # Different demangled representation of a type - "Chapter01/12_A_noncopyable_movable": tester._test_but_ignore_output_diff, # Different C++11 support - "Chapter05/02_mutex": tester._test_but_ignore_output_diff, # Intentionally has data race - "Chapter06/08_exception_ptr": tester._test_but_ignore_output_diff, # Different demangled exception name "Chapter06/09_tasks_processor_signals": tester._test_tasks_processor_signals, "Chapter07/02_regex_match": tester._test_regex_match, "Chapter07/03_regex_replace": tester._test_regex_replace, - 'Chapter08/01_vector_of_types': tester._test_but_ignore_output_diff, # Different manglings - 'Chapter08/02_manipulating_vector_of_types': tester._test_but_ignore_output_diff, # Different manglings - "Chapter10/export_import": tester._test_export_import, + 'Chapter08/01_vector_of_types': tester._test_but_ignore_output_diff, # Different manglings + 'Chapter08/02_manipulating_vector_of_types': tester._test_but_ignore_output_diff, # Different manglings "Chapter11/listing_files": tester._test_but_ignore_output_diff, + "Chapter12/gil": tester._test_gil, + "Chapter05/02_mutex": tester._test_but_ignore_output_diff, "Chapter11/coroutines": tester._test_but_ignore_output_diff, # Sanitizers do not like coroutines and add some warnings "Chapter12/random": tester._test_but_ignore_output_diff, - # TODO: "Chapter10/no_rtti": tester._ignore, - "Chapter11/reading_files": tester._ignore, "Chapter11/interprocess_basics": tester._ignore, "Chapter11/interprocess_pointers": tester._ignore, "Chapter11/interprocess_queue": tester._ignore, - "Chapter12/gil": tester._ignore, #tester._test_gil, + "Chapter11/interprocess_queue": tester._ignore, } - test_name = os.path.dirname(os.path.relpath(path)).replace('\\release', '').replace('\\debug', '').replace('\\', '/') + test_name = os.path.dirname(os.path.relpath(path)) print "* {}".format(test_name) if test_name in special_cases: f = special_cases[test_name] @@ -311,7 +277,7 @@ def _print_outputs_short(): @staticmethod def _is_exe(path): - return os.path.isfile(path) and os.access(path, os.X_OK) and (os.name != 'nt' or '.exe' in path) and '/.git/' not in path and '.sh' not in path + return os.path.isfile(path) and os.access(path, os.X_OK) and (os.name != 'nt' or '.exe' in path) and '/.git/' not in path and '.sh' not in path and '.so' not in path ''' ****************************************** Public functions *********************************************** ''' @staticmethod