/* * Copyright 2014 Cloudius Systems */ #include "core/reactor.hh" #include "core/app-template.hh" #include "core/temporary_buffer.hh" #include "core/smp.hh" #include #include static std::string str_ping{"ping"}; static std::string str_txtx{"txtx"}; static std::string str_rxrx{"rxrx"}; static std::string str_pong{"pong"}; static std::string str_unknow{"unknow cmd"}; static int tx_msg_total_size = 100 * 1024 * 1024; static int tx_msg_size = 4 * 1024; static int tx_msg_nr = tx_msg_total_size / tx_msg_size; static int rx_msg_size = 4 * 1024; static std::string str_txbuf(tx_msg_size, 'X'); class tcp_server { std::vector _listeners; public: future<> listen(ipv4_addr addr) { listen_options lo; lo.reuse_address = true; _listeners.push_back(engine.listen(make_ipv4_address(addr), lo)); do_accepts(_listeners.size() - 1); return make_ready_future<>(); } void do_accepts(int which) { _listeners[which].accept().then([this, which] (connected_socket fd, socket_address addr) mutable { auto conn = new connection(*this, std::move(fd), addr); conn->process().rescue([this, conn] (auto get_ex) { delete conn; try { get_ex(); } catch (std::exception& ex) { std::cout << "request error " << ex.what() << "\n"; } }); do_accepts(which); }).rescue([] (auto get_ex) { try { get_ex(); } catch (std::exception& ex) { std::cout << "accept failed: " << ex.what() << "\n"; } }); } class connection { connected_socket _fd; input_stream _read_buf; output_stream _write_buf; public: connection(tcp_server& server, connected_socket&& fd, socket_address addr) : _fd(std::move(fd)) , _read_buf(_fd.input()) , _write_buf(_fd.output()) {} future<> process() { return read(); } future<> read() { if (_read_buf.eof()) { return make_ready_future(); } // Expect 4 bytes cmd from client size_t n = 4; return _read_buf.read_exactly(n).then([this] (temporary_buffer buf) { if (buf.size() == 0) { return make_ready_future(); } auto cmd = std::string(buf.get(), buf.size()); // pingpong test if (cmd == str_ping) { return _write_buf.write(str_pong).then([this] { return _write_buf.flush(); }).then([this] { return this->read(); }); // server tx test } else if (cmd == str_txtx) { return tx_test(); // server tx test } else if (cmd == str_rxrx) { return rx_test(); // unknow test } else { return _write_buf.write(str_unknow).then([this] { return _write_buf.flush(); }).then([this] { return make_ready_future(); }); } }); } future<> do_write(int end) { if (end == 0) { return make_ready_future<>(); } return _write_buf.write(str_txbuf).then([this, end] { return _write_buf.flush(); }).then([this, end] { return do_write(end - 1); }); } future<> tx_test() { return do_write(tx_msg_nr).then([this] { return _write_buf.close(); }).then([this] { return make_ready_future<>(); }); } future<> do_read() { return _read_buf.read_exactly(rx_msg_size).then([this] (temporary_buffer buf) { if (buf.size() == 0) { return make_ready_future(); } else { return do_read(); } }); } future<> rx_test() { return do_read().then([] { return make_ready_future<>(); }); } }; }; namespace bpo = boost::program_options; int main(int ac, char** av) { app_template app; app.add_options() ("port", bpo::value()->default_value(10000), "TCP server port") ; return app.run(ac, av, [&] { auto&& config = app.configuration(); uint16_t port = config["port"].as(); auto server = new distributed; server->start().then([server = std::move(server), port] () mutable { server->invoke_on_all(&tcp_server::listen, ipv4_addr{port}); }).then([port] { std::cout << "Seastar TCP server listening on port " << port << " ...\n"; }); }); }