├── .gitignore ├── CMakeLists.txt ├── LICENSE_1_0.txt ├── README.md ├── clienttest.cpp ├── impl ├── helper.hpp ├── named_pipe_unix.hpp ├── named_pipe_windows.hpp └── scoped_handle.hpp ├── named_pipe.hpp ├── runtest.sh ├── servertest.cpp └── testdata.h /.gitignore: -------------------------------------------------------------------------------- 1 | /a.out 2 | /test 3 | /build/ 4 | /relbuild/ 5 | /vsbuild/ -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.8) 2 | 3 | project(named_pipe) 4 | 5 | set(Boost_USE_MULTITHREAD OFF) 6 | 7 | find_package(Boost COMPONENTS system filesystem REQUIRED) 8 | 9 | include_directories(${Boost_INCLUDE_DIRS}) 10 | link_directories(${Boost_LIBRARY_DIRS}) 11 | 12 | add_executable(servertest servertest.cpp) 13 | target_link_libraries(servertest ${Boost_LIBRARIES}) 14 | 15 | add_executable(clienttest clienttest.cpp) 16 | target_link_libraries(clienttest ${Boost_LIBRARIES}) 17 | 18 | enable_testing() 19 | add_test(round_trip "../runtest.sh") 20 | -------------------------------------------------------------------------------- /LICENSE_1_0.txt: -------------------------------------------------------------------------------- 1 | Boost Software License - Version 1.0 - August 17th, 2003 2 | 3 | Permission is hereby granted, free of charge, to any person or organization 4 | obtaining a copy of the software and accompanying documentation covered by 5 | this license (the "Software") to use, reproduce, display, distribute, 6 | execute, and transmit the Software, and to prepare derivative works of the 7 | Software, and to permit third-parties to whom the Software is furnished to 8 | do so, all subject to the following: 9 | 10 | The copyright notices in the Software and this entire statement, including 11 | the above license grant, this restriction and the following disclaimer, 12 | must be included in all copies of the Software, in whole or in part, and 13 | all derivative works of the Software, unless such copies or derivative 14 | works are solely in the form of machine-executable object code generated by 15 | a source language processor. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT 20 | SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE 21 | FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 22 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 | DEALINGS IN THE SOFTWARE. 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Named Pipe for Boost.Interprocess 2 | ================================= 3 | 4 | This is the repo for an ISP I'm doing on building a basic 5 | cross-platform named-pipe implementation. One of the design goals is 6 | that it eventually be included in the Boost.Interprocess library. 7 | 8 | Ideas and suggestions (and pull requests!) welcome! 9 | 10 | Thanks for their help in refining the interface to: Rob Stewart and 11 | Edward Diener. 12 | 13 | 14 | Update 8/16/2013 15 | ---------------- 16 | 17 | Ok, so I've been convinced by Niall Douglas, and John Vernarchick from 18 | the mailing list that an ASIO implementation is actually the 19 | appropriate way to go. However, since I only have a couple more days 20 | to work on my independent study, I'm going to continue with the raw 21 | implementation for now. I'm going to treat this as research though, 22 | and a generally good learning experience, but the actual code for a 23 | cross-platform named pipe will eventually be based on ASIO code and be 24 | compatible with inclusion in the Boost.ASIO library. 25 | -------------------------------------------------------------------------------- /clienttest.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "testdata.h" 5 | #include "named_pipe.hpp" 6 | 7 | #define BUFSIZE 120 8 | 9 | using namespace boost::interprocess; 10 | 11 | int main() { 12 | named_pipe pipe(pipename); 13 | 14 | if (strcmp(pipename, pipe.get_name().c_str()) != 0) { 15 | printf("error: received '%s'; expected '%s'\n", 16 | pipe.get_name().c_str(), pipename); 17 | return 1; 18 | } 19 | 20 | char buff[BUFSIZE]; 21 | 22 | pipe.write(clientString, strlen(clientString)); 23 | 24 | pipe.read(buff, BUFSIZE); 25 | 26 | if (strcmp(serverString, buff) != 0) { 27 | printf("error: received '%s'; expected '%s'\n", 28 | buff, serverString); 29 | return 2; 30 | } 31 | 32 | return 0; 33 | } 34 | -------------------------------------------------------------------------------- /impl/helper.hpp: -------------------------------------------------------------------------------- 1 | ////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // (C) Copyright geoff@minty-dark-tower 2013. Distributed under the Boost 4 | // Software License, Version 1.0. (See accompanying file 5 | // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | // 7 | ////////////////////////////////////////////////////////////////////////////// 8 | 9 | #ifndef BOOST_INTERPROCESS_NAMED_PIPE_HELPER_HPP 10 | #define BOOST_INTERPROCESS_NAMED_PIPE_HELPER_HPP 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #include 18 | #include 19 | 20 | #include 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | #include 28 | 29 | namespace boost { 30 | namespace interprocess { 31 | namespace impl { 32 | 33 | using namespace boost::system; 34 | 35 | const char *get_temp_path() { 36 | char *temp = getenv("TEMP"); 37 | if (temp == NULL) { 38 | temp = getenv("TMP"); 39 | } 40 | if (temp == NULL) { 41 | temp = getenv("TMPDIR"); 42 | } 43 | if (temp == NULL) { 44 | return "/tmp"; 45 | } 46 | return temp; 47 | } 48 | 49 | void ensure_path_exists(const std::string path) { 50 | size_t index = path.find_first_of('/'); 51 | index = path.find_first_of('/', index+1); 52 | 53 | while (index != std::string::npos) { 54 | boost::filesystem::create_directory(path.substr(0, index)); 55 | index = path.find_first_of('/', index+1); 56 | } 57 | } 58 | 59 | int make_local_socket() { 60 | int fd; 61 | if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) { 62 | error_code ec(errno, system_category()); 63 | system_error e(ec); 64 | boost::throw_exception(e); 65 | } 66 | 67 | return fd; 68 | } 69 | 70 | void bind_local_socket(int fd, const std::string &name) { 71 | ensure_path_exists(name); 72 | struct sockaddr_un un; 73 | 74 | un.sun_family = AF_UNIX; 75 | 76 | strcpy(un.sun_path, name.c_str()); 77 | int len = name.length() + offsetof(struct sockaddr_un, sun_path); 78 | 79 | if (bind(fd, (struct sockaddr *)&un, len) < 0) { 80 | error_code ec(errno, system_category()); 81 | system_error e(ec); 82 | boost::throw_exception(e); 83 | } 84 | 85 | } 86 | 87 | } //namespace impl { 88 | } //namespace interprocess { 89 | } //namespace boost { 90 | 91 | #endif //BOOST_INTERPROCESS_NAMED_PIPE_HELPER_HPP 92 | -------------------------------------------------------------------------------- /impl/named_pipe_unix.hpp: -------------------------------------------------------------------------------- 1 | ////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // (C) Copyright Geoff Shannon 2013. Distributed under the Boost 4 | // Software License, Version 1.0. (See accompanying file 5 | // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | // 7 | ////////////////////////////////////////////////////////////////////////////// 8 | 9 | #ifndef BOOST_INTERPROCESS_NAMED_PIPE_UNIX_HPP 10 | #define BOOST_INTERPROCESS_NAMED_PIPE_UNIX_HPP 11 | 12 | #include 13 | #include 14 | 15 | #include 16 | #include 17 | 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | #include 29 | #include 30 | 31 | #include "helper.hpp" 32 | 33 | #define PATH_PREFIX "boost/interprocess" 34 | #define CLI_PERM S_IRWXU // rwx for user only 35 | 36 | #define QLEN 10 37 | #define STALE 30 38 | 39 | namespace boost { 40 | namespace interprocess { 41 | namespace impl { 42 | 43 | using namespace boost::system; 44 | 45 | class named_pipe_impl 46 | { 47 | public: 48 | named_pipe_impl(const std::string &name); 49 | 50 | named_pipe_impl(const std::string &name, int fd): 51 | _name(name), _fd(fd) {} 52 | 53 | const std::string &get_name() { 54 | return _name; 55 | } 56 | 57 | std::size_t read(char *buffer, const int length); 58 | 59 | std::size_t write(const char *buffer, const int length); 60 | 61 | private: 62 | const std::string _name; 63 | 64 | int _fd; 65 | }; 66 | 67 | named_pipe_impl::named_pipe_impl(const std::string &name): _name(name) { 68 | 69 | _fd = make_local_socket(); 70 | 71 | struct sockaddr_un un; 72 | char buff[128]; 73 | int len = snprintf(buff,128, "%s/%s/%s", 74 | get_temp_path(), PATH_PREFIX, name.c_str()); 75 | 76 | un.sun_family = AF_UNIX; 77 | strcpy(un.sun_path, buff); 78 | len += offsetof(struct sockaddr_un, sun_path); 79 | 80 | if (connect(_fd, (struct sockaddr *)&un, len) < 0) { 81 | error_code ec(errno, system_category()); 82 | system_error e(ec); 83 | boost::throw_exception(e); 84 | } 85 | } 86 | 87 | inline std::size_t named_pipe_impl::read(char *buffer, const int length) { 88 | std::size_t size = ::read(_fd, buffer, length); 89 | if (size < 0) { 90 | error_code ec(errno, system_category()); 91 | system_error e(ec); 92 | boost::throw_exception(e); 93 | } 94 | buffer[size] = '\0'; 95 | return size; 96 | } 97 | 98 | inline std::size_t named_pipe_impl::write(const char *buffer, const int length) { 99 | std::size_t size = ::write(_fd, buffer, length); 100 | if (size < 0) { 101 | error_code ec(errno, system_category()); 102 | system_error e(ec); 103 | boost::throw_exception(e); 104 | } 105 | return size; 106 | } 107 | 108 | // End named_pipe_impl 109 | 110 | 111 | class named_pipe_server_impl 112 | { 113 | public: 114 | named_pipe_server_impl(const std::string &name); 115 | 116 | const std::string &get_name() { 117 | return _name; 118 | } 119 | 120 | named_pipe_impl *accept(); 121 | 122 | private: 123 | 124 | const std::string _name; 125 | 126 | int _fd; 127 | }; 128 | 129 | named_pipe_server_impl::named_pipe_server_impl(const std::string &name): 130 | _name(name), _fd(-1) { 131 | 132 | _fd = make_local_socket(); 133 | 134 | char buff[128]; 135 | snprintf(buff,128, "%s/%s/%s", 136 | get_temp_path(), PATH_PREFIX, name.c_str()); 137 | unlink(buff); 138 | bind_local_socket(_fd, buff); 139 | 140 | // Tell kernel we're a server 141 | if (listen(_fd, QLEN) < 0) { 142 | error_code ec(errno, system_category()); 143 | system_error e(ec); 144 | boost::throw_exception(e); 145 | } 146 | } 147 | 148 | named_pipe_impl *named_pipe_server_impl::accept() { 149 | int clifd; 150 | struct sockaddr_un un; 151 | 152 | socklen_t len = sizeof(un); 153 | 154 | if ((clifd = ::accept(_fd, (struct sockaddr *)&un, &len)) < 0) { 155 | error_code ec(errno, system_category()); 156 | system_error e(ec); 157 | boost::throw_exception(e); 158 | } 159 | 160 | return new named_pipe_impl(_name, clifd); 161 | } 162 | 163 | // End named_pipe_server_impl 164 | 165 | } //namespace impl { 166 | } //namespace interprocess { 167 | } //namespace boost { 168 | 169 | #endif //BOOST_INTERPROCESS_NAMED_PIPE_UNIX_HPP 170 | -------------------------------------------------------------------------------- /impl/named_pipe_windows.hpp: -------------------------------------------------------------------------------- 1 | ////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // (C) Copyright Geoff Shannon 2013. Distributed under the Boost 4 | // Software License, Version 1.0. (See accompanying file 5 | // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | // 7 | ////////////////////////////////////////////////////////////////////////////// 8 | 9 | #ifndef BOOST_INTERPROCESS_NAMED_PIPE_WINDOWS_HPP 10 | #define BOOST_INTERPROCESS_NAMED_PIPE_WINDOWS_HPP 11 | 12 | #include 13 | 14 | #include 15 | #include 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | #define BUFFSIZE 512 23 | #define QLEN 10 24 | 25 | namespace boost { 26 | namespace interprocess { 27 | namespace impl { 28 | 29 | using namespace boost::system; 30 | 31 | std::string &getPipePrefix(void) { 32 | static std::string prefix("\\\\.\\pipe\\boost\\interprocess\\"); 33 | return prefix; 34 | } 35 | 36 | std::string windowifyPath(const std::string &str) { 37 | int count = 0; 38 | int pos = -1; 39 | // Count occurrences of '/' 40 | while ((pos = str.find("/", pos+1)) != std::string::npos) { 41 | ++count; 42 | } 43 | int buflen = str.length(); 44 | char *buffer = new char[buflen+1]; 45 | int to = 0; 46 | for (int from = 0; from < buflen; ++from, ++to) { 47 | if (str[from] != '/') { 48 | buffer[to] = str[from]; 49 | } else { 50 | buffer[to] = '\\'; 51 | } 52 | } 53 | buffer[to] = '\0'; 54 | std::string ret(buffer); 55 | delete buffer; 56 | return ret; 57 | } 58 | 59 | class named_pipe_impl 60 | { 61 | public: 62 | named_pipe_impl(const std::string &name); 63 | 64 | named_pipe_impl(const std::string &name, HANDLE pipe): _name(name), _pipe(pipe) 65 | {} 66 | 67 | static named_pipe_impl *create_and_accept(const std::string &name); 68 | 69 | const std::string &get_name() { 70 | return _name; 71 | } 72 | 73 | std::size_t read(char *buffer, const int length); 74 | 75 | std::size_t write(const char *buffer, const int length); 76 | 77 | private: 78 | const std::string _name; 79 | 80 | HANDLE _pipe; 81 | 82 | }; 83 | 84 | named_pipe_impl::named_pipe_impl(const std::string &name): 85 | _name(name) { 86 | std::string whole = getPipePrefix() + windowifyPath(_name); 87 | printf("pipename: '%s'\n", whole.c_str()); 88 | _pipe = CreateFile(whole.c_str(), 89 | GENERIC_READ | // read and write access 90 | GENERIC_WRITE, 91 | 0, // no sharing 92 | NULL, // default security attributes 93 | OPEN_EXISTING, // opens existing pipe 94 | 0, // default attributes 95 | NULL); 96 | if (_pipe == INVALID_HANDLE_VALUE) { 97 | error_code ec(GetLastError(), system_category()); 98 | system_error e(ec); 99 | boost::throw_exception(e); 100 | } 101 | } 102 | 103 | inline named_pipe_impl *named_pipe_impl::create_and_accept(const std::string &name) { 104 | return new named_pipe_impl(name); 105 | } 106 | 107 | inline std::size_t named_pipe_impl::read(char *buffer, const int length) { 108 | DWORD read; 109 | bool success = ReadFile(_pipe, buffer, length, &read, NULL); 110 | int error = GetLastError(); 111 | if (!success && error != ERROR_MORE_DATA ) { 112 | error_code ec(error, system_category()); 113 | system_error e(ec); 114 | boost::throw_exception(e); 115 | } 116 | if (read < length) { 117 | buffer[read] = '\0'; 118 | } 119 | return read; 120 | } 121 | 122 | inline std::size_t named_pipe_impl::write(const char *buffer, const int length) { 123 | DWORD written; 124 | bool success = WriteFile(_pipe, buffer, length, &written, NULL); 125 | if (!success) { 126 | error_code ec(GetLastError(), system_category()); 127 | system_error e(ec); 128 | boost::throw_exception(e); 129 | } 130 | return written; 131 | } 132 | 133 | // End named_pipe_impl 134 | 135 | 136 | class named_pipe_server_impl 137 | { 138 | public: 139 | named_pipe_server_impl(const std::string &name); 140 | 141 | const std::string &get_name() { 142 | return _name; 143 | } 144 | 145 | named_pipe_impl *accept(); 146 | 147 | private: 148 | const std::string _name; 149 | }; 150 | 151 | named_pipe_server_impl::named_pipe_server_impl(const std::string &name): 152 | _name(name) { 153 | 154 | } 155 | 156 | inline named_pipe_impl *named_pipe_server_impl::accept() { 157 | std::string whole = getPipePrefix() + windowifyPath(_name); 158 | printf("server pipename: '%s'\n", whole.c_str()); 159 | HANDLE pipe = CreateNamedPipe(whole.c_str(), 160 | PIPE_ACCESS_DUPLEX, // read/write access 161 | PIPE_TYPE_BYTE | 162 | PIPE_READMODE_BYTE | 163 | PIPE_WAIT | 164 | PIPE_REJECT_REMOTE_CLIENTS, 165 | QLEN, 166 | BUFFSIZE, 167 | BUFFSIZE, 168 | 0, 169 | NULL); 170 | if (pipe == INVALID_HANDLE_VALUE) { 171 | error_code ec(GetLastError(), system_category()); 172 | system_error e(ec); 173 | boost::throw_exception(e); 174 | } 175 | bool connected = ConnectNamedPipe(pipe, NULL) ? 176 | TRUE : (GetLastError() == ERROR_PIPE_CONNECTED); 177 | 178 | if (!connected) { 179 | error_code ec(GetLastError(), system_category()); 180 | system_error e(ec); 181 | boost::throw_exception(e); 182 | } 183 | 184 | return new named_pipe_impl(_name, pipe); 185 | } 186 | 187 | // End named_pipe_server_impl 188 | 189 | } //namespace impl { 190 | } //namespace interprocess { 191 | } //namespace boost { 192 | 193 | #endif //BOOST_INTERPROCESS_NAMED_PIPE_WINDOWS_HPP 194 | -------------------------------------------------------------------------------- /impl/scoped_handle.hpp: -------------------------------------------------------------------------------- 1 | /*************************************************************************************************************** 2 | * 3 | * Filename: ScopedHandle.h 4 | * 5 | * Author: Miki Rozloznik 6 | * 7 | * Date: 2010/07/21 8 | * 9 | * Implementation Description: 10 | *//** \file 11 | * The scoped handle for Windows objects (ala scoped_ptr()). 12 | *//* 13 | * 14 | **************************************************************************************************************/ 15 | 16 | #ifndef __SCOPED_HANDLE_HPP__ 17 | #define __SCOPED_HANDLE_HPP__ 18 | 19 | #include 20 | #include 21 | 22 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////// 23 | /// The invalid handle NULL. 24 | /// 25 | /// The class returns invalid handle for all handles which invalid value is NULL. 26 | template 27 | class NullHandleValue 28 | { 29 | public: 30 | //////////////////////////////////////////////////////////////////////////////////////////////////////////// 31 | /// Gets the invalid handle. 32 | /// 33 | /// \return 34 | /// Invalid handle NULL. 35 | static inline HandleType Get() { return NULL; } 36 | }; 37 | 38 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////// 39 | /// The invalid handle INVALID_HANDLE_VALUE. 40 | /// 41 | /// The class returns invalid handle for all handles which invalid value is INVALID_HANDLE_VALUE. 42 | class InvalidHandleValue 43 | { 44 | public: 45 | //////////////////////////////////////////////////////////////////////////////////////////////////////////// 46 | /// Gets the invalid handle. 47 | /// 48 | /// \return 49 | /// Invalid handle INVALID_HANDLE_VALUE. 50 | static inline HANDLE Get() { return INVALID_HANDLE_VALUE; } 51 | }; 52 | 53 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////// 54 | /// The invalid handle INVALID_SOCKET. 55 | /// 56 | /// The class returns invalid handle for all handles which invalid value is INVALID_SOCKET. 57 | class InvalidSocketValue 58 | { 59 | public: 60 | //////////////////////////////////////////////////////////////////////////////////////////////////////////// 61 | /// Gets the invalid handle. 62 | /// 63 | /// \return 64 | /// Invalid handle INVALID_SOCKET. 65 | static inline SOCKET Get() { return INVALID_SOCKET; } 66 | }; 67 | 68 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////// 69 | /// The CloseHandle() method. 70 | class CloseHandleMethod 71 | { 72 | public: 73 | //////////////////////////////////////////////////////////////////////////////////////////////////////////// 74 | /// Closes the handle. 75 | static inline void Close(HANDLE Handle) { CloseHandle(Handle); } 76 | }; 77 | 78 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////// 79 | /// The DeleteObject() method. 80 | class DeleteObjectMethod 81 | { 82 | public: 83 | //////////////////////////////////////////////////////////////////////////////////////////////////////////// 84 | /// Deletes the attached Windows GDI object from memory. 85 | static inline void Close(HGDIOBJ Handle) { DeleteObject(Handle); } 86 | }; 87 | 88 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////// 89 | /// The closesocket() method. 90 | class CloseSocketMethod 91 | { 92 | public: 93 | //////////////////////////////////////////////////////////////////////////////////////////////////////////// 94 | /// Closes an existing socket. 95 | static inline void Close(SOCKET Handle) { closesocket(Handle); } 96 | }; 97 | 98 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////// 99 | /// The UnmapViewOfFile() method. 100 | class UnmapViewOfFileMethod 101 | { 102 | public: 103 | //////////////////////////////////////////////////////////////////////////////////////////////////////////// 104 | /// Unmaps a mapped view of a file from the calling process's address space. 105 | static inline void Close(LPVOID Handle) { UnmapViewOfFile(Handle); } 106 | }; 107 | 108 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////// 109 | /// The RegCloseKey() method. 110 | class RegCloseKeyMethod 111 | { 112 | public: 113 | //////////////////////////////////////////////////////////////////////////////////////////////////////////// 114 | /// Releases a handle to the specified registry key. 115 | static inline void Close(HKEY Handle) { RegCloseKey(Handle); } 116 | }; 117 | 118 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////// 119 | /// The FreeLibrary() method. 120 | class FreeLibraryMethod 121 | { 122 | public: 123 | //////////////////////////////////////////////////////////////////////////////////////////////////////////// 124 | /// Frees the loaded dynamic-link library (DLL). 125 | static inline void Close(HMODULE Handle) { FreeLibrary(Handle); } 126 | }; 127 | 128 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////// 129 | /// The FindClose() method. 130 | class FindCloseMethod 131 | { 132 | public: 133 | //////////////////////////////////////////////////////////////////////////////////////////////////////////// 134 | /// Closes a file search handle. 135 | static inline void Close(HANDLE Handle) { FindClose(Handle); } 136 | }; 137 | 138 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////// 139 | /// The scoped handle for Windows objects. 140 | /// 141 | /// This wrapper ensures that the delete handle method will be called during destruction ala scoped_ptr(). 142 | /// 143 | /// Because invalid value and delete method for handles are inconsistent in Windows, the template parameters 144 | /// InvalidHandle and CloseMethod have been introduced. 145 | /// 146 | /// Because old compiler does not like the template none-class parameters, the special classes which return 147 | /// the invalid handles and close methods have been introduced. 148 | template 149 | class ScopedHandle 150 | { 151 | public: 152 | //////////////////////////////////////////////////////////////////////////////////////////////////////////// 153 | /// Constructor. 154 | explicit ScopedHandle 155 | ( 156 | HandleType Handle = InvalidValue::Get() ///< Windows object handle to wrap 157 | ) : m_Handle(Handle) 158 | { 159 | } // ScopedHandle 160 | 161 | //////////////////////////////////////////////////////////////////////////////////////////////////////////// 162 | /// Destructor. 163 | ~ScopedHandle() 164 | { 165 | if (m_Handle != InvalidValue::Get()) 166 | CloseMethod::Close(m_Handle); 167 | } // ~ScopedHandle 168 | 169 | //////////////////////////////////////////////////////////////////////////////////////////////////////////// 170 | /// Reset the wrapped handle. 171 | void Reset 172 | ( 173 | HandleType Handle = InvalidValue::Get() ///< Windows object handle to reset 174 | ) 175 | { 176 | ScopedHandle NewWrapper(m_Handle); 177 | m_Handle = Handle; 178 | } // Reset 179 | 180 | //////////////////////////////////////////////////////////////////////////////////////////////////////////// 181 | /// Gets the wrapped handle. 182 | /// 183 | /// \return 184 | /// The wrapped handle. 185 | HandleType Get() const 186 | { 187 | return m_Handle; 188 | } // Get 189 | 190 | //////////////////////////////////////////////////////////////////////////////////////////////////////////// 191 | /// Implementation of the cast operator to bool. 192 | operator bool() const 193 | { 194 | return m_Handle != InvalidValue::Get(); 195 | } // operator bool() 196 | 197 | //////////////////////////////////////////////////////////////////////////////////////////////////////////// 198 | /// Implementation of the operator!. 199 | bool operator!() const 200 | { 201 | return m_Handle == InvalidValue::Get(); 202 | } // operator!() 203 | 204 | //////////////////////////////////////////////////////////////////////////////////////////////////////////// 205 | /// Exchanges the contents of the two scoped handles. 206 | void Swap 207 | ( 208 | ScopedHandle& Other ///< Object to swap the value with 209 | ) 210 | { 211 | HandleType Tmp = m_Handle; 212 | m_Handle = Other.m_Handle; 213 | Other.m_Handle = Tmp; 214 | } // Swap 215 | 216 | private: 217 | // disable copy constructor and copy assignment operator 218 | ScopedHandle(const ScopedHandle&); 219 | ScopedHandle& operator=(const ScopedHandle&); 220 | 221 | HandleType m_Handle; ///< the Windows object handle to wrap 222 | }; 223 | 224 | /// The wrapper for the event handle returned from CreateEvent() method. 225 | typedef ScopedHandle, CloseHandleMethod> EventScopedHandle; 226 | 227 | /// The wrapper for the thread handle returned from CreateThread() method. 228 | typedef ScopedHandle, CloseHandleMethod> ThreadScopedHandle; 229 | 230 | /// The wrapper for the file handle returned from CreateFile() method. 231 | typedef ScopedHandle FileScopedHandle; 232 | 233 | /// The wrapper for the socket handle returned from socket() method. 234 | typedef ScopedHandle SocketScopedHandle; 235 | 236 | /// The wrapper for the file mapping handle returned from CreateFileMapping() method. 237 | typedef ScopedHandle, CloseHandleMethod> MappingScopedHandle; 238 | 239 | /// The wrapper for the view of file handle returned from MapViewOfFile() method. 240 | typedef ScopedHandle, UnmapViewOfFileMethod> ViewOfFileScopedHandle; 241 | 242 | /// The wrapper for the registry key handle returned from RegOpenKeyEx() method. 243 | typedef ScopedHandle, RegCloseKeyMethod> RegKeyScopedHandle; 244 | 245 | /// The wrapper for the module handle returned from LoadLibrary() method. 246 | typedef ScopedHandle, FreeLibraryMethod> ModuleScopedHandle; 247 | 248 | /// The wrapper for the find file handle returned from FindFirstFile() method. 249 | typedef ScopedHandle FindFileScopedHandle; 250 | 251 | #endif // __SCOPED_HANDLE_HPP__ 252 | -------------------------------------------------------------------------------- /named_pipe.hpp: -------------------------------------------------------------------------------- 1 | ////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // (C) Copyright Geoff Shannon 2013. Distributed under the Boost 4 | // Software License, Version 1.0. (See accompanying file 5 | // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | // 7 | ////////////////////////////////////////////////////////////////////////////// 8 | 9 | #ifndef BOOST_INTERPROCESS_NAMED_PIPE_HPP 10 | #define BOOST_INTERPROCESS_NAMED_PIPE_HPP 11 | 12 | #include 13 | 14 | #include 15 | 16 | #ifdef BOOST_WINDOWS 17 | 18 | #include "impl/named_pipe_windows.hpp" 19 | 20 | #else // !defined BOOST_WINDOWS 21 | 22 | #include "impl/named_pipe_unix.hpp" 23 | 24 | #endif 25 | 26 | namespace boost { 27 | namespace interprocess { 28 | 29 | class named_pipe_server; 30 | 31 | class named_pipe 32 | { 33 | 34 | public: 35 | /// Construct and open a named_pipe_object 36 | /** 37 | * This constructor opens a connection to an already existing named 38 | * pipe with the specified name. 39 | * 40 | * @param name The name of the named pipe to connect to. 41 | */ 42 | named_pipe(const std::string &name): _pimpl(new impl::named_pipe_impl(name)) 43 | {} 44 | 45 | named_pipe(const named_pipe &pipe): _pimpl(pipe._pimpl) {} 46 | 47 | named_pipe &operator =(const named_pipe &that) { 48 | if (this != &that) { 49 | _pimpl = that._pimpl; 50 | } 51 | } 52 | 53 | /// Returns the name of the named pipe object. 54 | const std::string &get_name() { 55 | return _pimpl->get_name(); 56 | } 57 | 58 | /// Read some data from the named pipe. 59 | /** 60 | * This function is used to read data to the named pipe. The 61 | * function call will block until one or more bytes of data have 62 | * been read successfully, or until an error occurs. 63 | * 64 | * @param buffer A buffer into which the data will be read. 65 | * 66 | * @return The number of bytes read. 67 | * 68 | * @throws boost::system::system_error Thrown on failure. 69 | * 70 | * @note The read operation may not completely fill the 71 | * buffer. 72 | */ 73 | std::size_t read(char *buffer, const int length) { 74 | return _pimpl->read(buffer, length); 75 | } 76 | 77 | /// Write some data to the named pipe. 78 | /** 79 | * This function is used to write data to the named pipe. The 80 | * function call will block until one or more bytes of data have 81 | * been written successfully, or until an error occurs. 82 | * 83 | * @param buffer A buffer to be written to the named pipe. 84 | * 85 | * @return The number of bytes written. 86 | * 87 | * @throws boost::system::system_error Thrown on failure. 88 | * 89 | * @note The write operation may not transmit all of the data 90 | * to the peer. 91 | */ 92 | std::size_t write(const char *buffer, const int length) { 93 | return _pimpl->write(buffer, length); 94 | } 95 | 96 | friend class named_pipe_server; 97 | 98 | private: 99 | 100 | boost::shared_ptr _pimpl; 101 | 102 | named_pipe(impl::named_pipe_impl *pimpl): _pimpl(pimpl) 103 | {} 104 | }; 105 | 106 | class named_pipe_server 107 | { 108 | 109 | public: 110 | /// Construct a named_pipe_server. 111 | /** 112 | * This constructor creates an object which can be used to listen 113 | * for named pipe connections under the specified name. 114 | * 115 | * @param name The name of the new pipe server. 116 | * 117 | * @note Nothing is actually opened or setup until a call to accept 118 | * is made. 119 | */ 120 | named_pipe_server(const std::string &name): 121 | _pimpl(new impl::named_pipe_server_impl(name)) 122 | {} 123 | 124 | /// Returns the name of the named pipe. 125 | const std::string &get_name() { 126 | return _pimpl->get_name(); 127 | } 128 | 129 | /// Waits for a new connection from a client process. 130 | /** 131 | * This function is used to wait for and accept a new connection 132 | * on this named pipe. 133 | * 134 | * @return The named_pipe for communicating with the new client. 135 | */ 136 | named_pipe accept() { 137 | named_pipe pipe(_pimpl->accept()); 138 | return pipe; 139 | } 140 | 141 | private: 142 | 143 | boost::shared_ptr _pimpl; 144 | }; 145 | 146 | } //namespace interprocess { 147 | } //namespace boost { 148 | 149 | #endif //BOOST_INTERPROCESS_NAMED_PIPE_HPP 150 | -------------------------------------------------------------------------------- /runtest.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | TEMP=$(getopt -o '' -n $(basename $0) -- "$@") 4 | 5 | if [ $? != 0 ] ; then echo "Terminating..." >&2 ; exit 1 ; fi 6 | 7 | eval set -- "$TEMP" 8 | 9 | while true; do 10 | case "$1" in 11 | -- ) shift; break ;; 12 | esac 13 | done 14 | 15 | build/test & 16 | PID=$! 17 | 18 | if build/clienttest && wait $PID 19 | then 20 | exit 0 21 | else 22 | exit 1 23 | fi 24 | -------------------------------------------------------------------------------- /servertest.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | 5 | #include 6 | 7 | #include "testdata.h" 8 | #include "named_pipe.hpp" 9 | 10 | #define BUFSIZE 120 11 | 12 | using namespace boost::interprocess; 13 | 14 | int main() { 15 | named_pipe_server server(pipename); 16 | 17 | if (strcmp(pipename, server.get_name().c_str()) != 0) { 18 | printf("error: received '%s'; expected '%s'\n", 19 | server.get_name().c_str(), pipename); 20 | return 1; 21 | } 22 | 23 | named_pipe pipe = server.accept(); 24 | 25 | if (strcmp(pipename, pipe.get_name().c_str()) != 0) { 26 | printf("error: received '%s'; expected '%s'\n", 27 | pipe.get_name().c_str(), pipename); 28 | return 2; 29 | } 30 | 31 | char buff[BUFSIZE]; 32 | 33 | pipe.read(buff, BUFSIZE); 34 | 35 | if (strcmp(clientString, buff) != 0) { 36 | printf("error: received '%s'; expected '%s'\n", 37 | buff, clientString); 38 | return 3; 39 | } 40 | 41 | pipe.write(serverString, strlen(serverString)); 42 | 43 | return 0; 44 | } 45 | -------------------------------------------------------------------------------- /testdata.h: -------------------------------------------------------------------------------- 1 | /* @(#)testdata.h 2 | */ 3 | 4 | #ifndef _TESTDATA_H 5 | #define _TESTDATA_H 1 6 | 7 | const char pipename[] = "my/named/pipe"; 8 | 9 | const char serverString[] = "this thing I'm doing."; 10 | const char clientString[] = "abc123xyz"; 11 | 12 | #endif /* _TESTDATA_H */ 13 | 14 | --------------------------------------------------------------------------------