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