tests: udp (partial) + added a few functions to udp handle

This commit is contained in:
Michele Caini 2017-01-30 15:39:34 +01:00
parent c98083164f
commit bef8bd1d5c
3 changed files with 216 additions and 0 deletions

View File

@ -315,6 +315,28 @@ public:
req->send(get(), reinterpret_cast<const sockaddr *>(&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.<br/>
* 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<typename I = IPv4>
void send(Addr addr, std::unique_ptr<char[]> data, std::size_t len) {
send<I>(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<const sockaddr *>(&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.<br/>
* 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<typename I = IPv4>
void send(Addr addr, char *data, std::size_t len) {
send<I>(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 wont queue a send request if it cant 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<typename I = IPv4>
int trySend(Addr addr, std::unique_ptr<char[]> data, std::size_t len) {
return trySend<I>(addr.ip, addr.port, std::move(data), len);
}
/**
* @brief Sends data over the UDP socket.
*
* Same as `send()`, but it wont queue a send request if it cant 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<typename I = IPv4>
int trySend(std::string ip, unsigned int port, char *data, std::size_t len) {
typename details::IpTraits<I>::Type addr;
details::IpTraits<I>::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<const sockaddr *>(&addr));
if(bw < 0) {
publish(ErrorEvent{bw});
bw = 0;
}
return bw;
}
/**
* @brief Sends data over the UDP socket.
*
* Same as `send()`, but it wont queue a send request if it cant 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<typename I = IPv4>
int trySend(Addr addr, char *data, std::size_t len) {
return trySend<I>(addr.ip, addr.port, data, len);
}
/**
* @brief Prepares for receiving data.
*

View File

@ -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 $<TARGET_OBJECTS:odr> 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 $<TARGET_OBJECTS:odr> uvw/util.cpp)

103
test/uvw/udp.cpp Normal file
View File

@ -0,0 +1,103 @@
#include <gtest/gtest.h>
#include <uvw.hpp>
TEST(Udp, Functionalities) {
auto loop = uvw::Loop::getDefault();
auto handle = loop->resource<uvw::UDPHandle>();
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<uvw::UDPHandle>();
handle->on<uvw::ErrorEvent>([](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<uvw::UDPHandle>();
auto client = loop->resource<uvw::UDPHandle>();
server->on<uvw::ErrorEvent>([](const auto &, auto &) { FAIL(); });
client->on<uvw::ErrorEvent>([](const auto &, auto &) { FAIL(); });
server->once<uvw::UDPDataEvent>([&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<char[]>(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<uvw::UDPHandle>();
auto client = loop->resource<uvw::UDPHandle>();
server->on<uvw::ErrorEvent>([](const auto &, auto &) { FAIL(); });
client->on<uvw::ErrorEvent>([](const auto &, auto &) { FAIL(); });
server->once<uvw::UDPDataEvent>([](const uvw::UDPDataEvent &, uvw::UDPHandle &handle) {
handle.close();
});
client->once<uvw::SendEvent>([](const uvw::SendEvent &, uvw::UDPHandle &handle) {
handle.close();
});
server->bind("127.0.0.1", 4242);
server->recv();
auto dataSend = std::unique_ptr<char[]>(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<uvw::UDPHandle>();
handle->on<uvw::ErrorEvent>([](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();
}