diff --git a/wpiutil/src/main/native/cpp/uv/Udp.cpp b/wpiutil/src/main/native/cpp/uv/Udp.cpp index cc7208d1b4..2c0d29fb06 100644 --- a/wpiutil/src/main/native/cpp/uv/Udp.cpp +++ b/wpiutil/src/main/native/cpp/uv/Udp.cpp @@ -1,5 +1,5 @@ /*----------------------------------------------------------------------------*/ -/* Copyright (c) 2018 FIRST. All Rights Reserved. */ +/* Copyright (c) 2018-2019 FIRST. All Rights Reserved. */ /* Open Source Software - may be modified and shared by FRC teams. The code */ /* must be accompanied by the FIRST BSD license file in the root directory of */ /* the project. */ @@ -69,6 +69,33 @@ void Udp::Bind6(const Twine& ip, unsigned int port, unsigned int flags) { Bind(reinterpret_cast(addr), flags); } +void Udp::Connect(const Twine& ip, unsigned int port) { + sockaddr_in addr; + int err = NameToAddr(ip, port, &addr); + if (err < 0) + ReportError(err); + else + Connect(reinterpret_cast(addr)); +} + +void Udp::Connect6(const Twine& ip, unsigned int port) { + sockaddr_in6 addr; + int err = NameToAddr(ip, port, &addr); + if (err < 0) + ReportError(err); + else + Connect(reinterpret_cast(addr)); +} + +sockaddr_storage Udp::GetPeer() { + sockaddr_storage name; + int len = sizeof(name); + if (!Invoke(&uv_udp_getpeername, GetRaw(), reinterpret_cast(&name), + &len)) + std::memset(&name, 0, sizeof(name)); + return name; +} + sockaddr_storage Udp::GetSock() { sockaddr_storage name; int len = sizeof(name); @@ -111,6 +138,22 @@ void Udp::Send(const sockaddr& addr, ArrayRef bufs, Send(addr, bufs, std::make_shared(bufs, callback)); } +void Udp::Send(ArrayRef bufs, const std::shared_ptr& req) { + if (Invoke(&uv_udp_send, req->GetRaw(), GetRaw(), bufs.data(), bufs.size(), + nullptr, [](uv_udp_send_t* r, int status) { + auto& h = *static_cast(r->data); + if (status < 0) h.ReportError(status); + h.complete(Error(status)); + h.Release(); // this is always a one-shot + })) + req->Keep(); +} + +void Udp::Send(ArrayRef bufs, + std::function, Error)> callback) { + Send(bufs, std::make_shared(bufs, callback)); +} + void Udp::StartRecv() { Invoke(&uv_udp_recv_start, GetRaw(), &AllocBuf, [](uv_udp_t* handle, ssize_t nread, const uv_buf_t* buf, diff --git a/wpiutil/src/main/native/include/wpi/uv/Udp.h b/wpiutil/src/main/native/include/wpi/uv/Udp.h index f27ab5fa43..2544c50276 100644 --- a/wpiutil/src/main/native/include/wpi/uv/Udp.h +++ b/wpiutil/src/main/native/include/wpi/uv/Udp.h @@ -115,6 +115,49 @@ class Udp final : public HandleImpl { */ void Bind6(const Twine& ip, unsigned int port, unsigned int flags = 0); + /** + * Associate the handle to a remote address and port, so every message sent + * by this handle is automatically sent to that destination. + * + * @param addr Initialized `sockaddr_in` or `sockaddr_in6` data structure. + */ + void Connect(const sockaddr& addr) { + Invoke(&uv_udp_connect, GetRaw(), &addr); + } + + void Connect(const sockaddr_in& addr) { + Connect(reinterpret_cast(addr)); + } + + void Connect(const sockaddr_in6& addr) { + Connect(reinterpret_cast(addr)); + } + + /** + * Associate the handle to an IPv4 address and port, so every message sent + * by this handle is automatically sent to that destination. + * + * @param ip The address to which to bind. + * @param port The port to which to bind. + */ + void Connect(const Twine& ip, unsigned int port); + + /** + * Associate the handle to an IPv6 address and port, so every message sent + * by this handle is automatically sent to that destination. + * + * @param ip The address to which to bind. + * @param port The port to which to bind. + * @param flags Optional additional flags. + */ + void Connect6(const Twine& ip, unsigned int port); + + /** + * Get the remote IP and port on connected UDP handles. + * @return The address (will be zeroed if an error occurred). + */ + sockaddr_storage GetPeer(); + /** * Get the current address to which the handle is bound. * @return The address (will be zeroed if an error occurred). @@ -204,6 +247,15 @@ class Udp final : public HandleImpl { Send(reinterpret_cast(addr), bufs, req); } + /** + * Variant of Send() for connected sockets. Cannot be used with + * connectionless sockets. + * + * @param bufs The buffers to be written to the stream. + * @param req write request + */ + void Send(ArrayRef bufs, const std::shared_ptr& req); + /** * Send data over the UDP socket. If the socket has not previously been bound * with Bind() it will be bound to 0.0.0.0 (the "all interfaces" IPv4 address) @@ -234,6 +286,16 @@ class Udp final : public HandleImpl { Send(reinterpret_cast(addr), bufs, callback); } + /** + * Variant of Send() for connected sockets. Cannot be used with + * connectionless sockets. + * + * @param bufs The buffers to be written to the stream. + * @param callback Callback function to call when the data has been sent. + */ + void Send(ArrayRef bufs, + std::function, Error)> callback); + /** * Same as Send(), but won't queue a send request if it can't be completed * immediately. @@ -261,6 +323,23 @@ class Udp final : public HandleImpl { return TrySend(reinterpret_cast(addr), bufs); } + /** + * Variant of TrySend() for connected sockets. Cannot be used with + * connectionless sockets. + * + * @param bufs The buffers to be written to the stream. + * @return Number of bytes sent. + */ + int TrySend(ArrayRef bufs) { + int val = uv_udp_try_send(GetRaw(), bufs.data(), + static_cast(bufs.size()), nullptr); + if (val < 0) { + this->ReportError(val); + return 0; + } + return val; + } + /** * Prepare for receiving data. If the socket has not previously been bound * with Bind() it is bound to 0.0.0.0 (the "all interfaces" IPv4 address) and