passenger 5.1.10 → 5.1.11
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of passenger might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG +18 -0
- data/Rakefile +20 -17
- data/bin/passenger-install-apache2-module +14 -11
- data/build/agent.rb +45 -18
- data/build/apache2.rb +32 -16
- data/build/basics.rb +29 -40
- data/build/common_library.rb +70 -54
- data/build/cxx_tests.rb +34 -43
- data/build/integration_tests.rb +10 -10
- data/build/misc.rb +6 -6
- data/build/node_tests.rb +1 -2
- data/build/oxt_tests.rb +7 -5
- data/build/packaging.rb +11 -441
- data/build/ruby_extension.rb +1 -1
- data/build/ruby_tests.rb +1 -2
- data/build/support/cplusplus.rb +6 -5
- data/build/support/cxx_dependency_map.rb +357 -833
- data/build/support/general.rb +23 -1
- data/build/test_basics.rb +3 -28
- data/dev/ci/tests/rpm/Jenkinsfile +68 -0
- data/dev/ci/tests/rpm/run +63 -0
- data/dev/ci/tests/source-packaging/run +1 -1
- data/dev/ci/tests/source-packaging/setup +1 -1
- data/doc/{Packaging.txt.md → Packaging.md} +0 -0
- data/resources/templates/apache2/deployment_example.txt.erb +2 -2
- data/resources/templates/apache2/multiple_apache_installations_detected.txt.erb +2 -2
- data/resources/templates/nginx/deployment_example.txt.erb +1 -1
- data/resources/templates/standalone/mass_deployment_default_server.erb +2 -2
- data/resources/templates/standalone/server.erb +2 -2
- data/src/agent/AgentMain.cpp +0 -4
- data/src/agent/Core/CoreMain.cpp +88 -5
- data/src/agent/Core/SpawningKit/Spawner.h +2 -1
- data/src/agent/Shared/Fundamentals/AbortHandler.cpp +1109 -0
- data/src/agent/Shared/Fundamentals/AbortHandler.h +63 -0
- data/src/agent/Shared/Fundamentals/Implementation.cpp +7 -0
- data/src/agent/Shared/Fundamentals/Initialization.cpp +614 -0
- data/src/agent/Shared/{Base.h → Fundamentals/Initialization.h} +23 -14
- data/src/agent/Shared/Fundamentals/Utils.cpp +127 -0
- data/src/agent/Shared/Fundamentals/Utils.h +46 -0
- data/src/agent/TempDirToucher/TempDirToucherMain.cpp +1 -1
- data/src/agent/Watchdog/CoreWatcher.cpp +3 -1
- data/src/agent/Watchdog/InstanceDirToucher.cpp +90 -53
- data/src/agent/Watchdog/WatchdogMain.cpp +13 -29
- data/src/apache2_module/Hooks.cpp +4 -1
- data/src/cxx_supportlib/ConfigKit/Store.h +32 -5
- data/src/cxx_supportlib/Constants.h +1 -2
- data/src/cxx_supportlib/Crypto.cpp +2 -1
- data/src/cxx_supportlib/Hooks.h +16 -37
- data/src/cxx_supportlib/LoggingKit/Context.h +22 -0
- data/src/cxx_supportlib/LoggingKit/Forward.h +1 -0
- data/src/cxx_supportlib/LoggingKit/Implementation.cpp +106 -22
- data/src/cxx_supportlib/ProcessManagement/Ruby.cpp +106 -0
- data/src/{agent/UstRouter/FileSink.h → cxx_supportlib/ProcessManagement/Ruby.h} +23 -47
- data/src/cxx_supportlib/ProcessManagement/Spawn.cpp +199 -0
- data/src/cxx_supportlib/ProcessManagement/Spawn.h +150 -0
- data/src/cxx_supportlib/ProcessManagement/Utils.cpp +459 -0
- data/src/cxx_supportlib/ProcessManagement/Utils.h +107 -0
- data/src/cxx_supportlib/Utils.cpp +41 -561
- data/src/cxx_supportlib/Utils.h +0 -68
- data/src/cxx_supportlib/Utils/AsyncSignalSafeUtils.h +187 -0
- data/src/cxx_supportlib/Utils/ProcessMetricsCollector.h +14 -2
- data/src/cxx_supportlib/WatchdogLauncher.h +2 -12
- data/src/cxx_supportlib/oxt/dynamic_thread_group.hpp +2 -2
- data/src/cxx_supportlib/vendor-modified/jsoncpp/json-forwards.h +4 -0
- data/src/cxx_supportlib/vendor-modified/jsoncpp/json.h +16 -1
- data/src/cxx_supportlib/vendor-modified/jsoncpp/jsoncpp.cpp +12 -9
- data/src/cxx_supportlib/vendor-modified/libev/ev++.h +4 -4
- data/src/cxx_supportlib/vendor-modified/libev/ev.h +3 -3
- data/src/nginx_module/CacheLocationConfig.c +0 -75
- data/src/nginx_module/CacheLocationConfig.c.cxxcodebuilder +1 -0
- data/src/nginx_module/Configuration.c +0 -1
- data/src/nginx_module/Configuration.h +0 -1
- data/src/nginx_module/ConfigurationCommands.c +1 -1
- data/src/nginx_module/ContentHandler.c +0 -1
- data/src/nginx_module/ContentHandler.h +0 -1
- data/src/nginx_module/CreateLocationConfig.c +0 -5
- data/src/nginx_module/CreateLocationConfig.c.cxxcodebuilder +1 -0
- data/src/nginx_module/LocationConfig.h +0 -4
- data/src/nginx_module/LocationConfig.h.cxxcodebuilder +2 -1
- data/src/nginx_module/MergeLocationConfig.c +0 -12
- data/src/nginx_module/MergeLocationConfig.c.cxxcodebuilder +1 -0
- data/src/nginx_module/ngx_http_passenger_module.h +0 -1
- data/src/ruby_supportlib/phusion_passenger.rb +1 -1
- data/src/ruby_supportlib/phusion_passenger/common_library.rb +20 -11
- data/src/ruby_supportlib/phusion_passenger/config/api_call_command.rb +1 -1
- data/src/ruby_supportlib/phusion_passenger/config/reopen_logs_command.rb +0 -1
- data/src/ruby_supportlib/phusion_passenger/config/validate_install_command.rb +10 -3
- data/src/ruby_supportlib/phusion_passenger/console_text_template.rb +3 -1
- data/src/ruby_supportlib/phusion_passenger/constants.rb +0 -1
- data/src/ruby_supportlib/phusion_passenger/debug_logging.rb +1 -1
- data/src/ruby_supportlib/phusion_passenger/loader_shared_helpers.rb +32 -6
- data/src/ruby_supportlib/phusion_passenger/nginx/config_options.rb +0 -1
- data/src/ruby_supportlib/phusion_passenger/packaging.rb +2 -4
- data/src/ruby_supportlib/phusion_passenger/platform_info/apache.rb +101 -20
- data/src/ruby_supportlib/phusion_passenger/platform_info/apache_detector.rb +21 -9
- data/src/ruby_supportlib/phusion_passenger/platform_info/compiler.rb +34 -31
- data/src/ruby_supportlib/phusion_passenger/platform_info/cxx_portability.rb +3 -1
- data/src/ruby_supportlib/phusion_passenger/platform_info/depcheck_specs/apache2.rb +2 -14
- data/src/ruby_supportlib/phusion_passenger/platform_info/operating_system.rb +40 -3
- data/src/ruby_supportlib/phusion_passenger/standalone/app_finder.rb +15 -14
- data/src/ruby_supportlib/phusion_passenger/standalone/config_options_list.rb +1 -1
- data/src/ruby_supportlib/phusion_passenger/standalone/config_utils.rb +1 -1
- data/src/ruby_supportlib/phusion_passenger/standalone/start_command.rb +8 -3
- data/src/ruby_supportlib/phusion_passenger/standalone/start_command/nginx_engine.rb +19 -18
- data/src/ruby_supportlib/phusion_passenger/standalone/stop_command.rb +6 -1
- data/src/ruby_supportlib/phusion_passenger/vendor/daemon_controller.rb +17 -1
- metadata +19 -97
- data/build/documentation.rb +0 -70
- data/doc/CloudLicensingConfiguration.html +0 -172
- data/doc/CloudLicensingConfiguration.txt.md +0 -3
- data/doc/Packaging.html +0 -488
- data/doc/Security of user switching support.idmap.txt +0 -34
- data/doc/Security of user switching support.txt +0 -197
- data/doc/ServerOptimizationGuide.html +0 -172
- data/doc/ServerOptimizationGuide.txt.md +0 -3
- data/doc/images/by_sa.png +0 -0
- data/doc/images/cloud_licensing_batch_job.png +0 -0
- data/doc/images/code_walkthrough.jpg +0 -0
- data/doc/images/direct_spawning.png +0 -0
- data/doc/images/direct_spawning.svg +0 -251
- data/doc/images/glyphicons-halflings-white.png +0 -0
- data/doc/images/glyphicons-halflings.png +0 -0
- data/doc/images/icons/README +0 -5
- data/doc/images/icons/callouts/1.png +0 -0
- data/doc/images/icons/callouts/10.png +0 -0
- data/doc/images/icons/callouts/11.png +0 -0
- data/doc/images/icons/callouts/12.png +0 -0
- data/doc/images/icons/callouts/13.png +0 -0
- data/doc/images/icons/callouts/14.png +0 -0
- data/doc/images/icons/callouts/15.png +0 -0
- data/doc/images/icons/callouts/2.png +0 -0
- data/doc/images/icons/callouts/3.png +0 -0
- data/doc/images/icons/callouts/4.png +0 -0
- data/doc/images/icons/callouts/5.png +0 -0
- data/doc/images/icons/callouts/6.png +0 -0
- data/doc/images/icons/callouts/7.png +0 -0
- data/doc/images/icons/callouts/8.png +0 -0
- data/doc/images/icons/callouts/9.png +0 -0
- data/doc/images/icons/caution.png +0 -0
- data/doc/images/icons/example.png +0 -0
- data/doc/images/icons/home.png +0 -0
- data/doc/images/icons/important.png +0 -0
- data/doc/images/icons/next.png +0 -0
- data/doc/images/icons/note.png +0 -0
- data/doc/images/icons/prev.png +0 -0
- data/doc/images/icons/tip.png +0 -0
- data/doc/images/icons/up.png +0 -0
- data/doc/images/icons/warning.png +0 -0
- data/doc/images/many_web_framework_protocols.png +0 -0
- data/doc/images/passenger_architecture.png +0 -0
- data/doc/images/passenger_architecture.svg +0 -385
- data/doc/images/passenger_architecture_overview.png +0 -0
- data/doc/images/passenger_core_architecture.png +0 -0
- data/doc/images/passenger_nodejs_architecture.svg +0 -558
- data/doc/images/phusion_banner.png +0 -0
- data/doc/images/rack.png +0 -0
- data/doc/images/smart_spawning.png +0 -0
- data/doc/images/smart_spawning.svg +0 -323
- data/doc/images/spawn_server_architecture.png +0 -0
- data/doc/images/spawn_server_architecture.svg +0 -655
- data/doc/images/spawning_preparation_work.png +0 -0
- data/doc/images/startup_sequence.png +0 -0
- data/doc/images/typical_isolated_web_application.png +0 -0
- data/doc/images/typical_isolated_web_application.svg +0 -213
- data/doc/users_guide_snippets/alternative_for_flying_passenger.txt +0 -1
- data/doc/users_guide_snippets/analysis_and_system_maintenance.txt +0 -61
- data/doc/users_guide_snippets/appendix_a_about.txt +0 -13
- data/doc/users_guide_snippets/appendix_b_terminology.txt +0 -71
- data/doc/users_guide_snippets/appendix_c_spawning_methods.txt +0 -36
- data/doc/users_guide_snippets/deployment_basics.txt +0 -37
- data/doc/users_guide_snippets/enterprise_only.txt +0 -1
- data/doc/users_guide_snippets/environment_variables.txt +0 -44
- data/doc/users_guide_snippets/global_queueing_explained.txt +0 -74
- data/doc/users_guide_snippets/installation.txt +0 -228
- data/doc/users_guide_snippets/installation/run_installer.txt +0 -58
- data/doc/users_guide_snippets/installation/verify_running_epilogue.txt +0 -6
- data/doc/users_guide_snippets/passenger_spawn_method.txt +0 -37
- data/doc/users_guide_snippets/rackup_specifications.txt +0 -1
- data/doc/users_guide_snippets/rvm_helper_tool.txt +0 -44
- data/doc/users_guide_snippets/since_version.txt +0 -1
- data/doc/users_guide_snippets/support_information.txt +0 -8
- data/doc/users_guide_snippets/tips.txt +0 -302
- data/doc/users_guide_snippets/troubleshooting/default.txt +0 -48
- data/doc/users_guide_snippets/troubleshooting/rails.txt +0 -59
- data/doc/users_guide_snippets/under_the_hood/page_caching_support.txt +0 -24
- data/doc/users_guide_snippets/under_the_hood/relationship_with_ruby.txt +0 -10
- data/doc/users_guide_snippets/where_to_get_support.txt +0 -9
- data/src/agent/Shared/Base.cpp +0 -1678
- data/src/agent/UstRouter/ApiServer.h +0 -292
- data/src/agent/UstRouter/Client.h +0 -112
- data/src/agent/UstRouter/Controller.h +0 -1309
- data/src/agent/UstRouter/LogSink.h +0 -145
- data/src/agent/UstRouter/OptionParser.h +0 -180
- data/src/agent/UstRouter/RemoteSender.h +0 -853
- data/src/agent/UstRouter/RemoteSink.h +0 -145
- data/src/agent/UstRouter/Transaction.h +0 -278
- data/src/agent/UstRouter/UstRouterMain.cpp +0 -681
- data/src/agent/Watchdog/UstRouterWatcher.cpp +0 -80
- data/src/ruby_supportlib/phusion_passenger/platform_info/macos.rb +0 -45
@@ -1,292 +0,0 @@
|
|
1
|
-
/*
|
2
|
-
* Phusion Passenger - https://www.phusionpassenger.com/
|
3
|
-
* Copyright (c) 2013-2017 Phusion Holding B.V.
|
4
|
-
*
|
5
|
-
* "Passenger", "Phusion Passenger" and "Union Station" are registered
|
6
|
-
* trademarks of Phusion Holding B.V.
|
7
|
-
*
|
8
|
-
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
9
|
-
* of this software and associated documentation files (the "Software"), to deal
|
10
|
-
* in the Software without restriction, including without limitation the rights
|
11
|
-
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
12
|
-
* copies of the Software, and to permit persons to whom the Software is
|
13
|
-
* furnished to do so, subject to the following conditions:
|
14
|
-
*
|
15
|
-
* The above copyright notice and this permission notice shall be included in
|
16
|
-
* all copies or substantial portions of the Software.
|
17
|
-
*
|
18
|
-
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
19
|
-
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
20
|
-
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
21
|
-
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
22
|
-
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
23
|
-
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
24
|
-
* THE SOFTWARE.
|
25
|
-
*/
|
26
|
-
#ifndef _PASSENGER_UST_ROUTER_API_SERVER_H_
|
27
|
-
#define _PASSENGER_UST_ROUTER_API_SERVER_H_
|
28
|
-
|
29
|
-
#include <string>
|
30
|
-
#include <exception>
|
31
|
-
#include <jsoncpp/json.h>
|
32
|
-
#include <modp_b64.h>
|
33
|
-
|
34
|
-
#include <ServerKit/HttpServer.h>
|
35
|
-
#include <DataStructures/LString.h>
|
36
|
-
#include <LoggingKit/LoggingKit.h>
|
37
|
-
#include <LoggingKit/Context.h>
|
38
|
-
#include <Exceptions.h>
|
39
|
-
#include <StaticString.h>
|
40
|
-
#include <Utils/StrIntUtils.h>
|
41
|
-
#include <Utils/BufferedIO.h>
|
42
|
-
#include <Utils/MessageIO.h>
|
43
|
-
#include <UstRouter/Controller.h>
|
44
|
-
#include <Shared/ApiServerUtils.h>
|
45
|
-
#include <Shared/ApplicationPoolApiKey.h>
|
46
|
-
|
47
|
-
namespace Passenger {
|
48
|
-
namespace UstRouter {
|
49
|
-
|
50
|
-
using namespace std;
|
51
|
-
|
52
|
-
|
53
|
-
class Request: public ServerKit::BaseHttpRequest {
|
54
|
-
public:
|
55
|
-
string body;
|
56
|
-
Json::Value jsonBody;
|
57
|
-
|
58
|
-
DEFINE_SERVER_KIT_BASE_HTTP_REQUEST_FOOTER(Request);
|
59
|
-
};
|
60
|
-
|
61
|
-
class ApiServer: public ServerKit::HttpServer<ApiServer, ServerKit::HttpClient<Request> > {
|
62
|
-
private:
|
63
|
-
typedef ServerKit::HttpServer<ApiServer, ServerKit::HttpClient<Request> > ParentClass;
|
64
|
-
typedef ServerKit::HttpClient<Request> Client;
|
65
|
-
typedef ServerKit::HeaderTable HeaderTable;
|
66
|
-
|
67
|
-
void route(Client *client, Request *req, const StaticString &path) {
|
68
|
-
if (path == P_STATIC_STRING("/ping.json")) {
|
69
|
-
apiServerProcessPing(this, client, req);
|
70
|
-
} else if (path == P_STATIC_STRING("/info.json")
|
71
|
-
// The "/version.json" path is deprecated
|
72
|
-
|| path == P_STATIC_STRING("/version.json"))
|
73
|
-
{
|
74
|
-
apiServerProcessInfo(this, client, req);
|
75
|
-
} else if (path == P_STATIC_STRING("/shutdown.json")) {
|
76
|
-
apiServerProcessShutdown(this, client, req);
|
77
|
-
} else if (path == P_STATIC_STRING("/backtraces.txt")) {
|
78
|
-
apiServerProcessBacktraces(this, client, req);
|
79
|
-
} else if (path == P_STATIC_STRING("/config.json")) {
|
80
|
-
processConfig(client, req);
|
81
|
-
} else if (path == P_STATIC_STRING("/reinherit_logs.json")) {
|
82
|
-
apiServerProcessReinheritLogs(this, client, req,
|
83
|
-
instanceDir, fdPassingPassword);
|
84
|
-
} else if (path == P_STATIC_STRING("/reopen_logs.json")) {
|
85
|
-
apiServerProcessReopenLogs(this, client, req);
|
86
|
-
} else if (path == P_STATIC_STRING("/server.json")) {
|
87
|
-
processServerStatus(client, req);
|
88
|
-
} else {
|
89
|
-
apiServerRespondWith404(this, client, req);
|
90
|
-
}
|
91
|
-
}
|
92
|
-
|
93
|
-
void processConfig(Client *client, Request *req) {
|
94
|
-
if (req->method == HTTP_GET) {
|
95
|
-
if (!authorizeStateInspectionOperation(this, client, req)) {
|
96
|
-
apiServerRespondWith401(this, client, req);
|
97
|
-
}
|
98
|
-
|
99
|
-
HeaderTable headers;
|
100
|
-
Json::Value doc = LoggingKit::context->getConfig().inspect();
|
101
|
-
headers.insert(req->pool, "Content-Type", "application/json");
|
102
|
-
writeSimpleResponse(client, 200, &headers, doc.toStyledString());
|
103
|
-
if (!req->ended()) {
|
104
|
-
endRequest(&client, &req);
|
105
|
-
}
|
106
|
-
} else if (req->method == HTTP_PUT) {
|
107
|
-
if (!authorizeAdminOperation(this, client, req)) {
|
108
|
-
apiServerRespondWith401(this, client, req);
|
109
|
-
} else if (!req->hasBody()) {
|
110
|
-
endAsBadRequest(&client, &req, "Body required");
|
111
|
-
}
|
112
|
-
// Continue in processConfigBody()
|
113
|
-
} else {
|
114
|
-
apiServerRespondWith405(this, client, req);
|
115
|
-
}
|
116
|
-
}
|
117
|
-
|
118
|
-
void processConfigBody(Client *client, Request *req) {
|
119
|
-
HeaderTable headers;
|
120
|
-
LoggingKit::ConfigChangeRequest configReq;
|
121
|
-
const Json::Value &json = req->jsonBody;
|
122
|
-
vector<ConfigKit::Error> errors;
|
123
|
-
bool ok;
|
124
|
-
|
125
|
-
headers.insert(req->pool, "Content-Type", "application/json");
|
126
|
-
headers.insert(req->pool, "Cache-Control", "no-cache, no-store, must-revalidate");
|
127
|
-
|
128
|
-
try {
|
129
|
-
ok = LoggingKit::context->prepareConfigChange(json,
|
130
|
-
errors, configReq);
|
131
|
-
} catch (const std::exception &e) {
|
132
|
-
unsigned int bufsize = 2048;
|
133
|
-
char *message = (char *) psg_pnalloc(req->pool, bufsize);
|
134
|
-
snprintf(message, bufsize, "{ \"status\": \"error\", "
|
135
|
-
"\"message\": \"Error reconfiguring logging system: %s\" }",
|
136
|
-
e.what());
|
137
|
-
writeSimpleResponse(client, 500, &headers, message);
|
138
|
-
if (!req->ended()) {
|
139
|
-
endRequest(&client, &req);
|
140
|
-
}
|
141
|
-
return;
|
142
|
-
}
|
143
|
-
if (!ok) {
|
144
|
-
unsigned int bufsize = 2048;
|
145
|
-
char *message = (char *) psg_pnalloc(req->pool, bufsize);
|
146
|
-
snprintf(message, bufsize, "{ \"status\": \"error\", "
|
147
|
-
"\"message\": \"Error reconfiguring logging system: %s\" }",
|
148
|
-
ConfigKit::toString(errors).c_str());
|
149
|
-
writeSimpleResponse(client, 500, &headers, message);
|
150
|
-
if (!req->ended()) {
|
151
|
-
endRequest(&client, &req);
|
152
|
-
}
|
153
|
-
return;
|
154
|
-
}
|
155
|
-
|
156
|
-
LoggingKit::context->commitConfigChange(configReq);
|
157
|
-
writeSimpleResponse(client, 200, &headers, "{ \"status\": \"ok\" }\n");
|
158
|
-
if (!req->ended()) {
|
159
|
-
endRequest(&client, &req);
|
160
|
-
}
|
161
|
-
}
|
162
|
-
|
163
|
-
void gatherControllerState(Client *client, Request *req, Controller *controller) {
|
164
|
-
Json::Value state = controller->inspectStateAsJson();
|
165
|
-
getContext()->libev->runLater(boost::bind(&ApiServer::controllerStateGathered,
|
166
|
-
this, client, req, state));
|
167
|
-
}
|
168
|
-
|
169
|
-
void controllerStateGathered(Client *client, Request *req, Json::Value state) {
|
170
|
-
if (req->ended()) {
|
171
|
-
unrefRequest(req, __FILE__, __LINE__);
|
172
|
-
return;
|
173
|
-
}
|
174
|
-
|
175
|
-
HeaderTable headers;
|
176
|
-
headers.insert(req->pool, "Content-Type", "application/json");
|
177
|
-
|
178
|
-
writeSimpleResponse(client, 200, &headers,
|
179
|
-
psg_pstrdup(req->pool, state.toStyledString()));
|
180
|
-
if (!req->ended()) {
|
181
|
-
Request *req2 = req;
|
182
|
-
endRequest(&client, &req2);
|
183
|
-
}
|
184
|
-
|
185
|
-
unrefRequest(req, __FILE__, __LINE__);
|
186
|
-
}
|
187
|
-
|
188
|
-
void processServerStatus(Client *client, Request *req) {
|
189
|
-
if (req->method != HTTP_GET) {
|
190
|
-
apiServerRespondWith405(this, client, req);
|
191
|
-
} else if (authorizeStateInspectionOperation(this, client, req)) {
|
192
|
-
refRequest(req, __FILE__, __LINE__);
|
193
|
-
controller->getContext()->libev->runLater(boost::bind(
|
194
|
-
&ApiServer::gatherControllerState, this,
|
195
|
-
client, req, controller));
|
196
|
-
} else {
|
197
|
-
apiServerRespondWith401(this, client, req);
|
198
|
-
}
|
199
|
-
}
|
200
|
-
|
201
|
-
protected:
|
202
|
-
virtual void onRequestBegin(Client *client, Request *req) {
|
203
|
-
const StaticString path(req->path.start->data, req->path.size);
|
204
|
-
|
205
|
-
P_INFO("API request: " << http_method_str(req->method) <<
|
206
|
-
" " << StaticString(req->path.start->data, req->path.size));
|
207
|
-
|
208
|
-
try {
|
209
|
-
route(client, req, path);
|
210
|
-
} catch (const oxt::tracable_exception &e) {
|
211
|
-
SKC_ERROR(client, "Exception: " << e.what() << "\n" << e.backtrace());
|
212
|
-
if (!req->ended()) {
|
213
|
-
req->wantKeepAlive = false;
|
214
|
-
endRequest(&client, &req);
|
215
|
-
}
|
216
|
-
}
|
217
|
-
}
|
218
|
-
|
219
|
-
virtual ServerKit::Channel::Result onRequestBody(Client *client, Request *req,
|
220
|
-
const MemoryKit::mbuf &buffer, int errcode)
|
221
|
-
{
|
222
|
-
if (buffer.size() > 0) {
|
223
|
-
// Data
|
224
|
-
req->body.append(buffer.start, buffer.size());
|
225
|
-
} else if (errcode == 0) {
|
226
|
-
// EOF
|
227
|
-
Json::Reader reader;
|
228
|
-
if (reader.parse(req->body, req->jsonBody)) {
|
229
|
-
try {
|
230
|
-
processConfigBody(client, req);
|
231
|
-
} catch (const oxt::tracable_exception &e) {
|
232
|
-
SKC_ERROR(client, "Exception: " << e.what() << "\n" << e.backtrace());
|
233
|
-
if (!req->ended()) {
|
234
|
-
req->wantKeepAlive = false;
|
235
|
-
endRequest(&client, &req);
|
236
|
-
}
|
237
|
-
}
|
238
|
-
} else {
|
239
|
-
apiServerRespondWith422(this, client, req, reader.getFormattedErrorMessages());
|
240
|
-
}
|
241
|
-
} else {
|
242
|
-
// Error
|
243
|
-
disconnect(&client);
|
244
|
-
}
|
245
|
-
return ServerKit::Channel::Result(buffer.size(), false);
|
246
|
-
}
|
247
|
-
|
248
|
-
virtual void deinitializeRequest(Client *client, Request *req) {
|
249
|
-
req->body.clear();
|
250
|
-
if (!req->jsonBody.isNull()) {
|
251
|
-
req->jsonBody = Json::Value();
|
252
|
-
}
|
253
|
-
ParentClass::deinitializeRequest(client, req);
|
254
|
-
}
|
255
|
-
|
256
|
-
public:
|
257
|
-
Controller *controller;
|
258
|
-
ApiAccountDatabase *apiAccountDatabase;
|
259
|
-
string instanceDir;
|
260
|
-
string fdPassingPassword;
|
261
|
-
EventFd *exitEvent;
|
262
|
-
|
263
|
-
ApiServer(ServerKit::Context *context, const ServerKit::HttpServerSchema &schema,
|
264
|
-
const Json::Value &initialConfig = Json::Value())
|
265
|
-
: ParentClass(context, schema, initialConfig),
|
266
|
-
controller(NULL),
|
267
|
-
apiAccountDatabase(NULL),
|
268
|
-
exitEvent(NULL)
|
269
|
-
{ }
|
270
|
-
|
271
|
-
virtual StaticString getServerName() const {
|
272
|
-
return P_STATIC_STRING("UstRouterApiServer");
|
273
|
-
}
|
274
|
-
|
275
|
-
virtual unsigned int getClientName(const Client *client, char *buf, size_t size) const {
|
276
|
-
return ParentClass::getClientName(client, buf, size);
|
277
|
-
}
|
278
|
-
|
279
|
-
bool authorizeByUid(uid_t uid) const {
|
280
|
-
return uid == 0 || uid == geteuid();
|
281
|
-
}
|
282
|
-
|
283
|
-
bool authorizeByApiKey(const ApplicationPool2::ApiKey &apiKey) const {
|
284
|
-
return apiKey.isSuper();
|
285
|
-
}
|
286
|
-
};
|
287
|
-
|
288
|
-
|
289
|
-
} // namespace UstRouter
|
290
|
-
} // namespace Passenger
|
291
|
-
|
292
|
-
#endif /* _PASSENGER_UST_ROUTER_API_SERVER_H_ */
|
@@ -1,112 +0,0 @@
|
|
1
|
-
/*
|
2
|
-
* Phusion Passenger - https://www.phusionpassenger.com/
|
3
|
-
* Copyright (c) 2010-2017 Phusion Holding B.V.
|
4
|
-
*
|
5
|
-
* "Passenger", "Phusion Passenger" and "Union Station" are registered
|
6
|
-
* trademarks of Phusion Holding B.V.
|
7
|
-
*
|
8
|
-
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
9
|
-
* of this software and associated documentation files (the "Software"), to deal
|
10
|
-
* in the Software without restriction, including without limitation the rights
|
11
|
-
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
12
|
-
* copies of the Software, and to permit persons to whom the Software is
|
13
|
-
* furnished to do so, subject to the following conditions:
|
14
|
-
*
|
15
|
-
* The above copyright notice and this permission notice shall be included in
|
16
|
-
* all copies or substantial portions of the Software.
|
17
|
-
*
|
18
|
-
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
19
|
-
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
20
|
-
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
21
|
-
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
22
|
-
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
23
|
-
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
24
|
-
* THE SOFTWARE.
|
25
|
-
*/
|
26
|
-
#ifndef _PASSENGER_UST_ROUTER_CLIENT_H_
|
27
|
-
#define _PASSENGER_UST_ROUTER_CLIENT_H_
|
28
|
-
|
29
|
-
#include <set>
|
30
|
-
#include <string>
|
31
|
-
#include <UstRouter/Transaction.h>
|
32
|
-
#include <ServerKit/Server.h>
|
33
|
-
#include <MessageReadersWriters.h>
|
34
|
-
|
35
|
-
namespace Passenger {
|
36
|
-
namespace UstRouter {
|
37
|
-
|
38
|
-
using namespace std;
|
39
|
-
using namespace boost;
|
40
|
-
|
41
|
-
|
42
|
-
class Client: public ServerKit::BaseClient {
|
43
|
-
public:
|
44
|
-
enum State {
|
45
|
-
READING_AUTH_USERNAME,
|
46
|
-
READING_AUTH_PASSWORD,
|
47
|
-
READING_MESSAGE,
|
48
|
-
READING_MESSAGE_BODY
|
49
|
-
};
|
50
|
-
|
51
|
-
enum Type {
|
52
|
-
UNINITIALIZED,
|
53
|
-
LOGGER
|
54
|
-
};
|
55
|
-
|
56
|
-
ArrayMessage arrayReader;
|
57
|
-
ScalarMessage scalarReader;
|
58
|
-
|
59
|
-
State state;
|
60
|
-
Type type;
|
61
|
-
string nodeName;
|
62
|
-
|
63
|
-
/**
|
64
|
-
* Set of transaction IDs opened by this client.
|
65
|
-
* @invariant This is a subset of the transaction IDs in the 'transactions' member.
|
66
|
-
*/
|
67
|
-
set<string> openTransactions;
|
68
|
-
|
69
|
-
struct {
|
70
|
-
TransactionPtr transaction;
|
71
|
-
string timestamp;
|
72
|
-
bool ack;
|
73
|
-
} logCommandParams;
|
74
|
-
|
75
|
-
Client(void *server)
|
76
|
-
: ServerKit::BaseClient(server)
|
77
|
-
{ }
|
78
|
-
|
79
|
-
const char *getStateName() const {
|
80
|
-
switch (state) {
|
81
|
-
case READING_AUTH_USERNAME:
|
82
|
-
return "UNINITIALIZED";
|
83
|
-
case READING_AUTH_PASSWORD:
|
84
|
-
return "READING_AUTH_PASSWORD";
|
85
|
-
case READING_MESSAGE:
|
86
|
-
return "READING_MESSAGE";
|
87
|
-
case READING_MESSAGE_BODY:
|
88
|
-
return "READING_MESSAGE_BODY";
|
89
|
-
default:
|
90
|
-
return "UNKNOWN";
|
91
|
-
}
|
92
|
-
}
|
93
|
-
|
94
|
-
const char *getTypeName() const {
|
95
|
-
switch (type) {
|
96
|
-
case UNINITIALIZED:
|
97
|
-
return "UNINITIALIZED";
|
98
|
-
case LOGGER:
|
99
|
-
return "LOGGER";
|
100
|
-
default:
|
101
|
-
return "UNKNOWN";
|
102
|
-
}
|
103
|
-
}
|
104
|
-
|
105
|
-
DEFINE_SERVER_KIT_BASE_CLIENT_FOOTER(Client);
|
106
|
-
};
|
107
|
-
|
108
|
-
|
109
|
-
} // namespace UstRouter
|
110
|
-
} // namespace Passenger
|
111
|
-
|
112
|
-
#endif /* _PASSENGER_UST_ROUTER_TRANSACTION_H_ */
|
@@ -1,1309 +0,0 @@
|
|
1
|
-
/*
|
2
|
-
* Phusion Passenger - https://www.phusionpassenger.com/
|
3
|
-
* Copyright (c) 2010-2017 Phusion Holding B.V.
|
4
|
-
*
|
5
|
-
* "Passenger", "Phusion Passenger" and "Union Station" are registered
|
6
|
-
* trademarks of Phusion Holding B.V.
|
7
|
-
*
|
8
|
-
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
9
|
-
* of this software and associated documentation files (the "Software"), to deal
|
10
|
-
* in the Software without restriction, including without limitation the rights
|
11
|
-
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
12
|
-
* copies of the Software, and to permit persons to whom the Software is
|
13
|
-
* furnished to do so, subject to the following conditions:
|
14
|
-
*
|
15
|
-
* The above copyright notice and this permission notice shall be included in
|
16
|
-
* all copies or substantial portions of the Software.
|
17
|
-
*
|
18
|
-
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
19
|
-
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
20
|
-
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
21
|
-
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
22
|
-
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
23
|
-
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
24
|
-
* THE SOFTWARE.
|
25
|
-
*/
|
26
|
-
#ifndef _PASSENGER_UST_ROUTER_CONTROLLER_H_
|
27
|
-
#define _PASSENGER_UST_ROUTER_CONTROLLER_H_
|
28
|
-
|
29
|
-
#include <string>
|
30
|
-
#include <set>
|
31
|
-
#include <cassert>
|
32
|
-
#include <boost/shared_ptr.hpp>
|
33
|
-
#include <boost/make_shared.hpp>
|
34
|
-
#include <boost/foreach.hpp>
|
35
|
-
#include <oxt/backtrace.hpp>
|
36
|
-
#include <ev++.h>
|
37
|
-
#include <SmallVector.h>
|
38
|
-
#include <ConfigKit/ConfigKit.h>
|
39
|
-
#include <ServerKit/Server.h>
|
40
|
-
#include <StaticString.h>
|
41
|
-
#include <Constants.h>
|
42
|
-
#include <LoggingKit/LoggingKit.h>
|
43
|
-
#include <UstRouter/Transaction.h>
|
44
|
-
#include <UstRouter/Client.h>
|
45
|
-
#include <UstRouter/FileSink.h>
|
46
|
-
#include <UstRouter/RemoteSink.h>
|
47
|
-
#include <UnionStationFilterSupport.h>
|
48
|
-
#include <MessageReadersWriters.h>
|
49
|
-
#include <Utils.h>
|
50
|
-
#include <Utils/StrIntUtils.h>
|
51
|
-
#include <Utils/StringMap.h>
|
52
|
-
#include <Utils/SystemTime.h>
|
53
|
-
|
54
|
-
|
55
|
-
namespace Passenger {
|
56
|
-
namespace UstRouter {
|
57
|
-
|
58
|
-
using namespace std;
|
59
|
-
using namespace boost;
|
60
|
-
using namespace oxt;
|
61
|
-
|
62
|
-
|
63
|
-
class Controller: public ServerKit::BaseServer<Controller, Client> {
|
64
|
-
public:
|
65
|
-
class Schema: public ServerKit::BaseServerSchema {
|
66
|
-
private:
|
67
|
-
static Json::Value getDefaultValueForDefaultNodeName(const ConfigKit::Store &store) {
|
68
|
-
return getHostName();
|
69
|
-
}
|
70
|
-
|
71
|
-
public:
|
72
|
-
Schema()
|
73
|
-
: ServerKit::BaseServerSchema(false)
|
74
|
-
{
|
75
|
-
using namespace ConfigKit;
|
76
|
-
|
77
|
-
add("ust_router_username", STRING_TYPE, OPTIONAL);
|
78
|
-
add("ust_router_password", STRING_TYPE, OPTIONAL);
|
79
|
-
add("ust_router_dump_dir", STRING_TYPE, OPTIONAL, "/tmp");
|
80
|
-
addWithDynamicDefault(
|
81
|
-
"ust_router_default_node_name",
|
82
|
-
STRING_TYPE, OPTIONAL | CACHE_DEFAULT_VALUE,
|
83
|
-
getDefaultValueForDefaultNodeName);
|
84
|
-
add("ust_router_dev_mode", BOOL_TYPE, OPTIONAL, false);
|
85
|
-
add("union_station_gateway_address", STRING_TYPE, OPTIONAL | READ_ONLY, DEFAULT_UNION_STATION_GATEWAY_ADDRESS);
|
86
|
-
add("union_station_gateway_port", UINT_TYPE, OPTIONAL | READ_ONLY, DEFAULT_UNION_STATION_GATEWAY_PORT);
|
87
|
-
add("union_station_gateway_cert", STRING_TYPE, OPTIONAL | READ_ONLY);
|
88
|
-
add("union_station_proxy_address", STRING_TYPE, OPTIONAL | READ_ONLY);
|
89
|
-
add("analytics_sink_flush_timer_interval", UINT_TYPE, OPTIONAL, 5);
|
90
|
-
add("analytics_sink_flush_interval", UINT_TYPE, OPTIONAL, 0);
|
91
|
-
|
92
|
-
finalize();
|
93
|
-
}
|
94
|
-
};
|
95
|
-
|
96
|
-
struct ConfigRealization {
|
97
|
-
bool devMode;
|
98
|
-
unsigned int sinkFlushTimerInterval;
|
99
|
-
unsigned int sinkFlushInterval;
|
100
|
-
|
101
|
-
ConfigRealization(const ConfigKit::Store &config)
|
102
|
-
: devMode(config["ust_router_dev_mode"].asBool()),
|
103
|
-
sinkFlushTimerInterval(config["analytics_sink_flush_timer_interval"].asUInt()),
|
104
|
-
sinkFlushInterval(config["analytics_sink_flush_interval"].asUInt())
|
105
|
-
{ }
|
106
|
-
|
107
|
-
void swap(ConfigRealization &other) BOOST_NOEXCEPT_OR_NOTHROW {
|
108
|
-
std::swap(devMode, other.devMode);
|
109
|
-
std::swap(sinkFlushTimerInterval, other.sinkFlushTimerInterval);
|
110
|
-
std::swap(sinkFlushInterval, other.sinkFlushInterval);
|
111
|
-
}
|
112
|
-
};
|
113
|
-
|
114
|
-
struct ConfigChangeRequest {
|
115
|
-
ServerKit::BaseServerConfigChangeRequest forParent;
|
116
|
-
boost::scoped_ptr<ConfigRealization> configRlz;
|
117
|
-
};
|
118
|
-
|
119
|
-
private:
|
120
|
-
static const unsigned int GARBAGE_COLLECTION_TIMEOUT = 60; // 1 minute
|
121
|
-
static const unsigned int LOG_SINK_MAX_IDLE_TIME = 5 * 60; // 5 minutes
|
122
|
-
static const unsigned int TXN_ID_MAX_SIZE =
|
123
|
-
2 * sizeof(unsigned int) + // max hex timestamp size
|
124
|
-
11 + // space for a random identifier
|
125
|
-
1; // null terminator
|
126
|
-
|
127
|
-
friend inline struct ::ev_loop *UstRouter::Controller_getLoop(Controller *controller);
|
128
|
-
friend inline RemoteSender &UstRouter::Controller_getRemoteSender(Controller *controller);
|
129
|
-
|
130
|
-
typedef ServerKit::BaseServer<Controller, Client> ParentClass;
|
131
|
-
typedef ServerKit::Channel Channel;
|
132
|
-
typedef StringMap<TransactionPtr> TransactionMap;
|
133
|
-
typedef StringMap<LogSinkPtr> LogSinkCache;
|
134
|
-
|
135
|
-
ConfigRealization configRlz;
|
136
|
-
RandomGenerator randomGenerator;
|
137
|
-
TransactionMap transactions;
|
138
|
-
LogSinkCache logSinkCache;
|
139
|
-
RemoteSender remoteSender;
|
140
|
-
StringMap<FilterSupport::FilterPtr> filters;
|
141
|
-
|
142
|
-
ev::timer gcTimer;
|
143
|
-
ev::timer flushTimer;
|
144
|
-
|
145
|
-
|
146
|
-
/****** Handshake and authentication ******/
|
147
|
-
|
148
|
-
void beginHandshake(Client *client) {
|
149
|
-
StaticString reply[] = {
|
150
|
-
P_STATIC_STRING("version"),
|
151
|
-
P_STATIC_STRING("1")
|
152
|
-
};
|
153
|
-
writeArrayMessage(client, reply, 2);
|
154
|
-
|
155
|
-
// Begin reading authentication username. Control
|
156
|
-
// continues in onAuthUsernameDataReceived().
|
157
|
-
client->state = Client::READING_AUTH_USERNAME;
|
158
|
-
}
|
159
|
-
|
160
|
-
Channel::Result onAuthUsernameDataReceived(Client *client, const MemoryKit::mbuf &buffer,
|
161
|
-
int errcode)
|
162
|
-
{
|
163
|
-
size_t consumed = client->scalarReader.feed(buffer.start, buffer.size());
|
164
|
-
if (client->scalarReader.done()) {
|
165
|
-
processAuthUsername(client);
|
166
|
-
}
|
167
|
-
return Channel::Result(consumed, false);
|
168
|
-
}
|
169
|
-
|
170
|
-
void processAuthUsername(Client *client) {
|
171
|
-
if (client->scalarReader.hasError()) {
|
172
|
-
string reason = "Error parsing username: ";
|
173
|
-
reason.append(client->scalarReader.errorString());
|
174
|
-
sendErrorToClient(client, reason);
|
175
|
-
if (client->connected()) {
|
176
|
-
disconnectWithError(&client, reason);
|
177
|
-
}
|
178
|
-
return;
|
179
|
-
}
|
180
|
-
|
181
|
-
StaticString username = client->scalarReader.value();
|
182
|
-
if (!constantTimeCompare(username, config["ust_router_username"].asString())) {
|
183
|
-
sendErrorToClient(client, "Invalid username or password");
|
184
|
-
if (client->connected()) {
|
185
|
-
disconnectWithError(&client, "Client sent invalid username");
|
186
|
-
}
|
187
|
-
return;
|
188
|
-
}
|
189
|
-
|
190
|
-
// Begin reading authentication password. Control continues
|
191
|
-
// in onAuthPasswordDataReceived().
|
192
|
-
SKC_DEBUG(client, "Username is correct");
|
193
|
-
client->scalarReader.reset();
|
194
|
-
client->state = Client::READING_AUTH_PASSWORD;
|
195
|
-
}
|
196
|
-
|
197
|
-
Channel::Result onAuthPasswordDataReceived(Client *client, const MemoryKit::mbuf &buffer,
|
198
|
-
int errcode)
|
199
|
-
{
|
200
|
-
size_t consumed = client->scalarReader.feed(buffer.start, buffer.size());
|
201
|
-
if (client->scalarReader.done()) {
|
202
|
-
processAuthPassword(client);
|
203
|
-
}
|
204
|
-
return Channel::Result(consumed, false);
|
205
|
-
}
|
206
|
-
|
207
|
-
void processAuthPassword(Client *client) {
|
208
|
-
if (client->scalarReader.hasError()) {
|
209
|
-
string reason = "Error parsing password: ";
|
210
|
-
reason.append(client->scalarReader.errorString());
|
211
|
-
sendErrorToClient(client, reason);
|
212
|
-
if (client->connected()) {
|
213
|
-
disconnectWithError(&client, reason);
|
214
|
-
}
|
215
|
-
return;
|
216
|
-
}
|
217
|
-
|
218
|
-
StaticString password = client->scalarReader.value();
|
219
|
-
if (!constantTimeCompare(password, config["ust_router_password"].asString())) {
|
220
|
-
sendErrorToClient(client, "Invalid username or password");
|
221
|
-
if (client->connected()) {
|
222
|
-
disconnectWithError(&client, "Client sent invalid password");
|
223
|
-
}
|
224
|
-
return;
|
225
|
-
}
|
226
|
-
|
227
|
-
// We are now authenticated.
|
228
|
-
client->scalarReader.reset(true);
|
229
|
-
SKC_DEBUG(client, "Password is correct. Client fully authenticated");
|
230
|
-
sendOkToClient(client);
|
231
|
-
|
232
|
-
// Begin reading normal message. Control continues in onWorkDataReceived().
|
233
|
-
client->state = Client::READING_MESSAGE;
|
234
|
-
}
|
235
|
-
|
236
|
-
|
237
|
-
/****** Normal message handling: parser and router ******/
|
238
|
-
|
239
|
-
Channel::Result onMessageDataReceived(Client *client, const MemoryKit::mbuf &buffer,
|
240
|
-
int errcode)
|
241
|
-
{
|
242
|
-
size_t consumed = client->arrayReader.feed(buffer.start, buffer.size());
|
243
|
-
|
244
|
-
if (client->arrayReader.hasError()) {
|
245
|
-
disconnectWithError(&client,
|
246
|
-
string("Error processing message: array message parse error: ")
|
247
|
-
+ client->arrayReader.errorString());
|
248
|
-
return Channel::Result(consumed, true);
|
249
|
-
}
|
250
|
-
|
251
|
-
if (client->arrayReader.done()) {
|
252
|
-
// No error
|
253
|
-
const vector<StaticString> &message = client->arrayReader.value();
|
254
|
-
SKC_DEBUG(client, "Message received: " << toString(message));
|
255
|
-
if (message.size() < 1) {
|
256
|
-
disconnectWithError(&client, "Error processing message:"
|
257
|
-
" too few parameters");
|
258
|
-
return Channel::Result(consumed, true);
|
259
|
-
}
|
260
|
-
|
261
|
-
processNewMessage(client, message);
|
262
|
-
client->arrayReader.reset();
|
263
|
-
}
|
264
|
-
return Channel::Result(consumed, false);
|
265
|
-
}
|
266
|
-
|
267
|
-
Channel::Result onMessageBodyDataReceived(Client *client, const MemoryKit::mbuf &buffer,
|
268
|
-
int errcode)
|
269
|
-
{
|
270
|
-
size_t consumed = client->scalarReader.feed(buffer.start, buffer.size());
|
271
|
-
|
272
|
-
if (client->scalarReader.hasError()) {
|
273
|
-
disconnectWithError(&client,
|
274
|
-
string("Error processing message: scalar message parse error: ")
|
275
|
-
+ client->scalarReader.errorString());
|
276
|
-
return Channel::Result(consumed, true);
|
277
|
-
}
|
278
|
-
|
279
|
-
if (client->scalarReader.done()) {
|
280
|
-
// No error
|
281
|
-
processLogMessageBody(client, client->scalarReader.value());
|
282
|
-
client->scalarReader.reset();
|
283
|
-
}
|
284
|
-
return Channel::Result(consumed, false);
|
285
|
-
}
|
286
|
-
|
287
|
-
void processNewMessage(Client *client, const vector<StaticString> &args) {
|
288
|
-
try {
|
289
|
-
if (args[0] == P_STATIC_STRING("log")) {
|
290
|
-
processLogMessage(client, args);
|
291
|
-
} else if (args[0] == P_STATIC_STRING("openTransaction")) {
|
292
|
-
processOpenTransactionMessage(client, args);
|
293
|
-
} else if (args[0] == P_STATIC_STRING("closeTransaction")) {
|
294
|
-
processCloseTransactionMessage(client, args);
|
295
|
-
} else if (args[0] == P_STATIC_STRING("init")) {
|
296
|
-
processInitMessage(client, args);
|
297
|
-
} else if (args[0] == P_STATIC_STRING("info")) {
|
298
|
-
processInfoMessage(client, args);
|
299
|
-
} else if (args[0] == P_STATIC_STRING("ping")) {
|
300
|
-
processPingMessage(client, args);
|
301
|
-
} else {
|
302
|
-
processUnknownMessage(client, args);
|
303
|
-
}
|
304
|
-
} catch (const oxt::tracable_exception &e) {
|
305
|
-
SKC_ERROR(client, "Exception: " << e.what() << "\n" << e.backtrace());
|
306
|
-
if (client->connected()) {
|
307
|
-
disconnect(&client);
|
308
|
-
}
|
309
|
-
}
|
310
|
-
}
|
311
|
-
|
312
|
-
|
313
|
-
/****** Individual message handlers ******/
|
314
|
-
|
315
|
-
void processLogMessage(Client *client, const vector<StaticString> &args) {
|
316
|
-
StaticString txnId, timestamp;
|
317
|
-
bool ack;
|
318
|
-
TransactionPtr transaction;
|
319
|
-
set<string>::iterator s_it;
|
320
|
-
|
321
|
-
if (OXT_UNLIKELY(!expectingMinArgumentsCount(client, args, 3)
|
322
|
-
|| !expectingLoggerType(client)))
|
323
|
-
{
|
324
|
-
goto done;
|
325
|
-
}
|
326
|
-
|
327
|
-
txnId = args[1];
|
328
|
-
timestamp = args[2];
|
329
|
-
ack = getBool(args, 3, false);
|
330
|
-
|
331
|
-
transaction = transactions.get(txnId);
|
332
|
-
if (OXT_UNLIKELY(transaction == NULL)) {
|
333
|
-
SKC_ERROR(client, "Cannot log data: transaction does not exist");
|
334
|
-
if (ack) {
|
335
|
-
sendErrorToClient(client, "Cannot log data: transaction does not exist");
|
336
|
-
if (client->connected()) {
|
337
|
-
disconnect(&client);
|
338
|
-
}
|
339
|
-
}
|
340
|
-
goto done;
|
341
|
-
}
|
342
|
-
|
343
|
-
s_it = client->openTransactions.find(transaction->getTxnId());
|
344
|
-
if (OXT_UNLIKELY(s_it == client->openTransactions.end())) {
|
345
|
-
SKC_ERROR(client, "Cannot log data: transaction not opened in this connection");
|
346
|
-
if (ack) {
|
347
|
-
sendErrorToClient(client,
|
348
|
-
"Cannot log data: transaction not opened in this connection");
|
349
|
-
if (client->connected()) {
|
350
|
-
disconnect(&client);
|
351
|
-
}
|
352
|
-
}
|
353
|
-
goto done;
|
354
|
-
}
|
355
|
-
|
356
|
-
client->logCommandParams.transaction = transaction;
|
357
|
-
client->logCommandParams.timestamp.assign(timestamp.data(), timestamp.size());
|
358
|
-
client->logCommandParams.ack = ack;
|
359
|
-
|
360
|
-
// Control will continue in processLogMessageBody()
|
361
|
-
// when body is fully read.
|
362
|
-
client->state = Client::READING_MESSAGE_BODY;
|
363
|
-
|
364
|
-
if (ack) {
|
365
|
-
sendOkToClient(client);
|
366
|
-
}
|
367
|
-
|
368
|
-
done:
|
369
|
-
if (client != NULL && client->connected()) {
|
370
|
-
SKC_DEBUG(client, "Done processing 'log' message");
|
371
|
-
}
|
372
|
-
}
|
373
|
-
|
374
|
-
void processLogMessageBody(Client *client, const StaticString &body) {
|
375
|
-
// In here we process the scalar message that's expected to come
|
376
|
-
// after the "log" command.
|
377
|
-
LoggingKit::Level level = LoggingKit::getLevel();
|
378
|
-
|
379
|
-
if (level == LoggingKit::DEBUG) {
|
380
|
-
string truncatedBody;
|
381
|
-
if (body.size() > 97) {
|
382
|
-
string truncatedBody = body.substr(0, 97);
|
383
|
-
truncatedBody.append("...");
|
384
|
-
SKC_DEBUG(client, "Processing message body (" << body.size() <<
|
385
|
-
" bytes): " << truncatedBody);
|
386
|
-
} else {
|
387
|
-
SKC_DEBUG(client, "Processing message body (" << body.size() <<
|
388
|
-
" bytes): " << body);
|
389
|
-
}
|
390
|
-
} else if (level >= LoggingKit::DEBUG2) {
|
391
|
-
SKC_TRACE(client, 2, "Processing message body (" << body.size() <<
|
392
|
-
" bytes): " << body);
|
393
|
-
}
|
394
|
-
|
395
|
-
writeLogEntry(client,
|
396
|
-
client->logCommandParams.transaction,
|
397
|
-
client->logCommandParams.timestamp,
|
398
|
-
body,
|
399
|
-
client->logCommandParams.ack);
|
400
|
-
client->logCommandParams.transaction.reset();
|
401
|
-
client->logCommandParams.timestamp.clear();
|
402
|
-
|
403
|
-
client->state = Client::READING_MESSAGE;
|
404
|
-
|
405
|
-
if (client->connected()) {
|
406
|
-
SKC_DEBUG(client, "Done processing 'log' message body");
|
407
|
-
}
|
408
|
-
}
|
409
|
-
|
410
|
-
void processOpenTransactionMessage(Client *client, const vector<StaticString> &args) {
|
411
|
-
if (OXT_UNLIKELY(!expectingMinArgumentsCount(client, args, 7)
|
412
|
-
|| !expectingLoggerType(client)))
|
413
|
-
{
|
414
|
-
return;
|
415
|
-
}
|
416
|
-
|
417
|
-
StaticString txnId = args[1];
|
418
|
-
StaticString groupName = args[2];
|
419
|
-
StaticString nodeName = args[3];
|
420
|
-
StaticString category = args[4];
|
421
|
-
StaticString timestamp = args[5];
|
422
|
-
StaticString unionStationKey = args[6];
|
423
|
-
bool crashProtect = getBool(args, 7, true);
|
424
|
-
bool ack = getBool(args, 8, false);
|
425
|
-
StaticString filters = getStaticString(args, 9);
|
426
|
-
|
427
|
-
TransactionPtr transaction;
|
428
|
-
char autogeneratedTxnIdBuf[TXN_ID_MAX_SIZE];
|
429
|
-
char *autogeneratedTxnIdBufEnd;
|
430
|
-
bool autogenTxnId = txnId.empty();
|
431
|
-
|
432
|
-
if (autogenTxnId) {
|
433
|
-
// Autogeneration requested
|
434
|
-
if (ack) {
|
435
|
-
unsigned long long timestamp = SystemTime::getUsec();
|
436
|
-
createTxnId(autogeneratedTxnIdBuf,
|
437
|
-
&autogeneratedTxnIdBufEnd,
|
438
|
-
timestamp);
|
439
|
-
txnId = StaticString(autogeneratedTxnIdBuf,
|
440
|
-
autogeneratedTxnIdBufEnd - autogeneratedTxnIdBuf);
|
441
|
-
} else {
|
442
|
-
SKC_ERROR(client, "Transaction autogeneration requested,"
|
443
|
-
" but 'ack' parameter is set to false");
|
444
|
-
goto done;
|
445
|
-
}
|
446
|
-
}
|
447
|
-
|
448
|
-
if (OXT_UNLIKELY(!validTxnId(txnId))) {
|
449
|
-
SKC_ERROR(client, "Invalid transaction ID format");
|
450
|
-
if (ack) {
|
451
|
-
sendErrorToClient(client, "Invalid transaction ID format");
|
452
|
-
if (client->connected()) {
|
453
|
-
disconnect(&client);
|
454
|
-
}
|
455
|
-
}
|
456
|
-
goto done;
|
457
|
-
}
|
458
|
-
if (!unionStationKey.empty()
|
459
|
-
&& OXT_UNLIKELY(!validUnionStationKey(unionStationKey)))
|
460
|
-
{
|
461
|
-
SKC_ERROR(client, "Invalid Union Station key format");
|
462
|
-
if (ack) {
|
463
|
-
sendErrorToClient(client, "Invalid Union Station key format");
|
464
|
-
if (client->connected()) {
|
465
|
-
disconnect(&client);
|
466
|
-
}
|
467
|
-
}
|
468
|
-
goto done;
|
469
|
-
}
|
470
|
-
|
471
|
-
if (nodeName.empty()) {
|
472
|
-
nodeName = client->nodeName;
|
473
|
-
}
|
474
|
-
|
475
|
-
transaction = transactions.get(txnId);
|
476
|
-
if (transaction == NULL) {
|
477
|
-
if (OXT_UNLIKELY(!supportedCategory(category))) {
|
478
|
-
SKC_ERROR(client, "Unsupported category '" << category << "'");
|
479
|
-
if (ack) {
|
480
|
-
sendErrorToClient(client, "Unsupported category");
|
481
|
-
if (client->connected()) {
|
482
|
-
disconnect(&client);
|
483
|
-
}
|
484
|
-
}
|
485
|
-
goto done;
|
486
|
-
}
|
487
|
-
|
488
|
-
transaction = boost::make_shared<Transaction>(
|
489
|
-
txnId, groupName, nodeName, category,
|
490
|
-
unionStationKey, ev_now(getLoop()), filters
|
491
|
-
);
|
492
|
-
transaction->enableCrashProtect(crashProtect);
|
493
|
-
transactions.set(txnId, transaction);
|
494
|
-
} else {
|
495
|
-
if (OXT_UNLIKELY(client->openTransactions.find(transaction->getTxnId()) !=
|
496
|
-
client->openTransactions.end()))
|
497
|
-
{
|
498
|
-
SKC_ERROR(client, "Cannot open transaction: transaction already opened in this connection");
|
499
|
-
if (ack) {
|
500
|
-
sendErrorToClient(client, "Cannot open transaction: transaction already opened in this connection");
|
501
|
-
if (client->connected()) {
|
502
|
-
disconnect(&client);
|
503
|
-
}
|
504
|
-
}
|
505
|
-
goto done;
|
506
|
-
}
|
507
|
-
if (OXT_UNLIKELY(transaction->getCategory() != category)) {
|
508
|
-
SKC_ERROR(client, "Cannot open transaction: transaction already opened with a different category name (" <<
|
509
|
-
transaction->getCategory() << " vs " << category << ")");
|
510
|
-
if (ack) {
|
511
|
-
sendErrorToClient(client,
|
512
|
-
"Cannot open transaction: transaction already opened with a different category name (" +
|
513
|
-
transaction->getCategory() + " vs " + category + ")");
|
514
|
-
if (client->connected()) {
|
515
|
-
disconnect(&client);
|
516
|
-
}
|
517
|
-
}
|
518
|
-
goto done;
|
519
|
-
}
|
520
|
-
if (OXT_UNLIKELY(transaction->getNodeName() != nodeName)) {
|
521
|
-
SKC_ERROR(client, "Cannot open transaction: transaction "
|
522
|
-
"already opened with a different node name (" <<
|
523
|
-
transaction->getNodeName() << " vs " << nodeName << ")");
|
524
|
-
if (ack) {
|
525
|
-
sendErrorToClient(client, "Cannot open transaction: transaction "
|
526
|
-
"already opened with a different node name (" +
|
527
|
-
transaction->getNodeName() + " vs " + nodeName + ")");
|
528
|
-
if (client->connected()) {
|
529
|
-
disconnect(&client);
|
530
|
-
}
|
531
|
-
}
|
532
|
-
goto done;
|
533
|
-
}
|
534
|
-
if (OXT_UNLIKELY(transaction->getUnionStationKey() != unionStationKey)) {
|
535
|
-
SKC_ERROR(client,
|
536
|
-
"Cannot open transaction: transaction already opened with a "
|
537
|
-
"different key ('" << transaction->getUnionStationKey() <<
|
538
|
-
"' vs '" << unionStationKey << "')");
|
539
|
-
if (ack) {
|
540
|
-
sendErrorToClient(client,
|
541
|
-
"Cannot open transaction: transaction already opened with a "
|
542
|
-
"different key ('" + transaction->getUnionStationKey() +
|
543
|
-
"' vs '" + unionStationKey + "')");
|
544
|
-
if (client->connected()) {
|
545
|
-
disconnect(&client);
|
546
|
-
}
|
547
|
-
}
|
548
|
-
goto done;
|
549
|
-
}
|
550
|
-
}
|
551
|
-
|
552
|
-
client->openTransactions.insert(transaction->getTxnId());
|
553
|
-
transaction->ref();
|
554
|
-
writeLogEntry(client, transaction, timestamp, P_STATIC_STRING("ATTACH"), ack);
|
555
|
-
|
556
|
-
if (client->connected() && ack) {
|
557
|
-
if (autogenTxnId) {
|
558
|
-
StaticString reply[] = {
|
559
|
-
P_STATIC_STRING("status"),
|
560
|
-
P_STATIC_STRING("ok"),
|
561
|
-
txnId
|
562
|
-
};
|
563
|
-
writeArrayMessage(client, reply, 3);
|
564
|
-
} else {
|
565
|
-
sendOkToClient(client);
|
566
|
-
}
|
567
|
-
}
|
568
|
-
|
569
|
-
done:
|
570
|
-
if (client != NULL && client->connected()) {
|
571
|
-
SKC_DEBUG(client, "Done processing 'openTransaction' message");
|
572
|
-
}
|
573
|
-
}
|
574
|
-
|
575
|
-
void processCloseTransactionMessage(Client *client, const vector<StaticString> &args) {
|
576
|
-
StaticString txnId, timestamp;
|
577
|
-
bool ack;
|
578
|
-
set<string>::const_iterator s_it;
|
579
|
-
TransactionPtr transaction;
|
580
|
-
|
581
|
-
if (OXT_UNLIKELY(!expectingMinArgumentsCount(client, args, 3)
|
582
|
-
|| !expectingLoggerType(client)))
|
583
|
-
{
|
584
|
-
goto done;
|
585
|
-
}
|
586
|
-
|
587
|
-
txnId = args[1];
|
588
|
-
timestamp = args[2];
|
589
|
-
ack = getBool(args, 3, false);
|
590
|
-
|
591
|
-
transaction = transactions.get(txnId);
|
592
|
-
if (OXT_UNLIKELY(transaction == NULL)) {
|
593
|
-
SKC_ERROR(client, "Cannot close transaction " << txnId <<
|
594
|
-
": transaction does not exist");
|
595
|
-
if (ack) {
|
596
|
-
sendErrorToClient(client,
|
597
|
-
"Cannot close transaction " + txnId +
|
598
|
-
": transaction does not exist");
|
599
|
-
if (client->connected()) {
|
600
|
-
disconnect(&client);
|
601
|
-
}
|
602
|
-
}
|
603
|
-
goto done;
|
604
|
-
} else {
|
605
|
-
s_it = client->openTransactions.find(transaction->getTxnId());
|
606
|
-
if (OXT_UNLIKELY(s_it == client->openTransactions.end())) {
|
607
|
-
SKC_ERROR(client, "Cannot close transaction " << txnId <<
|
608
|
-
": transaction not opened in this connection");
|
609
|
-
if (ack) {
|
610
|
-
sendErrorToClient(client,
|
611
|
-
"Cannot close transaction " + txnId +
|
612
|
-
": transaction not opened in this connection");
|
613
|
-
if (client->connected()) {
|
614
|
-
disconnect(&client);
|
615
|
-
}
|
616
|
-
}
|
617
|
-
goto done;
|
618
|
-
}
|
619
|
-
|
620
|
-
client->openTransactions.erase(s_it);
|
621
|
-
writeDetachEntry(client, transaction, timestamp, ack);
|
622
|
-
transaction->unref();
|
623
|
-
if (transaction->getRefCount() == 0) {
|
624
|
-
transactions.remove(txnId);
|
625
|
-
closeTransaction(client, transaction);
|
626
|
-
}
|
627
|
-
}
|
628
|
-
|
629
|
-
if (ack) {
|
630
|
-
sendOkToClient(client);
|
631
|
-
}
|
632
|
-
|
633
|
-
done:
|
634
|
-
if (client != NULL && client->connected()) {
|
635
|
-
SKC_DEBUG(client, "Done processing 'closeTransaction' message");
|
636
|
-
}
|
637
|
-
}
|
638
|
-
|
639
|
-
void processInitMessage(Client *client, const vector<StaticString> &args) {
|
640
|
-
StaticString nodeName;
|
641
|
-
|
642
|
-
if (OXT_UNLIKELY(client->type != Client::UNINITIALIZED)) {
|
643
|
-
logErrorAndSendToClient(client, "Already initialized");
|
644
|
-
if (client->connected()) {
|
645
|
-
disconnect(&client);
|
646
|
-
}
|
647
|
-
goto done;
|
648
|
-
}
|
649
|
-
if (OXT_UNLIKELY(!expectingMinArgumentsCount(client, args, 1))) {
|
650
|
-
goto done;
|
651
|
-
}
|
652
|
-
|
653
|
-
nodeName = getStaticString(args, 1);
|
654
|
-
if (nodeName.empty()) {
|
655
|
-
client->nodeName = config["ust_router_default_node_name"].asString();
|
656
|
-
} else {
|
657
|
-
client->nodeName.assign(nodeName.data(), nodeName.size());
|
658
|
-
}
|
659
|
-
client->type = Client::LOGGER;
|
660
|
-
sendOkToClient(client);
|
661
|
-
|
662
|
-
done:
|
663
|
-
if (client != NULL && client->connected()) {
|
664
|
-
SKC_DEBUG(client, "Done processing 'init' message");
|
665
|
-
}
|
666
|
-
}
|
667
|
-
|
668
|
-
void processInfoMessage(Client *client, const vector<StaticString> &args) {
|
669
|
-
string info = inspectStateAsJson().toStyledString();
|
670
|
-
|
671
|
-
StaticString reply[] = {
|
672
|
-
P_STATIC_STRING("status"),
|
673
|
-
P_STATIC_STRING("ok"),
|
674
|
-
info
|
675
|
-
};
|
676
|
-
writeArrayMessage(client, reply, 3);
|
677
|
-
|
678
|
-
if (client->connected()) {
|
679
|
-
SKC_DEBUG(client, "Done processing 'info' message");
|
680
|
-
}
|
681
|
-
}
|
682
|
-
|
683
|
-
void processPingMessage(Client *client, const vector<StaticString> &args) {
|
684
|
-
StaticString reply = P_STATIC_STRING("pong");
|
685
|
-
writeArrayMessage(client, &reply, 1);
|
686
|
-
if (client->connected()) {
|
687
|
-
SKC_DEBUG(client, "Done processing 'ping' message");
|
688
|
-
}
|
689
|
-
}
|
690
|
-
|
691
|
-
void processUnknownMessage(Client *client, const vector<StaticString> &args) {
|
692
|
-
string reason = "Unknown message: ";
|
693
|
-
reason.append(toString(args));
|
694
|
-
logErrorAndSendToClient(client, reason);
|
695
|
-
if (client->connected()) {
|
696
|
-
disconnect(&client);
|
697
|
-
}
|
698
|
-
}
|
699
|
-
|
700
|
-
|
701
|
-
/****** Periodic tasks ******/
|
702
|
-
|
703
|
-
/**
|
704
|
-
* A periodic task in which log sinks are garbage collected.
|
705
|
-
*/
|
706
|
-
void garbageCollect(ev::timer &timer, int revents) {
|
707
|
-
P_DEBUG("Running UstRouter garbage collector");
|
708
|
-
|
709
|
-
LogSinkCache::iterator it, end = logSinkCache.end();
|
710
|
-
ev_tstamp threshold = ev_now(getLoop()) - LOG_SINK_MAX_IDLE_TIME;
|
711
|
-
SmallVector<string, 8> toRemove;
|
712
|
-
|
713
|
-
for (it = logSinkCache.begin(); it != end; it++) {
|
714
|
-
const LogSinkPtr &sink = it->second;
|
715
|
-
if (canGarbageCollectSink(sink, threshold)) {
|
716
|
-
toRemove.push_back(string(it->first.data(), it->first.size()));
|
717
|
-
}
|
718
|
-
}
|
719
|
-
|
720
|
-
foreach (string key, toRemove) {
|
721
|
-
P_DEBUG("Garbage collecting UstRouter sink: " <<
|
722
|
-
logSinkCache.get(key)->inspect());
|
723
|
-
logSinkCache.remove(key);
|
724
|
-
}
|
725
|
-
|
726
|
-
P_DEBUG("Done running UstRouter garbage collector");
|
727
|
-
}
|
728
|
-
|
729
|
-
bool canGarbageCollectSink(const LogSinkPtr &sink, ev_tstamp threshold) const {
|
730
|
-
return sink->isRemote()
|
731
|
-
&& sink->opened == 0
|
732
|
-
&& sink->lastClosed != 0
|
733
|
-
&& sink->lastClosed < threshold;
|
734
|
-
}
|
735
|
-
|
736
|
-
/**
|
737
|
-
* A period task in which the sinks are flushed whose
|
738
|
-
* flush timeout have expired.
|
739
|
-
*/
|
740
|
-
void flushSomeSinks(ev::timer &timer, int revents) {
|
741
|
-
P_DEBUG("Flushing sinks that need flushing");
|
742
|
-
|
743
|
-
LogSinkCache::iterator it;
|
744
|
-
LogSinkCache::iterator end = logSinkCache.end();
|
745
|
-
ev_tstamp threshold = ev_now(getLoop()) - configRlz.sinkFlushInterval;
|
746
|
-
|
747
|
-
for (it = logSinkCache.begin(); it != end; it++) {
|
748
|
-
const LogSinkPtr &sink = it->second;
|
749
|
-
if (sink->lastFlushed < threshold) {
|
750
|
-
// flush() method is responsible for logging
|
751
|
-
sink->flush();
|
752
|
-
}
|
753
|
-
}
|
754
|
-
|
755
|
-
P_DEBUG("Done flushing sinks that need flushing");
|
756
|
-
}
|
757
|
-
|
758
|
-
|
759
|
-
/****** Utility functions ******/
|
760
|
-
|
761
|
-
void writeArrayMessage(Client *client, StaticString args[], unsigned int argsCount) {
|
762
|
-
char headerBuf[sizeof(boost::uint16_t)];
|
763
|
-
unsigned int outputSize = ArrayMessage::outputSize(argsCount);
|
764
|
-
SmallVector<StaticString, 8> output;
|
765
|
-
|
766
|
-
output.resize(outputSize);
|
767
|
-
ArrayMessage::generate(args, argsCount, headerBuf, &output[0], outputSize);
|
768
|
-
|
769
|
-
unsigned int bufferSize = 0;
|
770
|
-
for (unsigned int i = 0; i < outputSize; i++) {
|
771
|
-
bufferSize += output[i].size();
|
772
|
-
}
|
773
|
-
|
774
|
-
MemoryKit::mbuf buffer(mbuf_get_with_size(&getContext()->mbuf_pool, bufferSize));
|
775
|
-
char *pos = buffer.start;
|
776
|
-
const char *end = buffer.start + bufferSize;
|
777
|
-
for (unsigned int i = 0; i < outputSize; i++) {
|
778
|
-
pos = appendData(pos, end, output[i].data(), output[i].size());
|
779
|
-
}
|
780
|
-
|
781
|
-
client->output.feed(buffer);
|
782
|
-
}
|
783
|
-
|
784
|
-
void sendErrorToClient(Client *client, const StaticString &message) {
|
785
|
-
StaticString reply[] = {
|
786
|
-
P_STATIC_STRING("status"),
|
787
|
-
P_STATIC_STRING("error"),
|
788
|
-
message
|
789
|
-
};
|
790
|
-
writeArrayMessage(client, reply, 3);
|
791
|
-
}
|
792
|
-
|
793
|
-
void logErrorAndSendToClient(Client *client, const StaticString &message) {
|
794
|
-
SKC_ERROR(client, message);
|
795
|
-
sendErrorToClient(client, message);
|
796
|
-
}
|
797
|
-
|
798
|
-
void sendOkToClient(Client *client) {
|
799
|
-
StaticString reply[] = {
|
800
|
-
P_STATIC_STRING("status"),
|
801
|
-
P_STATIC_STRING("ok")
|
802
|
-
};
|
803
|
-
writeArrayMessage(client, reply, 2);
|
804
|
-
}
|
805
|
-
|
806
|
-
bool expectingArgumentsCount(Client *client, const vector<StaticString> &args, unsigned int size) {
|
807
|
-
if (args.size() == size) {
|
808
|
-
return true;
|
809
|
-
} else {
|
810
|
-
SKC_ERROR(client, "Invalid number of arguments in message (expecting " <<
|
811
|
-
size << ", got " << args.size() << ")");
|
812
|
-
StaticString reply[] = {
|
813
|
-
P_STATIC_STRING("status"),
|
814
|
-
P_STATIC_STRING("error"),
|
815
|
-
P_STATIC_STRING("Invalid number of arguments in message")
|
816
|
-
};
|
817
|
-
writeArrayMessage(client, reply, 3);
|
818
|
-
disconnect(&client);
|
819
|
-
return false;
|
820
|
-
}
|
821
|
-
}
|
822
|
-
|
823
|
-
bool expectingMinArgumentsCount(Client *client, const vector<StaticString> &args, unsigned int size) {
|
824
|
-
if (args.size() >= size) {
|
825
|
-
return true;
|
826
|
-
} else {
|
827
|
-
SKC_ERROR(client, "Invalid number of arguments in message (expecting at least " <<
|
828
|
-
size << ", got " << args.size() << ")");
|
829
|
-
sendErrorToClient(client, P_STATIC_STRING("Invalid number of arguments in message"));
|
830
|
-
if (client->connected()) {
|
831
|
-
disconnect(&client);
|
832
|
-
}
|
833
|
-
return false;
|
834
|
-
}
|
835
|
-
}
|
836
|
-
|
837
|
-
bool expectingLoggerType(Client *client) {
|
838
|
-
if (client->type == Client::LOGGER) {
|
839
|
-
return true;
|
840
|
-
} else {
|
841
|
-
logErrorAndSendToClient(client, "Client not initialized as logger");
|
842
|
-
if (client->connected()) {
|
843
|
-
disconnect(&client);
|
844
|
-
}
|
845
|
-
return false;
|
846
|
-
}
|
847
|
-
}
|
848
|
-
|
849
|
-
static bool getBool(const vector<StaticString> &args, unsigned int index,
|
850
|
-
bool defaultValue = false)
|
851
|
-
{
|
852
|
-
if (index < args.size()) {
|
853
|
-
return args[index] == "true";
|
854
|
-
} else {
|
855
|
-
return defaultValue;
|
856
|
-
}
|
857
|
-
}
|
858
|
-
|
859
|
-
static StaticString getStaticString(const vector<StaticString> &args,
|
860
|
-
unsigned int index, const StaticString &defaultValue = StaticString())
|
861
|
-
{
|
862
|
-
if (index < args.size()) {
|
863
|
-
return args[index];
|
864
|
-
} else {
|
865
|
-
return defaultValue;
|
866
|
-
}
|
867
|
-
}
|
868
|
-
|
869
|
-
void createTxnId(char *txnId, char **txnIdEnd, unsigned long long timestamp) {
|
870
|
-
unsigned int timestampSize;
|
871
|
-
char *end;
|
872
|
-
// "[timestamp]"
|
873
|
-
// Our timestamp is like a Unix timestamp but with minutes
|
874
|
-
// resolution instead of seconds. 32 bits will last us for
|
875
|
-
// about 8000 years.
|
876
|
-
timestampSize = integerToHexatri<unsigned int>(
|
877
|
-
timestamp / 1000000 / 60,
|
878
|
-
txnId);
|
879
|
-
end = txnId + timestampSize;
|
880
|
-
|
881
|
-
// "[timestamp]-"
|
882
|
-
*end = '-';
|
883
|
-
end++;
|
884
|
-
// "[timestamp]-[random id]"
|
885
|
-
randomGenerator.generateAsciiString(end, 11);
|
886
|
-
end += 11;
|
887
|
-
*end = '\0';
|
888
|
-
*txnIdEnd = end;
|
889
|
-
}
|
890
|
-
|
891
|
-
bool validTxnId(const StaticString &txnId) const {
|
892
|
-
// TODO: must contain timestamp
|
893
|
-
// TODO: must contain separator
|
894
|
-
// TODO: must contain random id
|
895
|
-
// TODO: must not be too large
|
896
|
-
return !txnId.empty();
|
897
|
-
}
|
898
|
-
|
899
|
-
bool validUnionStationKey(const StaticString &key) const {
|
900
|
-
// TODO: must be hexadecimal
|
901
|
-
// TODO: must not be too large
|
902
|
-
return !key.empty();
|
903
|
-
}
|
904
|
-
|
905
|
-
bool validLogContent(const StaticString &data) const {
|
906
|
-
const char *current = data.c_str();
|
907
|
-
const char *end = current + data.size();
|
908
|
-
while (current < end) {
|
909
|
-
char c = *current;
|
910
|
-
if ((c < 1 && c > 126) || c == '\n' || c == '\r') {
|
911
|
-
return false;
|
912
|
-
}
|
913
|
-
current++;
|
914
|
-
}
|
915
|
-
return true;
|
916
|
-
}
|
917
|
-
|
918
|
-
bool validTimestamp(const StaticString ×tamp) const {
|
919
|
-
// TODO: must be hexadecimal
|
920
|
-
// TODO: must not be too large
|
921
|
-
return true;
|
922
|
-
}
|
923
|
-
|
924
|
-
bool supportedCategory(const StaticString &category) const {
|
925
|
-
return category == P_STATIC_STRING("requests")
|
926
|
-
|| category == P_STATIC_STRING("processes")
|
927
|
-
|| category == P_STATIC_STRING("exceptions")
|
928
|
-
|| category == P_STATIC_STRING("system_metrics")
|
929
|
-
|| category == P_STATIC_STRING("internal_information");
|
930
|
-
}
|
931
|
-
|
932
|
-
/**
|
933
|
-
* Given a logSinkCache key, which may contains NULLs, converts it
|
934
|
-
* into something that can be represented as a JSON string. It's not
|
935
|
-
* a perfect representation, but probably good enough for display
|
936
|
-
* purposes.
|
937
|
-
*/
|
938
|
-
string createJsonKey(const StaticString &key) const {
|
939
|
-
return replaceAll(key, P_STATIC_STRING("\0"), P_STATIC_STRING("__"));
|
940
|
-
}
|
941
|
-
|
942
|
-
LogSinkPtr openLogFile(Client *client, const StaticString &category) {
|
943
|
-
size_t cacheKeySize =
|
944
|
-
(sizeof("file:") - 1) +
|
945
|
-
category.size();
|
946
|
-
char cacheKey[cacheKeySize];
|
947
|
-
char *pos = cacheKey;
|
948
|
-
const char *end = cacheKey + cacheKeySize;
|
949
|
-
|
950
|
-
pos = appendData(pos, end, P_STATIC_STRING("file:"));
|
951
|
-
pos = appendData(pos, end, category);
|
952
|
-
|
953
|
-
LogSinkPtr sink = logSinkCache.get(StaticString(cacheKey, cacheKeySize));
|
954
|
-
if (sink == NULL) {
|
955
|
-
string dumpFile = config["ust_router_dump_dir"].asString() + "/" + category;
|
956
|
-
SKC_DEBUG(client, "Creating dump file: " << dumpFile);
|
957
|
-
sink = boost::make_shared<FileSink>(this, dumpFile);
|
958
|
-
sink->opened = 1;
|
959
|
-
logSinkCache.set(StaticString(cacheKey, cacheKeySize), sink);
|
960
|
-
} else {
|
961
|
-
sink->opened++;
|
962
|
-
}
|
963
|
-
return sink;
|
964
|
-
}
|
965
|
-
|
966
|
-
LogSinkPtr openRemoteSink(const StaticString &unionStationKey, const string &nodeName,
|
967
|
-
const string &category)
|
968
|
-
{
|
969
|
-
size_t cacheKeySize =
|
970
|
-
(sizeof("remote:") - 1) +
|
971
|
-
unionStationKey.size() +
|
972
|
-
1 + // null
|
973
|
-
nodeName.size() +
|
974
|
-
1 + // null
|
975
|
-
category.size();
|
976
|
-
char cacheKey[cacheKeySize];
|
977
|
-
char *pos = cacheKey;
|
978
|
-
const char *end = cacheKey + cacheKeySize;
|
979
|
-
|
980
|
-
pos = appendData(pos, end, P_STATIC_STRING("remote:"));
|
981
|
-
pos = appendData(pos, end, unionStationKey);
|
982
|
-
pos = appendData(pos, end, "\0", 1);
|
983
|
-
pos = appendData(pos, end, nodeName);
|
984
|
-
pos = appendData(pos, end, "\0", 1);
|
985
|
-
pos = appendData(pos, end, category);
|
986
|
-
|
987
|
-
LogSinkPtr sink(logSinkCache.get(StaticString(cacheKey, cacheKeySize)));
|
988
|
-
if (sink == NULL) {
|
989
|
-
sink = boost::make_shared<RemoteSink>(this, unionStationKey,
|
990
|
-
nodeName, category);
|
991
|
-
sink->opened = 1;
|
992
|
-
logSinkCache.set(StaticString(cacheKey, cacheKeySize), sink);
|
993
|
-
} else {
|
994
|
-
sink->opened++;
|
995
|
-
}
|
996
|
-
return sink;
|
997
|
-
}
|
998
|
-
|
999
|
-
/**
|
1000
|
-
* Close the given transaction, potentially flushing its data to a sink.
|
1001
|
-
*/
|
1002
|
-
void closeTransaction(Client *client, const TransactionPtr &transaction) {
|
1003
|
-
if (!transaction->isDiscarded() && passesFilter(transaction)) {
|
1004
|
-
LogSinkPtr logSink;
|
1005
|
-
if (configRlz.devMode) {
|
1006
|
-
logSink = openLogFile(client, transaction->getCategory());
|
1007
|
-
} else {
|
1008
|
-
logSink = openRemoteSink(transaction->getUnionStationKey(),
|
1009
|
-
transaction->getNodeName(), transaction->getCategory());
|
1010
|
-
}
|
1011
|
-
P_DEBUG("Closing transaction " << transaction->getTxnId() <<
|
1012
|
-
": appending " << transaction->getBody().size() << " bytes "
|
1013
|
-
"to sink " << logSink->inspect());
|
1014
|
-
logSink->append(transaction);
|
1015
|
-
closeLogSink(logSink);
|
1016
|
-
}
|
1017
|
-
}
|
1018
|
-
|
1019
|
-
/**
|
1020
|
-
* Decrement the reference count on the given log sink. When the refcount hits 0,
|
1021
|
-
* it's not actually deleted from memory; instead it's cached for later use. A
|
1022
|
-
* garbage collection run periodically cleans up log sinks that have zero
|
1023
|
-
* references.
|
1024
|
-
*/
|
1025
|
-
void closeLogSink(const LogSinkPtr &logSink) {
|
1026
|
-
logSink->opened--;
|
1027
|
-
assert(logSink->opened >= 0);
|
1028
|
-
logSink->lastClosed = ev_now(getLoop());
|
1029
|
-
}
|
1030
|
-
|
1031
|
-
void writeLogEntry(Client *client, const TransactionPtr &transaction,
|
1032
|
-
const StaticString ×tamp, const StaticString &data, bool ack)
|
1033
|
-
{
|
1034
|
-
if (transaction->isDiscarded()) {
|
1035
|
-
return;
|
1036
|
-
}
|
1037
|
-
if (OXT_UNLIKELY(!validLogContent(data))) {
|
1038
|
-
SKC_ERROR(client, "Log entry data contains an invalid character");
|
1039
|
-
if (ack && client != NULL) {
|
1040
|
-
sendErrorToClient(client, "Log entry data contains an invalid character");
|
1041
|
-
disconnect(&client);
|
1042
|
-
}
|
1043
|
-
return;
|
1044
|
-
}
|
1045
|
-
if (OXT_UNLIKELY(!validTimestamp(timestamp))) {
|
1046
|
-
SKC_ERROR(client, "Log entry timestamp is invalid");
|
1047
|
-
if (ack && client != NULL) {
|
1048
|
-
sendErrorToClient(client, "Log entry timestamp is invalid");
|
1049
|
-
disconnect(&client);
|
1050
|
-
}
|
1051
|
-
return;
|
1052
|
-
}
|
1053
|
-
|
1054
|
-
transaction->append(timestamp, data);
|
1055
|
-
}
|
1056
|
-
|
1057
|
-
void writeDetachEntry(Client *client, const TransactionPtr &transaction, bool ack) {
|
1058
|
-
char timestamp[2 * sizeof(unsigned long long) + 1];
|
1059
|
-
// Must use System::getUsec() here instead of ev_now() because the
|
1060
|
-
// precision of the time is very important.
|
1061
|
-
unsigned int size = integerToHexatri<unsigned long long>(
|
1062
|
-
SystemTime::getUsec(), timestamp);
|
1063
|
-
writeDetachEntry(client, transaction, StaticString(timestamp, size), ack);
|
1064
|
-
}
|
1065
|
-
|
1066
|
-
void writeDetachEntry(Client *client, const TransactionPtr &transaction,
|
1067
|
-
const StaticString ×tamp, bool ack)
|
1068
|
-
{
|
1069
|
-
writeLogEntry(client, transaction, timestamp, P_STATIC_STRING("DETACH"), ack);
|
1070
|
-
}
|
1071
|
-
|
1072
|
-
bool passesFilter(const TransactionPtr &transaction) {
|
1073
|
-
StaticString filters(transaction->getFilters());
|
1074
|
-
if (filters.empty()) {
|
1075
|
-
return true;
|
1076
|
-
}
|
1077
|
-
|
1078
|
-
StaticString body = transaction->getBody();
|
1079
|
-
const char *current = filters.data();
|
1080
|
-
const char *end = filters.data() + filters.size();
|
1081
|
-
bool result = true;
|
1082
|
-
FilterSupport::ContextFromLog ctx(body);
|
1083
|
-
|
1084
|
-
// 'filters' may contain multiple filter sources, separated
|
1085
|
-
// by '\1' characters. Process each.
|
1086
|
-
while (current < end && result) {
|
1087
|
-
StaticString tmp(current, end - current);
|
1088
|
-
size_t pos = tmp.find('\1');
|
1089
|
-
if (pos == string::npos) {
|
1090
|
-
pos = tmp.size();
|
1091
|
-
}
|
1092
|
-
|
1093
|
-
StaticString source(current, pos);
|
1094
|
-
FilterSupport::Filter &filter = compileFilter(source);
|
1095
|
-
result = filter.run(ctx);
|
1096
|
-
|
1097
|
-
current = tmp.data() + pos + 1;
|
1098
|
-
}
|
1099
|
-
return result;
|
1100
|
-
}
|
1101
|
-
|
1102
|
-
FilterSupport::Filter &compileFilter(const StaticString &source) {
|
1103
|
-
// TODO: garbage collect filters based on time
|
1104
|
-
FilterSupport::FilterPtr filter = filters.get(source);
|
1105
|
-
if (filter == NULL) {
|
1106
|
-
filter = boost::make_shared<FilterSupport::Filter>(source);
|
1107
|
-
filters.set(source, filter);
|
1108
|
-
}
|
1109
|
-
return *filter;
|
1110
|
-
}
|
1111
|
-
|
1112
|
-
protected:
|
1113
|
-
virtual void reinitializeClient(Client *client, int fd) {
|
1114
|
-
ParentClass::reinitializeClient(client, fd);
|
1115
|
-
client->arrayReader.setMaxSize(1024 * 16);
|
1116
|
-
client->scalarReader.setMaxSize(1024 * 1024);
|
1117
|
-
client->state = Client::READING_AUTH_USERNAME;
|
1118
|
-
client->type = Client::UNINITIALIZED;
|
1119
|
-
}
|
1120
|
-
|
1121
|
-
virtual void deinitializeClient(Client *client) {
|
1122
|
-
client->arrayReader.reset();
|
1123
|
-
client->scalarReader.reset();
|
1124
|
-
client->nodeName.clear();
|
1125
|
-
|
1126
|
-
set<string>::const_iterator s_it;
|
1127
|
-
set<string>::const_iterator s_end = client->openTransactions.end();
|
1128
|
-
|
1129
|
-
// Close any transactions that this client had opened.
|
1130
|
-
for (s_it = client->openTransactions.begin(); s_it != s_end; s_it++) {
|
1131
|
-
const string &txnId = *s_it;
|
1132
|
-
TransactionPtr transaction = transactions.get(txnId);
|
1133
|
-
if (OXT_UNLIKELY(transaction == NULL)) {
|
1134
|
-
P_BUG("client->openTransactions is not a subset of this->transactions!");
|
1135
|
-
}
|
1136
|
-
|
1137
|
-
if (transaction->crashProtectEnabled()) {
|
1138
|
-
writeDetachEntry(client, transaction, false);
|
1139
|
-
} else {
|
1140
|
-
transaction->discard();
|
1141
|
-
}
|
1142
|
-
transaction->unref();
|
1143
|
-
if (transaction->getRefCount() == 0) {
|
1144
|
-
transactions.remove(transaction->getTxnId());
|
1145
|
-
closeTransaction(client, transaction);
|
1146
|
-
}
|
1147
|
-
}
|
1148
|
-
client->openTransactions.clear();
|
1149
|
-
|
1150
|
-
client->logCommandParams.transaction.reset();
|
1151
|
-
client->logCommandParams.timestamp.clear();
|
1152
|
-
|
1153
|
-
ParentClass::deinitializeClient(client);
|
1154
|
-
}
|
1155
|
-
|
1156
|
-
virtual void onClientAccepted(Client *client) {
|
1157
|
-
beginHandshake(client);
|
1158
|
-
}
|
1159
|
-
|
1160
|
-
virtual Channel::Result onClientDataReceived(Client *client, const MemoryKit::mbuf &buffer,
|
1161
|
-
int errcode)
|
1162
|
-
{
|
1163
|
-
if (buffer.empty()) {
|
1164
|
-
disconnect(&client);
|
1165
|
-
return Channel::Result(0, true);
|
1166
|
-
}
|
1167
|
-
|
1168
|
-
switch (client->state) {
|
1169
|
-
case Client::READING_AUTH_USERNAME:
|
1170
|
-
return onAuthUsernameDataReceived(client, buffer, errcode);
|
1171
|
-
case Client::READING_AUTH_PASSWORD:
|
1172
|
-
return onAuthPasswordDataReceived(client, buffer, errcode);
|
1173
|
-
case Client::READING_MESSAGE:
|
1174
|
-
return onMessageDataReceived(client, buffer, errcode);
|
1175
|
-
case Client::READING_MESSAGE_BODY:
|
1176
|
-
return onMessageBodyDataReceived(client, buffer, errcode);
|
1177
|
-
default:
|
1178
|
-
P_BUG("Unknown state " << client->state);
|
1179
|
-
return Channel::Result(0, false); // Never reached
|
1180
|
-
}
|
1181
|
-
}
|
1182
|
-
|
1183
|
-
virtual void onShutdown(bool forceDisconnect) {
|
1184
|
-
gcTimer.stop();
|
1185
|
-
flushTimer.stop();
|
1186
|
-
ParentClass::onShutdown(forceDisconnect);
|
1187
|
-
}
|
1188
|
-
|
1189
|
-
public:
|
1190
|
-
Controller(ServerKit::Context *context, const Schema &schema,
|
1191
|
-
const Json::Value &initialConfig)
|
1192
|
-
: ServerKit::BaseServer<Controller, Client>(context, schema, initialConfig),
|
1193
|
-
configRlz(config),
|
1194
|
-
remoteSender(
|
1195
|
-
config["union_station_gateway_address"].asString(),
|
1196
|
-
config["union_station_gateway_port"].asUInt(),
|
1197
|
-
config["union_station_gateway_cert"].asString(),
|
1198
|
-
config["union_station_proxy_address"].asString()),
|
1199
|
-
gcTimer(getLoop()),
|
1200
|
-
flushTimer(getLoop())
|
1201
|
-
{
|
1202
|
-
gcTimer.set<Controller, &Controller::garbageCollect>(this);
|
1203
|
-
gcTimer.start(GARBAGE_COLLECTION_TIMEOUT, GARBAGE_COLLECTION_TIMEOUT);
|
1204
|
-
|
1205
|
-
flushTimer.set<Controller, &Controller::flushSomeSinks>(this);
|
1206
|
-
}
|
1207
|
-
|
1208
|
-
virtual StaticString getServerName() const {
|
1209
|
-
return P_STATIC_STRING("UstRouter");
|
1210
|
-
}
|
1211
|
-
|
1212
|
-
virtual unsigned int getClientName(const Client *client, char *buf, size_t size) const {
|
1213
|
-
char *pos = buf;
|
1214
|
-
const char *end = buf + size - 1;
|
1215
|
-
pos = appendData(pos, end, P_STATIC_STRING("UstRtr."));
|
1216
|
-
pos += uintToString(client->number, pos, end - pos);
|
1217
|
-
*pos = '\0';
|
1218
|
-
return pos - buf;
|
1219
|
-
}
|
1220
|
-
|
1221
|
-
bool prepareConfigChange(const Json::Value &updates,
|
1222
|
-
vector<ConfigKit::Error> &errors, ConfigChangeRequest &req)
|
1223
|
-
{
|
1224
|
-
if (ParentClass::prepareConfigChange(updates, errors, req.forParent)) {
|
1225
|
-
req.configRlz.reset(new ConfigRealization(*req.forParent.config));
|
1226
|
-
}
|
1227
|
-
return errors.empty();
|
1228
|
-
}
|
1229
|
-
|
1230
|
-
void commitConfigChange(ConfigChangeRequest &req)
|
1231
|
-
BOOST_NOEXCEPT_OR_NOTHROW
|
1232
|
-
{
|
1233
|
-
ParentClass::commitConfigChange(req.forParent);
|
1234
|
-
configRlz.swap(*req.configRlz);
|
1235
|
-
|
1236
|
-
flushTimer.stop();
|
1237
|
-
flushTimer.start(configRlz.sinkFlushTimerInterval,
|
1238
|
-
configRlz.sinkFlushTimerInterval);
|
1239
|
-
}
|
1240
|
-
|
1241
|
-
virtual Json::Value inspectStateAsJson() const {
|
1242
|
-
Json::Value doc = ParentClass::inspectStateAsJson();
|
1243
|
-
doc["dev_mode"] = configRlz.devMode;
|
1244
|
-
doc["log_sink_cache"] = inspectLogSinkCacheStateAsJson();
|
1245
|
-
doc["transactions"] = inspectTransactionsStateAsJson();
|
1246
|
-
if (configRlz.devMode) {
|
1247
|
-
doc["dump_dir"] = config["ust_router_dump_dir"];
|
1248
|
-
} else {
|
1249
|
-
doc["remote_sender"] = remoteSender.inspectStateAsJson();
|
1250
|
-
}
|
1251
|
-
doc["default_node_name"] = config["ust_router_default_node_name"];
|
1252
|
-
return doc;
|
1253
|
-
}
|
1254
|
-
|
1255
|
-
virtual Json::Value inspectClientStateAsJson(const Client *client) const {
|
1256
|
-
Json::Value doc = ParentClass::inspectClientStateAsJson(client);
|
1257
|
-
doc["state"] = client->getStateName();
|
1258
|
-
doc["type"] = client->getTypeName();
|
1259
|
-
doc["node_name"] = client->nodeName;
|
1260
|
-
doc["open_transactions_count"] = Json::UInt(client->openTransactions.size());
|
1261
|
-
|
1262
|
-
Json::Value openTransactions(Json::arrayValue);
|
1263
|
-
foreach (string txnId, client->openTransactions) {
|
1264
|
-
openTransactions.append(txnId);
|
1265
|
-
}
|
1266
|
-
doc["open_transactions"] = openTransactions;
|
1267
|
-
|
1268
|
-
return doc;
|
1269
|
-
}
|
1270
|
-
|
1271
|
-
Json::Value inspectLogSinkCacheStateAsJson() const {
|
1272
|
-
Json::Value doc(Json::objectValue);
|
1273
|
-
LogSinkCache::const_iterator it;
|
1274
|
-
LogSinkCache::const_iterator end = logSinkCache.end();
|
1275
|
-
for (it = logSinkCache.begin(); it != end; it++) {
|
1276
|
-
const LogSinkPtr &logSink = it->second;
|
1277
|
-
doc[createJsonKey(it->first)] = logSink->inspectStateAsJson();
|
1278
|
-
}
|
1279
|
-
return doc;
|
1280
|
-
}
|
1281
|
-
|
1282
|
-
Json::Value inspectTransactionsStateAsJson() const {
|
1283
|
-
Json::Value doc(Json::objectValue);
|
1284
|
-
TransactionMap::const_iterator it;
|
1285
|
-
TransactionMap::const_iterator end = transactions.end();
|
1286
|
-
for (it = transactions.begin(); it != end; it++) {
|
1287
|
-
const TransactionPtr &transaction = it->second;
|
1288
|
-
doc[it->first.toString()] = transaction->inspectStateAsJson();
|
1289
|
-
}
|
1290
|
-
return doc;
|
1291
|
-
}
|
1292
|
-
};
|
1293
|
-
|
1294
|
-
|
1295
|
-
inline struct ev_loop *
|
1296
|
-
Controller_getLoop(Controller *controller) {
|
1297
|
-
return controller->getLoop();
|
1298
|
-
}
|
1299
|
-
|
1300
|
-
inline RemoteSender &
|
1301
|
-
Controller_getRemoteSender(Controller *controller) {
|
1302
|
-
return controller->remoteSender;
|
1303
|
-
}
|
1304
|
-
|
1305
|
-
|
1306
|
-
} // namespace UstRouter
|
1307
|
-
} // namespace Passenger
|
1308
|
-
|
1309
|
-
#endif /* _PASSENGER_UST_ROUTER_CONTROLLER_H_ */
|