mirror of
https://github.com/wpilibsuite/allwpilib
synced 2026-06-26 01:51:41 +00:00
[wpinet] Move network portions of wpiutil into new wpinet library (#4077)
This commit is contained in:
33
wpinet/src/main/native/cpp/uv/Async.cpp
Normal file
33
wpinet/src/main/native/cpp/uv/Async.cpp
Normal file
@@ -0,0 +1,33 @@
|
||||
// Copyright (c) FIRST and other WPILib contributors.
|
||||
// Open Source Software; you can modify and/or share it under the terms of
|
||||
// the WPILib BSD license file in the root directory of this project.
|
||||
|
||||
#include "wpinet/uv/Async.h"
|
||||
|
||||
#include "wpinet/uv/Loop.h"
|
||||
|
||||
namespace wpi::uv {
|
||||
|
||||
Async<>::~Async() noexcept {
|
||||
if (auto loop = m_loop.lock()) {
|
||||
Close();
|
||||
} else {
|
||||
ForceClosed();
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<Async<>> Async<>::Create(const std::shared_ptr<Loop>& loop) {
|
||||
auto h = std::make_shared<Async>(loop, private_init{});
|
||||
int err = uv_async_init(loop->GetRaw(), h->GetRaw(), [](uv_async_t* handle) {
|
||||
Async& h = *static_cast<Async*>(handle->data);
|
||||
h.wakeup();
|
||||
});
|
||||
if (err < 0) {
|
||||
loop->ReportError(err);
|
||||
return nullptr;
|
||||
}
|
||||
h->Keep();
|
||||
return h;
|
||||
}
|
||||
|
||||
} // namespace wpi::uv
|
||||
29
wpinet/src/main/native/cpp/uv/Check.cpp
Normal file
29
wpinet/src/main/native/cpp/uv/Check.cpp
Normal file
@@ -0,0 +1,29 @@
|
||||
// Copyright (c) FIRST and other WPILib contributors.
|
||||
// Open Source Software; you can modify and/or share it under the terms of
|
||||
// the WPILib BSD license file in the root directory of this project.
|
||||
|
||||
#include "wpinet/uv/Check.h"
|
||||
|
||||
#include "wpinet/uv/Loop.h"
|
||||
|
||||
namespace wpi::uv {
|
||||
|
||||
std::shared_ptr<Check> Check::Create(Loop& loop) {
|
||||
auto h = std::make_shared<Check>(private_init{});
|
||||
int err = uv_check_init(loop.GetRaw(), h->GetRaw());
|
||||
if (err < 0) {
|
||||
loop.ReportError(err);
|
||||
return nullptr;
|
||||
}
|
||||
h->Keep();
|
||||
return h;
|
||||
}
|
||||
|
||||
void Check::Start() {
|
||||
Invoke(&uv_check_start, GetRaw(), [](uv_check_t* handle) {
|
||||
Check& h = *static_cast<Check*>(handle->data);
|
||||
h.check();
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace wpi::uv
|
||||
64
wpinet/src/main/native/cpp/uv/FsEvent.cpp
Normal file
64
wpinet/src/main/native/cpp/uv/FsEvent.cpp
Normal file
@@ -0,0 +1,64 @@
|
||||
// Copyright (c) FIRST and other WPILib contributors.
|
||||
// Open Source Software; you can modify and/or share it under the terms of
|
||||
// the WPILib BSD license file in the root directory of this project.
|
||||
|
||||
#include "wpinet/uv/FsEvent.h"
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
#include <wpi/SmallString.h>
|
||||
|
||||
#include "wpinet/uv/Loop.h"
|
||||
|
||||
namespace wpi::uv {
|
||||
|
||||
std::shared_ptr<FsEvent> FsEvent::Create(Loop& loop) {
|
||||
auto h = std::make_shared<FsEvent>(private_init{});
|
||||
int err = uv_fs_event_init(loop.GetRaw(), h->GetRaw());
|
||||
if (err < 0) {
|
||||
loop.ReportError(err);
|
||||
return nullptr;
|
||||
}
|
||||
h->Keep();
|
||||
return h;
|
||||
}
|
||||
|
||||
void FsEvent::Start(std::string_view path, unsigned int flags) {
|
||||
SmallString<128> pathBuf{path};
|
||||
Invoke(
|
||||
&uv_fs_event_start, GetRaw(),
|
||||
[](uv_fs_event_t* handle, const char* filename, int events, int status) {
|
||||
FsEvent& h = *static_cast<FsEvent*>(handle->data);
|
||||
if (status < 0) {
|
||||
h.ReportError(status);
|
||||
} else {
|
||||
h.fsEvent(filename, events);
|
||||
}
|
||||
},
|
||||
pathBuf.c_str(), flags);
|
||||
}
|
||||
|
||||
std::string FsEvent::GetPath() {
|
||||
// Per the libuv docs, GetPath() always gives us a null-terminated string.
|
||||
// common case should be small
|
||||
char buf[128];
|
||||
size_t size = 128;
|
||||
int r = uv_fs_event_getpath(GetRaw(), buf, &size);
|
||||
if (r == 0) {
|
||||
return buf;
|
||||
} else if (r == UV_ENOBUFS) {
|
||||
// need to allocate a big enough buffer
|
||||
char* buf2 = static_cast<char*>(std::malloc(size));
|
||||
r = uv_fs_event_getpath(GetRaw(), buf2, &size);
|
||||
if (r == 0) {
|
||||
std::string out{buf2};
|
||||
std::free(buf2);
|
||||
return out;
|
||||
}
|
||||
std::free(buf2);
|
||||
}
|
||||
ReportError(r);
|
||||
return std::string{};
|
||||
}
|
||||
|
||||
} // namespace wpi::uv
|
||||
52
wpinet/src/main/native/cpp/uv/GetAddrInfo.cpp
Normal file
52
wpinet/src/main/native/cpp/uv/GetAddrInfo.cpp
Normal file
@@ -0,0 +1,52 @@
|
||||
// Copyright (c) FIRST and other WPILib contributors.
|
||||
// Open Source Software; you can modify and/or share it under the terms of
|
||||
// the WPILib BSD license file in the root directory of this project.
|
||||
|
||||
#include "wpinet/uv/GetAddrInfo.h"
|
||||
|
||||
#include <wpi/SmallString.h>
|
||||
|
||||
#include "wpinet/uv/Loop.h"
|
||||
#include "wpinet/uv/util.h"
|
||||
|
||||
namespace wpi::uv {
|
||||
|
||||
GetAddrInfoReq::GetAddrInfoReq() {
|
||||
error = [this](Error err) { GetLoop().error(err); };
|
||||
}
|
||||
|
||||
void GetAddrInfo(Loop& loop, const std::shared_ptr<GetAddrInfoReq>& req,
|
||||
std::string_view node, std::string_view service,
|
||||
const addrinfo* hints) {
|
||||
SmallString<128> nodeStr{node};
|
||||
SmallString<128> serviceStr{service};
|
||||
int err = uv_getaddrinfo(
|
||||
loop.GetRaw(), req->GetRaw(),
|
||||
[](uv_getaddrinfo_t* req, int status, addrinfo* res) {
|
||||
auto& h = *static_cast<GetAddrInfoReq*>(req->data);
|
||||
if (status < 0) {
|
||||
h.ReportError(status);
|
||||
} else {
|
||||
h.resolved(*res);
|
||||
}
|
||||
uv_freeaddrinfo(res);
|
||||
h.Release(); // this is always a one-shot
|
||||
},
|
||||
node.empty() ? nullptr : nodeStr.c_str(),
|
||||
service.empty() ? nullptr : serviceStr.c_str(), hints);
|
||||
if (err < 0) {
|
||||
loop.ReportError(err);
|
||||
} else {
|
||||
req->Keep();
|
||||
}
|
||||
}
|
||||
|
||||
void GetAddrInfo(Loop& loop, std::function<void(const addrinfo&)> callback,
|
||||
std::string_view node, std::string_view service,
|
||||
const addrinfo* hints) {
|
||||
auto req = std::make_shared<GetAddrInfoReq>();
|
||||
req->resolved.connect(std::move(callback));
|
||||
GetAddrInfo(loop, req, node, service, hints);
|
||||
}
|
||||
|
||||
} // namespace wpi::uv
|
||||
94
wpinet/src/main/native/cpp/uv/GetNameInfo.cpp
Normal file
94
wpinet/src/main/native/cpp/uv/GetNameInfo.cpp
Normal file
@@ -0,0 +1,94 @@
|
||||
// Copyright (c) FIRST and other WPILib contributors.
|
||||
// Open Source Software; you can modify and/or share it under the terms of
|
||||
// the WPILib BSD license file in the root directory of this project.
|
||||
|
||||
#include "wpinet/uv/GetNameInfo.h"
|
||||
|
||||
#include "wpinet/uv/Loop.h"
|
||||
#include "wpinet/uv/util.h"
|
||||
|
||||
namespace wpi::uv {
|
||||
|
||||
GetNameInfoReq::GetNameInfoReq() {
|
||||
error = [this](Error err) { GetLoop().error(err); };
|
||||
}
|
||||
|
||||
void GetNameInfo(Loop& loop, const std::shared_ptr<GetNameInfoReq>& req,
|
||||
const sockaddr& addr, int flags) {
|
||||
int err = uv_getnameinfo(
|
||||
loop.GetRaw(), req->GetRaw(),
|
||||
[](uv_getnameinfo_t* req, int status, const char* hostname,
|
||||
const char* service) {
|
||||
auto& h = *static_cast<GetNameInfoReq*>(req->data);
|
||||
if (status < 0) {
|
||||
h.ReportError(status);
|
||||
} else {
|
||||
h.resolved(hostname, service);
|
||||
}
|
||||
h.Release(); // this is always a one-shot
|
||||
},
|
||||
&addr, flags);
|
||||
if (err < 0) {
|
||||
loop.ReportError(err);
|
||||
} else {
|
||||
req->Keep();
|
||||
}
|
||||
}
|
||||
|
||||
void GetNameInfo(Loop& loop,
|
||||
std::function<void(const char*, const char*)> callback,
|
||||
const sockaddr& addr, int flags) {
|
||||
auto req = std::make_shared<GetNameInfoReq>();
|
||||
req->resolved.connect(std::move(callback));
|
||||
GetNameInfo(loop, req, addr, flags);
|
||||
}
|
||||
|
||||
void GetNameInfo4(Loop& loop, const std::shared_ptr<GetNameInfoReq>& req,
|
||||
std::string_view ip, unsigned int port, int flags) {
|
||||
sockaddr_in addr;
|
||||
int err = NameToAddr(ip, port, &addr);
|
||||
if (err < 0) {
|
||||
loop.ReportError(err);
|
||||
} else {
|
||||
GetNameInfo(loop, req, reinterpret_cast<const sockaddr&>(addr), flags);
|
||||
}
|
||||
}
|
||||
|
||||
void GetNameInfo4(Loop& loop,
|
||||
std::function<void(const char*, const char*)> callback,
|
||||
std::string_view ip, unsigned int port, int flags) {
|
||||
sockaddr_in addr;
|
||||
int err = NameToAddr(ip, port, &addr);
|
||||
if (err < 0) {
|
||||
loop.ReportError(err);
|
||||
} else {
|
||||
GetNameInfo(loop, std::move(callback),
|
||||
reinterpret_cast<const sockaddr&>(addr), flags);
|
||||
}
|
||||
}
|
||||
|
||||
void GetNameInfo6(Loop& loop, const std::shared_ptr<GetNameInfoReq>& req,
|
||||
std::string_view ip, unsigned int port, int flags) {
|
||||
sockaddr_in6 addr;
|
||||
int err = NameToAddr(ip, port, &addr);
|
||||
if (err < 0) {
|
||||
loop.ReportError(err);
|
||||
} else {
|
||||
GetNameInfo(loop, req, reinterpret_cast<const sockaddr&>(addr), flags);
|
||||
}
|
||||
}
|
||||
|
||||
void GetNameInfo6(Loop& loop,
|
||||
std::function<void(const char*, const char*)> callback,
|
||||
std::string_view ip, unsigned int port, int flags) {
|
||||
sockaddr_in6 addr;
|
||||
int err = NameToAddr(ip, port, &addr);
|
||||
if (err < 0) {
|
||||
loop.ReportError(err);
|
||||
} else {
|
||||
GetNameInfo(loop, std::move(callback),
|
||||
reinterpret_cast<const sockaddr&>(addr), flags);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace wpi::uv
|
||||
35
wpinet/src/main/native/cpp/uv/Handle.cpp
Normal file
35
wpinet/src/main/native/cpp/uv/Handle.cpp
Normal file
@@ -0,0 +1,35 @@
|
||||
// Copyright (c) FIRST and other WPILib contributors.
|
||||
// Open Source Software; you can modify and/or share it under the terms of
|
||||
// the WPILib BSD license file in the root directory of this project.
|
||||
|
||||
#include "wpinet/uv/Handle.h"
|
||||
|
||||
using namespace wpi::uv;
|
||||
|
||||
Handle::~Handle() noexcept {
|
||||
if (!m_closed && m_uv_handle->type != UV_UNKNOWN_HANDLE) {
|
||||
uv_close(m_uv_handle, [](uv_handle_t* uv_handle) { std::free(uv_handle); });
|
||||
} else {
|
||||
std::free(m_uv_handle);
|
||||
}
|
||||
}
|
||||
|
||||
void Handle::Close() noexcept {
|
||||
if (!IsClosing()) {
|
||||
uv_close(m_uv_handle, [](uv_handle_t* handle) {
|
||||
Handle& h = *static_cast<Handle*>(handle->data);
|
||||
h.closed();
|
||||
h.Release(); // free ourselves
|
||||
});
|
||||
m_closed = true;
|
||||
}
|
||||
}
|
||||
|
||||
void Handle::AllocBuf(uv_handle_t* handle, size_t size, uv_buf_t* buf) {
|
||||
auto& h = *static_cast<Handle*>(handle->data);
|
||||
*buf = h.m_allocBuf(size);
|
||||
}
|
||||
|
||||
void Handle::DefaultFreeBuf(Buffer& buf) {
|
||||
buf.Deallocate();
|
||||
}
|
||||
29
wpinet/src/main/native/cpp/uv/Idle.cpp
Normal file
29
wpinet/src/main/native/cpp/uv/Idle.cpp
Normal file
@@ -0,0 +1,29 @@
|
||||
// Copyright (c) FIRST and other WPILib contributors.
|
||||
// Open Source Software; you can modify and/or share it under the terms of
|
||||
// the WPILib BSD license file in the root directory of this project.
|
||||
|
||||
#include "wpinet/uv/Idle.h"
|
||||
|
||||
#include "wpinet/uv/Loop.h"
|
||||
|
||||
namespace wpi::uv {
|
||||
|
||||
std::shared_ptr<Idle> Idle::Create(Loop& loop) {
|
||||
auto h = std::make_shared<Idle>(private_init{});
|
||||
int err = uv_idle_init(loop.GetRaw(), h->GetRaw());
|
||||
if (err < 0) {
|
||||
loop.ReportError(err);
|
||||
return nullptr;
|
||||
}
|
||||
h->Keep();
|
||||
return h;
|
||||
}
|
||||
|
||||
void Idle::Start() {
|
||||
Invoke(&uv_idle_start, GetRaw(), [](uv_idle_t* handle) {
|
||||
Idle& h = *static_cast<Idle*>(handle->data);
|
||||
h.idle();
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace wpi::uv
|
||||
70
wpinet/src/main/native/cpp/uv/Loop.cpp
Normal file
70
wpinet/src/main/native/cpp/uv/Loop.cpp
Normal file
@@ -0,0 +1,70 @@
|
||||
// Copyright (c) FIRST and other WPILib contributors.
|
||||
// Open Source Software; you can modify and/or share it under the terms of
|
||||
// the WPILib BSD license file in the root directory of this project.
|
||||
|
||||
#include "wpinet/uv/Loop.h"
|
||||
|
||||
using namespace wpi::uv;
|
||||
|
||||
Loop::Loop(const private_init&) noexcept {
|
||||
#ifndef _WIN32
|
||||
// Ignore SIGPIPE (see https://github.com/joyent/libuv/issues/1254)
|
||||
static bool once = []() {
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
return true;
|
||||
}();
|
||||
(void)once;
|
||||
#endif
|
||||
}
|
||||
|
||||
Loop::~Loop() noexcept {
|
||||
if (m_loop) {
|
||||
m_loop->data = nullptr;
|
||||
Close();
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<Loop> Loop::Create() {
|
||||
auto loop = std::make_shared<Loop>(private_init{});
|
||||
if (uv_loop_init(&loop->m_loopStruct) < 0) {
|
||||
return nullptr;
|
||||
}
|
||||
loop->m_loop = &loop->m_loopStruct;
|
||||
loop->m_loop->data = loop.get();
|
||||
return loop;
|
||||
}
|
||||
|
||||
std::shared_ptr<Loop> Loop::GetDefault() {
|
||||
static std::shared_ptr<Loop> loop = std::make_shared<Loop>(private_init{});
|
||||
loop->m_loop = uv_default_loop();
|
||||
if (!loop->m_loop) {
|
||||
return nullptr;
|
||||
}
|
||||
loop->m_loop->data = loop.get();
|
||||
return loop;
|
||||
}
|
||||
|
||||
void Loop::Close() {
|
||||
int err = uv_loop_close(m_loop);
|
||||
if (err < 0) {
|
||||
ReportError(err);
|
||||
}
|
||||
}
|
||||
|
||||
void Loop::Walk(function_ref<void(Handle&)> callback) {
|
||||
uv_walk(
|
||||
m_loop,
|
||||
[](uv_handle_t* handle, void* func) {
|
||||
auto& h = *static_cast<Handle*>(handle->data);
|
||||
auto& f = *static_cast<function_ref<void(Handle&)>*>(func);
|
||||
f(h);
|
||||
},
|
||||
&callback);
|
||||
}
|
||||
|
||||
void Loop::Fork() {
|
||||
int err = uv_loop_fork(m_loop);
|
||||
if (err < 0) {
|
||||
ReportError(err);
|
||||
}
|
||||
}
|
||||
59
wpinet/src/main/native/cpp/uv/NameToAddr.cpp
Normal file
59
wpinet/src/main/native/cpp/uv/NameToAddr.cpp
Normal file
@@ -0,0 +1,59 @@
|
||||
// Copyright (c) FIRST and other WPILib contributors.
|
||||
// Open Source Software; you can modify and/or share it under the terms of
|
||||
// the WPILib BSD license file in the root directory of this project.
|
||||
|
||||
#include "wpinet/uv/util.h" // NOLINT(build/include_order)
|
||||
|
||||
#include <cstring>
|
||||
|
||||
#include <wpi/SmallString.h>
|
||||
|
||||
namespace wpi::uv {
|
||||
|
||||
int NameToAddr(std::string_view ip, unsigned int port, sockaddr_in* addr) {
|
||||
if (ip.empty()) {
|
||||
std::memset(addr, 0, sizeof(sockaddr_in));
|
||||
addr->sin_family = PF_INET;
|
||||
addr->sin_addr.s_addr = INADDR_ANY;
|
||||
addr->sin_port = htons(port);
|
||||
return 0;
|
||||
} else {
|
||||
SmallString<128> ipBuf{ip};
|
||||
return uv_ip4_addr(ipBuf.c_str(), port, addr);
|
||||
}
|
||||
}
|
||||
|
||||
int NameToAddr(std::string_view ip, unsigned int port, sockaddr_in6* addr) {
|
||||
if (ip.empty()) {
|
||||
std::memset(addr, 0, sizeof(sockaddr_in6));
|
||||
addr->sin6_family = PF_INET6;
|
||||
addr->sin6_addr = in6addr_any;
|
||||
addr->sin6_port = htons(port);
|
||||
return 0;
|
||||
} else {
|
||||
SmallString<128> ipBuf{ip};
|
||||
return uv_ip6_addr(ipBuf.c_str(), port, addr);
|
||||
}
|
||||
}
|
||||
|
||||
int NameToAddr(std::string_view ip, in_addr* addr) {
|
||||
if (ip.empty()) {
|
||||
addr->s_addr = INADDR_ANY;
|
||||
return 0;
|
||||
} else {
|
||||
SmallString<128> ipBuf{ip};
|
||||
return uv_inet_pton(AF_INET, ipBuf.c_str(), addr);
|
||||
}
|
||||
}
|
||||
|
||||
int NameToAddr(std::string_view ip, in6_addr* addr) {
|
||||
if (ip.empty()) {
|
||||
*addr = in6addr_any;
|
||||
return 0;
|
||||
} else {
|
||||
SmallString<128> ipBuf{ip};
|
||||
return uv_inet_pton(AF_INET6, ipBuf.c_str(), addr);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace wpi::uv
|
||||
30
wpinet/src/main/native/cpp/uv/NetworkStream.cpp
Normal file
30
wpinet/src/main/native/cpp/uv/NetworkStream.cpp
Normal file
@@ -0,0 +1,30 @@
|
||||
// Copyright (c) FIRST and other WPILib contributors.
|
||||
// Open Source Software; you can modify and/or share it under the terms of
|
||||
// the WPILib BSD license file in the root directory of this project.
|
||||
|
||||
#include "wpinet/uv/NetworkStream.h"
|
||||
|
||||
namespace wpi::uv {
|
||||
|
||||
ConnectReq::ConnectReq() {
|
||||
error = [this](Error err) { GetStream().error(err); };
|
||||
}
|
||||
|
||||
void NetworkStream::Listen(int backlog) {
|
||||
Invoke(&uv_listen, GetRawStream(), backlog,
|
||||
[](uv_stream_t* handle, int status) {
|
||||
auto& h = *static_cast<NetworkStream*>(handle->data);
|
||||
if (status < 0) {
|
||||
h.ReportError(status);
|
||||
} else {
|
||||
h.connection();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void NetworkStream::Listen(std::function<void()> callback, int backlog) {
|
||||
connection.connect(std::move(callback));
|
||||
Listen(backlog);
|
||||
}
|
||||
|
||||
} // namespace wpi::uv
|
||||
138
wpinet/src/main/native/cpp/uv/Pipe.cpp
Normal file
138
wpinet/src/main/native/cpp/uv/Pipe.cpp
Normal file
@@ -0,0 +1,138 @@
|
||||
// Copyright (c) FIRST and other WPILib contributors.
|
||||
// Open Source Software; you can modify and/or share it under the terms of
|
||||
// the WPILib BSD license file in the root directory of this project.
|
||||
|
||||
#include "wpinet/uv/Pipe.h"
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
#include <wpi/SmallString.h>
|
||||
|
||||
namespace wpi::uv {
|
||||
|
||||
std::shared_ptr<Pipe> Pipe::Create(Loop& loop, bool ipc) {
|
||||
auto h = std::make_shared<Pipe>(private_init{});
|
||||
int err = uv_pipe_init(loop.GetRaw(), h->GetRaw(), ipc ? 1 : 0);
|
||||
if (err < 0) {
|
||||
loop.ReportError(err);
|
||||
return nullptr;
|
||||
}
|
||||
h->Keep();
|
||||
return h;
|
||||
}
|
||||
|
||||
void Pipe::Reuse(std::function<void()> callback, bool ipc) {
|
||||
if (IsClosing()) {
|
||||
return;
|
||||
}
|
||||
if (!m_reuseData) {
|
||||
m_reuseData = std::make_unique<ReuseData>();
|
||||
}
|
||||
m_reuseData->callback = std::move(callback);
|
||||
m_reuseData->ipc = ipc;
|
||||
uv_close(GetRawHandle(), [](uv_handle_t* handle) {
|
||||
Pipe& h = *static_cast<Pipe*>(handle->data);
|
||||
if (!h.m_reuseData) {
|
||||
return;
|
||||
}
|
||||
auto data = std::move(h.m_reuseData);
|
||||
auto err =
|
||||
uv_pipe_init(h.GetLoopRef().GetRaw(), h.GetRaw(), data->ipc ? 1 : 0);
|
||||
if (err < 0) {
|
||||
h.ReportError(err);
|
||||
return;
|
||||
}
|
||||
data->callback();
|
||||
});
|
||||
}
|
||||
|
||||
std::shared_ptr<Pipe> Pipe::Accept() {
|
||||
auto client = Create(GetLoopRef(), GetRaw()->ipc);
|
||||
if (!client) {
|
||||
return nullptr;
|
||||
}
|
||||
if (!Accept(client)) {
|
||||
client->Release();
|
||||
return nullptr;
|
||||
}
|
||||
return client;
|
||||
}
|
||||
|
||||
Pipe* Pipe::DoAccept() {
|
||||
return Accept().get();
|
||||
}
|
||||
|
||||
void Pipe::Bind(std::string_view name) {
|
||||
SmallString<128> nameBuf{name};
|
||||
Invoke(&uv_pipe_bind, GetRaw(), nameBuf.c_str());
|
||||
}
|
||||
|
||||
void Pipe::Connect(std::string_view name,
|
||||
const std::shared_ptr<PipeConnectReq>& req) {
|
||||
SmallString<128> nameBuf{name};
|
||||
uv_pipe_connect(req->GetRaw(), GetRaw(), nameBuf.c_str(),
|
||||
[](uv_connect_t* req, int status) {
|
||||
auto& h = *static_cast<PipeConnectReq*>(req->data);
|
||||
if (status < 0) {
|
||||
h.ReportError(status);
|
||||
} else {
|
||||
h.connected();
|
||||
}
|
||||
h.Release(); // this is always a one-shot
|
||||
});
|
||||
req->Keep();
|
||||
}
|
||||
|
||||
void Pipe::Connect(std::string_view name, std::function<void()> callback) {
|
||||
auto req = std::make_shared<PipeConnectReq>();
|
||||
req->connected.connect(std::move(callback));
|
||||
Connect(name, req);
|
||||
}
|
||||
|
||||
std::string Pipe::GetSock() {
|
||||
// Per libuv docs, the returned buffer is NOT null terminated.
|
||||
// common case should be small
|
||||
char buf[128];
|
||||
size_t size = 128;
|
||||
int r = uv_pipe_getsockname(GetRaw(), buf, &size);
|
||||
if (r == 0) {
|
||||
return std::string{buf, size};
|
||||
} else if (r == UV_ENOBUFS) {
|
||||
// need to allocate a big enough buffer
|
||||
char* buf2 = static_cast<char*>(std::malloc(size));
|
||||
r = uv_pipe_getsockname(GetRaw(), buf2, &size);
|
||||
if (r == 0) {
|
||||
std::string out{buf2, size};
|
||||
std::free(buf2);
|
||||
return out;
|
||||
}
|
||||
std::free(buf2);
|
||||
}
|
||||
ReportError(r);
|
||||
return std::string{};
|
||||
}
|
||||
|
||||
std::string Pipe::GetPeer() {
|
||||
// Per libuv docs, the returned buffer is NOT null terminated.
|
||||
// common case should be small
|
||||
char buf[128];
|
||||
size_t size = 128;
|
||||
int r = uv_pipe_getpeername(GetRaw(), buf, &size);
|
||||
if (r == 0) {
|
||||
return std::string{buf, size};
|
||||
} else if (r == UV_ENOBUFS) {
|
||||
// need to allocate a big enough buffer
|
||||
char* buf2 = static_cast<char*>(std::malloc(size));
|
||||
r = uv_pipe_getpeername(GetRaw(), buf2, &size);
|
||||
if (r == 0) {
|
||||
std::string out{buf2, size};
|
||||
std::free(buf2);
|
||||
return out;
|
||||
}
|
||||
std::free(buf2);
|
||||
}
|
||||
ReportError(r);
|
||||
return std::string{};
|
||||
}
|
||||
|
||||
} // namespace wpi::uv
|
||||
95
wpinet/src/main/native/cpp/uv/Poll.cpp
Normal file
95
wpinet/src/main/native/cpp/uv/Poll.cpp
Normal file
@@ -0,0 +1,95 @@
|
||||
// Copyright (c) FIRST and other WPILib contributors.
|
||||
// Open Source Software; you can modify and/or share it under the terms of
|
||||
// the WPILib BSD license file in the root directory of this project.
|
||||
|
||||
#include "wpinet/uv/Poll.h"
|
||||
|
||||
#include "wpinet/uv/Loop.h"
|
||||
|
||||
namespace wpi::uv {
|
||||
|
||||
std::shared_ptr<Poll> Poll::Create(Loop& loop, int fd) {
|
||||
auto h = std::make_shared<Poll>(private_init{});
|
||||
int err = uv_poll_init(loop.GetRaw(), h->GetRaw(), fd);
|
||||
if (err < 0) {
|
||||
loop.ReportError(err);
|
||||
return nullptr;
|
||||
}
|
||||
h->Keep();
|
||||
return h;
|
||||
}
|
||||
|
||||
std::shared_ptr<Poll> Poll::CreateSocket(Loop& loop, uv_os_sock_t sock) {
|
||||
auto h = std::make_shared<Poll>(private_init{});
|
||||
int err = uv_poll_init_socket(loop.GetRaw(), h->GetRaw(), sock);
|
||||
if (err < 0) {
|
||||
loop.ReportError(err);
|
||||
return nullptr;
|
||||
}
|
||||
h->Keep();
|
||||
return h;
|
||||
}
|
||||
|
||||
void Poll::Reuse(int fd, std::function<void()> callback) {
|
||||
if (IsClosing()) {
|
||||
return;
|
||||
}
|
||||
if (!m_reuseData) {
|
||||
m_reuseData = std::make_unique<ReuseData>();
|
||||
}
|
||||
m_reuseData->callback = std::move(callback);
|
||||
m_reuseData->isSocket = false;
|
||||
m_reuseData->fd = fd;
|
||||
uv_close(GetRawHandle(), [](uv_handle_t* handle) {
|
||||
Poll& h = *static_cast<Poll*>(handle->data);
|
||||
if (!h.m_reuseData || h.m_reuseData->isSocket) {
|
||||
return; // just in case
|
||||
}
|
||||
auto data = std::move(h.m_reuseData);
|
||||
int err = uv_poll_init(h.GetLoopRef().GetRaw(), h.GetRaw(), data->fd);
|
||||
if (err < 0) {
|
||||
h.ReportError(err);
|
||||
return;
|
||||
}
|
||||
data->callback();
|
||||
});
|
||||
}
|
||||
|
||||
void Poll::ReuseSocket(uv_os_sock_t sock, std::function<void()> callback) {
|
||||
if (IsClosing()) {
|
||||
return;
|
||||
}
|
||||
if (!m_reuseData) {
|
||||
m_reuseData = std::make_unique<ReuseData>();
|
||||
}
|
||||
m_reuseData->callback = std::move(callback);
|
||||
m_reuseData->isSocket = true;
|
||||
m_reuseData->sock = sock;
|
||||
uv_close(GetRawHandle(), [](uv_handle_t* handle) {
|
||||
Poll& h = *static_cast<Poll*>(handle->data);
|
||||
if (!h.m_reuseData || !h.m_reuseData->isSocket) {
|
||||
return; // just in case
|
||||
}
|
||||
auto data = std::move(h.m_reuseData);
|
||||
int err = uv_poll_init(h.GetLoopRef().GetRaw(), h.GetRaw(), data->sock);
|
||||
if (err < 0) {
|
||||
h.ReportError(err);
|
||||
return;
|
||||
}
|
||||
data->callback();
|
||||
});
|
||||
}
|
||||
|
||||
void Poll::Start(int events) {
|
||||
Invoke(&uv_poll_start, GetRaw(), events,
|
||||
[](uv_poll_t* handle, int status, int events) {
|
||||
Poll& h = *static_cast<Poll*>(handle->data);
|
||||
if (status < 0) {
|
||||
h.ReportError(status);
|
||||
} else {
|
||||
h.pollEvent(events);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace wpi::uv
|
||||
29
wpinet/src/main/native/cpp/uv/Prepare.cpp
Normal file
29
wpinet/src/main/native/cpp/uv/Prepare.cpp
Normal file
@@ -0,0 +1,29 @@
|
||||
// Copyright (c) FIRST and other WPILib contributors.
|
||||
// Open Source Software; you can modify and/or share it under the terms of
|
||||
// the WPILib BSD license file in the root directory of this project.
|
||||
|
||||
#include "wpinet/uv/Prepare.h"
|
||||
|
||||
#include "wpinet/uv/Loop.h"
|
||||
|
||||
namespace wpi::uv {
|
||||
|
||||
std::shared_ptr<Prepare> Prepare::Create(Loop& loop) {
|
||||
auto h = std::make_shared<Prepare>(private_init{});
|
||||
int err = uv_prepare_init(loop.GetRaw(), h->GetRaw());
|
||||
if (err < 0) {
|
||||
loop.ReportError(err);
|
||||
return nullptr;
|
||||
}
|
||||
h->Keep();
|
||||
return h;
|
||||
}
|
||||
|
||||
void Prepare::Start() {
|
||||
Invoke(&uv_prepare_start, GetRaw(), [](uv_prepare_t* handle) {
|
||||
Prepare& h = *static_cast<Prepare*>(handle->data);
|
||||
h.prepare();
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace wpi::uv
|
||||
134
wpinet/src/main/native/cpp/uv/Process.cpp
Normal file
134
wpinet/src/main/native/cpp/uv/Process.cpp
Normal file
@@ -0,0 +1,134 @@
|
||||
// Copyright (c) FIRST and other WPILib contributors.
|
||||
// Open Source Software; you can modify and/or share it under the terms of
|
||||
// the WPILib BSD license file in the root directory of this project.
|
||||
|
||||
#include "wpinet/uv/Process.h"
|
||||
|
||||
#include <wpi/SmallString.h>
|
||||
|
||||
#include "wpinet/uv/Loop.h"
|
||||
#include "wpinet/uv/Pipe.h"
|
||||
|
||||
namespace wpi::uv {
|
||||
|
||||
std::shared_ptr<Process> Process::SpawnArray(Loop& loop, std::string_view file,
|
||||
span<const Option> options) {
|
||||
// convert Option array to libuv structure
|
||||
uv_process_options_t coptions;
|
||||
|
||||
coptions.exit_cb = [](uv_process_t* handle, int64_t status, int signal) {
|
||||
auto& h = *static_cast<Process*>(handle->data);
|
||||
h.exited(status, signal);
|
||||
};
|
||||
|
||||
SmallString<128> fileBuf{file};
|
||||
coptions.file = fileBuf.c_str();
|
||||
coptions.cwd = nullptr;
|
||||
coptions.flags = 0;
|
||||
coptions.uid = 0;
|
||||
coptions.gid = 0;
|
||||
|
||||
SmallVector<char*, 4> argsBuf;
|
||||
SmallVector<char*, 4> envBuf;
|
||||
struct StdioContainer : public uv_stdio_container_t {
|
||||
StdioContainer() {
|
||||
flags = UV_IGNORE;
|
||||
data.fd = 0;
|
||||
}
|
||||
};
|
||||
SmallVector<StdioContainer, 4> stdioBuf;
|
||||
|
||||
for (auto&& o : options) {
|
||||
switch (o.m_type) {
|
||||
case Option::kArg:
|
||||
argsBuf.push_back(const_cast<char*>(o.m_data.str));
|
||||
break;
|
||||
case Option::kEnv:
|
||||
envBuf.push_back(const_cast<char*>(o.m_data.str));
|
||||
break;
|
||||
case Option::kCwd:
|
||||
coptions.cwd = o.m_data.str[0] == '\0' ? nullptr : o.m_data.str;
|
||||
break;
|
||||
case Option::kUid:
|
||||
coptions.uid = o.m_data.uid;
|
||||
coptions.flags |= UV_PROCESS_SETUID;
|
||||
break;
|
||||
case Option::kGid:
|
||||
coptions.gid = o.m_data.gid;
|
||||
coptions.flags |= UV_PROCESS_SETGID;
|
||||
break;
|
||||
case Option::kSetFlags:
|
||||
coptions.flags |= o.m_data.flags;
|
||||
break;
|
||||
case Option::kClearFlags:
|
||||
coptions.flags &= ~o.m_data.flags;
|
||||
break;
|
||||
case Option::kStdioIgnore: {
|
||||
size_t index = o.m_data.stdio.index;
|
||||
if (index >= stdioBuf.size()) {
|
||||
stdioBuf.resize(index + 1);
|
||||
}
|
||||
stdioBuf[index].flags = UV_IGNORE;
|
||||
stdioBuf[index].data.fd = 0;
|
||||
break;
|
||||
}
|
||||
case Option::kStdioInheritFd: {
|
||||
size_t index = o.m_data.stdio.index;
|
||||
if (index >= stdioBuf.size()) {
|
||||
stdioBuf.resize(index + 1);
|
||||
}
|
||||
stdioBuf[index].flags = UV_INHERIT_FD;
|
||||
stdioBuf[index].data.fd = o.m_data.stdio.fd;
|
||||
break;
|
||||
}
|
||||
case Option::kStdioInheritPipe: {
|
||||
size_t index = o.m_data.stdio.index;
|
||||
if (index >= stdioBuf.size()) {
|
||||
stdioBuf.resize(index + 1);
|
||||
}
|
||||
stdioBuf[index].flags = UV_INHERIT_STREAM;
|
||||
stdioBuf[index].data.stream = o.m_data.stdio.pipe->GetRawStream();
|
||||
break;
|
||||
}
|
||||
case Option::kStdioCreatePipe: {
|
||||
size_t index = o.m_data.stdio.index;
|
||||
if (index >= stdioBuf.size()) {
|
||||
stdioBuf.resize(index + 1);
|
||||
}
|
||||
stdioBuf[index].flags =
|
||||
static_cast<uv_stdio_flags>(UV_CREATE_PIPE | o.m_data.stdio.flags);
|
||||
stdioBuf[index].data.stream = o.m_data.stdio.pipe->GetRawStream();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (argsBuf.empty()) {
|
||||
argsBuf.push_back(const_cast<char*>(coptions.file));
|
||||
}
|
||||
argsBuf.push_back(nullptr);
|
||||
coptions.args = argsBuf.data();
|
||||
|
||||
if (envBuf.empty()) {
|
||||
coptions.env = nullptr;
|
||||
} else {
|
||||
envBuf.push_back(nullptr);
|
||||
coptions.env = envBuf.data();
|
||||
}
|
||||
|
||||
coptions.stdio_count = stdioBuf.size();
|
||||
coptions.stdio = static_cast<uv_stdio_container_t*>(stdioBuf.data());
|
||||
|
||||
auto h = std::make_shared<Process>(private_init{});
|
||||
int err = uv_spawn(loop.GetRaw(), h->GetRaw(), &coptions);
|
||||
if (err < 0) {
|
||||
loop.ReportError(err);
|
||||
return nullptr;
|
||||
}
|
||||
h->Keep();
|
||||
return h;
|
||||
}
|
||||
|
||||
} // namespace wpi::uv
|
||||
32
wpinet/src/main/native/cpp/uv/Signal.cpp
Normal file
32
wpinet/src/main/native/cpp/uv/Signal.cpp
Normal file
@@ -0,0 +1,32 @@
|
||||
// Copyright (c) FIRST and other WPILib contributors.
|
||||
// Open Source Software; you can modify and/or share it under the terms of
|
||||
// the WPILib BSD license file in the root directory of this project.
|
||||
|
||||
#include "wpinet/uv/Signal.h"
|
||||
|
||||
#include "wpinet/uv/Loop.h"
|
||||
|
||||
namespace wpi::uv {
|
||||
|
||||
std::shared_ptr<Signal> Signal::Create(Loop& loop) {
|
||||
auto h = std::make_shared<Signal>(private_init{});
|
||||
int err = uv_signal_init(loop.GetRaw(), h->GetRaw());
|
||||
if (err < 0) {
|
||||
loop.ReportError(err);
|
||||
return nullptr;
|
||||
}
|
||||
h->Keep();
|
||||
return h;
|
||||
}
|
||||
|
||||
void Signal::Start(int signum) {
|
||||
Invoke(
|
||||
&uv_signal_start, GetRaw(),
|
||||
[](uv_signal_t* handle, int signum) {
|
||||
Signal& h = *static_cast<Signal*>(handle->data);
|
||||
h.signal(signum);
|
||||
},
|
||||
signum);
|
||||
}
|
||||
|
||||
} // namespace wpi::uv
|
||||
109
wpinet/src/main/native/cpp/uv/Stream.cpp
Normal file
109
wpinet/src/main/native/cpp/uv/Stream.cpp
Normal file
@@ -0,0 +1,109 @@
|
||||
// Copyright (c) FIRST and other WPILib contributors.
|
||||
// Open Source Software; you can modify and/or share it under the terms of
|
||||
// the WPILib BSD license file in the root directory of this project.
|
||||
|
||||
#include "wpinet/uv/Stream.h"
|
||||
|
||||
#include <wpi/SmallVector.h>
|
||||
|
||||
using namespace wpi;
|
||||
using namespace wpi::uv;
|
||||
|
||||
namespace {
|
||||
class CallbackWriteReq : public WriteReq {
|
||||
public:
|
||||
CallbackWriteReq(span<const Buffer> bufs,
|
||||
std::function<void(span<Buffer>, Error)> callback)
|
||||
: m_bufs{bufs.begin(), bufs.end()} {
|
||||
finish.connect(
|
||||
[this, f = std::move(callback)](Error err) { f(m_bufs, err); });
|
||||
}
|
||||
|
||||
private:
|
||||
SmallVector<Buffer, 4> m_bufs;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
namespace wpi::uv {
|
||||
|
||||
ShutdownReq::ShutdownReq() {
|
||||
error = [this](Error err) { GetStream().error(err); };
|
||||
}
|
||||
|
||||
WriteReq::WriteReq() {
|
||||
error = [this](Error err) { GetStream().error(err); };
|
||||
}
|
||||
|
||||
void Stream::Shutdown(const std::shared_ptr<ShutdownReq>& req) {
|
||||
if (Invoke(&uv_shutdown, req->GetRaw(), GetRawStream(),
|
||||
[](uv_shutdown_t* req, int status) {
|
||||
auto& h = *static_cast<ShutdownReq*>(req->data);
|
||||
if (status < 0) {
|
||||
h.ReportError(status);
|
||||
} else {
|
||||
h.complete();
|
||||
}
|
||||
h.Release(); // this is always a one-shot
|
||||
})) {
|
||||
req->Keep();
|
||||
}
|
||||
}
|
||||
|
||||
void Stream::Shutdown(std::function<void()> callback) {
|
||||
auto req = std::make_shared<ShutdownReq>();
|
||||
if (callback) {
|
||||
req->complete.connect(std::move(callback));
|
||||
}
|
||||
Shutdown(req);
|
||||
}
|
||||
|
||||
void Stream::StartRead() {
|
||||
Invoke(&uv_read_start, GetRawStream(), &Handle::AllocBuf,
|
||||
[](uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf) {
|
||||
auto& h = *static_cast<Stream*>(stream->data);
|
||||
Buffer data = *buf;
|
||||
|
||||
// nread=0 is simply ignored
|
||||
if (nread == UV_EOF) {
|
||||
h.end();
|
||||
} else if (nread > 0) {
|
||||
h.data(data, static_cast<size_t>(nread));
|
||||
} else if (nread < 0) {
|
||||
h.ReportError(nread);
|
||||
}
|
||||
|
||||
// free the buffer
|
||||
h.FreeBuf(data);
|
||||
});
|
||||
}
|
||||
|
||||
void Stream::Write(span<const Buffer> bufs,
|
||||
const std::shared_ptr<WriteReq>& req) {
|
||||
if (Invoke(&uv_write, req->GetRaw(), GetRawStream(), bufs.data(), bufs.size(),
|
||||
[](uv_write_t* r, int status) {
|
||||
auto& h = *static_cast<WriteReq*>(r->data);
|
||||
if (status < 0) {
|
||||
h.ReportError(status);
|
||||
}
|
||||
h.finish(Error(status));
|
||||
h.Release(); // this is always a one-shot
|
||||
})) {
|
||||
req->Keep();
|
||||
}
|
||||
}
|
||||
|
||||
void Stream::Write(span<const Buffer> bufs,
|
||||
std::function<void(span<Buffer>, Error)> callback) {
|
||||
Write(bufs, std::make_shared<CallbackWriteReq>(bufs, std::move(callback)));
|
||||
}
|
||||
|
||||
int Stream::TryWrite(span<const Buffer> bufs) {
|
||||
int val = uv_try_write(GetRawStream(), bufs.data(), bufs.size());
|
||||
if (val < 0) {
|
||||
this->ReportError(val);
|
||||
return 0;
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
} // namespace wpi::uv
|
||||
170
wpinet/src/main/native/cpp/uv/Tcp.cpp
Normal file
170
wpinet/src/main/native/cpp/uv/Tcp.cpp
Normal file
@@ -0,0 +1,170 @@
|
||||
// Copyright (c) FIRST and other WPILib contributors.
|
||||
// Open Source Software; you can modify and/or share it under the terms of
|
||||
// the WPILib BSD license file in the root directory of this project.
|
||||
|
||||
#include "wpinet/uv/Tcp.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
#include "wpinet/uv/util.h"
|
||||
|
||||
namespace wpi::uv {
|
||||
|
||||
std::shared_ptr<Tcp> Tcp::Create(Loop& loop, unsigned int flags) {
|
||||
auto h = std::make_shared<Tcp>(private_init{});
|
||||
int err = uv_tcp_init_ex(loop.GetRaw(), h->GetRaw(), flags);
|
||||
if (err < 0) {
|
||||
loop.ReportError(err);
|
||||
return nullptr;
|
||||
}
|
||||
h->Keep();
|
||||
return h;
|
||||
}
|
||||
|
||||
void Tcp::Reuse(std::function<void()> callback, unsigned int flags) {
|
||||
if (IsClosing()) {
|
||||
return;
|
||||
}
|
||||
if (!m_reuseData) {
|
||||
m_reuseData = std::make_unique<ReuseData>();
|
||||
}
|
||||
m_reuseData->callback = std::move(callback);
|
||||
m_reuseData->flags = flags;
|
||||
uv_close(GetRawHandle(), [](uv_handle_t* handle) {
|
||||
Tcp& h = *static_cast<Tcp*>(handle->data);
|
||||
if (!h.m_reuseData) {
|
||||
return; // just in case
|
||||
}
|
||||
auto data = std::move(h.m_reuseData);
|
||||
int err = uv_tcp_init_ex(h.GetLoopRef().GetRaw(), h.GetRaw(), data->flags);
|
||||
if (err < 0) {
|
||||
h.ReportError(err);
|
||||
return;
|
||||
}
|
||||
data->callback();
|
||||
});
|
||||
}
|
||||
|
||||
std::shared_ptr<Tcp> Tcp::Accept() {
|
||||
auto client = Create(GetLoopRef());
|
||||
if (!client) {
|
||||
return nullptr;
|
||||
}
|
||||
if (!Accept(client)) {
|
||||
client->Release();
|
||||
return nullptr;
|
||||
}
|
||||
return client;
|
||||
}
|
||||
|
||||
Tcp* Tcp::DoAccept() {
|
||||
return Accept().get();
|
||||
}
|
||||
|
||||
void Tcp::Bind(std::string_view ip, unsigned int port, unsigned int flags) {
|
||||
sockaddr_in addr;
|
||||
int err = NameToAddr(ip, port, &addr);
|
||||
if (err < 0) {
|
||||
ReportError(err);
|
||||
} else {
|
||||
Bind(reinterpret_cast<const sockaddr&>(addr), flags);
|
||||
}
|
||||
}
|
||||
|
||||
void Tcp::Bind6(std::string_view ip, unsigned int port, unsigned int flags) {
|
||||
sockaddr_in6 addr;
|
||||
int err = NameToAddr(ip, port, &addr);
|
||||
if (err < 0) {
|
||||
ReportError(err);
|
||||
} else {
|
||||
Bind(reinterpret_cast<const sockaddr&>(addr), flags);
|
||||
}
|
||||
}
|
||||
|
||||
sockaddr_storage Tcp::GetSock() {
|
||||
sockaddr_storage name;
|
||||
int len = sizeof(name);
|
||||
if (!Invoke(&uv_tcp_getsockname, GetRaw(), reinterpret_cast<sockaddr*>(&name),
|
||||
&len)) {
|
||||
std::memset(&name, 0, sizeof(name));
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
sockaddr_storage Tcp::GetPeer() {
|
||||
sockaddr_storage name;
|
||||
int len = sizeof(name);
|
||||
if (!Invoke(&uv_tcp_getpeername, GetRaw(), reinterpret_cast<sockaddr*>(&name),
|
||||
&len)) {
|
||||
std::memset(&name, 0, sizeof(name));
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
void Tcp::Connect(const sockaddr& addr,
|
||||
const std::shared_ptr<TcpConnectReq>& req) {
|
||||
if (Invoke(&uv_tcp_connect, req->GetRaw(), GetRaw(), &addr,
|
||||
[](uv_connect_t* req, int status) {
|
||||
auto& h = *static_cast<TcpConnectReq*>(req->data);
|
||||
if (status < 0) {
|
||||
h.ReportError(status);
|
||||
} else {
|
||||
h.connected();
|
||||
}
|
||||
h.Release(); // this is always a one-shot
|
||||
})) {
|
||||
req->Keep();
|
||||
}
|
||||
}
|
||||
|
||||
void Tcp::Connect(const sockaddr& addr, std::function<void()> callback) {
|
||||
auto req = std::make_shared<TcpConnectReq>();
|
||||
req->connected.connect(std::move(callback));
|
||||
Connect(addr, req);
|
||||
}
|
||||
|
||||
void Tcp::Connect(std::string_view ip, unsigned int port,
|
||||
const std::shared_ptr<TcpConnectReq>& req) {
|
||||
sockaddr_in addr;
|
||||
int err = NameToAddr(ip, port, &addr);
|
||||
if (err < 0) {
|
||||
ReportError(err);
|
||||
} else {
|
||||
Connect(reinterpret_cast<const sockaddr&>(addr), req);
|
||||
}
|
||||
}
|
||||
|
||||
void Tcp::Connect(std::string_view ip, unsigned int port,
|
||||
std::function<void()> callback) {
|
||||
sockaddr_in addr;
|
||||
int err = NameToAddr(ip, port, &addr);
|
||||
if (err < 0) {
|
||||
ReportError(err);
|
||||
} else {
|
||||
Connect(reinterpret_cast<const sockaddr&>(addr), std::move(callback));
|
||||
}
|
||||
}
|
||||
|
||||
void Tcp::Connect6(std::string_view ip, unsigned int port,
|
||||
const std::shared_ptr<TcpConnectReq>& req) {
|
||||
sockaddr_in6 addr;
|
||||
int err = NameToAddr(ip, port, &addr);
|
||||
if (err < 0) {
|
||||
ReportError(err);
|
||||
} else {
|
||||
Connect(reinterpret_cast<const sockaddr&>(addr), req);
|
||||
}
|
||||
}
|
||||
|
||||
void Tcp::Connect6(std::string_view ip, unsigned int port,
|
||||
std::function<void()> callback) {
|
||||
sockaddr_in6 addr;
|
||||
int err = NameToAddr(ip, port, &addr);
|
||||
if (err < 0) {
|
||||
ReportError(err);
|
||||
} else {
|
||||
Connect(reinterpret_cast<const sockaddr&>(addr), std::move(callback));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace wpi::uv
|
||||
44
wpinet/src/main/native/cpp/uv/Timer.cpp
Normal file
44
wpinet/src/main/native/cpp/uv/Timer.cpp
Normal file
@@ -0,0 +1,44 @@
|
||||
// Copyright (c) FIRST and other WPILib contributors.
|
||||
// Open Source Software; you can modify and/or share it under the terms of
|
||||
// the WPILib BSD license file in the root directory of this project.
|
||||
|
||||
#include "wpinet/uv/Timer.h"
|
||||
|
||||
#include "wpinet/uv/Loop.h"
|
||||
|
||||
namespace wpi::uv {
|
||||
|
||||
std::shared_ptr<Timer> Timer::Create(Loop& loop) {
|
||||
auto h = std::make_shared<Timer>(private_init{});
|
||||
int err = uv_timer_init(loop.GetRaw(), h->GetRaw());
|
||||
if (err < 0) {
|
||||
loop.ReportError(err);
|
||||
return nullptr;
|
||||
}
|
||||
h->Keep();
|
||||
return h;
|
||||
}
|
||||
|
||||
void Timer::SingleShot(Loop& loop, Time timeout, std::function<void()> func) {
|
||||
auto h = Create(loop);
|
||||
if (!h) {
|
||||
return;
|
||||
}
|
||||
h->timeout.connect([theTimer = h.get(), f = std::move(func)]() {
|
||||
f();
|
||||
theTimer->Close();
|
||||
});
|
||||
h->Start(timeout);
|
||||
}
|
||||
|
||||
void Timer::Start(Time timeout, Time repeat) {
|
||||
Invoke(
|
||||
&uv_timer_start, GetRaw(),
|
||||
[](uv_timer_t* handle) {
|
||||
Timer& h = *static_cast<Timer*>(handle->data);
|
||||
h.timeout();
|
||||
},
|
||||
timeout.count(), repeat.count());
|
||||
}
|
||||
|
||||
} // namespace wpi::uv
|
||||
22
wpinet/src/main/native/cpp/uv/Tty.cpp
Normal file
22
wpinet/src/main/native/cpp/uv/Tty.cpp
Normal file
@@ -0,0 +1,22 @@
|
||||
// Copyright (c) FIRST and other WPILib contributors.
|
||||
// Open Source Software; you can modify and/or share it under the terms of
|
||||
// the WPILib BSD license file in the root directory of this project.
|
||||
|
||||
#include "wpinet/uv/Tty.h"
|
||||
|
||||
#include "wpinet/uv/Loop.h"
|
||||
|
||||
namespace wpi::uv {
|
||||
|
||||
std::shared_ptr<Tty> Tty::Create(Loop& loop, uv_file fd, bool readable) {
|
||||
auto h = std::make_shared<Tty>(private_init{});
|
||||
int err = uv_tty_init(loop.GetRaw(), h->GetRaw(), fd, readable ? 1 : 0);
|
||||
if (err < 0) {
|
||||
loop.ReportError(err);
|
||||
return nullptr;
|
||||
}
|
||||
h->Keep();
|
||||
return h;
|
||||
}
|
||||
|
||||
} // namespace wpi::uv
|
||||
185
wpinet/src/main/native/cpp/uv/Udp.cpp
Normal file
185
wpinet/src/main/native/cpp/uv/Udp.cpp
Normal file
@@ -0,0 +1,185 @@
|
||||
// Copyright (c) FIRST and other WPILib contributors.
|
||||
// Open Source Software; you can modify and/or share it under the terms of
|
||||
// the WPILib BSD license file in the root directory of this project.
|
||||
|
||||
#include "wpinet/uv/Udp.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
#include <wpi/SmallString.h>
|
||||
#include <wpi/SmallVector.h>
|
||||
|
||||
#include "wpinet/uv/util.h"
|
||||
|
||||
namespace {
|
||||
|
||||
using namespace wpi;
|
||||
using namespace wpi::uv;
|
||||
|
||||
class CallbackUdpSendReq : public UdpSendReq {
|
||||
public:
|
||||
CallbackUdpSendReq(span<const Buffer> bufs,
|
||||
std::function<void(span<Buffer>, Error)> callback)
|
||||
: m_bufs{bufs.begin(), bufs.end()} {
|
||||
complete.connect(
|
||||
[this, f = std::move(callback)](Error err) { f(m_bufs, err); });
|
||||
}
|
||||
|
||||
private:
|
||||
SmallVector<Buffer, 4> m_bufs;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace wpi::uv {
|
||||
|
||||
UdpSendReq::UdpSendReq() {
|
||||
error = [this](Error err) { GetUdp().error(err); };
|
||||
}
|
||||
|
||||
std::shared_ptr<Udp> Udp::Create(Loop& loop, unsigned int flags) {
|
||||
auto h = std::make_shared<Udp>(private_init{});
|
||||
int err = uv_udp_init_ex(loop.GetRaw(), h->GetRaw(), flags);
|
||||
if (err < 0) {
|
||||
loop.ReportError(err);
|
||||
return nullptr;
|
||||
}
|
||||
h->Keep();
|
||||
return h;
|
||||
}
|
||||
|
||||
void Udp::Bind(std::string_view ip, unsigned int port, unsigned int flags) {
|
||||
sockaddr_in addr;
|
||||
int err = NameToAddr(ip, port, &addr);
|
||||
if (err < 0) {
|
||||
ReportError(err);
|
||||
} else {
|
||||
Bind(reinterpret_cast<const sockaddr&>(addr), flags);
|
||||
}
|
||||
}
|
||||
|
||||
void Udp::Bind6(std::string_view ip, unsigned int port, unsigned int flags) {
|
||||
sockaddr_in6 addr;
|
||||
int err = NameToAddr(ip, port, &addr);
|
||||
if (err < 0) {
|
||||
ReportError(err);
|
||||
} else {
|
||||
Bind(reinterpret_cast<const sockaddr&>(addr), flags);
|
||||
}
|
||||
}
|
||||
|
||||
void Udp::Connect(std::string_view ip, unsigned int port) {
|
||||
sockaddr_in addr;
|
||||
int err = NameToAddr(ip, port, &addr);
|
||||
if (err < 0) {
|
||||
ReportError(err);
|
||||
} else {
|
||||
Connect(reinterpret_cast<const sockaddr&>(addr));
|
||||
}
|
||||
}
|
||||
|
||||
void Udp::Connect6(std::string_view ip, unsigned int port) {
|
||||
sockaddr_in6 addr;
|
||||
int err = NameToAddr(ip, port, &addr);
|
||||
if (err < 0) {
|
||||
ReportError(err);
|
||||
} else {
|
||||
Connect(reinterpret_cast<const sockaddr&>(addr));
|
||||
}
|
||||
}
|
||||
|
||||
sockaddr_storage Udp::GetPeer() {
|
||||
sockaddr_storage name;
|
||||
int len = sizeof(name);
|
||||
if (!Invoke(&uv_udp_getpeername, GetRaw(), reinterpret_cast<sockaddr*>(&name),
|
||||
&len)) {
|
||||
std::memset(&name, 0, sizeof(name));
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
sockaddr_storage Udp::GetSock() {
|
||||
sockaddr_storage name;
|
||||
int len = sizeof(name);
|
||||
if (!Invoke(&uv_udp_getsockname, GetRaw(), reinterpret_cast<sockaddr*>(&name),
|
||||
&len)) {
|
||||
std::memset(&name, 0, sizeof(name));
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
void Udp::SetMembership(std::string_view multicastAddr,
|
||||
std::string_view interfaceAddr,
|
||||
uv_membership membership) {
|
||||
SmallString<128> multicastAddrBuf{multicastAddr};
|
||||
SmallString<128> interfaceAddrBuf{interfaceAddr};
|
||||
Invoke(&uv_udp_set_membership, GetRaw(), multicastAddrBuf.c_str(),
|
||||
interfaceAddrBuf.c_str(), membership);
|
||||
}
|
||||
|
||||
void Udp::SetMulticastInterface(std::string_view interfaceAddr) {
|
||||
SmallString<128> interfaceAddrBuf{interfaceAddr};
|
||||
Invoke(&uv_udp_set_multicast_interface, GetRaw(), interfaceAddrBuf.c_str());
|
||||
}
|
||||
|
||||
void Udp::Send(const sockaddr& addr, span<const Buffer> bufs,
|
||||
const std::shared_ptr<UdpSendReq>& req) {
|
||||
if (Invoke(&uv_udp_send, req->GetRaw(), GetRaw(), bufs.data(), bufs.size(),
|
||||
&addr, [](uv_udp_send_t* r, int status) {
|
||||
auto& h = *static_cast<UdpSendReq*>(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(const sockaddr& addr, span<const Buffer> bufs,
|
||||
std::function<void(span<Buffer>, Error)> callback) {
|
||||
Send(addr, bufs,
|
||||
std::make_shared<CallbackUdpSendReq>(bufs, std::move(callback)));
|
||||
}
|
||||
|
||||
void Udp::Send(span<const Buffer> bufs,
|
||||
const std::shared_ptr<UdpSendReq>& 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<UdpSendReq*>(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(span<const Buffer> bufs,
|
||||
std::function<void(span<Buffer>, Error)> callback) {
|
||||
Send(bufs, std::make_shared<CallbackUdpSendReq>(bufs, std::move(callback)));
|
||||
}
|
||||
|
||||
void Udp::StartRecv() {
|
||||
Invoke(&uv_udp_recv_start, GetRaw(), &AllocBuf,
|
||||
[](uv_udp_t* handle, ssize_t nread, const uv_buf_t* buf,
|
||||
const sockaddr* addr, unsigned flags) {
|
||||
auto& h = *static_cast<Udp*>(handle->data);
|
||||
Buffer data = *buf;
|
||||
|
||||
// nread=0 is simply ignored
|
||||
if (nread > 0) {
|
||||
h.received(data, static_cast<size_t>(nread), *addr, flags);
|
||||
} else if (nread < 0) {
|
||||
h.ReportError(nread);
|
||||
}
|
||||
|
||||
// free the buffer
|
||||
h.FreeBuf(data);
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace wpi::uv
|
||||
50
wpinet/src/main/native/cpp/uv/Work.cpp
Normal file
50
wpinet/src/main/native/cpp/uv/Work.cpp
Normal file
@@ -0,0 +1,50 @@
|
||||
// Copyright (c) FIRST and other WPILib contributors.
|
||||
// Open Source Software; you can modify and/or share it under the terms of
|
||||
// the WPILib BSD license file in the root directory of this project.
|
||||
|
||||
#include "wpinet/uv/Work.h"
|
||||
|
||||
#include "wpinet/uv/Loop.h"
|
||||
|
||||
namespace wpi::uv {
|
||||
|
||||
WorkReq::WorkReq() {
|
||||
error = [this](Error err) { GetLoop().error(err); };
|
||||
}
|
||||
|
||||
void QueueWork(Loop& loop, const std::shared_ptr<WorkReq>& req) {
|
||||
int err = uv_queue_work(
|
||||
loop.GetRaw(), req->GetRaw(),
|
||||
[](uv_work_t* req) {
|
||||
auto& h = *static_cast<WorkReq*>(req->data);
|
||||
h.work();
|
||||
},
|
||||
[](uv_work_t* req, int status) {
|
||||
auto& h = *static_cast<WorkReq*>(req->data);
|
||||
if (status < 0) {
|
||||
h.ReportError(status);
|
||||
} else {
|
||||
h.afterWork();
|
||||
}
|
||||
h.Release(); // this is always a one-shot
|
||||
});
|
||||
if (err < 0) {
|
||||
loop.ReportError(err);
|
||||
} else {
|
||||
req->Keep();
|
||||
}
|
||||
}
|
||||
|
||||
void QueueWork(Loop& loop, std::function<void()> work,
|
||||
std::function<void()> afterWork) {
|
||||
auto req = std::make_shared<WorkReq>();
|
||||
if (work) {
|
||||
req->work.connect(std::move(work));
|
||||
}
|
||||
if (afterWork) {
|
||||
req->afterWork.connect(std::move(afterWork));
|
||||
}
|
||||
QueueWork(loop, req);
|
||||
}
|
||||
|
||||
} // namespace wpi::uv
|
||||
Reference in New Issue
Block a user