From 6f6cbeba8069f8570a8838ca711a9809c76450fb Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Fri, 12 Jan 2024 12:09:41 +0100 Subject: [PATCH] net/SocketDescriptor: add Send()/Receive() overloads with iovec --- src/net/MsgHdr.hxx | 62 ++++++++++++++++++++++++++++++ src/net/SocketDescriptor.cxx | 14 +++++++ src/net/SocketDescriptor.hxx | 21 ++++++++-- src/net/UniqueSocketDescriptor.hxx | 5 +-- 4 files changed, 94 insertions(+), 8 deletions(-) create mode 100644 src/net/MsgHdr.hxx diff --git a/src/net/MsgHdr.hxx b/src/net/MsgHdr.hxx new file mode 100644 index 000000000..a013fb78b --- /dev/null +++ b/src/net/MsgHdr.hxx @@ -0,0 +1,62 @@ +// SPDX-License-Identifier: BSD-2-Clause +// Copyright CM4all GmbH +// author: Max Kellermann + +#pragma once + +#include "SocketAddress.hxx" +#include "StaticSocketAddress.hxx" + +#include + +#include + +inline constexpr struct msghdr +MakeMsgHdr(std::span iov) noexcept +{ + struct msghdr mh{}; + mh.msg_iov = const_cast(iov.data()); + mh.msg_iovlen = iov.size(); + return mh; +} + +/** + * Construct a struct msghdr. The parameters are `const` because that + * is needed for sending; but for receiving, these buffers must + * actually be writable. + */ +inline constexpr struct msghdr +MakeMsgHdr(SocketAddress name, std::span iov, + std::span control) noexcept +{ + auto mh = MakeMsgHdr(iov); + mh.msg_name = const_cast(name.GetAddress()); + mh.msg_namelen = name.GetSize(); + mh.msg_control = const_cast(control.data()); + mh.msg_controllen = control.size(); + return mh; +} + +inline constexpr struct msghdr +MakeMsgHdr(StaticSocketAddress &name, std::span iov, + std::span control) noexcept +{ + auto mh = MakeMsgHdr(iov); + mh.msg_name = name; + mh.msg_namelen = name.GetCapacity(); + mh.msg_control = const_cast(control.data()); + mh.msg_controllen = control.size(); + return mh; +} + +inline constexpr struct msghdr +MakeMsgHdr(struct sockaddr_storage &name, std::span iov, + std::span control) noexcept +{ + auto mh = MakeMsgHdr(iov); + mh.msg_name = static_cast(static_cast(&name)); + mh.msg_namelen = sizeof(name); + mh.msg_control = const_cast(control.data()); + mh.msg_controllen = control.size(); + return mh; +} diff --git a/src/net/SocketDescriptor.cxx b/src/net/SocketDescriptor.cxx index b86a07dfa..f255bd885 100644 --- a/src/net/SocketDescriptor.cxx +++ b/src/net/SocketDescriptor.cxx @@ -6,6 +6,7 @@ #include "StaticSocketAddress.hxx" #include "IPv4Address.hxx" #include "IPv6Address.hxx" +#include "MsgHdr.hxx" #ifdef _WIN32 #include @@ -423,6 +424,13 @@ SocketDescriptor::Receive(struct msghdr &msg, int flags) const noexcept return ::recvmsg(Get(), &msg, flags); } +ssize_t +SocketDescriptor::Receive(std::span v, int flags) const noexcept +{ + auto msg = MakeMsgHdr(v); + return Receive(msg, flags); +} + ssize_t SocketDescriptor::Send(std::span src, int flags) const noexcept { @@ -443,6 +451,12 @@ SocketDescriptor::Send(const struct msghdr &msg, int flags) const noexcept return ::sendmsg(Get(), &msg, flags); } +ssize_t +SocketDescriptor::Send(std::span v, int flags) const noexcept +{ + return Send(MakeMsgHdr(v), flags); +} + ssize_t SocketDescriptor::ReadNoWait(std::span dest) const noexcept { diff --git a/src/net/SocketDescriptor.hxx b/src/net/SocketDescriptor.hxx index 029c4ed83..0aeb50fe7 100644 --- a/src/net/SocketDescriptor.hxx +++ b/src/net/SocketDescriptor.hxx @@ -1,8 +1,7 @@ // SPDX-License-Identifier: BSD-2-Clause // author: Max Kellermann -#ifndef SOCKET_DESCRIPTOR_HXX -#define SOCKET_DESCRIPTOR_HXX +#pragma once #include "Features.hxx" @@ -19,6 +18,8 @@ #include // for SOCKET, INVALID_SOCKET #endif +struct msghdr; +struct iovec; class SocketAddress; class StaticSocketAddress; class IPv4Address; @@ -309,6 +310,12 @@ public: [[nodiscard]] ssize_t Receive(struct msghdr &msg, int flags=0) const noexcept; + /** + * Wrapper for recvmsg(). + */ + [[nodiscard]] + ssize_t Receive(std::span v, int flags=0) const noexcept; + /** * Wrapper for send(). * @@ -325,6 +332,14 @@ public: [[nodiscard]] ssize_t Send(const struct msghdr &msg, int flags=0) const noexcept; + /** + * Wrapper for sendmsg(). + * + * MSG_NOSIGNAL is implicitly added (if available). + */ + [[nodiscard]] + ssize_t Send(std::span v, int flags=0) const noexcept; + [[nodiscard]] ssize_t Read(std::span dest) const noexcept { return Receive(dest); @@ -383,5 +398,3 @@ public: }; static_assert(std::is_trivial::value, "type is not trivial"); - -#endif diff --git a/src/net/UniqueSocketDescriptor.hxx b/src/net/UniqueSocketDescriptor.hxx index a6809aef5..159f80222 100644 --- a/src/net/UniqueSocketDescriptor.hxx +++ b/src/net/UniqueSocketDescriptor.hxx @@ -1,8 +1,7 @@ // SPDX-License-Identifier: BSD-2-Clause // author: Max Kellermann -#ifndef UNIQUE_SOCKET_DESCRIPTOR_SOCKET_HXX -#define UNIQUE_SOCKET_DESCRIPTOR_SOCKET_HXX +#pragma once #include "SocketDescriptor.hxx" @@ -90,5 +89,3 @@ public: } #endif }; - -#endif