Move networking system call interfaces to net module
This commit is contained in:
		
							parent
							
								
									ed664d1143
								
							
						
					
					
						commit
						987e06a458
					
				| @ -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 }; | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user