mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-17 02:26:46 +00:00
Move smoltcp-related code to bigtcp
This commit is contained in:
parent
9fba9445bd
commit
67d3682116
11
Cargo.lock
generated
11
Cargo.lock
generated
@ -66,6 +66,15 @@ version = "1.1.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d92bec98840b8f03a5ff5413de5293bfcd8bf96467cf5452609f939ec6f5de16"
|
checksum = "d92bec98840b8f03a5ff5413de5293bfcd8bf96467cf5452609f939ec6f5de16"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "aster-bigtcp"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"keyable-arc",
|
||||||
|
"ostd",
|
||||||
|
"smoltcp",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "aster-block"
|
name = "aster-block"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
@ -144,6 +153,7 @@ version = "0.1.0"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"align_ext",
|
"align_ext",
|
||||||
"ascii",
|
"ascii",
|
||||||
|
"aster-bigtcp",
|
||||||
"aster-block",
|
"aster-block",
|
||||||
"aster-console",
|
"aster-console",
|
||||||
"aster-framebuffer",
|
"aster-framebuffer",
|
||||||
@ -179,7 +189,6 @@ dependencies = [
|
|||||||
"ostd",
|
"ostd",
|
||||||
"paste",
|
"paste",
|
||||||
"rand",
|
"rand",
|
||||||
"smoltcp",
|
|
||||||
"spin 0.9.8",
|
"spin 0.9.8",
|
||||||
"static_assertions",
|
"static_assertions",
|
||||||
"takeable",
|
"takeable",
|
||||||
|
@ -24,6 +24,7 @@ members = [
|
|||||||
"kernel/libs/aster-rights",
|
"kernel/libs/aster-rights",
|
||||||
"kernel/libs/aster-rights-proc",
|
"kernel/libs/aster-rights-proc",
|
||||||
"kernel/libs/aster-util",
|
"kernel/libs/aster-util",
|
||||||
|
"kernel/libs/aster-bigtcp",
|
||||||
"kernel/libs/keyable-arc",
|
"kernel/libs/keyable-arc",
|
||||||
"kernel/libs/typeflags",
|
"kernel/libs/typeflags",
|
||||||
"kernel/libs/typeflags-util",
|
"kernel/libs/typeflags-util",
|
||||||
|
3
Makefile
3
Makefile
@ -126,7 +126,8 @@ OSDK_CRATES := \
|
|||||||
kernel/comps/network \
|
kernel/comps/network \
|
||||||
kernel/comps/time \
|
kernel/comps/time \
|
||||||
kernel/comps/virtio \
|
kernel/comps/virtio \
|
||||||
kernel/libs/aster-util
|
kernel/libs/aster-util \
|
||||||
|
kernel/libs/aster-bigtcp
|
||||||
|
|
||||||
.PHONY: all
|
.PHONY: all
|
||||||
all: build
|
all: build
|
||||||
|
@ -22,6 +22,7 @@ typeflags = { path = "libs/typeflags" }
|
|||||||
typeflags-util = { path = "libs/typeflags-util" }
|
typeflags-util = { path = "libs/typeflags-util" }
|
||||||
aster-rights-proc = { path = "libs/aster-rights-proc" }
|
aster-rights-proc = { path = "libs/aster-rights-proc" }
|
||||||
aster-util = { path = "libs/aster-util" }
|
aster-util = { path = "libs/aster-util" }
|
||||||
|
aster-bigtcp = { path = "libs/aster-bigtcp" }
|
||||||
id-alloc = { path = "../ostd/libs/id-alloc" }
|
id-alloc = { path = "../ostd/libs/id-alloc" }
|
||||||
int-to-c-enum = { path = "libs/int-to-c-enum" }
|
int-to-c-enum = { path = "libs/int-to-c-enum" }
|
||||||
cpio-decoder = { path = "libs/cpio-decoder" }
|
cpio-decoder = { path = "libs/cpio-decoder" }
|
||||||
@ -29,20 +30,6 @@ ascii = { version = "1.1", default-features = false, features = ["alloc"] }
|
|||||||
intrusive-collections = "0.9.5"
|
intrusive-collections = "0.9.5"
|
||||||
paste = "1.0"
|
paste = "1.0"
|
||||||
time = { version = "0.3", default-features = false, features = ["alloc"] }
|
time = { version = "0.3", default-features = false, features = ["alloc"] }
|
||||||
smoltcp = { git = "https://github.com/smoltcp-rs/smoltcp", rev = "dc08e0b", default-features = false, features = [
|
|
||||||
"alloc",
|
|
||||||
"log",
|
|
||||||
"medium-ethernet",
|
|
||||||
"medium-ip",
|
|
||||||
"proto-dhcpv4",
|
|
||||||
"proto-ipv4",
|
|
||||||
"proto-igmp",
|
|
||||||
"socket-icmp",
|
|
||||||
"socket-udp",
|
|
||||||
"socket-tcp",
|
|
||||||
"socket-raw",
|
|
||||||
"socket-dhcpv4",
|
|
||||||
] }
|
|
||||||
tdx-guest = { version = "0.1.7", optional = true }
|
tdx-guest = { version = "0.1.7", optional = true }
|
||||||
|
|
||||||
# parse elf file
|
# parse elf file
|
||||||
|
24
kernel/libs/aster-bigtcp/Cargo.toml
Normal file
24
kernel/libs/aster-bigtcp/Cargo.toml
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
[package]
|
||||||
|
name = "aster-bigtcp"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
keyable-arc = { path = "../keyable-arc" }
|
||||||
|
ostd = { path = "../../../ostd" }
|
||||||
|
smoltcp = { git = "https://github.com/smoltcp-rs/smoltcp", rev = "dc08e0b", default-features = false, features = [
|
||||||
|
"alloc",
|
||||||
|
"log",
|
||||||
|
"medium-ethernet",
|
||||||
|
"medium-ip",
|
||||||
|
"proto-dhcpv4",
|
||||||
|
"proto-ipv4",
|
||||||
|
"proto-igmp",
|
||||||
|
"socket-icmp",
|
||||||
|
"socket-udp",
|
||||||
|
"socket-tcp",
|
||||||
|
"socket-raw",
|
||||||
|
"socket-dhcpv4",
|
||||||
|
] }
|
@ -1,6 +1,6 @@
|
|||||||
// SPDX-License-Identifier: MPL-2.0
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
use smoltcp::phy::Device;
|
pub use smoltcp::phy::{Device, Loopback, Medium};
|
||||||
|
|
||||||
/// A trait that allows to obtain a mutable reference of [`Device`].
|
/// A trait that allows to obtain a mutable reference of [`Device`].
|
||||||
///
|
///
|
18
kernel/libs/aster-bigtcp/src/errors.rs
Normal file
18
kernel/libs/aster-bigtcp/src/errors.rs
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
/// An error describing the reason why `bind` failed.
|
||||||
|
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
||||||
|
pub enum BindError {
|
||||||
|
/// All ephemeral ports is exhausted.
|
||||||
|
Exhausted,
|
||||||
|
/// The specified address is in use.
|
||||||
|
InUse,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub mod tcp {
|
||||||
|
pub use smoltcp::socket::tcp::{ConnectError, ListenError, RecvError, SendError};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub mod udp {
|
||||||
|
pub use smoltcp::socket::udp::{RecvError, SendError};
|
||||||
|
}
|
@ -1,24 +1,30 @@
|
|||||||
// SPDX-License-Identifier: MPL-2.0
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
use alloc::collections::btree_map::Entry;
|
use alloc::{
|
||||||
|
boxed::Box,
|
||||||
|
collections::{
|
||||||
|
btree_map::{BTreeMap, Entry},
|
||||||
|
btree_set::BTreeSet,
|
||||||
|
},
|
||||||
|
sync::Arc,
|
||||||
|
vec::Vec,
|
||||||
|
};
|
||||||
|
|
||||||
use keyable_arc::KeyableArc;
|
use keyable_arc::KeyableArc;
|
||||||
use ostd::sync::LocalIrqDisabled;
|
use ostd::sync::{LocalIrqDisabled, RwLock, SpinLock, SpinLockGuard};
|
||||||
use smoltcp::{
|
use smoltcp::{
|
||||||
iface::{SocketHandle, SocketSet},
|
iface::{SocketHandle, SocketSet},
|
||||||
phy::Device,
|
phy::Device,
|
||||||
|
wire::Ipv4Address,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{
|
use super::{port::BindPortConfig, time::get_network_timestamp, Iface};
|
||||||
any_socket::{AnyBoundSocketInner, AnyRawSocket, AnyUnboundSocket, SocketFamily},
|
use crate::{
|
||||||
ext::IfaceExt,
|
errors::BindError,
|
||||||
time::get_network_timestamp,
|
socket::{AnyBoundSocket, AnyBoundSocketInner, AnyRawSocket, AnyUnboundSocket, SocketFamily},
|
||||||
util::BindPortConfig,
|
|
||||||
AnyBoundSocket, Iface,
|
|
||||||
};
|
};
|
||||||
use crate::{net::socket::ip::Ipv4Address, prelude::*};
|
|
||||||
|
|
||||||
pub struct IfaceCommon<E = IfaceExt> {
|
pub struct IfaceCommon<E> {
|
||||||
interface: SpinLock<smoltcp::iface::Interface>,
|
interface: SpinLock<smoltcp::iface::Interface>,
|
||||||
sockets: SpinLock<SocketSet<'static>>,
|
sockets: SpinLock<SocketSet<'static>>,
|
||||||
used_ports: RwLock<BTreeMap<u16, usize>>,
|
used_ports: RwLock<BTreeMap<u16, usize>>,
|
||||||
@ -44,14 +50,14 @@ impl<E> IfaceCommon<E> {
|
|||||||
/// Acquires the lock to the interface.
|
/// Acquires the lock to the interface.
|
||||||
///
|
///
|
||||||
/// *Lock ordering:* [`Self::sockets`] first, [`Self::interface`] second.
|
/// *Lock ordering:* [`Self::sockets`] first, [`Self::interface`] second.
|
||||||
pub(super) fn interface(&self) -> SpinLockGuard<smoltcp::iface::Interface, LocalIrqDisabled> {
|
pub(crate) fn interface(&self) -> SpinLockGuard<smoltcp::iface::Interface, LocalIrqDisabled> {
|
||||||
self.interface.disable_irq().lock()
|
self.interface.disable_irq().lock()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Acuqires the lock to the sockets.
|
/// Acuqires the lock to the sockets.
|
||||||
///
|
///
|
||||||
/// *Lock ordering:* [`Self::sockets`] first, [`Self::interface`] second.
|
/// *Lock ordering:* [`Self::sockets`] first, [`Self::interface`] second.
|
||||||
pub(super) fn sockets(
|
pub(crate) fn sockets(
|
||||||
&self,
|
&self,
|
||||||
) -> SpinLockGuard<smoltcp::iface::SocketSet<'static>, LocalIrqDisabled> {
|
) -> SpinLockGuard<smoltcp::iface::SocketSet<'static>, LocalIrqDisabled> {
|
||||||
self.sockets.disable_irq().lock()
|
self.sockets.disable_irq().lock()
|
||||||
@ -62,34 +68,35 @@ impl<E> IfaceCommon<E> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Alloc an unused port range from 49152 ~ 65535 (According to smoltcp docs)
|
/// Alloc an unused port range from 49152 ~ 65535 (According to smoltcp docs)
|
||||||
fn alloc_ephemeral_port(&self) -> Result<u16> {
|
fn alloc_ephemeral_port(&self) -> Option<u16> {
|
||||||
let mut used_ports = self.used_ports.write();
|
let mut used_ports = self.used_ports.write();
|
||||||
for port in IP_LOCAL_PORT_START..=IP_LOCAL_PORT_END {
|
for port in IP_LOCAL_PORT_START..=IP_LOCAL_PORT_END {
|
||||||
if let Entry::Vacant(e) = used_ports.entry(port) {
|
if let Entry::Vacant(e) = used_ports.entry(port) {
|
||||||
e.insert(0);
|
e.insert(0);
|
||||||
return Ok(port);
|
return Some(port);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return_errno_with_message!(Errno::EAGAIN, "no ephemeral port is available");
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
fn bind_port(&self, port: u16, can_reuse: bool) -> Result<()> {
|
#[must_use]
|
||||||
|
fn bind_port(&self, port: u16, can_reuse: bool) -> bool {
|
||||||
let mut used_ports = self.used_ports.write();
|
let mut used_ports = self.used_ports.write();
|
||||||
if let Some(used_times) = used_ports.get_mut(&port) {
|
if let Some(used_times) = used_ports.get_mut(&port) {
|
||||||
if *used_times == 0 || can_reuse {
|
if *used_times == 0 || can_reuse {
|
||||||
// FIXME: Check if the previous socket was bound with SO_REUSEADDR.
|
// FIXME: Check if the previous socket was bound with SO_REUSEADDR.
|
||||||
*used_times += 1;
|
*used_times += 1;
|
||||||
} else {
|
} else {
|
||||||
return_errno_with_message!(Errno::EADDRINUSE, "the address is already in use");
|
return false;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
used_ports.insert(port, 1);
|
used_ports.insert(port, 1);
|
||||||
}
|
}
|
||||||
Ok(())
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Release port number so the port can be used again. For reused port, the port may still be in use.
|
/// Release port number so the port can be used again. For reused port, the port may still be in use.
|
||||||
pub(super) fn release_port(&self, port: u16) {
|
pub(crate) fn release_port(&self, port: u16) {
|
||||||
let mut used_ports = self.used_ports.write();
|
let mut used_ports = self.used_ports.write();
|
||||||
if let Some(used_times) = used_ports.remove(&port) {
|
if let Some(used_times) = used_ports.remove(&port) {
|
||||||
if used_times != 1 {
|
if used_times != 1 {
|
||||||
@ -103,17 +110,17 @@ impl<E> IfaceCommon<E> {
|
|||||||
iface: Arc<dyn Iface<E>>,
|
iface: Arc<dyn Iface<E>>,
|
||||||
socket: Box<AnyUnboundSocket>,
|
socket: Box<AnyUnboundSocket>,
|
||||||
config: BindPortConfig,
|
config: BindPortConfig,
|
||||||
) -> core::result::Result<AnyBoundSocket<E>, (Error, Box<AnyUnboundSocket>)> {
|
) -> core::result::Result<AnyBoundSocket<E>, (BindError, Box<AnyUnboundSocket>)> {
|
||||||
let port = if let Some(port) = config.port() {
|
let port = if let Some(port) = config.port() {
|
||||||
port
|
port
|
||||||
} else {
|
} else {
|
||||||
match self.alloc_ephemeral_port() {
|
match self.alloc_ephemeral_port() {
|
||||||
Ok(port) => port,
|
Some(port) => port,
|
||||||
Err(err) => return Err((err, socket)),
|
None => return Err((BindError::Exhausted, socket)),
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
if let Some(err) = self.bind_port(port, config.can_reuse()).err() {
|
if !self.bind_port(port, config.can_reuse()) {
|
||||||
return Err((err, socket));
|
return Err((BindError::InUse, socket));
|
||||||
}
|
}
|
||||||
|
|
||||||
let (handle, socket_family, observer) = match socket.into_raw() {
|
let (handle, socket_family, observer) = match socket.into_raw() {
|
||||||
@ -135,7 +142,7 @@ impl<E> IfaceCommon<E> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Remove a socket from the interface
|
/// Remove a socket from the interface
|
||||||
pub(super) fn remove_socket(&self, handle: SocketHandle) {
|
pub(crate) fn remove_socket(&self, handle: SocketHandle) {
|
||||||
self.sockets.disable_irq().lock().remove(handle);
|
self.sockets.disable_irq().lock().remove(handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -209,7 +216,7 @@ impl<E> IfaceCommon<E> {
|
|||||||
assert!(inserted);
|
assert!(inserted);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn remove_bound_socket_now(&self, socket: &Arc<AnyBoundSocketInner<E>>) {
|
pub(crate) fn remove_bound_socket_now(&self, socket: &Arc<AnyBoundSocketInner<E>>) {
|
||||||
let keyable_socket = KeyableArc::from(socket.clone());
|
let keyable_socket = KeyableArc::from(socket.clone());
|
||||||
|
|
||||||
let removed = self
|
let removed = self
|
||||||
@ -219,7 +226,7 @@ impl<E> IfaceCommon<E> {
|
|||||||
assert!(removed);
|
assert!(removed);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn remove_bound_socket_when_closed(&self, socket: &Arc<AnyBoundSocketInner<E>>) {
|
pub(crate) fn remove_bound_socket_when_closed(&self, socket: &Arc<AnyBoundSocketInner<E>>) {
|
||||||
let keyable_socket = KeyableArc::from(socket.clone());
|
let keyable_socket = KeyableArc::from(socket.clone());
|
||||||
|
|
||||||
let removed = self
|
let removed = self
|
69
kernel/libs/aster-bigtcp/src/iface/iface.rs
Normal file
69
kernel/libs/aster-bigtcp/src/iface/iface.rs
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
use alloc::{boxed::Box, sync::Arc};
|
||||||
|
|
||||||
|
use smoltcp::wire::Ipv4Address;
|
||||||
|
|
||||||
|
use super::port::BindPortConfig;
|
||||||
|
use crate::{
|
||||||
|
errors::BindError,
|
||||||
|
socket::{AnyBoundSocket, AnyUnboundSocket},
|
||||||
|
};
|
||||||
|
|
||||||
|
/// A network interface.
|
||||||
|
///
|
||||||
|
/// A network interface (abbreviated as iface) is a hardware or software component that connects a
|
||||||
|
/// computer to a network. Network interfaces can be physical components like Ethernet ports or
|
||||||
|
/// wireless adapters. They can also be virtual interfaces created by software, such as virtual
|
||||||
|
/// private network (VPN) connections.
|
||||||
|
pub trait Iface<E>: internal::IfaceInternal<E> + Send + Sync {
|
||||||
|
/// Transmits or receives packets queued in the iface, and updates socket status accordingly.
|
||||||
|
///
|
||||||
|
/// The `schedule_next_poll` callback is invoked with the time at which the next poll should be
|
||||||
|
/// performed, or `None` if no next poll is required. It's up to the caller to determine the
|
||||||
|
/// mechanism to ensure that the next poll happens at the right time (e.g. by setting a timer).
|
||||||
|
fn raw_poll(&self, schedule_next_poll: &dyn Fn(Option<u64>));
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<E> dyn Iface<E> {
|
||||||
|
/// Gets the extension of the iface.
|
||||||
|
pub fn ext(&self) -> &E {
|
||||||
|
self.common().ext()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Binds a socket to the iface.
|
||||||
|
///
|
||||||
|
/// After binding the socket to the iface, the iface will handle all packets to and from the
|
||||||
|
/// socket.
|
||||||
|
///
|
||||||
|
/// If [`BindPortConfig::Ephemeral`] is specified, the iface will pick up an ephemeral port for
|
||||||
|
/// the socket.
|
||||||
|
///
|
||||||
|
/// FIXME: The reason for binding the socket and the iface together is because there are
|
||||||
|
/// limitations inside smoltcp. See discussion at
|
||||||
|
/// <https://github.com/smoltcp-rs/smoltcp/issues/779>.
|
||||||
|
pub fn bind_socket(
|
||||||
|
self: &Arc<Self>,
|
||||||
|
socket: Box<AnyUnboundSocket>,
|
||||||
|
config: BindPortConfig,
|
||||||
|
) -> core::result::Result<AnyBoundSocket<E>, (BindError, Box<AnyUnboundSocket>)> {
|
||||||
|
let common = self.common();
|
||||||
|
common.bind_socket(self.clone(), socket, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the IPv4 address of the iface, if any.
|
||||||
|
///
|
||||||
|
/// FIXME: One iface may have multiple IPv4 addresses.
|
||||||
|
pub fn ipv4_addr(&self) -> Option<Ipv4Address> {
|
||||||
|
self.common().ipv4_addr()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) mod internal {
|
||||||
|
use crate::iface::common::IfaceCommon;
|
||||||
|
|
||||||
|
/// An internal trait that abstracts the common part of different ifaces.
|
||||||
|
pub trait IfaceInternal<E> {
|
||||||
|
fn common(&self) -> &IfaceCommon<E>;
|
||||||
|
}
|
||||||
|
}
|
12
kernel/libs/aster-bigtcp/src/iface/mod.rs
Normal file
12
kernel/libs/aster-bigtcp/src/iface/mod.rs
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
mod common;
|
||||||
|
#[allow(clippy::module_inception)]
|
||||||
|
mod iface;
|
||||||
|
mod phy;
|
||||||
|
mod port;
|
||||||
|
mod time;
|
||||||
|
|
||||||
|
pub use iface::Iface;
|
||||||
|
pub use phy::{EtherIface, IpIface};
|
||||||
|
pub use port::BindPortConfig;
|
@ -1,17 +1,20 @@
|
|||||||
// SPDX-License-Identifier: MPL-2.0
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
pub use smoltcp::wire::EthernetAddress;
|
use alloc::sync::Arc;
|
||||||
|
|
||||||
|
use ostd::prelude::*;
|
||||||
use smoltcp::{
|
use smoltcp::{
|
||||||
iface::{Config, SocketHandle, SocketSet},
|
iface::{Config, SocketHandle, SocketSet},
|
||||||
socket::dhcpv4,
|
socket::dhcpv4,
|
||||||
wire::{self, IpCidr},
|
wire::{self, EthernetAddress, IpCidr},
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{
|
use crate::{
|
||||||
common::IfaceCommon, device::WithDevice, internal::IfaceInternal, time::get_network_timestamp,
|
device::WithDevice,
|
||||||
Iface,
|
iface::{
|
||||||
|
common::IfaceCommon, iface::internal::IfaceInternal, time::get_network_timestamp, Iface,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
use crate::prelude::*;
|
|
||||||
|
|
||||||
pub struct EtherIface<D: WithDevice, E> {
|
pub struct EtherIface<D: WithDevice, E> {
|
||||||
driver: D,
|
driver: D,
|
||||||
@ -51,18 +54,15 @@ impl<D: WithDevice, E> EtherIface<D, E> {
|
|||||||
pub fn process_dhcp(&self) {
|
pub fn process_dhcp(&self) {
|
||||||
let mut socket_set = self.common.sockets();
|
let mut socket_set = self.common.sockets();
|
||||||
let dhcp_socket: &mut dhcpv4::Socket = socket_set.get_mut(self.dhcp_handle);
|
let dhcp_socket: &mut dhcpv4::Socket = socket_set.get_mut(self.dhcp_handle);
|
||||||
let config = if let Some(event) = dhcp_socket.poll() {
|
|
||||||
debug!("event = {:?}", event);
|
let Some(dhcpv4::Event::Configured(config)) = dhcp_socket.poll() else {
|
||||||
if let dhcpv4::Event::Configured(config) = event {
|
|
||||||
config
|
|
||||||
} else {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
let ip_addr = IpCidr::Ipv4(config.address);
|
let ip_addr = IpCidr::Ipv4(config.address);
|
||||||
|
|
||||||
let mut interface = self.common.interface();
|
let mut interface = self.common.interface();
|
||||||
|
|
||||||
|
println!("[DHCP] Local IP address: {:?}", ip_addr,);
|
||||||
interface.update_ip_addrs(|ipaddrs| {
|
interface.update_ip_addrs(|ipaddrs| {
|
||||||
if let Some(addr) = ipaddrs.iter_mut().next() {
|
if let Some(addr) = ipaddrs.iter_mut().next() {
|
||||||
// already has ipaddrs
|
// already has ipaddrs
|
||||||
@ -72,12 +72,9 @@ impl<D: WithDevice, E> EtherIface<D, E> {
|
|||||||
ipaddrs.push(ip_addr).unwrap();
|
ipaddrs.push(ip_addr).unwrap();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
println!(
|
|
||||||
"DHCP update IP address: {:?}",
|
|
||||||
interface.ipv4_addr().unwrap()
|
|
||||||
);
|
|
||||||
if let Some(router) = config.router {
|
if let Some(router) = config.router {
|
||||||
println!("Default router address: {:?}", router);
|
println!("[DHCP] Router IP address: {:?}", router);
|
||||||
interface
|
interface
|
||||||
.routes_mut()
|
.routes_mut()
|
||||||
.add_default_ipv4_route(router)
|
.add_default_ipv4_route(router)
|
@ -1,10 +1,15 @@
|
|||||||
// SPDX-License-Identifier: MPL-2.0
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
use smoltcp::iface::Config;
|
use alloc::sync::Arc;
|
||||||
pub use smoltcp::wire::{IpAddress, IpCidr, Ipv4Address};
|
|
||||||
|
|
||||||
use super::{common::IfaceCommon, device::WithDevice, internal::IfaceInternal, Iface};
|
use smoltcp::{iface::Config, wire::IpCidr};
|
||||||
use crate::{net::iface::time::get_network_timestamp, prelude::*};
|
|
||||||
|
use crate::{
|
||||||
|
device::WithDevice,
|
||||||
|
iface::{
|
||||||
|
common::IfaceCommon, iface::internal::IfaceInternal, time::get_network_timestamp, Iface,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
pub struct IpIface<D: WithDevice, E> {
|
pub struct IpIface<D: WithDevice, E> {
|
||||||
driver: D,
|
driver: D,
|
7
kernel/libs/aster-bigtcp/src/iface/phy/mod.rs
Normal file
7
kernel/libs/aster-bigtcp/src/iface/phy/mod.rs
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
mod ether;
|
||||||
|
mod ip;
|
||||||
|
|
||||||
|
pub use ether::EtherIface;
|
||||||
|
pub use ip::IpIface;
|
42
kernel/libs/aster-bigtcp/src/iface/port.rs
Normal file
42
kernel/libs/aster-bigtcp/src/iface/port.rs
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
/// The configuration using for bind to a TCP/UDP port.
|
||||||
|
pub enum BindPortConfig {
|
||||||
|
/// Binds to the specified non-reusable port.
|
||||||
|
CanReuse(u16),
|
||||||
|
/// Binds to the specified reusable port.
|
||||||
|
Specified(u16),
|
||||||
|
/// Allocates an ephemeral port to bind.
|
||||||
|
Ephemeral,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BindPortConfig {
|
||||||
|
/// Creates new configuration using for bind to a TCP/UDP port.
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// This method will panic if `port` is zero (indicating that an ephemeral port should be
|
||||||
|
/// allocated) and `can_use` is true. This makes no sense because new ephemeral ports are
|
||||||
|
/// always not reused.
|
||||||
|
pub fn new(port: u16, can_reuse: bool) -> Self {
|
||||||
|
match (port, can_reuse) {
|
||||||
|
(0, _) => {
|
||||||
|
assert!(!can_reuse);
|
||||||
|
Self::Ephemeral
|
||||||
|
}
|
||||||
|
(_, true) => Self::CanReuse(port),
|
||||||
|
(_, false) => Self::Specified(port),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn can_reuse(&self) -> bool {
|
||||||
|
matches!(self, Self::CanReuse(_))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn port(&self) -> Option<u16> {
|
||||||
|
match self {
|
||||||
|
Self::CanReuse(port) | Self::Specified(port) => Some(*port),
|
||||||
|
Self::Ephemeral => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
23
kernel/libs/aster-bigtcp/src/lib.rs
Normal file
23
kernel/libs/aster-bigtcp/src/lib.rs
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
//! _bigtcp_ is a crate that wraps [`smoltcp`].
|
||||||
|
//!
|
||||||
|
//! [`smoltcp`] is designed for embedded systems where the number of sockets is always small. It
|
||||||
|
//! turns out that such a design cannot satisfy the need to implement the network stack of a
|
||||||
|
//! general-purpose OS kernel, in terms of flexibility and efficiency.
|
||||||
|
//!
|
||||||
|
//! The short-term goal of _bigtcp_ is to reuse the powerful TCP implementation of _smoltcp_, while
|
||||||
|
//! reimplementing Ethernet and IP protocols to increase the flexibility and performance of packet
|
||||||
|
//! dispatching.
|
||||||
|
|
||||||
|
#![no_std]
|
||||||
|
#![deny(unsafe_code)]
|
||||||
|
#![feature(btree_extract_if)]
|
||||||
|
|
||||||
|
pub mod device;
|
||||||
|
pub mod errors;
|
||||||
|
pub mod iface;
|
||||||
|
pub mod socket;
|
||||||
|
pub mod wire;
|
||||||
|
|
||||||
|
extern crate alloc;
|
@ -1,77 +1,30 @@
|
|||||||
// SPDX-License-Identifier: MPL-2.0
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
use super::{ext::IfaceExt, Iface};
|
use alloc::sync::{Arc, Weak};
|
||||||
use crate::{
|
|
||||||
events::Observer,
|
use ostd::sync::RwLock;
|
||||||
net::socket::ip::{IpAddress, IpEndpoint},
|
use smoltcp::{
|
||||||
prelude::*,
|
socket::tcp::ConnectError,
|
||||||
|
wire::{IpAddress, IpEndpoint},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub type RawTcpSocket = smoltcp::socket::tcp::Socket<'static>;
|
use super::{event::SocketEventObserver, RawTcpSocket, RawUdpSocket};
|
||||||
pub type RawUdpSocket = smoltcp::socket::udp::Socket<'static>;
|
use crate::iface::Iface;
|
||||||
|
|
||||||
pub struct AnyUnboundSocket {
|
pub(crate) enum SocketFamily {
|
||||||
socket_family: AnyRawSocket,
|
|
||||||
observer: Weak<dyn Observer<()>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(clippy::large_enum_variant)]
|
|
||||||
pub(super) enum AnyRawSocket {
|
|
||||||
Tcp(RawTcpSocket),
|
|
||||||
Udp(RawUdpSocket),
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(super) enum SocketFamily {
|
|
||||||
Tcp,
|
Tcp,
|
||||||
Udp,
|
Udp,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AnyUnboundSocket {
|
pub struct AnyBoundSocket<E>(Arc<AnyBoundSocketInner<E>>);
|
||||||
pub fn new_tcp(observer: Weak<dyn Observer<()>>) -> Self {
|
|
||||||
let raw_tcp_socket = {
|
|
||||||
let rx_buffer = smoltcp::socket::tcp::SocketBuffer::new(vec![0u8; TCP_RECV_BUF_LEN]);
|
|
||||||
let tx_buffer = smoltcp::socket::tcp::SocketBuffer::new(vec![0u8; TCP_SEND_BUF_LEN]);
|
|
||||||
RawTcpSocket::new(rx_buffer, tx_buffer)
|
|
||||||
};
|
|
||||||
AnyUnboundSocket {
|
|
||||||
socket_family: AnyRawSocket::Tcp(raw_tcp_socket),
|
|
||||||
observer,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn new_udp(observer: Weak<dyn Observer<()>>) -> Self {
|
|
||||||
let raw_udp_socket = {
|
|
||||||
let metadata = smoltcp::socket::udp::PacketMetadata::EMPTY;
|
|
||||||
let rx_buffer = smoltcp::socket::udp::PacketBuffer::new(
|
|
||||||
vec![metadata; UDP_METADATA_LEN],
|
|
||||||
vec![0u8; UDP_RECV_PAYLOAD_LEN],
|
|
||||||
);
|
|
||||||
let tx_buffer = smoltcp::socket::udp::PacketBuffer::new(
|
|
||||||
vec![metadata; UDP_METADATA_LEN],
|
|
||||||
vec![0u8; UDP_SEND_PAYLOAD_LEN],
|
|
||||||
);
|
|
||||||
RawUdpSocket::new(rx_buffer, tx_buffer)
|
|
||||||
};
|
|
||||||
AnyUnboundSocket {
|
|
||||||
socket_family: AnyRawSocket::Udp(raw_udp_socket),
|
|
||||||
observer,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(super) fn into_raw(self) -> (AnyRawSocket, Weak<dyn Observer<()>>) {
|
|
||||||
(self.socket_family, self.observer)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct AnyBoundSocket<E = IfaceExt>(Arc<AnyBoundSocketInner<E>>);
|
|
||||||
|
|
||||||
impl<E> AnyBoundSocket<E> {
|
impl<E> AnyBoundSocket<E> {
|
||||||
pub(super) fn new(
|
pub(crate) fn new(
|
||||||
iface: Arc<dyn Iface<E>>,
|
iface: Arc<dyn Iface<E>>,
|
||||||
handle: smoltcp::iface::SocketHandle,
|
handle: smoltcp::iface::SocketHandle,
|
||||||
port: u16,
|
port: u16,
|
||||||
socket_family: SocketFamily,
|
socket_family: SocketFamily,
|
||||||
observer: Weak<dyn Observer<()>>,
|
observer: Weak<dyn SocketEventObserver>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self(Arc::new(AnyBoundSocketInner {
|
Self(Arc::new(AnyBoundSocketInner {
|
||||||
iface,
|
iface,
|
||||||
@ -82,18 +35,18 @@ impl<E> AnyBoundSocket<E> {
|
|||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn inner(&self) -> &Arc<AnyBoundSocketInner<E>> {
|
pub(crate) fn inner(&self) -> &Arc<AnyBoundSocketInner<E>> {
|
||||||
&self.0
|
&self.0
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the observer whose `on_events` will be called when certain iface events happen. After
|
/// Sets the observer whose `on_events` will be called when certain iface events happen. After
|
||||||
/// setting, the new observer will fire once immediately to avoid missing any events.
|
/// setting, the new observer will fire once immediately to avoid missing any events.
|
||||||
///
|
///
|
||||||
/// If there is an existing observer, due to race conditions, this function does not guarantee
|
/// If there is an existing observer, due to race conditions, this function does not guarantee
|
||||||
/// that the old observer will never be called after the setting. Users should be aware of this
|
/// that the old observer will never be called after the setting. Users should be aware of this
|
||||||
/// and proactively handle the race conditions if necessary.
|
/// and proactively handle the race conditions if necessary.
|
||||||
pub fn set_observer(&self, handler: Weak<dyn Observer<()>>) {
|
pub fn set_observer(&self, new_observer: Weak<dyn SocketEventObserver>) {
|
||||||
*self.0.observer.write() = handler;
|
*self.0.observer.write() = new_observer;
|
||||||
|
|
||||||
self.0.on_iface_events();
|
self.0.on_iface_events();
|
||||||
}
|
}
|
||||||
@ -118,7 +71,7 @@ impl<E> AnyBoundSocket<E> {
|
|||||||
/// # Panics
|
/// # Panics
|
||||||
///
|
///
|
||||||
/// This method will panic if the socket is not a TCP socket.
|
/// This method will panic if the socket is not a TCP socket.
|
||||||
pub fn do_connect(&self, remote_endpoint: IpEndpoint) -> Result<()> {
|
pub fn do_connect(&self, remote_endpoint: IpEndpoint) -> Result<(), ConnectError> {
|
||||||
let common = self.iface().common();
|
let common = self.iface().common();
|
||||||
|
|
||||||
let mut sockets = common.sockets();
|
let mut sockets = common.sockets();
|
||||||
@ -127,21 +80,7 @@ impl<E> AnyBoundSocket<E> {
|
|||||||
let mut iface = common.interface();
|
let mut iface = common.interface();
|
||||||
let cx = iface.context();
|
let cx = iface.context();
|
||||||
|
|
||||||
// The only reason this method might fail is because we're trying to connect to an
|
socket.connect(cx, remote_endpoint, self.0.port)
|
||||||
// unspecified address (i.e. 0.0.0.0). We currently have no support for binding to,
|
|
||||||
// listening on, or connecting to the unspecified address.
|
|
||||||
//
|
|
||||||
// We assume the remote will just refuse to connect, so we return `ECONNREFUSED`.
|
|
||||||
socket
|
|
||||||
.connect(cx, remote_endpoint, self.0.port)
|
|
||||||
.map_err(|_| {
|
|
||||||
Error::with_message(
|
|
||||||
Errno::ECONNREFUSED,
|
|
||||||
"connecting to an unspecified address is not supported",
|
|
||||||
)
|
|
||||||
})?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn iface(&self) -> &Arc<dyn Iface<E>> {
|
pub fn iface(&self) -> &Arc<dyn Iface<E>> {
|
||||||
@ -162,22 +101,22 @@ impl<E> Drop for AnyBoundSocket<E> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) struct AnyBoundSocketInner<E> {
|
pub(crate) struct AnyBoundSocketInner<E> {
|
||||||
iface: Arc<dyn Iface<E>>,
|
iface: Arc<dyn Iface<E>>,
|
||||||
handle: smoltcp::iface::SocketHandle,
|
handle: smoltcp::iface::SocketHandle,
|
||||||
port: u16,
|
port: u16,
|
||||||
socket_family: SocketFamily,
|
socket_family: SocketFamily,
|
||||||
observer: RwLock<Weak<dyn Observer<()>>>,
|
observer: RwLock<Weak<dyn SocketEventObserver>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<E> AnyBoundSocketInner<E> {
|
impl<E> AnyBoundSocketInner<E> {
|
||||||
pub(super) fn on_iface_events(&self) {
|
pub(crate) fn on_iface_events(&self) {
|
||||||
if let Some(observer) = Weak::upgrade(&*self.observer.read()) {
|
if let Some(observer) = Weak::upgrade(&*self.observer.read()) {
|
||||||
observer.on_events(&())
|
observer.on_events();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn is_closed(&self) -> bool {
|
pub(crate) fn is_closed(&self) -> bool {
|
||||||
match self.socket_family {
|
match self.socket_family {
|
||||||
SocketFamily::Tcp => self.raw_with(|socket: &mut RawTcpSocket| {
|
SocketFamily::Tcp => self.raw_with(|socket: &mut RawTcpSocket| {
|
||||||
socket.state() == smoltcp::socket::tcp::State::Closed
|
socket.state() == smoltcp::socket::tcp::State::Closed
|
||||||
@ -225,12 +164,3 @@ impl<E> Drop for AnyBoundSocketInner<E> {
|
|||||||
iface_common.release_port(self.port);
|
iface_common.release_port(self.port);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// For TCP
|
|
||||||
pub const TCP_RECV_BUF_LEN: usize = 65536;
|
|
||||||
pub const TCP_SEND_BUF_LEN: usize = 65536;
|
|
||||||
|
|
||||||
// For UDP
|
|
||||||
pub const UDP_SEND_PAYLOAD_LEN: usize = 65536;
|
|
||||||
pub const UDP_RECV_PAYLOAD_LEN: usize = 65536;
|
|
||||||
const UDP_METADATA_LEN: usize = 256;
|
|
11
kernel/libs/aster-bigtcp/src/socket/event.rs
Normal file
11
kernel/libs/aster-bigtcp/src/socket/event.rs
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
/// A observer that will be invoked whenever events occur on the socket.
|
||||||
|
pub trait SocketEventObserver: Send + Sync {
|
||||||
|
/// Notifies that events occurred on the socket.
|
||||||
|
fn on_events(&self);
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SocketEventObserver for () {
|
||||||
|
fn on_events(&self) {}
|
||||||
|
}
|
17
kernel/libs/aster-bigtcp/src/socket/mod.rs
Normal file
17
kernel/libs/aster-bigtcp/src/socket/mod.rs
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
mod bound;
|
||||||
|
mod event;
|
||||||
|
mod unbound;
|
||||||
|
|
||||||
|
pub use bound::AnyBoundSocket;
|
||||||
|
pub(crate) use bound::{AnyBoundSocketInner, SocketFamily};
|
||||||
|
pub use event::SocketEventObserver;
|
||||||
|
pub(crate) use unbound::AnyRawSocket;
|
||||||
|
pub use unbound::{
|
||||||
|
AnyUnboundSocket, TCP_RECV_BUF_LEN, TCP_SEND_BUF_LEN, UDP_RECV_PAYLOAD_LEN,
|
||||||
|
UDP_SEND_PAYLOAD_LEN,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub type RawTcpSocket = smoltcp::socket::tcp::Socket<'static>;
|
||||||
|
pub type RawUdpSocket = smoltcp::socket::udp::Socket<'static>;
|
62
kernel/libs/aster-bigtcp/src/socket/unbound.rs
Normal file
62
kernel/libs/aster-bigtcp/src/socket/unbound.rs
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
use alloc::{sync::Weak, vec};
|
||||||
|
|
||||||
|
use super::{event::SocketEventObserver, RawTcpSocket, RawUdpSocket};
|
||||||
|
|
||||||
|
pub struct AnyUnboundSocket {
|
||||||
|
socket_family: AnyRawSocket,
|
||||||
|
observer: Weak<dyn SocketEventObserver>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::large_enum_variant)]
|
||||||
|
pub(crate) enum AnyRawSocket {
|
||||||
|
Tcp(RawTcpSocket),
|
||||||
|
Udp(RawUdpSocket),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AnyUnboundSocket {
|
||||||
|
pub fn new_tcp(observer: Weak<dyn SocketEventObserver>) -> Self {
|
||||||
|
let raw_tcp_socket = {
|
||||||
|
let rx_buffer = smoltcp::socket::tcp::SocketBuffer::new(vec![0u8; TCP_RECV_BUF_LEN]);
|
||||||
|
let tx_buffer = smoltcp::socket::tcp::SocketBuffer::new(vec![0u8; TCP_SEND_BUF_LEN]);
|
||||||
|
RawTcpSocket::new(rx_buffer, tx_buffer)
|
||||||
|
};
|
||||||
|
AnyUnboundSocket {
|
||||||
|
socket_family: AnyRawSocket::Tcp(raw_tcp_socket),
|
||||||
|
observer,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_udp(observer: Weak<dyn SocketEventObserver>) -> Self {
|
||||||
|
let raw_udp_socket = {
|
||||||
|
let metadata = smoltcp::socket::udp::PacketMetadata::EMPTY;
|
||||||
|
let rx_buffer = smoltcp::socket::udp::PacketBuffer::new(
|
||||||
|
vec![metadata; UDP_METADATA_LEN],
|
||||||
|
vec![0u8; UDP_RECV_PAYLOAD_LEN],
|
||||||
|
);
|
||||||
|
let tx_buffer = smoltcp::socket::udp::PacketBuffer::new(
|
||||||
|
vec![metadata; UDP_METADATA_LEN],
|
||||||
|
vec![0u8; UDP_SEND_PAYLOAD_LEN],
|
||||||
|
);
|
||||||
|
RawUdpSocket::new(rx_buffer, tx_buffer)
|
||||||
|
};
|
||||||
|
AnyUnboundSocket {
|
||||||
|
socket_family: AnyRawSocket::Udp(raw_udp_socket),
|
||||||
|
observer,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn into_raw(self) -> (AnyRawSocket, Weak<dyn SocketEventObserver>) {
|
||||||
|
(self.socket_family, self.observer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// For TCP
|
||||||
|
pub const TCP_RECV_BUF_LEN: usize = 65536;
|
||||||
|
pub const TCP_SEND_BUF_LEN: usize = 65536;
|
||||||
|
|
||||||
|
// For UDP
|
||||||
|
pub const UDP_SEND_PAYLOAD_LEN: usize = 65536;
|
||||||
|
pub const UDP_RECV_PAYLOAD_LEN: usize = 65536;
|
||||||
|
const UDP_METADATA_LEN: usize = 256;
|
5
kernel/libs/aster-bigtcp/src/wire.rs
Normal file
5
kernel/libs/aster-bigtcp/src/wire.rs
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
pub use smoltcp::wire::{EthernetAddress, IpAddress, IpCidr, IpEndpoint, Ipv4Address, Ipv4Cidr};
|
||||||
|
|
||||||
|
pub type PortNum = u16;
|
@ -67,7 +67,7 @@ pub trait IfaceEx {
|
|||||||
fn poll(&self);
|
fn poll(&self);
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IfaceEx for dyn Iface<IfaceExt> {
|
impl IfaceEx for Iface {
|
||||||
fn name(&self) -> &str {
|
fn name(&self) -> &str {
|
||||||
&self.ext().name
|
&self.ext().name
|
||||||
}
|
}
|
||||||
|
@ -2,19 +2,17 @@
|
|||||||
|
|
||||||
use alloc::{borrow::ToOwned, sync::Arc};
|
use alloc::{borrow::ToOwned, sync::Arc};
|
||||||
|
|
||||||
|
use aster_bigtcp::device::WithDevice;
|
||||||
use ostd::sync::PreemptDisabled;
|
use ostd::sync::PreemptDisabled;
|
||||||
use spin::Once;
|
use spin::Once;
|
||||||
|
|
||||||
use super::{spawn_background_poll_thread, Iface};
|
use super::{poll_ifaces, Iface};
|
||||||
use crate::{
|
use crate::{
|
||||||
net::iface::{
|
net::iface::ext::{IfaceEx, IfaceExt},
|
||||||
device::WithDevice,
|
|
||||||
ext::{IfaceEx, IfaceExt},
|
|
||||||
},
|
|
||||||
prelude::*,
|
prelude::*,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub static IFACES: Once<Vec<Arc<dyn Iface>>> = Once::new();
|
pub static IFACES: Once<Vec<Arc<Iface>>> = Once::new();
|
||||||
|
|
||||||
pub fn init() {
|
pub fn init() {
|
||||||
IFACES.call_once(|| {
|
IFACES.call_once(|| {
|
||||||
@ -34,12 +32,11 @@ pub fn init() {
|
|||||||
poll_ifaces();
|
poll_ifaces();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new_virtio() -> Arc<dyn Iface> {
|
fn new_virtio() -> Arc<Iface> {
|
||||||
|
use aster_bigtcp::{iface::EtherIface, wire::EthernetAddress};
|
||||||
use aster_network::AnyNetworkDevice;
|
use aster_network::AnyNetworkDevice;
|
||||||
use aster_virtio::device::network::DEVICE_NAME;
|
use aster_virtio::device::network::DEVICE_NAME;
|
||||||
|
|
||||||
use super::ether::{EtherIface, EthernetAddress};
|
|
||||||
|
|
||||||
let virtio_net = aster_network::get_device(DEVICE_NAME).unwrap();
|
let virtio_net = aster_network::get_device(DEVICE_NAME).unwrap();
|
||||||
|
|
||||||
let ether_addr = virtio_net.disable_irq().lock().mac_addr().0;
|
let ether_addr = virtio_net.disable_irq().lock().mac_addr().0;
|
||||||
@ -65,10 +62,12 @@ fn new_virtio() -> Arc<dyn Iface> {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new_loopback() -> Arc<dyn Iface> {
|
fn new_loopback() -> Arc<Iface> {
|
||||||
use smoltcp::phy::{Loopback, Medium};
|
use aster_bigtcp::{
|
||||||
|
device::{Loopback, Medium},
|
||||||
use super::ip::{IpAddress, IpCidr, IpIface, Ipv4Address};
|
iface::IpIface,
|
||||||
|
wire::{IpAddress, IpCidr, Ipv4Address},
|
||||||
|
};
|
||||||
|
|
||||||
const LOOPBACK_ADDRESS: IpAddress = {
|
const LOOPBACK_ADDRESS: IpAddress = {
|
||||||
let ipv4_addr = Ipv4Address::new(127, 0, 0, 1);
|
let ipv4_addr = Ipv4Address::new(127, 0, 0, 1);
|
||||||
@ -96,17 +95,3 @@ fn new_loopback() -> Arc<dyn Iface> {
|
|||||||
IfaceExt::new("lo".to_owned()),
|
IfaceExt::new("lo".to_owned()),
|
||||||
) as _
|
) as _
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn lazy_init() {
|
|
||||||
for iface in IFACES.get().unwrap() {
|
|
||||||
spawn_background_poll_thread(iface.clone());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn poll_ifaces() {
|
|
||||||
let ifaces = IFACES.get().unwrap();
|
|
||||||
|
|
||||||
for iface in ifaces.iter() {
|
|
||||||
iface.poll();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -1,82 +1,11 @@
|
|||||||
// SPDX-License-Identifier: MPL-2.0
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
use self::common::IfaceCommon;
|
|
||||||
use crate::prelude::*;
|
|
||||||
|
|
||||||
mod any_socket;
|
|
||||||
mod common;
|
|
||||||
mod device;
|
|
||||||
mod ether;
|
|
||||||
mod ext;
|
mod ext;
|
||||||
mod init;
|
mod init;
|
||||||
mod ip;
|
mod poll;
|
||||||
mod time;
|
|
||||||
mod util;
|
|
||||||
|
|
||||||
pub use any_socket::{
|
pub use init::{init, IFACES};
|
||||||
AnyBoundSocket, AnyUnboundSocket, RawTcpSocket, RawUdpSocket, TCP_RECV_BUF_LEN,
|
pub use poll::{lazy_init, poll_ifaces};
|
||||||
TCP_SEND_BUF_LEN, UDP_RECV_PAYLOAD_LEN, UDP_SEND_PAYLOAD_LEN,
|
|
||||||
};
|
|
||||||
pub use init::{init, lazy_init, poll_ifaces, IFACES};
|
|
||||||
pub use smoltcp::wire::EthernetAddress;
|
|
||||||
pub use util::{spawn_background_poll_thread, BindPortConfig};
|
|
||||||
|
|
||||||
use crate::net::socket::ip::Ipv4Address;
|
pub type Iface = dyn aster_bigtcp::iface::Iface<ext::IfaceExt>;
|
||||||
|
pub type AnyBoundSocket = aster_bigtcp::socket::AnyBoundSocket<ext::IfaceExt>;
|
||||||
/// A network interface.
|
|
||||||
///
|
|
||||||
/// A network interface (abbreviated as iface) is a hardware or software component that connects a
|
|
||||||
/// computer to a network. Network interfaces can be physical components like Ethernet ports or
|
|
||||||
/// wireless adapters. They can also be virtual interfaces created by software, such as virtual
|
|
||||||
/// private network (VPN) connections.
|
|
||||||
pub trait Iface<E = ext::IfaceExt>: internal::IfaceInternal<E> + Send + Sync {
|
|
||||||
/// Transmits or receives packets queued in the iface, and updates socket status accordingly.
|
|
||||||
///
|
|
||||||
/// The `schedule_next_poll` callback is invoked with the time at which the next poll should be
|
|
||||||
/// performed, or `None` if no next poll is required. It's up to the caller to determine the
|
|
||||||
/// mechanism to ensure that the next poll happens at the right time (e.g. by setting a timer).
|
|
||||||
fn raw_poll(&self, schedule_next_poll: &dyn Fn(Option<u64>));
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<E> dyn Iface<E> {
|
|
||||||
/// Gets the extension of the iface.
|
|
||||||
pub fn ext(&self) -> &E {
|
|
||||||
self.common().ext()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Binds a socket to the iface.
|
|
||||||
///
|
|
||||||
/// After binding the socket to the iface, the iface will handle all packets to and from the
|
|
||||||
/// socket.
|
|
||||||
///
|
|
||||||
/// If [`BindPortConfig::Ephemeral`] is specified, the iface will pick up an ephemeral port for
|
|
||||||
/// the socket.
|
|
||||||
///
|
|
||||||
/// FIXME: The reason for binding the socket and the iface together is because there are
|
|
||||||
/// limitations inside smoltcp. See discussion at
|
|
||||||
/// <https://github.com/smoltcp-rs/smoltcp/issues/779>.
|
|
||||||
pub fn bind_socket(
|
|
||||||
self: &Arc<Self>,
|
|
||||||
socket: Box<AnyUnboundSocket>,
|
|
||||||
config: BindPortConfig,
|
|
||||||
) -> core::result::Result<AnyBoundSocket<E>, (Error, Box<AnyUnboundSocket>)> {
|
|
||||||
let common = self.common();
|
|
||||||
common.bind_socket(self.clone(), socket, config)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Gets the IPv4 address of the iface, if any.
|
|
||||||
///
|
|
||||||
/// FIXME: One iface may have multiple IPv4 addresses.
|
|
||||||
pub fn ipv4_addr(&self) -> Option<Ipv4Address> {
|
|
||||||
self.common().ipv4_addr()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mod internal {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
/// An internal trait that abstracts the common part of different ifaces.
|
|
||||||
pub trait IfaceInternal<E> {
|
|
||||||
fn common(&self) -> &IfaceCommon<E>;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -1,53 +1,35 @@
|
|||||||
// SPDX-License-Identifier: MPL-2.0
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
use alloc::sync::Arc;
|
||||||
use core::time::Duration;
|
use core::time::Duration;
|
||||||
|
|
||||||
|
use log::trace;
|
||||||
use ostd::{arch::timer::Jiffies, task::Priority};
|
use ostd::{arch::timer::Jiffies, task::Priority};
|
||||||
|
|
||||||
use super::{ext::IfaceEx, Iface};
|
use super::{ext::IfaceEx, Iface, IFACES};
|
||||||
use crate::{
|
use crate::{
|
||||||
prelude::*,
|
|
||||||
thread::{
|
thread::{
|
||||||
kernel_thread::{KernelThreadExt, ThreadOptions},
|
kernel_thread::{KernelThreadExt, ThreadOptions},
|
||||||
Thread,
|
Thread,
|
||||||
},
|
},
|
||||||
|
WaitTimeout,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub enum BindPortConfig {
|
pub fn lazy_init() {
|
||||||
CanReuse(u16),
|
for iface in IFACES.get().unwrap() {
|
||||||
Specified(u16),
|
spawn_background_poll_thread(iface.clone());
|
||||||
Ephemeral,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl BindPortConfig {
|
|
||||||
pub fn new(port: u16, can_reuse: bool) -> Result<Self> {
|
|
||||||
let config = if port != 0 {
|
|
||||||
if can_reuse {
|
|
||||||
Self::CanReuse(port)
|
|
||||||
} else {
|
|
||||||
Self::Specified(port)
|
|
||||||
}
|
|
||||||
} else if can_reuse {
|
|
||||||
return_errno_with_message!(Errno::EINVAL, "invalid bind port config");
|
|
||||||
} else {
|
|
||||||
Self::Ephemeral
|
|
||||||
};
|
|
||||||
Ok(config)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(super) fn can_reuse(&self) -> bool {
|
|
||||||
matches!(self, Self::CanReuse(_))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(super) fn port(&self) -> Option<u16> {
|
|
||||||
match self {
|
|
||||||
Self::CanReuse(port) | Self::Specified(port) => Some(*port),
|
|
||||||
Self::Ephemeral => None,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn spawn_background_poll_thread(iface: Arc<dyn Iface>) {
|
pub fn poll_ifaces() {
|
||||||
|
let ifaces = IFACES.get().unwrap();
|
||||||
|
|
||||||
|
for iface in ifaces.iter() {
|
||||||
|
iface.poll();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn spawn_background_poll_thread(iface: Arc<Iface>) {
|
||||||
let task_fn = move || {
|
let task_fn = move || {
|
||||||
trace!("spawn background poll thread for {}", iface.name());
|
trace!("spawn background poll thread for {}", iface.name());
|
||||||
|
|
@ -1,11 +1,9 @@
|
|||||||
// SPDX-License-Identifier: MPL-2.0
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
pub use smoltcp::wire::{IpAddress, IpEndpoint, Ipv4Address};
|
use aster_bigtcp::wire::{IpAddress, IpEndpoint, Ipv4Address};
|
||||||
|
|
||||||
use crate::{net::socket::SocketAddr, prelude::*, return_errno_with_message};
|
use crate::{net::socket::SocketAddr, prelude::*, return_errno_with_message};
|
||||||
|
|
||||||
pub type PortNum = u16;
|
|
||||||
|
|
||||||
impl TryFrom<SocketAddr> for IpEndpoint {
|
impl TryFrom<SocketAddr> for IpEndpoint {
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
|
|
||||||
@ -29,3 +27,11 @@ impl From<IpEndpoint> for SocketAddr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A local endpoint, which indicates that the local endpoint is unspecified.
|
||||||
|
///
|
||||||
|
/// According to the Linux man pages and the Linux implementation, `getsockname()` will _not_ fail
|
||||||
|
/// even if the socket is unbound. Instead, it will return an unspecified socket address. This
|
||||||
|
/// unspecified endpoint helps with that.
|
||||||
|
pub(super) const UNSPECIFIED_LOCAL_ENDPOINT: IpEndpoint =
|
||||||
|
IpEndpoint::new(IpAddress::Ipv4(Ipv4Address::UNSPECIFIED), 0);
|
||||||
|
@ -1,12 +1,18 @@
|
|||||||
// SPDX-License-Identifier: MPL-2.0
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
use super::{IpAddress, IpEndpoint};
|
use aster_bigtcp::{
|
||||||
|
errors::BindError,
|
||||||
|
iface::BindPortConfig,
|
||||||
|
socket::AnyUnboundSocket,
|
||||||
|
wire::{IpAddress, IpEndpoint},
|
||||||
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
net::iface::{AnyBoundSocket, AnyUnboundSocket, BindPortConfig, Iface, IFACES},
|
net::iface::{AnyBoundSocket, Iface, IFACES},
|
||||||
prelude::*,
|
prelude::*,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn get_iface_to_bind(ip_addr: &IpAddress) -> Option<Arc<dyn Iface>> {
|
pub(super) fn get_iface_to_bind(ip_addr: &IpAddress) -> Option<Arc<Iface>> {
|
||||||
let ifaces = IFACES.get().unwrap();
|
let ifaces = IFACES.get().unwrap();
|
||||||
let IpAddress::Ipv4(ipv4_addr) = ip_addr;
|
let IpAddress::Ipv4(ipv4_addr) = ip_addr;
|
||||||
ifaces
|
ifaces
|
||||||
@ -24,7 +30,7 @@ pub fn get_iface_to_bind(ip_addr: &IpAddress) -> Option<Arc<dyn Iface>> {
|
|||||||
/// Get a suitable iface to deal with sendto/connect request if the socket is not bound to an iface.
|
/// Get a suitable iface to deal with sendto/connect request if the socket is not bound to an iface.
|
||||||
/// If the remote address is the same as that of some iface, we will use the iface.
|
/// If the remote address is the same as that of some iface, we will use the iface.
|
||||||
/// Otherwise, we will use a default interface.
|
/// Otherwise, we will use a default interface.
|
||||||
fn get_ephemeral_iface(remote_ip_addr: &IpAddress) -> Arc<dyn Iface> {
|
fn get_ephemeral_iface(remote_ip_addr: &IpAddress) -> Arc<Iface> {
|
||||||
let ifaces = IFACES.get().unwrap();
|
let ifaces = IFACES.get().unwrap();
|
||||||
let IpAddress::Ipv4(remote_ipv4_addr) = remote_ip_addr;
|
let IpAddress::Ipv4(remote_ipv4_addr) = remote_ip_addr;
|
||||||
if let Some(iface) = ifaces.iter().find(|iface| {
|
if let Some(iface) = ifaces.iter().find(|iface| {
|
||||||
@ -48,18 +54,35 @@ pub(super) fn bind_socket(
|
|||||||
let iface = match get_iface_to_bind(&endpoint.addr) {
|
let iface = match get_iface_to_bind(&endpoint.addr) {
|
||||||
Some(iface) => iface,
|
Some(iface) => iface,
|
||||||
None => {
|
None => {
|
||||||
let err = Error::with_message(Errno::EADDRNOTAVAIL, "Request iface is not available");
|
let err = Error::with_message(
|
||||||
|
Errno::EADDRNOTAVAIL,
|
||||||
|
"the address is not available from the local machine",
|
||||||
|
);
|
||||||
return Err((err, unbound_socket));
|
return Err((err, unbound_socket));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let bind_port_config = match BindPortConfig::new(endpoint.port, can_reuse) {
|
|
||||||
Ok(config) => config,
|
let bind_port_config = BindPortConfig::new(endpoint.port, can_reuse);
|
||||||
Err(e) => return Err((e, unbound_socket)),
|
|
||||||
};
|
iface
|
||||||
iface.bind_socket(unbound_socket, bind_port_config)
|
.bind_socket(unbound_socket, bind_port_config)
|
||||||
|
.map_err(|(err, unbound)| (err.into(), unbound))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_ephemeral_endpoint(remote_endpoint: &IpEndpoint) -> IpEndpoint {
|
impl From<BindError> for Error {
|
||||||
|
fn from(value: BindError) -> Self {
|
||||||
|
match value {
|
||||||
|
BindError::Exhausted => {
|
||||||
|
Error::with_message(Errno::EAGAIN, "no ephemeral port is available")
|
||||||
|
}
|
||||||
|
BindError::InUse => {
|
||||||
|
Error::with_message(Errno::EADDRINUSE, "the address is already in use")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn get_ephemeral_endpoint(remote_endpoint: &IpEndpoint) -> IpEndpoint {
|
||||||
let iface = get_ephemeral_iface(&remote_endpoint.addr);
|
let iface = get_ephemeral_iface(&remote_endpoint.addr);
|
||||||
let ip_addr = iface.ipv4_addr().unwrap();
|
let ip_addr = iface.ipv4_addr().unwrap();
|
||||||
IpEndpoint::new(IpAddress::Ipv4(ip_addr), 0)
|
IpEndpoint::new(IpAddress::Ipv4(ip_addr), 0)
|
||||||
|
@ -1,14 +1,14 @@
|
|||||||
// SPDX-License-Identifier: MPL-2.0
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
use smoltcp::socket::udp::{RecvError, SendError};
|
use aster_bigtcp::{
|
||||||
|
errors::udp::{RecvError, SendError},
|
||||||
|
socket::RawUdpSocket,
|
||||||
|
wire::IpEndpoint,
|
||||||
|
};
|
||||||
|
|
||||||
use super::IpEndpoint;
|
|
||||||
use crate::{
|
use crate::{
|
||||||
events::IoEvents,
|
events::IoEvents,
|
||||||
net::{
|
net::{iface::AnyBoundSocket, socket::util::send_recv_flags::SendRecvFlags},
|
||||||
iface::{AnyBoundSocket, RawUdpSocket},
|
|
||||||
socket::util::send_recv_flags::SendRecvFlags,
|
|
||||||
},
|
|
||||||
prelude::*,
|
prelude::*,
|
||||||
process::signal::Pollee,
|
process::signal::Pollee,
|
||||||
};
|
};
|
||||||
|
@ -2,10 +2,11 @@
|
|||||||
|
|
||||||
use core::sync::atomic::{AtomicBool, Ordering};
|
use core::sync::atomic::{AtomicBool, Ordering};
|
||||||
|
|
||||||
|
use aster_bigtcp::{socket::SocketEventObserver, wire::IpEndpoint};
|
||||||
use takeable::Takeable;
|
use takeable::Takeable;
|
||||||
|
|
||||||
use self::{bound::BoundDatagram, unbound::UnboundDatagram};
|
use self::{bound::BoundDatagram, unbound::UnboundDatagram};
|
||||||
use super::{common::get_ephemeral_endpoint, IpEndpoint, UNSPECIFIED_LOCAL_ENDPOINT};
|
use super::{common::get_ephemeral_endpoint, UNSPECIFIED_LOCAL_ENDPOINT};
|
||||||
use crate::{
|
use crate::{
|
||||||
events::{IoEvents, Observer},
|
events::{IoEvents, Observer},
|
||||||
fs::{file_handle::FileLike, utils::StatusFlags},
|
fs::{file_handle::FileLike, utils::StatusFlags},
|
||||||
@ -393,8 +394,8 @@ impl Socket for DatagramSocket {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Observer<()> for DatagramSocket {
|
impl SocketEventObserver for DatagramSocket {
|
||||||
fn on_events(&self, _events: &()) {
|
fn on_events(&self) {
|
||||||
self.update_io_events();
|
self.update_io_events();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,15 +2,14 @@
|
|||||||
|
|
||||||
use alloc::sync::Weak;
|
use alloc::sync::Weak;
|
||||||
|
|
||||||
use super::{bound::BoundDatagram, IpEndpoint};
|
use aster_bigtcp::{
|
||||||
|
socket::{AnyUnboundSocket, RawUdpSocket, SocketEventObserver},
|
||||||
|
wire::IpEndpoint,
|
||||||
|
};
|
||||||
|
|
||||||
|
use super::bound::BoundDatagram;
|
||||||
use crate::{
|
use crate::{
|
||||||
events::{IoEvents, Observer},
|
events::IoEvents, net::socket::ip::common::bind_socket, prelude::*, process::signal::Pollee,
|
||||||
net::{
|
|
||||||
iface::{AnyUnboundSocket, RawUdpSocket},
|
|
||||||
socket::ip::common::bind_socket,
|
|
||||||
},
|
|
||||||
prelude::*,
|
|
||||||
process::signal::Pollee,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct UnboundDatagram {
|
pub struct UnboundDatagram {
|
||||||
@ -18,7 +17,7 @@ pub struct UnboundDatagram {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl UnboundDatagram {
|
impl UnboundDatagram {
|
||||||
pub fn new(observer: Weak<dyn Observer<()>>) -> Self {
|
pub fn new(observer: Weak<dyn SocketEventObserver>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
unbound_socket: Box::new(AnyUnboundSocket::new_udp(observer)),
|
unbound_socket: Box::new(AnyUnboundSocket::new_udp(observer)),
|
||||||
}
|
}
|
||||||
|
@ -5,14 +5,6 @@ mod common;
|
|||||||
mod datagram;
|
mod datagram;
|
||||||
pub mod stream;
|
pub mod stream;
|
||||||
|
|
||||||
pub use addr::{IpAddress, IpEndpoint, Ipv4Address, PortNum};
|
use addr::UNSPECIFIED_LOCAL_ENDPOINT;
|
||||||
pub use datagram::DatagramSocket;
|
pub use datagram::DatagramSocket;
|
||||||
pub use stream::StreamSocket;
|
pub use stream::StreamSocket;
|
||||||
|
|
||||||
/// A local endpoint, which indicates that the local endpoint is unspecified.
|
|
||||||
///
|
|
||||||
/// According to the Linux man pages and the Linux implementation, `getsockname()` will _not_ fail
|
|
||||||
/// even if the socket is unbound. Instead, it will return an unspecified socket address. This
|
|
||||||
/// unspecified endpoint helps with that.
|
|
||||||
const UNSPECIFIED_LOCAL_ENDPOINT: IpEndpoint =
|
|
||||||
IpEndpoint::new(IpAddress::Ipv4(Ipv4Address::UNSPECIFIED), 0);
|
|
||||||
|
@ -2,13 +2,16 @@
|
|||||||
|
|
||||||
use alloc::sync::Weak;
|
use alloc::sync::Weak;
|
||||||
|
|
||||||
use smoltcp::socket::tcp::{RecvError, SendError};
|
use aster_bigtcp::{
|
||||||
|
errors::tcp::{RecvError, SendError},
|
||||||
|
socket::{RawTcpSocket, SocketEventObserver},
|
||||||
|
wire::IpEndpoint,
|
||||||
|
};
|
||||||
|
|
||||||
use super::IpEndpoint;
|
|
||||||
use crate::{
|
use crate::{
|
||||||
events::{IoEvents, Observer},
|
events::IoEvents,
|
||||||
net::{
|
net::{
|
||||||
iface::{AnyBoundSocket, RawTcpSocket},
|
iface::AnyBoundSocket,
|
||||||
socket::util::{send_recv_flags::SendRecvFlags, shutdown_cmd::SockShutdownCmd},
|
socket::util::{send_recv_flags::SendRecvFlags, shutdown_cmd::SockShutdownCmd},
|
||||||
},
|
},
|
||||||
prelude::*,
|
prelude::*,
|
||||||
@ -122,7 +125,7 @@ impl ConnectedStream {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn set_observer(&self, observer: Weak<dyn Observer<()>>) {
|
pub(super) fn set_observer(&self, observer: Weak<dyn SocketEventObserver>) {
|
||||||
self.bound_socket.set_observer(observer)
|
self.bound_socket.set_observer(observer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,9 @@
|
|||||||
// SPDX-License-Identifier: MPL-2.0
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
use super::{connected::ConnectedStream, init::InitStream, IpEndpoint};
|
use aster_bigtcp::{socket::RawTcpSocket, wire::IpEndpoint};
|
||||||
use crate::{
|
|
||||||
net::iface::{AnyBoundSocket, RawTcpSocket},
|
use super::{connected::ConnectedStream, init::InitStream};
|
||||||
prelude::*,
|
use crate::{net::iface::AnyBoundSocket, prelude::*, process::signal::Pollee};
|
||||||
process::signal::Pollee,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub struct ConnectingStream {
|
pub struct ConnectingStream {
|
||||||
bound_socket: AnyBoundSocket,
|
bound_socket: AnyBoundSocket,
|
||||||
@ -29,9 +27,21 @@ impl ConnectingStream {
|
|||||||
bound_socket: AnyBoundSocket,
|
bound_socket: AnyBoundSocket,
|
||||||
remote_endpoint: IpEndpoint,
|
remote_endpoint: IpEndpoint,
|
||||||
) -> core::result::Result<Self, (Error, AnyBoundSocket)> {
|
) -> core::result::Result<Self, (Error, AnyBoundSocket)> {
|
||||||
if let Err(err) = bound_socket.do_connect(remote_endpoint) {
|
// The only reason this method might fail is because we're trying to connect to an
|
||||||
return Err((err, bound_socket));
|
// unspecified address (i.e. 0.0.0.0). We currently have no support for binding to,
|
||||||
|
// listening on, or connecting to the unspecified address.
|
||||||
|
//
|
||||||
|
// We assume the remote will just refuse to connect, so we return `ECONNREFUSED`.
|
||||||
|
if bound_socket.do_connect(remote_endpoint).is_err() {
|
||||||
|
return Err((
|
||||||
|
Error::with_message(
|
||||||
|
Errno::ECONNREFUSED,
|
||||||
|
"connecting to an unspecified address is not supported",
|
||||||
|
),
|
||||||
|
bound_socket,
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
bound_socket,
|
bound_socket,
|
||||||
remote_endpoint,
|
remote_endpoint,
|
||||||
|
@ -2,11 +2,16 @@
|
|||||||
|
|
||||||
use alloc::sync::Weak;
|
use alloc::sync::Weak;
|
||||||
|
|
||||||
use super::{connecting::ConnectingStream, listen::ListenStream, IpEndpoint};
|
use aster_bigtcp::{
|
||||||
|
socket::{AnyUnboundSocket, SocketEventObserver},
|
||||||
|
wire::IpEndpoint,
|
||||||
|
};
|
||||||
|
|
||||||
|
use super::{connecting::ConnectingStream, listen::ListenStream};
|
||||||
use crate::{
|
use crate::{
|
||||||
events::{IoEvents, Observer},
|
events::IoEvents,
|
||||||
net::{
|
net::{
|
||||||
iface::{AnyBoundSocket, AnyUnboundSocket},
|
iface::AnyBoundSocket,
|
||||||
socket::ip::common::{bind_socket, get_ephemeral_endpoint},
|
socket::ip::common::{bind_socket, get_ephemeral_endpoint},
|
||||||
},
|
},
|
||||||
prelude::*,
|
prelude::*,
|
||||||
@ -19,7 +24,7 @@ pub enum InitStream {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl InitStream {
|
impl InitStream {
|
||||||
pub fn new(observer: Weak<dyn Observer<()>>) -> Self {
|
pub fn new(observer: Weak<dyn SocketEventObserver>) -> Self {
|
||||||
InitStream::Unbound(Box::new(AnyUnboundSocket::new_tcp(observer)))
|
InitStream::Unbound(Box::new(AnyUnboundSocket::new_tcp(observer)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,15 +1,15 @@
|
|||||||
// SPDX-License-Identifier: MPL-2.0
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
use smoltcp::socket::tcp::ListenError;
|
use aster_bigtcp::{
|
||||||
|
errors::tcp::ListenError,
|
||||||
use super::{connected::ConnectedStream, IpEndpoint};
|
iface::BindPortConfig,
|
||||||
use crate::{
|
socket::{AnyUnboundSocket, RawTcpSocket},
|
||||||
events::IoEvents,
|
wire::IpEndpoint,
|
||||||
net::iface::{AnyBoundSocket, AnyUnboundSocket, BindPortConfig, RawTcpSocket},
|
|
||||||
prelude::*,
|
|
||||||
process::signal::Pollee,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use super::connected::ConnectedStream;
|
||||||
|
use crate::{events::IoEvents, net::iface::AnyBoundSocket, prelude::*, process::signal::Pollee};
|
||||||
|
|
||||||
pub struct ListenStream {
|
pub struct ListenStream {
|
||||||
backlog: usize,
|
backlog: usize,
|
||||||
/// A bound socket held to ensure the TCP port cannot be released
|
/// A bound socket held to ensure the TCP port cannot be released
|
||||||
@ -117,7 +117,7 @@ impl BacklogSocket {
|
|||||||
let unbound_socket = Box::new(AnyUnboundSocket::new_tcp(Weak::<()>::new()));
|
let unbound_socket = Box::new(AnyUnboundSocket::new_tcp(Weak::<()>::new()));
|
||||||
let bound_socket = {
|
let bound_socket = {
|
||||||
let iface = bound_socket.iface();
|
let iface = bound_socket.iface();
|
||||||
let bind_port_config = BindPortConfig::new(local_endpoint.port, true)?;
|
let bind_port_config = BindPortConfig::new(local_endpoint.port, true);
|
||||||
iface
|
iface
|
||||||
.bind_socket(unbound_socket, bind_port_config)
|
.bind_socket(unbound_socket, bind_port_config)
|
||||||
.map_err(|(err, _)| err)?
|
.map_err(|(err, _)| err)?
|
||||||
|
@ -2,12 +2,12 @@
|
|||||||
|
|
||||||
use core::sync::atomic::{AtomicBool, Ordering};
|
use core::sync::atomic::{AtomicBool, Ordering};
|
||||||
|
|
||||||
|
use aster_bigtcp::{socket::SocketEventObserver, wire::IpEndpoint};
|
||||||
use connected::ConnectedStream;
|
use connected::ConnectedStream;
|
||||||
use connecting::ConnectingStream;
|
use connecting::ConnectingStream;
|
||||||
use init::InitStream;
|
use init::InitStream;
|
||||||
use listen::ListenStream;
|
use listen::ListenStream;
|
||||||
use options::{Congestion, MaxSegment, NoDelay, WindowClamp};
|
use options::{Congestion, MaxSegment, NoDelay, WindowClamp};
|
||||||
use smoltcp::wire::IpEndpoint;
|
|
||||||
use takeable::Takeable;
|
use takeable::Takeable;
|
||||||
use util::{TcpOptionSet, DEFAULT_MAXSEG};
|
use util::{TcpOptionSet, DEFAULT_MAXSEG};
|
||||||
|
|
||||||
@ -647,8 +647,8 @@ impl Socket for StreamSocket {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Observer<()> for StreamSocket {
|
impl SocketEventObserver for StreamSocket {
|
||||||
fn on_events(&self, _events: &()) {
|
fn on_events(&self) {
|
||||||
let conn_ready = self.update_io_events();
|
let conn_ready = self.update_io_events();
|
||||||
|
|
||||||
if conn_ready {
|
if conn_ready {
|
||||||
|
@ -2,13 +2,14 @@
|
|||||||
|
|
||||||
use core::time::Duration;
|
use core::time::Duration;
|
||||||
|
|
||||||
|
use aster_bigtcp::socket::{
|
||||||
|
TCP_RECV_BUF_LEN, TCP_SEND_BUF_LEN, UDP_RECV_PAYLOAD_LEN, UDP_SEND_PAYLOAD_LEN,
|
||||||
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
match_sock_option_mut, match_sock_option_ref,
|
match_sock_option_mut, match_sock_option_ref,
|
||||||
net::{
|
net::socket::options::{
|
||||||
iface::{TCP_RECV_BUF_LEN, TCP_SEND_BUF_LEN, UDP_RECV_PAYLOAD_LEN, UDP_SEND_PAYLOAD_LEN},
|
Error as SocketError, Linger, RecvBuf, ReuseAddr, ReusePort, SendBuf, SocketOption,
|
||||||
socket::options::{
|
|
||||||
Error as SocketError, Linger, RecvBuf, ReuseAddr, ReusePort, SendBuf, SocketOption,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
prelude::*,
|
prelude::*,
|
||||||
};
|
};
|
||||||
|
@ -1,11 +1,9 @@
|
|||||||
// SPDX-License-Identifier: MPL-2.0
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
use aster_bigtcp::wire::{Ipv4Address, PortNum};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
net::socket::{
|
net::socket::{unix::UnixSocketAddr, vsock::addr::VsockSocketAddr},
|
||||||
ip::{Ipv4Address, PortNum},
|
|
||||||
unix::UnixSocketAddr,
|
|
||||||
vsock::addr::VsockSocketAddr,
|
|
||||||
},
|
|
||||||
prelude::*,
|
prelude::*,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,10 +1,9 @@
|
|||||||
// SPDX-License-Identifier: MPL-2.0
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
use aster_bigtcp::wire::{Ipv4Address, PortNum};
|
||||||
|
|
||||||
use super::family::CSocketAddrFamily;
|
use super::family::CSocketAddrFamily;
|
||||||
use crate::{
|
use crate::prelude::*;
|
||||||
net::socket::ip::{Ipv4Address, PortNum},
|
|
||||||
prelude::*,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// IPv4 socket address.
|
/// IPv4 socket address.
|
||||||
///
|
///
|
||||||
|
Loading…
x
Reference in New Issue
Block a user