passenger 3.0.8 → 3.0.9
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 +9 -0
- data/bin/passenger-install-nginx-module +1 -1
- data/build/basics.rb +0 -1
- data/build/cxx_tests.rb +5 -0
- data/build/rpm.rb +1 -1
- data/doc/Users guide Apache.html +1 -1
- data/doc/Users guide Nginx.html +1 -1
- data/ext/apache2/Configuration.cpp +12 -0
- data/ext/apache2/Configuration.hpp +12 -1
- data/ext/apache2/Hooks.cpp +2 -0
- data/ext/common/AgentsStarter.cpp +4 -0
- data/ext/common/AgentsStarter.h +2 -0
- data/ext/common/AgentsStarter.hpp +4 -0
- data/ext/common/Constants.h +1 -1
- data/ext/common/Logging.h +481 -261
- data/ext/common/LoggingAgent/LoggingServer.h +10 -4
- data/ext/common/LoggingAgent/Main.cpp +7 -2
- data/ext/common/LoggingAgent/RemoteSender.h +25 -3
- data/ext/common/MessageChannel.h +18 -227
- data/ext/common/MessageClient.h +95 -92
- data/ext/common/Utils/IOUtils.cpp +114 -1
- data/ext/common/Utils/IOUtils.h +57 -1
- data/ext/common/Utils/MessageIO.h +576 -0
- data/ext/nginx/Configuration.c +35 -0
- data/ext/nginx/Configuration.h +2 -0
- data/ext/nginx/ContentHandler.c +17 -6
- data/ext/nginx/ngx_http_passenger_module.c +8 -0
- data/lib/phusion_passenger.rb +2 -2
- data/lib/phusion_passenger/analytics_logger.rb +174 -117
- data/lib/phusion_passenger/app_process.rb +14 -2
- data/test/cxx/CxxTestMain.cpp +14 -19
- data/test/cxx/IOUtilsTest.cpp +68 -18
- data/test/cxx/LoggingTest.cpp +20 -24
- data/test/cxx/MessageChannelTest.cpp +1 -1
- data/test/cxx/MessageIOTest.cpp +310 -0
- data/test/cxx/TestSupport.cpp +47 -0
- data/test/cxx/TestSupport.h +8 -0
- data/test/ruby/analytics_logger_spec.rb +20 -28
- data/test/tut/tut.h +2 -0
- metadata +11 -11
- data/build/rdoctask.rb +0 -209
- data/test/cxx/HttpStatusExtractorTest.cpp +0 -198
@@ -0,0 +1,576 @@
|
|
1
|
+
/*
|
2
|
+
* Phusion Passenger - http://www.modrails.com/
|
3
|
+
* Copyright (c) 2011 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_MESSAGE_IO_H_
|
26
|
+
#define _PASSENGER_MESSAGE_IO_H_
|
27
|
+
|
28
|
+
/**
|
29
|
+
* This file contains functions for reading and writing structured messages over
|
30
|
+
* I/O channels. Supported message types are as follows.
|
31
|
+
*
|
32
|
+
* == 16-bit and 32-bit integers
|
33
|
+
* Their raw formats are binary, in big endian.
|
34
|
+
*
|
35
|
+
* == Array of strings (array messages)
|
36
|
+
* Each string may contain arbitrary data except for the NUL byte.
|
37
|
+
* Its raw format consists of a 16-bit big endian size header
|
38
|
+
* and a body containing all the strings in the array, each terminated
|
39
|
+
* by a NUL byte. The size header specifies the raw size of the body.
|
40
|
+
*
|
41
|
+
* == Arbitary binary strings (scalar messages)
|
42
|
+
* Its raw format consists of a 32-bit big endian size header
|
43
|
+
* followed by the raw string data.
|
44
|
+
*
|
45
|
+
* == File descriptor passing and negotiation
|
46
|
+
* Unix socket file descriptor passing is not safe without some kind
|
47
|
+
* of negotiation protocol. If one side passes a file descriptor, and
|
48
|
+
* the other side accidentally read()s past the normal data then it
|
49
|
+
* will read away the passed file descriptor too without actually
|
50
|
+
* receiving it.
|
51
|
+
*
|
52
|
+
* For example suppose that side A looks like this:
|
53
|
+
*
|
54
|
+
* read(fd, buf, 1024)
|
55
|
+
* read_io(fd)
|
56
|
+
*
|
57
|
+
* and side B:
|
58
|
+
*
|
59
|
+
* write(fd, buf, 100)
|
60
|
+
* send_io(fd_to_pass)
|
61
|
+
*
|
62
|
+
* If B completes both write() and send_io(), then A's read() call
|
63
|
+
* reads past the 100 bytes that B sent. On some platforms, like
|
64
|
+
* Linux, this will cause read_io() to fail. And it just so happens
|
65
|
+
* that Ruby's IO#read method slurps more than just the given amount
|
66
|
+
* of bytes.
|
67
|
+
*
|
68
|
+
* In order to solve this problem, we wrap the actual file descriptor
|
69
|
+
* passing/reading code into a negotiation protocol to ensure that
|
70
|
+
* this situation can never happen.
|
71
|
+
*/
|
72
|
+
|
73
|
+
// For ntohl/htonl/ntohs/htons.
|
74
|
+
#include <sys/types.h>
|
75
|
+
#include <arpa/inet.h>
|
76
|
+
#include <netinet/in.h>
|
77
|
+
|
78
|
+
#include <algorithm>
|
79
|
+
#include <string>
|
80
|
+
#include <vector>
|
81
|
+
#include <cstring>
|
82
|
+
#include <cstdarg>
|
83
|
+
|
84
|
+
#include <boost/cstdint.hpp>
|
85
|
+
#include <boost/bind.hpp>
|
86
|
+
#include <boost/scoped_array.hpp>
|
87
|
+
|
88
|
+
#include <oxt/macros.hpp>
|
89
|
+
|
90
|
+
#include <StaticString.h>
|
91
|
+
#include <Exceptions.h>
|
92
|
+
#include <Utils/MemZeroGuard.h>
|
93
|
+
#include <Utils/ScopeGuard.h>
|
94
|
+
#include <Utils/IOUtils.h>
|
95
|
+
#include <Utils/StrIntUtils.h>
|
96
|
+
|
97
|
+
|
98
|
+
namespace Passenger {
|
99
|
+
|
100
|
+
using namespace std;
|
101
|
+
using namespace boost;
|
102
|
+
|
103
|
+
/**
|
104
|
+
* Reads a 16-bit unsigned integer from the given file descriptor. The result
|
105
|
+
* is put into 'output'.
|
106
|
+
*
|
107
|
+
* @param timeout A pointer to an integer, which specifies the maximum number of
|
108
|
+
* microseconds that may be spent on reading the necessary data.
|
109
|
+
* If the timeout expired then TimeoutException will be thrown.
|
110
|
+
* If this function returns without throwing an exception, then the
|
111
|
+
* total number of microseconds spent on reading will be deducted
|
112
|
+
* from <tt>timeout</tt>.
|
113
|
+
* Pass NULL if you do not want to enforce a timeout.
|
114
|
+
* @return True if reading was successful, false if end-of-file was prematurely reached.
|
115
|
+
* @throws SystemException Something went wrong.
|
116
|
+
* @throws TimeoutException Unable to read the necessary data within
|
117
|
+
* <tt>timeout</tt> microseconds.
|
118
|
+
* @throws boost::thread_interrupted
|
119
|
+
*/
|
120
|
+
inline bool
|
121
|
+
readUint16(int fd, uint16_t &output, unsigned long long *timeout = NULL) {
|
122
|
+
uint16_t temp;
|
123
|
+
|
124
|
+
if (readExact(fd, &temp, sizeof(uint16_t), timeout) == sizeof(uint16_t)) {
|
125
|
+
output = ntohs(temp);
|
126
|
+
return true;
|
127
|
+
} else {
|
128
|
+
return false;
|
129
|
+
}
|
130
|
+
}
|
131
|
+
|
132
|
+
/**
|
133
|
+
* Reads a 16-bit unsigned integer from the given file descriptor.
|
134
|
+
*
|
135
|
+
* @param timeout A pointer to an integer, which specifies the maximum number of
|
136
|
+
* microseconds that may be spent on reading the necessary data.
|
137
|
+
* If the timeout expired then TimeoutException will be thrown.
|
138
|
+
* If this function returns without throwing an exception, then the
|
139
|
+
* total number of microseconds spent on reading will be deducted
|
140
|
+
* from <tt>timeout</tt>.
|
141
|
+
* Pass NULL if you do not want to enforce a timeout.
|
142
|
+
* @throws EOFException End-of-file was reached before a full integer could be read.
|
143
|
+
* @throws SystemException Something went wrong.
|
144
|
+
* @throws TimeoutException Unable to read the necessary data within
|
145
|
+
* <tt>timeout</tt> microseconds.
|
146
|
+
* @throws boost::thread_interrupted
|
147
|
+
*/
|
148
|
+
inline uint16_t
|
149
|
+
readUint16(int fd, unsigned long long *timeout = NULL) {
|
150
|
+
uint16_t temp;
|
151
|
+
|
152
|
+
if (readUint16(fd, temp, timeout)) {
|
153
|
+
return temp;
|
154
|
+
} else {
|
155
|
+
throw EOFException("EOF encountered before a full 16-bit integer could be read");
|
156
|
+
}
|
157
|
+
}
|
158
|
+
|
159
|
+
/**
|
160
|
+
* Reads a 32-bit unsigned integer from the given file descriptor. The result
|
161
|
+
* is put into 'output'.
|
162
|
+
*
|
163
|
+
* @param timeout A pointer to an integer, which specifies the maximum number of
|
164
|
+
* microseconds that may be spent on reading the necessary data.
|
165
|
+
* If the timeout expired then TimeoutException will be thrown.
|
166
|
+
* If this function returns without throwing an exception, then the
|
167
|
+
* total number of microseconds spent on reading will be deducted
|
168
|
+
* from <tt>timeout</tt>.
|
169
|
+
* Pass NULL if you do not want to enforce a timeout.
|
170
|
+
* @return True if reading was successful, false if end-of-file was prematurely reached.
|
171
|
+
* @throws SystemException Something went wrong.
|
172
|
+
* @throws TimeoutException Unable to read the necessary data within
|
173
|
+
* <tt>timeout</tt> microseconds.
|
174
|
+
* @throws boost::thread_interrupted
|
175
|
+
*/
|
176
|
+
inline bool
|
177
|
+
readUint32(int fd, uint32_t &output, unsigned long long *timeout = NULL) {
|
178
|
+
uint32_t temp;
|
179
|
+
|
180
|
+
if (readExact(fd, &temp, sizeof(uint32_t), timeout) == sizeof(uint32_t)) {
|
181
|
+
output = ntohl(temp);
|
182
|
+
return true;
|
183
|
+
} else {
|
184
|
+
return false;
|
185
|
+
}
|
186
|
+
}
|
187
|
+
|
188
|
+
/**
|
189
|
+
* Reads a 32-bit unsigned integer from the given file descriptor.
|
190
|
+
*
|
191
|
+
* @param timeout A pointer to an integer, which specifies the maximum number of
|
192
|
+
* microseconds that may be spent on reading the necessary data.
|
193
|
+
* If the timeout expired then TimeoutException will be thrown.
|
194
|
+
* If this function returns without throwing an exception, then the
|
195
|
+
* total number of microseconds spent on reading will be deducted
|
196
|
+
* from <tt>timeout</tt>.
|
197
|
+
* Pass NULL if you do not want to enforce a timeout.
|
198
|
+
* @throws EOFException End-of-file was reached before a full integer could be read.
|
199
|
+
* @throws SystemException Something went wrong.
|
200
|
+
* @throws TimeoutException Unable to read the necessary data within
|
201
|
+
* <tt>timeout</tt> microseconds.
|
202
|
+
* @throws boost::thread_interrupted
|
203
|
+
*/
|
204
|
+
inline uint32_t
|
205
|
+
readUint32(int fd, unsigned long long *timeout = NULL) {
|
206
|
+
uint32_t temp;
|
207
|
+
|
208
|
+
if (readUint32(fd, temp, timeout)) {
|
209
|
+
return temp;
|
210
|
+
} else {
|
211
|
+
throw EOFException("EOF encountered before a full 32-bit integer could be read");
|
212
|
+
}
|
213
|
+
}
|
214
|
+
|
215
|
+
|
216
|
+
/**
|
217
|
+
* Reads an array message from the given file descriptor. This version
|
218
|
+
* puts the result into the given collection instead of returning a
|
219
|
+
* new collection.
|
220
|
+
*
|
221
|
+
* @param timeout A pointer to an integer, which specifies the maximum number of
|
222
|
+
* microseconds that may be spent on reading the necessary data.
|
223
|
+
* If the timeout expired then TimeoutException will be thrown.
|
224
|
+
* If this function returns without throwing an exception, then the
|
225
|
+
* total number of microseconds spent on reading will be deducted
|
226
|
+
* from <tt>timeout</tt>.
|
227
|
+
* Pass NULL if you do not want to enforce a timeout.
|
228
|
+
* @return True if an array message was read, false if end-of-file was reached
|
229
|
+
* before a full array message could be read.
|
230
|
+
* @throws SystemException Something went wrong.
|
231
|
+
* @throws TimeoutException Unable to read the necessary data within
|
232
|
+
* <tt>timeout</tt> microseconds.
|
233
|
+
* @throws boost::thread_interrupted
|
234
|
+
*/
|
235
|
+
template<typename Collection>
|
236
|
+
inline bool
|
237
|
+
readArrayMessage(int fd, Collection &output, unsigned long long *timeout = NULL) {
|
238
|
+
uint16_t size;
|
239
|
+
if (!readUint16(fd, size, timeout)) {
|
240
|
+
return false;
|
241
|
+
}
|
242
|
+
|
243
|
+
scoped_array<char> buffer(new char[size]);
|
244
|
+
MemZeroGuard g(buffer.get(), size);
|
245
|
+
if (readExact(fd, buffer.get(), size, timeout) != size) {
|
246
|
+
return false;
|
247
|
+
}
|
248
|
+
|
249
|
+
output.clear();
|
250
|
+
if (size != 0) {
|
251
|
+
string::size_type start = 0, pos;
|
252
|
+
StaticString buffer_str(buffer.get(), size);
|
253
|
+
while ((pos = buffer_str.find('\0', start)) != string::npos) {
|
254
|
+
output.push_back(buffer_str.substr(start, pos - start));
|
255
|
+
start = pos + 1;
|
256
|
+
}
|
257
|
+
}
|
258
|
+
return true;
|
259
|
+
}
|
260
|
+
|
261
|
+
/**
|
262
|
+
* Reads an array message from the given file descriptor. This version returns
|
263
|
+
* the result immediately as a string vector.
|
264
|
+
*
|
265
|
+
* @param timeout A pointer to an integer, which specifies the maximum number of
|
266
|
+
* microseconds that may be spent on reading the necessary data.
|
267
|
+
* If the timeout expired then TimeoutException will be thrown.
|
268
|
+
* If this function returns without throwing an exception, then the
|
269
|
+
* total number of microseconds spent on reading will be deducted
|
270
|
+
* from <tt>timeout</tt>.
|
271
|
+
* Pass NULL if you do not want to enforce a timeout.
|
272
|
+
* @throws EOFException End-of-file was reached before a full integer could be read.
|
273
|
+
* @throws SystemException Something went wrong.
|
274
|
+
* @throws TimeoutException Unable to read the necessary data within
|
275
|
+
* <tt>timeout</tt> microseconds.
|
276
|
+
* @throws boost::thread_interrupted
|
277
|
+
*/
|
278
|
+
inline vector<string>
|
279
|
+
readArrayMessage(int fd, unsigned long long *timeout = NULL) {
|
280
|
+
vector<string> output;
|
281
|
+
|
282
|
+
if (readArrayMessage(fd, output, timeout)) {
|
283
|
+
return output;
|
284
|
+
} else {
|
285
|
+
throw EOFException("EOF encountered before the full array message could be read");
|
286
|
+
}
|
287
|
+
}
|
288
|
+
|
289
|
+
|
290
|
+
/**
|
291
|
+
* Reads a scalar message from the given file descriptor.
|
292
|
+
*
|
293
|
+
* @param maxSize The maximum number of bytes that may be read. If the
|
294
|
+
* scalar to read is larger than this, then a SecurityException
|
295
|
+
* will be thrown. Set to 0 for no size limit.
|
296
|
+
* @param timeout A pointer to an integer, which specifies the maximum number of
|
297
|
+
* microseconds that may be spent on reading the necessary data.
|
298
|
+
* If the timeout expired then TimeoutException will be thrown.
|
299
|
+
* If this function returns without throwing an exception, then the
|
300
|
+
* total number of microseconds spent on reading will be deducted
|
301
|
+
* from <tt>timeout</tt>.
|
302
|
+
* Pass NULL if you do not want to enforce a timeout.
|
303
|
+
* @throws EOFException End-of-file was reached before a full integer could be read.
|
304
|
+
* @throws SystemException Something went wrong.
|
305
|
+
* @throws SecurityException The message body is larger than allowed by maxSize.
|
306
|
+
* @throws TimeoutException Unable to read the necessary data within
|
307
|
+
* <tt>timeout</tt> microseconds.
|
308
|
+
* @throws boost::thread_interrupted
|
309
|
+
*/
|
310
|
+
inline string
|
311
|
+
readScalarMessage(int fd, unsigned int maxSize = 0, unsigned long long *timeout = NULL) {
|
312
|
+
uint32_t size;
|
313
|
+
if (!readUint32(fd, size, timeout)) {
|
314
|
+
throw EOFException("EOF encountered before a 32-bit scalar message header could be read");
|
315
|
+
}
|
316
|
+
|
317
|
+
if (maxSize != 0 && size > (uint32_t) maxSize) {
|
318
|
+
throw SecurityException("The scalar message body is larger than the size limit");
|
319
|
+
}
|
320
|
+
|
321
|
+
string output;
|
322
|
+
unsigned int remaining = size;
|
323
|
+
output.reserve(size);
|
324
|
+
if (OXT_LIKELY(remaining > 0)) {
|
325
|
+
char buf[1024 * 32];
|
326
|
+
MemZeroGuard g(buf, sizeof(buf));
|
327
|
+
|
328
|
+
while (remaining > 0) {
|
329
|
+
unsigned int blockSize = min((unsigned int) sizeof(buf), remaining);
|
330
|
+
|
331
|
+
if (readExact(fd, buf, blockSize, timeout) != blockSize) {
|
332
|
+
throw EOFException("EOF encountered before the full scalar message body could be read");
|
333
|
+
}
|
334
|
+
output.append(buf, blockSize);
|
335
|
+
remaining -= blockSize;
|
336
|
+
}
|
337
|
+
}
|
338
|
+
return output;
|
339
|
+
}
|
340
|
+
|
341
|
+
|
342
|
+
/**
|
343
|
+
* Writes a 16-bit unsigned integer to the given file descriptor.
|
344
|
+
*
|
345
|
+
* @param timeout A pointer to an integer, which specifies the maximum number of
|
346
|
+
* microseconds that may be spent on writing the necessary data.
|
347
|
+
* If the timeout expired then TimeoutException will be thrown.
|
348
|
+
* If this function returns without throwing an exception, then the
|
349
|
+
* total number of microseconds spent on writing will be deducted
|
350
|
+
* from <tt>timeout</tt>.
|
351
|
+
* Pass NULL if you do not want to enforce a timeout.
|
352
|
+
* @throws SystemException Something went wrong.
|
353
|
+
* @throws TimeoutException Unable to write the necessary data within
|
354
|
+
* <tt>timeout</tt> microseconds.
|
355
|
+
* @throws boost::thread_interrupted
|
356
|
+
*/
|
357
|
+
inline void
|
358
|
+
writeUint16(int fd, uint16_t value, unsigned long long *timeout = NULL) {
|
359
|
+
uint16_t l = htons(value);
|
360
|
+
writeExact(fd, &l, sizeof(uint16_t), timeout);
|
361
|
+
}
|
362
|
+
|
363
|
+
/**
|
364
|
+
* Writes a 32-bit unsigned integer to the given file descriptor.
|
365
|
+
*
|
366
|
+
* @param timeout A pointer to an integer, which specifies the maximum number of
|
367
|
+
* microseconds that may be spent on writing the necessary data.
|
368
|
+
* If the timeout expired then TimeoutException will be thrown.
|
369
|
+
* If this function returns without throwing an exception, then the
|
370
|
+
* total number of microseconds spent on writing will be deducted
|
371
|
+
* from <tt>timeout</tt>.
|
372
|
+
* Pass NULL if you do not want to enforce a timeout.
|
373
|
+
* @throws SystemException Something went wrong.
|
374
|
+
* @throws TimeoutException Unable to write the necessary data within
|
375
|
+
* <tt>timeout</tt> microseconds.
|
376
|
+
* @throws boost::thread_interrupted
|
377
|
+
*/
|
378
|
+
inline void
|
379
|
+
writeUint32(int fd, uint32_t value, unsigned long long *timeout = NULL) {
|
380
|
+
uint32_t l = htonl(value);
|
381
|
+
writeExact(fd, &l, sizeof(uint32_t), timeout);
|
382
|
+
}
|
383
|
+
|
384
|
+
|
385
|
+
/**
|
386
|
+
* Writes an array message to the given file descriptor.
|
387
|
+
*
|
388
|
+
* @param args A collection of strings containing the array message's elements.
|
389
|
+
* The collection must have an STL container-like interface and
|
390
|
+
* the strings must have an STL string-like interface.
|
391
|
+
* @param timeout A pointer to an integer, which specifies the maximum number of
|
392
|
+
* microseconds that may be spent on writing the necessary data.
|
393
|
+
* If the timeout expired then TimeoutException will be thrown.
|
394
|
+
* If this function returns without throwing an exception, then the
|
395
|
+
* total number of microseconds spent on writing will be deducted
|
396
|
+
* from <tt>timeout</tt>.
|
397
|
+
* Pass NULL if you do not want to enforce a timeout.
|
398
|
+
* @throws SystemException Something went wrong.
|
399
|
+
* @throws TimeoutException Unable to write the necessary data within
|
400
|
+
* <tt>timeout</tt> microseconds.
|
401
|
+
* @throws boost::thread_interrupted
|
402
|
+
*/
|
403
|
+
template<typename Collection>
|
404
|
+
inline void
|
405
|
+
writeArrayMessage(int fd, const Collection &args, unsigned long long *timeout = NULL) {
|
406
|
+
typename Collection::const_iterator it, end = args.end();
|
407
|
+
uint16_t bodySize = 0;
|
408
|
+
|
409
|
+
for (it = args.begin(); it != end; it++) {
|
410
|
+
bodySize += it->size() + 1;
|
411
|
+
}
|
412
|
+
|
413
|
+
scoped_array<char> data(new char[sizeof(uint16_t) + bodySize]);
|
414
|
+
uint16_t header = htons(bodySize);
|
415
|
+
memcpy(data.get(), &header, sizeof(uint16_t));
|
416
|
+
|
417
|
+
char *dataEnd = data.get() + sizeof(uint16_t);
|
418
|
+
for (it = args.begin(); it != end; it++) {
|
419
|
+
memcpy(dataEnd, it->data(), it->size());
|
420
|
+
dataEnd += it->size();
|
421
|
+
*dataEnd = '\0';
|
422
|
+
dataEnd++;
|
423
|
+
}
|
424
|
+
|
425
|
+
writeExact(fd, data.get(), sizeof(uint16_t) + bodySize, timeout);
|
426
|
+
}
|
427
|
+
|
428
|
+
inline void
|
429
|
+
writeArrayMessage(int fd, const StaticString &name, va_list &ap, unsigned long long *timeout = NULL) {
|
430
|
+
vector<StaticString> args;
|
431
|
+
|
432
|
+
args.push_back(name);
|
433
|
+
while (true) {
|
434
|
+
const char *arg = va_arg(ap, const char *);
|
435
|
+
if (arg == NULL) {
|
436
|
+
break;
|
437
|
+
} else {
|
438
|
+
args.push_back(arg);
|
439
|
+
}
|
440
|
+
}
|
441
|
+
writeArrayMessage(fd, args, timeout);
|
442
|
+
}
|
443
|
+
|
444
|
+
struct _VaGuard {
|
445
|
+
va_list ≈
|
446
|
+
|
447
|
+
_VaGuard(va_list &_ap)
|
448
|
+
: ap(_ap)
|
449
|
+
{ }
|
450
|
+
|
451
|
+
~_VaGuard() {
|
452
|
+
va_end(ap);
|
453
|
+
}
|
454
|
+
};
|
455
|
+
|
456
|
+
/** Version of writeArrayMessage() that accepts a variadic list of 'const char *'
|
457
|
+
* arguments as message elements. The list must be terminated with a NULL.
|
458
|
+
*/
|
459
|
+
inline void
|
460
|
+
writeArrayMessage(int fd, const StaticString &name, ...) {
|
461
|
+
va_list ap;
|
462
|
+
va_start(ap, name);
|
463
|
+
_VaGuard guard(ap);
|
464
|
+
writeArrayMessage(fd, name, ap);
|
465
|
+
}
|
466
|
+
|
467
|
+
/** Version of writeArrayMessage() that accepts a variadic list of 'const char *'
|
468
|
+
* arguments as message elements, with timeout support. The list must be terminated
|
469
|
+
* with a NULL.
|
470
|
+
*/
|
471
|
+
inline void
|
472
|
+
writeArrayMessage(int fd, unsigned long long *timeout, const StaticString &name, ...) {
|
473
|
+
va_list ap;
|
474
|
+
va_start(ap, name);
|
475
|
+
_VaGuard guard(ap);
|
476
|
+
writeArrayMessage(fd, name, ap, timeout);
|
477
|
+
}
|
478
|
+
|
479
|
+
/**
|
480
|
+
* Writes a scalar message to the given file descriptor.
|
481
|
+
*
|
482
|
+
* @param timeout A pointer to an integer, which specifies the maximum number of
|
483
|
+
* microseconds that may be spent on writing the necessary data.
|
484
|
+
* If the timeout expired then TimeoutException will be thrown.
|
485
|
+
* If this function returns without throwing an exception, then the
|
486
|
+
* total number of microseconds spent on writing will be deducted
|
487
|
+
* from <tt>timeout</tt>.
|
488
|
+
* Pass NULL if you do not want to enforce a timeout.
|
489
|
+
* @throws SystemException Something went wrong.
|
490
|
+
* @throws TimeoutException Unable to write the necessary data within
|
491
|
+
* <tt>timeout</tt> microseconds.
|
492
|
+
* @throws boost::thread_interrupted
|
493
|
+
*/
|
494
|
+
inline void
|
495
|
+
writeScalarMessage(int fd, const StaticString &data, unsigned long long *timeout = NULL) {
|
496
|
+
uint32_t header = htonl(data.size());
|
497
|
+
StaticString buffers[2] = {
|
498
|
+
StaticString((const char *) &header, sizeof(uint32_t)),
|
499
|
+
data
|
500
|
+
};
|
501
|
+
gatheredWrite(fd, buffers, 2, timeout);
|
502
|
+
}
|
503
|
+
|
504
|
+
inline void
|
505
|
+
writeScalarMessage(int fd, const char *data, size_t size, unsigned long long *timeout = NULL) {
|
506
|
+
writeScalarMessage(fd, StaticString(data, size), timeout);
|
507
|
+
}
|
508
|
+
|
509
|
+
|
510
|
+
/**
|
511
|
+
* Receive a file descriptor over the given Unix domain socket,
|
512
|
+
* involving a negotiation protocol.
|
513
|
+
*
|
514
|
+
* @param timeout A pointer to an integer, which specifies the maximum number of
|
515
|
+
* microseconds that may be spent on receiving the file descriptor.
|
516
|
+
* If the timeout expired then TimeoutException will be thrown.
|
517
|
+
* If this function returns without throwing an exception, then the
|
518
|
+
* total number of microseconds spent on receiving will be deducted
|
519
|
+
* from <tt>timeout</tt>.
|
520
|
+
* Pass NULL if you do not want to enforce a timeout.
|
521
|
+
* @return The received file descriptor.
|
522
|
+
* @throws SystemException Something went wrong.
|
523
|
+
* @throws IOException Whatever was received doesn't seem to be a
|
524
|
+
* file descriptor.
|
525
|
+
* @throws TimeoutException Unable to receive a file descriptor within
|
526
|
+
* <tt>timeout</tt> microseconds.
|
527
|
+
* @throws boost::thread_interrupted
|
528
|
+
*/
|
529
|
+
inline int
|
530
|
+
readFileDescriptorWithNegotiation(int fd, unsigned long long *timeout = NULL) {
|
531
|
+
writeArrayMessage(fd, timeout, "pass IO", NULL);
|
532
|
+
int result = readFileDescriptor(fd, timeout);
|
533
|
+
ScopeGuard guard(boost::bind(safelyClose, result));
|
534
|
+
writeArrayMessage(fd, timeout, "got IO", NULL);
|
535
|
+
guard.clear();
|
536
|
+
return result;
|
537
|
+
}
|
538
|
+
|
539
|
+
|
540
|
+
/**
|
541
|
+
* Pass the file descriptor 'fdToSend' over the Unix socket 'fd',
|
542
|
+
* involving a negotiation protocol.
|
543
|
+
*
|
544
|
+
* @param timeout A pointer to an integer, which specifies the maximum number of
|
545
|
+
* microseconds that may be spent on trying to pass the file descriptor.
|
546
|
+
* If the timeout expired then TimeoutException will be thrown.
|
547
|
+
* If this function returns without throwing an exception, then the
|
548
|
+
* total number of microseconds spent on writing will be deducted
|
549
|
+
* from <tt>timeout</tt>.
|
550
|
+
* Pass NULL if you do not want to enforce a timeout.
|
551
|
+
* @throws SystemException Something went wrong.
|
552
|
+
* @throws TimeoutException Unable to pass the file descriptor within
|
553
|
+
* <tt>timeout</tt> microseconds.
|
554
|
+
* @throws boost::thread_interrupted
|
555
|
+
*/
|
556
|
+
inline void
|
557
|
+
writeFileDescriptorWithNegotiation(int fd, int fdToPass, unsigned long long *timeout = NULL) {
|
558
|
+
vector<string> args;
|
559
|
+
|
560
|
+
args = readArrayMessage(fd, timeout);
|
561
|
+
if (args.size() != 1 || args[0] != "pass IO") {
|
562
|
+
throw IOException("FD passing pre-negotiation message expected");
|
563
|
+
}
|
564
|
+
|
565
|
+
writeFileDescriptor(fd, fdToPass, timeout);
|
566
|
+
|
567
|
+
args = readArrayMessage(fd, timeout);
|
568
|
+
if (args.size() != 1 || args[0] != "got IO") {
|
569
|
+
throw IOException("FD passing post-negotiation message expected.");
|
570
|
+
}
|
571
|
+
}
|
572
|
+
|
573
|
+
|
574
|
+
} // namespace Passenger
|
575
|
+
|
576
|
+
#endif /* _PASSENGER_MESSAGE_IO_H_ */
|