summaryrefslogtreecommitdiffstats
path: root/src/bin/netconf/http_control_socket.cc
blob: ec1f9ae569016e204a1582379397e292d85dd4d5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
// Copyright (C) 2018-2021 Internet Systems Consortium, Inc. ("ISC")
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

/// @file http_control_socket.cc
/// Contains the HTTP socket derived class for control socket communication.

#include <config.h>

#include <netconf/http_control_socket.h>
#include <cc/command_interpreter.h>
#include <asiolink/asio_wrapper.h>
#include <asiolink/io_service.h>
#include <asiolink/tls_socket.h>
#include <http/client.h>
#include <http/post_request_json.h>
#include <http/response_json.h>
#include <config/timeouts.h>

using namespace std;
using namespace isc::asiolink;
using namespace isc::config;
using namespace isc::data;
using namespace isc::http;

namespace isc {
namespace netconf {

template <> ControlSocketBasePtr
createControlSocket<CfgControlSocket::Type::HTTP>(CfgControlSocketPtr ctrl_sock) {
    return (HttpControlSocketPtr(new HttpControlSocket(ctrl_sock)));
}

HttpControlSocket::HttpControlSocket(CfgControlSocketPtr ctrl_sock)
    : ControlSocketBase(ctrl_sock) {
}

ConstElementPtr
HttpControlSocket::configGet(const string& service) {
    if (service == "ca") {
        return (sendCommand(createCommand("config-get")));
    } else {
        return (sendCommand(createCommand("config-get", service)));
    }
}

ConstElementPtr
HttpControlSocket::configTest(ConstElementPtr config, const string& service) {
    if (service == "ca") {
        return (sendCommand(createCommand("config-test", config)));
    } else {
        return (sendCommand(createCommand("config-test", config, service)));
    }
}

ConstElementPtr
HttpControlSocket::configSet(ConstElementPtr config, const string& service) {
    if (service == "ca") {
        return (sendCommand(createCommand("config-set", config)));
    } else {
        return (sendCommand(createCommand("config-set", config, service)));
    }
}

ConstElementPtr
HttpControlSocket::sendCommand(ConstElementPtr command) {
    PostHttpRequestJsonPtr request;
    request.reset(new PostHttpRequestJson(HttpRequest::Method::HTTP_POST,
                                          "/",
                                          HttpVersion(1, 1)));
    request->setBodyAsJson(command);
    try {
        request->finalize();
    } catch (const std::exception& ex) {
        isc_throw(ControlSocketError, "failed to create request: "
                  << ex.what());
    }

    IOServicePtr io_service(new IOService());
    HttpClient client(*io_service);
    boost::system::error_code received_ec;
    string receive_errmsg;
    HttpResponseJsonPtr response(new HttpResponseJson());

    client.asyncSendRequest(getUrl(), TlsContextPtr(), request, response,
                [&io_service, &received_ec, &receive_errmsg]
                (const boost::system::error_code& ec,
                const HttpResponsePtr&, const string& errmsg) {
                        // Capture error code and message.
                        received_ec = ec;
                        receive_errmsg = errmsg;
                        // Got the IO service so stop IO service.
                        // This causes to stop IO service when
                        // all handlers have been invoked.
                        io_service->stopWork();
                },
                HttpClient::RequestTimeout(TIMEOUT_AGENT_FORWARD_COMMAND));

    // Perform this synchronously.
    io_service->run();

    if (received_ec) {
        // Got an error code.
        isc_throw(ControlSocketError, "communication error (code): "
                  << received_ec.message());
    }

    if (!receive_errmsg.empty()) {
        // Got an error message.
        isc_throw(ControlSocketError, "communication error (message): "
                  << receive_errmsg);
    }

    if (!response) {
        // Failed to get the answer.
        isc_throw(ControlSocketError, "empty response");
    }

    try {
        return (response->getBodyAsJson());
    } catch (const std::exception& ex) {
        isc_throw(ControlSocketError, "unparsable response: " << ex.what());
    }
}

} // namespace netconf
} // namespace isc