From 987e06a458df33daa71185adc1f2e4bf1c0595e6 Mon Sep 17 00:00:00 2001 From: He Sun Date: Thu, 28 May 2020 17:41:06 +0800 Subject: [PATCH] Move networking system call interfaces to net module --- src/libos/src/net/syscalls.rs | 345 +++++++++++++++++++++++++++++++++ src/libos/src/syscall/mod.rs | 349 +--------------------------------- 2 files changed, 350 insertions(+), 344 deletions(-) diff --git a/src/libos/src/net/syscalls.rs b/src/libos/src/net/syscalls.rs index 364e31a5..c3a5381e 100644 --- a/src/libos/src/net/syscalls.rs +++ b/src/libos/src/net/syscalls.rs @@ -8,6 +8,351 @@ use std::convert::TryFrom; use time::timeval_t; use util::mem_util::from_user; +pub fn do_socket(domain: c_int, socket_type: c_int, protocol: c_int) -> Result { + debug!( + "socket: domain: {}, socket_type: 0x{:x}, protocol: {}", + domain, socket_type, protocol + ); + + let file_ref: Arc> = 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 { + 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 { + 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 { + 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> = 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> = 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { debug!( "sendmsg: fd: {}, msg: {:?}, flags: 0x{:x}", diff --git a/src/libos/src/syscall/mod.rs b/src/libos/src/syscall/mod.rs index ff4e9ca6..3cc522ae 100644 --- a/src/libos/src/syscall/mod.rs +++ b/src/libos/src/syscall/mod.rs @@ -27,9 +27,11 @@ use crate::fs::{ }; use crate::misc::{resource_t, rlimit_t, utsname_t}; use crate::net::{ - do_epoll_create, do_epoll_create1, do_epoll_ctl, do_epoll_pwait, do_epoll_wait, do_poll, - do_recvmsg, do_select, do_sendmsg, msghdr, msghdr_mut, AsSocket, AsUnixSocket, EpollEvent, - SocketFile, UnixSocketFile, + do_accept, do_accept4, do_bind, do_connect, do_epoll_create, do_epoll_create1, do_epoll_ctl, + do_epoll_pwait, do_epoll_wait, do_getpeername, do_getsockname, do_getsockopt, do_listen, + 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::{ 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 Result { - debug!( - "socket: domain: {}, socket_type: 0x{:x}, protocol: {}", - domain, socket_type, protocol - ); - - let file_ref: Arc> = 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 { - 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 { - 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 { - 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> = 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> = 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 { - 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 { - 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 { - 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 { - 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 { - 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 { - 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 { - 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 { - 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 { - 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 { - 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 { check_mut_ptr(name)?; let name = unsafe { &mut *name };