passenger 4.0.2 → 4.0.3
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.
- data.tar.gz.asc +7 -7
- data/NEWS +27 -0
- data/bin/passenger-config +6 -3
- data/bin/passenger-install-apache2-module +2 -2
- data/bin/passenger-install-nginx-module +16 -2
- data/build/agents.rb +4 -0
- data/build/apache2.rb +1 -1
- data/build/cplusplus_support.rb +1 -1
- data/build/cxx_tests.rb +3 -0
- data/build/packaging.rb +51 -8
- data/build/ruby_extension.rb +1 -1
- data/doc/Packaging.txt.md +20 -7
- data/doc/Users guide Apache.html +1 -1
- data/doc/Users guide Apache.txt +1 -1
- data/doc/Users guide Nginx.html +5 -4
- data/doc/Users guide Nginx.txt +1 -1
- data/doc/users_guide_snippets/installation.txt +5 -3
- data/ext/apache2/Configuration.cpp +12 -0
- data/ext/apache2/Configuration.hpp +7 -4
- data/ext/apache2/Hooks.cpp +29 -19
- data/ext/common/AgentsStarter.cpp +85 -57
- data/ext/common/AgentsStarter.h +570 -42
- data/ext/common/ApplicationPool2/DirectSpawner.h +5 -2
- data/ext/common/ApplicationPool2/Implementation.cpp +7 -1
- data/ext/common/ApplicationPool2/Pool.h +6 -3
- data/ext/common/ApplicationPool2/Process.h +12 -3
- data/ext/common/ApplicationPool2/SmartSpawner.h +2 -1
- data/ext/common/Constants.h +4 -1
- data/ext/common/EventedBufferedInput.h +139 -16
- data/ext/common/MultiLibeio.cpp +4 -2
- data/ext/common/SafeLibev.h +15 -62
- data/ext/common/ServerInstanceDir.h +10 -26
- data/ext/common/Utils.cpp +1 -3
- data/ext/common/Utils.h +1 -1
- data/ext/common/Utils/StrIntUtils.cpp +9 -0
- data/ext/common/Utils/StrIntUtils.h +5 -0
- data/ext/common/Utils/VariantMap.h +63 -14
- data/ext/common/agents/Base.cpp +50 -15
- data/ext/common/agents/HelperAgent/AgentOptions.h +20 -12
- data/ext/common/agents/HelperAgent/FileBackedPipe.h +1 -1
- data/ext/common/agents/HelperAgent/Main.cpp +5 -4
- data/ext/common/agents/HelperAgent/RequestHandler.h +1 -1
- data/ext/common/agents/LoggingAgent/Main.cpp +0 -1
- data/ext/common/agents/LoggingAgent/RemoteSender.h +2 -2
- data/ext/common/agents/SpawnPreparer.cpp +23 -5
- data/ext/common/agents/Watchdog/AgentWatcher.cpp +508 -0
- data/ext/common/agents/Watchdog/HelperAgentWatcher.cpp +93 -0
- data/ext/common/agents/Watchdog/LoggingAgentWatcher.cpp +68 -0
- data/ext/common/agents/Watchdog/Main.cpp +180 -802
- data/ext/common/agents/Watchdog/ServerInstanceDirToucher.cpp +111 -0
- data/ext/nginx/Configuration.c +107 -92
- data/ext/nginx/Configuration.h +1 -0
- data/ext/nginx/ContentHandler.c +6 -6
- data/ext/nginx/ContentHandler.h +1 -1
- data/ext/nginx/config +8 -2
- data/ext/nginx/ngx_http_passenger_module.c +54 -60
- data/ext/nginx/ngx_http_passenger_module.h +6 -6
- data/lib/phusion_passenger.rb +17 -10
- data/lib/phusion_passenger/admin_tools/server_instance.rb +2 -2
- data/lib/phusion_passenger/common_library.rb +0 -1
- data/lib/phusion_passenger/platform_info.rb +10 -1
- data/lib/phusion_passenger/platform_info/depcheck.rb +4 -4
- data/lib/phusion_passenger/platform_info/depcheck_specs/compiler_toolchain.rb +2 -2
- data/lib/phusion_passenger/platform_info/ruby.rb +7 -0
- data/lib/phusion_passenger/request_handler.rb +119 -42
- data/lib/phusion_passenger/request_handler/thread_handler.rb +25 -22
- data/lib/phusion_passenger/standalone/command.rb +2 -0
- data/lib/phusion_passenger/standalone/runtime_installer.rb +4 -3
- data/lib/phusion_passenger/standalone/start_command.rb +49 -37
- data/resources/templates/nginx/pcre_checksum_could_not_be_verified.txt.erb +11 -0
- data/test/cxx/CxxTestMain.cpp +2 -0
- data/test/cxx/EventedBufferedInputTest.cpp +758 -0
- data/test/cxx/ServerInstanceDirTest.cpp +16 -31
- data/test/cxx/TestSupport.cpp +2 -1
- data/test/cxx/VariantMapTest.cpp +23 -11
- metadata +8 -4
- metadata.gz.asc +7 -7
- data/ext/common/AgentsStarter.hpp +0 -655
- data/lib/phusion_passenger/utils/robust_interruption.rb +0 -173
@@ -23,26 +23,11 @@ namespace tut {
|
|
23
23
|
|
24
24
|
DEFINE_TEST_GROUP(ServerInstanceDirTest);
|
25
25
|
|
26
|
-
TEST_METHOD(1) {
|
27
|
-
// The (pid_t, string) constructor creates a server instance directory
|
28
|
-
// in the given parent directory, and this server instance directory
|
29
|
-
// name contains the major and minor structure versions and the given PID.
|
30
|
-
ServerInstanceDir dir(1234, parentDir);
|
31
|
-
vector<string> contents = listDir(parentDir);
|
32
|
-
ensure_equals(contents.size(), 1u);
|
33
|
-
ensure_equals(contents[0],
|
34
|
-
"passenger." +
|
35
|
-
toString(ServerInstanceDir::DIR_STRUCTURE_MAJOR_VERSION) +
|
36
|
-
"." +
|
37
|
-
toString(ServerInstanceDir::DIR_STRUCTURE_MINOR_VERSION) +
|
38
|
-
".1234");
|
39
|
-
}
|
40
|
-
|
41
26
|
TEST_METHOD(2) {
|
42
27
|
// The (string) constructor creates a ServerInstanceDir object that's
|
43
28
|
// associated with the given directory, and creates the directory
|
44
29
|
// if it doesn't exist.
|
45
|
-
ServerInstanceDir dir(1234
|
30
|
+
ServerInstanceDir dir(parentDir + "/passenger-test.1234");
|
46
31
|
ServerInstanceDir dir2(dir.getPath());
|
47
32
|
ServerInstanceDir dir3(parentDir + "/foo");
|
48
33
|
ensure_equals(dir2.getPath(), dir.getPath());
|
@@ -54,12 +39,12 @@ namespace tut {
|
|
54
39
|
// A ServerInstanceDir object removes the server instance directory
|
55
40
|
// upon destruction, but only if there are no more generations in it.
|
56
41
|
{
|
57
|
-
ServerInstanceDir dir(1234
|
42
|
+
ServerInstanceDir dir(parentDir + "/passenger-test.1234");
|
58
43
|
}
|
59
44
|
ensure_equals(listDir(parentDir).size(), 0u);
|
60
45
|
|
61
46
|
{
|
62
|
-
ServerInstanceDir dir(1234
|
47
|
+
ServerInstanceDir dir(parentDir + "/passenger-test.1234");
|
63
48
|
createGenerationDir(dir.getPath(), 1);
|
64
49
|
}
|
65
50
|
ensure_equals(listDir(parentDir).size(), 1u);
|
@@ -68,7 +53,7 @@ namespace tut {
|
|
68
53
|
TEST_METHOD(4) {
|
69
54
|
// The destructor does not throw any exceptions if the server instance
|
70
55
|
// directory doesn't exist anymore.
|
71
|
-
ServerInstanceDir dir(1234
|
56
|
+
ServerInstanceDir dir(parentDir + "/passenger-test.1234");
|
72
57
|
removeDirTree(dir.getPath());
|
73
58
|
}
|
74
59
|
|
@@ -77,8 +62,8 @@ namespace tut {
|
|
77
62
|
// wasn't created with the ownership flag or if it's been detached.
|
78
63
|
string path, path2;
|
79
64
|
{
|
80
|
-
ServerInstanceDir dir(1234,
|
81
|
-
ServerInstanceDir dir2(5678,
|
65
|
+
ServerInstanceDir dir(parentDir + "/passenger-test.1234", false);
|
66
|
+
ServerInstanceDir dir2(parentDir + "/passenger-test.5678", false);
|
82
67
|
dir2.detach();
|
83
68
|
path = dir.getPath();
|
84
69
|
path2 = dir2.getPath();
|
@@ -90,7 +75,7 @@ namespace tut {
|
|
90
75
|
TEST_METHOD(6) {
|
91
76
|
// If there are no existing generations, newGeneration() creates a new
|
92
77
|
// generation directory with number 0.
|
93
|
-
ServerInstanceDir dir(1234
|
78
|
+
ServerInstanceDir dir(parentDir + "/passenger-test.1234");
|
94
79
|
unsigned int ncontents = listDir(dir.getPath()).size();
|
95
80
|
ServerInstanceDir::GenerationPtr generation = dir.newGeneration(true,
|
96
81
|
"nobody", nobodyGroup, 0, 0);
|
@@ -103,7 +88,7 @@ namespace tut {
|
|
103
88
|
TEST_METHOD(7) {
|
104
89
|
// A Generation object returned by newGeneration() deletes the associated
|
105
90
|
// generation directory upon destruction.
|
106
|
-
ServerInstanceDir dir(1234
|
91
|
+
ServerInstanceDir dir(parentDir + "/passenger-test.1234");
|
107
92
|
ServerInstanceDir::GenerationPtr generation = dir.newGeneration(true,
|
108
93
|
"nobody", nobodyGroup, 0, 0);
|
109
94
|
string path = generation->getPath();
|
@@ -113,7 +98,7 @@ namespace tut {
|
|
113
98
|
|
114
99
|
TEST_METHOD(8) {
|
115
100
|
// getNewestGeneration() returns the newest generation.
|
116
|
-
ServerInstanceDir dir(1234
|
101
|
+
ServerInstanceDir dir(parentDir + "/passenger-test.1234");
|
117
102
|
ServerInstanceDir::GenerationPtr generation0 = dir.newGeneration(true, "nobody", nobodyGroup, 0, 0);
|
118
103
|
ServerInstanceDir::GenerationPtr generation1 = dir.newGeneration(true, "nobody", nobodyGroup, 0, 0);
|
119
104
|
ServerInstanceDir::GenerationPtr generation2 = dir.newGeneration(true, "nobody", nobodyGroup, 0, 0);
|
@@ -127,14 +112,14 @@ namespace tut {
|
|
127
112
|
|
128
113
|
TEST_METHOD(9) {
|
129
114
|
// getNewestGeneration returns null if there are no generations.
|
130
|
-
ServerInstanceDir dir(1234
|
115
|
+
ServerInstanceDir dir(parentDir + "/passenger-test.1234");
|
131
116
|
ensure(dir.getNewestGeneration() == NULL);
|
132
117
|
}
|
133
118
|
|
134
119
|
TEST_METHOD(10) {
|
135
120
|
// A Generation object returned by getNewestGeneration() doesn't delete
|
136
121
|
// the associated generation directory upon destruction.
|
137
|
-
ServerInstanceDir dir(1234
|
122
|
+
ServerInstanceDir dir(parentDir + "/passenger-test.1234");
|
138
123
|
ServerInstanceDir::GenerationPtr generation = dir.newGeneration(true, "nobody", nobodyGroup, 0, 0);
|
139
124
|
ServerInstanceDir::GenerationPtr newestGeneration = dir.getNewestGeneration();
|
140
125
|
newestGeneration.reset();
|
@@ -143,7 +128,7 @@ namespace tut {
|
|
143
128
|
|
144
129
|
TEST_METHOD(11) {
|
145
130
|
// getGeneration() returns the given generation.
|
146
|
-
ServerInstanceDir dir(1234
|
131
|
+
ServerInstanceDir dir(parentDir + "/passenger-test.1234");
|
147
132
|
ServerInstanceDir::GenerationPtr generation0 = dir.newGeneration(true, "nobody", nobodyGroup, 0, 0);
|
148
133
|
ServerInstanceDir::GenerationPtr generation1 = dir.newGeneration(true, "nobody", nobodyGroup, 0, 0);
|
149
134
|
ServerInstanceDir::GenerationPtr generation2 = dir.newGeneration(true, "nobody", nobodyGroup, 0, 0);
|
@@ -156,7 +141,7 @@ namespace tut {
|
|
156
141
|
TEST_METHOD(12) {
|
157
142
|
// A Generation object returned by getGeneration() doesn't delete the
|
158
143
|
// associated generation directory upon destruction.
|
159
|
-
ServerInstanceDir dir(1234
|
144
|
+
ServerInstanceDir dir(parentDir + "/passenger-test.1234");
|
160
145
|
ServerInstanceDir::GenerationPtr generation0 = dir.newGeneration(true, "nobody", nobodyGroup, 0, 0);
|
161
146
|
ServerInstanceDir::GenerationPtr generation1 = dir.newGeneration(true, "nobody", nobodyGroup, 0, 0);
|
162
147
|
|
@@ -169,7 +154,7 @@ namespace tut {
|
|
169
154
|
TEST_METHOD(13) {
|
170
155
|
// A detached Generation doesn't delete the associated generation
|
171
156
|
// directory upon destruction.
|
172
|
-
ServerInstanceDir dir(1234
|
157
|
+
ServerInstanceDir dir(parentDir + "/passenger-test.1234");
|
173
158
|
ServerInstanceDir::GenerationPtr generation = dir.newGeneration(true, "nobody", nobodyGroup, 0, 0);
|
174
159
|
string path = generation->getPath();
|
175
160
|
generation->detach();
|
@@ -180,7 +165,7 @@ namespace tut {
|
|
180
165
|
TEST_METHOD(14) {
|
181
166
|
// It's possible to have two ServerInstanceDir objects constructed
|
182
167
|
// with the same (pid_t, string) constructor arguments.
|
183
|
-
ServerInstanceDir
|
184
|
-
ServerInstanceDir dir2(1234
|
168
|
+
ServerInstanceDir dir(parentDir + "/passenger-test.1234");
|
169
|
+
ServerInstanceDir dir2(parentDir + "/passenger-test.1234");
|
185
170
|
}
|
186
171
|
}
|
data/test/cxx/TestSupport.cpp
CHANGED
@@ -19,7 +19,8 @@ Json::Value testConfig;
|
|
19
19
|
void createServerInstanceDirAndGeneration(ServerInstanceDirPtr &serverInstanceDir,
|
20
20
|
ServerInstanceDir::GenerationPtr &generation)
|
21
21
|
{
|
22
|
-
|
22
|
+
string path = "/tmp/passenger-test." + toString(getpid());
|
23
|
+
serverInstanceDir.reset(new ServerInstanceDir(path));
|
23
24
|
generation = serverInstanceDir->newGeneration(geteuid() == 0,
|
24
25
|
"nobody", getPrimaryGroupName("nobody"),
|
25
26
|
geteuid(), getegid());
|
data/test/cxx/VariantMapTest.cpp
CHANGED
@@ -21,18 +21,15 @@ namespace tut {
|
|
21
21
|
// Test setting and getting string values.
|
22
22
|
map.set("hello", "world");
|
23
23
|
map.set("abcd", "efgh");
|
24
|
-
map.set("foo", "");
|
25
24
|
map.set("", "bar");
|
26
|
-
ensure_equals(map.get("hello"), "world");
|
27
|
-
ensure_equals(map.get("abcd"), "efgh");
|
28
|
-
ensure_equals(map.get("
|
29
|
-
ensure_equals(map.
|
30
|
-
|
31
|
-
ensure(map.has("
|
32
|
-
ensure(map.has("
|
33
|
-
ensure(map.has("
|
34
|
-
ensure(map.has(""));
|
35
|
-
ensure(!map.has("xyz"));
|
25
|
+
ensure_equals("(1)", map.get("hello"), "world");
|
26
|
+
ensure_equals("(2)", map.get("abcd"), "efgh");
|
27
|
+
ensure_equals("(3)", map.get(""), "bar");
|
28
|
+
ensure_equals("(4)", map.size(), 3u);
|
29
|
+
ensure("(5)", map.has("hello"));
|
30
|
+
ensure("(6)", map.has("abcd"));
|
31
|
+
ensure("(7)", map.has(""));
|
32
|
+
ensure("(8)", !map.has("xyz"));
|
36
33
|
}
|
37
34
|
|
38
35
|
TEST_METHOD(3) {
|
@@ -176,4 +173,19 @@ namespace tut {
|
|
176
173
|
ensure_equals(map.get("foo"), "1234");
|
177
174
|
ensure_equals(map.get("bar"), "5678");
|
178
175
|
}
|
176
|
+
|
177
|
+
TEST_METHOD(7) {
|
178
|
+
// Setting an empty value result in the deletion of the key.
|
179
|
+
map.set("a", "a");
|
180
|
+
map.set("b", "b");
|
181
|
+
map.set("b", "");
|
182
|
+
try {
|
183
|
+
map.get("b");
|
184
|
+
fail("MissingKeyException expected");
|
185
|
+
} catch (const VariantMap::MissingKeyException &e) {
|
186
|
+
// Pass.
|
187
|
+
}
|
188
|
+
ensure(!map.has("foo"));
|
189
|
+
ensure_equals(map.size(), 1u);
|
190
|
+
}
|
179
191
|
}
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: passenger
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 4.0.
|
4
|
+
version: 4.0.3
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-05-
|
12
|
+
date: 2013-05-24 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rake
|
@@ -156,7 +156,6 @@ files:
|
|
156
156
|
- lib/phusion_passenger/utils/ansi_colors.rb
|
157
157
|
- lib/phusion_passenger/utils/file_system_watcher.rb
|
158
158
|
- lib/phusion_passenger/utils/hosts_file_parser.rb
|
159
|
-
- lib/phusion_passenger/utils/robust_interruption.rb
|
160
159
|
- lib/phusion_passenger/utils/tee_input.rb
|
161
160
|
- lib/phusion_passenger/utils/tmpdir.rb
|
162
161
|
- lib/phusion_passenger/utils/tmpio.rb
|
@@ -281,7 +280,11 @@ files:
|
|
281
280
|
- ext/common/agents/LoggingAgent/FilterSupport.cpp
|
282
281
|
- ext/common/agents/LoggingAgent/Main.cpp
|
283
282
|
- ext/common/agents/SpawnPreparer.cpp
|
283
|
+
- ext/common/agents/Watchdog/AgentWatcher.cpp
|
284
|
+
- ext/common/agents/Watchdog/HelperAgentWatcher.cpp
|
285
|
+
- ext/common/agents/Watchdog/LoggingAgentWatcher.cpp
|
284
286
|
- ext/common/agents/Watchdog/Main.cpp
|
287
|
+
- ext/common/agents/Watchdog/ServerInstanceDirToucher.cpp
|
285
288
|
- ext/common/AgentsStarter.cpp
|
286
289
|
- ext/common/ApplicationPool2/AppTypes.cpp
|
287
290
|
- ext/common/ApplicationPool2/Implementation.cpp
|
@@ -391,7 +394,6 @@ files:
|
|
391
394
|
- ext/common/Utils/utf8.h
|
392
395
|
- ext/common/Utils/VariantMap.h
|
393
396
|
- ext/common/Utils.h
|
394
|
-
- ext/common/AgentsStarter.hpp
|
395
397
|
- ext/common/Utils/CachedFileStat.hpp
|
396
398
|
- ext/common/ApplicationPool2/README.md
|
397
399
|
- ext/apache2/Bucket.cpp
|
@@ -2223,6 +2225,7 @@ files:
|
|
2223
2225
|
- resources/templates/nginx/confirm_extra_configure_flags.txt.erb
|
2224
2226
|
- resources/templates/nginx/deployment_example.txt.erb
|
2225
2227
|
- resources/templates/nginx/not_available_when_natively_packaged.txt.erb
|
2228
|
+
- resources/templates/nginx/pcre_checksum_could_not_be_verified.txt.erb
|
2226
2229
|
- resources/templates/nginx/pcre_could_not_be_downloaded.txt.erb
|
2227
2230
|
- resources/templates/nginx/pcre_could_not_be_extracted.txt.erb
|
2228
2231
|
- resources/templates/nginx/possible_solutions_for_compilation_and_installation_problems.txt.erb
|
@@ -2261,6 +2264,7 @@ files:
|
|
2261
2264
|
- test/cxx/CachedFileStatTest.cpp
|
2262
2265
|
- test/cxx/CxxTestMain.cpp
|
2263
2266
|
- test/cxx/DechunkerTest.cpp
|
2267
|
+
- test/cxx/EventedBufferedInputTest.cpp
|
2264
2268
|
- test/cxx/EventedClientTest.cpp
|
2265
2269
|
- test/cxx/FileBackedPipeTest.cpp
|
2266
2270
|
- test/cxx/FileChangeCheckerTest.cpp
|
metadata.gz.asc
CHANGED
@@ -2,11 +2,11 @@
|
|
2
2
|
Version: GnuPG/MacGPG2 v2.0.17 (Darwin)
|
3
3
|
Comment: GPGTools - http://gpgtools.org
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
=
|
5
|
+
iQEcBAABAgAGBQJRn9OxAAoJECrHRaUKISqM/UAH/282HhIyLkr616LFhFf7KWTQ
|
6
|
+
OQnu9P8NlHQaUw/yJDZonQDMnMjlPuUYdgJ3xgqFEpLpcAspmJdhlO1G4z4jdhtV
|
7
|
+
G5kTA9LCCuBAbpml0d17grFOEO/23VhJaNjU2uOQKnxS2Q6zVazffCj8AQwRugNc
|
8
|
+
PXCshWCE909zln9HgpC3Rs+W0kJHGsrkX/lFHQPWQvVuTQYxYYBuHsafj+TcAzjg
|
9
|
+
wB7TRZIsBV4SzGuaQDlmDhwDo38LEOHhg3d7wFej0sGaUaqmrBgcgBt8UKPI2nr5
|
10
|
+
U43eiJEitSfaNxCtLtfIQDGxvSVcY2Qh2yJ/+L4UguStJbxlQ5dgNswD3P1yc5w=
|
11
|
+
=zaV0
|
12
12
|
-----END PGP SIGNATURE-----
|
@@ -1,655 +0,0 @@
|
|
1
|
-
/*
|
2
|
-
* Phusion Passenger - https://www.phusionpassenger.com/
|
3
|
-
* Copyright (c) 2010-2013 Phusion
|
4
|
-
*
|
5
|
-
* "Phusion Passenger" is a trademark of Hongli Lai & Ninh Bui.
|
6
|
-
*
|
7
|
-
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
8
|
-
* of this software and associated documentation files (the "Software"), to deal
|
9
|
-
* in the Software without restriction, including without limitation the rights
|
10
|
-
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
11
|
-
* copies of the Software, and to permit persons to whom the Software is
|
12
|
-
* furnished to do so, subject to the following conditions:
|
13
|
-
*
|
14
|
-
* The above copyright notice and this permission notice shall be included in
|
15
|
-
* all copies or substantial portions of the Software.
|
16
|
-
*
|
17
|
-
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
18
|
-
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
19
|
-
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
20
|
-
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
21
|
-
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
22
|
-
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
23
|
-
* THE SOFTWARE.
|
24
|
-
*/
|
25
|
-
#ifndef _PASSENGER_AGENTS_STARTER_HPP_
|
26
|
-
#define _PASSENGER_AGENTS_STARTER_HPP_
|
27
|
-
|
28
|
-
#include <boost/function.hpp>
|
29
|
-
#include <oxt/system_calls.hpp>
|
30
|
-
#include <oxt/backtrace.hpp>
|
31
|
-
#include <string>
|
32
|
-
#include <vector>
|
33
|
-
#include <set>
|
34
|
-
|
35
|
-
#include <sys/types.h>
|
36
|
-
#include <unistd.h>
|
37
|
-
#include <signal.h>
|
38
|
-
|
39
|
-
#include <Constants.h>
|
40
|
-
#include <FileDescriptor.h>
|
41
|
-
#include <MessageClient.h>
|
42
|
-
#include <ServerInstanceDir.h>
|
43
|
-
#include <Exceptions.h>
|
44
|
-
#include <ResourceLocator.h>
|
45
|
-
#include <Utils.h>
|
46
|
-
#include <Utils/IOUtils.h>
|
47
|
-
#include <Utils/MessageIO.h>
|
48
|
-
#include <Utils/Base64.h>
|
49
|
-
#include <Utils/Timer.h>
|
50
|
-
#include <Utils/ScopeGuard.h>
|
51
|
-
#include <Utils/VariantMap.h>
|
52
|
-
|
53
|
-
namespace Passenger {
|
54
|
-
|
55
|
-
using namespace std;
|
56
|
-
using namespace boost;
|
57
|
-
using namespace oxt;
|
58
|
-
|
59
|
-
/**
|
60
|
-
* Utility class for starting various Phusion Passenger agents through the watchdog.
|
61
|
-
*/
|
62
|
-
class AgentsStarter {
|
63
|
-
public:
|
64
|
-
enum Type {
|
65
|
-
APACHE,
|
66
|
-
NGINX
|
67
|
-
};
|
68
|
-
|
69
|
-
private:
|
70
|
-
/** The watchdog's PID. Equals 0 if the watchdog hasn't been started yet
|
71
|
-
* or if detach() is called. */
|
72
|
-
pid_t pid;
|
73
|
-
|
74
|
-
Type type;
|
75
|
-
|
76
|
-
/** The watchdog's feedback file descriptor. Only valid if pid != 0. */
|
77
|
-
FileDescriptor feedbackFd;
|
78
|
-
|
79
|
-
/**
|
80
|
-
* The helper agent's request socket filename. This socket only exists
|
81
|
-
* for the Nginx helper agent, and it's for serving SCGI requests.
|
82
|
-
*
|
83
|
-
* Only valid if pid != 0.
|
84
|
-
*/
|
85
|
-
string requestSocketFilename;
|
86
|
-
|
87
|
-
/**
|
88
|
-
* A password for connecting to the request socket. Only valid if pid != 0.
|
89
|
-
*/
|
90
|
-
string requestSocketPassword;
|
91
|
-
|
92
|
-
/**
|
93
|
-
* The helper agent's message server socket filename, on which e.g. the
|
94
|
-
* application pool server is listening. Only valid if pid != 0.
|
95
|
-
*
|
96
|
-
* The application pool server is available through the account "_web_server".
|
97
|
-
*/
|
98
|
-
string messageSocketFilename;
|
99
|
-
|
100
|
-
/**
|
101
|
-
* A password for the message server socket. The associated username is "_web_server".
|
102
|
-
*
|
103
|
-
* Only valid if pid != 0.
|
104
|
-
*/
|
105
|
-
string messageSocketPassword;
|
106
|
-
|
107
|
-
bool loggingAgentRunningLocally;
|
108
|
-
string loggingSocketAddress;
|
109
|
-
string loggingSocketPassword;
|
110
|
-
|
111
|
-
/**
|
112
|
-
* The server instance dir of the agents. Only valid if pid != 0.
|
113
|
-
*/
|
114
|
-
ServerInstanceDirPtr serverInstanceDir;
|
115
|
-
|
116
|
-
/**
|
117
|
-
* The generation dir of the agents. Only valid if pid != 0.
|
118
|
-
*/
|
119
|
-
ServerInstanceDir::GenerationPtr generation;
|
120
|
-
|
121
|
-
/**
|
122
|
-
* Safely dup2() the given file descriptor to 3 (FEEDBACK_FD).
|
123
|
-
*/
|
124
|
-
void installFeedbackFd(const FileDescriptor &fd) {
|
125
|
-
if (fd != FEEDBACK_FD && syscalls::dup2(fd, FEEDBACK_FD) == -1) {
|
126
|
-
int e = errno;
|
127
|
-
try {
|
128
|
-
writeArrayMessage(fd,
|
129
|
-
"system error",
|
130
|
-
"dup2() failed",
|
131
|
-
toString(e).c_str(),
|
132
|
-
NULL);
|
133
|
-
_exit(1);
|
134
|
-
} catch (...) {
|
135
|
-
fprintf(stderr, "Passenger AgentsStarter: dup2() failed: %s (%d)\n",
|
136
|
-
strerror(e), e);
|
137
|
-
fflush(stderr);
|
138
|
-
_exit(1);
|
139
|
-
}
|
140
|
-
}
|
141
|
-
}
|
142
|
-
|
143
|
-
/**
|
144
|
-
* Call this if the watchdog seems to have crashed. This function will try
|
145
|
-
* to determine whether the watchdog is still running, whether it crashed
|
146
|
-
* with a signal, etc. If it has detected that the watchdog is no longer running
|
147
|
-
* then it will set <em>pid</em> to -1.
|
148
|
-
*/
|
149
|
-
void inspectWatchdogCrashReason(pid_t &pid) {
|
150
|
-
this_thread::disable_interruption di;
|
151
|
-
this_thread::disable_syscall_interruption dsi;
|
152
|
-
int ret, status;
|
153
|
-
|
154
|
-
/* Upon noticing that something went wrong, the watchdog
|
155
|
-
* or its subprocesses might still be writing out an error
|
156
|
-
* report, so we wait a while before killing the watchdog.
|
157
|
-
*/
|
158
|
-
ret = timedWaitPid(pid, &status, 5000);
|
159
|
-
if (ret == 0) {
|
160
|
-
/* Looks like the watchdog didn't crash and is still running. */
|
161
|
-
throw RuntimeException(
|
162
|
-
"Unable to start the Phusion Passenger watchdog: "
|
163
|
-
"it froze during startup and reported an unknown error");
|
164
|
-
} else if (ret != -1 && WIFSIGNALED(status)) {
|
165
|
-
/* Looks like a crash which caused a signal. */
|
166
|
-
pid = -1;
|
167
|
-
throw RuntimeException(
|
168
|
-
"Unable to start the Phusion Passenger watchdog: "
|
169
|
-
"it seems to have been killed with signal " +
|
170
|
-
getSignalName(WTERMSIG(status)) + " during startup");
|
171
|
-
} else if (ret == -1) {
|
172
|
-
/* Looks like it exited for a different reason and has no exit code. */
|
173
|
-
pid = -1;
|
174
|
-
throw RuntimeException(
|
175
|
-
"Unable to start the Phusion Passenger watchdog: "
|
176
|
-
"it seems to have crashed during startup for an unknown reason");
|
177
|
-
} else {
|
178
|
-
/* Looks like it exited for a different reason, but has an exit code. */
|
179
|
-
pid = -1;
|
180
|
-
throw RuntimeException(
|
181
|
-
"Unable to start the Phusion Passenger watchdog: "
|
182
|
-
"it seems to have crashed during startup for an unknown reason, "
|
183
|
-
"with exit code " + toString(WEXITSTATUS(status)));
|
184
|
-
}
|
185
|
-
}
|
186
|
-
|
187
|
-
static void killProcessGroupAndWait(pid_t *pid, unsigned long long timeout = 0) {
|
188
|
-
if (*pid != -1 && (timeout == 0 || timedWaitPid(*pid, NULL, timeout) <= 0)) {
|
189
|
-
this_thread::disable_syscall_interruption dsi;
|
190
|
-
syscalls::killpg(*pid, SIGKILL);
|
191
|
-
syscalls::waitpid(*pid, NULL, 0);
|
192
|
-
*pid = -1;
|
193
|
-
}
|
194
|
-
}
|
195
|
-
|
196
|
-
/**
|
197
|
-
* Behaves like <tt>waitpid(pid, status, WNOHANG)</tt>, but waits at most
|
198
|
-
* <em>timeout</em> miliseconds for the process to exit.
|
199
|
-
*/
|
200
|
-
static int timedWaitPid(pid_t pid, int *status, unsigned long long timeout) {
|
201
|
-
Timer timer;
|
202
|
-
int ret;
|
203
|
-
|
204
|
-
do {
|
205
|
-
ret = syscalls::waitpid(pid, status, WNOHANG);
|
206
|
-
if (ret > 0 || ret == -1) {
|
207
|
-
return ret;
|
208
|
-
} else {
|
209
|
-
syscalls::usleep(10000);
|
210
|
-
}
|
211
|
-
} while (timer.elapsed() < timeout);
|
212
|
-
return 0; // timed out
|
213
|
-
}
|
214
|
-
|
215
|
-
/**
|
216
|
-
* Gracefully shutdown an agent process by sending an exit command to its socket.
|
217
|
-
* Returns whether the agent has successfully processed the exit command.
|
218
|
-
* Any exceptions are caught and will cause false to be returned.
|
219
|
-
*/
|
220
|
-
bool gracefullyShutdownAgent(const string &socketFilename, const string &username,
|
221
|
-
const string &password
|
222
|
-
) {
|
223
|
-
try {
|
224
|
-
MessageClient client;
|
225
|
-
vector<string> args;
|
226
|
-
|
227
|
-
client.connect("unix:" + socketFilename, username, password);
|
228
|
-
client.write("exit", NULL);
|
229
|
-
return client.read(args) && args[0] == "Passed security" &&
|
230
|
-
client.read(args) && args[0] == "exit command received";
|
231
|
-
} catch (const SystemException &) {
|
232
|
-
} catch (const IOException &) {
|
233
|
-
} catch (const SecurityException &) {
|
234
|
-
}
|
235
|
-
return false;
|
236
|
-
}
|
237
|
-
|
238
|
-
string serializePrestartURLs(const set<string> &prestartURLs) const {
|
239
|
-
set<string>::const_iterator it;
|
240
|
-
string result;
|
241
|
-
|
242
|
-
for (it = prestartURLs.begin(); it != prestartURLs.end(); it++) {
|
243
|
-
result.append(*it);
|
244
|
-
result.append(1, '\0');
|
245
|
-
}
|
246
|
-
return Base64::encode(result);
|
247
|
-
}
|
248
|
-
|
249
|
-
public:
|
250
|
-
/**
|
251
|
-
* Construct a AgentsStarter object. The watchdog and the agents
|
252
|
-
* aren't started yet until you call start().
|
253
|
-
*
|
254
|
-
* @param type Whether one wants to start the Apache or the Nginx helper agent.
|
255
|
-
*/
|
256
|
-
AgentsStarter(Type type) {
|
257
|
-
pid = 0;
|
258
|
-
loggingAgentRunningLocally = false;
|
259
|
-
this->type = type;
|
260
|
-
}
|
261
|
-
|
262
|
-
~AgentsStarter() {
|
263
|
-
if (pid != 0) {
|
264
|
-
this_thread::disable_syscall_interruption dsi;
|
265
|
-
bool cleanShutdown = gracefullyShutdownAgent(messageSocketFilename,
|
266
|
-
"_web_server", messageSocketPassword);
|
267
|
-
if (loggingAgentRunningLocally) {
|
268
|
-
string filename = parseUnixSocketAddress(loggingSocketAddress);
|
269
|
-
cleanShutdown = cleanShutdown &&
|
270
|
-
gracefullyShutdownAgent(filename,
|
271
|
-
"logging", loggingSocketPassword);
|
272
|
-
}
|
273
|
-
|
274
|
-
/* Send a message down the feedback fd to tell the watchdog
|
275
|
-
* Whether this is a clean shutdown. Closing the fd without
|
276
|
-
* sending anything also indicates an unclean shutdown,
|
277
|
-
* but we send a byte anyway in case there are other processes
|
278
|
-
* who have the fd open.
|
279
|
-
*/
|
280
|
-
if (cleanShutdown) {
|
281
|
-
syscalls::write(feedbackFd, "c", 1);
|
282
|
-
} else {
|
283
|
-
syscalls::write(feedbackFd, "u", 1);
|
284
|
-
}
|
285
|
-
|
286
|
-
/* If we failed to send an exit command to one of the agents then we have
|
287
|
-
* to forcefully kill all agents now because otherwise one of them might
|
288
|
-
* never exit. We do this by closing the feedback fd without sending a
|
289
|
-
* random byte, to indicate that this is an abnormal shutdown. The watchdog
|
290
|
-
* will then kill all agents.
|
291
|
-
*/
|
292
|
-
|
293
|
-
feedbackFd.close();
|
294
|
-
syscalls::waitpid(pid, NULL, 0);
|
295
|
-
}
|
296
|
-
}
|
297
|
-
|
298
|
-
/**
|
299
|
-
* Returns the type as was passed to the constructor.
|
300
|
-
*/
|
301
|
-
Type getType() const {
|
302
|
-
return type;
|
303
|
-
}
|
304
|
-
|
305
|
-
/**
|
306
|
-
* Returns the watchdog's PID. Equals 0 if the watchdog hasn't been started yet
|
307
|
-
* or if detach() is called.
|
308
|
-
*/
|
309
|
-
pid_t getPid() const {
|
310
|
-
return pid;
|
311
|
-
}
|
312
|
-
|
313
|
-
/**
|
314
|
-
* The helper agent's request socket filename, on which it's listening
|
315
|
-
* for SCGI requests.
|
316
|
-
*
|
317
|
-
* @pre getPid() != 0 && getType() == NGINX
|
318
|
-
*/
|
319
|
-
string getRequestSocketFilename() const {
|
320
|
-
return requestSocketFilename;
|
321
|
-
}
|
322
|
-
|
323
|
-
/**
|
324
|
-
* Returns the password for connecting to the request socket.
|
325
|
-
*
|
326
|
-
* @pre getPid() != 0 && getType() == NGINX
|
327
|
-
*/
|
328
|
-
string getRequestSocketPassword() const {
|
329
|
-
return requestSocketPassword;
|
330
|
-
}
|
331
|
-
|
332
|
-
string getMessageSocketFilename() const {
|
333
|
-
return messageSocketFilename;
|
334
|
-
}
|
335
|
-
|
336
|
-
string getMessageSocketPassword() const {
|
337
|
-
return messageSocketPassword;
|
338
|
-
}
|
339
|
-
|
340
|
-
string getLoggingSocketAddress() const {
|
341
|
-
return loggingSocketAddress;
|
342
|
-
}
|
343
|
-
|
344
|
-
string getLoggingSocketPassword() const {
|
345
|
-
return loggingSocketPassword;
|
346
|
-
}
|
347
|
-
|
348
|
-
/**
|
349
|
-
* Returns the server instance dir of the agents.
|
350
|
-
*
|
351
|
-
* @pre getPid() != 0
|
352
|
-
*/
|
353
|
-
ServerInstanceDirPtr getServerInstanceDir() const {
|
354
|
-
return serverInstanceDir;
|
355
|
-
}
|
356
|
-
|
357
|
-
/**
|
358
|
-
* Returns the generation dir of the agents.
|
359
|
-
*
|
360
|
-
* @pre getPid() != 0
|
361
|
-
*/
|
362
|
-
ServerInstanceDir::GenerationPtr getGeneration() const {
|
363
|
-
return generation;
|
364
|
-
}
|
365
|
-
|
366
|
-
/**
|
367
|
-
* Start the agents through the watchdog, with the given parameters.
|
368
|
-
*
|
369
|
-
* @throws SystemException Something went wrong.
|
370
|
-
* @throws IOException Something went wrong while communicating with one
|
371
|
-
* of the agents during its initialization phase.
|
372
|
-
* @throws RuntimeException Something went wrong.
|
373
|
-
*/
|
374
|
-
void start(int logLevel, const string &debugLogFile,
|
375
|
-
pid_t webServerPid, const string &tempDir,
|
376
|
-
bool userSwitching, const string &defaultUser, const string &defaultGroup,
|
377
|
-
uid_t webServerWorkerUid, gid_t webServerWorkerGid,
|
378
|
-
const string &passengerRoot, const string &defaultRubyCommand,
|
379
|
-
unsigned int maxPoolSize, unsigned int maxInstancesPerApp,
|
380
|
-
unsigned int poolIdleTime,
|
381
|
-
const string &analyticsServer,
|
382
|
-
const string &analyticsLogUser,
|
383
|
-
const string &analyticsLogGroup,
|
384
|
-
const string &unionStationGatewayAddress,
|
385
|
-
unsigned short unionStationGatewayPort,
|
386
|
-
const string &unionStationGatewayCert,
|
387
|
-
const string &unionStationProxyAddress,
|
388
|
-
const set<string> &prestartURLs,
|
389
|
-
const function<void ()> &afterFork = function<void ()>())
|
390
|
-
{
|
391
|
-
TRACE_POINT();
|
392
|
-
this_thread::disable_interruption di;
|
393
|
-
this_thread::disable_syscall_interruption dsi;
|
394
|
-
ResourceLocator locator(passengerRoot);
|
395
|
-
|
396
|
-
string realUnionStationGatewayCert;
|
397
|
-
if (unionStationGatewayCert.empty()) {
|
398
|
-
realUnionStationGatewayCert = locator.getResourcesDir() + "/union_station_gateway.crt";
|
399
|
-
} else if (unionStationGatewayCert != "-") {
|
400
|
-
realUnionStationGatewayCert = unionStationGatewayCert;
|
401
|
-
}
|
402
|
-
string watchdogFilename = locator.getAgentsDir() + "/PassengerWatchdog";
|
403
|
-
|
404
|
-
VariantMap watchdogArgs;
|
405
|
-
watchdogArgs
|
406
|
-
.set ("web_server_type", type == APACHE ? "apache" : "nginx")
|
407
|
-
.setInt ("log_level", logLevel)
|
408
|
-
.set ("debug_log_file", debugLogFile)
|
409
|
-
.setPid ("web_server_pid", webServerPid)
|
410
|
-
.set ("temp_dir", tempDir.empty() ? getSystemTempDir() : tempDir)
|
411
|
-
.setBool("user_switching", userSwitching)
|
412
|
-
.set ("default_user", defaultUser)
|
413
|
-
.set ("default_group", defaultGroup)
|
414
|
-
.setUid ("web_server_worker_uid", webServerWorkerUid)
|
415
|
-
.setGid ("web_server_worker_gid", webServerWorkerGid)
|
416
|
-
.set ("passenger_root", passengerRoot)
|
417
|
-
.set ("default_ruby", defaultRubyCommand)
|
418
|
-
.setInt ("max_pool_size", maxPoolSize)
|
419
|
-
.setInt ("max_instances_per_app", maxInstancesPerApp)
|
420
|
-
.setInt ("pool_idle_time", poolIdleTime)
|
421
|
-
.set ("analytics_server", analyticsServer)
|
422
|
-
.set ("analytics_log_user", analyticsLogUser)
|
423
|
-
.set ("analytics_log_group", analyticsLogGroup)
|
424
|
-
.set ("union_station_gateway_address", unionStationGatewayAddress)
|
425
|
-
.setInt ("union_station_gateway_port", unionStationGatewayPort)
|
426
|
-
.set ("union_station_gateway_cert", realUnionStationGatewayCert)
|
427
|
-
.set ("union_station_proxy_address", unionStationProxyAddress)
|
428
|
-
.set ("prestart_urls", serializePrestartURLs(prestartURLs));
|
429
|
-
|
430
|
-
SocketPair fds;
|
431
|
-
int e;
|
432
|
-
pid_t pid;
|
433
|
-
|
434
|
-
fds = createUnixSocketPair();
|
435
|
-
pid = syscalls::fork();
|
436
|
-
if (pid == 0) {
|
437
|
-
// Child
|
438
|
-
|
439
|
-
/* Become the session leader so that Apache can't kill the
|
440
|
-
* watchdog with killpg() during shutdown, so that a
|
441
|
-
* Ctrl-C only affects the web server, and so that
|
442
|
-
* we can kill all of our subprocesses in a single killpg().
|
443
|
-
*/
|
444
|
-
setsid();
|
445
|
-
|
446
|
-
// Make sure the feedback fd is 3 and close all file descriptors
|
447
|
-
// except stdin, stdout, stderr and 3.
|
448
|
-
syscalls::close(fds[0]);
|
449
|
-
installFeedbackFd(fds[1]);
|
450
|
-
closeAllFileDescriptors(FEEDBACK_FD);
|
451
|
-
|
452
|
-
/* We don't know how the web server or the environment affect
|
453
|
-
* signal handlers and the signal mask, so reset this stuff
|
454
|
-
* just in case.
|
455
|
-
*/
|
456
|
-
resetSignalHandlersAndMask();
|
457
|
-
|
458
|
-
if (afterFork) {
|
459
|
-
afterFork();
|
460
|
-
}
|
461
|
-
|
462
|
-
execl(watchdogFilename.c_str(), "PassengerWatchdog", (char *) 0);
|
463
|
-
e = errno;
|
464
|
-
try {
|
465
|
-
writeArrayMessage(FEEDBACK_FD,
|
466
|
-
"exec error",
|
467
|
-
toString(e).c_str(),
|
468
|
-
NULL);
|
469
|
-
_exit(1);
|
470
|
-
} catch (...) {
|
471
|
-
fprintf(stderr, "Passenger AgentsStarter: could not execute %s: %s (%d)\n",
|
472
|
-
watchdogFilename.c_str(), strerror(e), e);
|
473
|
-
fflush(stderr);
|
474
|
-
_exit(1);
|
475
|
-
}
|
476
|
-
} else if (pid == -1) {
|
477
|
-
// Error
|
478
|
-
e = errno;
|
479
|
-
throw SystemException("Cannot fork a new process", e);
|
480
|
-
} else {
|
481
|
-
// Parent
|
482
|
-
UPDATE_TRACE_POINT();
|
483
|
-
FileDescriptor feedbackFd = fds[0];
|
484
|
-
vector<string> args;
|
485
|
-
bool result, allAgentsStarted;
|
486
|
-
|
487
|
-
ServerInstanceDirPtr serverInstanceDir;
|
488
|
-
ServerInstanceDir::GenerationPtr generation;
|
489
|
-
ScopeGuard guard(boost::bind(&AgentsStarter::killProcessGroupAndWait, &pid, 0));
|
490
|
-
fds[1].close();
|
491
|
-
|
492
|
-
|
493
|
-
/****** Send arguments to watchdog through the feedback channel ******/
|
494
|
-
|
495
|
-
UPDATE_TRACE_POINT();
|
496
|
-
/* Here we don't care about EPIPE and ECONNRESET errors. The watchdog
|
497
|
-
* could have sent an error message over the feedback fd without
|
498
|
-
* reading the arguments. We'll notice that later.
|
499
|
-
*/
|
500
|
-
try {
|
501
|
-
watchdogArgs.writeToFd(feedbackFd);
|
502
|
-
} catch (const SystemException &e) {
|
503
|
-
if (e.code() != EPIPE && e.code() != ECONNRESET) {
|
504
|
-
inspectWatchdogCrashReason(pid);
|
505
|
-
}
|
506
|
-
}
|
507
|
-
|
508
|
-
|
509
|
-
/****** Read basic startup information ******/
|
510
|
-
|
511
|
-
this_thread::restore_interruption ri(di);
|
512
|
-
this_thread::restore_syscall_interruption rsi(dsi);
|
513
|
-
UPDATE_TRACE_POINT();
|
514
|
-
|
515
|
-
try {
|
516
|
-
result = readArrayMessage(feedbackFd, args);
|
517
|
-
} catch (const SystemException &ex) {
|
518
|
-
if (ex.code() == ECONNRESET) {
|
519
|
-
inspectWatchdogCrashReason(pid);
|
520
|
-
} else {
|
521
|
-
killProcessGroupAndWait(&pid, 5000);
|
522
|
-
guard.clear();
|
523
|
-
throw SystemException("Unable to start the Phusion Passenger watchdog: "
|
524
|
-
"unable to read its startup information",
|
525
|
-
ex.code());
|
526
|
-
}
|
527
|
-
}
|
528
|
-
if (!result) {
|
529
|
-
UPDATE_TRACE_POINT();
|
530
|
-
inspectWatchdogCrashReason(pid);
|
531
|
-
}
|
532
|
-
|
533
|
-
UPDATE_TRACE_POINT();
|
534
|
-
if (args[0] == "Basic startup info") {
|
535
|
-
if (args.size() == 3) {
|
536
|
-
serverInstanceDir.reset(new ServerInstanceDir(args[1], false));
|
537
|
-
generation = serverInstanceDir->getGeneration(atoi(args[2]));
|
538
|
-
} else {
|
539
|
-
throw IOException("Unable to start the Phusion Passenger watchdog: "
|
540
|
-
"it returned an invalid basic startup information message");
|
541
|
-
}
|
542
|
-
} else if (args[0] == "Watchdog startup error") {
|
543
|
-
killProcessGroupAndWait(&pid, 5000);
|
544
|
-
guard.clear();
|
545
|
-
throw RuntimeException("Unable to start the Phusion Passenger watchdog "
|
546
|
-
"because it encountered the following error during startup: " +
|
547
|
-
args[1]);
|
548
|
-
} else if (args[0] == "system error") {
|
549
|
-
killProcessGroupAndWait(&pid, 5000);
|
550
|
-
guard.clear();
|
551
|
-
throw SystemException(args[1], atoi(args[2]));
|
552
|
-
} else if (args[0] == "exec error") {
|
553
|
-
e = atoi(args[1]);
|
554
|
-
killProcessGroupAndWait(&pid, 5000);
|
555
|
-
guard.clear();
|
556
|
-
if (e == ENOENT) {
|
557
|
-
string passengerRootConfig;
|
558
|
-
if (type == APACHE) {
|
559
|
-
passengerRootConfig = "PassengerRoot";
|
560
|
-
} else {
|
561
|
-
passengerRootConfig = "passenger_root";
|
562
|
-
}
|
563
|
-
throw RuntimeException("Unable to start the Phusion Passenger watchdog "
|
564
|
-
"because its executable (" + watchdogFilename + ") does "
|
565
|
-
"not exist. This probably means that your Phusion Passenger "
|
566
|
-
"installation is broken or incomplete, or that your '" +
|
567
|
-
passengerRootConfig + "' directive is set to the wrong value. "
|
568
|
-
"Please reinstall Phusion Passenger or fix your '" +
|
569
|
-
passengerRootConfig + "' directive, whichever is applicable.");
|
570
|
-
} else {
|
571
|
-
throw SystemException("Unable to start the Phusion Passenger watchdog (" +
|
572
|
-
watchdogFilename + ")", e);
|
573
|
-
}
|
574
|
-
}
|
575
|
-
|
576
|
-
|
577
|
-
/****** Read agents startup information ******/
|
578
|
-
|
579
|
-
UPDATE_TRACE_POINT();
|
580
|
-
allAgentsStarted = false;
|
581
|
-
|
582
|
-
while (!allAgentsStarted) {
|
583
|
-
try {
|
584
|
-
UPDATE_TRACE_POINT();
|
585
|
-
result = readArrayMessage(feedbackFd, args);
|
586
|
-
} catch (const SystemException &ex) {
|
587
|
-
killProcessGroupAndWait(&pid, 5000);
|
588
|
-
guard.clear();
|
589
|
-
throw SystemException("Unable to start the Phusion Passenger watchdog: "
|
590
|
-
"unable to read all agent startup information",
|
591
|
-
ex.code());
|
592
|
-
}
|
593
|
-
if (!result) {
|
594
|
-
UPDATE_TRACE_POINT();
|
595
|
-
inspectWatchdogCrashReason(pid);
|
596
|
-
}
|
597
|
-
|
598
|
-
if (args[0] == "HelperAgent info") {
|
599
|
-
UPDATE_TRACE_POINT();
|
600
|
-
if (args.size() == 5) {
|
601
|
-
this->pid = pid;
|
602
|
-
this->feedbackFd = feedbackFd;
|
603
|
-
requestSocketFilename = args[1];
|
604
|
-
requestSocketPassword = Base64::decode(args[2]);
|
605
|
-
messageSocketFilename = args[3];
|
606
|
-
messageSocketPassword = Base64::decode(args[4]);
|
607
|
-
this->serverInstanceDir = serverInstanceDir;
|
608
|
-
this->generation = generation;
|
609
|
-
} else {
|
610
|
-
killProcessGroupAndWait(&pid, 5000);
|
611
|
-
guard.clear();
|
612
|
-
throw IOException("Unable to start the Phusion Passenger watchdog: "
|
613
|
-
"it returned an invalid initialization feedback message");
|
614
|
-
}
|
615
|
-
} else if (args[0] == "LoggingServer info") {
|
616
|
-
UPDATE_TRACE_POINT();
|
617
|
-
if (args.size() == 3) {
|
618
|
-
loggingAgentRunningLocally = true;
|
619
|
-
loggingSocketAddress = args[1];
|
620
|
-
loggingSocketPassword = args[2];
|
621
|
-
} else {
|
622
|
-
killProcessGroupAndWait(&pid, 5000);
|
623
|
-
guard.clear();
|
624
|
-
throw IOException("Unable to start the Phusion Passenger watchdog: "
|
625
|
-
"it returned an invalid initialization feedback message");
|
626
|
-
}
|
627
|
-
} else if (args[0] == "All agents started") {
|
628
|
-
allAgentsStarted = true;
|
629
|
-
} else {
|
630
|
-
UPDATE_TRACE_POINT();
|
631
|
-
killProcessGroupAndWait(&pid, 5000);
|
632
|
-
guard.clear();
|
633
|
-
throw RuntimeException("One of the Passenger agents sent an unknown feedback message '" + args[0] + "'");
|
634
|
-
}
|
635
|
-
}
|
636
|
-
|
637
|
-
guard.clear();
|
638
|
-
}
|
639
|
-
}
|
640
|
-
|
641
|
-
/**
|
642
|
-
* Close any file descriptors that this object has, and make it so that the destructor
|
643
|
-
* doesn't try to shut down the agents.
|
644
|
-
*
|
645
|
-
* @post getPid() == 0
|
646
|
-
*/
|
647
|
-
void detach() {
|
648
|
-
feedbackFd.close();
|
649
|
-
pid = 0;
|
650
|
-
}
|
651
|
-
};
|
652
|
-
|
653
|
-
} // namespace Passenger
|
654
|
-
|
655
|
-
#endif /* _PASSENGER_AGENTS_STARTER_HPP_ */
|