hack unix socket for php
This commit is contained in:
parent
3850c31235
commit
dd3de96b8e
@ -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
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user