Merge pull request #23 from cynnyx/master
Added a bunch of functionalities
This commit is contained in:
commit
e506cbdfbb
13
README.md
13
README.md
@ -26,7 +26,7 @@ void listen(uvw::Loop &loop) {
|
||||
client->read();
|
||||
});
|
||||
|
||||
tcp->bind<uvw::Tcp::IPv4>("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<uvw::Tcp::IPv4>(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<uvw::ListenEvent>([](const uvw::ListenEvent &event, uvw::Tcp &srv) mutab
|
||||
client->read();
|
||||
});
|
||||
|
||||
tcp->bind<uvw::Tcp::IPv4>("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<uvw::Tcp::IPv4>("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
|
||||
|
||||
|
||||
@ -39,6 +39,22 @@ class Handle: public BaseHandle, public Resource<T>
|
||||
ref.publish(CloseEvent{});
|
||||
}
|
||||
|
||||
template<typename F>
|
||||
int setBufferSize(F &&f) {
|
||||
int value = 0;
|
||||
|
||||
if(0 != invoke(std::forward<F>(f), this->template get<uv_handle_t>(), &value)) {
|
||||
value = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
template<typename F>
|
||||
void getBufferSize(F &&f, int value) {
|
||||
invoke(&std::forward<F>(f), this->template get<uv_handle_t>(), &value);
|
||||
}
|
||||
|
||||
protected:
|
||||
using Resource<T>::Resource;
|
||||
|
||||
@ -91,6 +107,28 @@ public:
|
||||
std::size_t size() const noexcept {
|
||||
return uv_handle_size(this->template get<uv_handle_t>()->type);
|
||||
}
|
||||
|
||||
int sendBufferSize() const {
|
||||
return setBufferSize(&uv_send_buffer_size);
|
||||
}
|
||||
|
||||
void sendBufferSize(int value) {
|
||||
getBufferSize(&uv_send_buffer_size, value);
|
||||
}
|
||||
|
||||
int recvBufferSize() const {
|
||||
return setBufferSize(&uv_recv_buffer_size);
|
||||
}
|
||||
|
||||
void recvBufferSize(int value) {
|
||||
getBufferSize(&uv_recv_buffer_size, value);
|
||||
}
|
||||
|
||||
OSFileDescriptor fileno() const {
|
||||
uv_os_fd_t fd;
|
||||
invoke(&uv_fileno, this->template get<uv_handle_t>(), &fd);
|
||||
return fd;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
@ -5,6 +5,7 @@
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
#include <type_traits>
|
||||
#include <chrono>
|
||||
#include <uv.h>
|
||||
#include "emitter.hpp"
|
||||
#include "util.hpp"
|
||||
@ -35,6 +36,12 @@ class Loop final: public Emitter<Loop>, public std::enable_shared_from_this<Loop
|
||||
{ }
|
||||
|
||||
public:
|
||||
using Time = std::chrono::milliseconds;
|
||||
|
||||
enum class Configure: std::underlying_type_t<uv_loop_option> {
|
||||
BLOCK_SIGNAL = UV_LOOP_BLOCK_SIGNAL
|
||||
};
|
||||
|
||||
static std::shared_ptr<Loop> create() {
|
||||
auto ptr = std::unique_ptr<uv_loop_t, Deleter>{new uv_loop_t, [](uv_loop_t *l){ delete l; }};
|
||||
auto loop = std::shared_ptr<Loop>(new Loop{std::move(ptr)});
|
||||
@ -77,6 +84,12 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
void configure(Configure flag, Args... args) {
|
||||
auto err = uv_loop_configure(loop.get(), static_cast<std::underlying_type_t<Configure>>(flag), std::forward<Args>(args)...);
|
||||
if(err) { publish(ErrorEvent{err}); }
|
||||
}
|
||||
|
||||
template<typename R, typename... Args>
|
||||
std::enable_if_t<std::is_base_of<BaseHandle, R>::value, std::shared_ptr<R>>
|
||||
resource(Args&&... args) {
|
||||
@ -116,6 +129,22 @@ public:
|
||||
uv_stop(loop.get());
|
||||
}
|
||||
|
||||
int descriptor() const noexcept {
|
||||
return uv_backend_fd(loop.get());
|
||||
}
|
||||
|
||||
Time timeout() const noexcept {
|
||||
return Time{uv_backend_timeout(loop.get())};
|
||||
}
|
||||
|
||||
Time now() const noexcept {
|
||||
return Time{uv_now(loop.get())};
|
||||
}
|
||||
|
||||
void update() const noexcept {
|
||||
return uv_update_time(loop.get());
|
||||
}
|
||||
|
||||
void walk(std::function<void(BaseHandle &)> callback) {
|
||||
// remember: non-capturing lambdas decay to pointers to functions
|
||||
uv_walk(loop.get(), [](uv_handle_t *handle, void *func) {
|
||||
|
||||
@ -28,6 +28,8 @@ public:
|
||||
|
||||
bool init(bool ipc = false) { return initialize<uv_pipe_t>(&uv_pipe_init, ipc); }
|
||||
|
||||
// TODO uv_pipe_open
|
||||
|
||||
void bind(std::string name) {
|
||||
invoke(&uv_pipe_bind, get<uv_pipe_t>(), name.data());
|
||||
}
|
||||
|
||||
@ -36,7 +36,7 @@ public:
|
||||
return std::shared_ptr<Poll>{new Poll{std::forward<Args>(args)...}};
|
||||
}
|
||||
|
||||
bool init(FileDescriptor fd) { return initialize<uv_poll_t>(&uv_poll_init, static_cast<FileDescriptor::Type>(fd)); }
|
||||
bool init(int fd) { return initialize<uv_poll_t>(&uv_poll_init, fd); }
|
||||
|
||||
void start(Flags<Event> flags) { invoke(&uv_poll_start, get<uv_poll_t>(), flags, &startCallback); }
|
||||
void start(Event event) { start(Flags<Event>{event}); }
|
||||
|
||||
@ -42,18 +42,18 @@ class Request: public Resource<T> {
|
||||
protected:
|
||||
using Resource<T>::Resource;
|
||||
|
||||
template<typename R, typename E, typename F, typename... A>
|
||||
auto exec(F &&f, A&&... args)
|
||||
-> std::enable_if_t<not std::is_void<std::result_of_t<F(A..., decltype(&execCallback<R, E>))>>::value, int> {
|
||||
auto ret = this->invoke(std::forward<F>(f), std::forward<A>(args)..., &execCallback<R, E>);
|
||||
template<typename R, typename E, typename F, typename... Args>
|
||||
auto exec(F &&f, Args&&... args)
|
||||
-> std::enable_if_t<not std::is_void<std::result_of_t<F(Args..., decltype(&execCallback<R, E>))>>::value, int> {
|
||||
auto ret = this->invoke(std::forward<F>(f), std::forward<Args>(args)..., &execCallback<R, E>);
|
||||
if(0 == ret) { this->leak(); }
|
||||
return ret;
|
||||
}
|
||||
|
||||
template<typename R, typename E, typename F, typename... A>
|
||||
auto exec(F &&f, A&&... args)
|
||||
-> std::enable_if_t<std::is_void<std::result_of_t<F(A..., decltype(&execCallback<R, E>))>>::value> {
|
||||
std::forward<F>(f)(std::forward<A>(args)..., &execCallback<R, E>);
|
||||
template<typename R, typename E, typename F, typename... Args>
|
||||
auto exec(F &&f, Args&&... args)
|
||||
-> std::enable_if_t<std::is_void<std::result_of_t<F(Args..., decltype(&execCallback<R, E>))>>::value> {
|
||||
std::forward<F>(f)(std::forward<Args>(args)..., &execCallback<R, E>);
|
||||
this->leak();
|
||||
}
|
||||
|
||||
|
||||
@ -29,9 +29,9 @@ public:
|
||||
return std::shared_ptr<Connect>{new Connect{std::forward<Args>(args)...}};
|
||||
}
|
||||
|
||||
template<typename F, typename... A>
|
||||
void connect(F &&f, A... args) {
|
||||
exec<uv_connect_t, ConnectEvent>(std::forward<F>(f), get<uv_connect_t>(), std::forward<A>(args)...);
|
||||
template<typename F, typename... Args>
|
||||
void connect(F &&f, Args... args) {
|
||||
exec<uv_connect_t, ConnectEvent>(std::forward<F>(f), get<uv_connect_t>(), std::forward<Args>(args)...);
|
||||
}
|
||||
};
|
||||
|
||||
@ -67,6 +67,10 @@ public:
|
||||
void write(uv_stream_t *handle, const uv_buf_t bufs[], unsigned int nbufs) {
|
||||
exec<uv_write_t, WriteEvent>(&uv_write, get<uv_write_t>(), handle, bufs, nbufs);
|
||||
}
|
||||
|
||||
void write(uv_stream_t *handle, const uv_buf_t bufs[], unsigned int nbufs, uv_stream_t *send) {
|
||||
exec<uv_write_t, WriteEvent>(&uv_write2, get<uv_write_t>(), handle, bufs, nbufs, send);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -126,7 +130,10 @@ public:
|
||||
listen(DEFAULT_BACKLOG);
|
||||
}
|
||||
|
||||
virtual void accept(T &) = 0;
|
||||
template<typename U>
|
||||
void accept(Stream<U> &ref) {
|
||||
this->invoke(&uv_accept, this->template get<uv_stream_t>(), ref.template get<uv_stream_t>());
|
||||
}
|
||||
|
||||
void read() {
|
||||
this->invoke(&uv_read_start, this->template get<uv_stream_t>(), &this->allocCallback, &readCallback);
|
||||
@ -153,6 +160,25 @@ public:
|
||||
write(data.get(), len);
|
||||
}
|
||||
|
||||
template<typename U>
|
||||
void write(Stream<U> &send, char *data, ssize_t len) {
|
||||
uv_buf_t bufs[] = { uv_buf_init(data, len) };
|
||||
|
||||
auto listener = [ptr = this->shared_from_this()](const auto &event, details::Write &) {
|
||||
ptr->publish(event);
|
||||
};
|
||||
|
||||
auto write = this->loop().template resource<details::Write>();
|
||||
write->template once<ErrorEvent>(listener);
|
||||
write->template once<WriteEvent>(listener);
|
||||
write->write(this->template get<uv_stream_t>(), bufs, 1, send.template get<uv_stream_t>());
|
||||
}
|
||||
|
||||
template<typename U>
|
||||
void write(Stream<U> &send, std::unique_ptr<char[]> data, ssize_t len) {
|
||||
write(send, data.get(), len);
|
||||
}
|
||||
|
||||
int tryWrite(char *data, ssize_t len) {
|
||||
uv_buf_t bufs[] = { uv_buf_init(data, len) };
|
||||
auto bw = uv_try_write(this->template get<uv_stream_t>(), bufs, 1);
|
||||
@ -176,6 +202,10 @@ public:
|
||||
bool writable() const noexcept {
|
||||
return (uv_is_writable(this->template get<uv_stream_t>()) == 1);
|
||||
}
|
||||
|
||||
void blocking(bool enable = false) {
|
||||
this->invoke(&uv_stream_set_blocking, this->template get<uv_stream_t>(), enable);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
@ -17,23 +17,8 @@ namespace uvw {
|
||||
|
||||
|
||||
class Tcp final: public Stream<Tcp> {
|
||||
using SockFunctionType = Addr(*)(const Tcp &);
|
||||
using PeerFunctionType = SockFunctionType;
|
||||
|
||||
template<typename I>
|
||||
static Addr tSock(const Tcp &tcp) noexcept {
|
||||
return details::address<I>(uv_tcp_getsockname, tcp.get<uv_tcp_t>());
|
||||
}
|
||||
|
||||
template<typename I>
|
||||
static Addr tPeer(const Tcp &tcp) noexcept {
|
||||
return details::address<I>(uv_tcp_getpeername, tcp.get<uv_tcp_t>());
|
||||
}
|
||||
|
||||
explicit Tcp(std::shared_ptr<Loop> ref)
|
||||
: Stream{HandleType<uv_tcp_t>{}, std::move(ref)},
|
||||
sockF{&tSock<details::IPv4>},
|
||||
peerF{&tPeer<details::IPv4>}
|
||||
: Stream{HandleType<uv_tcp_t>{}, std::move(ref)}
|
||||
{ }
|
||||
|
||||
public:
|
||||
@ -53,6 +38,15 @@ public:
|
||||
|
||||
bool init() { return initialize<uv_tcp_t>(&uv_tcp_init); }
|
||||
|
||||
template<typename T, typename... Args>
|
||||
bool init(T&& t, Args&&... args) {
|
||||
return initialize<uv_tcp_t>(&uv_tcp_init_ex, std::forward<T>(t), std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
void open(OSSocketHandle sock) {
|
||||
invoke(&uv_tcp_open, get<uv_tcp_t>(), sock);
|
||||
}
|
||||
|
||||
void noDelay(bool value = false) {
|
||||
invoke(&uv_tcp_nodelay, get<uv_tcp_t>(), value);
|
||||
}
|
||||
@ -61,33 +55,38 @@ public:
|
||||
invoke(&uv_tcp_keepalive, get<uv_tcp_t>(), enable, time.count());
|
||||
}
|
||||
|
||||
template<typename I, typename..., typename Traits = details::IpTraits<I>>
|
||||
void bind(std::string ip, unsigned int port, Flags<Bind> flags = Flags<Bind>{}) {
|
||||
typename Traits::Type addr;
|
||||
Traits::AddrFunc(ip.data(), port, &addr);
|
||||
|
||||
if(0 == invoke(&uv_tcp_bind, get<uv_tcp_t>(), reinterpret_cast<const sockaddr *>(&addr), flags)) {
|
||||
sockF = &tSock<I>;
|
||||
peerF = &tPeer<I>;
|
||||
}
|
||||
void simultaneousAccepts(bool enable = true) {
|
||||
invoke(&uv_tcp_simultaneous_accepts, get<uv_tcp_t>(), enable);
|
||||
}
|
||||
|
||||
template<typename I, typename..., typename Traits = details::IpTraits<I>>
|
||||
template<typename I = IPv4>
|
||||
void bind(std::string ip, unsigned int port, Flags<Bind> flags = Flags<Bind>{}) {
|
||||
typename details::IpTraits<I>::Type addr;
|
||||
details::IpTraits<I>::AddrFunc(ip.data(), port, &addr);
|
||||
invoke(&uv_tcp_bind, get<uv_tcp_t>(), reinterpret_cast<const sockaddr *>(&addr), flags);
|
||||
}
|
||||
|
||||
template<typename I = IPv4>
|
||||
void bind(Addr addr, Flags<Bind> flags = Flags<Bind>{}) {
|
||||
bind<I>(addr.ip, addr.port, flags);
|
||||
}
|
||||
|
||||
Addr sock() const noexcept { return sockF(*this); }
|
||||
Addr peer() const noexcept { return peerF(*this); }
|
||||
template<typename I = IPv4>
|
||||
Addr sock() const noexcept {
|
||||
return details::address<I>(&uv_tcp_getsockname, get<uv_tcp_t>());
|
||||
}
|
||||
|
||||
template<typename I, typename..., typename Traits = details::IpTraits<I>>
|
||||
template<typename I = IPv4>
|
||||
Addr peer() const noexcept {
|
||||
return details::address<I>(&uv_tcp_getpeername, get<uv_tcp_t>());
|
||||
}
|
||||
|
||||
template<typename I = IPv4>
|
||||
void connect(std::string ip, unsigned int port) {
|
||||
typename Traits::Type addr;
|
||||
Traits::AddrFunc(ip.data(), port, &addr);
|
||||
typename details::IpTraits<I>::Type addr;
|
||||
details::IpTraits<I>::AddrFunc(ip.data(), port, &addr);
|
||||
|
||||
auto listener = [ptr = this->shared_from_this()](const auto &event, details::Connect &) {
|
||||
ptr->sockF = &tSock<I>;
|
||||
ptr->peerF = &tPeer<I>;
|
||||
ptr->publish(event);
|
||||
};
|
||||
|
||||
@ -97,19 +96,8 @@ public:
|
||||
connect->connect(&uv_tcp_connect, get<uv_tcp_t>(), reinterpret_cast<const sockaddr *>(&addr));
|
||||
}
|
||||
|
||||
template<typename I, typename..., typename Traits = details::IpTraits<I>>
|
||||
template<typename I = IPv4>
|
||||
void connect(Addr addr) { connect<I>(addr.ip, addr.port); }
|
||||
|
||||
void accept(Tcp &tcp) override {
|
||||
if(0 == invoke(&uv_accept, get<uv_stream_t>(), tcp.get<uv_stream_t>())) {
|
||||
tcp.sockF = sockF;
|
||||
tcp.peerF = peerF;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
SockFunctionType sockF;
|
||||
PeerFunctionType peerF;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@ -15,10 +15,10 @@ namespace uvw {
|
||||
|
||||
class TTY final: public Stream<TTY> {
|
||||
explicit TTY(std::shared_ptr<Loop> ref,
|
||||
FileDescriptor desc,
|
||||
FileHandle desc,
|
||||
bool readable)
|
||||
: Stream{HandleType<uv_tty_t>{}, std::move(ref)},
|
||||
fd{static_cast<FileDescriptor::Type>(desc)},
|
||||
fd{static_cast<FileHandle::Type>(desc)},
|
||||
rw{readable}
|
||||
{ }
|
||||
|
||||
@ -63,7 +63,7 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
FileDescriptor::Type fd;
|
||||
FileHandle::Type fd;
|
||||
int rw;
|
||||
};
|
||||
|
||||
|
||||
105
src/uvw/udp.hpp
105
src/uvw/udp.hpp
@ -39,40 +39,27 @@ public:
|
||||
|
||||
|
||||
class Udp final: public Handle<Udp> {
|
||||
using SockFunctionType = Addr(*)(const Udp &);
|
||||
using PeerFunctionType = Addr(*)(const sockaddr *);
|
||||
|
||||
template<typename I>
|
||||
static Addr tSock(const Udp &udp) noexcept {
|
||||
return details::address<I>(uv_udp_getsockname, udp.get<uv_udp_t>());
|
||||
}
|
||||
|
||||
template<typename I, typename..., typename Traits = details::IpTraits<I>>
|
||||
static Addr tPeer(const sockaddr *addr) noexcept {
|
||||
const typename Traits::Type *aptr = reinterpret_cast<const typename Traits::Type *>(addr);
|
||||
int len = sizeof(*addr);
|
||||
return details::address<I>(aptr, len);
|
||||
}
|
||||
|
||||
explicit Udp(std::shared_ptr<Loop> ref)
|
||||
: Handle{HandleType<uv_udp_t>{}, std::move(ref)},
|
||||
sockF{&tSock<details::IPv4>},
|
||||
peerF{&tPeer<details::IPv4>}
|
||||
: Handle{HandleType<uv_udp_t>{}, std::move(ref)}
|
||||
{ }
|
||||
|
||||
template<typename I>
|
||||
static void recvCallback(uv_udp_t *handle, ssize_t nread, const uv_buf_t *buf, const sockaddr *addr, unsigned flags) {
|
||||
typename details::IpTraits<I>::Type *aptr = reinterpret_cast<const typename details::IpTraits<I>::Type *>(addr);
|
||||
int len = sizeof(*addr);
|
||||
|
||||
Udp &udp = *(static_cast<Udp*>(handle->data));
|
||||
// data will be destroyed no matter of what the value of nread is
|
||||
std::unique_ptr<const char[]> 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<I>(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<I>(aptr, len), std::move(data), nread, false});
|
||||
} else {
|
||||
// transmission error
|
||||
udp.publish(ErrorEvent(nread));
|
||||
@ -100,30 +87,35 @@ public:
|
||||
|
||||
bool init() { return initialize<uv_udp_t>(&uv_udp_init); }
|
||||
|
||||
template<typename I, typename..., typename Traits = details::IpTraits<I>>
|
||||
void bind(std::string ip, unsigned int port, Flags<Bind> flags = Flags<Bind>{}) {
|
||||
typename Traits::Type addr;
|
||||
Traits::AddrFunc(ip.data(), port, &addr);
|
||||
|
||||
if(0 == invoke(&uv_udp_bind, get<uv_udp_t>(), reinterpret_cast<const sockaddr *>(&addr), flags)) {
|
||||
sockF = &tSock<I>;
|
||||
peerF = &tPeer<I>;
|
||||
}
|
||||
template<typename T, typename... Args>
|
||||
bool init(T&& t, Args&&... args) {
|
||||
return initialize<uv_udp_t>(&uv_udp_init_ex, std::forward<T>(t), std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template<typename I, typename..., typename Traits = details::IpTraits<I>>
|
||||
void open(OSSocketHandle sock) {
|
||||
invoke(&uv_udp_open, get<uv_udp_t>(), sock);
|
||||
}
|
||||
|
||||
template<typename I = IPv4>
|
||||
void bind(std::string ip, unsigned int port, Flags<Bind> flags = Flags<Bind>{}) {
|
||||
typename details::IpTraits<I>::Type addr;
|
||||
details::IpTraits<I>::AddrFunc(ip.data(), port, &addr);
|
||||
invoke(&uv_udp_bind, get<uv_udp_t>(), reinterpret_cast<const sockaddr *>(&addr), flags);
|
||||
}
|
||||
|
||||
template<typename I = IPv4>
|
||||
void bind(Addr addr, Flags<Bind> flags = Flags<Bind>{}) {
|
||||
bind<I>(addr.ip, addr.port, flags);
|
||||
}
|
||||
|
||||
Addr sock() const noexcept { return sockF(*this); }
|
||||
template<typename I = IPv4>
|
||||
Addr sock() const noexcept {
|
||||
return details::address<I>(&uv_udp_getsockname, get<uv_udp_t>());
|
||||
}
|
||||
|
||||
template<typename I>
|
||||
template<typename I = IPv4>
|
||||
void multicastMembership(std::string multicast, std::string interface, Membership membership) {
|
||||
if(0 == invoke(&uv_udp_set_membership, get<uv_udp_t>(), multicast.data(), interface.data(), static_cast<uv_membership>(membership))) {
|
||||
sockF = &tSock<I>;
|
||||
peerF = &tPeer<I>;
|
||||
}
|
||||
invoke(&uv_udp_set_membership, get<uv_udp_t>(), multicast.data(), interface.data(), static_cast<uv_membership>(membership));
|
||||
}
|
||||
|
||||
void multicastLoop(bool enable = true) {
|
||||
@ -134,27 +126,22 @@ public:
|
||||
invoke(&uv_udp_set_multicast_ttl, get<uv_udp_t>(), val > 255 ? 255 : val);
|
||||
}
|
||||
|
||||
template<typename I>
|
||||
template<typename I = IPv4>
|
||||
void multicastInterface(std::string interface) {
|
||||
if(0 == invoke(&uv_udp_set_multicast_interface, get<uv_udp_t>(), interface.data())) {
|
||||
sockF = &tSock<I>;
|
||||
peerF = &tPeer<I>;
|
||||
}
|
||||
invoke(&uv_udp_set_multicast_interface, get<uv_udp_t>(), interface.data());
|
||||
}
|
||||
|
||||
void broadcast(bool enable = false) { invoke(&uv_udp_set_broadcast, get<uv_udp_t>(), enable); }
|
||||
void ttl(int val) { invoke(&uv_udp_set_ttl, get<uv_udp_t>(), val > 255 ? 255 : val); }
|
||||
|
||||
template<typename I, typename..., typename Traits = details::IpTraits<I>>
|
||||
template<typename I = IPv4>
|
||||
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<I>::Type addr;
|
||||
details::IpTraits<I>::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<I>;
|
||||
ptr->peerF = &tPeer<I>;
|
||||
ptr->publish(event);
|
||||
};
|
||||
|
||||
@ -162,20 +149,17 @@ public:
|
||||
send->once<ErrorEvent>(listener);
|
||||
send->once<SendEvent>(listener);
|
||||
send->send(get<uv_udp_t>(), bufs, 1, reinterpret_cast<const sockaddr *>(&addr));
|
||||
|
||||
sockF = &tSock<I>;
|
||||
peerF = &tPeer<I>;
|
||||
}
|
||||
|
||||
template<typename I, typename..., typename Traits = details::IpTraits<I>>
|
||||
template<typename I = IPv4>
|
||||
void send(std::string ip, unsigned int port, std::unique_ptr<char[]> data, ssize_t len) {
|
||||
send<I>(ip, port, data.get(), len);
|
||||
}
|
||||
|
||||
template<typename I, typename..., typename Traits = details::IpTraits<I>>
|
||||
template<typename I = IPv4>
|
||||
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<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<uv_udp_t>(), bufs, 1, reinterpret_cast<const sockaddr *>(&addr));
|
||||
@ -183,25 +167,22 @@ public:
|
||||
if(bw < 0) {
|
||||
this->publish(ErrorEvent{bw});
|
||||
bw = 0;
|
||||
} else {
|
||||
sockF = &tSock<I>;
|
||||
peerF = &tPeer<I>;
|
||||
}
|
||||
|
||||
return bw;
|
||||
}
|
||||
|
||||
template<typename I, typename..., typename Traits = details::IpTraits<I>>
|
||||
template<typename I = IPv4>
|
||||
int trySend(std::string ip, unsigned int port, std::unique_ptr<char[]> data, ssize_t len) {
|
||||
return trySend<I>(ip, port, data.get(), len);
|
||||
}
|
||||
|
||||
void recv() { invoke(&uv_udp_recv_start, get<uv_udp_t>(), &allocCallback, &recvCallback); }
|
||||
void stop() { invoke(&uv_udp_recv_stop, get<uv_udp_t>()); }
|
||||
template<typename I = IPv4>
|
||||
void recv() {
|
||||
invoke(&uv_udp_recv_start, get<uv_udp_t>(), &allocCallback, &recvCallback<I>);
|
||||
}
|
||||
|
||||
private:
|
||||
SockFunctionType sockF;
|
||||
PeerFunctionType peerF;
|
||||
void stop() { invoke(&uv_udp_recv_stop, get<uv_udp_t>()); }
|
||||
};
|
||||
|
||||
|
||||
|
||||
@ -44,21 +44,24 @@ private:
|
||||
};
|
||||
|
||||
|
||||
struct FileDescriptor {
|
||||
using Type = uv_file;
|
||||
|
||||
constexpr FileDescriptor(Type desc): fd{desc} { }
|
||||
|
||||
constexpr operator Type() const noexcept { return fd; }
|
||||
|
||||
template<typename T>
|
||||
struct UVTypeWrapper {
|
||||
using Type = T;
|
||||
constexpr UVTypeWrapper(Type val): value{val} { }
|
||||
constexpr operator Type() const noexcept { return value; }
|
||||
private:
|
||||
const Type fd;
|
||||
const Type value;
|
||||
};
|
||||
|
||||
|
||||
static constexpr auto STDIN = FileDescriptor{0};
|
||||
static constexpr auto STDOUT = FileDescriptor{1};
|
||||
static constexpr auto STDERR = FileDescriptor{2};
|
||||
using FileHandle = UVTypeWrapper<uv_file>;
|
||||
using OSSocketHandle = UVTypeWrapper<uv_os_sock_t>;
|
||||
using OSFileDescriptor = UVTypeWrapper<uv_os_fd_t>;
|
||||
|
||||
|
||||
static constexpr auto STDIN = FileHandle{0};
|
||||
static constexpr auto STDOUT = FileHandle{1};
|
||||
static constexpr auto STDERR = FileHandle{2};
|
||||
|
||||
|
||||
/**
|
||||
@ -107,12 +110,12 @@ const IpTraits<IPv4>::NameFuncType IpTraits<IPv4>::NameFunc = &uv_ip4_name;
|
||||
const IpTraits<IPv6>::NameFuncType IpTraits<IPv6>::NameFunc = &uv_ip6_name;
|
||||
|
||||
|
||||
template<typename I, typename..., typename Traits = details::IpTraits<I>>
|
||||
Addr address(const typename Traits::Type *aptr, int len) noexcept {
|
||||
template<typename I>
|
||||
Addr address(const typename details::IpTraits<I>::Type *aptr, int len) noexcept {
|
||||
std::pair<std::string, unsigned int> addr{};
|
||||
char name[len];
|
||||
|
||||
int err = Traits::NameFunc(aptr, name, len);
|
||||
int err = details::IpTraits<I>::NameFunc(aptr, name, len);
|
||||
|
||||
if(0 == err) {
|
||||
addr = { std::string{name}, ntohs(aptr->sin_port) };
|
||||
@ -126,7 +129,7 @@ Addr address(const typename Traits::Type *aptr, int len) noexcept {
|
||||
}
|
||||
|
||||
|
||||
template<typename I, typename F, typename H, typename..., typename Traits = details::IpTraits<I>>
|
||||
template<typename I, typename F, typename H>
|
||||
Addr address(F &&f, const H *handle) noexcept {
|
||||
sockaddr_storage ssto;
|
||||
int len = sizeof(ssto);
|
||||
@ -135,7 +138,7 @@ Addr address(F &&f, const H *handle) noexcept {
|
||||
int err = std::forward<F>(f)(handle, reinterpret_cast<sockaddr *>(&ssto), &len);
|
||||
|
||||
if(0 == err) {
|
||||
typename Traits::Type *aptr = reinterpret_cast<typename Traits::Type *>(&ssto);
|
||||
typename details::IpTraits<I>::Type *aptr = reinterpret_cast<typename details::IpTraits<I>::Type *>(&ssto);
|
||||
addr = address<I>(aptr, len);
|
||||
}
|
||||
|
||||
|
||||
@ -56,7 +56,7 @@ void listen(uvw::Loop &loop) {
|
||||
std::cout << "close" << std::endl;
|
||||
});
|
||||
|
||||
tcp->bind<uvw::Tcp::IPv4>("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<uvw::Tcp::IPv4>(std::string{"127.0.0.1"}, 4242);
|
||||
tcp->connect(std::string{"127.0.0.1"}, 4242);
|
||||
}
|
||||
|
||||
void g() {
|
||||
|
||||
@ -3,6 +3,8 @@
|
||||
|
||||
|
||||
TEST(Loop, Basics) {
|
||||
// TODO partially done
|
||||
|
||||
auto def = uvw::Loop::getDefault();
|
||||
|
||||
ASSERT_TRUE(static_cast<bool>(def));
|
||||
|
||||
Loading…
Reference in New Issue
Block a user