00001 /* 00002 * Phusion Passenger - http://www.modrails.com/ 00003 * Copyright (c) 2010 Phusion 00004 * 00005 * "Phusion Passenger" is a trademark of Hongli Lai & Ninh Bui. 00006 * 00007 * Permission is hereby granted, free of charge, to any person obtaining a copy 00008 * of this software and associated documentation files (the "Software"), to deal 00009 * in the Software without restriction, including without limitation the rights 00010 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 00011 * copies of the Software, and to permit persons to whom the Software is 00012 * furnished to do so, subject to the following conditions: 00013 * 00014 * The above copyright notice and this permission notice shall be included in 00015 * all copies or substantial portions of the Software. 00016 * 00017 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 00018 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 00019 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 00020 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 00021 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 00022 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 00023 * THE SOFTWARE. 00024 */ 00025 #ifndef _PASSENGER_MESSAGE_CHANNEL_H_ 00026 #define _PASSENGER_MESSAGE_CHANNEL_H_ 00027 00028 #include <oxt/system_calls.hpp> 00029 #include <oxt/macros.hpp> 00030 00031 #include <algorithm> 00032 #include <string> 00033 #include <list> 00034 #include <vector> 00035 00036 #include <sys/types.h> 00037 #include <sys/socket.h> 00038 #include <sys/uio.h> 00039 #include <arpa/inet.h> 00040 #include <errno.h> 00041 #include <unistd.h> 00042 #include <cstdarg> 00043 #include <cmath> 00044 #if !APR_HAVE_IOVEC 00045 // We don't want apr_want.h to redefine 'struct iovec'. 00046 // http://groups.google.com/group/phusion-passenger/browse_thread/thread/7e162f60df212e9c 00047 #undef APR_HAVE_IOVEC 00048 #define APR_HAVE_IOVEC 1 00049 #endif 00050 00051 #include "StaticString.h" 00052 #include "Exceptions.h" 00053 #include "Utils/Timer.h" 00054 #include "Utils/MemZeroGuard.h" 00055 #include "Utils/IOUtils.h" 00056 00057 namespace Passenger { 00058 00059 using namespace std; 00060 using namespace oxt; 00061 00062 00063 /** 00064 * Convenience class for I/O operations on file descriptors. 00065 * 00066 * This class provides convenience methods for: 00067 * - sending and receiving raw data over a file descriptor. 00068 * - sending and receiving messages over a file descriptor. 00069 * - file descriptor passing over a Unix socket. 00070 * - data size limit enforcement and time constraint enforcement. 00071 * All of these methods use exceptions for error reporting. 00072 * 00073 * There are two kinds of messages: 00074 * - Array messages. These are just a list of strings, and the message 00075 * itself has a specific length. The contained strings may not 00076 * contain NUL characters (<tt>'\\0'</tt>). Note that an array message 00077 * must have at least one element. 00078 * - Scalar messages. These are byte strings which may contain arbitrary 00079 * binary data. Scalar messages also have a specific length. 00080 * The protocol is designed to be low overhead, easy to implement and 00081 * easy to parse. 00082 * 00083 * MessageChannel is to be wrapped around a file descriptor. For example: 00084 * @code 00085 * int p[2]; 00086 * pipe(p); 00087 * MessageChannel channel1(p[0]); 00088 * MessageChannel channel2(p[1]); 00089 * 00090 * // Send an array message. 00091 * channel2.write("hello", "world !!", NULL); 00092 * list<string> args; 00093 * channel1.read(args); // args now contains { "hello", "world !!" } 00094 * 00095 * // Send a scalar message. 00096 * channel2.writeScalar("some long string which can contain arbitrary binary data"); 00097 * string str; 00098 * channel1.readScalar(str); 00099 * @endcode 00100 * 00101 * The life time of a MessageChannel is independent from that of the 00102 * wrapped file descriptor. If a MessageChannel object is destroyed, 00103 * the file descriptor is not automatically closed. Call close() 00104 * if you want to close the file descriptor. 00105 * 00106 * @note I/O operations are not buffered. 00107 * @note Be careful with mixing the sending/receiving of array messages, 00108 * scalar messages and file descriptors. If you send a collection of any 00109 * of these in a specific order, then the receiving side must receive them 00110 * in the exact some order. So suppose you first send a message, then a 00111 * file descriptor, then a scalar, then the receiving side must first 00112 * receive a message, then a file descriptor, then a scalar. If the 00113 * receiving side does things in the wrong order then bad things will 00114 * happen. 00115 * @note MessageChannel is not thread-safe, but is reentrant. 00116 * @note Some methods throw SecurityException and TimeoutException. When these 00117 * exceptions are thrown, the channel will be left in an inconsistent state 00118 * because only parts of the data have been read. You should close the channel 00119 * after having caught these exceptions. 00120 * 00121 * @ingroup Support 00122 */ 00123 class MessageChannel { 00124 private: 00125 const static char DELIMITER = '\0'; 00126 int fd; 00127 00128 #ifdef __OpenBSD__ 00129 typedef u_int32_t uint32_t; 00130 typedef u_int16_t uint16_t; 00131 #endif 00132 00133 public: 00134 /** 00135 * Construct a new MessageChannel with no underlying file descriptor. 00136 * Thus the resulting MessageChannel object will not be usable. 00137 * This constructor exists to allow one to declare an "empty" 00138 * MessageChannel variable which is to be initialized later. 00139 */ 00140 MessageChannel() { 00141 this->fd = -1; 00142 } 00143 00144 /** 00145 * Construct a new MessageChannel with the given file descriptor. 00146 */ 00147 MessageChannel(int fd) { 00148 this->fd = fd; 00149 } 00150 00151 /** 00152 * Returns the underlying file descriptor. -1 if it has already been closed. 00153 */ 00154 int filenum() const { 00155 return fd; 00156 } 00157 00158 /** 00159 * Returns whether close() has been called. 00160 */ 00161 bool connected() const { 00162 return fd != -1; 00163 } 00164 00165 /** 00166 * Close the underlying file descriptor. If this method is called multiple 00167 * times, the file descriptor will only be closed the first time. 00168 * 00169 * @throw SystemException 00170 * @throw boost::thread_interrupted 00171 * @post filenum() == -1 00172 * @post !connected() 00173 */ 00174 void close() { 00175 if (fd != -1) { 00176 int ret = syscalls::close(fd); 00177 fd = -1; 00178 if (ret == -1) { 00179 throw SystemException("Cannot close file descriptor", errno); 00180 } 00181 } 00182 } 00183 00184 /** 00185 * Send an array message, which consists of the given elements, over the underlying 00186 * file descriptor. 00187 * 00188 * @param args An object which contains the message elements. This object must 00189 * support STL-style iteration, and each iterator must have an 00190 * std::string as value. Use the StringArrayType and 00191 * StringArrayConstIteratorType template parameters to specify the exact type names. 00192 * @throws SystemException An error occured while writing the data to the file descriptor. 00193 * @throws boost::thread_interrupted 00194 * @pre None of the message elements may contain a NUL character (<tt>'\\0'</tt>). 00195 * @see read(), write(const char *, ...) 00196 */ 00197 template<typename StringArrayType, typename StringArrayConstIteratorType> 00198 void write(const StringArrayType &args) { 00199 StringArrayConstIteratorType it; 00200 string data; 00201 uint16_t dataSize = 0; 00202 00203 for (it = args.begin(); it != args.end(); it++) { 00204 dataSize += it->size() + 1; 00205 } 00206 data.reserve(dataSize + sizeof(dataSize)); 00207 dataSize = htons(dataSize); 00208 data.append((const char *) &dataSize, sizeof(dataSize)); 00209 for (it = args.begin(); it != args.end(); it++) { 00210 data.append(*it); 00211 data.append(1, DELIMITER); 00212 } 00213 00214 writeExact(fd, data); 00215 } 00216 00217 /** 00218 * Send an array message, which consists of the given elements, over the underlying 00219 * file descriptor. 00220 * 00221 * @param args The message elements. 00222 * @throws SystemException An error occured while writing the data to the file descriptor. 00223 * @throws boost::thread_interrupted 00224 * @pre None of the message elements may contain a NUL character (<tt>'\\0'</tt>). 00225 * @see read(), write(const char *, ...) 00226 */ 00227 void write(const list<string> &args) { 00228 write<list<string>, list<string>::const_iterator>(args); 00229 } 00230 00231 /** 00232 * Send an array message, which consists of the given elements, over the underlying 00233 * file descriptor. 00234 * 00235 * @param args The message elements. 00236 * @throws SystemException An error occured while writing the data to the file descriptor. 00237 * @throws boost::thread_interrupted 00238 * @pre None of the message elements may contain a NUL character (<tt>'\\0'</tt>). 00239 * @see read(), write(const char *, ...) 00240 */ 00241 void write(const vector<string> &args) { 00242 write<vector<string>, vector<string>::const_iterator>(args); 00243 } 00244 00245 /** 00246 * Send an array message, which consists of the given strings, over the underlying 00247 * file descriptor. Like <tt>write(const char *name, ...)</tt> but takes a va_list 00248 * instead. 00249 * 00250 * @throws SystemException An error occured while writing the data to the file descriptor. 00251 * @throws boost::thread_interrupted 00252 * @pre None of the message elements may contain a NUL character (<tt>'\\0'</tt>). 00253 */ 00254 void write(const char *name, va_list &ap) { 00255 list<string> args; 00256 args.push_back(name); 00257 00258 while (true) { 00259 const char *arg = va_arg(ap, const char *); 00260 if (arg == NULL) { 00261 break; 00262 } else { 00263 args.push_back(arg); 00264 } 00265 } 00266 write(args); 00267 } 00268 00269 /** 00270 * Send an array message, which consists of the given strings, over the underlying 00271 * file descriptor. 00272 * 00273 * @param name The first element of the message to send. 00274 * @param ... Other elements of the message. These *must* be strings, i.e. of type char*. 00275 * It is also required to terminate this list with a NULL. 00276 * @throws SystemException An error occured while writing the data to the file descriptor. 00277 * @throws boost::thread_interrupted 00278 * @pre None of the message elements may contain a NUL character (<tt>'\\0'</tt>). 00279 * @see read(), write(const list<string> &) 00280 */ 00281 void write(const char *name, ...) { 00282 va_list ap; 00283 va_start(ap, name); 00284 try { 00285 write(name, ap); 00286 va_end(ap); 00287 } catch (...) { 00288 va_end(ap); 00289 throw; 00290 } 00291 } 00292 00293 /** 00294 * Write a 32-bit big-endian unsigned integer to the underlying file descriptor. 00295 * 00296 * @throws SystemException An error occurred while writing the data to the file descriptor. 00297 * @throws boost::thread_interrupted 00298 */ 00299 void writeUint32(unsigned int value) { 00300 uint32_t l = htonl(value); 00301 writeExact(fd, &l, sizeof(uint32_t)); 00302 } 00303 00304 /** 00305 * Write a scalar message to the underlying file descriptor. 00306 * 00307 * @note Security guarantee: this method will not copy the data in memory, 00308 * so it's safe to use this method to write passwords to the underlying 00309 * file descriptor. 00310 * 00311 * @param str The scalar message's content. 00312 * @throws SystemException An error occured while writing the data to the file descriptor. 00313 * @throws boost::thread_interrupted 00314 * @see readScalar(), writeScalar(const char *, unsigned int) 00315 */ 00316 void writeScalar(const string &str) { 00317 writeScalar(str.c_str(), str.size()); 00318 } 00319 00320 /** 00321 * Write a scalar message to the underlying file descriptor. 00322 * 00323 * @note Security guarantee: this method will not copy the data in memory, 00324 * so it's safe to use this method to write passwords to the underlying 00325 * file descriptor. 00326 * 00327 * @param data The scalar message's content. 00328 * @param size The number of bytes in <tt>data</tt>. 00329 * @pre <tt>data != NULL</tt> 00330 * @throws SystemException An error occured while writing the data to the file descriptor. 00331 * @throws boost::thread_interrupted 00332 * @see readScalar(), writeScalar(const string &) 00333 */ 00334 void writeScalar(const char *data, unsigned int size) { 00335 writeUint32(size); 00336 writeExact(fd, data, size); 00337 } 00338 00339 /** 00340 * Pass a file descriptor. This only works if the underlying file 00341 * descriptor is a Unix socket. 00342 * 00343 * @param fileDescriptor The file descriptor to pass. 00344 * @param negotiate See Ruby's MessageChannel#send_io method's comments. 00345 * @throws SystemException Something went wrong during file descriptor passing. 00346 * @throws boost::thread_interrupted 00347 * @pre <tt>fileDescriptor >= 0</tt> 00348 * @see readFileDescriptor() 00349 */ 00350 void writeFileDescriptor(int fileDescriptor, bool negotiate = true) { 00351 // See message_channel.rb for more info about negotiation. 00352 if (negotiate) { 00353 vector<string> args; 00354 00355 if (!read(args)) { 00356 throw IOException("Unexpected end of stream encountered while pre-negotiating a file descriptor"); 00357 } else if (args.size() != 1 || args[0] != "pass IO") { 00358 throw IOException("FD passing pre-negotiation message expected."); 00359 } 00360 } 00361 00362 struct msghdr msg; 00363 struct iovec vec; 00364 char dummy[1]; 00365 #if defined(__APPLE__) || defined(__SOLARIS__) || defined(__arm__) 00366 struct { 00367 struct cmsghdr header; 00368 int fd; 00369 } control_data; 00370 #else 00371 char control_data[CMSG_SPACE(sizeof(int))]; 00372 #endif 00373 struct cmsghdr *control_header; 00374 int ret; 00375 00376 msg.msg_name = NULL; 00377 msg.msg_namelen = 0; 00378 00379 /* Linux and Solaris require msg_iov to be non-NULL. */ 00380 dummy[0] = '\0'; 00381 vec.iov_base = dummy; 00382 vec.iov_len = sizeof(dummy); 00383 msg.msg_iov = &vec; 00384 msg.msg_iovlen = 1; 00385 00386 msg.msg_control = (caddr_t) &control_data; 00387 msg.msg_controllen = sizeof(control_data); 00388 msg.msg_flags = 0; 00389 00390 control_header = CMSG_FIRSTHDR(&msg); 00391 control_header->cmsg_level = SOL_SOCKET; 00392 control_header->cmsg_type = SCM_RIGHTS; 00393 #if defined(__APPLE__) || defined(__SOLARIS__) || defined(__arm__) 00394 control_header->cmsg_len = sizeof(control_data); 00395 control_data.fd = fileDescriptor; 00396 #else 00397 control_header->cmsg_len = CMSG_LEN(sizeof(int)); 00398 memcpy(CMSG_DATA(control_header), &fileDescriptor, sizeof(int)); 00399 #endif 00400 00401 ret = syscalls::sendmsg(fd, &msg, 0); 00402 if (ret == -1) { 00403 throw SystemException("Cannot send file descriptor with sendmsg()", errno); 00404 } 00405 00406 if (negotiate) { 00407 vector<string> args; 00408 00409 if (!read(args)) { 00410 throw IOException("Unexpected end of stream encountered while post-negotiating a file descriptor"); 00411 } else if (args.size() != 1 || args[0] != "got IO") { 00412 throw IOException("FD passing post-negotiation message expected."); 00413 } 00414 } 00415 } 00416 00417 /** 00418 * Read an array message from the underlying file descriptor. 00419 * 00420 * @param args The message will be put in this variable. 00421 * @return Whether end-of-file has been reached. If so, then the contents 00422 * of <tt>args</tt> will be undefined. 00423 * @throws SystemException If an error occured while receiving the message. 00424 * @throws boost::thread_interrupted 00425 * @see write() 00426 */ 00427 bool read(vector<string> &args) { 00428 uint16_t size; 00429 int ret; 00430 unsigned int alreadyRead = 0; 00431 00432 do { 00433 ret = syscalls::read(fd, (char *) &size + alreadyRead, sizeof(size) - alreadyRead); 00434 if (ret == -1) { 00435 throw SystemException("read() failed", errno); 00436 } else if (ret == 0) { 00437 return false; 00438 } 00439 alreadyRead += ret; 00440 } while (alreadyRead < sizeof(size)); 00441 size = ntohs(size); 00442 00443 string buffer; 00444 args.clear(); 00445 buffer.reserve(size); 00446 while (buffer.size() < size) { 00447 char tmp[1024 * 8]; 00448 ret = syscalls::read(fd, tmp, min(size - buffer.size(), sizeof(tmp))); 00449 if (ret == -1) { 00450 throw SystemException("read() failed", errno); 00451 } else if (ret == 0) { 00452 return false; 00453 } 00454 buffer.append(tmp, ret); 00455 } 00456 00457 if (!buffer.empty()) { 00458 string::size_type start = 0, pos; 00459 const string &const_buffer(buffer); 00460 while ((pos = const_buffer.find('\0', start)) != string::npos) { 00461 args.push_back(const_buffer.substr(start, pos - start)); 00462 start = pos + 1; 00463 } 00464 } 00465 return true; 00466 } 00467 00468 /** 00469 * Read a 32-bit big-endian unsigned integer from the underlying file descriptor. 00470 * 00471 * @param value Upon success, the read value will be stored in here. 00472 * @param timeout A pointer to an integer, representing the maximum number of 00473 * milliseconds to spend on reading the entire integer. 00474 * A TimeoutException will be thrown if the timeout expires. 00475 * If no exception is thrown, the the amount of time spent on waiting 00476 * will be deducted from <tt>*timeout</tt>. 00477 * Pass NULL if you do not want to enforce any time limits. 00478 * @return True if a value was read, false if EOF was reached before all data can be 00479 * read. 00480 * @throws SystemException An error occurred while reading data from the file descriptor. 00481 * @throws boost::thread_interrupted 00482 */ 00483 bool readUint32(unsigned int &value, unsigned long long *timeout = NULL) { 00484 uint32_t temp; 00485 00486 if (!readRaw(&temp, sizeof(uint32_t), timeout)) { 00487 return false; 00488 } else { 00489 value = ntohl(temp); 00490 return true; 00491 } 00492 } 00493 00494 /** 00495 * Read a scalar message from the underlying file descriptor. 00496 * 00497 * @param output The message will be put in here. 00498 * @param maxSize The maximum number of bytes that may be read. If the 00499 * scalar to read is larger than this, then a SecurityException 00500 * will be thrown. Set to 0 for no size limit. 00501 * @param timeout A pointer to an integer, representing the maximum number of 00502 * milliseconds to spend on reading the entire scalar. 00503 * A TimeoutException will be thrown if unable to read the entire 00504 * scalar within this time period. 00505 * If no exception is thrown, the the amount of time spent on waiting 00506 * will be deducted from <tt>*timeout</tt>. 00507 * Pass NULL if you do not want to enforce any time limits. 00508 * @returns Whether end-of-file was reached during reading. 00509 * @throws SystemException An error occured while reading data from the file descriptor. 00510 * @throws SecurityException There is more data to read than allowed by maxSize. 00511 * @throws TimeoutException Unable to read the entire scalar within <tt>timeout</tt> 00512 * milliseconds. 00513 * @throws boost::thread_interrupted 00514 * @see writeScalar() 00515 */ 00516 bool readScalar(string &output, unsigned int maxSize = 0, unsigned long long *timeout = NULL) { 00517 unsigned int size; 00518 unsigned int remaining; 00519 00520 if (!readUint32(size, timeout)) { 00521 return false; 00522 } 00523 00524 if (maxSize != 0 && size > maxSize) { 00525 throw SecurityException("There is more data available than is allowed by the size limit."); 00526 } 00527 00528 output.clear(); 00529 output.reserve(size); 00530 remaining = size; 00531 if (OXT_LIKELY(remaining > 0)) { 00532 char buf[1024 * 32]; 00533 // Wipe the buffer when we're done; it might contain sensitive data. 00534 MemZeroGuard g(buf, sizeof(buf)); 00535 00536 while (remaining > 0) { 00537 unsigned int blockSize = min((unsigned int) sizeof(buf), remaining); 00538 00539 if (!readRaw(buf, blockSize, timeout)) { 00540 return false; 00541 } 00542 output.append(buf, blockSize); 00543 remaining -= blockSize; 00544 } 00545 } 00546 return true; 00547 } 00548 00549 /** 00550 * Read exactly <tt>size</tt> bytes of data from the underlying file descriptor, 00551 * and put the result in <tt>buf</tt>. If end-of-file has been reached, or if 00552 * end-of-file was encountered before <tt>size</tt> bytes have been read, then 00553 * <tt>false</tt> will be returned. Otherwise (i.e. if the read was successful), 00554 * <tt>true</tt> will be returned. 00555 * 00556 * @param buf The buffer to place the read data in. This buffer must be at least 00557 * <tt>size</tt> bytes long. 00558 * @param size The number of bytes to read. 00559 * @param timeout A pointer to an integer, which specifies the maximum number of 00560 * milliseconds that may be spent on reading the <tt>size</tt> bytes 00561 * of data. If the timeout expired then TimeoutException will be 00562 * thrown. 00563 * If this function returns without throwing an exception, then the 00564 * total number of milliseconds spent on reading will be deducted 00565 * from <tt>timeout</tt>. 00566 * Pass NULL if you do not want to enforce a timeout. 00567 * @return Whether reading was successful or whether EOF was reached. 00568 * @pre buf != NULL 00569 * @throws SystemException Something went wrong during reading. 00570 * @throws TimeoutException Unable to read <tt>size</tt> bytes of data within 00571 * <tt>timeout</tt> milliseconds. 00572 * @throws boost::thread_interrupted 00573 */ 00574 bool readRaw(void *buf, unsigned int size, unsigned long long *timeout = NULL) { 00575 if (timeout != NULL) { 00576 unsigned long long t = *timeout * 1000; 00577 unsigned int ret; 00578 try { 00579 ret = Passenger::readExact(fd, buf, size, &t); 00580 #if defined(__NetBSD__) || defined(__OpenBSD__) 00581 *timeout = llround((double) t / 1000); 00582 #else 00583 *timeout = llroundl((long double) t / 1000); 00584 #endif 00585 return ret == size; 00586 } catch (...) { 00587 #if defined(__NetBSD__) || defined(__OpenBSD__) 00588 *timeout = llround((double) t / 1000); 00589 #else 00590 *timeout = llroundl((long double) t / 1000); 00591 #endif 00592 throw; 00593 } 00594 } else { 00595 return Passenger::readExact(fd, buf, size) == size; 00596 } 00597 } 00598 00599 /** 00600 * Receive a file descriptor, which had been passed over the underlying 00601 * file descriptor. 00602 * 00603 * @param negotiate See Ruby's MessageChannel#send_io method's comments. 00604 * @return The passed file descriptor. 00605 * @throws SystemException If something went wrong during the 00606 * receiving of a file descriptor. Perhaps the underlying 00607 * file descriptor isn't a Unix socket. 00608 * @throws IOException Whatever was received doesn't seem to be a 00609 * file descriptor. 00610 * @throws boost::thread_interrupted 00611 */ 00612 int readFileDescriptor(bool negotiate = true) { 00613 // See message_channel.rb for more info about negotiation. 00614 if (negotiate) { 00615 write("pass IO", NULL); 00616 } 00617 00618 struct msghdr msg; 00619 struct iovec vec; 00620 char dummy[1]; 00621 #if defined(__APPLE__) || defined(__SOLARIS__) || defined(__arm__) 00622 // File descriptor passing macros (CMSG_*) seem to be broken 00623 // on 64-bit MacOS X. This structure works around the problem. 00624 struct { 00625 struct cmsghdr header; 00626 int fd; 00627 } control_data; 00628 #define EXPECTED_CMSG_LEN sizeof(control_data) 00629 #else 00630 char control_data[CMSG_SPACE(sizeof(int))]; 00631 #define EXPECTED_CMSG_LEN CMSG_LEN(sizeof(int)) 00632 #endif 00633 struct cmsghdr *control_header; 00634 int ret; 00635 00636 msg.msg_name = NULL; 00637 msg.msg_namelen = 0; 00638 00639 dummy[0] = '\0'; 00640 vec.iov_base = dummy; 00641 vec.iov_len = sizeof(dummy); 00642 msg.msg_iov = &vec; 00643 msg.msg_iovlen = 1; 00644 00645 msg.msg_control = (caddr_t) &control_data; 00646 msg.msg_controllen = sizeof(control_data); 00647 msg.msg_flags = 0; 00648 00649 ret = syscalls::recvmsg(fd, &msg, 0); 00650 if (ret == -1) { 00651 throw SystemException("Cannot read file descriptor with recvmsg()", errno); 00652 } 00653 00654 control_header = CMSG_FIRSTHDR(&msg); 00655 if (control_header == NULL) { 00656 throw IOException("No valid file descriptor received."); 00657 } 00658 if (control_header->cmsg_len != EXPECTED_CMSG_LEN 00659 || control_header->cmsg_level != SOL_SOCKET 00660 || control_header->cmsg_type != SCM_RIGHTS) { 00661 throw IOException("No valid file descriptor received."); 00662 } 00663 00664 #if defined(__APPLE__) || defined(__SOLARIS__) || defined(__arm__) 00665 int fd = control_data.fd; 00666 #else 00667 int fd = *((int *) CMSG_DATA(control_header)); 00668 #endif 00669 00670 if (negotiate) { 00671 try { 00672 write("got IO", NULL); 00673 } catch (...) { 00674 this_thread::disable_syscall_interruption dsi; 00675 syscalls::close(fd); 00676 throw; 00677 } 00678 } 00679 00680 return fd; 00681 } 00682 00683 /** 00684 * Set the timeout value for reading data from this channel. 00685 * If no data can be read within the timeout period, then a 00686 * SystemException will be thrown by one of the read methods, 00687 * with error code EAGAIN or EWOULDBLOCK. 00688 * 00689 * @param msec The timeout, in milliseconds. If 0 is given, 00690 * there will be no timeout. 00691 * @throws SystemException Cannot set the timeout. 00692 */ 00693 void setReadTimeout(unsigned int msec) { 00694 // See the comment for setWriteTimeout(). 00695 struct timeval tv; 00696 int ret; 00697 00698 tv.tv_sec = msec / 1000; 00699 tv.tv_usec = msec % 1000 * 1000; 00700 ret = syscalls::setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, 00701 &tv, sizeof(tv)); 00702 #ifndef __SOLARIS__ 00703 // SO_RCVTIMEO is unimplemented and returns an error on Solaris 00704 // 9 and 10 SPARC. Seems to work okay without it. 00705 if (ret == -1) { 00706 throw SystemException("Cannot set read timeout for socket", errno); 00707 } 00708 #endif 00709 } 00710 00711 /** 00712 * Set the timeout value for writing data to this channel. 00713 * If no data can be written within the timeout period, then a 00714 * SystemException will be thrown, with error code EAGAIN or 00715 * EWOULDBLOCK. 00716 * 00717 * @param msec The timeout, in milliseconds. If 0 is given, 00718 * there will be no timeout. 00719 * @throws SystemException Cannot set the timeout. 00720 */ 00721 void setWriteTimeout(unsigned int msec) { 00722 // People say that SO_RCVTIMEO/SO_SNDTIMEO are unreliable and 00723 // not well-implemented on all platforms. 00724 // http://www.developerweb.net/forum/archive/index.php/t-3439.html 00725 // That's why we use APR's timeout facilities as well (see Hooks.cpp). 00726 struct timeval tv; 00727 int ret; 00728 00729 tv.tv_sec = msec / 1000; 00730 tv.tv_usec = msec % 1000 * 1000; 00731 ret = syscalls::setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, 00732 &tv, sizeof(tv)); 00733 #ifndef __SOLARIS__ 00734 // SO_SNDTIMEO is unimplemented and returns an error on Solaris 00735 // 9 and 10 SPARC. Seems to work okay without it. 00736 if (ret == -1) { 00737 throw SystemException("Cannot set read timeout for socket", errno); 00738 } 00739 #endif 00740 } 00741 }; 00742 00743 } // namespace Passenger 00744 00745 #endif /* _PASSENGER_MESSAGE_CHANNEL_H_ */