Move networking system call interfaces to net module

This commit is contained in:
He Sun 2020-05-28 17:41:06 +08:00
parent ed664d1143
commit 987e06a458
2 changed files with 350 additions and 344 deletions

@ -8,6 +8,351 @@ use std::convert::TryFrom;
use time::timeval_t; use time::timeval_t;
use util::mem_util::from_user; use util::mem_util::from_user;
pub fn do_socket(domain: c_int, socket_type: c_int, protocol: c_int) -> Result<isize> {
debug!(
"socket: domain: {}, socket_type: 0x{:x}, protocol: {}",
domain, socket_type, protocol
);
let file_ref: Arc<Box<dyn File>> = match domain {
libc::AF_LOCAL => {
let unix_socket = UnixSocketFile::new(socket_type, protocol)?;
Arc::new(Box::new(unix_socket))
}
_ => {
let socket = SocketFile::new(domain, socket_type, protocol)?;
Arc::new(Box::new(socket))
}
};
let fd = current!().add_file(file_ref, false);
Ok(fd as isize)
}
pub fn do_connect(
fd: c_int,
addr: *const libc::sockaddr,
addr_len: libc::socklen_t,
) -> Result<isize> {
debug!(
"connect: fd: {}, addr: {:?}, addr_len: {}",
fd, addr, addr_len
);
// For SOCK_DGRAM sockets not initiated in connection-mode,
// if address is a null address for the protocol,
// the socket's peer address shall be reset.
let need_check: bool = !addr.is_null();
if need_check {
from_user::check_array(addr as *const u8, addr_len as usize)?;
}
let file_ref = current!().file(fd as FileDesc)?;
if let Ok(socket) = file_ref.as_socket() {
if need_check {
from_user::check_ptr(addr as *const libc::sockaddr_in)?;
}
let ret = try_libc!(libc::ocall::connect(socket.fd(), addr, addr_len));
Ok(ret as isize)
} else if let Ok(unix_socket) = file_ref.as_unix_socket() {
let addr = addr as *const libc::sockaddr_un;
from_user::check_ptr(addr)?;
let path = from_user::clone_cstring_safely(unsafe { (&*addr).sun_path.as_ptr() })?
.to_string_lossy()
.into_owned();
unix_socket.connect(path)?;
Ok(0)
} else {
return_errno!(EBADF, "not a socket")
}
}
pub fn do_accept(
fd: c_int,
addr: *mut libc::sockaddr,
addr_len: *mut libc::socklen_t,
) -> Result<isize> {
do_accept4(fd, addr, addr_len, 0)
}
pub fn do_accept4(
fd: c_int,
addr: *mut libc::sockaddr,
addr_len: *mut libc::socklen_t,
flags: c_int,
) -> Result<isize> {
debug!(
"accept4: fd: {}, addr: {:?}, addr_len: {:?}, flags: {:#x}",
fd, addr, addr_len, flags
);
let need_check: bool = !addr.is_null();
if addr.is_null() ^ addr_len.is_null() {
return_errno!(EINVAL, "addr and ddr_len should be both null");
}
if need_check {
from_user::check_mut_array(addr as *mut u8, unsafe { *addr_len } as usize)?;
}
let file_ref = current!().file(fd as FileDesc)?;
if let Ok(socket) = file_ref.as_socket() {
if need_check {
from_user::check_mut_ptr(addr as *mut libc::sockaddr_in)?;
}
let new_socket = socket.accept(addr, addr_len, flags)?;
let new_file_ref: Arc<Box<dyn File>> = Arc::new(Box::new(new_socket));
let new_fd = current!().add_file(new_file_ref, false);
Ok(new_fd as isize)
} else if let Ok(unix_socket) = file_ref.as_unix_socket() {
let addr = addr as *mut libc::sockaddr_un;
if need_check {
from_user::check_mut_ptr(addr)?;
}
// TODO: handle addr
let new_socket = unix_socket.accept()?;
let new_file_ref: Arc<Box<dyn File>> = Arc::new(Box::new(new_socket));
let new_fd = current!().add_file(new_file_ref, false);
Ok(new_fd as isize)
} else {
return_errno!(EBADF, "not a socket")
}
}
pub fn do_shutdown(fd: c_int, how: c_int) -> Result<isize> {
debug!("shutdown: fd: {}, how: {}", fd, how);
let file_ref = current!().file(fd as FileDesc)?;
if let Ok(socket) = file_ref.as_socket() {
let ret = try_libc!(libc::ocall::shutdown(socket.fd(), how));
Ok(ret as isize)
} else {
return_errno!(EBADF, "not a socket")
}
}
pub fn do_bind(fd: c_int, addr: *const libc::sockaddr, addr_len: libc::socklen_t) -> Result<isize> {
debug!("bind: fd: {}, addr: {:?}, addr_len: {}", fd, addr, addr_len);
if addr.is_null() && addr_len == 0 {
return_errno!(EINVAL, "no address is specified");
}
from_user::check_array(addr as *const u8, addr_len as usize)?;
let file_ref = current!().file(fd as FileDesc)?;
if let Ok(socket) = file_ref.as_socket() {
from_user::check_ptr(addr as *const libc::sockaddr_in)?;
let ret = try_libc!(libc::ocall::bind(socket.fd(), addr, addr_len));
Ok(ret as isize)
} else if let Ok(unix_socket) = file_ref.as_unix_socket() {
let addr = addr as *const libc::sockaddr_un;
from_user::check_ptr(addr)?;
let path = from_user::clone_cstring_safely(unsafe { (&*addr).sun_path.as_ptr() })?
.to_string_lossy()
.into_owned();
unix_socket.bind(path)?;
Ok(0)
} else {
return_errno!(EBADF, "not a socket")
}
}
pub fn do_listen(fd: c_int, backlog: c_int) -> Result<isize> {
debug!("listen: fd: {}, backlog: {}", fd, backlog);
let file_ref = current!().file(fd as FileDesc)?;
if let Ok(socket) = file_ref.as_socket() {
let ret = try_libc!(libc::ocall::listen(socket.fd(), backlog));
Ok(ret as isize)
} else if let Ok(unix_socket) = file_ref.as_unix_socket() {
unix_socket.listen()?;
Ok(0)
} else {
return_errno!(EBADF, "not a socket")
}
}
pub fn do_setsockopt(
fd: c_int,
level: c_int,
optname: c_int,
optval: *const c_void,
optlen: libc::socklen_t,
) -> Result<isize> {
debug!(
"setsockopt: fd: {}, level: {}, optname: {}, optval: {:?}, optlen: {:?}",
fd, level, optname, optval, optlen
);
let file_ref = current!().file(fd as FileDesc)?;
if let Ok(socket) = file_ref.as_socket() {
let ret = try_libc!(libc::ocall::setsockopt(
socket.fd(),
level,
optname,
optval,
optlen
));
Ok(ret as isize)
} else if let Ok(unix_socket) = file_ref.as_unix_socket() {
warn!("setsockopt for unix socket is unimplemented");
Ok(0)
} else {
return_errno!(EBADF, "not a socket")
}
}
pub fn do_getsockopt(
fd: c_int,
level: c_int,
optname: c_int,
optval: *mut c_void,
optlen: *mut libc::socklen_t,
) -> Result<isize> {
debug!(
"getsockopt: fd: {}, level: {}, optname: {}, optval: {:?}, optlen: {:?}",
fd, level, optname, optval, optlen
);
let file_ref = current!().file(fd as FileDesc)?;
let socket = file_ref.as_socket()?;
let ret = try_libc!(libc::ocall::getsockopt(
socket.fd(),
level,
optname,
optval,
optlen
));
Ok(ret as isize)
}
pub fn do_getpeername(
fd: c_int,
addr: *mut libc::sockaddr,
addr_len: *mut libc::socklen_t,
) -> Result<isize> {
debug!(
"getpeername: fd: {}, addr: {:?}, addr_len: {:?}",
fd, addr, addr_len
);
let file_ref = current!().file(fd as FileDesc)?;
if let Ok(socket) = file_ref.as_socket() {
let ret = try_libc!(libc::ocall::getpeername(socket.fd(), addr, addr_len));
Ok(ret as isize)
} else if let Ok(unix_socket) = file_ref.as_unix_socket() {
warn!("getpeername for unix socket is unimplemented");
return_errno!(
ENOTCONN,
"hack for php: Transport endpoint is not connected"
)
} else {
return_errno!(EBADF, "not a socket")
}
}
pub fn do_getsockname(
fd: c_int,
addr: *mut libc::sockaddr,
addr_len: *mut libc::socklen_t,
) -> Result<isize> {
debug!(
"getsockname: fd: {}, addr: {:?}, addr_len: {:?}",
fd, addr, addr_len
);
let file_ref = current!().file(fd as FileDesc)?;
if let Ok(socket) = file_ref.as_socket() {
let ret = try_libc!(libc::ocall::getsockname(socket.fd(), addr, addr_len));
Ok(ret as isize)
} else if let Ok(unix_socket) = file_ref.as_unix_socket() {
warn!("getsockname for unix socket is unimplemented");
Ok(0)
} else {
return_errno!(EBADF, "not a socket")
}
}
pub fn do_sendto(
fd: c_int,
base: *const c_void,
len: size_t,
flags: c_int,
addr: *const libc::sockaddr,
addr_len: libc::socklen_t,
) -> Result<isize> {
debug!(
"sendto: fd: {}, base: {:?}, len: {}, addr: {:?}, addr_len: {}",
fd, base, len, addr, addr_len
);
let file_ref = current!().file(fd as FileDesc)?;
let socket = file_ref.as_socket()?;
let ret = try_libc!(libc::ocall::sendto(
socket.fd(),
base,
len,
flags,
addr,
addr_len
));
Ok(ret as isize)
}
pub fn do_recvfrom(
fd: c_int,
base: *mut c_void,
len: size_t,
flags: c_int,
addr: *mut libc::sockaddr,
addr_len: *mut libc::socklen_t,
) -> Result<isize> {
debug!(
"recvfrom: fd: {}, base: {:?}, len: {}, flags: {}, addr: {:?}, addr_len: {:?}",
fd, base, len, flags, addr, addr_len
);
let file_ref = current!().file(fd as FileDesc)?;
let socket = file_ref.as_socket()?;
let ret = try_libc!(libc::ocall::recvfrom(
socket.fd(),
base,
len,
flags,
addr,
addr_len
));
Ok(ret as isize)
}
pub fn do_socketpair(
domain: c_int,
socket_type: c_int,
protocol: c_int,
sv: *mut c_int,
) -> Result<isize> {
debug!(
"socketpair: domain: {}, type:0x{:x}, protocol: {}",
domain, socket_type, protocol
);
let mut sock_pair = unsafe {
from_user::check_mut_array(sv, 2)?;
std::slice::from_raw_parts_mut(sv as *mut u32, 2)
};
if (domain == libc::AF_UNIX) {
let (client_socket, server_socket) =
UnixSocketFile::socketpair(socket_type as i32, protocol as i32)?;
let current = current!();
let mut files = current.files().lock().unwrap();
sock_pair[0] = files.put(Arc::new(Box::new(client_socket)), false);
sock_pair[1] = files.put(Arc::new(Box::new(server_socket)), false);
debug!("socketpair: ({}, {})", sock_pair[0], sock_pair[1]);
Ok(0)
} else if (domain == libc::AF_TIPC) {
return_errno!(EAFNOSUPPORT, "cluster domain sockets not supported")
} else {
return_errno!(EAFNOSUPPORT, "domain not supported")
}
}
pub fn do_sendmsg(fd: c_int, msg_ptr: *const msghdr, flags_c: c_int) -> Result<isize> { pub fn do_sendmsg(fd: c_int, msg_ptr: *const msghdr, flags_c: c_int) -> Result<isize> {
debug!( debug!(
"sendmsg: fd: {}, msg: {:?}, flags: 0x{:x}", "sendmsg: fd: {}, msg: {:?}, flags: 0x{:x}",

@ -27,9 +27,11 @@ use crate::fs::{
}; };
use crate::misc::{resource_t, rlimit_t, utsname_t}; use crate::misc::{resource_t, rlimit_t, utsname_t};
use crate::net::{ use crate::net::{
do_epoll_create, do_epoll_create1, do_epoll_ctl, do_epoll_pwait, do_epoll_wait, do_poll, do_accept, do_accept4, do_bind, do_connect, do_epoll_create, do_epoll_create1, do_epoll_ctl,
do_recvmsg, do_select, do_sendmsg, msghdr, msghdr_mut, AsSocket, AsUnixSocket, EpollEvent, do_epoll_pwait, do_epoll_wait, do_getpeername, do_getsockname, do_getsockopt, do_listen,
SocketFile, UnixSocketFile, do_poll, do_recvfrom, do_recvmsg, do_select, do_sendmsg, do_sendto, do_setsockopt, do_shutdown,
do_socket, do_socketpair, msghdr, msghdr_mut, AsSocket, AsUnixSocket, EpollEvent, SocketFile,
UnixSocketFile,
}; };
use crate::process::{ use crate::process::{
do_arch_prctl, do_clone, do_exit, do_exit_group, do_futex, do_getegid, do_geteuid, do_getgid, do_arch_prctl, do_clone, do_exit, do_exit_group, do_futex, do_getegid, do_geteuid, do_getgid,
@ -785,347 +787,6 @@ fn do_nanosleep(req_u: *const timespec_t, rem_u: *mut timespec_t) -> Result<isiz
Ok(0) Ok(0)
} }
fn do_socket(domain: c_int, socket_type: c_int, protocol: c_int) -> Result<isize> {
debug!(
"socket: domain: {}, socket_type: 0x{:x}, protocol: {}",
domain, socket_type, protocol
);
let file_ref: Arc<Box<dyn File>> = match domain {
libc::AF_LOCAL => {
let unix_socket = UnixSocketFile::new(socket_type, protocol)?;
Arc::new(Box::new(unix_socket))
}
_ => {
let socket = SocketFile::new(domain, socket_type, protocol)?;
Arc::new(Box::new(socket))
}
};
let fd = current!().add_file(file_ref, false);
Ok(fd as isize)
}
fn do_connect(fd: c_int, addr: *const libc::sockaddr, addr_len: libc::socklen_t) -> Result<isize> {
debug!(
"connect: fd: {}, addr: {:?}, addr_len: {}",
fd, addr, addr_len
);
// For SOCK_DGRAM sockets not initiated in connection-mode,
// if address is a null address for the protocol,
// the socket's peer address shall be reset.
let need_check: bool = !addr.is_null();
if need_check {
check_array(addr as *const u8, addr_len as usize)?;
}
let file_ref = current!().file(fd as FileDesc)?;
if let Ok(socket) = file_ref.as_socket() {
if need_check {
check_ptr(addr as *const libc::sockaddr_in)?;
}
let ret = try_libc!(libc::ocall::connect(socket.fd(), addr, addr_len));
Ok(ret as isize)
} else if let Ok(unix_socket) = file_ref.as_unix_socket() {
let addr = addr as *const libc::sockaddr_un;
check_ptr(addr)?;
let path = clone_cstring_safely(unsafe { (&*addr).sun_path.as_ptr() })?
.to_string_lossy()
.into_owned();
unix_socket.connect(path)?;
Ok(0)
} else {
return_errno!(EBADF, "not a socket")
}
}
fn do_accept(
fd: c_int,
addr: *mut libc::sockaddr,
addr_len: *mut libc::socklen_t,
) -> Result<isize> {
do_accept4(fd, addr, addr_len, 0)
}
fn do_accept4(
fd: c_int,
addr: *mut libc::sockaddr,
addr_len: *mut libc::socklen_t,
flags: c_int,
) -> Result<isize> {
debug!(
"accept4: fd: {}, addr: {:?}, addr_len: {:?}, flags: {:#x}",
fd, addr, addr_len, flags
);
let need_check: bool = !addr.is_null();
if addr.is_null() ^ addr_len.is_null() {
return_errno!(EINVAL, "addr and ddr_len should be both null");
}
if need_check {
check_mut_array(addr as *mut u8, unsafe { *addr_len } as usize)?;
}
let file_ref = current!().file(fd as FileDesc)?;
if let Ok(socket) = file_ref.as_socket() {
if need_check {
check_mut_ptr(addr as *mut libc::sockaddr_in)?;
}
let new_socket = socket.accept(addr, addr_len, flags)?;
let new_file_ref: Arc<Box<dyn File>> = Arc::new(Box::new(new_socket));
let new_fd = current!().add_file(new_file_ref, false);
Ok(new_fd as isize)
} else if let Ok(unix_socket) = file_ref.as_unix_socket() {
let addr = addr as *mut libc::sockaddr_un;
if need_check {
check_mut_ptr(addr)?;
}
// TODO: handle addr
let new_socket = unix_socket.accept()?;
let new_file_ref: Arc<Box<dyn File>> = Arc::new(Box::new(new_socket));
let new_fd = current!().add_file(new_file_ref, false);
Ok(new_fd as isize)
} else {
return_errno!(EBADF, "not a socket")
}
}
fn do_shutdown(fd: c_int, how: c_int) -> Result<isize> {
debug!("shutdown: fd: {}, how: {}", fd, how);
let file_ref = current!().file(fd as FileDesc)?;
if let Ok(socket) = file_ref.as_socket() {
let ret = try_libc!(libc::ocall::shutdown(socket.fd(), how));
Ok(ret as isize)
} else {
return_errno!(EBADF, "not a socket")
}
}
fn do_bind(fd: c_int, addr: *const libc::sockaddr, addr_len: libc::socklen_t) -> Result<isize> {
debug!("bind: fd: {}, addr: {:?}, addr_len: {}", fd, addr, addr_len);
if addr.is_null() && addr_len == 0 {
return_errno!(EINVAL, "no address is specified");
}
check_array(addr as *const u8, addr_len as usize)?;
let file_ref = current!().file(fd as FileDesc)?;
if let Ok(socket) = file_ref.as_socket() {
check_ptr(addr as *const libc::sockaddr_in)?;
let ret = try_libc!(libc::ocall::bind(socket.fd(), addr, addr_len));
Ok(ret as isize)
} else if let Ok(unix_socket) = file_ref.as_unix_socket() {
let addr = addr as *const libc::sockaddr_un;
check_ptr(addr)?;
let path = clone_cstring_safely(unsafe { (&*addr).sun_path.as_ptr() })?
.to_string_lossy()
.into_owned();
unix_socket.bind(path)?;
Ok(0)
} else {
return_errno!(EBADF, "not a socket")
}
}
fn do_listen(fd: c_int, backlog: c_int) -> Result<isize> {
debug!("listen: fd: {}, backlog: {}", fd, backlog);
let file_ref = current!().file(fd as FileDesc)?;
if let Ok(socket) = file_ref.as_socket() {
let ret = try_libc!(libc::ocall::listen(socket.fd(), backlog));
Ok(ret as isize)
} else if let Ok(unix_socket) = file_ref.as_unix_socket() {
unix_socket.listen()?;
Ok(0)
} else {
return_errno!(EBADF, "not a socket")
}
}
fn do_setsockopt(
fd: c_int,
level: c_int,
optname: c_int,
optval: *const c_void,
optlen: libc::socklen_t,
) -> Result<isize> {
debug!(
"setsockopt: fd: {}, level: {}, optname: {}, optval: {:?}, optlen: {:?}",
fd, level, optname, optval, optlen
);
let file_ref = current!().file(fd as FileDesc)?;
if let Ok(socket) = file_ref.as_socket() {
let ret = try_libc!(libc::ocall::setsockopt(
socket.fd(),
level,
optname,
optval,
optlen
));
Ok(ret as isize)
} else if let Ok(unix_socket) = file_ref.as_unix_socket() {
warn!("setsockopt for unix socket is unimplemented");
Ok(0)
} else {
return_errno!(EBADF, "not a socket")
}
}
fn do_getsockopt(
fd: c_int,
level: c_int,
optname: c_int,
optval: *mut c_void,
optlen: *mut libc::socklen_t,
) -> Result<isize> {
debug!(
"getsockopt: fd: {}, level: {}, optname: {}, optval: {:?}, optlen: {:?}",
fd, level, optname, optval, optlen
);
let file_ref = current!().file(fd as FileDesc)?;
let socket = file_ref.as_socket()?;
let ret = try_libc!(libc::ocall::getsockopt(
socket.fd(),
level,
optname,
optval,
optlen
));
Ok(ret as isize)
}
fn do_getpeername(
fd: c_int,
addr: *mut libc::sockaddr,
addr_len: *mut libc::socklen_t,
) -> Result<isize> {
debug!(
"getpeername: fd: {}, addr: {:?}, addr_len: {:?}",
fd, addr, addr_len
);
let file_ref = current!().file(fd as FileDesc)?;
if let Ok(socket) = file_ref.as_socket() {
let ret = try_libc!(libc::ocall::getpeername(socket.fd(), addr, addr_len));
Ok(ret as isize)
} else if let Ok(unix_socket) = file_ref.as_unix_socket() {
warn!("getpeername for unix socket is unimplemented");
return_errno!(
ENOTCONN,
"hack for php: Transport endpoint is not connected"
)
} else {
return_errno!(EBADF, "not a socket")
}
}
fn do_getsockname(
fd: c_int,
addr: *mut libc::sockaddr,
addr_len: *mut libc::socklen_t,
) -> Result<isize> {
debug!(
"getsockname: fd: {}, addr: {:?}, addr_len: {:?}",
fd, addr, addr_len
);
let file_ref = current!().file(fd as FileDesc)?;
if let Ok(socket) = file_ref.as_socket() {
let ret = try_libc!(libc::ocall::getsockname(socket.fd(), addr, addr_len));
Ok(ret as isize)
} else if let Ok(unix_socket) = file_ref.as_unix_socket() {
warn!("getsockname for unix socket is unimplemented");
Ok(0)
} else {
return_errno!(EBADF, "not a socket")
}
}
fn do_sendto(
fd: c_int,
base: *const c_void,
len: size_t,
flags: c_int,
addr: *const libc::sockaddr,
addr_len: libc::socklen_t,
) -> Result<isize> {
debug!(
"sendto: fd: {}, base: {:?}, len: {}, addr: {:?}, addr_len: {}",
fd, base, len, addr, addr_len
);
let file_ref = current!().file(fd as FileDesc)?;
let socket = file_ref.as_socket()?;
let ret = try_libc!(libc::ocall::sendto(
socket.fd(),
base,
len,
flags,
addr,
addr_len
));
Ok(ret as isize)
}
fn do_recvfrom(
fd: c_int,
base: *mut c_void,
len: size_t,
flags: c_int,
addr: *mut libc::sockaddr,
addr_len: *mut libc::socklen_t,
) -> Result<isize> {
debug!(
"recvfrom: fd: {}, base: {:?}, len: {}, flags: {}, addr: {:?}, addr_len: {:?}",
fd, base, len, flags, addr, addr_len
);
let file_ref = current!().file(fd as FileDesc)?;
let socket = file_ref.as_socket()?;
let ret = try_libc!(libc::ocall::recvfrom(
socket.fd(),
base,
len,
flags,
addr,
addr_len
));
Ok(ret as isize)
}
fn do_socketpair(
domain: c_int,
socket_type: c_int,
protocol: c_int,
sv: *mut c_int,
) -> Result<isize> {
debug!(
"socketpair: domain: {}, type:0x{:x}, protocol: {}",
domain, socket_type, protocol
);
let mut sock_pair = unsafe {
check_mut_array(sv, 2)?;
std::slice::from_raw_parts_mut(sv as *mut u32, 2)
};
if (domain == libc::AF_UNIX) {
let (client_socket, server_socket) =
UnixSocketFile::socketpair(socket_type as i32, protocol as i32)?;
let current = current!();
let mut files = current.files().lock().unwrap();
sock_pair[0] = files.put(Arc::new(Box::new(client_socket)), false);
sock_pair[1] = files.put(Arc::new(Box::new(server_socket)), false);
debug!("socketpair: ({}, {})", sock_pair[0], sock_pair[1]);
Ok(0)
} else if (domain == libc::AF_TIPC) {
return_errno!(EAFNOSUPPORT, "cluster domain sockets not supported")
} else {
return_errno!(EAFNOSUPPORT, "domain not supported")
}
}
fn do_uname(name: *mut utsname_t) -> Result<isize> { fn do_uname(name: *mut utsname_t) -> Result<isize> {
check_mut_ptr(name)?; check_mut_ptr(name)?;
let name = unsafe { &mut *name }; let name = unsafe { &mut *name };