diff options
| author | Lexi Winter <lexi@hemlock.eden.le-fay.org> | 2025-03-29 07:54:43 +0000 |
|---|---|---|
| committer | Lexi Winter <lexi@hemlock.eden.le-fay.org> | 2025-03-29 07:54:43 +0000 |
| commit | 7eb396734ebbdcb4ecef90d21a89201e0d89c709 (patch) | |
| tree | 64d8d437a819236096b63ae62dbfb01bb5cdf865 /libnvxx | |
| parent | b48e5ad9b57372c7904dfaa8e10bfe5c527149a7 (diff) | |
| download | libnvxx-7eb396734ebbdcb4ecef90d21a89201e0d89c709.tar.gz libnvxx-7eb396734ebbdcb4ecef90d21a89201e0d89c709.tar.bz2 | |
make xfer() a member function, and add tests
Diffstat (limited to 'libnvxx')
| -rw-r--r-- | libnvxx/nv_list.cc | 30 | ||||
| -rw-r--r-- | libnvxx/nvxx.3 | 21 | ||||
| -rw-r--r-- | libnvxx/nvxx_base.h | 20 | ||||
| -rw-r--r-- | libnvxx/tests/Makefile | 2 | ||||
| -rw-r--r-- | libnvxx/tests/nvxx_basic.cc | 82 |
5 files changed, 127 insertions, 28 deletions
diff --git a/libnvxx/nv_list.cc b/libnvxx/nv_list.cc index 6eadd36..eace039 100644 --- a/libnvxx/nv_list.cc +++ b/libnvxx/nv_list.cc @@ -130,20 +130,6 @@ nv_list::recv(int fd, int flags) std::error_code(errno, std::system_category())); } -nv_list -nv_list::xfer(int fd, nv_list &&nvl, int flags) -{ - if (auto *nv = ::nvlist_xfer(fd, nvl.__m_nv, flags); - nv != nullptr) { - // nvlist_xfer destroys the original list - nvl.__m_nv = nullptr; - return (nv_list(nv)); - } - - throw std::system_error( - std::error_code(errno, std::system_category())); -} - namespace __detail { /* @@ -164,6 +150,22 @@ __nv_list::operator const_nv_list() const return (const_nv_list(__m_nv)); } +nv_list +__nv_list::xfer(int fd, int flags) && +{ + __throw_if_error(); + + auto *nv = ::nvlist_xfer(fd, __m_nv, flags); + // nvlist_xfer always destroys the original list + __m_nv = nullptr; + + if (nv != nullptr) + return (nv_list(nv)); + + throw std::system_error( + std::error_code(errno, std::system_category())); +} + void __nv_list::free(std::string_view key) { diff --git a/libnvxx/nvxx.3 b/libnvxx/nvxx.3 index 37db659..c5ef02f 100644 --- a/libnvxx/nvxx.3 +++ b/libnvxx/nvxx.3 @@ -134,6 +134,8 @@ struct nv_list : <unspecified> { operator const_nv_list() const; + nv_list xfer(int fd, int flags = 0) &&; + void add_null(std::string_view key); void add_bool(std::string_view key, bool value); void add_number(std::string_view key, std::uint64_t); @@ -603,6 +605,25 @@ If the nvlist is already in the error state, then an exception of type is thrown and the error state is not changed. .Pp The +.Fn xfer +function sends this nvlist over a socket as if by +.Fn send , +and then receives a new nvlist from the same socket as if by +.Fn recv , +which is returned. +If +.Fa flags +is non-zero, the specified flags will be used to create the returned nvlist. +The nvlist being sent is left in the empty state. +If the nvlist is in the error state, an exception of type +.Vt nv_error_state +is thrown. +If an operating system error occurs while writing to or reading from the file +descriptor, an exception of type +.Vt std::system_error +is thrown and the nvlist being sent is left in the empty state. +.Pp +The .Fn add_null , .Fn add_bool , .Fn add_number , diff --git a/libnvxx/nvxx_base.h b/libnvxx/nvxx_base.h index 43e53cf..06d213e 100644 --- a/libnvxx/nvxx_base.h +++ b/libnvxx/nvxx_base.h @@ -214,6 +214,16 @@ struct __nv_list : virtual __nv_list_base { */ operator const_nv_list() const; + /* + * Send this nv_list over a file descriptor and receive another nv_list + * in response, which is returned, by calling nvlist_xfer(). On + * failure, throws std::system_error. + * + * The source nv_list is moved-from and is left in an undefined state. + * The returned nv_list is owning. + */ + [[nodiscard]] nv_list xfer(int __fd, int __flags = 0) &&; + /* add */ void add_null(std::string_view); @@ -434,16 +444,6 @@ struct nv_list final */ [[nodiscard]] static auto recv(int __fd, int __flags = 0) -> nv_list; - /* - * Send an nv_list over a file descriptor and receive another nv_list - * in response, which is returned, by calling nvlist_xfer(). On - * failure, throws std::system_error. - * - * The source nv_list is moved-from and is left in an undefined state. - * The returned nv_list is owning. - */ - [[nodiscard]] static nv_list xfer(int, nv_list &&, int); - void add_bool_range(std::string_view __key, std::ranges::range auto &&__value) { diff --git a/libnvxx/tests/Makefile b/libnvxx/tests/Makefile index 3ea8a5a..384f8a8 100644 --- a/libnvxx/tests/Makefile +++ b/libnvxx/tests/Makefile @@ -9,6 +9,6 @@ CXXSTD= c++23 CXXFLAGS+= -W -Wall -Wextra CFLAGS+= -I${.CURDIR:H} LDFLAGS+= -lprivateatf-c++ -L${.OBJDIR:H} -lnvxx -LDFLAGS.nvxx_basic+= -lnv +LDFLAGS.nvxx_basic+= -lnv -lpthread .include <bsd.test.mk> diff --git a/libnvxx/tests/nvxx_basic.cc b/libnvxx/tests/nvxx_basic.cc index dbca98c..ca70fec 100644 --- a/libnvxx/tests/nvxx_basic.cc +++ b/libnvxx/tests/nvxx_basic.cc @@ -10,6 +10,7 @@ #include <span> #include <string> #include <string_view> +#include <thread> #include <sys/types.h> #include <sys/socket.h> @@ -526,8 +527,6 @@ TEST_CASE(nvxx_send_recv) TEST_CASE(nvxx_send_error) { - using namespace std::literals; - auto nvl = bsd::nv_list(); nvl.set_error(std::errc::invalid_argument); @@ -556,6 +555,79 @@ TEST_CASE(nvxx_send_empty) } /* + * xfer + */ + +TEST_CASE(nvxx_xfer) +{ + using namespace std::literals; + auto constexpr send_key = "test"sv; + auto constexpr send_value = 42u; + auto constexpr resp_key = "response"sv; + + auto fds = std::array<int, 2>{}; + auto ret = ::socketpair(AF_UNIX, SOCK_STREAM, 0, &fds[0]); + ATF_REQUIRE_EQ(0, ret); + + bsd::nv_fd fd0(fds[0]); + bsd::nv_fd fd1(fds[1]); + + /* + * testing xfer() is a bit tricky because it blocks waiting for a + * response. create a thread that receives a list and sends its own in + * response. + */ + + auto respond_thread = std::thread([&] { + auto nvl2 = bsd::nv_list::recv(fd1.get()); + + auto resp_nvl = bsd::nv_list(); + resp_nvl.add_number(resp_key, nvl2.get_number(send_key)); + resp_nvl.send(fd1.get()); + }); + + auto send_nvl = bsd::nv_list(); + send_nvl.add_number(send_key, send_value); + + auto nvl2 = std::move(send_nvl).xfer(fd0.get()); + ATF_REQUIRE_EQ(send_value, nvl2.get_number(resp_key)); + + ATF_REQUIRE_THROW(std::logic_error, send_nvl.ptr()); + + respond_thread.join(); +} + +TEST_CASE(nvxx_xfer_error) +{ + auto nvl = bsd::nv_list(); + nvl.set_error(std::errc::invalid_argument); + + auto fds = std::array<int, 2>{}; + auto ret = ::socketpair(AF_UNIX, SOCK_STREAM, 0, &fds[0]); + ATF_REQUIRE_EQ(0, ret); + + bsd::nv_fd fd0(fds[0]); + bsd::nv_fd fd1(fds[1]); + + ATF_REQUIRE_THROW(bsd::nv_error_state, (void)std::move(nvl).xfer(fd0.get())); +} + +TEST_CASE(nvxx_xfer_empty) +{ + auto nvl = bsd::nv_list(); + auto nvl2 = std::move(nvl); + + auto fds = std::array<int, 2>{}; + auto ret = ::socketpair(AF_UNIX, SOCK_STREAM, 0, &fds[0]); + ATF_REQUIRE_EQ(0, ret); + + bsd::nv_fd fd0(fds[0]); + bsd::nv_fd fd1(fds[1]); + + ATF_REQUIRE_THROW(std::logic_error, (void)std::move(nvl).xfer(fd0.get())); +} + +/* * exists(_type) */ @@ -2107,11 +2179,15 @@ ATF_INIT_TEST_CASES(tcs) ATF_ADD_TEST_CASE(tcs, nvxx_unpack); ATF_ADD_TEST_CASE(tcs, nvxx_unpack_range); - ATF_ADD_TEST_CASE(tcs, nvxx_send_non_socket); ATF_ADD_TEST_CASE(tcs, nvxx_send_recv); + ATF_ADD_TEST_CASE(tcs, nvxx_send_non_socket); ATF_ADD_TEST_CASE(tcs, nvxx_send_empty); ATF_ADD_TEST_CASE(tcs, nvxx_send_error); + ATF_ADD_TEST_CASE(tcs, nvxx_xfer); + ATF_ADD_TEST_CASE(tcs, nvxx_xfer_empty); + ATF_ADD_TEST_CASE(tcs, nvxx_xfer_error); + ATF_ADD_TEST_CASE(tcs, nvxx_exists); ATF_ADD_TEST_CASE(tcs, nvxx_exists_nul_key); ATF_ADD_TEST_CASE(tcs, nvxx_exists_type); |
