ian@0: // ian@0: // Boost.Process ian@0: // ~~~~~~~~~~~~~ ian@0: // ian@0: // Copyright (c) 2006, 2007 Julio M. Merino Vidal ian@0: // Copyright (c) 2008 Ilya Sokolov, Boris Schaeling ian@0: // Copyright (c) 2009 Boris Schaeling ian@0: // Copyright (c) 2010 Felipe Tanus, Boris Schaeling ian@0: // ian@0: // Distributed under the Boost Software License, Version 1.0. (See accompanying ian@0: // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ian@0: // ian@0: ian@0: /** ian@0: * \file boost/process/stream_behavior.hpp ian@0: * ian@0: * Includes the declaration of stream behavior classes. ian@0: */ ian@0: ian@0: #ifndef BOOST_PROCESS_STREAM_BEHAVIOR_HPP ian@0: #define BOOST_PROCESS_STREAM_BEHAVIOR_HPP ian@0: ian@0: #include ian@0: ian@0: #if defined(BOOST_POSIX_API) ian@0: # include ian@0: # include ian@0: # include ian@0: #elif defined(BOOST_WINDOWS_API) ian@0: # include ian@0: # include ian@0: #endif ian@0: ian@0: #include ian@0: #include ian@0: #include ian@0: #include ian@0: #include ian@0: ian@0: namespace boost { ian@0: namespace process { ian@0: namespace behavior { ian@0: ian@0: /** ian@0: * Stream behavior to close streams of a child process. ian@0: * ian@0: * A child process will not be able to use the stream. ian@0: */ ian@0: class close ian@0: { ian@0: public: ian@0: stream_ends operator()(stream_type) const ian@0: { ian@0: return stream_ends(); ian@0: } ian@0: }; ian@0: ian@0: /** ian@0: * Stream behavior to make a child process inherit streams. ian@0: * ian@0: * A child process will use the very same stream of its parent process. ian@0: */ ian@0: class inherit ian@0: { ian@0: public: ian@0: inherit(handle::native_type h) ian@0: : h_(h, handle::dont_close) ian@0: { ian@0: #if defined(BOOST_WINDOWS_API) ian@0: if (h != INVALID_HANDLE_VALUE) ian@0: { ian@0: if (!SetHandleInformation(h_.native(), HANDLE_FLAG_INHERIT, ian@0: HANDLE_FLAG_INHERIT)) ian@0: { ian@0: HANDLE proc = GetCurrentProcess(); ian@0: HANDLE dup; ian@0: if (!DuplicateHandle(proc, h_.native(), proc, &dup, 0, ian@0: TRUE, DUPLICATE_SAME_ACCESS)) ian@0: { ian@0: BOOST_PROCESS_THROW_LAST_SYSTEM_ERROR( ian@0: "DuplicateHandle() failed"); ian@0: } ian@0: h_ = dup; ian@0: } ian@0: } ian@0: #endif ian@0: } ian@0: ian@0: stream_ends operator()(stream_type) const ian@0: { ian@0: return stream_ends(h_, handle()); ian@0: } ian@0: ian@0: private: ian@0: handle h_; ian@0: }; ian@0: ian@0: /** ian@0: * Stream behavior to redirect streams with a pipe. ian@0: * ian@0: * A child process will be able to communicate with its parent process. ian@0: */ ian@0: class pipe ian@0: { ian@0: public: ian@0: #if defined(BOOST_POSIX_API) ian@0: pipe() ian@0: : stype_(unknown_stream) ian@0: { ian@0: } ian@0: ian@0: pipe(stream_type stype) ian@0: : stype_(stype) ian@0: { ian@0: } ian@0: #endif ian@0: ian@0: stream_ends operator()(stream_type stype) const ian@0: { ian@0: handle::native_type ends[2]; ian@0: #if defined(BOOST_POSIX_API) ian@0: if (::pipe(ends) == -1) ian@0: BOOST_PROCESS_THROW_LAST_SYSTEM_ERROR("pipe(2) failed"); ian@0: if (stype_ != unknown_stream) ian@0: stype = stype_; ian@0: #elif defined(BOOST_WINDOWS_API) ian@0: SECURITY_ATTRIBUTES sa; ian@0: ZeroMemory(&sa, sizeof(sa)); ian@0: sa.nLength = sizeof(sa); ian@0: sa.lpSecurityDescriptor = NULL; ian@0: sa.bInheritHandle = FALSE; ian@0: if (!CreatePipe(&ends[0], &ends[1], &sa, 0)) ian@0: BOOST_PROCESS_THROW_LAST_SYSTEM_ERROR("CreatePipe() failed"); ian@0: #endif ian@0: handle child_end = ends[stype == input_stream ? 0 : 1]; ian@0: handle parent_end = ends[stype == input_stream ? 1 : 0]; ian@0: #if defined(BOOST_WINDOWS_API) ian@0: if (!SetHandleInformation(child_end.native(), HANDLE_FLAG_INHERIT, ian@0: HANDLE_FLAG_INHERIT)) ian@0: BOOST_PROCESS_THROW_LAST_SYSTEM_ERROR( ian@0: "SetHandleInformation() failed"); ian@0: #endif ian@0: return stream_ends(child_end, parent_end); ian@0: } ian@0: ian@0: #if defined(BOOST_POSIX_API) ian@0: private: ian@0: stream_type stype_; ian@0: #endif ian@0: }; ian@0: ian@0: /** ian@0: * Stream behavior to redirect streams with a named pipe. ian@0: * ian@0: * A child process will be able to communicate with its parent process. ian@0: */ ian@0: class named_pipe ian@0: { ian@0: public: ian@0: named_pipe(const std::string &name) ian@0: : name_(name) ian@0: #if defined(BOOST_POSIX_API) ian@0: , stype_(unknown_stream) ian@0: #endif ian@0: { ian@0: } ian@0: ian@0: #if defined(BOOST_POSIX_API) ian@0: named_pipe(const std::string &name, stream_type stype) ian@0: : name_(name), ian@0: stype_(stype) ian@0: { ian@0: } ian@0: #endif ian@0: ian@0: stream_ends operator()(stream_type stype) const ian@0: { ian@0: #if defined(BOOST_POSIX_API) ian@0: if (mkfifo(name_.c_str(), S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) == -1) ian@0: BOOST_PROCESS_THROW_LAST_SYSTEM_ERROR("mkfifo(3) failed"); ian@0: handle child_end = open(name_.c_str(), O_RDONLY | O_NONBLOCK); ian@0: if (!child_end.valid()) ian@0: BOOST_PROCESS_THROW_LAST_SYSTEM_ERROR("open(2) failed"); ian@0: int opts = fcntl(child_end.native(), F_GETFL); ian@0: if (opts == -1) ian@0: BOOST_PROCESS_THROW_LAST_SYSTEM_ERROR("fcntl(2) failed"); ian@0: opts ^= O_NONBLOCK; ian@0: if (fcntl(child_end.native(), F_SETFL, opts) == -1) ian@0: BOOST_PROCESS_THROW_LAST_SYSTEM_ERROR("fcntl(2) failed"); ian@0: handle parent_end = open(name_.c_str(), O_WRONLY); ian@0: if (!parent_end.valid()) ian@0: BOOST_PROCESS_THROW_LAST_SYSTEM_ERROR("open(2) failed"); ian@0: if (stype_ != unknown_stream) ian@0: stype = stype_; ian@0: #elif defined(BOOST_WINDOWS_API) ian@0: SECURITY_ATTRIBUTES sa; ian@0: ZeroMemory(&sa, sizeof(sa)); ian@0: sa.nLength = sizeof(sa); ian@0: sa.lpSecurityDescriptor = NULL; ian@0: sa.bInheritHandle = TRUE; ian@0: handle child_end = CreateNamedPipeA(name_.c_str(), PIPE_ACCESS_INBOUND | ian@0: FILE_FLAG_OVERLAPPED, 0, 1, 8192, 8192, 0, &sa); ian@0: if (!child_end.valid()) ian@0: BOOST_PROCESS_THROW_LAST_SYSTEM_ERROR("CreateNamedPipe() failed"); ian@0: handle parent_end = CreateFileA(name_.c_str(), GENERIC_WRITE, 0, NULL, ian@0: OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL); ian@0: if (!parent_end.valid()) ian@0: BOOST_PROCESS_THROW_LAST_SYSTEM_ERROR("CreateFile() failed"); ian@0: #endif ian@0: if (stype == output_stream) ian@0: std::swap(child_end, parent_end); ian@0: #if defined(BOOST_WINDOWS_API) ian@0: if (!SetHandleInformation(child_end.native(), HANDLE_FLAG_INHERIT, ian@0: HANDLE_FLAG_INHERIT)) ian@0: BOOST_PROCESS_THROW_LAST_SYSTEM_ERROR( ian@0: "SetHandleInformation() failed"); ian@0: #endif ian@0: return stream_ends(child_end, parent_end); ian@0: } ian@0: ian@0: private: ian@0: std::string name_; ian@0: ian@0: #if defined(BOOST_POSIX_API) ian@0: stream_type stype_; ian@0: #endif ian@0: }; ian@0: ian@0: /** ian@0: * Stream behavior to redirect streams with a pipe which supports asynchronous ian@0: * I/O. ian@0: * ian@0: * As platforms require different types of pipes for asynchronous I/O this ian@0: * stream behavior is provided for convenience. It uses the minimum required ian@0: * pipe type on a platform in order to be able to use asynchronous I/O. ian@0: */ ian@0: #if defined(BOOST_POSIX_API) || defined(BOOST_PROCESS_DOXYGEN) ian@0: typedef pipe async_pipe; ian@0: #elif defined(BOOST_WINDOWS_API) ian@0: class async_pipe ian@0: { ian@0: public: ian@0: stream_ends operator()(stream_type stype) const ian@0: { ian@0: UUID uuid; ian@0: RPC_STATUS s = UuidCreateSequential(&uuid); ian@0: if (s != RPC_S_OK && s != RPC_S_UUID_LOCAL_ONLY) ian@0: BOOST_PROCESS_THROW_ERROR(s, "UuidCreateSequential() failed"); ian@0: unsigned char *c; ian@0: s = UuidToStringA(&uuid, &c); ian@0: if (s != RPC_S_OK) ian@0: BOOST_PROCESS_THROW_ERROR(s, "UuidToString() failed"); ian@0: std::string name; ian@0: try ian@0: { ian@0: name = reinterpret_cast(c); ian@0: } ian@0: catch (...) ian@0: { ian@0: RpcStringFreeA(&c); ian@0: throw; ian@0: } ian@0: RpcStringFreeA(&c); ian@0: named_pipe p("\\\\.\\pipe\\boost_process_" + name); ian@0: return p(stype); ian@0: } ian@0: }; ian@0: #endif ian@0: ian@0: /** ian@0: * Stream behavior to mute streams. ian@0: * ian@0: * A child process will be able to use streams. But data written to an ian@0: * output stream is discarded and data read from an input stream is 0. ian@0: */ ian@0: class null ian@0: { ian@0: public: ian@0: #if defined(BOOST_POSIX_API) ian@0: null() ian@0: : stype_(unknown_stream) ian@0: { ian@0: } ian@0: ian@0: null(stream_type stype) ian@0: : stype_(stype) ian@0: { ian@0: } ian@0: #endif ian@0: ian@0: stream_ends operator()(stream_type stype) const ian@0: { ian@0: #if defined(BOOST_POSIX_API) ian@0: if (stype_ != unknown_stream) ian@0: stype = stype_; ian@0: std::string filename = (stype == input_stream) ? "/dev/zero" : ian@0: "/dev/null"; ian@0: int flag = (stype == input_stream) ? O_RDONLY : O_WRONLY; ian@0: handle child_end = open(filename.c_str(), flag); ian@0: if (!child_end.valid()) ian@0: BOOST_PROCESS_THROW_LAST_SYSTEM_ERROR("open(2) failed"); ian@0: #elif defined(BOOST_WINDOWS_API) ian@0: DWORD access = (stype == input_stream) ? GENERIC_READ : GENERIC_WRITE; ian@0: handle child_end = CreateFileA("NUL", access, 0, NULL, OPEN_EXISTING, ian@0: FILE_ATTRIBUTE_NORMAL, NULL); ian@0: if (!child_end.valid()) ian@0: BOOST_PROCESS_THROW_LAST_SYSTEM_ERROR("CreateFile() failed"); ian@0: if (!SetHandleInformation(child_end.native(), HANDLE_FLAG_INHERIT, ian@0: HANDLE_FLAG_INHERIT)) ian@0: BOOST_PROCESS_THROW_LAST_SYSTEM_ERROR( ian@0: "SetHandleInformation() failed"); ian@0: #endif ian@0: return stream_ends(child_end, handle()); ian@0: } ian@0: ian@0: #if defined(BOOST_POSIX_API) ian@0: private: ian@0: stream_type stype_; ian@0: #endif ian@0: }; ian@0: ian@0: } ian@0: } ian@0: } ian@0: ian@0: #endif