1 /* Icinga 2 | (c) 2012 Icinga GmbH | GPLv2+ */
2
3 #include "remote/jsonrpc.hpp"
4 #include "base/netstring.hpp"
5 #include "base/json.hpp"
6 #include "base/console.hpp"
7 #include "base/scriptglobal.hpp"
8 #include "base/convert.hpp"
9 #include "base/tlsstream.hpp"
10 #include <iostream>
11 #include <memory>
12 #include <utility>
13 #include <boost/asio/spawn.hpp>
14
15 using namespace icinga;
16
17 #ifdef I2_DEBUG
18 /**
19 * Determine whether the developer wants to see raw JSON messages.
20 *
21 * @return Internal.DebugJsonRpc boolean
22 */
GetDebugJsonRpcCached()23 static bool GetDebugJsonRpcCached()
24 {
25 static int debugJsonRpc = -1;
26
27 if (debugJsonRpc != -1)
28 return debugJsonRpc;
29
30 debugJsonRpc = false;
31
32 Namespace::Ptr internal = ScriptGlobal::Get("Internal", &Empty);
33
34 if (!internal)
35 return false;
36
37 Value vdebug;
38
39 if (!internal->Get("DebugJsonRpc", &vdebug))
40 return false;
41
42 debugJsonRpc = Convert::ToLong(vdebug);
43
44 return debugJsonRpc;
45 }
46 #endif /* I2_DEBUG */
47
48 /**
49 * Sends a message to the connected peer and returns the bytes sent.
50 *
51 * @param message The message.
52 *
53 * @return The amount of bytes sent.
54 */
SendMessage(const Shared<AsioTlsStream>::Ptr & stream,const Dictionary::Ptr & message)55 size_t JsonRpc::SendMessage(const Shared<AsioTlsStream>::Ptr& stream, const Dictionary::Ptr& message)
56 {
57 String json = JsonEncode(message);
58
59 #ifdef I2_DEBUG
60 if (GetDebugJsonRpcCached())
61 std::cerr << ConsoleColorTag(Console_ForegroundBlue) << ">> " << json << ConsoleColorTag(Console_Normal) << "\n";
62 #endif /* I2_DEBUG */
63
64 return NetString::WriteStringToStream(stream, json);
65 }
66
67 /**
68 * Sends a message to the connected peer and returns the bytes sent.
69 *
70 * @param message The message.
71 *
72 * @return The amount of bytes sent.
73 */
SendMessage(const Shared<AsioTlsStream>::Ptr & stream,const Dictionary::Ptr & message,boost::asio::yield_context yc)74 size_t JsonRpc::SendMessage(const Shared<AsioTlsStream>::Ptr& stream, const Dictionary::Ptr& message, boost::asio::yield_context yc)
75 {
76 return JsonRpc::SendRawMessage(stream, JsonEncode(message), yc);
77 }
78
79 /**
80 * Sends a raw message to the connected peer.
81 *
82 * @param stream ASIO TLS Stream
83 * @param json message
84 * @param yc Yield context required for ASIO
85 *
86 * @return bytes sent
87 */
SendRawMessage(const Shared<AsioTlsStream>::Ptr & stream,const String & json,boost::asio::yield_context yc)88 size_t JsonRpc::SendRawMessage(const Shared<AsioTlsStream>::Ptr& stream, const String& json, boost::asio::yield_context yc)
89 {
90 #ifdef I2_DEBUG
91 if (GetDebugJsonRpcCached())
92 std::cerr << ConsoleColorTag(Console_ForegroundBlue) << ">> " << json << ConsoleColorTag(Console_Normal) << "\n";
93 #endif /* I2_DEBUG */
94
95 return NetString::WriteStringToStream(stream, json, yc);
96 }
97
98 /**
99 * Reads a message from the connected peer.
100 *
101 * @param stream ASIO TLS Stream
102 * @param maxMessageLength maximum size of bytes read.
103 *
104 * @return A JSON string
105 */
106
ReadMessage(const Shared<AsioTlsStream>::Ptr & stream,ssize_t maxMessageLength)107 String JsonRpc::ReadMessage(const Shared<AsioTlsStream>::Ptr& stream, ssize_t maxMessageLength)
108 {
109 String jsonString = NetString::ReadStringFromStream(stream, maxMessageLength);
110
111 #ifdef I2_DEBUG
112 if (GetDebugJsonRpcCached())
113 std::cerr << ConsoleColorTag(Console_ForegroundBlue) << "<< " << jsonString << ConsoleColorTag(Console_Normal) << "\n";
114 #endif /* I2_DEBUG */
115
116 return std::move(jsonString);
117 }
118
119 /**
120 * Reads a message from the connected peer.
121 *
122 * @param stream ASIO TLS Stream
123 * @param yc Yield Context for ASIO
124 * @param maxMessageLength maximum size of bytes read.
125 *
126 * @return A JSON string
127 */
ReadMessage(const Shared<AsioTlsStream>::Ptr & stream,boost::asio::yield_context yc,ssize_t maxMessageLength)128 String JsonRpc::ReadMessage(const Shared<AsioTlsStream>::Ptr& stream, boost::asio::yield_context yc, ssize_t maxMessageLength)
129 {
130 String jsonString = NetString::ReadStringFromStream(stream, yc, maxMessageLength);
131
132 #ifdef I2_DEBUG
133 if (GetDebugJsonRpcCached())
134 std::cerr << ConsoleColorTag(Console_ForegroundBlue) << "<< " << jsonString << ConsoleColorTag(Console_Normal) << "\n";
135 #endif /* I2_DEBUG */
136
137 return std::move(jsonString);
138 }
139
140 /**
141 * Decode message, enforce a Dictionary
142 *
143 * @param message JSON string
144 *
145 * @return Dictionary ptr
146 */
DecodeMessage(const String & message)147 Dictionary::Ptr JsonRpc::DecodeMessage(const String& message)
148 {
149 Value value = JsonDecode(message);
150
151 if (!value.IsObjectType<Dictionary>()) {
152 BOOST_THROW_EXCEPTION(std::invalid_argument("JSON-RPC"
153 " message must be a dictionary."));
154 }
155
156 return value;
157 }
158