hack unix socket for php

This commit is contained in:
WangRunji 2019-04-24 19:25:09 +08:00
parent 3850c31235
commit dd3de96b8e
4 changed files with 152 additions and 12 deletions

@ -3,6 +3,7 @@ use std::any::Any;
use std::collections::btree_map::BTreeMap;
use std::fmt;
use std::vec::Vec;
use std::sync::atomic::spin_loop_hint;
/// Forward to host `poll`
/// (sgx_libc doesn't have `select`)
@ -13,6 +14,7 @@ pub fn do_select(
exceptfds: &mut libc::fd_set,
timeout: Option<libc::timeval>,
) -> Result<usize, Error> {
info!("select: nfds: {}", nfds);
// convert libos fd to Linux fd
let mut host_to_libos_fd = [0; libc::FD_SETSIZE];
let mut polls = Vec::<libc::pollfd>::new();
@ -30,6 +32,29 @@ pub fn do_select(
if !(r || w || e) {
continue;
}
if let Ok(socket) = file_table_ref.get(fd as FileDesc)?.as_unix_socket() {
warn!("select unix socket is unimplemented, spin for read");
readfds.clear();
writefds.clear();
exceptfds.clear();
// FIXME: spin poll until can read (hack for php)
while r && socket.poll()?.0 == false {
spin_loop_hint();
}
let (rr, ww, ee) = socket.poll()?;
if r && rr {
readfds.set(fd);
}
if w && ww {
writefds.set(fd);
}
if e && ee {
writefds.set(fd);
}
return Ok(1);
}
let host_fd = file_table_ref.get(fd as FileDesc)?.as_socket()?.fd();
host_to_libos_fd[host_fd as usize] = fd;
@ -80,7 +105,7 @@ pub fn do_select(
}
pub fn do_poll(polls: &mut [libc::pollfd], timeout: c_int) -> Result<usize, Error> {
info!("poll: [..], timeout: {}", timeout);
info!("poll: {:?}, timeout: {}", polls.iter().map(|p| p.fd).collect::<Vec<_>>(), timeout);
let current_ref = process::get_current();
let mut proc = current_ref.lock().unwrap();
@ -88,8 +113,30 @@ pub fn do_poll(polls: &mut [libc::pollfd], timeout: c_int) -> Result<usize, Erro
// convert libos fd to Linux fd
for poll in polls.iter_mut() {
let file_ref = proc.get_files().lock().unwrap().get(poll.fd as FileDesc)?;
let socket = file_ref.as_socket()?;
poll.fd = socket.fd();
if let Ok(socket) = file_ref.as_socket() {
poll.fd = socket.fd();
} else if let Ok(socket) = file_ref.as_unix_socket() {
// FIXME: spin poll until can read (hack for php)
while (poll.events & libc::POLLIN) != 0 && socket.poll()?.0 == false {
spin_loop_hint();
}
let (r, w, e) = socket.poll()?;
if r {
poll.revents |= libc::POLLIN;
}
if w {
poll.revents |= libc::POLLOUT;
}
if e {
poll.revents |= libc::POLLERR;
}
poll.revents &= poll.events;
warn!("poll unix socket is unimplemented, spin for read");
return Ok(1);
} else {
return errno!(EBADF, "not a socket");
}
}
let ret = try_libc!(libc::ocall::poll(polls.as_mut_ptr(), polls.len() as u64, timeout));
// recover fd ?

@ -4,6 +4,7 @@ use util::ring_buf::{RingBufReader, RingBufWriter, RingBuf};
use std::sync::SgxMutex as Mutex;
use alloc::prelude::ToString;
use std::fmt;
use std::sync::atomic::spin_loop_hint;
pub struct UnixSocketFile {
inner: Mutex<UnixSocket>
@ -127,6 +128,16 @@ impl UnixSocketFile {
let mut inner = self.inner.lock().unwrap();
inner.connect(path)
}
pub fn poll(&self) -> Result<(bool, bool, bool), Error> {
let mut inner = self.inner.lock().unwrap();
inner.poll()
}
pub fn ioctl(&self, cmd: c_int, argp: *mut c_int) -> Result<(), Error> {
let mut inner = self.inner.lock().unwrap();
inner.ioctl(cmd, argp)
}
}
impl Debug for UnixSocketFile {
@ -189,14 +200,19 @@ impl UnixSocket {
Ok(())
}
/// Server 4: Accept a connection on listening. Non-blocking.
/// Server 4: Accept a connection on listening.
pub fn accept(&mut self) -> Result<UnixSocket, Error> {
match self.status {
Status::Listening => {}
_ => return errno!(EINVAL, "unix socket is not listening"),
};
let socket = self.obj.as_mut().unwrap().pop()
.ok_or(Error::new(EAGAIN, "no connections are present to be accepted"))?;
// FIXME: Block. Now spin loop.
let socket = loop {
if let Some(socket) = self.obj.as_mut().unwrap().pop() {
break socket;
}
spin_loop_hint();
};
Ok(socket)
}
@ -217,16 +233,35 @@ impl UnixSocket {
}
pub fn read(&self, buf: &mut [u8]) -> Result<usize, Error> {
if let Status::Connected(channel) = &self.status {
channel.reader.read(buf)
} else {
errno!(EBADF, "UnixSocket is not connected")
}
self.channel()?.reader.read(buf)
}
pub fn write(&self, buf: &[u8]) -> Result<usize, Error> {
self.channel()?.writer.write(buf)
}
pub fn poll(&self) -> Result<(bool, bool, bool), Error> { // (read, write, error)
let channel = self.channel()?;
let r = channel.reader.can_read();
let w = channel.writer.can_write();
Ok((r, w, false))
}
pub fn ioctl(&self, cmd: c_int, argp: *mut c_int) -> Result<(), Error> {
const FIONREAD: c_int = 0x541B; // Get the number of bytes to read
if cmd == FIONREAD {
let bytes_to_read = self.channel()?.reader.bytes_to_read();
unsafe { argp.write(bytes_to_read as c_int); }
Ok(())
} else {
warn!("ioctl for unix socket is unimplemented");
errno!(ENOSYS, "ioctl for unix socket is unimplemented")
}
}
fn channel(&self) -> Result<&Channel, Error> {
if let Status::Connected(channel) = &self.status {
channel.writer.write(buf)
Ok(channel)
} else {
errno!(EBADF, "UnixSocket is not connected")
}

@ -258,6 +258,11 @@ pub extern "C" fn dispatch_syscall(
arg1 as *mut libc::sockaddr,
arg2 as *mut libc::socklen_t,
),
SYS_GETSOCKNAME => do_getsockname(
arg0 as c_int,
arg1 as *mut libc::sockaddr,
arg2 as *mut libc::socklen_t,
),
SYS_SENDTO => do_sendto(
arg0 as c_int,
arg1 as *const c_void,
@ -926,6 +931,10 @@ fn do_ioctl(fd: FileDesc, cmd: c_int, argp: *mut c_int) -> Result<isize, Error>
if let Ok(socket) = file_ref.as_socket() {
let ret = try_libc!(libc::ocall::ioctl_arg1(socket.fd(), cmd, argp));
Ok(ret as isize)
} else if let Ok(unix_socket) = file_ref.as_unix_socket() {
// TODO: check argp
unix_socket.ioctl(cmd, argp)?;
Ok(0)
} else {
warn!("ioctl is unimplemented");
errno!(ENOSYS, "ioctl is unimplemented")
@ -1156,6 +1165,30 @@ fn do_getpeername(
Ok(ret as isize)
} else if let Ok(unix_socket) = file_ref.as_unix_socket() {
warn!("getpeername for unix socket is unimplemented");
errno!(ENOTCONN, "hack for php: Transport endpoint is not connected")
} else {
errno!(EBADF, "not a socket")
}
}
fn do_getsockname(
fd: c_int,
addr: *mut libc::sockaddr,
addr_len: *mut libc::socklen_t,
) -> Result<isize, Error> {
info!("getsockname: fd: {}, addr: {:?}, addr_len: {:?}", fd, addr, addr_len);
let current_ref = process::get_current();
let mut proc = current_ref.lock().unwrap();
let file_ref = proc.get_files().lock().unwrap().get(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 {
errno!(EBADF, "not a socket")

@ -155,6 +155,20 @@ impl RingBufReader {
}
Ok(buf_pos)
}
pub fn can_read(&self) -> bool {
self.bytes_to_read() != 0
}
pub fn bytes_to_read(&self) -> usize {
let tail = self.inner.get_tail();
let head = self.inner.get_head();
if tail <= head {
head - tail
} else {
self.inner.capacity - tail + head
}
}
}
impl Drop for RingBufReader {
@ -202,4 +216,15 @@ impl RingBufWriter {
}
Ok(buf_pos)
}
pub fn can_write(&self) -> bool {
let tail = self.inner.get_tail();
let head = self.inner.get_head();
let may_write_nbytes = if tail <= head {
self.inner.capacity - head
} else {
tail - head - 1
};
may_write_nbytes != 0
}
}