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.

Files changed (42) hide show
  1. data/NEWS +9 -0
  2. data/bin/passenger-install-nginx-module +1 -1
  3. data/build/basics.rb +0 -1
  4. data/build/cxx_tests.rb +5 -0
  5. data/build/rpm.rb +1 -1
  6. data/doc/Users guide Apache.html +1 -1
  7. data/doc/Users guide Nginx.html +1 -1
  8. data/ext/apache2/Configuration.cpp +12 -0
  9. data/ext/apache2/Configuration.hpp +12 -1
  10. data/ext/apache2/Hooks.cpp +2 -0
  11. data/ext/common/AgentsStarter.cpp +4 -0
  12. data/ext/common/AgentsStarter.h +2 -0
  13. data/ext/common/AgentsStarter.hpp +4 -0
  14. data/ext/common/Constants.h +1 -1
  15. data/ext/common/Logging.h +481 -261
  16. data/ext/common/LoggingAgent/LoggingServer.h +10 -4
  17. data/ext/common/LoggingAgent/Main.cpp +7 -2
  18. data/ext/common/LoggingAgent/RemoteSender.h +25 -3
  19. data/ext/common/MessageChannel.h +18 -227
  20. data/ext/common/MessageClient.h +95 -92
  21. data/ext/common/Utils/IOUtils.cpp +114 -1
  22. data/ext/common/Utils/IOUtils.h +57 -1
  23. data/ext/common/Utils/MessageIO.h +576 -0
  24. data/ext/nginx/Configuration.c +35 -0
  25. data/ext/nginx/Configuration.h +2 -0
  26. data/ext/nginx/ContentHandler.c +17 -6
  27. data/ext/nginx/ngx_http_passenger_module.c +8 -0
  28. data/lib/phusion_passenger.rb +2 -2
  29. data/lib/phusion_passenger/analytics_logger.rb +174 -117
  30. data/lib/phusion_passenger/app_process.rb +14 -2
  31. data/test/cxx/CxxTestMain.cpp +14 -19
  32. data/test/cxx/IOUtilsTest.cpp +68 -18
  33. data/test/cxx/LoggingTest.cpp +20 -24
  34. data/test/cxx/MessageChannelTest.cpp +1 -1
  35. data/test/cxx/MessageIOTest.cpp +310 -0
  36. data/test/cxx/TestSupport.cpp +47 -0
  37. data/test/cxx/TestSupport.h +8 -0
  38. data/test/ruby/analytics_logger_spec.rb +20 -28
  39. data/test/tut/tut.h +2 -0
  40. metadata +11 -11
  41. data/build/rdoctask.rb +0 -209
  42. 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 &ap;
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_ */