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.

Files changed (200) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +18 -0
  3. data/Rakefile +20 -17
  4. data/bin/passenger-install-apache2-module +14 -11
  5. data/build/agent.rb +45 -18
  6. data/build/apache2.rb +32 -16
  7. data/build/basics.rb +29 -40
  8. data/build/common_library.rb +70 -54
  9. data/build/cxx_tests.rb +34 -43
  10. data/build/integration_tests.rb +10 -10
  11. data/build/misc.rb +6 -6
  12. data/build/node_tests.rb +1 -2
  13. data/build/oxt_tests.rb +7 -5
  14. data/build/packaging.rb +11 -441
  15. data/build/ruby_extension.rb +1 -1
  16. data/build/ruby_tests.rb +1 -2
  17. data/build/support/cplusplus.rb +6 -5
  18. data/build/support/cxx_dependency_map.rb +357 -833
  19. data/build/support/general.rb +23 -1
  20. data/build/test_basics.rb +3 -28
  21. data/dev/ci/tests/rpm/Jenkinsfile +68 -0
  22. data/dev/ci/tests/rpm/run +63 -0
  23. data/dev/ci/tests/source-packaging/run +1 -1
  24. data/dev/ci/tests/source-packaging/setup +1 -1
  25. data/doc/{Packaging.txt.md → Packaging.md} +0 -0
  26. data/resources/templates/apache2/deployment_example.txt.erb +2 -2
  27. data/resources/templates/apache2/multiple_apache_installations_detected.txt.erb +2 -2
  28. data/resources/templates/nginx/deployment_example.txt.erb +1 -1
  29. data/resources/templates/standalone/mass_deployment_default_server.erb +2 -2
  30. data/resources/templates/standalone/server.erb +2 -2
  31. data/src/agent/AgentMain.cpp +0 -4
  32. data/src/agent/Core/CoreMain.cpp +88 -5
  33. data/src/agent/Core/SpawningKit/Spawner.h +2 -1
  34. data/src/agent/Shared/Fundamentals/AbortHandler.cpp +1109 -0
  35. data/src/agent/Shared/Fundamentals/AbortHandler.h +63 -0
  36. data/src/agent/Shared/Fundamentals/Implementation.cpp +7 -0
  37. data/src/agent/Shared/Fundamentals/Initialization.cpp +614 -0
  38. data/src/agent/Shared/{Base.h → Fundamentals/Initialization.h} +23 -14
  39. data/src/agent/Shared/Fundamentals/Utils.cpp +127 -0
  40. data/src/agent/Shared/Fundamentals/Utils.h +46 -0
  41. data/src/agent/TempDirToucher/TempDirToucherMain.cpp +1 -1
  42. data/src/agent/Watchdog/CoreWatcher.cpp +3 -1
  43. data/src/agent/Watchdog/InstanceDirToucher.cpp +90 -53
  44. data/src/agent/Watchdog/WatchdogMain.cpp +13 -29
  45. data/src/apache2_module/Hooks.cpp +4 -1
  46. data/src/cxx_supportlib/ConfigKit/Store.h +32 -5
  47. data/src/cxx_supportlib/Constants.h +1 -2
  48. data/src/cxx_supportlib/Crypto.cpp +2 -1
  49. data/src/cxx_supportlib/Hooks.h +16 -37
  50. data/src/cxx_supportlib/LoggingKit/Context.h +22 -0
  51. data/src/cxx_supportlib/LoggingKit/Forward.h +1 -0
  52. data/src/cxx_supportlib/LoggingKit/Implementation.cpp +106 -22
  53. data/src/cxx_supportlib/ProcessManagement/Ruby.cpp +106 -0
  54. data/src/{agent/UstRouter/FileSink.h → cxx_supportlib/ProcessManagement/Ruby.h} +23 -47
  55. data/src/cxx_supportlib/ProcessManagement/Spawn.cpp +199 -0
  56. data/src/cxx_supportlib/ProcessManagement/Spawn.h +150 -0
  57. data/src/cxx_supportlib/ProcessManagement/Utils.cpp +459 -0
  58. data/src/cxx_supportlib/ProcessManagement/Utils.h +107 -0
  59. data/src/cxx_supportlib/Utils.cpp +41 -561
  60. data/src/cxx_supportlib/Utils.h +0 -68
  61. data/src/cxx_supportlib/Utils/AsyncSignalSafeUtils.h +187 -0
  62. data/src/cxx_supportlib/Utils/ProcessMetricsCollector.h +14 -2
  63. data/src/cxx_supportlib/WatchdogLauncher.h +2 -12
  64. data/src/cxx_supportlib/oxt/dynamic_thread_group.hpp +2 -2
  65. data/src/cxx_supportlib/vendor-modified/jsoncpp/json-forwards.h +4 -0
  66. data/src/cxx_supportlib/vendor-modified/jsoncpp/json.h +16 -1
  67. data/src/cxx_supportlib/vendor-modified/jsoncpp/jsoncpp.cpp +12 -9
  68. data/src/cxx_supportlib/vendor-modified/libev/ev++.h +4 -4
  69. data/src/cxx_supportlib/vendor-modified/libev/ev.h +3 -3
  70. data/src/nginx_module/CacheLocationConfig.c +0 -75
  71. data/src/nginx_module/CacheLocationConfig.c.cxxcodebuilder +1 -0
  72. data/src/nginx_module/Configuration.c +0 -1
  73. data/src/nginx_module/Configuration.h +0 -1
  74. data/src/nginx_module/ConfigurationCommands.c +1 -1
  75. data/src/nginx_module/ContentHandler.c +0 -1
  76. data/src/nginx_module/ContentHandler.h +0 -1
  77. data/src/nginx_module/CreateLocationConfig.c +0 -5
  78. data/src/nginx_module/CreateLocationConfig.c.cxxcodebuilder +1 -0
  79. data/src/nginx_module/LocationConfig.h +0 -4
  80. data/src/nginx_module/LocationConfig.h.cxxcodebuilder +2 -1
  81. data/src/nginx_module/MergeLocationConfig.c +0 -12
  82. data/src/nginx_module/MergeLocationConfig.c.cxxcodebuilder +1 -0
  83. data/src/nginx_module/ngx_http_passenger_module.h +0 -1
  84. data/src/ruby_supportlib/phusion_passenger.rb +1 -1
  85. data/src/ruby_supportlib/phusion_passenger/common_library.rb +20 -11
  86. data/src/ruby_supportlib/phusion_passenger/config/api_call_command.rb +1 -1
  87. data/src/ruby_supportlib/phusion_passenger/config/reopen_logs_command.rb +0 -1
  88. data/src/ruby_supportlib/phusion_passenger/config/validate_install_command.rb +10 -3
  89. data/src/ruby_supportlib/phusion_passenger/console_text_template.rb +3 -1
  90. data/src/ruby_supportlib/phusion_passenger/constants.rb +0 -1
  91. data/src/ruby_supportlib/phusion_passenger/debug_logging.rb +1 -1
  92. data/src/ruby_supportlib/phusion_passenger/loader_shared_helpers.rb +32 -6
  93. data/src/ruby_supportlib/phusion_passenger/nginx/config_options.rb +0 -1
  94. data/src/ruby_supportlib/phusion_passenger/packaging.rb +2 -4
  95. data/src/ruby_supportlib/phusion_passenger/platform_info/apache.rb +101 -20
  96. data/src/ruby_supportlib/phusion_passenger/platform_info/apache_detector.rb +21 -9
  97. data/src/ruby_supportlib/phusion_passenger/platform_info/compiler.rb +34 -31
  98. data/src/ruby_supportlib/phusion_passenger/platform_info/cxx_portability.rb +3 -1
  99. data/src/ruby_supportlib/phusion_passenger/platform_info/depcheck_specs/apache2.rb +2 -14
  100. data/src/ruby_supportlib/phusion_passenger/platform_info/operating_system.rb +40 -3
  101. data/src/ruby_supportlib/phusion_passenger/standalone/app_finder.rb +15 -14
  102. data/src/ruby_supportlib/phusion_passenger/standalone/config_options_list.rb +1 -1
  103. data/src/ruby_supportlib/phusion_passenger/standalone/config_utils.rb +1 -1
  104. data/src/ruby_supportlib/phusion_passenger/standalone/start_command.rb +8 -3
  105. data/src/ruby_supportlib/phusion_passenger/standalone/start_command/nginx_engine.rb +19 -18
  106. data/src/ruby_supportlib/phusion_passenger/standalone/stop_command.rb +6 -1
  107. data/src/ruby_supportlib/phusion_passenger/vendor/daemon_controller.rb +17 -1
  108. metadata +19 -97
  109. data/build/documentation.rb +0 -70
  110. data/doc/CloudLicensingConfiguration.html +0 -172
  111. data/doc/CloudLicensingConfiguration.txt.md +0 -3
  112. data/doc/Packaging.html +0 -488
  113. data/doc/Security of user switching support.idmap.txt +0 -34
  114. data/doc/Security of user switching support.txt +0 -197
  115. data/doc/ServerOptimizationGuide.html +0 -172
  116. data/doc/ServerOptimizationGuide.txt.md +0 -3
  117. data/doc/images/by_sa.png +0 -0
  118. data/doc/images/cloud_licensing_batch_job.png +0 -0
  119. data/doc/images/code_walkthrough.jpg +0 -0
  120. data/doc/images/direct_spawning.png +0 -0
  121. data/doc/images/direct_spawning.svg +0 -251
  122. data/doc/images/glyphicons-halflings-white.png +0 -0
  123. data/doc/images/glyphicons-halflings.png +0 -0
  124. data/doc/images/icons/README +0 -5
  125. data/doc/images/icons/callouts/1.png +0 -0
  126. data/doc/images/icons/callouts/10.png +0 -0
  127. data/doc/images/icons/callouts/11.png +0 -0
  128. data/doc/images/icons/callouts/12.png +0 -0
  129. data/doc/images/icons/callouts/13.png +0 -0
  130. data/doc/images/icons/callouts/14.png +0 -0
  131. data/doc/images/icons/callouts/15.png +0 -0
  132. data/doc/images/icons/callouts/2.png +0 -0
  133. data/doc/images/icons/callouts/3.png +0 -0
  134. data/doc/images/icons/callouts/4.png +0 -0
  135. data/doc/images/icons/callouts/5.png +0 -0
  136. data/doc/images/icons/callouts/6.png +0 -0
  137. data/doc/images/icons/callouts/7.png +0 -0
  138. data/doc/images/icons/callouts/8.png +0 -0
  139. data/doc/images/icons/callouts/9.png +0 -0
  140. data/doc/images/icons/caution.png +0 -0
  141. data/doc/images/icons/example.png +0 -0
  142. data/doc/images/icons/home.png +0 -0
  143. data/doc/images/icons/important.png +0 -0
  144. data/doc/images/icons/next.png +0 -0
  145. data/doc/images/icons/note.png +0 -0
  146. data/doc/images/icons/prev.png +0 -0
  147. data/doc/images/icons/tip.png +0 -0
  148. data/doc/images/icons/up.png +0 -0
  149. data/doc/images/icons/warning.png +0 -0
  150. data/doc/images/many_web_framework_protocols.png +0 -0
  151. data/doc/images/passenger_architecture.png +0 -0
  152. data/doc/images/passenger_architecture.svg +0 -385
  153. data/doc/images/passenger_architecture_overview.png +0 -0
  154. data/doc/images/passenger_core_architecture.png +0 -0
  155. data/doc/images/passenger_nodejs_architecture.svg +0 -558
  156. data/doc/images/phusion_banner.png +0 -0
  157. data/doc/images/rack.png +0 -0
  158. data/doc/images/smart_spawning.png +0 -0
  159. data/doc/images/smart_spawning.svg +0 -323
  160. data/doc/images/spawn_server_architecture.png +0 -0
  161. data/doc/images/spawn_server_architecture.svg +0 -655
  162. data/doc/images/spawning_preparation_work.png +0 -0
  163. data/doc/images/startup_sequence.png +0 -0
  164. data/doc/images/typical_isolated_web_application.png +0 -0
  165. data/doc/images/typical_isolated_web_application.svg +0 -213
  166. data/doc/users_guide_snippets/alternative_for_flying_passenger.txt +0 -1
  167. data/doc/users_guide_snippets/analysis_and_system_maintenance.txt +0 -61
  168. data/doc/users_guide_snippets/appendix_a_about.txt +0 -13
  169. data/doc/users_guide_snippets/appendix_b_terminology.txt +0 -71
  170. data/doc/users_guide_snippets/appendix_c_spawning_methods.txt +0 -36
  171. data/doc/users_guide_snippets/deployment_basics.txt +0 -37
  172. data/doc/users_guide_snippets/enterprise_only.txt +0 -1
  173. data/doc/users_guide_snippets/environment_variables.txt +0 -44
  174. data/doc/users_guide_snippets/global_queueing_explained.txt +0 -74
  175. data/doc/users_guide_snippets/installation.txt +0 -228
  176. data/doc/users_guide_snippets/installation/run_installer.txt +0 -58
  177. data/doc/users_guide_snippets/installation/verify_running_epilogue.txt +0 -6
  178. data/doc/users_guide_snippets/passenger_spawn_method.txt +0 -37
  179. data/doc/users_guide_snippets/rackup_specifications.txt +0 -1
  180. data/doc/users_guide_snippets/rvm_helper_tool.txt +0 -44
  181. data/doc/users_guide_snippets/since_version.txt +0 -1
  182. data/doc/users_guide_snippets/support_information.txt +0 -8
  183. data/doc/users_guide_snippets/tips.txt +0 -302
  184. data/doc/users_guide_snippets/troubleshooting/default.txt +0 -48
  185. data/doc/users_guide_snippets/troubleshooting/rails.txt +0 -59
  186. data/doc/users_guide_snippets/under_the_hood/page_caching_support.txt +0 -24
  187. data/doc/users_guide_snippets/under_the_hood/relationship_with_ruby.txt +0 -10
  188. data/doc/users_guide_snippets/where_to_get_support.txt +0 -9
  189. data/src/agent/Shared/Base.cpp +0 -1678
  190. data/src/agent/UstRouter/ApiServer.h +0 -292
  191. data/src/agent/UstRouter/Client.h +0 -112
  192. data/src/agent/UstRouter/Controller.h +0 -1309
  193. data/src/agent/UstRouter/LogSink.h +0 -145
  194. data/src/agent/UstRouter/OptionParser.h +0 -180
  195. data/src/agent/UstRouter/RemoteSender.h +0 -853
  196. data/src/agent/UstRouter/RemoteSink.h +0 -145
  197. data/src/agent/UstRouter/Transaction.h +0 -278
  198. data/src/agent/UstRouter/UstRouterMain.cpp +0 -681
  199. data/src/agent/Watchdog/UstRouterWatcher.cpp +0 -80
  200. 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 &timestamp) 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 &timestamp, 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 &timestamp, 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_ */