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,145 +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_LOG_SINK_H_
27
- #define _PASSENGER_UST_ROUTER_LOG_SINK_H_
28
-
29
- #include <boost/shared_ptr.hpp>
30
- #include <cstddef>
31
- #include <cassert>
32
- #include <ev++.h>
33
- #include <jsoncpp/json.h>
34
- #include <Utils/JsonUtils.h>
35
-
36
- namespace Passenger {
37
- namespace UstRouter {
38
-
39
- using namespace std;
40
- using namespace boost;
41
-
42
-
43
- class Controller;
44
- inline struct ev_loop *Controller_getLoop(Controller *controller);
45
-
46
-
47
- class LogSink {
48
- public:
49
- Controller *controller;
50
-
51
- /**
52
- * Marks how many times this LogSink is currently opened, i.e. the
53
- * number of Transaction objects currently referencing this LogSink.
54
- * Only when this value is 0 is this LogSink eligible for garbage
55
- * collection.
56
- */
57
- int opened;
58
-
59
- /**
60
- * Last time append() was called. This may be 0, meaning that
61
- * append() has never been called before.
62
- */
63
- ev_tstamp lastWrittenTo;
64
-
65
- /**
66
- * Last time the reference count on this log sink was decremented.
67
- * A value of 0 means that this LogSink is new and the reference
68
- * count has never been decremented before. Such LogSinks are not
69
- * eligible for garbage collection.
70
- */
71
- ev_tstamp lastClosed;
72
-
73
- /**
74
- * Last time data was actually written to the underlying storage device.
75
- * This may be 0, meaning that the data has never been flushed before.
76
- */
77
- ev_tstamp lastFlushed;
78
-
79
- /**
80
- * The amount of data that has been written to this sink so far.
81
- */
82
- size_t totalBytesWritten;
83
-
84
- LogSink(Controller *_controller)
85
- : controller(_controller),
86
- opened(0),
87
- lastWrittenTo(0),
88
- lastClosed(0),
89
- lastFlushed(0),
90
- totalBytesWritten(0)
91
- { }
92
-
93
- virtual ~LogSink() {
94
- // Subclasses should flush any data in their destructors.
95
- // We cannot call flush() here because it is not allowed
96
- // to call virtual functions in a destructor.
97
- }
98
-
99
- virtual bool isRemote() const {
100
- return false;
101
- }
102
-
103
- virtual void append(const TransactionPtr &transaction) {
104
- assert(!transaction->isDiscarded());
105
- lastWrittenTo = ev_now(Controller_getLoop(controller));
106
- totalBytesWritten += transaction->getBody().size();
107
- }
108
-
109
- virtual bool flush() {
110
- lastFlushed = ev_now(Controller_getLoop(controller));
111
- return true;
112
- }
113
-
114
- virtual Json::Value inspectStateAsJson() const {
115
- Json::Value doc;
116
- doc["opened"] = opened;
117
- if (lastWrittenTo == 0) {
118
- doc["last_written_to"] = Json::Value(Json::nullValue);
119
- } else {
120
- doc["last_written_to"] = timeToJson(lastWrittenTo * 1000000.0);
121
- }
122
- if (lastClosed == 0) {
123
- doc["last_closed"] = Json::Value(Json::nullValue);
124
- } else {
125
- doc["last_closed"] = timeToJson(lastClosed * 1000000.0);
126
- }
127
- if (lastFlushed == 0) {
128
- doc["last_flushed"] = Json::Value(Json::nullValue);
129
- } else {
130
- doc["last_flushed"] = timeToJson(lastFlushed * 1000000.0);
131
- }
132
- doc["total_bytes_written"] = byteSizeToJson(totalBytesWritten);
133
- return doc;
134
- }
135
-
136
- virtual string inspect() const = 0;
137
- };
138
-
139
- typedef boost::shared_ptr<LogSink> LogSinkPtr;
140
-
141
-
142
- } // namespace UstRouter
143
- } // namespace Passenger
144
-
145
- #endif /* _PASSENGER_UST_ROUTER_LOG_SINK_H_ */
@@ -1,180 +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_OPTION_PARSER_H_
27
- #define _PASSENGER_UST_ROUTER_OPTION_PARSER_H_
28
-
29
- #include <cstdio>
30
- #include <cstdlib>
31
- #include <Constants.h>
32
- #include <Utils.h>
33
- #include <Utils/VariantMap.h>
34
- #include <Utils/OptionParsing.h>
35
- #include <Utils/StrIntUtils.h>
36
-
37
- namespace Passenger {
38
-
39
- using namespace std;
40
-
41
-
42
- inline void
43
- ustRouterUsage() {
44
- printf("Usage: " AGENT_EXE " ust-router <OPTIONS...>\n");
45
- printf("Runs the " PROGRAM_NAME " UstRouter.\n");
46
- printf("\n");
47
- printf("Required options:\n");
48
- printf(" --passenger-root PATH The location to the " PROGRAM_NAME " source\n");
49
- printf(" directory\n");
50
- printf(" --password-file PATH Protect the UstRouter controller with the password in\n");
51
- printf(" this file\n");
52
- printf("\n");
53
- printf("Socket options (optional):\n");
54
- printf(" -l, --listen ADDRESS Listen on the given address. The address must be\n");
55
- printf(" formatted as tcp://IP:PORT for TCP sockets, or\n");
56
- printf(" unix:PATH for Unix domain sockets.\n");
57
- printf(" " DEFAULT_UST_ROUTER_LISTEN_ADDRESS "\n");
58
- printf("\n");
59
- printf(" --api-listen ADDRESS Listen on the given address for API commands.\n");
60
- printf(" The address must be in the same format as that\n");
61
- printf(" of --listen\n");
62
- printf(" --authorize [LEVEL]:USERNAME:PASSWORDFILE\n");
63
- printf(" Enables authentication on the API server,\n");
64
- printf(" through the given API account. LEVEL indicates\n");
65
- printf(" the privilege level (see below). PASSWORDFILE must\n");
66
- printf(" point to a file containing the password\n");
67
- printf("\n");
68
- printf("Operational options (optional):\n");
69
- printf(" --dev-mode Enable development mode: dump data to a directory\n");
70
- printf(" instead of sending them to the Union Station gateway\n");
71
- printf(" --dump-dir PATH Directory to dump to\n");
72
- printf("\n");
73
- printf("Other options (optional):\n");
74
- printf(" --user USERNAME Lower privilege to the given user. Only has\n");
75
- printf(" effect when started as root\n");
76
- printf(" --group GROUPNAME Lower privilege to the given group. Only has\n");
77
- printf(" effect when started as root. Default: primary\n");
78
- printf(" group of the username given by '--user'\n");
79
- printf("\n");
80
- printf(" --log-file PATH Log to the given file.\n");
81
- printf(" --log-level LEVEL Logging level. Default: %d\n", DEFAULT_LOG_LEVEL);
82
- printf("\n");
83
- printf(" --core-file-descriptor-ulimit NUMBER\n");
84
- printf(" Set custom file descriptor ulimit for the core\n");
85
- printf("\n");
86
- printf(" -h, --help Show this help\n");
87
- printf("\n");
88
- printf("API account privilege levels (ordered from most to least privileges):\n");
89
- printf(" readonly Read-only access\n");
90
- printf(" full Full access (default)\n");
91
- }
92
-
93
- inline bool
94
- parseUstRouterOption(int argc, const char *argv[], int &i, VariantMap &options) {
95
- OptionParser p(ustRouterUsage);
96
-
97
- if (p.isValueFlag(argc, i, argv[i], '\0', "--passenger-root")) {
98
- options.set("passenger_root", argv[i + 1]);
99
- i += 2;
100
- } else if (p.isValueFlag(argc, i, argv[i], '\0', "--password-file")) {
101
- options.set("ust_router_password_file", argv[i + 1]);
102
- i += 2;
103
- } else if (p.isValueFlag(argc, i, argv[i], 'l', "--listen")) {
104
- if (getSocketAddressType(argv[i + 1]) != SAT_UNKNOWN) {
105
- options.set("ust_router_address", argv[i + 1]);
106
- i += 2;
107
- } else {
108
- fprintf(stderr, "ERROR: invalid address format for --listen. The address "
109
- "must be formatted as tcp://IP:PORT for TCP sockets, or unix:PATH "
110
- "for Unix domain sockets.\n");
111
- exit(1);
112
- }
113
- } else if (p.isValueFlag(argc, i, argv[i], '\0', "--api-listen")) {
114
- if (getSocketAddressType(argv[i + 1]) != SAT_UNKNOWN) {
115
- vector<string> addresses = options.getStrSet("ust_router_api_addresses",
116
- false);
117
- if (addresses.size() == SERVER_KIT_MAX_SERVER_ENDPOINTS) {
118
- fprintf(stderr, "ERROR: you may specify up to %u --api-listen addresses.\n",
119
- SERVER_KIT_MAX_SERVER_ENDPOINTS);
120
- exit(1);
121
- }
122
- addresses.push_back(argv[i + 1]);
123
- options.setStrSet("ust_router_api_addresses", addresses);
124
- i += 2;
125
- } else {
126
- fprintf(stderr, "ERROR: invalid address format for --api-listen. The address "
127
- "must be formatted as tcp://IP:PORT for TCP sockets, or unix:PATH "
128
- "for Unix domain sockets.\n");
129
- exit(1);
130
- }
131
- } else if (p.isValueFlag(argc, i, argv[i], '\0', "--authorize")) {
132
- vector<string> args;
133
- vector<string> authorizations = options.getStrSet("ust_router_authorizations",
134
- false);
135
-
136
- split(argv[i + 1], ':', args);
137
- if (args.size() < 2 || args.size() > 3) {
138
- fprintf(stderr, "ERROR: invalid format for --authorize. The syntax "
139
- "is \"[LEVEL:]USERNAME:PASSWORDFILE\".\n");
140
- exit(1);
141
- }
142
-
143
- authorizations.push_back(argv[i + 1]);
144
- options.setStrSet("ust_router_authorizations", authorizations);
145
- i += 2;
146
- } else if (p.isFlag(argv[i], '\0', "--dev-mode")) {
147
- options.setBool("ust_router_dev_mode", true);
148
- i++;
149
- } else if (p.isValueFlag(argc, i, argv[i], '\0', "--dump-dir")) {
150
- options.set("ust_router_dump_dir", argv[i + 1]);
151
- i += 2;
152
- } else if (p.isValueFlag(argc, i, argv[i], '\0', "--user")) {
153
- options.set("analytics_log_user", argv[i + 1]);
154
- i += 2;
155
- } else if (p.isValueFlag(argc, i, argv[i], '\0', "--group")) {
156
- options.set("analytics_log_group", argv[i + 1]);
157
- i += 2;
158
- } else if (p.isValueFlag(argc, i, argv[i], '\0', "--log-level")) {
159
- // We do not set log_level because, when this function is called from
160
- // the Watchdog, we don't want to affect the Watchdog's own log level.
161
- options.setInt("ust_router_log_level", atoi(argv[i + 1]));
162
- i += 2;
163
- } else if (p.isValueFlag(argc, i, argv[i], '\0', "--log-file")) {
164
- // We do not set debug_log_file because, when this function is called from
165
- // the Watchdog, we don't want to affect the Watchdog's own log file.
166
- options.set("ust_router_log_file", argv[i + 1]);
167
- i += 2;
168
- } else if (p.isValueFlag(argc, i, argv[i], '\0', "--core-file-descriptor-ulimit")) {
169
- options.setUint("core_file_descriptor_ulimit", atoi(argv[i + 1]));
170
- i += 2;
171
- } else {
172
- return false;
173
- }
174
- return true;
175
- }
176
-
177
-
178
- } // namespace Passenger
179
-
180
- #endif /* _PASSENGER_UST_ROUTER_OPTION_PARSER_H_ */
@@ -1,853 +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_REMOTE_SENDER_H_
27
- #define _PASSENGER_REMOTE_SENDER_H_
28
-
29
- #include <sys/types.h>
30
- #include <ctime>
31
- #include <cassert>
32
- #include <curl/curl.h>
33
- #include <zlib.h>
34
-
35
- #include <boost/shared_ptr.hpp>
36
- #include <boost/bind.hpp>
37
- #include <boost/foreach.hpp>
38
- #include <oxt/thread.hpp>
39
- #include <string>
40
- #include <list>
41
- #include <jsoncpp/json.h>
42
- #include <modp_b64.h>
43
-
44
- #include <LoggingKit/LoggingKit.h>
45
- #include <StaticString.h>
46
- #include <Utils.h>
47
- #include <Utils/BlockingQueue.h>
48
- #include <Utils/SystemTime.h>
49
- #include <Utils/ScopeGuard.h>
50
- #include <Utils/JsonUtils.h>
51
- #include <Utils/Curl.h>
52
-
53
- namespace Passenger {
54
-
55
- using namespace std;
56
- using namespace boost;
57
- using namespace oxt;
58
-
59
- #ifdef PASSENGER_IS_ENTERPRISE
60
- #define UST_ROUTER_CLIENT_DESCRIPTION PROGRAM_NAME " Enterprise " PASSENGER_VERSION
61
- #else
62
- #define UST_ROUTER_CLIENT_DESCRIPTION PROGRAM_NAME " " PASSENGER_VERSION
63
- #endif
64
-
65
-
66
- class RemoteSender {
67
- private:
68
- struct Item {
69
- bool exit;
70
- bool compressed;
71
- string unionStationKey;
72
- string nodeName;
73
- string category;
74
- string data;
75
-
76
- Item() {
77
- exit = false;
78
- compressed = false;
79
- }
80
- };
81
-
82
- class Server {
83
- public:
84
- enum SendResult {
85
- /**
86
- * The gateway accepted the packet.
87
- */
88
- SR_OK,
89
-
90
- /**
91
- * Unable to contact the gateway: it appears to be down.
92
- * Unable to obtain a valid HTTP response from the gateway.
93
- */
94
- SR_DOWN,
95
-
96
- /**
97
- * We were able to contact the gateway, but it appears to be
98
- * responding with gibberish. It might be so that the gateway
99
- * machine is up, but the actual service running inside is
100
- * down or malfunctioning.
101
- */
102
- SR_MALFUNCTION,
103
-
104
- /**
105
- * We were able to contact the gateway, but the
106
- * rejected the packet by responding with an error.
107
- */
108
- SR_REJECTED
109
- };
110
-
111
- private:
112
- string ip;
113
- unsigned short port;
114
- string certificate;
115
- const CurlProxyInfo *proxyInfo;
116
-
117
- CURL *curl;
118
- struct curl_slist *headers;
119
- char lastCurlErrorMessage[CURL_ERROR_SIZE];
120
- string hostHeader;
121
- string responseBody;
122
-
123
- string pingURL;
124
- string sinkURL;
125
-
126
- mutable boost::mutex syncher;
127
- string lastErrorMessage;
128
- unsigned long long lastErrorTime;
129
- unsigned long long lastSuccessTime;
130
- unsigned int pingErrors;
131
- unsigned int packetsAccepted;
132
- unsigned int packetsRejected;
133
- unsigned int packetsDropped;
134
-
135
- void resetConnection() {
136
- if (curl != NULL) {
137
- #ifdef HAS_CURL_EASY_RESET
138
- curl_easy_reset(curl);
139
- #else
140
- curl_easy_cleanup(curl);
141
- curl = NULL;
142
- #endif
143
- }
144
- if (curl == NULL) {
145
- curl = curl_easy_init();
146
- if (curl == NULL) {
147
- throw IOException("Unable to create a CURL handle");
148
- }
149
- }
150
- curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
151
- curl_easy_setopt(curl, CURLOPT_TIMEOUT, 180);
152
- curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, lastCurlErrorMessage);
153
- curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
154
- curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curlDataReceived);
155
- curl_easy_setopt(curl, CURLOPT_WRITEDATA, this);
156
- if (certificate.empty()) {
157
- curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0);
158
- } else {
159
- curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1);
160
- curl_easy_setopt(curl, CURLOPT_CAINFO, certificate.c_str());
161
- }
162
- /* No host name verification because Curl thinks the
163
- * host name is the IP address. But if we have the
164
- * certificate then it doesn't matter.
165
- */
166
- curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0);
167
- setCurlProxy(curl, *proxyInfo);
168
- responseBody.clear();
169
- }
170
-
171
- void prepareRequest(const string &url) {
172
- curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
173
- responseBody.clear();
174
- }
175
-
176
- static bool validateResponse(const Json::Value &response) {
177
- if (response.isObject() && response["status"].isString()) {
178
- string status = response["status"].asString();
179
- if (status == "ok") {
180
- return true;
181
- } else if (status == "error") {
182
- return response["message"].isString();
183
- } else {
184
- return false;
185
- }
186
- } else {
187
- return false;
188
- }
189
- }
190
-
191
- SendResult handleSendResponse(const Item &item) {
192
- Json::Reader reader;
193
- Json::Value response;
194
- long httpCode = -1;
195
-
196
- curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &httpCode);
197
-
198
- if (!reader.parse(responseBody, response, false) || !validateResponse(response)) {
199
- setRequestError(
200
- "The Union Station gateway server " + ip +
201
- " encountered an error while processing sent analytics data. "
202
- "It sent an invalid response. Key: " + item.unionStationKey
203
- + ". Parse error: " + reader.getFormattedErrorMessages()
204
- + "; HTTP code: " + toString(httpCode)
205
- + "; data: \"" + cEscapeString(responseBody) + "\"");
206
- return SR_MALFUNCTION;
207
- } else if (response["status"].asString() == "ok") {
208
- if (httpCode == 200) {
209
- handleResponseSuccess();
210
- P_DEBUG("The Union Station gateway server " << ip
211
- << " accepted the packet. Key: "
212
- << item.unionStationKey);
213
- return SR_OK;
214
- } else {
215
- setRequestError(
216
- "The Union Station gateway server " + ip
217
- + " encountered an error while processing sent "
218
- "analytics data. It sent an invalid response. Key: "
219
- + item.unionStationKey + ". HTTP code: "
220
- + toString(httpCode) + ". Data: \""
221
- + cEscapeString(responseBody) + "\"");
222
- return SR_MALFUNCTION;
223
- }
224
- } else {
225
- // response == error
226
- setPacketRejectedError(
227
- "The Union Station gateway server "
228
- + ip + " did not accept the sent analytics data. "
229
- "Key: " + item.unionStationKey + ". "
230
- "Error: " + response["message"].asString());
231
- return SR_REJECTED;
232
- }
233
- }
234
-
235
- void handleSendError(const Item &item) {
236
- setRequestError(
237
- "Could not send data to Union Station gateway server " +
238
- ip + ". It might be down. Key: " + item.unionStationKey +
239
- ". Error: " + lastCurlErrorMessage);
240
- }
241
-
242
- void setPingError(const string &message) {
243
- boost::lock_guard<boost::mutex> l(syncher);
244
- P_INFO(message);
245
- setLastErrorMessage(message);
246
- pingErrors++;
247
- }
248
-
249
- /**
250
- * Handles the case when SendResult == SR_DOWN
251
- * or SendResult == SR_MALFUNCTION.
252
- * See SendResult comments for notes.
253
- */
254
- void setRequestError(const string &message) {
255
- boost::lock_guard<boost::mutex> l(syncher);
256
- P_ERROR(message);
257
- setLastErrorMessage(message);
258
- packetsDropped++;
259
- }
260
-
261
- /**
262
- * Handles the case when SendResult == SR_REJECTED.
263
- * See SendResult comments for notes.
264
- */
265
- void setPacketRejectedError(const string &message) {
266
- boost::lock_guard<boost::mutex> l(syncher);
267
- P_ERROR(message);
268
- setLastErrorMessage(message);
269
- packetsRejected++;
270
- }
271
-
272
- void setLastErrorMessage(const string &message) {
273
- lastErrorMessage = message;
274
- lastErrorTime = SystemTime::getUsec();
275
- }
276
-
277
- void handleResponseSuccess() {
278
- boost::lock_guard<boost::mutex> l(syncher);
279
- lastSuccessTime = SystemTime::getUsec();
280
- packetsAccepted++;
281
- }
282
-
283
- static size_t curlDataReceived(void *buffer, size_t size, size_t nmemb, void *userData) {
284
- Server *self = (Server *) userData;
285
- self->responseBody.append((const char *) buffer, size * nmemb);
286
- return size * nmemb;
287
- }
288
-
289
- public:
290
- Server(const string &ip, const string &hostName, unsigned short port,
291
- const string &cert, const CurlProxyInfo *proxyInfo)
292
- {
293
- this->ip = ip;
294
- this->port = port;
295
- this->certificate = cert;
296
- this->proxyInfo = proxyInfo;
297
-
298
- hostHeader = "Host: " + hostName;
299
- headers = NULL;
300
- headers = curl_slist_append(headers, hostHeader.c_str());
301
- if (headers == NULL) {
302
- throw IOException("Unable to create a CURL linked list");
303
- }
304
-
305
- // Older libcurl versions didn't strdup() any option
306
- // strings so we need to keep these in memory.
307
- pingURL = string("https://") + ip + ":" + toString(port) +
308
- "/ping";
309
- sinkURL = string("https://") + ip + ":" + toString(port) +
310
- "/sink";
311
-
312
- curl = NULL;
313
- lastErrorTime = 0;
314
- lastSuccessTime = 0;
315
- pingErrors = 0;
316
- packetsAccepted = 0;
317
- packetsRejected = 0;
318
- packetsDropped = 0;
319
- resetConnection();
320
- }
321
-
322
- ~Server() {
323
- if (curl != NULL) {
324
- curl_easy_cleanup(curl);
325
- }
326
- curl_slist_free_all(headers);
327
- }
328
-
329
- string name() const {
330
- return ip + ":" + toString(port);
331
- }
332
-
333
- bool ping() {
334
- P_INFO("Pinging Union Station gateway " << ip << ":" << port);
335
- ScopeGuard guard(boost::bind(&Server::resetConnection, this));
336
- prepareRequest(pingURL);
337
-
338
- curl_easy_setopt(curl, CURLOPT_HTTPGET, 1);
339
- CURLcode code;
340
- if (CURLE_OK == (code = setCurlDefaultCaInfo(curl))) {
341
- code = curl_easy_perform(curl);
342
- }
343
- if (code != 0) {
344
- setPingError(
345
- "Could not ping Union Station gateway server " +
346
- ip + ": " + lastCurlErrorMessage);
347
- return false;
348
- }
349
- if (responseBody == "pong") {
350
- guard.clear();
351
- return true;
352
- } else {
353
- setPingError(
354
- "Union Station gateway server " + ip +
355
- " returned an unexpected ping message: " +
356
- responseBody);
357
- return false;
358
- }
359
- }
360
-
361
- SendResult send(const Item &item) {
362
- ScopeGuard guard(boost::bind(&Server::resetConnection, this));
363
- prepareRequest(sinkURL);
364
-
365
- struct curl_httppost *post = NULL;
366
- struct curl_httppost *last = NULL;
367
- string base64_data;
368
-
369
- curl_formadd(&post, &last,
370
- CURLFORM_PTRNAME, "key",
371
- CURLFORM_PTRCONTENTS, item.unionStationKey.c_str(),
372
- CURLFORM_CONTENTSLENGTH, (long) item.unionStationKey.size(),
373
- CURLFORM_END);
374
- curl_formadd(&post, &last,
375
- CURLFORM_PTRNAME, "node_name",
376
- CURLFORM_PTRCONTENTS, item.nodeName.c_str(),
377
- CURLFORM_CONTENTSLENGTH, (long) item.nodeName.size(),
378
- CURLFORM_END);
379
- curl_formadd(&post, &last,
380
- CURLFORM_PTRNAME, "category",
381
- CURLFORM_PTRCONTENTS, item.category.c_str(),
382
- CURLFORM_CONTENTSLENGTH, (long) item.category.size(),
383
- CURLFORM_END);
384
- curl_formadd(&post, &last,
385
- CURLFORM_PTRNAME, "client_description",
386
- CURLFORM_PTRCONTENTS, UST_ROUTER_CLIENT_DESCRIPTION,
387
- CURLFORM_CONTENTSLENGTH, (long) sizeof(UST_ROUTER_CLIENT_DESCRIPTION),
388
- CURLFORM_END);
389
- if (item.compressed) {
390
- base64_data = modp::b64_encode(item.data);
391
- curl_formadd(&post, &last,
392
- CURLFORM_PTRNAME, "data",
393
- CURLFORM_PTRCONTENTS, base64_data.data(),
394
- CURLFORM_CONTENTSLENGTH, (long) base64_data.size(),
395
- CURLFORM_END);
396
- curl_formadd(&post, &last,
397
- CURLFORM_PTRNAME, "compressed",
398
- CURLFORM_PTRCONTENTS, "1",
399
- CURLFORM_END);
400
- } else {
401
- curl_formadd(&post, &last,
402
- CURLFORM_PTRNAME, "data",
403
- CURLFORM_PTRCONTENTS, item.data.c_str(),
404
- CURLFORM_CONTENTSLENGTH, (long) item.data.size(),
405
- CURLFORM_END);
406
- }
407
-
408
- curl_easy_setopt(curl, CURLOPT_HTTPGET, 0);
409
- curl_easy_setopt(curl, CURLOPT_HTTPPOST, post);
410
- P_DEBUG("Sending Union Station packet: key=" << item.unionStationKey <<
411
- ", node=" << item.nodeName << ", category=" << item.category <<
412
- ", compressedDataSize=" << item.data.size());
413
- CURLcode code;
414
- if (CURLE_OK == (code = setCurlDefaultCaInfo(curl))) {
415
- code = curl_easy_perform(curl);
416
- }
417
- curl_formfree(post);
418
-
419
- if (code == CURLE_OK) {
420
- guard.clear();
421
- return handleSendResponse(item);
422
- } else {
423
- handleSendError(item);
424
- return SR_DOWN;
425
- }
426
- }
427
-
428
- Json::Value inspectStateAsJson() const {
429
- Json::Value doc, errorDoc;
430
- doc["sink_url"] = sinkURL;
431
- doc["ping_url"] = pingURL;
432
-
433
- boost::lock_guard<boost::mutex> l(syncher);
434
-
435
- if (lastErrorTime == 0) {
436
- doc["last_error_time"] = Json::Value(Json::nullValue);
437
- } else {
438
- doc["last_error_time"] = timeToJson(lastErrorTime);
439
- }
440
- if (!lastErrorMessage.empty()) {
441
- doc["last_error_message"] = lastErrorMessage;
442
- }
443
- if (lastSuccessTime == 0) {
444
- doc["last_success_time"] = Json::Value(Json::nullValue);
445
- } else {
446
- doc["last_success_time"] = timeToJson(lastSuccessTime);
447
- }
448
-
449
- errorDoc["ping_errors"] = pingErrors;
450
- errorDoc["packets_dropped"] = packetsDropped;
451
- errorDoc["packets_rejected"] = packetsRejected;
452
-
453
- doc["errors"] = errorDoc;
454
- doc["packets_accepted"] = packetsAccepted;
455
-
456
- return doc;
457
- }
458
- };
459
-
460
- typedef boost::shared_ptr<Server> ServerPtr;
461
-
462
- string gatewayAddress;
463
- unsigned short gatewayPort;
464
- string certificate;
465
- CurlProxyInfo proxyInfo;
466
- BlockingQueue<Item> queue;
467
- oxt::thread *thr;
468
-
469
- mutable boost::mutex syncher;
470
- list<ServerPtr> upServers;
471
- vector<ServerPtr> downServers;
472
- time_t lastCheckupTime, nextCheckupTime;
473
- string lastDnsErrorMessage;
474
- unsigned int packetsAccepted, packetsRejected, packetsDropped;
475
-
476
- void threadMain() {
477
- ScopeGuard guard(boost::bind(&RemoteSender::freeThreadData, this));
478
-
479
- while (true) {
480
- Item item;
481
- bool hasItem;
482
-
483
- if (firstStarted()) {
484
- item = queue.get();
485
- hasItem = true;
486
- } else {
487
- hasItem = queue.timedGet(item, msecUntilNextCheckup());
488
- }
489
-
490
- if (hasItem) {
491
- if (item.exit) {
492
- return;
493
- } else {
494
- if (timeForCheckup()) {
495
- recheckServers();
496
- }
497
- sendOut(item);
498
- }
499
- } else if (timeForCheckup()) {
500
- recheckServers();
501
- }
502
- }
503
- }
504
-
505
- bool firstStarted() const {
506
- boost::lock_guard<boost::mutex> l(syncher);
507
- return nextCheckupTime == 0;
508
- }
509
-
510
- void recheckServers() {
511
- P_INFO("Rechecking Union Station gateway servers (" << gatewayAddress << ")...");
512
-
513
- vector<string> ips;
514
- vector<string>::const_iterator it;
515
- list<ServerPtr> upServers;
516
- vector<ServerPtr> downServers;
517
-
518
- try {
519
- ips = resolveHostname(gatewayAddress, gatewayPort);
520
- } catch (const tracable_exception &e) {
521
- P_ERROR(e.what());
522
- // DNS errors tend to be temporary, so retry
523
- // after a short timeout.
524
- scheduleNextCheckup(1 * 60);
525
- // Take note of the error, but do not change the server
526
- // list so that the RemoteSender can keep working with
527
- // the last known server list.
528
- boost::lock_guard<boost::mutex> l(syncher);
529
- this->lastCheckupTime = SystemTime::get();
530
- this->lastDnsErrorMessage = e.what();
531
- return;
532
- }
533
-
534
-
535
- P_INFO(ips.size() << " Union Station gateway servers found");
536
-
537
- for (it = ips.begin(); it != ips.end(); it++) {
538
- ServerPtr server = boost::make_shared<Server>(
539
- *it, gatewayAddress, gatewayPort, certificate,
540
- &proxyInfo);
541
- if (server->ping()) {
542
- upServers.push_back(server);
543
- } else {
544
- downServers.push_back(server);
545
- }
546
- }
547
- P_INFO(upServers.size() << " Union Station gateway servers are up");
548
-
549
- if (downServers.empty()) {
550
- if (upServers.empty()) {
551
- // The DNS lookup was successful, but returned no results.
552
- // This is probably some kind of DNS misconfiguration which
553
- // the infrastructure team is working on, so we check back
554
- // in a short while. It may not help because DNS queries are
555
- // cached, but it's better than not trying.
556
- scheduleNextCheckup(1 * 60);
557
- } else {
558
- // If all gateways are healthy then the list of gateways
559
- // is unlikely to change, so schedule the next checkup
560
- // in 3 hours.
561
- scheduleNextCheckup(3 * 60 * 60);
562
- }
563
- } else {
564
- // If some gateways are down then the infrastructure team
565
- // is likely already working on the problem, so we check
566
- // back in 1 minute.
567
- scheduleNextCheckup(1 * 60);
568
- }
569
-
570
- boost::lock_guard<boost::mutex> l(syncher);
571
- this->lastCheckupTime = SystemTime::get();
572
- this->upServers = upServers;
573
- this->downServers = downServers;
574
- this->lastDnsErrorMessage.clear();
575
- }
576
-
577
- void freeThreadData() {
578
- boost::lock_guard<boost::mutex> l(syncher);
579
- // Invoke destructors inside this thread.
580
- upServers.clear();
581
- downServers.clear();
582
- }
583
-
584
- /**
585
- * Schedules the next checkup to be run after the given number
586
- * of seconds, unless there's already a checkup scheduled for
587
- * earlier.
588
- */
589
- void scheduleNextCheckup(unsigned int seconds) {
590
- time_t now = SystemTime::get();
591
- if (now >= nextCheckupTime || (time_t) (now + seconds) < nextCheckupTime) {
592
- nextCheckupTime = now + seconds;
593
- P_DEBUG("Next checkup time in about " << seconds << " seconds");
594
- }
595
- }
596
-
597
- unsigned int msecUntilNextCheckup() const {
598
- boost::lock_guard<boost::mutex> l(syncher);
599
- time_t now = SystemTime::get();
600
- if (now >= nextCheckupTime) {
601
- return 0;
602
- } else {
603
- return (nextCheckupTime - now) * 1000;
604
- }
605
- }
606
-
607
- bool timeForCheckup() const {
608
- boost::lock_guard<boost::mutex> l(syncher);
609
- return SystemTime::get() >= nextCheckupTime;
610
- }
611
-
612
- void sendOut(const Item &item) {
613
- boost::unique_lock<boost::mutex> l(syncher);
614
- bool done = false;
615
- bool accepted = false;
616
- bool rejected = false;
617
- bool upServersEmpty;
618
-
619
- while (!done && !upServers.empty()) {
620
- // Pick first available server and put it on the back of the list
621
- // for round-robin load balancing.
622
- ServerPtr server = upServers.front();
623
-
624
- l.unlock();
625
- Server::SendResult result = server->send(item);
626
- l.lock();
627
-
628
- if (result == Server::SR_OK) {
629
- upServers.pop_front();
630
- upServers.push_back(server);
631
- accepted = true;
632
- done = true;
633
- } else if (result == Server::SR_REJECTED) {
634
- upServers.pop_front();
635
- upServers.push_back(server);
636
- rejected = true;
637
- done = true;
638
- } else {
639
- upServers.pop_front();
640
- downServers.push_back(server);
641
- }
642
- }
643
-
644
- if (!downServers.empty()) {
645
- // If some gateways are down then the infrastructure team
646
- // is likely already working on the problem, so we check
647
- // back in 1 minute.
648
- scheduleNextCheckup(1 * 60);
649
- }
650
-
651
- if (accepted) {
652
- packetsAccepted++;
653
- } else if (rejected) {
654
- packetsRejected++;
655
- } else {
656
- packetsDropped++;
657
- }
658
-
659
- upServersEmpty = upServers.empty();
660
-
661
- l.unlock();
662
-
663
- if (!accepted && !rejected) {
664
- assert(upServersEmpty);
665
- (void) upServersEmpty; // Avoid compiler warning
666
-
667
- /* If all servers went down then all items in the queue will be
668
- * effectively dropped until after the next checkup has detected
669
- * servers that are up.
670
- */
671
- P_WARN("Dropping Union Station packet because no servers are"
672
- " available. Run `passenger-status --show=union_station` to"
673
- " view server status. Details of dropped packet:"
674
- " key=" << item.unionStationKey <<
675
- ", node=" << item.nodeName <<
676
- ", category=" << item.category <<
677
- ", compressedDataSize=" << item.data.size());
678
- }
679
- }
680
-
681
- bool compress(const StaticString data[], unsigned int count, string &output) {
682
- if (count == 0) {
683
- StaticString newdata;
684
- return compress(&newdata, 1, output);
685
- }
686
-
687
- unsigned char out[128 * 1024];
688
- z_stream strm;
689
- int ret, flush;
690
- unsigned int i, have;
691
-
692
- strm.zalloc = Z_NULL;
693
- strm.zfree = Z_NULL;
694
- strm.opaque = Z_NULL;
695
- ret = deflateInit(&strm, Z_DEFAULT_COMPRESSION);
696
- if (ret != Z_OK) {
697
- return false;
698
- }
699
-
700
- for (i = 0; i < count; i++) {
701
- strm.avail_in = data[i].size();
702
- strm.next_in = (unsigned char *) data[i].c_str();
703
- flush = (i == count - 1) ? Z_FINISH : Z_NO_FLUSH;
704
-
705
- do {
706
- strm.avail_out = sizeof(out);
707
- strm.next_out = out;
708
- ret = deflate(&strm, flush);
709
- assert(ret != Z_STREAM_ERROR);
710
- have = sizeof(out) - strm.avail_out;
711
- output.append((const char *) out, have);
712
- } while (strm.avail_out == 0);
713
- assert(strm.avail_in == 0);
714
- }
715
- assert(ret == Z_STREAM_END);
716
-
717
- deflateEnd(&strm);
718
- return true;
719
- }
720
-
721
- Json::Value inspectUpServersStateAsJson() const {
722
- Json::Value doc(Json::arrayValue);
723
- foreach (const ServerPtr server, upServers) {
724
- doc.append(server->inspectStateAsJson());
725
- }
726
- return doc;
727
- }
728
-
729
- Json::Value inspectDownServersStateAsJson() const {
730
- Json::Value doc(Json::arrayValue);
731
- foreach (const ServerPtr server, downServers) {
732
- doc.append(server->inspectStateAsJson());
733
- }
734
- return doc;
735
- }
736
-
737
- public:
738
- RemoteSender(const string &gatewayAddress, unsigned short gatewayPort,
739
- const string &certificate, const string &proxyAddress)
740
- : queue(1024)
741
- {
742
- TRACE_POINT();
743
- this->gatewayAddress = gatewayAddress;
744
- this->gatewayPort = gatewayPort;
745
- this->certificate = certificate;
746
- try {
747
- this->proxyInfo = prepareCurlProxy(proxyAddress);
748
- } catch (const ArgumentException &e) {
749
- throw RuntimeException("Invalid Union Station proxy address \"" +
750
- proxyAddress + "\": " + e.what());
751
- }
752
- lastCheckupTime = 0;
753
- nextCheckupTime = 0;
754
- packetsAccepted = 0;
755
- packetsRejected = 0;
756
- packetsDropped = 0;
757
- thr = new oxt::thread(
758
- boost::bind(&RemoteSender::threadMain, this),
759
- "RemoteSender thread",
760
- 1024 * 512
761
- );
762
- }
763
-
764
- ~RemoteSender() {
765
- Item item;
766
- item.exit = true;
767
- queue.add(item);
768
- /* Wait until the thread sends out all queued items.
769
- * If this cannot be done within a short amount of time,
770
- * e.g. because all servers are down, then we'll get killed
771
- * by the watchdog anyway.
772
- */
773
- thr->join();
774
- delete thr;
775
- }
776
-
777
- void schedule(const string &unionStationKey, const StaticString &nodeName,
778
- const StaticString &category, const StaticString data[],
779
- unsigned int count)
780
- {
781
- Item item;
782
-
783
- item.unionStationKey = unionStationKey;
784
- item.nodeName = nodeName;
785
- item.category = category;
786
-
787
- if (compress(data, count, item.data)) {
788
- item.compressed = true;
789
- } else {
790
- size_t size = 0;
791
- unsigned int i;
792
-
793
- for (i = 0; i < count; i++) {
794
- size += data[i].size();
795
- }
796
- item.data.reserve(size);
797
- for (i = 0; i < count; i++) {
798
- item.data.append(data[i].c_str(), data[i].size());
799
- }
800
- }
801
-
802
- P_DEBUG("Scheduling Union Station packet: key=" << unionStationKey <<
803
- ", node=" << nodeName << ", category=" << category <<
804
- ", compressedDataSize=" << item.data.size());
805
-
806
- if (!queue.tryAdd(item)) {
807
- P_WARN("The Union Station gateway isn't responding quickly enough; dropping packet.");
808
- boost::lock_guard<boost::mutex> l(syncher);
809
- packetsDropped++;
810
- }
811
- }
812
-
813
- unsigned int queued() const {
814
- return queue.size();
815
- }
816
-
817
- Json::Value inspectStateAsJson() const {
818
- Json::Value doc;
819
- boost::lock_guard<boost::mutex> l(syncher);
820
- doc["up_servers"] = inspectUpServersStateAsJson();
821
- doc["down_servers"] = inspectDownServersStateAsJson();
822
- doc["queue_size"] = queue.size();
823
- doc["packets_accepted"] = packetsAccepted;
824
- doc["packets_rejected"] = packetsRejected;
825
- doc["packets_dropped"] = packetsDropped;
826
- if (certificate.empty()) {
827
- doc["certificate"] = Json::nullValue;
828
- } else {
829
- doc["certificate"] = certificate;
830
- }
831
- if (lastCheckupTime == 0) {
832
- doc["last_server_checkup_time"] = Json::Value(Json::nullValue);
833
- doc["last_server_checkup_time_note"] = "not yet started";
834
- } else {
835
- doc["last_server_checkup_time"] = timeToJson(lastCheckupTime * 1000000.0);
836
- }
837
- if (nextCheckupTime == 0) {
838
- doc["next_server_checkup_time"] = Json::Value(Json::nullValue);
839
- doc["next_server_checkup_time_note"] = "not yet scheduled, waiting for first packet";
840
- } else {
841
- doc["next_server_checkup_time"] = timeToJson(nextCheckupTime * 1000000.0);
842
- }
843
- if (!lastDnsErrorMessage.empty()) {
844
- doc["last_dns_error_message"] = lastDnsErrorMessage;
845
- }
846
- return doc;
847
- }
848
- };
849
-
850
-
851
- } // namespace Passenger
852
-
853
- #endif /* _PASSENGER_REMOTE_SENDER_H_ */