From bef8bd1d5c205f5a9a09f0fa177d6789a55a13fe Mon Sep 17 00:00:00 2001 From: Michele Caini Date: Mon, 30 Jan 2017 15:39:34 +0100 Subject: [PATCH] tests: udp (partial) + added a few functions to udp handle --- src/uvw/udp.hpp | 104 ++++++++++++++++++++++++++++++++++++++++++++ test/CMakeLists.txt | 9 ++++ test/uvw/udp.cpp | 103 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 216 insertions(+) create mode 100644 test/uvw/udp.cpp diff --git a/src/uvw/udp.hpp b/src/uvw/udp.hpp index 0e611de9..e0faf97e 100644 --- a/src/uvw/udp.hpp +++ b/src/uvw/udp.hpp @@ -315,6 +315,28 @@ public: req->send(get(), reinterpret_cast(&addr)); } + /** + * @brief Sends data over the UDP socket. + * + * Note that if the socket has not previously been bound with `bind()`, it + * will be bound to `0.0.0.0` (the _all interfaces_ IPv4 address) and a + * random port number. + * + * The handle takes the ownership of the data and it is in charge of delete + * them. + * + * A SendEvent event will be emitted when the data have been sent.
+ * An ErrorEvent event will be emitted in case of errors. + * + * @param addr A valid instance of Addr. + * @param data The data to be sent. + * @param len The lenght of the submitted data. + */ + template + void send(Addr addr, std::unique_ptr data, std::size_t len) { + send(addr.ip, addr.port, std::move(data), len); + } + /** * @brief Sends data over the UDP socket. * @@ -353,6 +375,28 @@ public: req->send(get(), reinterpret_cast(&addr)); } + /** + * @brief Sends data over the UDP socket. + * + * Note that if the socket has not previously been bound with `bind()`, it + * will be bound to `0.0.0.0` (the _all interfaces_ IPv4 address) and a + * random port number. + * + * The handle doesn't take the ownership of the data. Be sure that their + * lifetime overcome the one of the request. + * + * A SendEvent event will be emitted when the data have been sent.
+ * An ErrorEvent event will be emitted in case of errors. + * + * @param addr A valid instance of Addr. + * @param data The data to be sent. + * @param len The lenght of the submitted data. + */ + template + void send(Addr addr, char *data, std::size_t len) { + send(addr.ip, addr.port, data, len); + } + /** * @brief Sends data over the UDP socket. * @@ -381,6 +425,66 @@ public: return bw; } + /** + * @brief Sends data over the UDP socket. + * + * Same as `send()`, but it won’t queue a send request if it can’t be + * completed immediately. + * + * @param addr A valid instance of Addr. + * @param data The data to be sent. + * @param len The lenght of the submitted data. + * @return Number of bytes written. + */ + template + int trySend(Addr addr, std::unique_ptr data, std::size_t len) { + return trySend(addr.ip, addr.port, std::move(data), len); + } + + /** + * @brief Sends data over the UDP socket. + * + * Same as `send()`, but it won’t queue a send request if it can’t be + * completed immediately. + * + * @param ip The address to which to send data. + * @param port The port to which to send data. + * @param data The data to be sent. + * @param len The lenght of the submitted data. + * @return Number of bytes written. + */ + template + int trySend(std::string ip, unsigned int port, char *data, std::size_t len) { + 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)); + + if(bw < 0) { + publish(ErrorEvent{bw}); + bw = 0; + } + + return bw; + } + + /** + * @brief Sends data over the UDP socket. + * + * Same as `send()`, but it won’t queue a send request if it can’t be + * completed immediately. + * + * @param addr A valid instance of Addr. + * @param data The data to be sent. + * @param len The lenght of the submitted data. + * @return Number of bytes written. + */ + template + int trySend(Addr addr, char *data, std::size_t len) { + return trySend(addr.ip, addr.port, data, len); + } + /** * @brief Prepares for receiving data. * diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index daaa8d48..9b2d76c8 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -47,6 +47,7 @@ set(TARGET_RESOURCE resource) set(TARGET_SIGNAL signal) set(TARGET_TCP tcp) set(TARGET_TIMER timer) +set(TARGET_UDP udp) set(TARGET_UTIL util) set(TARGET_WORK work) @@ -183,6 +184,14 @@ target_include_directories(${TARGET_TIMER} PRIVATE ${COMMON_INCLUDE_DIRS}) target_link_libraries(${TARGET_TIMER} PRIVATE ${COMMON_LINK_LIBS}) add_test(NAME ${TARGET_TIMER} COMMAND ${TARGET_TIMER}) +# Test TARGET_UDP + +set(TARGET_UDP_SOURCES $ uvw/udp.cpp) +add_executable(${TARGET_UDP} ${TARGET_UDP_SOURCES}) +target_include_directories(${TARGET_UDP} PRIVATE ${COMMON_INCLUDE_DIRS}) +target_link_libraries(${TARGET_UDP} PRIVATE ${COMMON_LINK_LIBS}) +add_test(NAME ${TARGET_UDP} COMMAND ${TARGET_UDP}) + # Test TARGET_UTIL set(TARGET_UTIL_SOURCES $ uvw/util.cpp) diff --git a/test/uvw/udp.cpp b/test/uvw/udp.cpp new file mode 100644 index 00000000..8172e346 --- /dev/null +++ b/test/uvw/udp.cpp @@ -0,0 +1,103 @@ +#include +#include + + +TEST(Udp, Functionalities) { + auto loop = uvw::Loop::getDefault(); + auto handle = loop->resource(); + + ASSERT_FALSE(handle->multicastMembership("0.0.0.0", "127.0.0.1", uvw::UDPHandle::Membership::JOIN_GROUP)); + ASSERT_TRUE(handle->multicastMembership("224.0.0.1", "127.0.0.1", uvw::UDPHandle::Membership::JOIN_GROUP)); + ASSERT_TRUE(handle->multicastMembership("224.0.0.1", "127.0.0.1", uvw::UDPHandle::Membership::LEAVE_GROUP)); + ASSERT_TRUE(handle->multicastLoop(true)); + ASSERT_TRUE(handle->multicastTtl(42)); + ASSERT_TRUE(handle->multicastInterface("127.0.0.1")); + ASSERT_TRUE(handle->broadcast(true)); + ASSERT_TRUE(handle->ttl(42)); + ASSERT_FALSE(handle->ttl(0)); + + handle->close(); + loop->run(); +} + + +TEST(Udp, BindRecvStop) { + auto loop = uvw::Loop::getDefault(); + auto handle = loop->resource(); + + handle->on([](const auto &, auto &) { FAIL(); }); + + handle->bind("127.0.0.1", 4242); + handle->recv(); + handle->stop(); + handle->close(); + + loop->run(); +} + + +TEST(Udp, ReadTrySend) { + auto loop = uvw::Loop::getDefault(); + auto server = loop->resource(); + auto client = loop->resource(); + + server->on([](const auto &, auto &) { FAIL(); }); + client->on([](const auto &, auto &) { FAIL(); }); + + server->once([&client](const uvw::UDPDataEvent &, uvw::UDPHandle &handle) { + client->close(); + handle.close(); + }); + + server->bind("127.0.0.1", 4242); + server->recv(); + + auto dataTrySend = std::unique_ptr(new char[1]{ 'a' }); + client->trySend("127.0.0.1", 4242, std::move(dataTrySend), 1); + + loop->run(); +} + + +TEST(Udp, ReadSend) { + auto loop = uvw::Loop::getDefault(); + auto server = loop->resource(); + auto client = loop->resource(); + + server->on([](const auto &, auto &) { FAIL(); }); + client->on([](const auto &, auto &) { FAIL(); }); + + server->once([](const uvw::UDPDataEvent &, uvw::UDPHandle &handle) { + handle.close(); + }); + + client->once([](const uvw::SendEvent &, uvw::UDPHandle &handle) { + handle.close(); + }); + + server->bind("127.0.0.1", 4242); + server->recv(); + + auto dataSend = std::unique_ptr(new char[2]{ 'b', 'c' }); + client->send(uvw::Addr{ "127.0.0.1", 4242 }, std::move(dataSend), 1); + + loop->run(); +} + + +TEST(Udp, Sock) { + auto loop = uvw::Loop::getDefault(); + auto handle = loop->resource(); + + handle->on([](const auto &, auto &) { FAIL(); }); + + handle->bind("127.0.0.1", 4242); + handle->recv(); + + uvw::Addr sock = handle->sock(); + ASSERT_EQ(sock.ip, "127.0.0.1"); + ASSERT_EQ(sock.port, decltype(sock.port){4242}); + + handle->close(); + loop->run(); +}