diff --git a/src/uvw/check.hpp b/src/uvw/check.hpp index 58d1129d..28e419a2 100644 --- a/src/uvw/check.hpp +++ b/src/uvw/check.hpp @@ -32,7 +32,7 @@ public: using CBF = CallbackFactory; auto func = CBF::on<&Check::startCallback>(*this, cb); auto err = uv_check_start(get(), func); - if(err) { cb(UVWError{err}, *this); } + if(err) { error(err); } } UVWError stop() noexcept { return UVWError{uv_check_stop(get())}; } diff --git a/src/uvw/loop.hpp b/src/uvw/loop.hpp index 3e8fa76d..59097125 100644 --- a/src/uvw/loop.hpp +++ b/src/uvw/loop.hpp @@ -12,7 +12,6 @@ namespace uvw { -class BaseResource; class Loop; @@ -50,9 +49,6 @@ public: constexpr operator R&() noexcept { return *res; } constexpr operator const R&() const noexcept { return *res; } - template::value>* = nullptr> - constexpr operator Handle() { return Handle{res}; } - private: std::shared_ptr res; }; @@ -109,6 +105,11 @@ public: } } + template + Handle handle(std::shared_ptr ptr) { + return Handle{std::move(ptr)}; + } + template Handle handle(Args&&... args) { return Handle{shared_from_this(), std::forward(args)...}; diff --git a/src/uvw/resource.hpp b/src/uvw/resource.hpp index 5c8c8dd3..c3fc65d5 100644 --- a/src/uvw/resource.hpp +++ b/src/uvw/resource.hpp @@ -67,11 +67,18 @@ protected: template explicit Resource(HandleType, std::shared_ptr r) - : pLoop{std::move(r)}, handle{std::make_shared()} + : uvHandle{std::make_shared()}, pLoop{std::move(r)} { } + void error(int error) { + auto ptr = std::static_pointer_cast(leak); + auto cb = std::move(callback); + leak.reset(); + cb(UVWError{error}, *ptr); + } + template - U* get() const noexcept { return reinterpret_cast(handle.get()); } + U* get() const noexcept { return reinterpret_cast(uvHandle.get()); } uv_loop_t* parent() const noexcept { return pLoop->loop.get(); } @@ -84,7 +91,8 @@ public: void operator=(const Resource &) = delete; void operator=(Resource &&) = delete; - std::shared_ptr loop() const noexcept { return pLoop; } + Handle handle() noexcept { return pLoop->handle(Resource::shared_from_this()); } + Loop& loop() const noexcept { return *pLoop; } bool active() const noexcept { return !(uv_is_active(get()) == 0); } bool closing() const noexcept { return !(uv_is_closing(get()) == 0); } @@ -100,8 +108,8 @@ public: } private: + std::shared_ptr uvHandle; std::shared_ptr pLoop; - std::shared_ptr handle; std::shared_ptr leak; std::function callback; }; @@ -134,7 +142,7 @@ template template &, H, Args...)> void UVCallbackFactory::protoOnce(H handle, Args... args) { T &ref = *(static_cast(details::get(handle))); - std::shared_ptr ptr = std::static_pointer_cast(ref.leak); + auto ptr = std::static_pointer_cast(ref.leak); auto cb = std::move(ref.callback); ref.leak.reset(); F(*ptr, cb, handle, std::forward(args)...); diff --git a/src/uvw/stream.hpp b/src/uvw/stream.hpp index 2bf1ffa0..41e3e1e6 100644 --- a/src/uvw/stream.hpp +++ b/src/uvw/stream.hpp @@ -11,6 +11,8 @@ namespace uvw { template class Stream: public Resource { + static constexpr unsigned int DEFAULT_BACKLOG = 128; + static void listenCallback(T &t, std::function &cb, uv_stream_t *, int status) { cb(UVWError{status}, t); } @@ -21,11 +23,15 @@ protected: public: // TODO shutdown + void listen(std::function cb) noexcept { + listen(DEFAULT_BACKLOG, std::move(cb)); + } + void listen(int backlog, std::function cb) noexcept { using CBF = typename Resource::template CallbackFactory; - auto func = CBF::on<&Stream::listenCallback>(*static_cast(this), cb); + auto func = CBF::template on<&Stream::listenCallback>(*static_cast(this), cb); auto err = uv_listen(this->template get(), backlog, func); - if(err) { cb(UVWError{err}, *static_cast(this)); } + if(err) { Stream::error(err); } } // TODO read diff --git a/src/uvw/tcp.hpp b/src/uvw/tcp.hpp index 59b53e69..f287f2df 100644 --- a/src/uvw/tcp.hpp +++ b/src/uvw/tcp.hpp @@ -34,7 +34,7 @@ class Tcp final: public Stream { public: using Time = std::chrono::duration; - enum { IPv4, IPv6 }; + enum IP { IPv4, IPv6 }; template static std::shared_ptr create(Args&&... args) { @@ -49,8 +49,15 @@ public: return UVWError{uv_tcp_keepalive(get(), enable ? 1 : 0, time.count())}; } - template - void connect(std::string, int, std::function) noexcept; + template + UVWError bind(std::string, unsigned int, bool = false); + + template + void connect(std::string, unsigned int, std::function) noexcept; + + UVWError accept(Tcp &tcp) { + return UVWError{uv_accept(get(), tcp.get())}; + } explicit operator bool() { return initialized; } @@ -61,24 +68,41 @@ private: template<> -void Tcp::connect(std::string ip, int port, std::function cb) noexcept { +UVWError Tcp::bind(std::string ip, unsigned int port, bool ipv6only) { + sockaddr_in addr; + uv_ip4_addr(ip.c_str(), port, &addr); + unsigned int flags = ipv6only ? UV_TCP_IPV6ONLY : 0; + return UVWError(uv_tcp_bind(get(), reinterpret_cast(&addr), flags));} + + +template<> +UVWError Tcp::bind(std::string ip, unsigned int port, bool ipv6only) { + sockaddr_in6 addr; + uv_ip6_addr(ip.c_str(), port, &addr); + unsigned int flags = ipv6only ? UV_TCP_IPV6ONLY : 0; + return UVWError(uv_tcp_bind(get(), reinterpret_cast(&addr), flags)); +} + + +template<> +void Tcp::connect(std::string ip, unsigned int port, std::function cb) noexcept { sockaddr_in addr; uv_ip4_addr(ip.c_str(), port, &addr); using CBF = CallbackFactory; auto func = CBF::template once<&Tcp::connectCallback>(*this, cb); auto err = uv_tcp_connect(conn.get(), get(), reinterpret_cast(&addr), func); - if(err) { cb(UVWError{err}, *this); } + if(err) { error(err); } } template<> -void Tcp::connect(std::string ip, int port, std::function cb) noexcept { +void Tcp::connect(std::string ip, unsigned int port, std::function cb) noexcept { sockaddr_in6 addr; uv_ip6_addr(ip.c_str(), port, &addr); using CBF = CallbackFactory; auto func = CBF::template once<&Tcp::connectCallback>(*this, cb); auto err = uv_tcp_connect(conn.get(), get(), reinterpret_cast(&addr), func); - if(err) { cb(UVWError{err}, *this); } + if(err) { error(err); } } diff --git a/src/uvw/timer.hpp b/src/uvw/timer.hpp index 2dd2170b..747a402a 100644 --- a/src/uvw/timer.hpp +++ b/src/uvw/timer.hpp @@ -36,7 +36,7 @@ public: using CBF = CallbackFactory; auto func = CBF::on<&Timer::startCallback>(*this, cb); auto err = uv_timer_start(get(), func, timeout.count(), rep.count()); - if(err) { cb(UVWError{err}, *this); } + if(err) { error(err); } } UVWError stop() noexcept { return UVWError{uv_timer_stop(get())}; } diff --git a/test/main.cpp b/test/main.cpp index b7a20e5e..ba881f97 100644 --- a/test/main.cpp +++ b/test/main.cpp @@ -2,23 +2,67 @@ #include -void f(uvw::Loop &loop) { +void listen(uvw::Loop &loop) { uvw::Handle handle = loop.handle(); - auto cb = [](uvw::UVWError err, uvw::Tcp &tcp) mutable { - std::cout << "---" << ((bool)err) << std::endl; - tcp.close([](uvw::UVWError err, uvw::Tcp &) mutable { - std::cout << "---" << ((bool)err) << std::endl; - }); + auto cb = [](uvw::UVWError err, uvw::Tcp &srv) mutable { + std::cout << "listen: " << ((bool)err) << std::endl; + + if(!err) { + uvw::Handle handle = srv.loop().handle(); + uvw::Tcp &client = handle; + + err = srv.accept(client); + std::cout << "accept: " << ((bool)err) << std::endl; + + if(!err) { + client.close([handle = srv.handle()](uvw::UVWError err, uvw::Tcp &) mutable { + std::cout << "close: " << ((bool)err) << std::endl; + + uvw::Tcp &srv = handle; + srv.close([](uvw::UVWError err, uvw::Tcp &) mutable { + std::cout << "close: " << ((bool)err) << std::endl; + }); + }); + } + } }; uvw::Tcp &tcp = handle; - tcp.connect(std::string{"127.0.0.1"}, 80, cb); + uvw::UVWError err = tcp.bind("127.0.0.1", 4242); + std::cout << "bind: " << ((bool)err) << std::endl; + + if(err) { + tcp.close([](uvw::UVWError err, uvw::Tcp &) mutable { + std::cout << "close: " << ((bool)err) << std::endl; + }); + } else { + tcp.listen(0, cb); + } +} + + +void conn(uvw::Loop &loop) { + uvw::Handle handle = loop.handle(); + + auto cb = [](uvw::UVWError err, uvw::Tcp &tcp) mutable { + std::cout << "connect: " << ((bool)err) << std::endl; + + auto cb = [](uvw::UVWError err, uvw::Tcp &tcp) mutable { + std::cout << "close: " << ((bool)err) << std::endl; + }; + + tcp.close(cb); + }; + + uvw::Tcp &tcp = handle; + tcp.connect(std::string{"127.0.0.1"}, 4242, cb); } void g() { auto loop = uvw::Loop::getDefault(); - f(*loop); + listen(*loop); + conn(*loop); loop->run(); loop = nullptr; }