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
data/ext/common/MessageClient.h
CHANGED
@@ -26,12 +26,14 @@
|
|
26
26
|
#define _PASSENGER_MESSAGE_CLIENT_H_
|
27
27
|
|
28
28
|
#include <boost/shared_ptr.hpp>
|
29
|
+
#include <boost/bind.hpp>
|
29
30
|
#include <string>
|
30
31
|
|
31
32
|
#include "StaticString.h"
|
32
|
-
#include "MessageChannel.h"
|
33
33
|
#include "Exceptions.h"
|
34
|
+
#include "Utils/MessageIO.h"
|
34
35
|
#include "Utils/IOUtils.h"
|
36
|
+
#include "Utils/ScopeGuard.h"
|
35
37
|
|
36
38
|
|
37
39
|
namespace Passenger {
|
@@ -42,17 +44,16 @@ using namespace boost;
|
|
42
44
|
class MessageClient {
|
43
45
|
protected:
|
44
46
|
FileDescriptor fd;
|
45
|
-
MessageChannel channel;
|
46
47
|
bool shouldAutoDisconnect;
|
47
48
|
|
48
49
|
/* sendUsername() and sendPassword() exist and are virtual in order to facilitate unit testing. */
|
49
50
|
|
50
|
-
virtual void sendUsername(
|
51
|
-
|
51
|
+
virtual void sendUsername(int fd, const StaticString &username, unsigned long long *timeout) {
|
52
|
+
writeScalarMessage(fd, username);
|
52
53
|
}
|
53
54
|
|
54
|
-
virtual void sendPassword(
|
55
|
-
|
55
|
+
virtual void sendPassword(int fd, const StaticString &userSuppliedPassword, unsigned long long *timeout) {
|
56
|
+
writeScalarMessage(fd, userSuppliedPassword);
|
56
57
|
}
|
57
58
|
|
58
59
|
/**
|
@@ -64,13 +65,15 @@ protected:
|
|
64
65
|
* @throws boost::thread_interrupted
|
65
66
|
* @pre <tt>channel</tt> is connected.
|
66
67
|
*/
|
67
|
-
void authenticate(const
|
68
|
+
void authenticate(const StaticString &username, const StaticString &userSuppliedPassword,
|
69
|
+
unsigned long long *timeout)
|
70
|
+
{
|
68
71
|
vector<string> args;
|
69
72
|
|
70
|
-
sendUsername(
|
71
|
-
sendPassword(
|
73
|
+
sendUsername(fd, username, timeout);
|
74
|
+
sendPassword(fd, userSuppliedPassword, timeout);
|
72
75
|
|
73
|
-
if (!
|
76
|
+
if (!readArrayMessage(fd, args, timeout)) {
|
74
77
|
throw IOException("The message server did not send an authentication response.");
|
75
78
|
} else if (args.size() != 1) {
|
76
79
|
throw IOException("The authentication response that the message server sent is not valid.");
|
@@ -79,11 +82,15 @@ protected:
|
|
79
82
|
}
|
80
83
|
}
|
81
84
|
|
85
|
+
void checkConnection() {
|
86
|
+
if (!connected()) {
|
87
|
+
throw IOException("Not connected");
|
88
|
+
}
|
89
|
+
}
|
90
|
+
|
82
91
|
void autoDisconnect() {
|
83
92
|
if (shouldAutoDisconnect) {
|
84
|
-
|
85
|
-
fd = FileDescriptor();
|
86
|
-
channel = MessageChannel();
|
93
|
+
fd.close(false);
|
87
94
|
}
|
88
95
|
}
|
89
96
|
|
@@ -122,48 +129,35 @@ public:
|
|
122
129
|
* @throws boost::thread_interrupted
|
123
130
|
* @post connected()
|
124
131
|
*/
|
125
|
-
MessageClient *connect(const string &serverAddress, const
|
132
|
+
MessageClient *connect(const string &serverAddress, const StaticString &username,
|
126
133
|
const StaticString &userSuppliedPassword)
|
127
134
|
{
|
128
135
|
TRACE_POINT();
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
}
|
137
|
-
if (args.size() != 2 || args[0] != "version") {
|
138
|
-
throw IOException("The message server didn't sent a valid version identifier.");
|
139
|
-
}
|
140
|
-
if (args[1] != "1") {
|
141
|
-
string message = string("Unsupported message server protocol version ") +
|
142
|
-
args[1] + ".";
|
143
|
-
throw IOException(message);
|
144
|
-
}
|
145
|
-
|
146
|
-
authenticate(username, userSuppliedPassword);
|
147
|
-
return this;
|
148
|
-
} catch (const RuntimeException &) {
|
149
|
-
autoDisconnect();
|
150
|
-
throw;
|
151
|
-
} catch (const SystemException &) {
|
152
|
-
autoDisconnect();
|
153
|
-
throw;
|
154
|
-
} catch (const IOException &) {
|
155
|
-
autoDisconnect();
|
156
|
-
throw;
|
157
|
-
} catch (const boost::thread_interrupted &) {
|
158
|
-
autoDisconnect();
|
159
|
-
throw;
|
136
|
+
ScopeGuard g(boost::bind(&MessageClient::autoDisconnect, this));
|
137
|
+
|
138
|
+
fd = connectToServer(serverAddress.c_str());
|
139
|
+
|
140
|
+
vector<string> args;
|
141
|
+
if (!readArrayMessage(fd, args)) {
|
142
|
+
throw IOException("The message server closed the connection before sending a version identifier.");
|
160
143
|
}
|
144
|
+
if (args.size() != 2 || args[0] != "version") {
|
145
|
+
throw IOException("The message server didn't sent a valid version identifier.");
|
146
|
+
}
|
147
|
+
if (args[1] != "1") {
|
148
|
+
string message = string("Unsupported message server protocol version ") +
|
149
|
+
args[1] + ".";
|
150
|
+
throw IOException(message);
|
151
|
+
}
|
152
|
+
|
153
|
+
authenticate(username, userSuppliedPassword, NULL);
|
154
|
+
|
155
|
+
g.clear();
|
156
|
+
return this;
|
161
157
|
}
|
162
158
|
|
163
159
|
void disconnect() {
|
164
160
|
fd.close();
|
165
|
-
fd = FileDescriptor();
|
166
|
-
channel = MessageChannel();
|
167
161
|
}
|
168
162
|
|
169
163
|
bool connected() const {
|
@@ -180,15 +174,24 @@ public:
|
|
180
174
|
|
181
175
|
/**
|
182
176
|
* @throws SystemException
|
177
|
+
* @throws TimeoutException
|
183
178
|
* @throws boost::thread_interrupted
|
184
179
|
*/
|
185
|
-
bool read(vector<string> &args) {
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
180
|
+
bool read(vector<string> &args, unsigned long long *timeout = NULL) {
|
181
|
+
return readArray(args);
|
182
|
+
}
|
183
|
+
|
184
|
+
/**
|
185
|
+
* @throws SystemException
|
186
|
+
* @throws TimeoutException
|
187
|
+
* @throws boost::thread_interrupted
|
188
|
+
*/
|
189
|
+
bool readArray(vector<string> &args, unsigned long long *timeout = NULL) {
|
190
|
+
checkConnection();
|
191
|
+
ScopeGuard g(boost::bind(&MessageClient::autoDisconnect, this));
|
192
|
+
bool result = readArrayMessage(fd, args, timeout);
|
193
|
+
g.clear();
|
194
|
+
return result;
|
192
195
|
}
|
193
196
|
|
194
197
|
/**
|
@@ -198,17 +201,15 @@ public:
|
|
198
201
|
* @throws boost::thread_interrupted
|
199
202
|
*/
|
200
203
|
bool readScalar(string &output, unsigned int maxSize = 0, unsigned long long *timeout = NULL) {
|
204
|
+
checkConnection();
|
205
|
+
ScopeGuard g(boost::bind(&MessageClient::autoDisconnect, this));
|
201
206
|
try {
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
throw;
|
209
|
-
} catch (const TimeoutException &) {
|
210
|
-
autoDisconnect();
|
211
|
-
throw;
|
207
|
+
output = readScalarMessage(fd, maxSize, timeout);
|
208
|
+
g.clear();
|
209
|
+
return true;
|
210
|
+
} catch (const EOFException &) {
|
211
|
+
g.clear();
|
212
|
+
return false;
|
212
213
|
}
|
213
214
|
}
|
214
215
|
|
@@ -218,15 +219,16 @@ public:
|
|
218
219
|
* @throws boost::thread_interrupted
|
219
220
|
*/
|
220
221
|
int readFileDescriptor(bool negotiate = true) {
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
}
|
227
|
-
|
228
|
-
throw;
|
222
|
+
checkConnection();
|
223
|
+
ScopeGuard g(boost::bind(&MessageClient::autoDisconnect, this));
|
224
|
+
int result;
|
225
|
+
if (negotiate) {
|
226
|
+
result = Passenger::readFileDescriptorWithNegotiation(fd);
|
227
|
+
} else {
|
228
|
+
result = Passenger::readFileDescriptor(fd);
|
229
229
|
}
|
230
|
+
g.clear();
|
231
|
+
return result;
|
230
232
|
}
|
231
233
|
|
232
234
|
/**
|
@@ -234,11 +236,12 @@ public:
|
|
234
236
|
* @throws boost::thread_interrupted
|
235
237
|
*/
|
236
238
|
void write(const char *name, ...) {
|
239
|
+
checkConnection();
|
237
240
|
va_list ap;
|
238
241
|
va_start(ap, name);
|
239
242
|
try {
|
240
243
|
try {
|
241
|
-
|
244
|
+
writeArrayMessage(fd, name, ap);
|
242
245
|
} catch (const SystemException &) {
|
243
246
|
autoDisconnect();
|
244
247
|
throw;
|
@@ -252,28 +255,26 @@ public:
|
|
252
255
|
|
253
256
|
/**
|
254
257
|
* @throws SystemException
|
258
|
+
* @throws TimeoutException
|
255
259
|
* @throws boost::thread_interrupted
|
256
260
|
*/
|
257
|
-
void writeScalar(const char *data, unsigned int size) {
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
throw;
|
263
|
-
}
|
261
|
+
void writeScalar(const char *data, unsigned int size, unsigned long long *timeout = NULL) {
|
262
|
+
checkConnection();
|
263
|
+
ScopeGuard g(boost::bind(&MessageClient::autoDisconnect, this));
|
264
|
+
writeScalarMessage(fd, data, size, timeout);
|
265
|
+
g.clear();
|
264
266
|
}
|
265
267
|
|
266
268
|
/**
|
267
269
|
* @throws SystemException
|
270
|
+
* @throws TimeoutException
|
268
271
|
* @throws boost::thread_interrupted
|
269
272
|
*/
|
270
|
-
void writeScalar(const StaticString &data) {
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
throw;
|
276
|
-
}
|
273
|
+
void writeScalar(const StaticString &data, unsigned long long *timeout = NULL) {
|
274
|
+
checkConnection();
|
275
|
+
ScopeGuard g(boost::bind(&MessageClient::autoDisconnect, this));
|
276
|
+
writeScalarMessage(fd, data, timeout);
|
277
|
+
g.clear();
|
277
278
|
}
|
278
279
|
|
279
280
|
/**
|
@@ -281,12 +282,14 @@ public:
|
|
281
282
|
* @throws boost::thread_interrupted
|
282
283
|
*/
|
283
284
|
void writeFileDescriptor(int fileDescriptor, bool negotiate = true) {
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
285
|
+
checkConnection();
|
286
|
+
ScopeGuard g(boost::bind(&MessageClient::autoDisconnect, this));
|
287
|
+
if (negotiate) {
|
288
|
+
Passenger::writeFileDescriptorWithNegotiation(fd, fileDescriptor);
|
289
|
+
} else {
|
290
|
+
Passenger::writeFileDescriptor(fd, fileDescriptor);
|
289
291
|
}
|
292
|
+
g.clear();
|
290
293
|
}
|
291
294
|
};
|
292
295
|
|
@@ -860,7 +860,7 @@ eraseBeginningOfIoVec(struct iovec *iov, size_t count, size_t index, size_t offs
|
|
860
860
|
}
|
861
861
|
|
862
862
|
void
|
863
|
-
gatheredWrite(int fd, const StaticString data[], unsigned int count) {
|
863
|
+
gatheredWrite(int fd, const StaticString data[], unsigned int count, unsigned long long *timeout) {
|
864
864
|
struct iovec iov[count];
|
865
865
|
size_t total, iovCount;
|
866
866
|
size_t written = 0;
|
@@ -868,6 +868,9 @@ gatheredWrite(int fd, const StaticString data[], unsigned int count) {
|
|
868
868
|
total = staticStringArrayToIoVec(data, count, iov, iovCount);
|
869
869
|
|
870
870
|
while (written < total) {
|
871
|
+
if (timeout != NULL && !waitUntilWritable(fd, timeout)) {
|
872
|
+
throw TimeoutException("Cannot write enough data within the specified timeout");
|
873
|
+
}
|
871
874
|
ssize_t ret = writevFunction(fd, iov, std::min(iovCount, (size_t) IOV_MAX));
|
872
875
|
if (ret == -1) {
|
873
876
|
int e = errno;
|
@@ -892,6 +895,116 @@ setWritevFunction(WritevFunction func) {
|
|
892
895
|
}
|
893
896
|
}
|
894
897
|
|
898
|
+
int
|
899
|
+
readFileDescriptor(int fd, unsigned long long *timeout) {
|
900
|
+
if (timeout != NULL && !waitUntilReadable(fd, timeout)) {
|
901
|
+
throw TimeoutException("Cannot receive file descriptor within the specified timeout");
|
902
|
+
}
|
903
|
+
|
904
|
+
struct msghdr msg;
|
905
|
+
struct iovec vec;
|
906
|
+
char dummy[1];
|
907
|
+
#if defined(__APPLE__) || defined(__SOLARIS__) || defined(__arm__)
|
908
|
+
// File descriptor passing macros (CMSG_*) seem to be broken
|
909
|
+
// on 64-bit MacOS X. This structure works around the problem.
|
910
|
+
struct {
|
911
|
+
struct cmsghdr header;
|
912
|
+
int fd;
|
913
|
+
} control_data;
|
914
|
+
#define EXPECTED_CMSG_LEN sizeof(control_data)
|
915
|
+
#else
|
916
|
+
char control_data[CMSG_SPACE(sizeof(int))];
|
917
|
+
#define EXPECTED_CMSG_LEN CMSG_LEN(sizeof(int))
|
918
|
+
#endif
|
919
|
+
struct cmsghdr *control_header;
|
920
|
+
int ret;
|
921
|
+
|
922
|
+
msg.msg_name = NULL;
|
923
|
+
msg.msg_namelen = 0;
|
924
|
+
|
925
|
+
dummy[0] = '\0';
|
926
|
+
vec.iov_base = dummy;
|
927
|
+
vec.iov_len = sizeof(dummy);
|
928
|
+
msg.msg_iov = &vec;
|
929
|
+
msg.msg_iovlen = 1;
|
930
|
+
|
931
|
+
msg.msg_control = (caddr_t) &control_data;
|
932
|
+
msg.msg_controllen = sizeof(control_data);
|
933
|
+
msg.msg_flags = 0;
|
934
|
+
|
935
|
+
ret = syscalls::recvmsg(fd, &msg, 0);
|
936
|
+
if (ret == -1) {
|
937
|
+
throw SystemException("Cannot read file descriptor with recvmsg()", errno);
|
938
|
+
}
|
939
|
+
|
940
|
+
control_header = CMSG_FIRSTHDR(&msg);
|
941
|
+
if (control_header == NULL) {
|
942
|
+
throw IOException("No valid file descriptor received.");
|
943
|
+
}
|
944
|
+
if (control_header->cmsg_len != EXPECTED_CMSG_LEN
|
945
|
+
|| control_header->cmsg_level != SOL_SOCKET
|
946
|
+
|| control_header->cmsg_type != SCM_RIGHTS) {
|
947
|
+
throw IOException("No valid file descriptor received.");
|
948
|
+
}
|
949
|
+
|
950
|
+
#if defined(__APPLE__) || defined(__SOLARIS__) || defined(__arm__)
|
951
|
+
return control_data.fd;
|
952
|
+
#else
|
953
|
+
return *((int *) CMSG_DATA(control_header));
|
954
|
+
#endif
|
955
|
+
}
|
956
|
+
|
957
|
+
void
|
958
|
+
writeFileDescriptor(int fd, int fdToSend, unsigned long long *timeout) {
|
959
|
+
if (timeout != NULL && !waitUntilWritable(fd, timeout)) {
|
960
|
+
throw TimeoutException("Cannot send file descriptor within the specified timeout");
|
961
|
+
}
|
962
|
+
|
963
|
+
struct msghdr msg;
|
964
|
+
struct iovec vec;
|
965
|
+
char dummy[1];
|
966
|
+
#if defined(__APPLE__) || defined(__SOLARIS__) || defined(__arm__)
|
967
|
+
struct {
|
968
|
+
struct cmsghdr header;
|
969
|
+
int fd;
|
970
|
+
} control_data;
|
971
|
+
#else
|
972
|
+
char control_data[CMSG_SPACE(sizeof(int))];
|
973
|
+
#endif
|
974
|
+
struct cmsghdr *control_header;
|
975
|
+
int ret;
|
976
|
+
|
977
|
+
msg.msg_name = NULL;
|
978
|
+
msg.msg_namelen = 0;
|
979
|
+
|
980
|
+
/* Linux and Solaris require msg_iov to be non-NULL. */
|
981
|
+
dummy[0] = '\0';
|
982
|
+
vec.iov_base = dummy;
|
983
|
+
vec.iov_len = sizeof(dummy);
|
984
|
+
msg.msg_iov = &vec;
|
985
|
+
msg.msg_iovlen = 1;
|
986
|
+
|
987
|
+
msg.msg_control = (caddr_t) &control_data;
|
988
|
+
msg.msg_controllen = sizeof(control_data);
|
989
|
+
msg.msg_flags = 0;
|
990
|
+
|
991
|
+
control_header = CMSG_FIRSTHDR(&msg);
|
992
|
+
control_header->cmsg_level = SOL_SOCKET;
|
993
|
+
control_header->cmsg_type = SCM_RIGHTS;
|
994
|
+
#if defined(__APPLE__) || defined(__SOLARIS__) || defined(__arm__)
|
995
|
+
control_header->cmsg_len = sizeof(control_data);
|
996
|
+
control_data.fd = fdToSend;
|
997
|
+
#else
|
998
|
+
control_header->cmsg_len = CMSG_LEN(sizeof(int));
|
999
|
+
memcpy(CMSG_DATA(control_header), &fdToSend, sizeof(int));
|
1000
|
+
#endif
|
1001
|
+
|
1002
|
+
ret = syscalls::sendmsg(fd, &msg, 0);
|
1003
|
+
if (ret == -1) {
|
1004
|
+
throw SystemException("Cannot send file descriptor with sendmsg()", errno);
|
1005
|
+
}
|
1006
|
+
}
|
1007
|
+
|
895
1008
|
void
|
896
1009
|
safelyClose(int fd) {
|
897
1010
|
if (syscalls::close(fd) == -1) {
|
data/ext/common/Utils/IOUtils.h
CHANGED
@@ -345,10 +345,19 @@ ssize_t gatheredWrite(int fd, const StaticString data[], unsigned int dataCount,
|
|
345
345
|
* @param fd The file descriptor to write to.
|
346
346
|
* @param data An array of buffers to be written.
|
347
347
|
* @param count Number of items in <em>data</em>.
|
348
|
+
* @param timeout A pointer to an integer, which specifies the maximum number of
|
349
|
+
* microseconds that may be spent on writing all the data.
|
350
|
+
* If the timeout expired then TimeoutException will be thrown.
|
351
|
+
* If this function returns without throwing an exception, then the
|
352
|
+
* total number of microseconds spent on writing will be deducted
|
353
|
+
* from <tt>timeout</tt>.
|
354
|
+
* Pass NULL if you do not want to enforce a timeout.
|
348
355
|
* @throws SystemException Something went wrong.
|
356
|
+
* @throws TimeoutException Unable to write all given data within
|
357
|
+
* <tt>timeout</tt> microseconds.
|
349
358
|
* @throws boost::thread_interrupted
|
350
359
|
*/
|
351
|
-
void gatheredWrite(int fd, const StaticString data[], unsigned int dataCount);
|
360
|
+
void gatheredWrite(int fd, const StaticString data[], unsigned int dataCount, unsigned long long *timeout = NULL);
|
352
361
|
|
353
362
|
/**
|
354
363
|
* Sets a writev-emulating function that gatheredWrite() should call instead of the real writev().
|
@@ -356,6 +365,53 @@ void gatheredWrite(int fd, const StaticString data[], unsigned int dataCount)
|
|
356
365
|
*/
|
357
366
|
void setWritevFunction(WritevFunction func);
|
358
367
|
|
368
|
+
/**
|
369
|
+
* Receive a file descriptor over the given Unix domain socket.
|
370
|
+
* This is a low-level function that directly wraps the Unix file
|
371
|
+
* descriptor passing system calls. You should not use this directly;
|
372
|
+
* instead you should use readFileDescriptorWithNegotiation() from MessageIO.h
|
373
|
+
* which is safer. See MessageIO.h for more information about the
|
374
|
+
* negotiation protocol for file descriptor passing.
|
375
|
+
*
|
376
|
+
* @param timeout A pointer to an integer, which specifies the maximum number of
|
377
|
+
* microseconds that may be spent on receiving the file descriptor.
|
378
|
+
* If the timeout expired then TimeoutException will be thrown.
|
379
|
+
* If this function returns without throwing an exception, then the
|
380
|
+
* total number of microseconds spent on receiving will be deducted
|
381
|
+
* from <tt>timeout</tt>.
|
382
|
+
* Pass NULL if you do not want to enforce a timeout.
|
383
|
+
* @return The received file descriptor.
|
384
|
+
* @throws SystemException Something went wrong.
|
385
|
+
* @throws IOException Whatever was received doesn't seem to be a
|
386
|
+
* file descriptor.
|
387
|
+
* @throws TimeoutException Unable to receive a file descriptor within
|
388
|
+
* <tt>timeout</tt> microseconds.
|
389
|
+
* @throws boost::thread_interrupted
|
390
|
+
*/
|
391
|
+
int readFileDescriptor(int fd, unsigned long long *timeout = NULL);
|
392
|
+
|
393
|
+
/**
|
394
|
+
* Pass the file descriptor 'fdToSend' over the Unix socket 'fd'.
|
395
|
+
* This is a low-level function that directly wraps the Unix file
|
396
|
+
* descriptor passing system calls. You should not use this directly;
|
397
|
+
* instead you should use writeFileDescriptorWithNegotiation() from MessageIO.h
|
398
|
+
* which is safer. See MessageIO.h for more information about the
|
399
|
+
* negotiation protocol for file descriptor passing.
|
400
|
+
*
|
401
|
+
* @param timeout A pointer to an integer, which specifies the maximum number of
|
402
|
+
* microseconds that may be spent on trying to pass the file descriptor.
|
403
|
+
* If the timeout expired then TimeoutException will be thrown.
|
404
|
+
* If this function returns without throwing an exception, then the
|
405
|
+
* total number of microseconds spent on writing will be deducted
|
406
|
+
* from <tt>timeout</tt>.
|
407
|
+
* Pass NULL if you do not want to enforce a timeout.
|
408
|
+
* @throws SystemException Something went wrong.
|
409
|
+
* @throws TimeoutException Unable to pass the file descriptor within
|
410
|
+
* <tt>timeout</tt> microseconds.
|
411
|
+
* @throws boost::thread_interrupted
|
412
|
+
*/
|
413
|
+
void writeFileDescriptor(int fd, int fdToSend, unsigned long long *timeout = NULL);
|
414
|
+
|
359
415
|
/**
|
360
416
|
* Closes the given file descriptor and throws an exception if anything goes wrong.
|
361
417
|
* This function also works around certain close() bugs on certain operating systems.
|