1 #pragma once 2 3 4 #include <type_traits> 5 #include <utility> 6 #include <memory> 7 #include <string> 8 #include <uv.h> 9 #include "request.hpp" 10 #include "stream.hpp" 11 #include "util.hpp" 12 #include "loop.hpp" 13 14 15 namespace uvw { 16 17 18 namespace details { 19 20 21 enum class UVChmodFlags: std::underlying_type_t<uv_poll_event> { 22 READABLE = UV_READABLE, 23 WRITABLE = UV_WRITABLE 24 }; 25 26 27 } 28 29 30 /** 31 * @brief The PipeHandle handle. 32 * 33 * Pipe handles provide an abstraction over local domain sockets on Unix and 34 * named pipes on Windows. 35 * 36 * To create a `PipeHandle` through a `Loop`, arguments follow: 37 * 38 * * An optional boolean value that indicates if this pipe will be used for 39 * handle passing between processes. 40 */ 41 class PipeHandle final: public StreamHandle<PipeHandle, uv_pipe_t> { 42 public: 43 using Chmod = details::UVChmodFlags; 44 PipeHandle(ConstructorAccess ca,std::shared_ptr<Loop> ref,bool pass=false)45 explicit PipeHandle(ConstructorAccess ca, std::shared_ptr<Loop> ref, bool pass = false) 46 : StreamHandle{ca, std::move(ref)}, ipc{pass} 47 {} 48 49 /** 50 * @brief Initializes the handle. 51 * @return True in case of success, false otherwise. 52 */ init()53 bool init() { 54 return initialize(&uv_pipe_init, ipc); 55 } 56 57 /** 58 * @brief Opens an existing file descriptor or HANDLE as a pipe. 59 * 60 * The passed file descriptor or HANDLE is not checked for its type, but 61 * it’s required that it represents a valid pipe.<br/> 62 * An ErrorEvent event is emitted in case of errors. 63 * 64 * @param file A valid file handle (either a file descriptor or a HANDLE). 65 */ open(FileHandle file)66 void open(FileHandle file) { 67 invoke(&uv_pipe_open, get(), file); 68 } 69 70 /** 71 * @brief bind Binds the pipe to a file path (Unix) or a name (Windows). 72 * 73 * Paths on Unix get truncated typically between 92 and 108 bytes.<br/> 74 * An ErrorEvent event is emitted in case of errors. 75 * 76 * @param name A valid file path. 77 */ bind(std::string name)78 void bind(std::string name) { 79 invoke(&uv_pipe_bind, get(), name.data()); 80 } 81 82 /** 83 * @brief Connects to the Unix domain socket or the named pipe. 84 * 85 * Paths on Unix get truncated typically between 92 and 108 bytes.<br/> 86 * A ConnectEvent event is emitted when the connection has been 87 * established.<br/> 88 * An ErrorEvent event is emitted in case of errors during the connection. 89 * 90 * @param name A valid domain socket or named pipe. 91 */ connect(std::string name)92 void connect(std::string name) { 93 auto listener = [ptr = shared_from_this()](const auto &event, const auto &) { 94 ptr->publish(event); 95 }; 96 97 auto connect = loop().resource<details::ConnectReq>(); 98 connect->once<ErrorEvent>(listener); 99 connect->once<ConnectEvent>(listener); 100 connect->connect(&uv_pipe_connect, get(), name.data()); 101 } 102 103 /** 104 * @brief Gets the name of the Unix domain socket or the named pipe. 105 * @return The name of the Unix domain socket or the named pipe, an empty 106 * string in case of errors. 107 */ sock() const108 std::string sock() const noexcept { 109 return details::tryRead(&uv_pipe_getsockname, get()); 110 } 111 112 /** 113 * @brief Gets the name of the Unix domain socket or the named pipe to which 114 * the handle is connected. 115 * @return The name of the Unix domain socket or the named pipe to which 116 * the handle is connected, an empty string in case of errors. 117 */ peer() const118 std::string peer() const noexcept { 119 return details::tryRead(&uv_pipe_getpeername, get()); 120 } 121 122 /** 123 * @brief Sets the number of pending pipe this instance can handle. 124 * 125 * This method can be used to set the number of pending pipe this instance 126 * handles when the pipe server is waiting for connections.<br/> 127 * Note that this setting applies to Windows only. 128 * 129 * @param count The number of accepted pending pipe. 130 */ pending(int count)131 void pending(int count) noexcept { 132 uv_pipe_pending_instances(get(), count); 133 } 134 135 /** 136 * @brief Gets the number of pending pipe this instance can handle. 137 * @return The number of pending pipe this instance can handle. 138 */ pending()139 int pending() noexcept { 140 return uv_pipe_pending_count(get()); 141 } 142 143 /** 144 * @brief Used to receive handles over IPC pipes. 145 * 146 * Steps to be done: 147 * 148 * * Call `pending()`, if it’s greater than zero then proceed. 149 * * Initialize a handle of the given type, as returned by `receive()`. 150 * * Call `accept(pipe, handle)`. 151 * 152 * @return The type of the pending handle. Possible values are: 153 * 154 * * `HandleType::PIPE` 155 * * `HandleType::TCP` 156 * * `HandleType::UDP` 157 * * `HandleType::UNKNOWN` 158 */ receive()159 HandleType receive() noexcept { 160 HandleCategory category = uv_pipe_pending_type(get()); 161 return Utilities::guessHandle(category); 162 } 163 164 /** 165 * @brief Alters pipe permissions. 166 * 167 * It allows the pipe to be accessed from processes run by different users. 168 * 169 * Available flags are: 170 * 171 * * `PipeHandle::Chmod::READABLE` 172 * * `PipeHandle::Chmod::WRITABLE` 173 * 174 * See the official 175 * [documentation](http://docs.libuv.org/en/v1.x/pipe.html#c.uv_pipe_chmod) 176 * for further details. 177 * 178 * @param flags A valid set of flags. 179 * @return True in case of success, false otherwise. 180 */ chmod(Flags<Chmod> flags)181 bool chmod(Flags<Chmod> flags) noexcept { 182 return (0 == uv_pipe_chmod(get(), flags)); 183 } 184 185 private: 186 bool ipc; 187 }; 188 189 190 } 191