15        : m_host(endpoint.first),
 
   16          m_port(endpoint.second),
 
   17          m_enable_cors(enable_cors) {}
 
 
   24        auto sock = MHD_quiesce_daemon(m_daemon);
 
   29                = MHD_get_daemon_info(m_daemon,
 
   30                                      MHD_DAEMON_INFO_CURRENT_CONNECTIONS);
 
   31            if(inf->num_connections == 0) {
 
   36            constexpr auto wait_time = std::chrono::milliseconds(100);
 
   37            std::this_thread::sleep_for(wait_time);
 
   43        MHD_stop_daemon(m_daemon);
 
 
   53            = (MHD_is_feature_supported(MHD_FEATURE_EPOLL) == MHD_YES);
 
   55            = has_epoll ? MHD_USE_EPOLL_INTERNALLY : MHD_USE_POLL_INTERNALLY;
 
   56        auto connection_limit = has_epoll ? 65536 : FD_SETSIZE - 4;
 
   57        auto addr = sockaddr_in{};
 
   58        addr.sin_family = AF_INET;
 
   59        addr.sin_port = htons(m_port);
 
   60        inet_aton(m_host.c_str(),
 
   61                  reinterpret_cast<in_addr*
>(&addr.sin_addr.s_addr));
 
   62        m_daemon = MHD_start_daemon(use_flag | MHD_ALLOW_SUSPEND_RESUME
 
   69                                    MHD_OPTION_NOTIFY_COMPLETED,
 
   72                                    MHD_OPTION_THREAD_POOL_SIZE,
 
   73                                    std::thread::hardware_concurrency(),
 
   74                                    MHD_OPTION_CONNECTION_TIMEOUT,
 
   76                                    MHD_OPTION_CONNECTION_LIMIT,
 
   81        return m_daemon != 
nullptr;
 
 
   84    auto json_rpc_http_server::callback(
void* cls,
 
   85                                        struct MHD_Connection* connection,
 
   89                                        const char* upload_data,
 
   90                                        size_t* upload_data_size,
 
   91                                        void** con_cls) -> MHD_Result {
 
   92        if(*con_cls == 
nullptr) {
 
   93            auto new_req = std::make_unique<request>();
 
   94            new_req->m_connection = connection;
 
   96            new_req->m_server = 
server;
 
   97            new_req->m_origin = MHD_lookup_connection_value(connection,
 
  100            *con_cls = new_req.get();
 
  102                std::unique_lock l(
server->m_requests_mut);
 
  103                server->m_requests.emplace(new_req.get(), std::move(new_req));
 
  109        auto* req = 
static_cast<request*
>(*con_cls);
 
  112        if(method == std::string(
"OPTIONS") && req->m_server->m_enable_cors) {
 
  113            send_cors_response(req);
 
  117        if(method != std::string(
"POST")) {
 
  118            req->m_code = MHD_HTTP_METHOD_NOT_ALLOWED;
 
  119            send_response(
"HTTP method not allowed", req);
 
  123        if(*upload_data_size != 0) {
 
  124            req->m_request.write(
 
  126                static_cast<std::streamsize
>(*upload_data_size));
 
  127            *upload_data_size = 0;
 
  131        if(!req->m_server->m_running) {
 
  132            req->m_code = MHD_HTTP_SERVICE_UNAVAILABLE;
 
  133            send_response(
"Server is shutting down", req);
 
  139        auto success = req->m_server->handle_request(req);
 
  141            req->m_code = MHD_HTTP_BAD_REQUEST;
 
  142            send_response(
"Invalid request payload", req);
 
  148    auto json_rpc_http_server::send_cors_response(request* request_info)
 
  151        auto* result = MHD_create_response_from_buffer(
 
  153            static_cast<void*
>(
response.data()),
 
  154            MHD_RESPMEM_MUST_COPY);
 
  155        if(!request_info->m_origin) {
 
  156            request_info->m_origin = 
"*";
 
  158        MHD_add_response_header(result,
 
  159                                "Access-Control-Allow-Origin",
 
  160                                request_info->m_origin);
 
  162        MHD_add_response_header(result,
 
  163                                "Access-Control-Allow-Methods",
 
  165        MHD_add_response_header(result,
 
  166                                "Access-Control-Allow-Headers",
 
  168        MHD_add_response_header(result, 
"Access-Control-Max-Age", 
"600");
 
  169        MHD_add_response_header(result, 
"Vary", 
"Origin");
 
  170        MHD_add_response_header(result,
 
  172                                "Access-Control-Request-Method");
 
  173        MHD_add_response_header(result,
 
  175                                "Access-Control-Request-Headers");
 
  176        auto ret = MHD_queue_response(request_info->m_connection, 200, result);
 
  177        MHD_destroy_response(result);
 
  178        const auto* inf = MHD_get_connection_info(
 
  179            request_info->m_connection,
 
  180            MHD_CONNECTION_INFO_CONNECTION_SUSPENDED);
 
  181        if(inf->suspended == MHD_YES) {
 
  182            MHD_resume_connection(request_info->m_connection);
 
  184        return ret == MHD_YES;
 
  187    auto json_rpc_http_server::send_response(std::string response,
 
  188                                             request* request_info) -> 
bool {
 
  189        auto* result = MHD_create_response_from_buffer(
 
  191            static_cast<void*
>(
response.data()),
 
  192            MHD_RESPMEM_MUST_COPY);
 
  194        if(request_info->m_server->m_enable_cors) {
 
  195            if(!request_info->m_origin) {
 
  196                request_info->m_origin = 
"*";
 
  198            MHD_add_response_header(result,
 
  199                                    "Access-Control-Allow-Origin",
 
  200                                    request_info->m_origin);
 
  201            MHD_add_response_header(result, 
"Vary", 
"Origin");
 
  204        MHD_add_response_header(result, 
"Content-Type", 
"application/json");
 
  205        auto ret = MHD_queue_response(request_info->m_connection,
 
  206                                      request_info->m_code,
 
  208        MHD_destroy_response(result);
 
  209        const auto* inf = MHD_get_connection_info(
 
  210            request_info->m_connection,
 
  211            MHD_CONNECTION_INFO_CONNECTION_SUSPENDED);
 
  212        if(inf->suspended == MHD_YES) {
 
  213            MHD_resume_connection(request_info->m_connection);
 
  215        return ret == MHD_YES;
 
  218    auto json_rpc_http_server::handle_request(request* request_info) -> 
bool {
 
  219        auto req = Json::Value();
 
  220        auto r = Json::Reader();
 
  221        auto success = r.parse(request_info->m_request.str(), req, 
false);
 
  226        if(!req.isMember(
"method")) {
 
  230        if(!req[
"method"].isString()) {
 
  234        auto method = req[
"method"].asString();
 
  235        auto params = Json::Value();
 
  237        if(req.isMember(
"params")) {
 
  238            params = req[
"params"];
 
  242        if(req[
"id"].isUInt64()) {
 
  243            id = req[
"id"].asUInt64();
 
  246        MHD_suspend_connection(request_info->m_connection);
 
  251                   [
this, request_info, 
id](std::optional<Json::Value> resp) {
 
  252                       handle_response(
id, request_info, std::move(resp));
 
  258    json_rpc_http_server::handle_response(uint64_t 
id,
 
  259                                          request* request_info,
 
  260                                          std::optional<Json::Value> resp) {
 
  261        if(!resp.has_value()) {
 
  262            request_info->m_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
 
  263            request_info->m_server->send_response(
"Error processing request",
 
  269        auto resp_payload = resp.value();
 
  270        resp_payload[
"jsonrpc"] = 
"2.0";
 
  271        resp_payload[
"id"] = id;
 
  273        request_info->m_code = MHD_HTTP_OK;
 
  274        auto resp_str = Json::writeString(m_builder, resp_payload);
 
  275        request_info->m_server->send_response(resp_str, request_info);
 
  280        m_cb = std::move(handler_callback);
 
 
  283    void json_rpc_http_server::request_complete(
 
  285        struct MHD_Connection* ,
 
  287        MHD_RequestTerminationCode ) {
 
  288        if(*con_cls == 
nullptr) {
 
  291        auto* req = 
static_cast<request*
>(*con_cls);
 
  294            std::unique_lock l(server->m_requests_mut);
 
  295            server->m_requests.erase(req);
 
Asynchrounous HTTP JSON-RPC server implemented using libmicrohttpd and libjsoncpp.
json_rpc_http_server(network::endpoint_t endpoint, bool enable_cors=false)
Construct a new server.
~json_rpc_http_server()
Stop the server.
void register_handler_callback(handler_callback_type handler_callback)
Register the application request handler function with the server.
std::function< bool(std::string, Json::Value, result_callback_type)> handler_callback_type
Callback function type provided by the application for processing requests.
auto init() -> bool
Start listening for incoming connections and processing requests.
std::pair< ip_address, port_number_t > endpoint_t
[host name, port number].
interface::exec_return_type response
Agent RPC response type.