passenger 5.1.10 → 5.1.11
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of passenger might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG +18 -0
- data/Rakefile +20 -17
- data/bin/passenger-install-apache2-module +14 -11
- data/build/agent.rb +45 -18
- data/build/apache2.rb +32 -16
- data/build/basics.rb +29 -40
- data/build/common_library.rb +70 -54
- data/build/cxx_tests.rb +34 -43
- data/build/integration_tests.rb +10 -10
- data/build/misc.rb +6 -6
- data/build/node_tests.rb +1 -2
- data/build/oxt_tests.rb +7 -5
- data/build/packaging.rb +11 -441
- data/build/ruby_extension.rb +1 -1
- data/build/ruby_tests.rb +1 -2
- data/build/support/cplusplus.rb +6 -5
- data/build/support/cxx_dependency_map.rb +357 -833
- data/build/support/general.rb +23 -1
- data/build/test_basics.rb +3 -28
- data/dev/ci/tests/rpm/Jenkinsfile +68 -0
- data/dev/ci/tests/rpm/run +63 -0
- data/dev/ci/tests/source-packaging/run +1 -1
- data/dev/ci/tests/source-packaging/setup +1 -1
- data/doc/{Packaging.txt.md → Packaging.md} +0 -0
- data/resources/templates/apache2/deployment_example.txt.erb +2 -2
- data/resources/templates/apache2/multiple_apache_installations_detected.txt.erb +2 -2
- data/resources/templates/nginx/deployment_example.txt.erb +1 -1
- data/resources/templates/standalone/mass_deployment_default_server.erb +2 -2
- data/resources/templates/standalone/server.erb +2 -2
- data/src/agent/AgentMain.cpp +0 -4
- data/src/agent/Core/CoreMain.cpp +88 -5
- data/src/agent/Core/SpawningKit/Spawner.h +2 -1
- data/src/agent/Shared/Fundamentals/AbortHandler.cpp +1109 -0
- data/src/agent/Shared/Fundamentals/AbortHandler.h +63 -0
- data/src/agent/Shared/Fundamentals/Implementation.cpp +7 -0
- data/src/agent/Shared/Fundamentals/Initialization.cpp +614 -0
- data/src/agent/Shared/{Base.h → Fundamentals/Initialization.h} +23 -14
- data/src/agent/Shared/Fundamentals/Utils.cpp +127 -0
- data/src/agent/Shared/Fundamentals/Utils.h +46 -0
- data/src/agent/TempDirToucher/TempDirToucherMain.cpp +1 -1
- data/src/agent/Watchdog/CoreWatcher.cpp +3 -1
- data/src/agent/Watchdog/InstanceDirToucher.cpp +90 -53
- data/src/agent/Watchdog/WatchdogMain.cpp +13 -29
- data/src/apache2_module/Hooks.cpp +4 -1
- data/src/cxx_supportlib/ConfigKit/Store.h +32 -5
- data/src/cxx_supportlib/Constants.h +1 -2
- data/src/cxx_supportlib/Crypto.cpp +2 -1
- data/src/cxx_supportlib/Hooks.h +16 -37
- data/src/cxx_supportlib/LoggingKit/Context.h +22 -0
- data/src/cxx_supportlib/LoggingKit/Forward.h +1 -0
- data/src/cxx_supportlib/LoggingKit/Implementation.cpp +106 -22
- data/src/cxx_supportlib/ProcessManagement/Ruby.cpp +106 -0
- data/src/{agent/UstRouter/FileSink.h → cxx_supportlib/ProcessManagement/Ruby.h} +23 -47
- data/src/cxx_supportlib/ProcessManagement/Spawn.cpp +199 -0
- data/src/cxx_supportlib/ProcessManagement/Spawn.h +150 -0
- data/src/cxx_supportlib/ProcessManagement/Utils.cpp +459 -0
- data/src/cxx_supportlib/ProcessManagement/Utils.h +107 -0
- data/src/cxx_supportlib/Utils.cpp +41 -561
- data/src/cxx_supportlib/Utils.h +0 -68
- data/src/cxx_supportlib/Utils/AsyncSignalSafeUtils.h +187 -0
- data/src/cxx_supportlib/Utils/ProcessMetricsCollector.h +14 -2
- data/src/cxx_supportlib/WatchdogLauncher.h +2 -12
- data/src/cxx_supportlib/oxt/dynamic_thread_group.hpp +2 -2
- data/src/cxx_supportlib/vendor-modified/jsoncpp/json-forwards.h +4 -0
- data/src/cxx_supportlib/vendor-modified/jsoncpp/json.h +16 -1
- data/src/cxx_supportlib/vendor-modified/jsoncpp/jsoncpp.cpp +12 -9
- data/src/cxx_supportlib/vendor-modified/libev/ev++.h +4 -4
- data/src/cxx_supportlib/vendor-modified/libev/ev.h +3 -3
- data/src/nginx_module/CacheLocationConfig.c +0 -75
- data/src/nginx_module/CacheLocationConfig.c.cxxcodebuilder +1 -0
- data/src/nginx_module/Configuration.c +0 -1
- data/src/nginx_module/Configuration.h +0 -1
- data/src/nginx_module/ConfigurationCommands.c +1 -1
- data/src/nginx_module/ContentHandler.c +0 -1
- data/src/nginx_module/ContentHandler.h +0 -1
- data/src/nginx_module/CreateLocationConfig.c +0 -5
- data/src/nginx_module/CreateLocationConfig.c.cxxcodebuilder +1 -0
- data/src/nginx_module/LocationConfig.h +0 -4
- data/src/nginx_module/LocationConfig.h.cxxcodebuilder +2 -1
- data/src/nginx_module/MergeLocationConfig.c +0 -12
- data/src/nginx_module/MergeLocationConfig.c.cxxcodebuilder +1 -0
- data/src/nginx_module/ngx_http_passenger_module.h +0 -1
- data/src/ruby_supportlib/phusion_passenger.rb +1 -1
- data/src/ruby_supportlib/phusion_passenger/common_library.rb +20 -11
- data/src/ruby_supportlib/phusion_passenger/config/api_call_command.rb +1 -1
- data/src/ruby_supportlib/phusion_passenger/config/reopen_logs_command.rb +0 -1
- data/src/ruby_supportlib/phusion_passenger/config/validate_install_command.rb +10 -3
- data/src/ruby_supportlib/phusion_passenger/console_text_template.rb +3 -1
- data/src/ruby_supportlib/phusion_passenger/constants.rb +0 -1
- data/src/ruby_supportlib/phusion_passenger/debug_logging.rb +1 -1
- data/src/ruby_supportlib/phusion_passenger/loader_shared_helpers.rb +32 -6
- data/src/ruby_supportlib/phusion_passenger/nginx/config_options.rb +0 -1
- data/src/ruby_supportlib/phusion_passenger/packaging.rb +2 -4
- data/src/ruby_supportlib/phusion_passenger/platform_info/apache.rb +101 -20
- data/src/ruby_supportlib/phusion_passenger/platform_info/apache_detector.rb +21 -9
- data/src/ruby_supportlib/phusion_passenger/platform_info/compiler.rb +34 -31
- data/src/ruby_supportlib/phusion_passenger/platform_info/cxx_portability.rb +3 -1
- data/src/ruby_supportlib/phusion_passenger/platform_info/depcheck_specs/apache2.rb +2 -14
- data/src/ruby_supportlib/phusion_passenger/platform_info/operating_system.rb +40 -3
- data/src/ruby_supportlib/phusion_passenger/standalone/app_finder.rb +15 -14
- data/src/ruby_supportlib/phusion_passenger/standalone/config_options_list.rb +1 -1
- data/src/ruby_supportlib/phusion_passenger/standalone/config_utils.rb +1 -1
- data/src/ruby_supportlib/phusion_passenger/standalone/start_command.rb +8 -3
- data/src/ruby_supportlib/phusion_passenger/standalone/start_command/nginx_engine.rb +19 -18
- data/src/ruby_supportlib/phusion_passenger/standalone/stop_command.rb +6 -1
- data/src/ruby_supportlib/phusion_passenger/vendor/daemon_controller.rb +17 -1
- metadata +19 -97
- data/build/documentation.rb +0 -70
- data/doc/CloudLicensingConfiguration.html +0 -172
- data/doc/CloudLicensingConfiguration.txt.md +0 -3
- data/doc/Packaging.html +0 -488
- data/doc/Security of user switching support.idmap.txt +0 -34
- data/doc/Security of user switching support.txt +0 -197
- data/doc/ServerOptimizationGuide.html +0 -172
- data/doc/ServerOptimizationGuide.txt.md +0 -3
- data/doc/images/by_sa.png +0 -0
- data/doc/images/cloud_licensing_batch_job.png +0 -0
- data/doc/images/code_walkthrough.jpg +0 -0
- data/doc/images/direct_spawning.png +0 -0
- data/doc/images/direct_spawning.svg +0 -251
- data/doc/images/glyphicons-halflings-white.png +0 -0
- data/doc/images/glyphicons-halflings.png +0 -0
- data/doc/images/icons/README +0 -5
- data/doc/images/icons/callouts/1.png +0 -0
- data/doc/images/icons/callouts/10.png +0 -0
- data/doc/images/icons/callouts/11.png +0 -0
- data/doc/images/icons/callouts/12.png +0 -0
- data/doc/images/icons/callouts/13.png +0 -0
- data/doc/images/icons/callouts/14.png +0 -0
- data/doc/images/icons/callouts/15.png +0 -0
- data/doc/images/icons/callouts/2.png +0 -0
- data/doc/images/icons/callouts/3.png +0 -0
- data/doc/images/icons/callouts/4.png +0 -0
- data/doc/images/icons/callouts/5.png +0 -0
- data/doc/images/icons/callouts/6.png +0 -0
- data/doc/images/icons/callouts/7.png +0 -0
- data/doc/images/icons/callouts/8.png +0 -0
- data/doc/images/icons/callouts/9.png +0 -0
- data/doc/images/icons/caution.png +0 -0
- data/doc/images/icons/example.png +0 -0
- data/doc/images/icons/home.png +0 -0
- data/doc/images/icons/important.png +0 -0
- data/doc/images/icons/next.png +0 -0
- data/doc/images/icons/note.png +0 -0
- data/doc/images/icons/prev.png +0 -0
- data/doc/images/icons/tip.png +0 -0
- data/doc/images/icons/up.png +0 -0
- data/doc/images/icons/warning.png +0 -0
- data/doc/images/many_web_framework_protocols.png +0 -0
- data/doc/images/passenger_architecture.png +0 -0
- data/doc/images/passenger_architecture.svg +0 -385
- data/doc/images/passenger_architecture_overview.png +0 -0
- data/doc/images/passenger_core_architecture.png +0 -0
- data/doc/images/passenger_nodejs_architecture.svg +0 -558
- data/doc/images/phusion_banner.png +0 -0
- data/doc/images/rack.png +0 -0
- data/doc/images/smart_spawning.png +0 -0
- data/doc/images/smart_spawning.svg +0 -323
- data/doc/images/spawn_server_architecture.png +0 -0
- data/doc/images/spawn_server_architecture.svg +0 -655
- data/doc/images/spawning_preparation_work.png +0 -0
- data/doc/images/startup_sequence.png +0 -0
- data/doc/images/typical_isolated_web_application.png +0 -0
- data/doc/images/typical_isolated_web_application.svg +0 -213
- data/doc/users_guide_snippets/alternative_for_flying_passenger.txt +0 -1
- data/doc/users_guide_snippets/analysis_and_system_maintenance.txt +0 -61
- data/doc/users_guide_snippets/appendix_a_about.txt +0 -13
- data/doc/users_guide_snippets/appendix_b_terminology.txt +0 -71
- data/doc/users_guide_snippets/appendix_c_spawning_methods.txt +0 -36
- data/doc/users_guide_snippets/deployment_basics.txt +0 -37
- data/doc/users_guide_snippets/enterprise_only.txt +0 -1
- data/doc/users_guide_snippets/environment_variables.txt +0 -44
- data/doc/users_guide_snippets/global_queueing_explained.txt +0 -74
- data/doc/users_guide_snippets/installation.txt +0 -228
- data/doc/users_guide_snippets/installation/run_installer.txt +0 -58
- data/doc/users_guide_snippets/installation/verify_running_epilogue.txt +0 -6
- data/doc/users_guide_snippets/passenger_spawn_method.txt +0 -37
- data/doc/users_guide_snippets/rackup_specifications.txt +0 -1
- data/doc/users_guide_snippets/rvm_helper_tool.txt +0 -44
- data/doc/users_guide_snippets/since_version.txt +0 -1
- data/doc/users_guide_snippets/support_information.txt +0 -8
- data/doc/users_guide_snippets/tips.txt +0 -302
- data/doc/users_guide_snippets/troubleshooting/default.txt +0 -48
- data/doc/users_guide_snippets/troubleshooting/rails.txt +0 -59
- data/doc/users_guide_snippets/under_the_hood/page_caching_support.txt +0 -24
- data/doc/users_guide_snippets/under_the_hood/relationship_with_ruby.txt +0 -10
- data/doc/users_guide_snippets/where_to_get_support.txt +0 -9
- data/src/agent/Shared/Base.cpp +0 -1678
- data/src/agent/UstRouter/ApiServer.h +0 -292
- data/src/agent/UstRouter/Client.h +0 -112
- data/src/agent/UstRouter/Controller.h +0 -1309
- data/src/agent/UstRouter/LogSink.h +0 -145
- data/src/agent/UstRouter/OptionParser.h +0 -180
- data/src/agent/UstRouter/RemoteSender.h +0 -853
- data/src/agent/UstRouter/RemoteSink.h +0 -145
- data/src/agent/UstRouter/Transaction.h +0 -278
- data/src/agent/UstRouter/UstRouterMain.cpp +0 -681
- data/src/agent/Watchdog/UstRouterWatcher.cpp +0 -80
- data/src/ruby_supportlib/phusion_passenger/platform_info/macos.rb +0 -45
@@ -1,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_ */
|