ext/common/MessageChannel.h in passenger-jmazzi-2.2.9 vs ext/common/MessageChannel.h in passenger-jmazzi-2.2.10
- old
+ new
@@ -317,16 +317,28 @@
/**
* Pass a file descriptor. This only works if the underlying file
* descriptor is a Unix socket.
*
* @param fileDescriptor The file descriptor to pass.
+ * @param negotiate See Ruby's MessageChannel#send_io method's comments.
* @throws SystemException Something went wrong during file descriptor passing.
* @throws boost::thread_interrupted
* @pre <tt>fileDescriptor >= 0</tt>
* @see readFileDescriptor()
*/
- void writeFileDescriptor(int fileDescriptor) {
+ void writeFileDescriptor(int fileDescriptor, bool negotiate = true) {
+ // See message_channel.rb for more info about negotiation.
+ if (negotiate) {
+ vector<string> args;
+
+ if (!read(args)) {
+ throw IOException("Unexpected end of stream encountered while pre-negotiating a file descriptor");
+ } else if (args.size() != 1 || args[0] != "pass IO") {
+ throw IOException("FD passing pre-negotiation message expected.");
+ }
+ }
+
struct msghdr msg;
struct iovec vec;
char dummy[1];
#if defined(__APPLE__) || defined(__SOLARIS__) || defined(__arm__)
struct {
@@ -366,10 +378,20 @@
ret = syscalls::sendmsg(fd, &msg, 0);
if (ret == -1) {
throw SystemException("Cannot send file descriptor with sendmsg()", errno);
}
+
+ if (negotiate) {
+ vector<string> args;
+
+ if (!read(args)) {
+ throw IOException("Unexpected end of stream encountered while post-negotiating a file descriptor");
+ } else if (args.size() != 1 || args[0] != "got IO") {
+ throw IOException("FD passing post-negotiation message expected.");
+ }
+ }
}
/**
* Read an array message from the underlying file descriptor.
*
@@ -490,19 +512,25 @@
/**
* Receive a file descriptor, which had been passed over the underlying
* file descriptor.
*
+ * @param negotiate See Ruby's MessageChannel#send_io method's comments.
* @return The passed file descriptor.
* @throws SystemException If something went wrong during the
* receiving of a file descriptor. Perhaps the underlying
* file descriptor isn't a Unix socket.
* @throws IOException Whatever was received doesn't seem to be a
* file descriptor.
* @throws boost::thread_interrupted
*/
- int readFileDescriptor() {
+ int readFileDescriptor(bool negotiate = true) {
+ // See message_channel.rb for more info about negotiation.
+ if (negotiate) {
+ write("pass IO", NULL);
+ }
+
struct msghdr msg;
struct iovec vec;
char dummy[1];
#if defined(__APPLE__) || defined(__SOLARIS__) || defined(__arm__)
// File descriptor passing macros (CMSG_*) seem to be broken
@@ -536,19 +564,35 @@
if (ret == -1) {
throw SystemException("Cannot read file descriptor with recvmsg()", errno);
}
control_header = CMSG_FIRSTHDR(&msg);
+ if (control_header == NULL) {
+ throw IOException("No valid file descriptor received.");
+ }
if (control_header->cmsg_len != EXPECTED_CMSG_LEN
|| control_header->cmsg_level != SOL_SOCKET
|| control_header->cmsg_type != SCM_RIGHTS) {
throw IOException("No valid file descriptor received.");
}
+
#if defined(__APPLE__) || defined(__SOLARIS__) || defined(__arm__)
- return control_data.fd;
+ int fd = control_data.fd;
#else
- return *((int *) CMSG_DATA(control_header));
+ int fd = *((int *) CMSG_DATA(control_header));
#endif
+
+ if (negotiate) {
+ try {
+ write("got IO", NULL);
+ } catch (...) {
+ this_thread::disable_syscall_interruption dsi;
+ syscalls::close(fd);
+ throw;
+ }
+ }
+
+ return fd;
}
/**
* Set the timeout value for reading data from this channel.
* If no data can be read within the timeout period, then a