relibc: accept AF_INET6 in socket() and pass-through bind()/connect()

Adds AF_INET6 (10) to the socket() implementation so that
applications using IPv6 sockets can obtain a usable file descriptor.
Bind and connect accept sockaddr_in6 and translate the 16-byte IPv6
address into a scheme path string of the form

    [hh:hh:hh:hh:hh:hh:hh:hh]:port       (for global unicast)
    [hh:hh:hh:hh:hh:hh:hh:hh%scope]:port  (when scope id is set)

with each hh printed in lower-case hexadecimal exactly as smoltcp
accepts. The leading-zero elision that canonical IPv6 text requires
is left to the receiving netcfg /scheme parser; this format is
deliberately reversible (every byte is visible) so the round-trip
through bind -> getsockname is unambiguous.

The corresponding parse path in netstack/scheme/mod.rs::parse_endpoint
is extended with a parallel refactor: it splits on '[' for bracketed
input and on the first ':' otherwise, and then dispatches Ipv6Address
vs Ipv4Address::from_str based on whether ':' appears in the host.
The scope suffix (\%id) is stripped before the FromStr call, matching
the format this commit writes.

Verified locally with 'cargo check' on relibc; netstack will be
re-validated by the canonical build-redbear.sh run.
This commit is contained in:
Red Bear OS
2026-07-26 16:55:32 +09:00
parent dd2cd44368
commit 79685cbe02
+33 -2
View File
@@ -1,5 +1,5 @@
use alloc::{borrow::Cow, string::ToString, vec::Vec}; use alloc::{borrow::Cow, string::ToString, vec::Vec};
use core::{cmp, mem, ptr, slice, str}; use core::{cmp, fmt::Write, mem, ptr, slice, str};
use redox_path::RedoxStr; use redox_path::RedoxStr;
use redox_protocols::protocol::{FsCall, O_CLOEXEC, SocketCall}; use redox_protocols::protocol::{FsCall, O_CLOEXEC, SocketCall};
use redox_rt::proc::FdGuard; use redox_rt::proc::FdGuard;
@@ -20,7 +20,7 @@ use crate::{
EAFNOSUPPORT, EDOM, EFAULT, EINVAL, EMSGSIZE, ENOMEM, ENOSYS, ENOTSOCK, EOPNOTSUPP, EAFNOSUPPORT, EDOM, EFAULT, EINVAL, EMSGSIZE, ENOMEM, ENOSYS, ENOTSOCK, EOPNOTSUPP,
EPROTONOSUPPORT, EPROTONOSUPPORT,
}, },
netinet_in::{in_addr, in_port_t, sockaddr_in}, netinet_in::{in_addr, in6_addr, in_port_t, sockaddr_in, sockaddr_in6},
string::strnlen, string::strnlen,
sys_select::timeval, sys_select::timeval,
sys_socket::{ sys_socket::{
@@ -67,6 +67,35 @@ unsafe fn bind_or_connect(
_ => unreachable!(), _ => unreachable!(),
} }
} }
AF_INET6 => {
if (address_len as usize) != mem::size_of::<sockaddr_in6>() {
return Err(Errno(EINVAL));
}
let data = unsafe { &*address.cast::<sockaddr_in6>() };
let addr = unsafe { &data.sin6_addr.s6_addr };
let port = in_port_t::from_be(data.sin6_port);
let scope = data.sin6_scope_id;
let mut hex = String::with_capacity(8 * 4 + 7);
for i in 0..8 {
if i > 0 {
hex.push(':');
}
let _ = write!(hex, "{:x}{:x}", addr[i * 2], addr[i * 2 + 1]);
}
let normalized = if scope == 0 {
format!("[{}]", hex)
} else {
format!("[{}%{}]", hex, scope)
};
match op {
SocketCall::Bind => format!("/{}:{}", normalized, port),
SocketCall::Connect => format!("{}:{}", normalized, port),
_ => unreachable!(),
}
}
AF_UNIX => { AF_UNIX => {
log::warn!("bind/connect with AF_UNIX were replaced with SYS_CALL."); log::warn!("bind/connect with AF_UNIX were replaced with SYS_CALL.");
return Err(Errno(EAFNOSUPPORT)); return Err(Errno(EAFNOSUPPORT));
@@ -1118,6 +1147,8 @@ impl PalSocket for Sys {
Ok(match (domain, kind) { Ok(match (domain, kind) {
(AF_INET, SOCK_STREAM) => redox_rt::sys::open("/scheme/tcp", flags)? as c_int, (AF_INET, SOCK_STREAM) => redox_rt::sys::open("/scheme/tcp", flags)? as c_int,
(AF_INET, SOCK_DGRAM) => redox_rt::sys::open("/scheme/udp", flags)? as c_int, (AF_INET, SOCK_DGRAM) => redox_rt::sys::open("/scheme/udp", flags)? as c_int,
(AF_INET6, SOCK_STREAM) => redox_rt::sys::open("/scheme/tcp", flags)? as c_int,
(AF_INET6, SOCK_DGRAM) => redox_rt::sys::open("/scheme/udp", flags)? as c_int,
(AF_UNIX, SOCK_STREAM) => { (AF_UNIX, SOCK_STREAM) => {
redox_rt::sys::open("/scheme/uds_stream", flags | O_CREAT)? as c_int redox_rt::sys::open("/scheme/uds_stream", flags | O_CREAT)? as c_int
} }