github.com/igggame/nebulas-go@v2.1.0+incompatible/nbre/core/net_ipc/server/nipc_server.cpp (about) 1 // Copyright (C) 2018 go-nebulas authors 2 // 3 // This file is part of the go-nebulas library. 4 // 5 // the go-nebulas library is free software: you can redistribute it and/or 6 // modify 7 // it under the terms of the GNU General Public License as published by 8 // the Free Software Foundation, either version 3 of the License, or 9 // (at your option) any later version. 10 // 11 // the go-nebulas library is distributed in the hope that it will be useful, 12 // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 // GNU General Public License for more details. 15 // 16 // You should have received a copy of the GNU General Public License 17 // along with the go-nebulas library. If not, see 18 // <http://www.gnu.org/licenses/>. 19 // 20 #include "core/net_ipc/server/nipc_server.h" 21 #include "common/configuration.h" 22 #include "core/net_ipc/nipc_pkg.h" 23 #include "fs/util.h" 24 #include <boost/format.hpp> 25 26 namespace neb { 27 namespace core { 28 nipc_server::nipc_server() : m_server(nullptr), m_conn(nullptr) {} 29 nipc_server::~nipc_server() { 30 LOG(INFO) << "to destroy nipc server"; 31 if (m_thread) { 32 m_thread->join(); 33 } 34 } 35 36 void nipc_server::init_params(const nbre_params_t ¶ms) { 37 neb::configuration::instance().nbre_root_dir() = params.m_nbre_root_dir; 38 neb::configuration::instance().nbre_exe_name() = params.m_nbre_exe_name; 39 neb::configuration::instance().neb_db_dir() = params.m_neb_db_dir; 40 neb::configuration::instance().nbre_db_dir() = params.m_nbre_db_dir; 41 neb::configuration::instance().nbre_log_dir() = params.m_nbre_log_dir; 42 neb::configuration::instance().admin_pub_addr() = 43 base58_to_address(params.m_admin_pub_addr); 44 neb::configuration::instance().nbre_start_height() = 45 params.m_nbre_start_height; 46 neb::configuration::instance().nipc_listen() = params.m_nipc_listen; 47 neb::configuration::instance().nipc_port() = params.m_nipc_port; 48 49 #ifdef NDEBUG 50 // supervisor start failed with reading file 51 #else 52 // read errno_list file 53 { 54 std::string errno_file = 55 neb::fs::join_path(neb::configuration::instance().nbre_root_dir(), 56 std::string("util/errno_list")); 57 std::ifstream ifs; 58 ifs.open(errno_file.c_str(), std::ios::in | std::ios::binary); 59 if (!ifs.is_open()) { 60 throw std::invalid_argument( 61 boost::str(boost::format("can't open file %1%") % errno_file)); 62 } 63 std::string line; 64 while (std::getline(ifs, line) && !line.empty()) { 65 neb::configuration::instance().set_exit_msg(line); 66 } 67 ifs.close(); 68 } 69 #endif 70 } 71 72 bool nipc_server::start() { 73 m_mutex.lock(); 74 m_is_started = false; 75 m_mutex.unlock(); 76 77 m_got_exception_when_start_ipc = false; 78 m_thread = std::make_unique<std::thread>([&, this] { 79 try { 80 m_server = std::make_unique<::ff::net::net_nervure>(); 81 m_pkg_hub = std::make_unique<::ff::net::typed_pkg_hub>(); 82 add_all_callbacks(); 83 m_server->add_pkg_hub(*m_pkg_hub); 84 m_server->add_tcp_server(neb::configuration::instance().nipc_listen(), 85 neb::configuration::instance().nipc_port()); 86 m_request_timer = std::make_unique<api_request_timer>( 87 &m_server->ioservice(), &ipc_callback_holder::instance()); 88 89 m_server->get_event_handler() 90 ->listen<::ff::net::event::more::tcp_server_accept_connection>( 91 [this](::ff::net::tcp_connection_base_ptr conn) { 92 LOG(INFO) << "got connection"; 93 m_conn = conn; 94 m_mutex.lock(); 95 m_is_started = true; 96 m_mutex.unlock(); 97 m_request_timer->reset_conn(conn); 98 m_last_heart_beat_time = std::chrono::steady_clock::now(); 99 m_start_complete_cond_var.notify_one(); 100 }); 101 m_server->get_event_handler() 102 ->listen<::ff::net::event::tcp_lost_connection>( 103 [this](::ff::net::tcp_connection_base *) { 104 // We may restart the client. But we can ignore this and leave 105 // this to ipc_client_watcher 106 LOG(INFO) << "lost connection"; 107 m_conn.reset(); 108 m_request_timer->reset_conn(nullptr); 109 }); 110 111 m_server->get_event_handler() 112 ->listen<::ff::net::event::more::tcp_recv_stream_succ>( 113 [this](::ff::net::tcp_connection_base *, size_t) { 114 m_last_heart_beat_time = std::chrono::steady_clock::now(); 115 }); 116 m_server->get_event_handler() 117 ->listen<::ff::net::event::more::tcp_send_stream_succ>( 118 [this](::ff::net::tcp_connection_base *, size_t) { 119 m_last_heart_beat_time = std::chrono::steady_clock::now(); 120 }); 121 122 // We need start the client here 123 m_client_watcher = 124 std::unique_ptr<ipc_client_watcher>(new ipc_client_watcher( 125 neb::configuration::instance().nbre_exe_name())); 126 m_client_watcher->start(); 127 128 m_heart_beat_watcher = 129 std::make_unique<util::timer_loop>(&m_server->ioservice()); 130 m_heart_beat_watcher->register_timer_and_callback(1, [this]() { 131 auto now = std::chrono::steady_clock::now(); 132 auto duration = now - m_last_heart_beat_time; 133 auto count = 134 std::chrono::duration_cast<std::chrono::seconds>(duration).count(); 135 if (count > 60) { 136 LOG(INFO) << "lost heart beat, to kill client"; 137 m_client_watcher->kill_client(); 138 } 139 }); 140 while (true) { 141 if (m_server->ioservice().stopped()) { 142 LOG(INFO) << "ioservice already stopped, wait to restart"; 143 break; 144 } 145 try { 146 m_server->run(); 147 } catch (...) { 148 LOG(INFO) << "to reset ioservice"; 149 m_server->ioservice().reset(); 150 } 151 } 152 LOG(INFO) << "ioservice quit"; 153 } catch (const std::exception &e) { 154 m_got_exception_when_start_ipc = true; 155 LOG(ERROR) << "get exception when start ipc, " << typeid(e).name() << ", " 156 << e.what(); 157 m_start_complete_cond_var.notify_one(); 158 } catch (...) { 159 m_got_exception_when_start_ipc = true; 160 LOG(ERROR) << "get unknown exception when start ipc"; 161 m_start_complete_cond_var.notify_one(); 162 } 163 }); 164 std::unique_lock<std::mutex> _l(m_mutex); 165 if (!m_is_started && !m_got_exception_when_start_ipc) { 166 LOG(INFO) << "wait to start complete cond var"; 167 m_start_complete_cond_var.wait(_l); 168 } 169 if (m_got_exception_when_start_ipc) { 170 LOG(INFO) << "got exception when server start ipc"; 171 return false; 172 } 173 174 return true; 175 } 176 177 void nipc_server::shutdown() { 178 LOG(INFO) << "to shutdown nipc server"; 179 if (m_conn) 180 m_conn->close(); 181 m_server->stop(); 182 LOG(INFO) << "nipc server send exit command"; 183 neb::core::command_queue::instance().send_command( 184 std::make_shared<neb::core::exit_command>()); 185 } 186 187 void nipc_server::add_all_callbacks() { 188 #define define_ipc_param(type, name) 189 #define define_ipc_pkg(type, ...) 190 #define define_ipc_api(req, ack) to_recv_pkg<ack>(); 191 192 #include "core/net_ipc/ipc_interface_impl.h" 193 194 #undef define_ipc_api 195 #undef define_ipc_pkg 196 #undef define_ipc_param 197 198 m_pkg_hub->to_recv_pkg<nbre_init_req>([this](std::shared_ptr<nbre_init_req>) { 199 std::shared_ptr<nbre_init_ack> ack = std::make_shared<nbre_init_ack>(); 200 LOG(INFO) << "recv nbre_init_req"; 201 configuration &conf = configuration::instance(); 202 ack->set<p_nbre_root_dir>(conf.nbre_root_dir()); 203 ack->set<p_nbre_exe_name>(conf.nbre_exe_name()); 204 ack->set<p_neb_db_dir>(conf.neb_db_dir()); 205 ack->set<p_nbre_db_dir>(conf.nbre_db_dir()); 206 ack->set<p_nbre_log_dir>(conf.nbre_log_dir()); 207 ack->set<p_admin_pub_addr>(std::to_string(conf.admin_pub_addr())); 208 ack->set<p_nbre_start_height>(conf.nbre_start_height()); 209 m_conn->send(ack); 210 LOG(INFO) << "send nbre_init_ack"; 211 }); 212 213 m_pkg_hub->to_recv_pkg<heart_beat_t>([this](std::shared_ptr<heart_beat_t> p) { 214 LOG(INFO) << "got heart beat"; 215 m_last_heart_beat_time = std::chrono::steady_clock::now(); 216 m_conn->send(p); 217 }); 218 } 219 } // namespace core 220 } // namespace neb