Commit 3d2f86b3 authored by Jeremy Soller's avatar Jeremy Soller

Merge branch 'feature/support-af-unix-sockets' into 'master'

Support AF_UNIX sockets

See merge request !255
parents 662051a9 76f07b16
Pipeline #6950 failed with stages
in 19 minutes and 20 seconds
......@@ -2,6 +2,6 @@ use crate::{header::sys_socket::sa_family_t, platform::types::*};
#[repr(C)]
pub struct sockaddr_un {
sun_family: sa_family_t,
sun_path: [c_char; 108],
pub sun_family: sa_family_t,
pub sun_path: [c_char; 108],
}
use core::{mem, ptr, slice};
use core::{mem, ptr, slice, str};
use syscall::{self, flag::*, Result};
use super::{
......@@ -9,6 +9,7 @@ use crate::header::{
netinet_in::{in_port_t, sockaddr_in},
sys_socket::{constants::*, sockaddr, socklen_t},
sys_time::timeval,
sys_un::sockaddr_un,
};
macro_rules! bind_or_connect {
......@@ -29,28 +30,48 @@ macro_rules! bind_or_connect {
0
}};
($mode:ident copy, $socket:expr, $address:expr, $address_len:expr) => {{
if (*$address).sa_family as c_int != AF_INET {
errno = syscall::EAFNOSUPPORT;
return -1;
}
if ($address_len as usize) < mem::size_of::<sockaddr>() {
errno = syscall::EINVAL;
return -1;
}
let data = &*($address as *const sockaddr_in);
let addr = slice::from_raw_parts(
&data.sin_addr.s_addr as *const _ as *const u8,
mem::size_of_val(&data.sin_addr.s_addr),
);
let port = in_port_t::from_be(data.sin_port);
let path = format!(
bind_or_connect!($mode "{}.{}.{}.{}:{}"),
addr[0],
addr[1],
addr[2],
addr[3],
port
);
let path = match (*$address).sa_family as c_int {
AF_INET => {
let data = &*($address as *const sockaddr_in);
let addr = slice::from_raw_parts(
&data.sin_addr.s_addr as *const _ as *const u8,
mem::size_of_val(&data.sin_addr.s_addr),
);
let port = in_port_t::from_be(data.sin_port);
let path = format!(
bind_or_connect!($mode "{}.{}.{}.{}:{}"),
addr[0],
addr[1],
addr[2],
addr[3],
port
);
path
},
AF_UNIX => {
let data = &*($address as *const sockaddr_un);
let addr = slice::from_raw_parts(
&data.sun_path as *const _ as *const u8,
mem::size_of_val(&data.sun_path),
);
let path = format!(
"{}",
str::from_utf8(addr).unwrap()
);
path
},
_ => {
errno = syscall::EAFNOSUPPORT;
return -1;
},
};
// Duplicate the socket, and then duplicate the copy back to the original fd
let fd = e(syscall::dup($socket as usize, path.as_bytes()));
......@@ -61,21 +82,28 @@ macro_rules! bind_or_connect {
}};
}
unsafe fn inner_get_name(
unsafe fn inner_af_unix(buf: &[u8], address: *mut sockaddr, address_len: *mut socklen_t) {
let data = &mut *(address as *mut sockaddr_un);
data.sun_family = AF_UNIX as c_ushort;
let path = slice::from_raw_parts_mut(
&mut data.sun_path as *mut _ as *mut u8,
mem::size_of_val(&data.sun_path),
);
let len = path.len().min(buf.len());
path[..len].copy_from_slice(&buf[..len]);
*address_len = len as socklen_t;
}
unsafe fn inner_af_inet(
local: bool,
socket: c_int,
buf: &[u8],
address: *mut sockaddr,
address_len: *mut socklen_t,
) -> Result<usize> {
// 32 should probably be large enough.
// Format: tcp:remote/local
// and since we only yet support IPv4 (I think)...
let mut buf = [0; 32];
let len = syscall::fpath(socket as usize, &mut buf)?;
let buf = &buf[..len];
assert!(&buf[..4] == b"tcp:" || &buf[..4] == b"udp:");
let buf = &buf[4..];
) {
let mut parts = buf.split(|c| *c == b'/');
if local {
// Skip the remote part
......@@ -96,6 +124,32 @@ unsafe fn inner_get_name(
data[..len].copy_from_slice(&part[..len]);
*address_len = len as socklen_t;
}
unsafe fn inner_get_name(
local: bool,
socket: c_int,
address: *mut sockaddr,
address_len: *mut socklen_t,
) -> Result<usize> {
// 32 should probably be large enough.
// Format: [udp|tcp:]remote/local, chan:path
let mut buf = [0; 32];
let len = syscall::fpath(socket as usize, &mut buf)?;
let buf = &buf[..len];
assert!(&buf[..4] == b"tcp:" || &buf[..4] == b"udp:" || &buf[..5] == b"chan:");
match &buf[..5] {
b"tcp:" | b"udp:" => {
inner_af_inet(local, &buf[4..], address, address_len);
}
b"chan:" => {
inner_af_unix(&buf[5..], address, address_len);
}
// Socket doesn't belong to any scheme
_ => panic!("socket doesn't match either tcp, udp or chan schemes"),
};
Ok(0)
}
......@@ -292,7 +346,7 @@ impl PalSocket for Sys {
}
unsafe fn socket(domain: c_int, mut kind: c_int, protocol: c_int) -> c_int {
if domain != AF_INET {
if domain != AF_INET && domain != AF_UNIX {
errno = syscall::EAFNOSUPPORT;
return -1;
}
......@@ -313,9 +367,10 @@ impl PalSocket for Sys {
// The tcp: and udp: schemes allow using no path,
// and later specifying one using `dup`.
match kind {
SOCK_STREAM => e(syscall::open("tcp:", flags)) as c_int,
SOCK_DGRAM => e(syscall::open("udp:", flags)) as c_int,
match (domain, kind) {
(AF_INET, SOCK_STREAM) => e(syscall::open("tcp:", flags)) as c_int,
(AF_INET, SOCK_DGRAM) => e(syscall::open("udp:", flags)) as c_int,
(AF_UNIX, SOCK_STREAM) => e(syscall::open("chan:", flags | O_CREAT)) as c_int,
_ => {
errno = syscall::EPROTONOSUPPORT;
-1
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment