2 #ifndef UVCC_HANDLE_STREAM__HPP 3 #define UVCC_HANDLE_STREAM__HPP 5 #include "uvcc/utility.hpp" 6 #include "uvcc/handle-base.hpp" 7 #include "uvcc/handle-io.hpp" 8 #include "uvcc/buffer.hpp" 9 #include "uvcc/loop.hpp" 16 #include <type_traits> 29 friend class handle::uv_interface;
30 friend class handle::instance< stream >;
33 friend class shutdown;
38 using uv_t = ::uv_stream_t;
39 using on_connection_t = std::function<
void(
stream _server) >;
49 struct properties :
io::properties
51 on_connection_t connection_cb;
54 struct uv_interface :
handle::uv_handle_interface,
io::uv_interface
56 std::size_t write_queue_size(
void *_uv_handle)
const noexcept override 57 {
return static_cast< ::uv_stream_t* >(_uv_handle)->write_queue_size; }
59 int read_start(
void *_uv_handle, int64_t _offset)
const noexcept override 61 if (_offset >= 0) instance::from(_uv_handle)->properties().rdoffset = _offset;
62 return ::uv_read_start(
static_cast< ::uv_stream_t* >(_uv_handle), alloc_cb, read_cb);
65 int read_stop(
void *_uv_handle)
const noexcept override 66 {
return ::uv_read_stop(
static_cast< ::uv_stream_t* >(_uv_handle)); }
77 stream()
noexcept =
default;
79 explicit stream(uv_t *_uv_handle) :
io(
static_cast<
io::uv_t* >(_uv_handle)) {}
85 stream(
const stream&) =
default;
88 stream(
stream&&)
noexcept =
default;
92 template<
typename =
void >
static void alloc_cb(::uv_handle_t*, std::size_t, ::uv_buf_t*);
93 template<
typename =
void >
static void read_cb(::uv_stream_t*, ssize_t,
const ::uv_buf_t*);
94 template<
typename =
void >
static void connection_cb(::uv_stream_t*,
int);
97 on_connection_t& on_connection()
const noexcept {
return instance::from(uv_handle)->properties().connection_cb; }
101 int listen(
int _backlog,
const on_connection_t &_connection_cb)
const 103 instance::from(uv_handle)->properties().connection_cb = _connection_cb;
105 auto uv_ret = ::uv_listen(
static_cast< uv_t* >(uv_handle), _backlog, connection_cb);
106 if (uv_ret < 0) uv_status(uv_ret);
116 std::size_t
write_queue_size()
const noexcept {
return static_cast< uv_t* >(uv_handle)->write_queue_size; }
119 bool is_readable()
const noexcept {
return uv_status(::uv_is_readable(
static_cast< uv_t* >(uv_handle))); }
121 bool is_writable()
const noexcept {
return uv_status(::uv_is_writable(
static_cast< uv_t* >(uv_handle))); }
125 int set_blocking(
bool _enable)
noexcept {
return uv_status(::uv_stream_set_blocking(
static_cast< uv_t* >(uv_handle), _enable)); }
128 explicit operator
const uv_t*()
const noexcept {
return static_cast<
const uv_t* >(uv_handle); }
129 explicit operator uv_t*()
noexcept {
return static_cast< uv_t* >(uv_handle); }
133 void stream::alloc_cb(::uv_handle_t *_uv_handle, std::size_t _suggested_size, ::uv_buf_t *_uv_buf)
134 { io_alloc_cb(_uv_handle, _suggested_size, _uv_buf); }
137 void stream::read_cb(::uv_stream_t *_uv_stream, ssize_t _nread,
const ::uv_buf_t *_uv_buf)
138 { io_read_cb(_uv_stream, _nread, _uv_buf,
nullptr); }
141 void stream::connection_cb(::uv_stream_t *_uv_stream,
int _status)
143 auto instance_ptr = instance::from(_uv_stream);
144 instance_ptr->uv_error = _status;
145 auto &connection_cb = instance_ptr->properties().connection_cb;
146 if (connection_cb) connection_cb(stream(_uv_stream));
157 friend class handle::instance< tcp >;
158 friend class connect;
162 using uv_t = ::uv_tcp_t;
165 using instance =
handle::instance<
tcp >;
169 explicit tcp(uv_t *_uv_handle) :
stream(
reinterpret_cast<
stream::uv_t* >(_uv_handle)) {}
175 tcp(
const tcp&) =
default;
176 tcp& operator =(
const tcp&) =
default;
178 tcp(
tcp&&)
noexcept =
default;
179 tcp& operator =(
tcp&&)
noexcept =
default;
187 uv_handle = instance::create();
189 auto uv_ret = ::uv_tcp_init_ex(
static_cast< uv::loop::uv_t* >(_loop),
static_cast< uv_t* >(uv_handle), _flags);
190 if (uv_status(uv_ret) < 0)
return;
192 instance::from(uv_handle)->book_loop();
197 tcp(
uv::
loop &_loop, ::uv_os_sock_t _socket,
bool _set_blocking)
199 uv_handle = instance::create();
201 auto uv_ret = ::uv_tcp_init(
static_cast<
uv::
loop::uv_t* >(_loop),
static_cast< uv_t* >(uv_handle));
202 if (uv_status(uv_ret) < 0)
return;
204 instance::from(uv_handle)->book_loop();
206 uv_ret = ::uv_tcp_open(
static_cast< uv_t* >(uv_handle), _socket);
207 if (uv_status(uv_ret) < 0)
return;
217 int nodelay(
bool _enable)
noexcept {
return uv_status(::uv_tcp_nodelay(
static_cast< uv_t* >(uv_handle), _enable)); }
220 int keepalive(
bool _enable,
unsigned int _delay)
noexcept {
return uv_status(::uv_tcp_keepalive(
static_cast< uv_t* >(uv_handle), _enable, _delay)); }
223 int simultaneous_accepts(
bool _enable)
noexcept {
return uv_status(::uv_tcp_simultaneous_accepts(
static_cast< uv_t* >(uv_handle), _enable)); }
231 int bind(
const _T_ &_sockaddr,
unsigned int _flags = 0)
noexcept 233 return uv_status(::uv_tcp_bind(
static_cast< uv_t* >(uv_handle),
reinterpret_cast<
const ::sockaddr* >(&_sockaddr), _flags));
245 uv_status(::uv_tcp_getsockname(
static_cast< uv_t* >(uv_handle),
reinterpret_cast< ::sockaddr* >(&_sockaddr), &z))
258 uv_status(::uv_tcp_getpeername(
static_cast< uv_t* >(uv_handle),
reinterpret_cast< ::sockaddr* >(&_sockaddr), &z))
269 uv_status(::uv_send_buffer_size(
static_cast<
handle::uv_t* >(uv_handle), (
int*)&v));
274 void send_buffer_size(
unsigned int _value)
noexcept { uv_status(::uv_send_buffer_size(
static_cast<
handle::uv_t* >(uv_handle), (
int*)&_value)); }
281 uv_status(::uv_recv_buffer_size(
static_cast<
handle::uv_t* >(uv_handle), (
int*)&v));
286 void recv_buffer_size(
unsigned int _value)
noexcept { uv_status(::uv_recv_buffer_size(
static_cast<
handle::uv_t* >(uv_handle), (
int*)&_value)); }
290 explicit operator
const uv_t*()
const noexcept {
return static_cast<
const uv_t* >(uv_handle); }
291 explicit operator uv_t*()
noexcept {
return static_cast< uv_t* >(uv_handle); }
302 friend class handle::instance< pipe >;
303 friend class connect;
305 friend class process;
309 using uv_t = ::uv_pipe_t;
316 explicit pipe(uv_t *_uv_handle) :
stream(
reinterpret_cast<
stream::uv_t* >(_uv_handle)) {}
318 pipe(
uv::
loop &_loop,
bool _ipc)
320 uv_handle = instance::create();
322 auto uv_ret = ::uv_pipe_init(
static_cast<
uv::
loop::uv_t* >(_loop),
static_cast< uv_t* >(uv_handle), _ipc);
323 if (uv_status(uv_ret) < 0)
return;
325 instance::from(uv_handle)->book_loop();
332 pipe(
const pipe&) =
default;
333 pipe& operator =(
const pipe&) =
default;
335 pipe(
pipe&&)
noexcept =
default;
336 pipe& operator =(
pipe&&)
noexcept =
default;
345 uv_status(::uv_pipe_bind(
static_cast< uv_t* >(uv_handle), _name));
349 pipe(
uv::
loop &_loop, ::uv_file _fd,
bool _ipc,
bool _set_blocking)
354 auto uv_ret = ::uv_pipe_open(
static_cast< uv_t* >(uv_handle), _fd);
355 if (uv_status(uv_ret) < 0)
return;
362 int ipc()
const noexcept {
return static_cast< uv_t* >(uv_handle)->ipc; }
368 std::size_t len = UNIX_PATH_MAX;
370 std::size_t len = 108;
372 std::string name(len,
'\0');
374 uv_status(::uv_pipe_getsockname(
static_cast< uv_t* >(uv_handle),
const_cast<
char* >(name.c_str()), &len)) < 0
376 uv_status() == UV_ENOBUFS
377 ) name.resize(len,
'\0');
384 std::size_t len = UNIX_PATH_MAX;
386 std::size_t len = 108;
388 std::string name(len,
'\0');
390 uv_status(::uv_pipe_getpeername(
static_cast< uv_t* >(uv_handle),
const_cast<
char* >(name.c_str()), &len)) < 0
392 uv_status() == UV_ENOBUFS
393 ) name.resize(len,
'\0');
397 void pending_instances(
int _count)
noexcept { ::uv_pipe_pending_instances(
static_cast< uv_t* >(uv_handle), _count); }
412 uv_status(::uv_send_buffer_size(
static_cast<
handle::uv_t* >(uv_handle), (
int*)&v));
417 void send_buffer_size(
unsigned int _value)
noexcept { uv_status(::uv_send_buffer_size(
static_cast<
handle::uv_t* >(uv_handle), (
int*)&_value)); }
424 uv_status(::uv_recv_buffer_size(
static_cast<
handle::uv_t* >(uv_handle), (
int*)&v));
429 void recv_buffer_size(
unsigned int _value)
noexcept { uv_status(::uv_recv_buffer_size(
static_cast<
handle::uv_t* >(uv_handle), (
int*)&_value)); }
433 explicit operator
const uv_t*()
const noexcept {
return static_cast<
const uv_t* >(uv_handle); }
434 explicit operator uv_t*()
noexcept {
return static_cast< uv_t* >(uv_handle); }
445 friend class handle::instance< tty >;
449 using uv_t = ::uv_tty_t;
456 explicit tty(uv_t *_uv_handle) :
stream(
reinterpret_cast<
stream::uv_t* >(_uv_handle)) {}
462 tty(
const tty&) =
default;
463 tty& operator =(
const tty&) =
default;
465 tty(
tty&&)
noexcept =
default;
466 tty& operator =(
tty&&)
noexcept =
default;
470 tty(
uv::
loop &_loop, ::uv_file _fd,
bool _readable,
bool _set_blocking)
472 uv_handle = instance::create();
474 auto uv_ret = ::uv_tty_init(
static_cast< uv::loop::uv_t* >(_loop),
static_cast< uv_t* >(uv_handle), _fd, _readable);
475 if (uv_status(uv_ret) < 0)
return;
477 instance::from(uv_handle)->book_loop();
488 return uv_status(::uv_tty_set_mode(
static_cast< uv_t* >(uv_handle), _mode));
495 return uv_status(::uv_tty_get_winsize(
static_cast< uv_t* >(uv_handle), &_width, &_height));
500 static int reset_mode()
noexcept {
return ::uv_tty_reset_mode(); }
503 explicit operator
const uv_t*()
const noexcept {
return static_cast<
const uv_t* >(uv_handle); }
504 explicit operator uv_t*()
noexcept {
return static_cast< uv_t* >(uv_handle); }
513 switch (
static_cast< uv_t* >(uv_handle)->type)
516 client.uv_handle = handle::instance< pipe >::create();
517 client.uv_status(::uv_pipe_init(
518 static_cast< ::uv_pipe_t* >(uv_handle)->loop,
519 static_cast< ::uv_pipe_t* >(client.uv_handle),
520 static_cast< ::uv_pipe_t* >(uv_handle)->ipc
522 if (client) handle::instance< pipe >::from(client.uv_handle)->book_loop();
525 client.uv_handle = handle::instance< tcp >::create();
526 client.uv_status(::uv_tcp_init(
527 static_cast< ::uv_tcp_t* >(uv_handle)->loop,
528 static_cast< ::uv_tcp_t* >(client.uv_handle)
530 if (client) handle::instance< tcp >::from(client.uv_handle)->book_loop();
533 client.uv_status(UV_ENOTSUP);
536 client.uv_status(UV_EBADF);
544 auto uv_ret = ::uv_accept(
static_cast< uv_t* >(uv_handle),
static_cast< uv_t* >(client));
545 if (uv_status(uv_ret) < 0) client.uv_status(uv_ret);
556 switch (::uv_pipe_pending_type(
static_cast< uv_t* >(uv_handle)))
559 fd.uv_handle = handle::instance< pipe >::create();
560 fd.uv_status(::uv_pipe_init(
561 static_cast< uv_t* >(uv_handle)->loop,
562 static_cast< ::uv_pipe_t* >(fd.uv_handle),
563 static_cast< uv_t* >(uv_handle)->ipc
565 if (fd) handle::instance< pipe >::from(fd.uv_handle)->book_loop();
568 fd.uv_handle = handle::instance< tcp >::create();
569 fd.uv_status(::uv_tcp_init(
570 static_cast< uv_t* >(uv_handle)->loop,
571 static_cast< ::uv_tcp_t* >(fd.uv_handle)
573 if (fd) handle::instance< tcp >::from(fd.uv_handle)->book_loop();
576 fd.uv_status(UV_EBADF);
584 auto uv_ret = ::uv_accept(
static_cast< ::uv_stream_t* >(uv_handle),
static_cast< ::uv_stream_t* >(fd));
585 if (uv_status(uv_ret) < 0) fd.uv_status(uv_ret);
Namespace for all uvcc definitions.
int keepalive(bool _enable, unsigned int _delay) noexcept
Enable or disable TCP keep-alive.
tcp(uv::loop &_loop, ::uv_os_sock_t _socket, bool _set_blocking)
Create a handle object from an existing native platform depended TCP socket descriptor.
static int reset_mode() noexcept
Reset TTY settings to default values. To be called when the program exits.
bool getsockname(_T_ &_sockaddr) const noexcept
Get the local address which this handle is bound to.
tcp(uv::loop &_loop, unsigned _flags=AF_UNSPEC)
Create a TCP socket with the specified flags.
int bind(const _T_ &_sockaddr, unsigned int _flags=0) noexcept
Bind the handle to an address and port.
tty(uv::loop &_loop, ::uv_file _fd, bool _readable, bool _set_blocking)
Create a tty object from the given TTY file descriptor.
bool getpeername(_T_ &_sockaddr) const noexcept
Get the address of the remote peer connected to this handle.
int set_mode(::uv_tty_mode_t _mode) noexcept
Set the TTY using the specified terminal mode.
std::string getpeername() const noexcept
Get the name of the Unix domain socket or the Windows named pipe which this pipe object is connected ...
pipe(uv::loop &_loop, const char *_name, bool _ipc)
Create a pipe bound to a file path (Unix domain socket) or a name (Windows named pipe).
void recv_buffer_size(unsigned int _value) noexcept
Set the size of the receive buffer that the operating system uses for the socket. ...
void send_buffer_size(unsigned int _value) noexcept
Set the size of the send buffer that the operating system uses for the socket.
stream accept_pending_handle() const
Used to receive handles over the IPC pipe.
int uv_status() const noexcept
The status value returned by the last executed libuv API function on this handle. ...
The base class for the libuv handles.
std::string getsockname() const noexcept
Get the name of the Unix domain socket or the Windows named pipe for this pipe object.
std::size_t write_queue_size() const noexcept
The amount of queued bytes waiting to be sent.
void send_buffer_size(unsigned int _value) noexcept
Set the size of the send buffer that the operating system uses for the pipe.
pipe(uv::loop &_loop, ::uv_file _fd, bool _ipc, bool _set_blocking)
Create a pipe object from an existing OS native pipe descriptor.
The I/O event loop class.
unsigned int recv_buffer_size() const noexcept
Get the size of the receive buffer that the operating system uses for the pipe.
bool is_writable() const noexcept
Check if the stream is writable.
The base class for handles representing I/O endpoints: a file, TCP/UDP socket, pipe, TTY.
int get_winsize(int &_width, int &_height) const noexcept
Get the current window size.
int simultaneous_accepts(bool _enable) noexcept
void pending_instances(int _count) noexcept
Set the number of pending pipe instances when this pipe server is waiting for connections. (Windows only.)
int ipc() const noexcept
Non-zero if this pipe is used for passing handles.
unsigned int recv_buffer_size() const noexcept
Get the size of the receive buffer that the operating system uses for the socket. ...
int set_blocking(bool _enable) noexcept
Enable or disable blocking mode for the stream.
unsigned int send_buffer_size() const noexcept
Get the size of the send buffer that the operating system uses for the pipe.
int pending_handle_count() const noexcept
The number of pending handles being sent over the IPC pipe.
stream accept() const
Accept incoming connections.
bool is_readable() const noexcept
Check if the stream is readable.
::uv_os_sock_t socket() const noexcept
Get the platform dependent socket descriptor. The alias for handle::fileno().
void recv_buffer_size(unsigned int _value) noexcept
Set the size of the receive buffer that the operating system uses for the pipe.
int listen(int _backlog, const on_connection_t &_connection_cb) const
Start listening for incoming connections.
int nodelay(bool _enable) noexcept
Enable or disable Nagle’s algorithm on the socket.
unsigned int send_buffer_size() const noexcept
Get the size of the send buffer that the operating system uses for the socket.