passenger 3.0.9 → 3.0.10
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/NEWS +32 -0
- data/Rakefile +1 -1
- data/build/common_library.rb +6 -1
- data/build/config.rb +3 -1
- data/doc/Users guide Apache.html +120 -39
- data/doc/Users guide Apache.txt +64 -0
- data/doc/Users guide Nginx.html +50 -2
- data/doc/Users guide Nginx.txt +29 -0
- data/ext/apache2/Bucket.cpp +7 -5
- data/ext/apache2/Bucket.h +2 -1
- data/ext/apache2/Configuration.cpp +8 -0
- data/ext/apache2/Configuration.hpp +9 -5
- data/ext/apache2/HelperAgent.cpp +4 -5
- data/ext/apache2/Hooks.cpp +1 -6
- data/ext/boost/thread/exceptions.hpp +7 -1
- data/ext/boost/thread/locks.hpp +11 -11
- data/ext/common/AgentBase.cpp +21 -1
- data/ext/common/AgentsStarter.hpp +22 -21
- data/ext/common/ApplicationPool/Client.h +0 -8
- data/ext/common/ApplicationPool/Server.h +22 -21
- data/ext/common/Constants.h +1 -1
- data/ext/common/EventedMessageServer.h +6 -2
- data/ext/common/IniFile.h +4 -4
- data/ext/common/Logging.h +1 -1
- data/ext/common/LoggingAgent/LoggingServer.h +2 -2
- data/ext/common/LoggingAgent/Main.cpp +2 -2
- data/ext/common/MessageChannel.h +20 -62
- data/ext/common/MessageReadersWriters.h +4 -4
- data/ext/common/MessageServer.h +18 -18
- data/ext/common/Process.h +4 -5
- data/ext/common/Session.h +6 -40
- data/ext/common/SpawnManager.h +20 -25
- data/ext/common/Utils.cpp +1 -1
- data/ext/common/Utils/Dechunker.h +1 -1
- data/ext/common/Utils/MessageIO.h +109 -14
- data/ext/common/Utils/StreamBoyerMooreHorspool.h +20 -14
- data/ext/common/Utils/VariantMap.h +9 -27
- data/ext/common/Watchdog.cpp +53 -42
- data/ext/libev/config.h +122 -0
- data/ext/nginx/Configuration.c +62 -0
- data/ext/nginx/Configuration.h +5 -0
- data/ext/nginx/ContentHandler.c +46 -19
- data/ext/nginx/HelperAgent.cpp +6 -5
- data/ext/nginx/config +12 -12
- data/ext/oxt/system_calls.cpp +10 -1
- data/ext/ruby/extconf.rb +0 -1
- data/ext/ruby/passenger_native_support.c +2 -2
- data/helper-scripts/prespawn +1 -1
- data/lib/phusion_passenger.rb +4 -4
- data/lib/phusion_passenger/classic_rails/application_spawner.rb +2 -2
- data/lib/phusion_passenger/dependencies.rb +6 -1
- data/lib/phusion_passenger/platform_info.rb +9 -0
- data/lib/phusion_passenger/platform_info/compiler.rb +5 -0
- data/lib/phusion_passenger/platform_info/operating_system.rb +1 -1
- data/lib/phusion_passenger/platform_info/ruby.rb +5 -5
- data/lib/phusion_passenger/rack/application_spawner.rb +6 -3
- data/lib/phusion_passenger/utils.rb +2 -2
- data/lib/phusion_passenger/wsgi/application_spawner.rb +1 -1
- data/resources/mime.types +2 -0
- data/test/cxx/LoggingTest.cpp +10 -12
- data/test/cxx/MessageIOTest.cpp +53 -3
- data/test/cxx/MessageReadersWritersTest.cpp +5 -2
- data/test/cxx/MessageServerTest.cpp +3 -1
- data/test/integration_tests/nginx_tests.rb +14 -1
- data/test/stub/rack/config.ru +2 -0
- data/test/tut/tut.h +9 -3
- metadata +5 -4
@@ -33,13 +33,13 @@
|
|
33
33
|
#include <sys/types.h>
|
34
34
|
#include <cstring>
|
35
35
|
#include <arpa/inet.h>
|
36
|
-
#include
|
37
|
-
#include
|
38
|
-
#include
|
36
|
+
#include <StaticString.h>
|
37
|
+
#include <Exceptions.h>
|
38
|
+
#include <Utils/MemZeroGuard.h>
|
39
39
|
|
40
40
|
/**
|
41
41
|
* This file provides a bunch of classes for reading and writing messages in the
|
42
|
-
*
|
42
|
+
* MessageIO format. Unlike MessageIO functions, whose operations take control over
|
43
43
|
* the I/O handle and may block, these classes act like parsers and data generators.
|
44
44
|
* To read messages one must feed data to them. To write messages one must instruct
|
45
45
|
* the classes to generate a bunch of data. These classes will never block, making
|
data/ext/common/MessageServer.h
CHANGED
@@ -70,7 +70,7 @@ using namespace oxt;
|
|
70
70
|
* - Designed for simple request/response cycles. That is, a client sends a request, and
|
71
71
|
* the server may respond with arbitrary data. The server does not respond sporadically,
|
72
72
|
* i.e. it only responds after a request.
|
73
|
-
* - Requests are
|
73
|
+
* - Requests are MessageIO array messages.
|
74
74
|
* - Connections are authenticated. Connecting clients must send a username and password,
|
75
75
|
* which are then checked against an accounts database. The associated account is known
|
76
76
|
* throughout the entire connection life time so that it's possible to implement
|
@@ -136,7 +136,7 @@ using namespace oxt;
|
|
136
136
|
* {
|
137
137
|
* if (args[0] == "ping") {
|
138
138
|
* MyContext *myContext = (MyContext *) specificContext.get();
|
139
|
-
* commonContext.
|
139
|
+
* writeArrayMessage(commonContext.fd, "pong", toString(specificContext->count).c_str(), NULL);
|
140
140
|
* specificContext->count++;
|
141
141
|
* return true;
|
142
142
|
* } else {
|
@@ -195,7 +195,7 @@ public:
|
|
195
195
|
|
196
196
|
/** Returns a string representation for this client context. */
|
197
197
|
string name() {
|
198
|
-
return toString(
|
198
|
+
return toString(fd);
|
199
199
|
}
|
200
200
|
|
201
201
|
/**
|
@@ -210,10 +210,10 @@ public:
|
|
210
210
|
void requireRights(Account::Rights rights) {
|
211
211
|
if (!account->hasRights(rights)) {
|
212
212
|
P_TRACE(2, "Security error: insufficient rights to execute this command.");
|
213
|
-
|
213
|
+
writeArrayMessage(fd, "SecurityException", "Insufficient rights to execute this command.", NULL);
|
214
214
|
throw SecurityException("Insufficient rights to execute this command.");
|
215
215
|
} else {
|
216
|
-
|
216
|
+
writeArrayMessage(fd, "Passed security", NULL);
|
217
217
|
}
|
218
218
|
}
|
219
219
|
};
|
@@ -356,45 +356,45 @@ protected:
|
|
356
356
|
*
|
357
357
|
* @return A smart pointer to an Account object, or NULL if authentication failed.
|
358
358
|
*/
|
359
|
-
AccountPtr authenticate(FileDescriptor &client) {
|
360
|
-
MessageChannel channel(client);
|
359
|
+
AccountPtr authenticate(const FileDescriptor &client) {
|
361
360
|
string username, password;
|
362
361
|
MemZeroGuard passwordGuard(password);
|
363
362
|
unsigned long long timeout = loginTimeout;
|
364
363
|
|
365
364
|
try {
|
366
|
-
|
365
|
+
writeArrayMessage(client, &timeout, "version", "1", NULL);
|
367
366
|
|
368
367
|
try {
|
369
|
-
if (!
|
368
|
+
if (!readScalarMessage(client, username, MESSAGE_SERVER_MAX_USERNAME_SIZE, &timeout)) {
|
370
369
|
return AccountPtr();
|
371
370
|
}
|
372
371
|
} catch (const SecurityException &) {
|
373
|
-
|
372
|
+
writeArrayMessage(client, &timeout, "The supplied username is too long.", NULL);
|
374
373
|
return AccountPtr();
|
375
374
|
}
|
376
375
|
|
377
376
|
try {
|
378
|
-
if (!
|
377
|
+
if (!readScalarMessage(client, password, MESSAGE_SERVER_MAX_PASSWORD_SIZE, &timeout)) {
|
379
378
|
return AccountPtr();
|
380
379
|
}
|
381
380
|
} catch (const SecurityException &) {
|
382
|
-
|
381
|
+
writeArrayMessage(client, &timeout, "The supplied password is too long.", NULL);
|
383
382
|
return AccountPtr();
|
384
383
|
}
|
385
384
|
|
386
385
|
AccountPtr account = accountsDatabase->authenticate(username, password);
|
387
386
|
passwordGuard.zeroNow();
|
388
387
|
if (account == NULL) {
|
389
|
-
|
388
|
+
writeArrayMessage(client, &timeout, "Invalid username or password.", NULL);
|
390
389
|
return AccountPtr();
|
391
390
|
} else {
|
392
|
-
|
391
|
+
writeArrayMessage(client, &timeout, "ok", NULL);
|
393
392
|
return account;
|
394
393
|
}
|
395
394
|
} catch (const SystemException &) {
|
396
395
|
return AccountPtr();
|
397
396
|
} catch (const TimeoutException &) {
|
397
|
+
P_WARN("Login timeout");
|
398
398
|
return AccountPtr();
|
399
399
|
}
|
400
400
|
}
|
@@ -439,7 +439,7 @@ protected:
|
|
439
439
|
/**
|
440
440
|
* The main function for a thread which handles a client.
|
441
441
|
*/
|
442
|
-
void clientHandlingMainLoop(FileDescriptor
|
442
|
+
void clientHandlingMainLoop(FileDescriptor client) {
|
443
443
|
TRACE_POINT();
|
444
444
|
vector<string> args;
|
445
445
|
|
@@ -459,7 +459,7 @@ protected:
|
|
459
459
|
|
460
460
|
while (!this_thread::interruption_requested()) {
|
461
461
|
UPDATE_TRACE_POINT();
|
462
|
-
if (!commonContext.
|
462
|
+
if (!readArrayMessage(commonContext.fd, args)) {
|
463
463
|
// Client closed connection.
|
464
464
|
break;
|
465
465
|
}
|
@@ -503,7 +503,7 @@ public:
|
|
503
503
|
MessageServer(const string &socketFilename, AccountsDatabasePtr accountsDatabase) {
|
504
504
|
this->socketFilename = socketFilename;
|
505
505
|
this->accountsDatabase = accountsDatabase;
|
506
|
-
loginTimeout =
|
506
|
+
loginTimeout = 2000000;
|
507
507
|
startListening();
|
508
508
|
}
|
509
509
|
|
@@ -562,7 +562,7 @@ public:
|
|
562
562
|
}
|
563
563
|
|
564
564
|
/**
|
565
|
-
* Sets the maximum number of
|
565
|
+
* Sets the maximum number of microseconds that clients may spend on logging in.
|
566
566
|
* Clients that take longer are disconnected.
|
567
567
|
*
|
568
568
|
* @pre timeout != 0
|
data/ext/common/Process.h
CHANGED
@@ -36,11 +36,10 @@
|
|
36
36
|
#include <unistd.h>
|
37
37
|
#include <errno.h>
|
38
38
|
|
39
|
-
#include
|
40
|
-
#include
|
41
|
-
#include
|
42
|
-
#include
|
43
|
-
#include "Utils.h"
|
39
|
+
#include <Session.h>
|
40
|
+
#include <Exceptions.h>
|
41
|
+
#include <Logging.h>
|
42
|
+
#include <Utils.h>
|
44
43
|
|
45
44
|
namespace Passenger {
|
46
45
|
|
data/ext/common/Session.h
CHANGED
@@ -41,11 +41,11 @@
|
|
41
41
|
#include <oxt/backtrace.hpp>
|
42
42
|
#include <oxt/system_calls.hpp>
|
43
43
|
|
44
|
-
#include
|
45
|
-
#include
|
46
|
-
#include
|
47
|
-
#include
|
48
|
-
#include
|
44
|
+
#include <StaticString.h>
|
45
|
+
#include <Exceptions.h>
|
46
|
+
#include <Utils/StrIntUtils.h>
|
47
|
+
#include <Utils/IOUtils.h>
|
48
|
+
#include <Utils/MessageIO.h>
|
49
49
|
|
50
50
|
namespace Passenger {
|
51
51
|
|
@@ -159,7 +159,7 @@ public:
|
|
159
159
|
"because the I/O stream has already been closed or discarded.");
|
160
160
|
}
|
161
161
|
try {
|
162
|
-
|
162
|
+
writeScalarMessage(stream, headers, size);
|
163
163
|
} catch (SystemException &e) {
|
164
164
|
e.setBriefMessage("An error occured while writing headers "
|
165
165
|
"to the request handler");
|
@@ -222,32 +222,6 @@ public:
|
|
222
222
|
*/
|
223
223
|
virtual int getStream() const = 0;
|
224
224
|
|
225
|
-
/**
|
226
|
-
* Set the timeout value for reading data from the I/O channel.
|
227
|
-
* If no data can be read within the timeout period, then the
|
228
|
-
* read call will fail with error EAGAIN or EWOULDBLOCK.
|
229
|
-
*
|
230
|
-
* @pre The I/O channel hasn't been closed or discarded.
|
231
|
-
* @pre initiated()
|
232
|
-
* @param msec The timeout, in milliseconds. If 0 is given,
|
233
|
-
* there will be no timeout.
|
234
|
-
* @throws SystemException Cannot set the timeout.
|
235
|
-
*/
|
236
|
-
virtual void setReaderTimeout(unsigned int msec) = 0;
|
237
|
-
|
238
|
-
/**
|
239
|
-
* Set the timeout value for writing data from the I/O channel.
|
240
|
-
* If no data can be written within the timeout period, then the
|
241
|
-
* write call will fail with error EAGAIN or EWOULDBLOCK.
|
242
|
-
*
|
243
|
-
* @pre The I/O channel hasn't been closed or discarded.
|
244
|
-
* @pre initiated()
|
245
|
-
* @param msec The timeout, in milliseconds. If 0 is given,
|
246
|
-
* there will be no timeout.
|
247
|
-
* @throws SystemException Cannot set the timeout.
|
248
|
-
*/
|
249
|
-
virtual void setWriterTimeout(unsigned int msec) = 0;
|
250
|
-
|
251
225
|
/**
|
252
226
|
* Indicate that we don't want to read data anymore from the I/O channel.
|
253
227
|
* Calling this method after closeStream()/discardStream() is called will
|
@@ -397,14 +371,6 @@ public:
|
|
397
371
|
return fd;
|
398
372
|
}
|
399
373
|
|
400
|
-
virtual void setReaderTimeout(unsigned int msec) {
|
401
|
-
MessageChannel(fd).setReadTimeout(msec);
|
402
|
-
}
|
403
|
-
|
404
|
-
virtual void setWriterTimeout(unsigned int msec) {
|
405
|
-
MessageChannel(fd).setWriteTimeout(msec);
|
406
|
-
}
|
407
|
-
|
408
374
|
virtual void shutdownReader() {
|
409
375
|
TRACE_POINT();
|
410
376
|
if (fd != -1) {
|
data/ext/common/SpawnManager.h
CHANGED
@@ -45,18 +45,18 @@
|
|
45
45
|
#include <pwd.h>
|
46
46
|
#include <signal.h>
|
47
47
|
|
48
|
-
#include
|
49
|
-
#include
|
50
|
-
#include
|
51
|
-
#include
|
52
|
-
#include
|
53
|
-
#include
|
54
|
-
#include
|
55
|
-
#include
|
56
|
-
#include
|
57
|
-
#include
|
58
|
-
#include
|
59
|
-
#include
|
48
|
+
#include <AbstractSpawnManager.h>
|
49
|
+
#include <ServerInstanceDir.h>
|
50
|
+
#include <FileDescriptor.h>
|
51
|
+
#include <Constants.h>
|
52
|
+
#include <AccountsDatabase.h>
|
53
|
+
#include <RandomGenerator.h>
|
54
|
+
#include <Exceptions.h>
|
55
|
+
#include <Logging.h>
|
56
|
+
#include <Utils/Base64.h>
|
57
|
+
#include <Utils/SystemTime.h>
|
58
|
+
#include <Utils/IOUtils.h>
|
59
|
+
#include <Utils/MessageIO.h>
|
60
60
|
|
61
61
|
namespace Passenger {
|
62
62
|
|
@@ -268,9 +268,8 @@ private:
|
|
268
268
|
FileDescriptor connect() const {
|
269
269
|
TRACE_POINT();
|
270
270
|
FileDescriptor fd = connectToUnixServer(socketFilename.c_str());
|
271
|
-
MessageChannel channel(fd);
|
272
271
|
UPDATE_TRACE_POINT();
|
273
|
-
|
272
|
+
writeScalarMessage(fd, socketPassword);
|
274
273
|
return fd;
|
275
274
|
}
|
276
275
|
|
@@ -286,13 +285,11 @@ private:
|
|
286
285
|
ProcessPtr sendSpawnCommand(const PoolOptions &options) {
|
287
286
|
TRACE_POINT();
|
288
287
|
FileDescriptor connection;
|
289
|
-
MessageChannel channel;
|
290
288
|
|
291
289
|
P_DEBUG("Spawning a new application process for " << options.appRoot << "...");
|
292
290
|
|
293
291
|
try {
|
294
292
|
connection = connect();
|
295
|
-
channel = MessageChannel(connection);
|
296
293
|
} catch (const SystemException &e) {
|
297
294
|
throw SpawnException(string("Could not connect to the spawn server: ") +
|
298
295
|
e.sys());
|
@@ -337,7 +334,7 @@ private:
|
|
337
334
|
args.push_back(Base64::encode(password));
|
338
335
|
}
|
339
336
|
|
340
|
-
|
337
|
+
writeArrayMessage(connection, args);
|
341
338
|
} catch (const SystemException &e) {
|
342
339
|
throw SpawnException(string("Could not write 'spawn_application' "
|
343
340
|
"command to the spawn server: ") + e.sys());
|
@@ -346,7 +343,7 @@ private:
|
|
346
343
|
try {
|
347
344
|
UPDATE_TRACE_POINT();
|
348
345
|
// Read status.
|
349
|
-
if (!
|
346
|
+
if (!readArrayMessage(connection, args)) {
|
350
347
|
throw SpawnException("The spawn server has exited unexpectedly.");
|
351
348
|
}
|
352
349
|
if (args.size() != 1) {
|
@@ -356,7 +353,7 @@ private:
|
|
356
353
|
UPDATE_TRACE_POINT();
|
357
354
|
string errorPage;
|
358
355
|
|
359
|
-
if (!
|
356
|
+
if (!readScalarMessage(connection, errorPage)) {
|
360
357
|
throw SpawnException("The spawn server has exited unexpectedly.");
|
361
358
|
}
|
362
359
|
throw SpawnException("An error occured while spawning the application.",
|
@@ -367,7 +364,7 @@ private:
|
|
367
364
|
|
368
365
|
// Read application info.
|
369
366
|
UPDATE_TRACE_POINT();
|
370
|
-
if (!
|
367
|
+
if (!readArrayMessage(connection, args)) {
|
371
368
|
throw SpawnException("The spawn server has exited unexpectedly.");
|
372
369
|
}
|
373
370
|
if (args.size() != 3) {
|
@@ -380,7 +377,7 @@ private:
|
|
380
377
|
|
381
378
|
UPDATE_TRACE_POINT();
|
382
379
|
for (i = 0; i < nServerSockets; i++) {
|
383
|
-
if (!
|
380
|
+
if (!readArrayMessage(connection, args)) {
|
384
381
|
throw SpawnException("The spawn server has exited unexpectedly.");
|
385
382
|
}
|
386
383
|
if (args.size() != 3) {
|
@@ -398,7 +395,7 @@ private:
|
|
398
395
|
|
399
396
|
UPDATE_TRACE_POINT();
|
400
397
|
try {
|
401
|
-
ownerPipe =
|
398
|
+
ownerPipe = readFileDescriptorWithNegotiation(connection);
|
402
399
|
} catch (const SystemException &e) {
|
403
400
|
throw SpawnException(string("Could not receive the spawned "
|
404
401
|
"application's owner pipe from the spawn server: ") +
|
@@ -454,11 +451,9 @@ private:
|
|
454
451
|
void sendReloadCommand(const string &appRoot) {
|
455
452
|
TRACE_POINT();
|
456
453
|
FileDescriptor connection;
|
457
|
-
MessageChannel channel;
|
458
454
|
|
459
455
|
try {
|
460
456
|
connection = connect();
|
461
|
-
channel = MessageChannel(connection);
|
462
457
|
} catch (SystemException &e) {
|
463
458
|
e.setBriefMessage("Could not connect to the spawn server");
|
464
459
|
throw;
|
@@ -468,7 +463,7 @@ private:
|
|
468
463
|
}
|
469
464
|
|
470
465
|
try {
|
471
|
-
|
466
|
+
writeArrayMessage(connection, "reload", appRoot.c_str(), NULL);
|
472
467
|
} catch (SystemException &e) {
|
473
468
|
e.setBriefMessage("Could not write 'reload' command to the spawn server");
|
474
469
|
throw;
|
data/ext/common/Utils.cpp
CHANGED
@@ -33,6 +33,7 @@
|
|
33
33
|
#include <sys/types.h>
|
34
34
|
#include <sys/wait.h>
|
35
35
|
#include <sys/resource.h>
|
36
|
+
#include <sys/uio.h>
|
36
37
|
#include <libgen.h>
|
37
38
|
#include <fcntl.h>
|
38
39
|
#include <poll.h>
|
@@ -41,7 +42,6 @@
|
|
41
42
|
#include <unistd.h>
|
42
43
|
#include <signal.h>
|
43
44
|
#include <FileDescriptor.h>
|
44
|
-
#include <MessageChannel.h>
|
45
45
|
#include <MessageServer.h>
|
46
46
|
#include <ResourceLocator.h>
|
47
47
|
#include <Exceptions.h>
|
@@ -300,26 +300,28 @@ readArrayMessage(int fd, unsigned long long *timeout = NULL) {
|
|
300
300
|
* total number of microseconds spent on reading will be deducted
|
301
301
|
* from <tt>timeout</tt>.
|
302
302
|
* Pass NULL if you do not want to enforce a timeout.
|
303
|
-
* @
|
303
|
+
* @return True if a scalar message was read, false if EOF was encountered.
|
304
304
|
* @throws SystemException Something went wrong.
|
305
305
|
* @throws SecurityException The message body is larger than allowed by maxSize.
|
306
306
|
* @throws TimeoutException Unable to read the necessary data within
|
307
307
|
* <tt>timeout</tt> microseconds.
|
308
308
|
* @throws boost::thread_interrupted
|
309
309
|
*/
|
310
|
-
inline
|
311
|
-
readScalarMessage(int fd, unsigned int maxSize = 0, unsigned long long *timeout = NULL) {
|
310
|
+
inline bool
|
311
|
+
readScalarMessage(int fd, string &output, unsigned int maxSize = 0, unsigned long long *timeout = NULL) {
|
312
312
|
uint32_t size;
|
313
313
|
if (!readUint32(fd, size, timeout)) {
|
314
|
-
|
314
|
+
return false;
|
315
315
|
}
|
316
316
|
|
317
317
|
if (maxSize != 0 && size > (uint32_t) maxSize) {
|
318
318
|
throw SecurityException("The scalar message body is larger than the size limit");
|
319
319
|
}
|
320
320
|
|
321
|
-
string output;
|
322
321
|
unsigned int remaining = size;
|
322
|
+
if (OXT_UNLIKELY(!output.empty())) {
|
323
|
+
output.clear();
|
324
|
+
}
|
323
325
|
output.reserve(size);
|
324
326
|
if (OXT_LIKELY(remaining > 0)) {
|
325
327
|
char buf[1024 * 32];
|
@@ -329,13 +331,43 @@ readScalarMessage(int fd, unsigned int maxSize = 0, unsigned long long *timeout
|
|
329
331
|
unsigned int blockSize = min((unsigned int) sizeof(buf), remaining);
|
330
332
|
|
331
333
|
if (readExact(fd, buf, blockSize, timeout) != blockSize) {
|
332
|
-
|
334
|
+
return false;
|
333
335
|
}
|
334
336
|
output.append(buf, blockSize);
|
335
337
|
remaining -= blockSize;
|
336
338
|
}
|
337
339
|
}
|
338
|
-
return
|
340
|
+
return true;
|
341
|
+
}
|
342
|
+
|
343
|
+
/**
|
344
|
+
* Reads a scalar message from the given file descriptor.
|
345
|
+
*
|
346
|
+
* @param maxSize The maximum number of bytes that may be read. If the
|
347
|
+
* scalar to read is larger than this, then a SecurityException
|
348
|
+
* will be thrown. Set to 0 for no size limit.
|
349
|
+
* @param timeout A pointer to an integer, which specifies the maximum number of
|
350
|
+
* microseconds that may be spent on reading the necessary data.
|
351
|
+
* If the timeout expired then TimeoutException will be thrown.
|
352
|
+
* If this function returns without throwing an exception, then the
|
353
|
+
* total number of microseconds spent on reading will be deducted
|
354
|
+
* from <tt>timeout</tt>.
|
355
|
+
* Pass NULL if you do not want to enforce a timeout.
|
356
|
+
* @throws EOFException End-of-file was reached before a full integer could be read.
|
357
|
+
* @throws SystemException Something went wrong.
|
358
|
+
* @throws SecurityException The message body is larger than allowed by maxSize.
|
359
|
+
* @throws TimeoutException Unable to read the necessary data within
|
360
|
+
* <tt>timeout</tt> microseconds.
|
361
|
+
* @throws boost::thread_interrupted
|
362
|
+
*/
|
363
|
+
inline string
|
364
|
+
readScalarMessage(int fd, unsigned int maxSize = 0, unsigned long long *timeout = NULL) {
|
365
|
+
string output;
|
366
|
+
if (readScalarMessage(fd, output, maxSize, timeout)) {
|
367
|
+
return output;
|
368
|
+
} else {
|
369
|
+
throw EOFException("EOF encountered before a full scalar message could be read");
|
370
|
+
}
|
339
371
|
}
|
340
372
|
|
341
373
|
|
@@ -402,7 +434,7 @@ writeUint32(int fd, uint32_t value, unsigned long long *timeout = NULL) {
|
|
402
434
|
*/
|
403
435
|
template<typename Collection>
|
404
436
|
inline void
|
405
|
-
|
437
|
+
writeArrayMessageEx(int fd, const Collection &args, unsigned long long *timeout = NULL) {
|
406
438
|
typename Collection::const_iterator it, end = args.end();
|
407
439
|
uint16_t bodySize = 0;
|
408
440
|
|
@@ -425,20 +457,78 @@ writeArrayMessage(int fd, const Collection &args, unsigned long long *timeout =
|
|
425
457
|
writeExact(fd, data.get(), sizeof(uint16_t) + bodySize, timeout);
|
426
458
|
}
|
427
459
|
|
460
|
+
inline void
|
461
|
+
writeArrayMessage(int fd, const vector<StaticString> &args, unsigned long long *timeout = NULL) {
|
462
|
+
writeArrayMessageEx(fd, args, timeout);
|
463
|
+
}
|
464
|
+
|
465
|
+
inline void
|
466
|
+
writeArrayMessage(int fd, const vector<string> &args, unsigned long long *timeout = NULL) {
|
467
|
+
writeArrayMessageEx(fd, args, timeout);
|
468
|
+
}
|
469
|
+
|
470
|
+
inline void
|
471
|
+
writeArrayMessage(int fd, const StaticString args[], unsigned int nargs, unsigned long long *timeout = NULL) {
|
472
|
+
unsigned int i;
|
473
|
+
uint16_t bodySize = 0;
|
474
|
+
|
475
|
+
for (i = 0; i < nargs; i++) {
|
476
|
+
bodySize += args[i].size() + 1;
|
477
|
+
}
|
478
|
+
|
479
|
+
scoped_array<char> data(new char[sizeof(uint16_t) + bodySize]);
|
480
|
+
uint16_t header = htons(bodySize);
|
481
|
+
memcpy(data.get(), &header, sizeof(uint16_t));
|
482
|
+
|
483
|
+
char *dataEnd = data.get() + sizeof(uint16_t);
|
484
|
+
for (i = 0; i < nargs; i++) {
|
485
|
+
memcpy(dataEnd, args[i].data(), args[i].size());
|
486
|
+
dataEnd += args[i].size();
|
487
|
+
*dataEnd = '\0';
|
488
|
+
dataEnd++;
|
489
|
+
}
|
490
|
+
|
491
|
+
writeExact(fd, data.get(), sizeof(uint16_t) + bodySize, timeout);
|
492
|
+
}
|
493
|
+
|
428
494
|
inline void
|
429
495
|
writeArrayMessage(int fd, const StaticString &name, va_list &ap, unsigned long long *timeout = NULL) {
|
430
|
-
|
496
|
+
StaticString args[10];
|
497
|
+
unsigned int nargs = 1;
|
498
|
+
bool done = false;
|
431
499
|
|
432
|
-
args
|
433
|
-
|
500
|
+
args[0] = name;
|
501
|
+
do {
|
434
502
|
const char *arg = va_arg(ap, const char *);
|
435
503
|
if (arg == NULL) {
|
436
|
-
|
504
|
+
done = true;
|
437
505
|
} else {
|
438
|
-
args
|
506
|
+
args[nargs] = arg;
|
507
|
+
nargs++;
|
439
508
|
}
|
509
|
+
} while (!done && nargs < sizeof(args) / sizeof(StaticString));
|
510
|
+
|
511
|
+
if (done) {
|
512
|
+
writeArrayMessage(fd, args, nargs, timeout);
|
513
|
+
} else {
|
514
|
+
// Arguments don't fit in static array. Use dynamic
|
515
|
+
// array instead.
|
516
|
+
vector<StaticString> dyn_args;
|
517
|
+
|
518
|
+
for (unsigned int i = 0; i < nargs; i++) {
|
519
|
+
dyn_args.push_back(args[i]);
|
520
|
+
}
|
521
|
+
do {
|
522
|
+
const char *arg = va_arg(ap, const char *);
|
523
|
+
if (arg == NULL) {
|
524
|
+
done = true;
|
525
|
+
} else {
|
526
|
+
dyn_args.push_back(arg);
|
527
|
+
}
|
528
|
+
} while (!done);
|
529
|
+
|
530
|
+
writeArrayMessage(fd, dyn_args, timeout);
|
440
531
|
}
|
441
|
-
writeArrayMessage(fd, args, timeout);
|
442
532
|
}
|
443
533
|
|
444
534
|
struct _VaGuard {
|
@@ -464,6 +554,11 @@ writeArrayMessage(int fd, const StaticString &name, ...) {
|
|
464
554
|
writeArrayMessage(fd, name, ap);
|
465
555
|
}
|
466
556
|
|
557
|
+
inline void
|
558
|
+
writeArrayMessage(int fd, const char *name) {
|
559
|
+
abort();
|
560
|
+
}
|
561
|
+
|
467
562
|
/** Version of writeArrayMessage() that accepts a variadic list of 'const char *'
|
468
563
|
* arguments as message elements, with timeout support. The list must be terminated
|
469
564
|
* with a NULL.
|