improved low-level interface for tcp/udp/dns

This commit is contained in:
Michele Caini 2017-11-28 14:13:16 +01:00
parent 38414e3063
commit 1e2c566295
3 changed files with 171 additions and 58 deletions

View File

@ -201,6 +201,15 @@ class GetNameInfoReq final: public Request<GetNameInfoReq, uv_getnameinfo_t> {
public:
using Request::Request;
/**
* @brief Async [getnameinfo](http://linux.die.net/man/3/getnameinfo).
* @param addr Initialized `sockaddr_in` or `sockaddr_in6` data structure.
* @param flags Optional flags that modify the behavior of `getnameinfo`.
*/
void nameInfo(const sockaddr &addr, int flags = 0) {
invoke(&uv_getnameinfo, parent(), get(), &nameInfoCallback, &addr, flags);
}
/**
* @brief Async [getnameinfo](http://linux.die.net/man/3/getnameinfo).
* @param ip A valid IP address.
@ -211,8 +220,7 @@ public:
void nameInfo(std::string ip, unsigned int port, int flags = 0) {
typename details::IpTraits<I>::Type addr;
details::IpTraits<I>::addrFunc(ip.data(), port, &addr);
auto saddr = reinterpret_cast<const sockaddr *>(&addr);
invoke(&uv_getnameinfo, parent(), get(), &nameInfoCallback, saddr, flags);
nameInfo(reinterpret_cast<const sockaddr &>(addr), flags);
}
/**
@ -222,7 +230,26 @@ public:
*/
template<typename I = IPv4>
void nameInfo(Addr addr, int flags = 0) {
nameInfo<I>(addr.ip, addr.port, flags);
nameInfo<I>(std::move(addr.ip), addr.port, flags);
}
/**
* @brief Sync [getnameinfo](http://linux.die.net/man/3/getnameinfo).
*
* @param addr Initialized `sockaddr_in` or `sockaddr_in6` data structure.
* @param flags Optional flags that modify the behavior of `getnameinfo`.
*
* @return A `std::pair` composed as it follows:
* * A boolean value that is true in case of success, false otherwise.
* * A `std::pair` composed as it follows:
* * A `const char *` containing a valid hostname.
* * A `const char *` containing a valid service name.
*/
std::pair<bool, std::pair<const char *, const char *>>
nameInfoSync(const sockaddr &addr, int flags = 0) {
auto req = get();
auto err = uv_getnameinfo(parent(), req, nullptr, &addr, flags);
return std::make_pair(!err, std::make_pair(req->host, req->service));
}
/**
@ -243,10 +270,7 @@ public:
nameInfoSync(std::string ip, unsigned int port, int flags = 0) {
typename details::IpTraits<I>::Type addr;
details::IpTraits<I>::addrFunc(ip.data(), port, &addr);
auto req = get();
auto saddr = reinterpret_cast<const sockaddr *>(&addr);
auto err = uv_getnameinfo(parent(), req, nullptr, saddr, flags);
return std::make_pair(!err, std::make_pair(req->host, req->service));
return nameInfoSync(reinterpret_cast<const sockaddr &>(addr), flags);
}
/**
@ -264,7 +288,7 @@ public:
template<typename I = IPv4>
std::pair<bool, std::pair<const char *, const char *>>
nameInfoSync(Addr addr, int flags = 0) {
return nameInfoSync<I>(addr.ip, addr.port, flags);
return nameInfoSync<I>(std::move(addr.ip), addr.port, flags);
}
};

View File

@ -130,7 +130,7 @@ public:
* @param opts Optional additional flags.
*/
void bind(const sockaddr &addr, Flags<Bind> opts = Flags<Bind>{}) {
invoke(&uv_tcp_bind, get(), reinterpret_cast<const sockaddr *>(&addr), opts);
invoke(&uv_tcp_bind, get(), &addr, opts);
}
/**
@ -175,7 +175,7 @@ public:
*/
template<typename I = IPv4>
void bind(Addr addr, Flags<Bind> opts = Flags<Bind>{}) {
bind<I>(addr.ip, addr.port, opts);
bind<I>(std::move(addr.ip), addr.port, std::move(opts));
}
/**
@ -244,7 +244,7 @@ public:
*/
template<typename I = IPv4>
void connect(Addr addr) {
connect<I>(addr.ip, addr.port);
connect<I>(std::move(addr.ip), addr.port);
}
private:

View File

@ -157,6 +157,25 @@ public:
invoke(&uv_udp_open, get(), socket);
}
/**
* @brief Binds the UDP handle to an IP address and port.
*
* Available flags are:
*
* * `UDPHandle::Bind::IPV6ONLY`
* * `UDPHandle::Bind::REUSEADDR`
*
* See the official
* [documentation](http://docs.libuv.org/en/v1.x/udp.html#c.uv_udp_flags)
* for further details.
*
* @param addr Initialized `sockaddr_in` or `sockaddr_in6` data structure.
* @param opts Optional additional flags.
*/
void bind(const sockaddr &addr, Flags<Bind> opts = Flags<Bind>{}) {
invoke(&uv_udp_bind, get(), &addr, opts);
}
/**
* @brief Binds the UDP handle to an IP address and port.
*
@ -177,7 +196,7 @@ public:
void bind(std::string ip, unsigned int port, Flags<Bind> opts = Flags<Bind>{}) {
typename details::IpTraits<I>::Type addr;
details::IpTraits<I>::addrFunc(ip.data(), port, &addr);
invoke(&uv_udp_bind, get(), reinterpret_cast<const sockaddr *>(&addr), opts);
bind(reinterpret_cast<const sockaddr &>(addr), std::move(opts));
}
/**
@ -197,7 +216,7 @@ public:
*/
template<typename I = IPv4>
void bind(Addr addr, Flags<Bind> opts = Flags<Bind>{}) {
bind<I>(addr.ip, addr.port, opts);
bind<I>(std::move(addr.ip), addr.port, std::move(opts));
}
/**
@ -289,16 +308,11 @@ public:
* A SendEvent event will be emitted when the data have been sent.<br/>
* An ErrorEvent event will be emitted in case of errors.
*
* @param ip The address to which to send data.
* @param port The port to which to send data.
* @param addr Initialized `sockaddr_in` or `sockaddr_in6` data structure.
* @param data The data to be sent.
* @param len The lenght of the submitted data.
*/
template<typename I = IPv4>
void send(std::string ip, unsigned int port, std::unique_ptr<char[]> data, unsigned int len) {
typename details::IpTraits<I>::Type addr;
details::IpTraits<I>::addrFunc(ip.data(), port, &addr);
void send(const sockaddr &addr, std::unique_ptr<char[]> data, unsigned int len) {
auto req = loop().resource<details::SendReq>(
std::unique_ptr<char[], details::SendReq::Deleter>{
data.release(), [](char *ptr) { delete[] ptr; }
@ -310,7 +324,32 @@ public:
req->once<ErrorEvent>(listener);
req->once<SendEvent>(listener);
req->send(get(), reinterpret_cast<const sockaddr *>(&addr));
req->send(get(), &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 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.
*/
template<typename I = IPv4>
void send(std::string ip, unsigned int port, std::unique_ptr<char[]> data, unsigned int len) {
typename details::IpTraits<I>::Type addr;
details::IpTraits<I>::addrFunc(ip.data(), port, &addr);
send(reinterpret_cast<const sockaddr &>(addr), std::move(data), len);
}
/**
@ -332,7 +371,39 @@ public:
*/
template<typename I = IPv4>
void send(Addr addr, std::unique_ptr<char[]> data, unsigned int len) {
send<I>(addr.ip, addr.port, std::move(data), len);
send<I>(std::move(addr.ip), addr.port, std::move(data), len);
}
/**
* @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 Initialized `sockaddr_in` or `sockaddr_in6` data structure.
* @param data The data to be sent.
* @param len The lenght of the submitted data.
*/
void send(const sockaddr &addr, char *data, unsigned int len) {
auto req = loop().resource<details::SendReq>(
std::unique_ptr<char[], details::SendReq::Deleter>{
data, [](char *) {}
}, len);
auto listener = [ptr = shared_from_this()](const auto &event, const auto &) {
ptr->publish(event);
};
req->once<ErrorEvent>(listener);
req->once<SendEvent>(listener);
req->send(get(), &addr);
}
/**
@ -357,19 +428,7 @@ public:
void send(std::string ip, unsigned int port, char *data, unsigned int len) {
typename details::IpTraits<I>::Type addr;
details::IpTraits<I>::addrFunc(ip.data(), port, &addr);
auto req = loop().resource<details::SendReq>(
std::unique_ptr<char[], details::SendReq::Deleter>{
data, [](char *) {}
}, len);
auto listener = [ptr = shared_from_this()](const auto &event, const auto &) {
ptr->publish(event);
};
req->once<ErrorEvent>(listener);
req->once<SendEvent>(listener);
req->send(get(), reinterpret_cast<const sockaddr *>(&addr));
send(reinterpret_cast<const sockaddr &>(addr), data, len);
}
/**
@ -391,7 +450,31 @@ public:
*/
template<typename I = IPv4>
void send(Addr addr, char *data, unsigned int len) {
send<I>(addr.ip, addr.port, data, len);
send<I>(std::move(addr.ip), addr.port, 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 addr Initialized `sockaddr_in` or `sockaddr_in6` data structure.
* @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(const sockaddr &addr, std::unique_ptr<char[]> data, unsigned int len) {
uv_buf_t bufs[] = { uv_buf_init(data.get(), len) };
auto bw = uv_udp_try_send(get(), bufs, 1, &addr);
if(bw < 0) {
publish(ErrorEvent{bw});
bw = 0;
}
return bw;
}
/**
@ -410,16 +493,7 @@ public:
int trySend(std::string ip, unsigned int port, std::unique_ptr<char[]> data, unsigned int len) {
typename details::IpTraits<I>::Type addr;
details::IpTraits<I>::addrFunc(ip.data(), port, &addr);
uv_buf_t bufs[] = { uv_buf_init(data.get(), 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;
return trySend(reinterpret_cast<const sockaddr &>(addr), std::move(data), len);
}
/**
@ -435,7 +509,31 @@ public:
*/
template<typename I = IPv4>
int trySend(Addr addr, std::unique_ptr<char[]> data, unsigned int len) {
return trySend<I>(addr.ip, addr.port, std::move(data), len);
return trySend<I>(std::move(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 addr Initialized `sockaddr_in` or `sockaddr_in6` data structure.
* @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(const sockaddr &addr, char *data, unsigned int len) {
uv_buf_t bufs[] = { uv_buf_init(data, len) };
auto bw = uv_udp_try_send(get(), bufs, 1, &addr);
if(bw < 0) {
publish(ErrorEvent{bw});
bw = 0;
}
return bw;
}
/**
@ -454,16 +552,7 @@ public:
int trySend(std::string ip, unsigned int port, char *data, unsigned int 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;
return trySend(reinterpret_cast<const sockaddr &>(addr), data, len);
}
/**
@ -479,7 +568,7 @@ public:
*/
template<typename I = IPv4>
int trySend(Addr addr, char *data, unsigned int len) {
return trySend<I>(addr.ip, addr.port, data, len);
return trySend<I>(std::move(addr.ip), addr.port, data, len);
}
/**