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::collections::btree_map::BTreeMap;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::vec::Vec;
|
use std::vec::Vec;
|
||||||
|
use std::sync::atomic::spin_loop_hint;
|
||||||
|
|
||||||
/// Forward to host `poll`
|
/// Forward to host `poll`
|
||||||
/// (sgx_libc doesn't have `select`)
|
/// (sgx_libc doesn't have `select`)
|
||||||
@ -13,6 +14,7 @@ pub fn do_select(
|
|||||||
exceptfds: &mut libc::fd_set,
|
exceptfds: &mut libc::fd_set,
|
||||||
timeout: Option<libc::timeval>,
|
timeout: Option<libc::timeval>,
|
||||||
) -> Result<usize, Error> {
|
) -> Result<usize, Error> {
|
||||||
|
info!("select: nfds: {}", nfds);
|
||||||
// convert libos fd to Linux fd
|
// convert libos fd to Linux fd
|
||||||
let mut host_to_libos_fd = [0; libc::FD_SETSIZE];
|
let mut host_to_libos_fd = [0; libc::FD_SETSIZE];
|
||||||
let mut polls = Vec::<libc::pollfd>::new();
|
let mut polls = Vec::<libc::pollfd>::new();
|
||||||
@ -30,6 +32,29 @@ pub fn do_select(
|
|||||||
if !(r || w || e) {
|
if !(r || w || e) {
|
||||||
continue;
|
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();
|
let host_fd = file_table_ref.get(fd as FileDesc)?.as_socket()?.fd();
|
||||||
|
|
||||||
host_to_libos_fd[host_fd as usize] = 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> {
|
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 current_ref = process::get_current();
|
||||||
let mut proc = current_ref.lock().unwrap();
|
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
|
// convert libos fd to Linux fd
|
||||||
for poll in polls.iter_mut() {
|
for poll in polls.iter_mut() {
|
||||||
let file_ref = proc.get_files().lock().unwrap().get(poll.fd as FileDesc)?;
|
let file_ref = proc.get_files().lock().unwrap().get(poll.fd as FileDesc)?;
|
||||||
let socket = file_ref.as_socket()?;
|
if let Ok(socket) = file_ref.as_socket() {
|
||||||
poll.fd = socket.fd();
|
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));
|
let ret = try_libc!(libc::ocall::poll(polls.as_mut_ptr(), polls.len() as u64, timeout));
|
||||||
// recover fd ?
|
// recover fd ?
|
||||||
|
@ -4,6 +4,7 @@ use util::ring_buf::{RingBufReader, RingBufWriter, RingBuf};
|
|||||||
use std::sync::SgxMutex as Mutex;
|
use std::sync::SgxMutex as Mutex;
|
||||||
use alloc::prelude::ToString;
|
use alloc::prelude::ToString;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
use std::sync::atomic::spin_loop_hint;
|
||||||
|
|
||||||
pub struct UnixSocketFile {
|
pub struct UnixSocketFile {
|
||||||
inner: Mutex<UnixSocket>
|
inner: Mutex<UnixSocket>
|
||||||
@ -127,6 +128,16 @@ impl UnixSocketFile {
|
|||||||
let mut inner = self.inner.lock().unwrap();
|
let mut inner = self.inner.lock().unwrap();
|
||||||
inner.connect(path)
|
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 {
|
impl Debug for UnixSocketFile {
|
||||||
@ -189,14 +200,19 @@ impl UnixSocket {
|
|||||||
Ok(())
|
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> {
|
pub fn accept(&mut self) -> Result<UnixSocket, Error> {
|
||||||
match self.status {
|
match self.status {
|
||||||
Status::Listening => {}
|
Status::Listening => {}
|
||||||
_ => return errno!(EINVAL, "unix socket is not listening"),
|
_ => return errno!(EINVAL, "unix socket is not listening"),
|
||||||
};
|
};
|
||||||
let socket = self.obj.as_mut().unwrap().pop()
|
// FIXME: Block. Now spin loop.
|
||||||
.ok_or(Error::new(EAGAIN, "no connections are present to be accepted"))?;
|
let socket = loop {
|
||||||
|
if let Some(socket) = self.obj.as_mut().unwrap().pop() {
|
||||||
|
break socket;
|
||||||
|
}
|
||||||
|
spin_loop_hint();
|
||||||
|
};
|
||||||
Ok(socket)
|
Ok(socket)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -217,16 +233,35 @@ impl UnixSocket {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn read(&self, buf: &mut [u8]) -> Result<usize, Error> {
|
pub fn read(&self, buf: &mut [u8]) -> Result<usize, Error> {
|
||||||
if let Status::Connected(channel) = &self.status {
|
self.channel()?.reader.read(buf)
|
||||||
channel.reader.read(buf)
|
|
||||||
} else {
|
|
||||||
errno!(EBADF, "UnixSocket is not connected")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn write(&self, buf: &[u8]) -> Result<usize, Error> {
|
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 {
|
if let Status::Connected(channel) = &self.status {
|
||||||
channel.writer.write(buf)
|
Ok(channel)
|
||||||
} else {
|
} else {
|
||||||
errno!(EBADF, "UnixSocket is not connected")
|
errno!(EBADF, "UnixSocket is not connected")
|
||||||
}
|
}
|
||||||
|
@ -258,6 +258,11 @@ pub extern "C" fn dispatch_syscall(
|
|||||||
arg1 as *mut libc::sockaddr,
|
arg1 as *mut libc::sockaddr,
|
||||||
arg2 as *mut libc::socklen_t,
|
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(
|
SYS_SENDTO => do_sendto(
|
||||||
arg0 as c_int,
|
arg0 as c_int,
|
||||||
arg1 as *const c_void,
|
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() {
|
if let Ok(socket) = file_ref.as_socket() {
|
||||||
let ret = try_libc!(libc::ocall::ioctl_arg1(socket.fd(), cmd, argp));
|
let ret = try_libc!(libc::ocall::ioctl_arg1(socket.fd(), cmd, argp));
|
||||||
Ok(ret as isize)
|
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 {
|
} else {
|
||||||
warn!("ioctl is unimplemented");
|
warn!("ioctl is unimplemented");
|
||||||
errno!(ENOSYS, "ioctl is unimplemented")
|
errno!(ENOSYS, "ioctl is unimplemented")
|
||||||
@ -1156,6 +1165,30 @@ fn do_getpeername(
|
|||||||
Ok(ret as isize)
|
Ok(ret as isize)
|
||||||
} else if let Ok(unix_socket) = file_ref.as_unix_socket() {
|
} else if let Ok(unix_socket) = file_ref.as_unix_socket() {
|
||||||
warn!("getpeername for unix socket is unimplemented");
|
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)
|
Ok(0)
|
||||||
} else {
|
} else {
|
||||||
errno!(EBADF, "not a socket")
|
errno!(EBADF, "not a socket")
|
||||||
|
@ -155,6 +155,20 @@ impl RingBufReader {
|
|||||||
}
|
}
|
||||||
Ok(buf_pos)
|
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 {
|
impl Drop for RingBufReader {
|
||||||
@ -202,4 +216,15 @@ impl RingBufWriter {
|
|||||||
}
|
}
|
||||||
Ok(buf_pos)
|
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