diff --git a/README.md b/README.md index a1449ebf..66272a5d 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,7 @@ void listen(uvw::Loop &loop) { client->read(); }); - tcp->bind("127.0.0.1", 4242); + tcp->bind("127.0.0.1", 4242); tcp->listen(); } @@ -41,7 +41,7 @@ void conn(uvw::Loop &loop) { tcp.close(); }); - tcp->connect(std::string{"127.0.0.1"}, 4242); + tcp->connect(std::string{"127.0.0.1"}, 4242); } int main() { @@ -147,7 +147,7 @@ To know what are the available resources' types, please refer the API reference. ##### The event-based approach For `uvw` offers an event-based approach, resources are small event emitters to which listeners can be attached. -Attaching a listener to a resource is the reccomended way to be notified about changes. +Attaching a listener to a resource is the recommended way to be notified about changes. Listeners must be callable objects of type `void(const EventType &, ResourceType &)`, where: * `EventType` is the type of the event for which they have been designed @@ -180,11 +180,14 @@ tcp->on([](const uvw::ListenEvent &event, uvw::Tcp &srv) mutab client->read(); }); -tcp->bind("127.0.0.1", 4242); +tcp->bind("127.0.0.1", 4242); tcp->listen(); ``` -The API reference is the reccomended documentation for further details about resources and their methods. +Note that `uvw::Tcp` already supports _IPv6_ out-of-the-box. The statement above is equivalent to `tcp->bind("127.0.0.1", 4242)`. +It's suffice to explicitly specify `uvw::Tcp::IPv6` as the underlying protocol to use it. + +The API reference is the recommended documentation for further details about resources and their methods. ## Tests diff --git a/src/uvw/stream.hpp b/src/uvw/stream.hpp index 191f7f67..36a8c1b4 100644 --- a/src/uvw/stream.hpp +++ b/src/uvw/stream.hpp @@ -126,7 +126,10 @@ public: listen(DEFAULT_BACKLOG); } - virtual void accept(T &) = 0; + template + void accept(U &ref) { + this->invoke(&uv_accept, this->template get(), ref.template get()); + } void read() { this->invoke(&uv_read_start, this->template get(), &this->allocCallback, &readCallback); diff --git a/src/uvw/tcp.hpp b/src/uvw/tcp.hpp index 7b3c985e..006f1f73 100644 --- a/src/uvw/tcp.hpp +++ b/src/uvw/tcp.hpp @@ -17,23 +17,8 @@ namespace uvw { class Tcp final: public Stream { - using SockFunctionType = Addr(*)(const Tcp &); - using PeerFunctionType = SockFunctionType; - - template - static Addr tSock(const Tcp &tcp) noexcept { - return details::address(uv_tcp_getsockname, tcp.get()); - } - - template - static Addr tPeer(const Tcp &tcp) noexcept { - return details::address(uv_tcp_getpeername, tcp.get()); - } - explicit Tcp(std::shared_ptr ref) - : Stream{HandleType{}, std::move(ref)}, - sockF{&tSock}, - peerF{&tPeer} + : Stream{HandleType{}, std::move(ref)} { } public: @@ -61,33 +46,34 @@ public: invoke(&uv_tcp_keepalive, get(), enable, time.count()); } - template> + template void bind(std::string ip, unsigned int port, Flags flags = Flags{}) { - typename Traits::Type addr; - Traits::AddrFunc(ip.data(), port, &addr); - - if(0 == invoke(&uv_tcp_bind, get(), reinterpret_cast(&addr), flags)) { - sockF = &tSock; - peerF = &tPeer; - } + typename details::IpTraits::Type addr; + details::IpTraits::AddrFunc(ip.data(), port, &addr); + invoke(&uv_tcp_bind, get(), reinterpret_cast(&addr), flags); } - template> + template void bind(Addr addr, Flags flags = Flags{}) { bind(addr.ip, addr.port, flags); } - Addr sock() const noexcept { return sockF(*this); } - Addr peer() const noexcept { return peerF(*this); } + template + Addr sock() const noexcept { + return details::address(&uv_tcp_getsockname, get()); + } - template> + template + Addr peer() const noexcept { + return details::address(&uv_tcp_getpeername, get()); + } + + template void connect(std::string ip, unsigned int port) { - typename Traits::Type addr; - Traits::AddrFunc(ip.data(), port, &addr); + typename details::IpTraits::Type addr; + details::IpTraits::AddrFunc(ip.data(), port, &addr); auto listener = [ptr = this->shared_from_this()](const auto &event, details::Connect &) { - ptr->sockF = &tSock; - ptr->peerF = &tPeer; ptr->publish(event); }; @@ -97,19 +83,8 @@ public: connect->connect(&uv_tcp_connect, get(), reinterpret_cast(&addr)); } - template> + template void connect(Addr addr) { connect(addr.ip, addr.port); } - - void accept(Tcp &tcp) override { - if(0 == invoke(&uv_accept, get(), tcp.get())) { - tcp.sockF = sockF; - tcp.peerF = peerF; - } - } - -private: - SockFunctionType sockF; - PeerFunctionType peerF; }; diff --git a/src/uvw/udp.hpp b/src/uvw/udp.hpp index b9469c31..3c7d7639 100644 --- a/src/uvw/udp.hpp +++ b/src/uvw/udp.hpp @@ -39,40 +39,27 @@ public: class Udp final: public Handle { - using SockFunctionType = Addr(*)(const Udp &); - using PeerFunctionType = Addr(*)(const sockaddr *); - - template - static Addr tSock(const Udp &udp) noexcept { - return details::address(uv_udp_getsockname, udp.get()); - } - - template> - static Addr tPeer(const sockaddr *addr) noexcept { - const typename Traits::Type *aptr = reinterpret_cast(addr); - int len = sizeof(*addr); - return details::address(aptr, len); - } - explicit Udp(std::shared_ptr ref) - : Handle{HandleType{}, std::move(ref)}, - sockF{&tSock}, - peerF{&tPeer} + : Handle{HandleType{}, std::move(ref)} { } + template static void recvCallback(uv_udp_t *handle, ssize_t nread, const uv_buf_t *buf, const sockaddr *addr, unsigned flags) { + typename details::IpTraits::Type *aptr = reinterpret_cast::Type *>(addr); + int len = sizeof(*addr); + Udp &udp = *(static_cast(handle->data)); // data will be destroyed no matter of what the value of nread is std::unique_ptr data{buf->base}; if(nread > 0) { // data available (can be truncated) - udp.publish(UDPDataEvent{udp.peerF(addr), std::move(data), nread, flags & UV_UDP_PARTIAL}); + udp.publish(UDPDataEvent{details::address(aptr, len), std::move(data), nread, flags & UV_UDP_PARTIAL}); } else if(nread == 0 && addr == nullptr) { // no more data to be read, doing nothing is fine } else if(nread == 0 && addr != nullptr) { // empty udp packet - udp.publish(UDPDataEvent{udp.peerF(addr), std::move(data), nread, false}); + udp.publish(UDPDataEvent{details::address(aptr, len), std::move(data), nread, false}); } else { // transmission error udp.publish(ErrorEvent(nread)); @@ -100,30 +87,26 @@ public: bool init() { return initialize(&uv_udp_init); } - template> + template void bind(std::string ip, unsigned int port, Flags flags = Flags{}) { - typename Traits::Type addr; - Traits::AddrFunc(ip.data(), port, &addr); - - if(0 == invoke(&uv_udp_bind, get(), reinterpret_cast(&addr), flags)) { - sockF = &tSock; - peerF = &tPeer; - } + typename details::IpTraits::Type addr; + details::IpTraits::AddrFunc(ip.data(), port, &addr); + invoke(&uv_udp_bind, get(), reinterpret_cast(&addr), flags); } - template> + template void bind(Addr addr, Flags flags = Flags{}) { bind(addr.ip, addr.port, flags); } - Addr sock() const noexcept { return sockF(*this); } + template + Addr sock() const noexcept { + return details::address(&uv_udp_getsockname, get()); + } - template + template void multicastMembership(std::string multicast, std::string interface, Membership membership) { - if(0 == invoke(&uv_udp_set_membership, get(), multicast.data(), interface.data(), static_cast(membership))) { - sockF = &tSock; - peerF = &tPeer; - } + invoke(&uv_udp_set_membership, get(), multicast.data(), interface.data(), static_cast(membership)); } void multicastLoop(bool enable = true) { @@ -134,27 +117,22 @@ public: invoke(&uv_udp_set_multicast_ttl, get(), val > 255 ? 255 : val); } - template + template void multicastInterface(std::string interface) { - if(0 == invoke(&uv_udp_set_multicast_interface, get(), interface.data())) { - sockF = &tSock; - peerF = &tPeer; - } + invoke(&uv_udp_set_multicast_interface, get(), interface.data()); } void broadcast(bool enable = false) { invoke(&uv_udp_set_broadcast, get(), enable); } void ttl(int val) { invoke(&uv_udp_set_ttl, get(), val > 255 ? 255 : val); } - template> + template void send(std::string ip, unsigned int port, char *data, ssize_t len) { - typename Traits::Type addr; - Traits::AddrFunc(ip.data(), port, &addr); + typename details::IpTraits::Type addr; + details::IpTraits::AddrFunc(ip.data(), port, &addr); uv_buf_t bufs[] = { uv_buf_init(data, len) }; auto listener = [ptr = this->shared_from_this()](const auto &event, details::Send &) { - ptr->sockF = &tSock; - ptr->peerF = &tPeer; ptr->publish(event); }; @@ -162,20 +140,17 @@ public: send->once(listener); send->once(listener); send->send(get(), bufs, 1, reinterpret_cast(&addr)); - - sockF = &tSock; - peerF = &tPeer; } - template> + template void send(std::string ip, unsigned int port, std::unique_ptr data, ssize_t len) { send(ip, port, data.get(), len); } - template> + template int trySend(std::string ip, unsigned int port, char *data, ssize_t len) { - typename Traits::Type addr; - Traits::AddrFunc(ip.data(), port, &addr); + typename details::IpTraits::Type addr; + details::IpTraits::AddrFunc(ip.data(), port, &addr); uv_buf_t bufs[] = { uv_buf_init(data, len) }; auto bw = uv_udp_try_send(get(), bufs, 1, reinterpret_cast(&addr)); @@ -183,25 +158,22 @@ public: if(bw < 0) { this->publish(ErrorEvent{bw}); bw = 0; - } else { - sockF = &tSock; - peerF = &tPeer; } return bw; } - template> + template int trySend(std::string ip, unsigned int port, std::unique_ptr data, ssize_t len) { return trySend(ip, port, data.get(), len); } - void recv() { invoke(&uv_udp_recv_start, get(), &allocCallback, &recvCallback); } - void stop() { invoke(&uv_udp_recv_stop, get()); } + template + void recv() { + invoke(&uv_udp_recv_start, get(), &allocCallback, &recvCallback); + } -private: - SockFunctionType sockF; - PeerFunctionType peerF; + void stop() { invoke(&uv_udp_recv_stop, get()); } }; diff --git a/src/uvw/util.hpp b/src/uvw/util.hpp index 7c41bd95..02fb1481 100644 --- a/src/uvw/util.hpp +++ b/src/uvw/util.hpp @@ -107,12 +107,12 @@ const IpTraits::NameFuncType IpTraits::NameFunc = &uv_ip4_name; const IpTraits::NameFuncType IpTraits::NameFunc = &uv_ip6_name; -template> -Addr address(const typename Traits::Type *aptr, int len) noexcept { +template +Addr address(const typename details::IpTraits::Type *aptr, int len) noexcept { std::pair addr{}; char name[len]; - int err = Traits::NameFunc(aptr, name, len); + int err = details::IpTraits::NameFunc(aptr, name, len); if(0 == err) { addr = { std::string{name}, ntohs(aptr->sin_port) }; @@ -126,7 +126,7 @@ Addr address(const typename Traits::Type *aptr, int len) noexcept { } -template> +template Addr address(F &&f, const H *handle) noexcept { sockaddr_storage ssto; int len = sizeof(ssto); @@ -135,7 +135,7 @@ Addr address(F &&f, const H *handle) noexcept { int err = std::forward(f)(handle, reinterpret_cast(&ssto), &len); if(0 == err) { - typename Traits::Type *aptr = reinterpret_cast(&ssto); + typename details::IpTraits::Type *aptr = reinterpret_cast::Type *>(&ssto); addr = address(aptr, len); } diff --git a/test/main.cpp b/test/main.cpp index d588e38a..8858ff23 100644 --- a/test/main.cpp +++ b/test/main.cpp @@ -56,7 +56,7 @@ void listen(uvw::Loop &loop) { std::cout << "close" << std::endl; }); - tcp->bind("127.0.0.1", 4242); + tcp->bind("127.0.0.1", 4242); tcp->listen(); } @@ -88,7 +88,7 @@ void conn(uvw::Loop &loop) { std::cout << "close" << std::endl; }); - tcp->connect(std::string{"127.0.0.1"}, 4242); + tcp->connect(std::string{"127.0.0.1"}, 4242); } void g() {