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 &params) {
    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