netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Michele Dalle Rive <dallerivemichele@gmail.com>
To: Miguel Ojeda <ojeda@kernel.org>,
	Alex Gaynor <alex.gaynor@gmail.com>,
	Wedson Almeida Filho <wedsonaf@gmail.com>,
	"David S. Miller" <davem@davemloft.net>
Cc: "Eric Dumazet" <edumazet@google.com>,
	"Jakub Kicinski" <kuba@kernel.org>,
	"Paolo Abeni" <pabeni@redhat.com>,
	"Boqun Feng" <boqun.feng@gmail.com>,
	"Gary Guo" <gary@garyguo.net>,
	"Björn Roy Baron" <bjorn3_gh@protonmail.com>,
	"Benno Lossin" <benno.lossin@proton.me>,
	"Alice Ryhl" <aliceryhl@google.com>,
	"Davide Rovelli" <davide.rovelli@usi.ch>,
	rust-for-linux@vger.kernel.org, netdev@vger.kernel.org,
	linux-kernel@vger.kernel.org, patches@lists.linux.dev,
	"Michele Dalle Rive" <dallerivemichele@gmail.com>
Subject: [RFC PATCH 7/7] rust: net: add socket UDP wrappers.
Date: Mon, 14 Aug 2023 11:23:02 +0200	[thread overview]
Message-ID: <20230814092302.1903203-8-dallerivemichele@gmail.com> (raw)
In-Reply-To: <20230814092302.1903203-1-dallerivemichele@gmail.com>

Add a UDP socket wrapper, which allows to handle UDP sockets conveniently.

This interface is intended to be as close as possible to the one in `std::net`.

Signed-off-by: Michele Dalle Rive <dallerivemichele@gmail.com>
---
 rust/kernel/net.rs     |   1 +
 rust/kernel/net/udp.rs | 182 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 183 insertions(+)
 create mode 100644 rust/kernel/net/udp.rs

diff --git a/rust/kernel/net.rs b/rust/kernel/net.rs
index c7d9d4b0bcab..c527bd1fb0a8 100644
--- a/rust/kernel/net.rs
+++ b/rust/kernel/net.rs
@@ -14,6 +14,7 @@
 pub mod ip;
 pub mod socket;
 pub mod tcp;
+pub mod udp;
 
 /// The address family.
 ///
diff --git a/rust/kernel/net/udp.rs b/rust/kernel/net/udp.rs
new file mode 100644
index 000000000000..9193292a30f6
--- /dev/null
+++ b/rust/kernel/net/udp.rs
@@ -0,0 +1,182 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! UDP socket wrapper.
+//!
+//! This module contains wrappers for a UDP Socket ([`UdpSocket`]).
+//! The wrapper is just convenience structs around the generic [`Socket`] type.
+//!
+//! The API is inspired by the Rust standard library's [`UdpSocket`](https://doc.rust-lang.org/std/net/struct.UdpSocket.html).
+
+use crate::error::Result;
+use crate::net::addr::SocketAddr;
+use crate::net::ip::IpProtocol;
+use crate::net::socket::flags::{FlagSet, ReceiveFlag, SendFlag};
+use crate::net::socket::{opts::SocketOption, MessageHeader, SockType, Socket};
+use crate::net::AddressFamily;
+use kernel::net::socket::opts::WritableOption;
+
+/// A UDP socket.
+///
+/// Provides an interface to send and receive UDP packets, removing
+/// all the socket functionality that is not needed for UDP.
+///
+/// # Examples
+/// ```rust
+/// use kernel::flag_set;
+/// use kernel::net::udp::UdpSocket;
+/// use kernel::net::addr::*;
+///
+/// let socket = UdpSocket::new().unwrap();
+/// socket.bind(SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::LOOPBACK, 8000))).unwrap();
+/// let mut buf = [0u8; 1024];
+/// while let Ok((len, addr)) = socket.receive_from(&mut buf, flag_set!()) {
+///     socket.send_to(&buf[..len], &addr, flag_set!()).unwrap();
+/// }
+/// ```
+pub struct UdpSocket(pub(crate) Socket);
+
+impl UdpSocket {
+    /// Creates a UDP socket.
+    ///
+    /// Returns a [`UdpSocket`] on success.
+    pub fn new() -> Result<Self> {
+        Ok(Self(Socket::new(
+            AddressFamily::Inet,
+            SockType::Datagram,
+            IpProtocol::Udp,
+        )?))
+    }
+
+    /// Binds the socket to the given address.
+    pub fn bind(&self, address: SocketAddr) -> Result {
+        self.0.bind(address)
+    }
+
+    /// Returns the socket's local address.
+    ///
+    /// This function assumes the socket is bound,
+    /// i.e. it must be called after [`bind()`](UdpSocket::bind).
+    ///
+    /// # Examples
+    /// ```rust
+    /// use kernel::net::udp::UdpSocket;
+    /// use kernel::net::addr::*;
+    ///
+    /// let socket = UdpSocket::new().unwrap();
+    /// let local_addr = SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::LOOPBACK, 8000));
+    /// socket.bind(local_addr).unwrap();
+    /// assert_eq!(socket.sockname().unwrap(), local_addr);
+    pub fn sockname(&self) -> Result<SocketAddr> {
+        self.0.sockname()
+    }
+
+    /// Returns the socket's peer address.
+    ///
+    /// This function assumes the socket is connected,
+    /// i.e. it must be called after [`connect()`](UdpSocket::connect).
+    ///
+    /// # Examples
+    /// ```rust
+    /// use kernel::net::udp::UdpSocket;
+    /// use kernel::net::addr::*;
+    ///
+    /// let socket = UdpSocket::new().unwrap();
+    /// let peer_addr = SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::LOOPBACK, 8000));
+    /// socket.connect(&peer_addr).unwrap();
+    /// assert_eq!(socket.peername().unwrap(), peer_addr);
+    pub fn peername(&self) -> Result<SocketAddr> {
+        self.0.peername()
+    }
+
+    /// Receive a message from the socket.
+    ///
+    /// The given flags are used to modify the behavior of the receive operation.
+    /// See [`ReceiveFlag`] for more.
+    ///
+    /// The returned [`MessageHeader`] contains metadata about the received message.
+    ///
+    /// See [`Socket::receive_msg()`] for more.
+    pub fn receive_msg(
+        &self,
+        buf: &mut [u8],
+        flags: FlagSet<ReceiveFlag>,
+    ) -> Result<(usize, MessageHeader)> {
+        self.0.receive_msg(buf, flags)
+    }
+
+    /// Receives data from another socket.
+    ///
+    /// The given flags are used to modify the behavior of the receive operation.
+    /// See [`ReceiveFlag`] for more.
+    ///
+    /// Returns the number of bytes received and the address of the sender.
+    pub fn receive_from(
+        &self,
+        buf: &mut [u8],
+        flags: FlagSet<ReceiveFlag>,
+    ) -> Result<(usize, SocketAddr)> {
+        self.0
+            .receive_from(buf, flags)
+            .map(|(size, addr)| (size, addr.unwrap()))
+    }
+
+    /// Sends data to another socket.
+    ///
+    /// The given flags are used to modify the behavior of the send operation.
+    /// See [`SendFlag`] for more.
+    ///
+    /// Returns the number of bytes sent.
+    pub fn send_to(
+        &self,
+        buf: &[u8],
+        address: &SocketAddr,
+        flags: FlagSet<SendFlag>,
+    ) -> Result<usize> {
+        self.0.send_to(buf, address, flags)
+    }
+
+    /// Connects the socket to the given address.
+    ///
+    /// # Examples
+    /// ```rust
+    /// use kernel::net::udp::UdpSocket;
+    /// use kernel::net::addr::*;
+    ///
+    /// let socket = UdpSocket::new().unwrap();
+    /// let peer_addr = SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::LOOPBACK, 8000));
+    /// socket.connect(&peer_addr).unwrap();
+    /// ```
+    pub fn connect(&self, address: &SocketAddr) -> Result {
+        self.0.connect(address, 0)
+    }
+
+    /// Receives data from the connected socket.
+    ///
+    /// This function assumes the socket is connected,
+    /// i.e. it must be called after [`connect()`](UdpSocket::connect).
+    ///
+    /// Returns the number of bytes received.
+    pub fn receive(&self, buf: &mut [u8], flags: FlagSet<ReceiveFlag>) -> Result<usize> {
+        self.0.receive(buf, flags)
+    }
+
+    /// Sends data to the connected socket.
+    ///
+    /// This function assumes the socket is connected,
+    /// i.e. it must be called after [`connect()`](UdpSocket::connect).
+    ///
+    /// Returns the number of bytes sent.
+    pub fn send(&self, buf: &[u8], flags: FlagSet<SendFlag>) -> Result<usize> {
+        self.0.send(buf, flags)
+    }
+
+    /// Sets the value of the given option.
+    ///
+    /// See [`Socket::set_option()`](Socket::set_option) for more.
+    pub fn set_option<O>(&self, value: impl Into<O::Type>) -> Result
+    where
+        O: SocketOption + WritableOption,
+    {
+        self.0.set_option::<O>(value)
+    }
+}
-- 
2.41.0


  parent reply	other threads:[~2023-08-14  9:24 UTC|newest]

Thread overview: 26+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-08-14  9:22 [RFC PATCH 0/7] Rust Socket abstractions Michele Dalle Rive
2023-08-14  9:22 ` [RFC PATCH 1/7] rust: net: add net module files and shared enums Michele Dalle Rive
2023-08-14  9:22 ` [RFC PATCH 2/7] rust: net: add ip and socket address bindings Michele Dalle Rive
2023-08-14  9:22 ` [RFC PATCH 3/7] rust: net: add socket-related flags and flagset Michele Dalle Rive
2023-08-14  9:22 ` [RFC PATCH 4/7] rust: net: add socket wrapper Michele Dalle Rive
2023-08-14  9:23 ` [RFC PATCH 5/7] rust: net: implement socket options API Michele Dalle Rive
2023-08-14  9:23 ` [RFC PATCH 6/7] rust: net: add socket TCP wrappers Michele Dalle Rive
2023-08-14  9:23 ` Michele Dalle Rive [this message]
2023-08-14 15:25 ` [RFC PATCH 0/7] Rust Socket abstractions Greg KH
2023-08-14 20:23   ` Andrew Lunn
2023-08-14 21:06     ` Michele Dalle Rive
2023-08-14 21:36       ` Andrew Lunn
2023-08-17 14:53         ` Michele Dalle Rive
2023-08-17 15:14           ` Andrew Lunn
2023-08-17 15:48           ` Jakub Kicinski
2023-08-17 17:01             ` Boqun Feng
2023-08-17 17:32             ` Miguel Ojeda
2023-08-17 18:41             ` Jonathan Corbet
2023-08-17 17:14           ` Miguel Ojeda
2023-08-17 18:38             ` Stephen Hemminger
2023-08-17 19:13               ` Miguel Ojeda
2023-08-17 19:14             ` Andrew Lunn
2023-08-17 22:27             ` Davide Rovelli
2023-08-18  1:30               ` Andrew Lunn
2023-08-18  7:50                 ` Davide Rovelli
2023-08-18 12:42                   ` Andrew Lunn

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20230814092302.1903203-8-dallerivemichele@gmail.com \
    --to=dallerivemichele@gmail.com \
    --cc=alex.gaynor@gmail.com \
    --cc=aliceryhl@google.com \
    --cc=benno.lossin@proton.me \
    --cc=bjorn3_gh@protonmail.com \
    --cc=boqun.feng@gmail.com \
    --cc=davem@davemloft.net \
    --cc=davide.rovelli@usi.ch \
    --cc=edumazet@google.com \
    --cc=gary@garyguo.net \
    --cc=kuba@kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=netdev@vger.kernel.org \
    --cc=ojeda@kernel.org \
    --cc=pabeni@redhat.com \
    --cc=patches@lists.linux.dev \
    --cc=rust-for-linux@vger.kernel.org \
    --cc=wedsonaf@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).