Optimize the perf of sendmsg/recvmsg by allocating untrusted buffers directly
It is slow to allocate big buffers using SGX SDK's malloc. Even worse, it consumes a large amount of precious trusted memory inside enclaves. This commit avoids using trusted buffers and allocates untrusted buffers for sendmsg/recvmsg directly via OCall, thus improving the performance of sendmsg/recvmsg. Note that this optimization does not affect the security of network data as it has to be sent/received via OCalls.
This commit is contained in:
		
							parent
							
								
									c3d042dcd0
								
							
						
					
					
						commit
						e352a190ea
					
				| @ -57,6 +57,9 @@ enclave { | |||||||
| 
 | 
 | ||||||
|         void occlum_ocall_sync(void); |         void occlum_ocall_sync(void); | ||||||
| 
 | 
 | ||||||
|  |         void* occlum_ocall_posix_memalign(size_t alignment, size_t size); | ||||||
|  |         void occlum_ocall_free([user_check] void* ptr); | ||||||
|  | 
 | ||||||
|         void occlum_ocall_sched_yield(void); |         void occlum_ocall_sched_yield(void); | ||||||
|         int occlum_ocall_sched_getaffinity( |         int occlum_ocall_sched_getaffinity( | ||||||
|             int host_tid, |             int host_tid, | ||||||
| @ -87,8 +90,8 @@ enclave { | |||||||
|             int sockfd, |             int sockfd, | ||||||
|             [in, size=msg_namelen] const void* msg_name, |             [in, size=msg_namelen] const void* msg_name, | ||||||
|             socklen_t msg_namelen, |             socklen_t msg_namelen, | ||||||
|             [in, size=buf_len] const void* buf, |             [in, count=msg_iovlen] const struct iovec* msg_iov, | ||||||
|             size_t buf_len, |             size_t msg_iovlen, | ||||||
|             [in, size=msg_controllen] const void* msg_control, |             [in, size=msg_controllen] const void* msg_control, | ||||||
|             size_t msg_controllen, |             size_t msg_controllen, | ||||||
|             int flags |             int flags | ||||||
| @ -98,8 +101,8 @@ enclave { | |||||||
|             [out, size=msg_namelen] void *msg_name, |             [out, size=msg_namelen] void *msg_name, | ||||||
|             socklen_t msg_namelen, |             socklen_t msg_namelen, | ||||||
|             [out] socklen_t* msg_namelen_recv, |             [out] socklen_t* msg_namelen_recv, | ||||||
|             [out, size=buf_len] void* buf, |             [in, count=msg_iovlen] struct iovec* msg_iov, | ||||||
|             size_t buf_len, |             size_t msg_iovlen, | ||||||
|             [out, size=msg_controllen] void *msg_control, |             [out, size=msg_controllen] void *msg_control, | ||||||
|             size_t msg_controllen, |             size_t msg_controllen, | ||||||
|             [out] size_t* msg_controllen_recv, |             [out] size_t* msg_controllen_recv, | ||||||
|  | |||||||
| @ -98,3 +98,15 @@ impl ToErrno for rcore_fs::vfs::FsError { | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | impl ToErrno for std::alloc::AllocErr { | ||||||
|  |     fn errno(&self) -> Errno { | ||||||
|  |         ENOMEM | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl ToErrno for std::alloc::LayoutErr { | ||||||
|  |     fn errno(&self) -> Errno { | ||||||
|  |         EINVAL | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | |||||||
| @ -7,6 +7,8 @@ | |||||||
| #![feature(core_intrinsics)] | #![feature(core_intrinsics)] | ||||||
| #![feature(stmt_expr_attributes)] | #![feature(stmt_expr_attributes)] | ||||||
| #![feature(atomic_min_max)] | #![feature(atomic_min_max)] | ||||||
|  | #![feature(no_more_cas)] | ||||||
|  | #![feature(alloc_layout_extra)] | ||||||
| 
 | 
 | ||||||
| #[macro_use] | #[macro_use] | ||||||
| extern crate alloc; | extern crate alloc; | ||||||
| @ -59,6 +61,7 @@ mod net; | |||||||
| mod process; | mod process; | ||||||
| mod syscall; | mod syscall; | ||||||
| mod time; | mod time; | ||||||
|  | mod untrusted; | ||||||
| mod util; | mod util; | ||||||
| mod vm; | mod vm; | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -1,6 +1,8 @@ | |||||||
| //! I/O vectors
 | //! I/O vectors
 | ||||||
| 
 | 
 | ||||||
| use super::*; | use super::*; | ||||||
|  | use crate::untrusted::SliceAsPtrAndLen; | ||||||
|  | use std::iter::Iterator; | ||||||
| 
 | 
 | ||||||
| /// A memory safe, immutable version of C iovec array
 | /// A memory safe, immutable version of C iovec array
 | ||||||
| pub struct Iovs<'a> { | pub struct Iovs<'a> { | ||||||
| @ -19,19 +21,6 @@ impl<'a> Iovs<'a> { | |||||||
|     pub fn total_bytes(&self) -> usize { |     pub fn total_bytes(&self) -> usize { | ||||||
|         self.iovs.iter().map(|s| s.len()).sum() |         self.iovs.iter().map(|s| s.len()).sum() | ||||||
|     } |     } | ||||||
| 
 |  | ||||||
|     pub fn gather_to_vec(&self) -> Vec<u8> { |  | ||||||
|         Self::gather_slices_to_vec(&self.iovs[..]) |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     fn gather_slices_to_vec(slices: &[&[u8]]) -> Vec<u8> { |  | ||||||
|         let vec_len = slices.iter().map(|slice| slice.len()).sum(); |  | ||||||
|         let mut vec = Vec::with_capacity(vec_len); |  | ||||||
|         for slice in slices { |  | ||||||
|             vec.extend_from_slice(slice); |  | ||||||
|         } |  | ||||||
|         vec |  | ||||||
|     } |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /// A memory safe, mutable version of C iovec array
 | /// A memory safe, mutable version of C iovec array
 | ||||||
| @ -59,30 +48,41 @@ impl<'a> IovsMut<'a> { | |||||||
|         self.iovs.iter().map(|s| s.len()).sum() |         self.iovs.iter().map(|s| s.len()).sum() | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     pub fn gather_to_vec(&self) -> Vec<u8> { |     /// Copy as many bytes from an u8 iterator as possible
 | ||||||
|         Iovs::gather_slices_to_vec(self.as_slices()) |     pub fn copy_from_iter<'b, T>(&mut self, src_iter: &mut T) -> usize | ||||||
|  |     where | ||||||
|  |         T: Iterator<Item = &'b u8>, | ||||||
|  |     { | ||||||
|  |         let mut bytes_copied = 0; | ||||||
|  |         let mut dst_iter = self | ||||||
|  |             .as_slices_mut() | ||||||
|  |             .iter_mut() | ||||||
|  |             .flat_map(|mut slice| slice.iter_mut()); | ||||||
|  |         while let (Some(mut d), Some(s)) = (dst_iter.next(), src_iter.next()) { | ||||||
|  |             *d = *s; | ||||||
|  |             bytes_copied += 1; | ||||||
|         } |         } | ||||||
| 
 |         bytes_copied | ||||||
|     pub fn scatter_copy_from(&mut self, data: &[u8]) -> usize { |     } | ||||||
|         let mut total_nbytes = 0; | } | ||||||
|         let mut remain_slice = data; | 
 | ||||||
|         for iov in &mut self.iovs { | /// An extention trait that converts slice to libc::iovec
 | ||||||
|             if remain_slice.len() == 0 { | pub trait SliceAsLibcIovec { | ||||||
|                 break; |     fn as_libc_iovec(&self) -> libc::iovec; | ||||||
|             } | } | ||||||
| 
 | 
 | ||||||
|             let copy_nbytes = remain_slice.len().min(iov.len()); | impl SliceAsLibcIovec for &[u8] { | ||||||
|             let dst_slice = unsafe { |     fn as_libc_iovec(&self) -> libc::iovec { | ||||||
|                 debug_assert!(iov.len() >= copy_nbytes); |         let (iov_base, iov_len) = self.as_ptr_and_len(); | ||||||
|                 iov.get_unchecked_mut(..copy_nbytes) |         let iov_base = iov_base as *mut u8 as *mut c_void; | ||||||
|             }; |         libc::iovec { iov_base, iov_len } | ||||||
|             let (src_slice, _remain_slice) = remain_slice.split_at(copy_nbytes); |     } | ||||||
|             dst_slice.copy_from_slice(src_slice); | } | ||||||
| 
 | 
 | ||||||
|             remain_slice = _remain_slice; | impl SliceAsLibcIovec for &mut [u8] { | ||||||
|             total_nbytes += copy_nbytes; |     fn as_libc_iovec(&self) -> libc::iovec { | ||||||
|         } |         let (iov_base, iov_len) = self.as_ptr_and_len(); | ||||||
|         debug_assert!(remain_slice.len() == 0); |         let iov_base = iov_base as *mut u8 as *mut c_void; | ||||||
|         total_nbytes |         libc::iovec { iov_base, iov_len } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -1,4 +1,5 @@ | |||||||
| use super::*; | use super::*; | ||||||
|  | use std::*; | ||||||
| 
 | 
 | ||||||
| mod iovs; | mod iovs; | ||||||
| mod msg; | mod msg; | ||||||
| @ -6,7 +7,7 @@ mod msg_flags; | |||||||
| mod socket_file; | mod socket_file; | ||||||
| mod syscalls; | mod syscalls; | ||||||
| 
 | 
 | ||||||
| pub use self::iovs::{Iovs, IovsMut}; | pub use self::iovs::{Iovs, IovsMut, SliceAsLibcIovec}; | ||||||
| pub use self::msg::{msghdr, msghdr_mut, MsgHdr, MsgHdrMut}; | pub use self::msg::{msghdr, msghdr_mut, MsgHdr, MsgHdrMut}; | ||||||
| pub use self::msg_flags::MsgFlags; | pub use self::msg_flags::MsgFlags; | ||||||
| pub use self::socket_file::{AsSocket, SocketFile}; | pub use self::socket_file::{AsSocket, SocketFile}; | ||||||
|  | |||||||
| @ -1,4 +1,5 @@ | |||||||
| use super::*; | use super::*; | ||||||
|  | use crate::untrusted::{SliceAsMutPtrAndLen, SliceAsPtrAndLen, UntrustedSliceAlloc}; | ||||||
| 
 | 
 | ||||||
| impl SocketFile { | impl SocketFile { | ||||||
|     // TODO: need sockaddr type to implement send/sento
 |     // TODO: need sockaddr type to implement send/sento
 | ||||||
| @ -19,37 +20,48 @@ impl SocketFile { | |||||||
|     }*/ |     }*/ | ||||||
| 
 | 
 | ||||||
|     pub fn recvmsg<'a, 'b>(&self, msg: &'b mut MsgHdrMut<'a>, flags: MsgFlags) -> Result<usize> { |     pub fn recvmsg<'a, 'b>(&self, msg: &'b mut MsgHdrMut<'a>, flags: MsgFlags) -> Result<usize> { | ||||||
|         // Allocate a single data buffer is big enough for all iovecs of msg.
 |         // Alloc untrusted iovecs to receive data via OCall
 | ||||||
|         // This is a workaround for the OCall that takes only one data buffer.
 |         let msg_iov = msg.get_iovs(); | ||||||
|         let mut data_buf = { |         let u_slice_alloc = UntrustedSliceAlloc::new(msg_iov.total_bytes())?; | ||||||
|             let data_buf_len = msg.get_iovs().total_bytes(); |         let mut u_slices = msg_iov | ||||||
|             let data_vec = vec![0; data_buf_len]; |             .as_slices() | ||||||
|             data_vec.into_boxed_slice() |             .iter() | ||||||
|         }; |             .map(|slice| { | ||||||
|  |                 u_slice_alloc | ||||||
|  |                     .new_slice_mut(slice.len()) | ||||||
|  |                     .expect("unexpected out of memory error in UntrustedSliceAlloc") | ||||||
|  |             }) | ||||||
|  |             .collect(); | ||||||
|  |         let mut u_iovs = IovsMut::new(u_slices); | ||||||
| 
 | 
 | ||||||
|  |         // Do OCall-based recvmsg
 | ||||||
|         let (bytes_recvd, namelen_recvd, controllen_recvd, flags_recvd) = { |         let (bytes_recvd, namelen_recvd, controllen_recvd, flags_recvd) = { | ||||||
|             let data = &mut data_buf[..]; |  | ||||||
|             // Acquire mutable references to the name and control buffers
 |             // Acquire mutable references to the name and control buffers
 | ||||||
|             let (name, control) = msg.get_name_and_control_mut(); |             let (name, control) = msg.get_name_and_control_mut(); | ||||||
|             // Fill the data, the name, and the control buffers
 |             // Fill the data, the name, and the control buffers
 | ||||||
|             self.do_recvmsg(data, flags, name, control)? |             self.do_recvmsg(u_iovs.as_slices_mut(), flags, name, control)? | ||||||
|         }; |         }; | ||||||
| 
 | 
 | ||||||
|         // Update the lengths and flags
 |         // Update the output lengths and flags
 | ||||||
|         msg.set_name_len(namelen_recvd)?; |         msg.set_name_len(namelen_recvd)?; | ||||||
|         msg.set_control_len(controllen_recvd)?; |         msg.set_control_len(controllen_recvd)?; | ||||||
|         msg.set_flags(flags_recvd); |         msg.set_flags(flags_recvd); | ||||||
| 
 | 
 | ||||||
|         let recv_data = &data_buf[..bytes_recvd]; |         // Copy data from untrusted iovecs into the output iovecs
 | ||||||
|         // TODO: avoid this one extra copy due to the intermediate data buffer
 |         let mut msg_iov = msg.get_iovs_mut(); | ||||||
|         msg.get_iovs_mut().scatter_copy_from(recv_data); |         let mut u_iovs_iter = u_iovs | ||||||
|  |             .as_slices() | ||||||
|  |             .iter() | ||||||
|  |             .flat_map(|slice| slice.iter()) | ||||||
|  |             .take(bytes_recvd); | ||||||
|  |         msg_iov.copy_from_iter(&mut u_iovs_iter); | ||||||
| 
 | 
 | ||||||
|         Ok(bytes_recvd) |         Ok(bytes_recvd) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fn do_recvmsg( |     fn do_recvmsg( | ||||||
|         &self, |         &self, | ||||||
|         data: &mut [u8], |         data: &mut [&mut [u8]], | ||||||
|         flags: MsgFlags, |         flags: MsgFlags, | ||||||
|         mut name: Option<&mut [u8]>, |         mut name: Option<&mut [u8]>, | ||||||
|         mut control: Option<&mut [u8]>, |         mut control: Option<&mut [u8]>, | ||||||
| @ -58,14 +70,15 @@ impl SocketFile { | |||||||
|         // Host socket fd
 |         // Host socket fd
 | ||||||
|         let host_fd = self.host_fd; |         let host_fd = self.host_fd; | ||||||
|         // Name
 |         // Name
 | ||||||
|         let (msg_name, msg_namelen) = name.get_mut_ptr_and_len(); |         let (msg_name, msg_namelen) = name.as_mut_ptr_and_len(); | ||||||
|         let msg_name = msg_name as *mut c_void; |         let msg_name = msg_name as *mut c_void; | ||||||
|         let mut msg_namelen_recvd = 0_u32; |         let mut msg_namelen_recvd = 0_u32; | ||||||
|         // Data
 |         // Iovs
 | ||||||
|         let msg_data = data.as_mut_ptr(); |         let mut raw_iovs: Vec<libc::iovec> = | ||||||
|         let msg_datalen = data.len(); |             data.iter().map(|slice| slice.as_libc_iovec()).collect(); | ||||||
|  |         let (msg_iov, msg_iovlen) = raw_iovs.as_mut_slice().as_mut_ptr_and_len(); | ||||||
|         // Control
 |         // Control
 | ||||||
|         let (msg_control, msg_controllen) = control.get_mut_ptr_and_len(); |         let (msg_control, msg_controllen) = control.as_mut_ptr_and_len(); | ||||||
|         let msg_control = msg_control as *mut c_void; |         let msg_control = msg_control as *mut c_void; | ||||||
|         let mut msg_controllen_recvd = 0; |         let mut msg_controllen_recvd = 0; | ||||||
|         // Flags
 |         // Flags
 | ||||||
| @ -81,8 +94,8 @@ impl SocketFile { | |||||||
|                 msg_name, |                 msg_name, | ||||||
|                 msg_namelen as u32, |                 msg_namelen as u32, | ||||||
|                 &mut msg_namelen_recvd as *mut u32, |                 &mut msg_namelen_recvd as *mut u32, | ||||||
|                 msg_data, |                 msg_iov, | ||||||
|                 msg_datalen, |                 msg_iovlen, | ||||||
|                 msg_control, |                 msg_control, | ||||||
|                 msg_controllen, |                 msg_controllen, | ||||||
|                 &mut msg_controllen_recvd as *mut usize, |                 &mut msg_controllen_recvd as *mut usize, | ||||||
| @ -103,7 +116,8 @@ impl SocketFile { | |||||||
|             let retval = retval as usize; |             let retval = retval as usize; | ||||||
| 
 | 
 | ||||||
|             // Check bytes_recvd returned from outside the enclave
 |             // Check bytes_recvd returned from outside the enclave
 | ||||||
|             assert!(retval <= data.len()); |             let max_bytes_recvd = data.iter().map(|x| x.len()).sum(); | ||||||
|  |             assert!(retval <= max_bytes_recvd); | ||||||
|             retval |             retval | ||||||
|         }; |         }; | ||||||
|         let msg_namelen_recvd = msg_namelen_recvd as usize; |         let msg_namelen_recvd = msg_namelen_recvd as usize; | ||||||
| @ -127,8 +141,8 @@ extern "C" { | |||||||
|         msg_name: *mut c_void, |         msg_name: *mut c_void, | ||||||
|         msg_namelen: libc::socklen_t, |         msg_namelen: libc::socklen_t, | ||||||
|         msg_namelen_recv: *mut libc::socklen_t, |         msg_namelen_recv: *mut libc::socklen_t, | ||||||
|         msg_data: *mut u8, |         msg_data: *mut libc::iovec, | ||||||
|         msg_data: size_t, |         msg_datalen: size_t, | ||||||
|         msg_control: *mut c_void, |         msg_control: *mut c_void, | ||||||
|         msg_controllen: size_t, |         msg_controllen: size_t, | ||||||
|         msg_controllen_recv: *mut size_t, |         msg_controllen_recv: *mut size_t, | ||||||
|  | |||||||
| @ -1,4 +1,5 @@ | |||||||
| use super::*; | use super::*; | ||||||
|  | use crate::untrusted::{SliceAsMutPtrAndLen, SliceAsPtrAndLen, UntrustedSliceAlloc}; | ||||||
| 
 | 
 | ||||||
| impl SocketFile { | impl SocketFile { | ||||||
|     // TODO: need sockaddr type to implement send/sento
 |     // TODO: need sockaddr type to implement send/sento
 | ||||||
| @ -18,44 +19,55 @@ impl SocketFile { | |||||||
|     */ |     */ | ||||||
| 
 | 
 | ||||||
|     pub fn sendmsg<'a, 'b>(&self, msg: &'b MsgHdr<'a>, flags: MsgFlags) -> Result<usize> { |     pub fn sendmsg<'a, 'b>(&self, msg: &'b MsgHdr<'a>, flags: MsgFlags) -> Result<usize> { | ||||||
|         // Copy data in iovs into a single buffer
 |         // Copy message's iovecs into untrusted iovecs
 | ||||||
|         let data_buf = msg.get_iovs().gather_to_vec(); |         let msg_iov = msg.get_iovs(); | ||||||
|  |         let u_slice_alloc = UntrustedSliceAlloc::new(msg_iov.total_bytes())?; | ||||||
|  |         let u_slices = msg_iov | ||||||
|  |             .as_slices() | ||||||
|  |             .iter() | ||||||
|  |             .map(|src_slice| { | ||||||
|  |                 u_slice_alloc | ||||||
|  |                     .new_slice(src_slice) | ||||||
|  |                     .expect("unexpected out of memory") | ||||||
|  |             }) | ||||||
|  |             .collect(); | ||||||
|  |         let u_iovs = Iovs::new(u_slices); | ||||||
| 
 | 
 | ||||||
|         self.do_sendmsg(&data_buf[..], flags, msg.get_name(), msg.get_control()) |         self.do_sendmsg(u_iovs.as_slices(), flags, msg.get_name(), msg.get_control()) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fn do_sendmsg( |     fn do_sendmsg( | ||||||
|         &self, |         &self, | ||||||
|         data: &[u8], |         data: &[&[u8]], | ||||||
|         flags: MsgFlags, |         flags: MsgFlags, | ||||||
|         name: Option<&[u8]>, |         name: Option<&[u8]>, | ||||||
|         control: Option<&[u8]>, |         control: Option<&[u8]>, | ||||||
|     ) -> Result<usize> { |     ) -> Result<usize> { | ||||||
|         let bytes_sent = try_libc!({ |  | ||||||
|         // Prepare the arguments for OCall
 |         // Prepare the arguments for OCall
 | ||||||
|         let mut retval: isize = 0; |         let mut retval: isize = 0; | ||||||
|         // Host socket fd
 |         // Host socket fd
 | ||||||
|         let host_fd = self.host_fd; |         let host_fd = self.host_fd; | ||||||
|         // Name
 |         // Name
 | ||||||
|             let (msg_name, msg_namelen) = name.get_ptr_and_len(); |         let (msg_name, msg_namelen) = name.as_ptr_and_len(); | ||||||
|         let msg_name = msg_name as *const c_void; |         let msg_name = msg_name as *const c_void; | ||||||
|             // Data
 |         // Iovs
 | ||||||
|             let msg_data = data.as_ptr(); |         let raw_iovs: Vec<libc::iovec> = data.iter().map(|slice| slice.as_libc_iovec()).collect(); | ||||||
|             let msg_datalen = data.len(); |         let (msg_iov, msg_iovlen) = raw_iovs.as_slice().as_ptr_and_len(); | ||||||
|         // Control
 |         // Control
 | ||||||
|             let (msg_control, msg_controllen) = control.get_ptr_and_len(); |         let (msg_control, msg_controllen) = control.as_ptr_and_len(); | ||||||
|         let msg_control = msg_control as *const c_void; |         let msg_control = msg_control as *const c_void; | ||||||
|         // Flags
 |         // Flags
 | ||||||
|         let flags = flags.to_u32() as i32; |         let flags = flags.to_u32() as i32; | ||||||
| 
 | 
 | ||||||
|  |         let bytes_sent = try_libc!({ | ||||||
|             // Do OCall
 |             // Do OCall
 | ||||||
|             let status = occlum_ocall_sendmsg( |             let status = occlum_ocall_sendmsg( | ||||||
|                 &mut retval as *mut isize, |                 &mut retval as *mut isize, | ||||||
|                 host_fd, |                 host_fd, | ||||||
|                 msg_name, |                 msg_name, | ||||||
|                 msg_namelen as u32, |                 msg_namelen as u32, | ||||||
|                 msg_data, |                 msg_iov, | ||||||
|                 msg_datalen, |                 msg_iovlen, | ||||||
|                 msg_control, |                 msg_control, | ||||||
|                 msg_controllen, |                 msg_controllen, | ||||||
|                 flags, |                 flags, | ||||||
| @ -75,7 +87,7 @@ extern "C" { | |||||||
|         fd: c_int, |         fd: c_int, | ||||||
|         msg_name: *const c_void, |         msg_name: *const c_void, | ||||||
|         msg_namelen: libc::socklen_t, |         msg_namelen: libc::socklen_t, | ||||||
|         msg_data: *const u8, |         msg_data: *const libc::iovec, | ||||||
|         msg_datalen: size_t, |         msg_datalen: size_t, | ||||||
|         msg_control: *const c_void, |         msg_control: *const c_void, | ||||||
|         msg_controllen: size_t, |         msg_controllen: size_t, | ||||||
|  | |||||||
| @ -31,29 +31,3 @@ pub fn align_down(addr: usize, align: usize) -> usize { | |||||||
| pub fn unbox<T>(value: Box<T>) -> T { | pub fn unbox<T>(value: Box<T>) -> T { | ||||||
|     *value |     *value | ||||||
| } | } | ||||||
| 
 |  | ||||||
| pub trait SliceOptionExt<T> { |  | ||||||
|     fn get_ptr_and_len(&self) -> (*const T, usize); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| impl<T> SliceOptionExt<T> for Option<&[T]> { |  | ||||||
|     fn get_ptr_and_len(&self) -> (*const T, usize) { |  | ||||||
|         match self { |  | ||||||
|             Some(self_slice) => (self_slice.as_ptr(), self_slice.len()), |  | ||||||
|             None => (std::ptr::null(), 0), |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| pub trait MutSliceOptionExt<T> { |  | ||||||
|     fn get_mut_ptr_and_len(&mut self) -> (*mut T, usize); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| impl<T> MutSliceOptionExt<T> for Option<&mut [T]> { |  | ||||||
|     fn get_mut_ptr_and_len(&mut self) -> (*mut T, usize) { |  | ||||||
|         match self { |  | ||||||
|             Some(self_slice) => (self_slice.as_mut_ptr(), self_slice.len()), |  | ||||||
|             None => (std::ptr::null_mut(), 0), |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  | |||||||
							
								
								
									
										62
									
								
								src/libos/src/untrusted/alloc.rs
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										62
									
								
								src/libos/src/untrusted/alloc.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,62 @@ | |||||||
|  | use super::*; | ||||||
|  | use std::alloc::{Alloc, AllocErr, Layout}; | ||||||
|  | use std::ptr::{self, NonNull}; | ||||||
|  | 
 | ||||||
|  | /// The global memory allocator for untrusted memory
 | ||||||
|  | pub static mut UNTRUSTED_ALLOC: UntrustedAlloc = UntrustedAlloc; | ||||||
|  | 
 | ||||||
|  | pub struct UntrustedAlloc; | ||||||
|  | 
 | ||||||
|  | unsafe impl Alloc for UntrustedAlloc { | ||||||
|  |     unsafe fn alloc(&mut self, layout: Layout) -> std::result::Result<NonNull<u8>, AllocErr> { | ||||||
|  |         if layout.size() == 0 { | ||||||
|  |             return Err(AllocErr); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         // Do OCall to allocate the untrusted memory according to the given layout
 | ||||||
|  |         let layout = layout | ||||||
|  |             .align_to(std::mem::size_of::<*const c_void>()) | ||||||
|  |             .unwrap(); | ||||||
|  |         let mem_ptr = { | ||||||
|  |             let mut mem_ptr: *mut c_void = ptr::null_mut(); | ||||||
|  |             let sgx_status = unsafe { | ||||||
|  |                 occlum_ocall_posix_memalign(&mut mem_ptr as *mut _, layout.align(), layout.size()) | ||||||
|  |             }; | ||||||
|  |             debug_assert!(sgx_status == sgx_status_t::SGX_SUCCESS); | ||||||
|  |             mem_ptr | ||||||
|  |         } as *mut u8; | ||||||
|  |         if mem_ptr == std::ptr::null_mut() { | ||||||
|  |             return Err(AllocErr); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         // Sanity checks
 | ||||||
|  |         // Post-condition 1: alignment
 | ||||||
|  |         debug_assert!(mem_ptr as usize % layout.align() == 0); | ||||||
|  |         // Post-condition 2: out-of-enclave
 | ||||||
|  |         assert!(sgx_trts::trts::rsgx_raw_is_outside_enclave( | ||||||
|  |             mem_ptr as *const u8, | ||||||
|  |             layout.size() | ||||||
|  |         )); | ||||||
|  |         Ok(NonNull::new(mem_ptr).unwrap()) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     unsafe fn dealloc(&mut self, ptr: NonNull<u8>, layout: Layout) { | ||||||
|  |         // Pre-condition: out-of-enclave
 | ||||||
|  |         debug_assert!(sgx_trts::trts::rsgx_raw_is_outside_enclave( | ||||||
|  |             ptr.as_ptr(), | ||||||
|  |             layout.size() | ||||||
|  |         )); | ||||||
|  | 
 | ||||||
|  |         let sgx_status = unsafe { occlum_ocall_free(ptr.as_ptr() as *mut c_void) }; | ||||||
|  |         debug_assert!(sgx_status == sgx_status_t::SGX_SUCCESS); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | extern "C" { | ||||||
|  |     fn occlum_ocall_posix_memalign( | ||||||
|  |         ptr: *mut *mut c_void, | ||||||
|  |         align: usize, // must be power of two and a multiple of sizeof(void*)
 | ||||||
|  |         size: usize, | ||||||
|  |     ) -> sgx_status_t; | ||||||
|  |     fn occlum_ocall_free(ptr: *mut c_void) -> sgx_status_t; | ||||||
|  | } | ||||||
							
								
								
									
										10
									
								
								src/libos/src/untrusted/mod.rs
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										10
									
								
								src/libos/src/untrusted/mod.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,10 @@ | |||||||
|  | /// Manipulate and access untrusted memory or functionalities safely
 | ||||||
|  | mod alloc; | ||||||
|  | mod slice_alloc; | ||||||
|  | mod slice_ext; | ||||||
|  | 
 | ||||||
|  | use super::*; | ||||||
|  | 
 | ||||||
|  | pub use self::alloc::UNTRUSTED_ALLOC; | ||||||
|  | pub use self::slice_alloc::UntrustedSliceAlloc; | ||||||
|  | pub use self::slice_ext::{SliceAsMutPtrAndLen, SliceAsPtrAndLen}; | ||||||
							
								
								
									
										81
									
								
								src/libos/src/untrusted/slice_alloc.rs
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										81
									
								
								src/libos/src/untrusted/slice_alloc.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,81 @@ | |||||||
|  | use super::*; | ||||||
|  | use std::alloc::{Alloc, AllocErr, Layout}; | ||||||
|  | use std::ptr::NonNull; | ||||||
|  | use std::sync::atomic::{AtomicUsize, Ordering}; | ||||||
|  | 
 | ||||||
|  | /// An memory allocator for slices, backed by a fixed-size, untrusted buffer
 | ||||||
|  | pub struct UntrustedSliceAlloc { | ||||||
|  |     /// The pointer to the untrusted buffer
 | ||||||
|  |     buf_ptr: *mut u8, | ||||||
|  |     /// The size of the untrusted buffer
 | ||||||
|  |     buf_size: usize, | ||||||
|  |     /// The next position to allocate new slice
 | ||||||
|  |     /// New slices must be allocated from [buf_ptr + buf_pos, buf_ptr + buf_size)
 | ||||||
|  |     buf_pos: AtomicUsize, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl UntrustedSliceAlloc { | ||||||
|  |     pub fn new(buf_size: usize) -> Result<Self> { | ||||||
|  |         if buf_size == 0 { | ||||||
|  |             // Create a dummy object
 | ||||||
|  |             return Ok(Self { | ||||||
|  |                 buf_ptr: std::ptr::null_mut(), | ||||||
|  |                 buf_size: 0, | ||||||
|  |                 buf_pos: AtomicUsize::new(0), | ||||||
|  |             }); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         let layout = Layout::from_size_align(buf_size, 1)?; | ||||||
|  |         let buf_ptr = unsafe { UNTRUSTED_ALLOC.alloc(layout)?.as_ptr() }; | ||||||
|  |         let buf_pos = AtomicUsize::new(0); | ||||||
|  |         Ok(Self { | ||||||
|  |             buf_ptr, | ||||||
|  |             buf_size, | ||||||
|  |             buf_pos, | ||||||
|  |         }) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     pub fn new_slice(&self, src_slice: &[u8]) -> Result<&[u8]> { | ||||||
|  |         let mut new_slice = self.new_slice_mut(src_slice.len())?; | ||||||
|  |         new_slice.copy_from_slice(src_slice); | ||||||
|  |         Ok(new_slice) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     pub fn new_slice_mut(&self, new_slice_len: usize) -> Result<&mut [u8]> { | ||||||
|  |         let new_slice_ptr = { | ||||||
|  |             // Move self.buf_pos forward if enough space _atomically_.
 | ||||||
|  |             let old_pos = self | ||||||
|  |                 .buf_pos | ||||||
|  |                 .fetch_update( | ||||||
|  |                     |old_pos| { | ||||||
|  |                         let new_pos = old_pos + new_slice_len; | ||||||
|  |                         if new_pos <= self.buf_size { | ||||||
|  |                             Some(new_pos) | ||||||
|  |                         } else { | ||||||
|  |                             None | ||||||
|  |                         } | ||||||
|  |                     }, | ||||||
|  |                     Ordering::SeqCst, | ||||||
|  |                     Ordering::SeqCst, | ||||||
|  |                 ) | ||||||
|  |                 .map_err(|e| errno!(ENOMEM, "No enough space"))?; | ||||||
|  |             unsafe { self.buf_ptr.add(old_pos) } | ||||||
|  |         }; | ||||||
|  |         let new_slice = unsafe { std::slice::from_raw_parts_mut(new_slice_ptr, new_slice_len) }; | ||||||
|  |         Ok(new_slice) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl Drop for UntrustedSliceAlloc { | ||||||
|  |     fn drop(&mut self) { | ||||||
|  |         // Do nothing for the dummy case
 | ||||||
|  |         if self.buf_size == 0 { | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         let layout = Layout::from_size_align(self.buf_size, 1).unwrap(); | ||||||
|  |         unsafe { | ||||||
|  |             UNTRUSTED_ALLOC.dealloc(NonNull::new(self.buf_ptr).unwrap(), layout); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										76
									
								
								src/libos/src/untrusted/slice_ext.rs
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										76
									
								
								src/libos/src/untrusted/slice_ext.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,76 @@ | |||||||
|  | /// Extension traits for slices
 | ||||||
|  | use super::*; | ||||||
|  | use std::ptr; | ||||||
|  | 
 | ||||||
|  | /// An extension trait for slice to get its _const_ pointer and length.
 | ||||||
|  | ///
 | ||||||
|  | /// If the length is zero, then the pointer is null. This trait is handy when
 | ||||||
|  | /// it comes to converting slices to pointers and lengths for OCalls.
 | ||||||
|  | pub trait SliceAsPtrAndLen<T> { | ||||||
|  |     fn as_ptr_and_len(&self) -> (*const T, usize); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl<T> SliceAsPtrAndLen<T> for Option<&[T]> { | ||||||
|  |     fn as_ptr_and_len(&self) -> (*const T, usize) { | ||||||
|  |         match self { | ||||||
|  |             Some(self_slice) => self_slice.as_ptr_and_len(), | ||||||
|  |             None => (std::ptr::null(), 0), | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl<T> SliceAsPtrAndLen<T> for Option<&mut [T]> { | ||||||
|  |     fn as_ptr_and_len(&self) -> (*const T, usize) { | ||||||
|  |         match self { | ||||||
|  |             Some(self_slice) => self_slice.as_ptr_and_len(), | ||||||
|  |             None => (std::ptr::null(), 0), | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl<T> SliceAsPtrAndLen<T> for &[T] { | ||||||
|  |     fn as_ptr_and_len(&self) -> (*const T, usize) { | ||||||
|  |         if self.len() > 0 { | ||||||
|  |             (self.as_ptr(), self.len()) | ||||||
|  |         } else { | ||||||
|  |             (ptr::null(), 0) | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl<T> SliceAsPtrAndLen<T> for &mut [T] { | ||||||
|  |     fn as_ptr_and_len(&self) -> (*const T, usize) { | ||||||
|  |         if self.len() > 0 { | ||||||
|  |             (self.as_ptr(), self.len()) | ||||||
|  |         } else { | ||||||
|  |             (ptr::null(), 0) | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /// An extension trait for slice to get its _mutable_ pointer and length.
 | ||||||
|  | ///
 | ||||||
|  | /// If the length is zero, then the pointer is null. This trait is handy when
 | ||||||
|  | /// it comes to converting slices to pointers and lengths for OCalls.
 | ||||||
|  | pub trait SliceAsMutPtrAndLen<T> { | ||||||
|  |     fn as_mut_ptr_and_len(&mut self) -> (*mut T, usize); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl<T> SliceAsMutPtrAndLen<T> for Option<&mut [T]> { | ||||||
|  |     fn as_mut_ptr_and_len(&mut self) -> (*mut T, usize) { | ||||||
|  |         match self { | ||||||
|  |             Some(self_slice) => self_slice.as_mut_ptr_and_len(), | ||||||
|  |             None => (std::ptr::null_mut(), 0), | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl<T> SliceAsMutPtrAndLen<T> for &mut [T] { | ||||||
|  |     fn as_mut_ptr_and_len(&mut self) -> (*mut T, usize) { | ||||||
|  |         if self.len() > 0 { | ||||||
|  |             (self.as_mut_ptr(), self.len()) | ||||||
|  |         } else { | ||||||
|  |             (ptr::null_mut(), 0) | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -3,5 +3,6 @@ | |||||||
| 
 | 
 | ||||||
| #include <time.h>       // import struct timespec | #include <time.h>       // import struct timespec | ||||||
| #include <sys/time.h>   // import struct timeval | #include <sys/time.h>   // import struct timeval | ||||||
|  | #include <sys/uio.h>    // import struct iovec | ||||||
| 
 | 
 | ||||||
| #endif /* __OCCLUM_EDL_TYPES__ */ | #endif /* __OCCLUM_EDL_TYPES__ */ | ||||||
|  | |||||||
							
								
								
									
										27
									
								
								src/pal/src/ocalls/mem.c
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										27
									
								
								src/pal/src/ocalls/mem.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,27 @@ | |||||||
|  | #include <stdlib.h> | ||||||
|  | #include "ocalls.h" | ||||||
|  | 
 | ||||||
|  | void* occlum_ocall_posix_memalign(size_t alignment, size_t size) { | ||||||
|  |     void* ptr = NULL; | ||||||
|  |     int ret = posix_memalign(&ptr, alignment, size); | ||||||
|  |     if (ret == 0) { | ||||||
|  |         return ptr; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // Handle errors
 | ||||||
|  |     switch(ret) { | ||||||
|  |         case ENOMEM: | ||||||
|  |             PAL_ERROR("Out of memory on the untrusted side"); | ||||||
|  |             break; | ||||||
|  |         case EINVAL: | ||||||
|  |             PAL_ERROR("Invalid arguments given to occlum_ocall_posix_memalign"); | ||||||
|  |             break; | ||||||
|  |         default: | ||||||
|  |             PAL_ERROR("Unexpected error in occlum_ocall_posix_memalign"); | ||||||
|  |     } | ||||||
|  |     return NULL; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void occlum_ocall_free(void* ptr) { | ||||||
|  |     free(ptr); | ||||||
|  | } | ||||||
| @ -6,20 +6,16 @@ | |||||||
| ssize_t occlum_ocall_sendmsg(int sockfd, | ssize_t occlum_ocall_sendmsg(int sockfd, | ||||||
|                              const void *msg_name, |                              const void *msg_name, | ||||||
|                              socklen_t msg_namelen, |                              socklen_t msg_namelen, | ||||||
|                              const void *buf, |                              const struct iovec *msg_iov, | ||||||
|                              size_t buf_len, |                              size_t msg_iovlen, | ||||||
|                              const void *msg_control, |                              const void *msg_control, | ||||||
|                              size_t msg_controllen, |                              size_t msg_controllen, | ||||||
|                              int flags) |                              int flags) | ||||||
| { | { | ||||||
|     struct iovec msg_iov = { .iov_base = (void*)buf, .iov_len = buf_len }; |  | ||||||
|     struct iovec* p_msg_iov = buf != NULL ? &msg_iov : NULL; |  | ||||||
|     size_t msg_iovlen = buf != NULL ? 1 : 0; |  | ||||||
| 
 |  | ||||||
|     struct msghdr msg = { |     struct msghdr msg = { | ||||||
|         (void*) msg_name, |         (void*) msg_name, | ||||||
|         msg_namelen, |         msg_namelen, | ||||||
|         p_msg_iov, |         (struct iovec *) msg_iov, | ||||||
|         msg_iovlen, |         msg_iovlen, | ||||||
|         (void*) msg_control, |         (void*) msg_control, | ||||||
|         msg_controllen, |         msg_controllen, | ||||||
| @ -32,22 +28,18 @@ ssize_t occlum_ocall_recvmsg(int sockfd, | |||||||
|                              void *msg_name, |                              void *msg_name, | ||||||
|                              socklen_t msg_namelen, |                              socklen_t msg_namelen, | ||||||
|                              socklen_t* msg_namelen_recv, |                              socklen_t* msg_namelen_recv, | ||||||
|                              void *buf, |                              struct iovec *msg_iov, | ||||||
|                              size_t buf_len, |                              size_t msg_iovlen, | ||||||
|                              void *msg_control, |                              void *msg_control, | ||||||
|                              size_t msg_controllen, |                              size_t msg_controllen, | ||||||
|                              size_t* msg_controllen_recv, |                              size_t* msg_controllen_recv, | ||||||
|                              int* msg_flags_recv, |                              int* msg_flags_recv, | ||||||
|                              int flags) |                              int flags) | ||||||
| { | { | ||||||
|     struct iovec msg_iov = { .iov_base = buf, .iov_len = buf_len }; |  | ||||||
|     struct iovec* p_msg_iov = buf != NULL ? &msg_iov : NULL; |  | ||||||
|     size_t msg_iovlen = buf != NULL ? 1 : 0; |  | ||||||
| 
 |  | ||||||
|     struct msghdr msg = { |     struct msghdr msg = { | ||||||
|         msg_name, |         msg_name, | ||||||
|         msg_namelen, |         msg_namelen, | ||||||
|         p_msg_iov, |         msg_iov, | ||||||
|         msg_iovlen, |         msg_iovlen, | ||||||
|         msg_control, |         msg_control, | ||||||
|         msg_controllen, |         msg_controllen, | ||||||
|  | |||||||
| @ -76,6 +76,13 @@ int client_sendmsg(int server_fd, char *buf) { | |||||||
|     ret = sendmsg(server_fd, &msg, 0); |     ret = sendmsg(server_fd, &msg, 0); | ||||||
|     if (ret <= 0) |     if (ret <= 0) | ||||||
|         THROW_ERROR("sendmsg failed"); |         THROW_ERROR("sendmsg failed"); | ||||||
|  | 
 | ||||||
|  |     msg.msg_iov = NULL; | ||||||
|  |     msg.msg_iovlen = 0; | ||||||
|  | 
 | ||||||
|  |     ret = sendmsg(server_fd, &msg, 0); | ||||||
|  |     if (ret != 0) | ||||||
|  |         THROW_ERROR("empty sendmsg failed"); | ||||||
|     return ret; |     return ret; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -64,13 +64,13 @@ int connect_with_child(int port, int *child_pid) { | |||||||
| 
 | 
 | ||||||
| int neogotiate_msg(int client_fd) { | int neogotiate_msg(int client_fd) { | ||||||
|     char buf[16]; |     char buf[16]; | ||||||
|     if (write(client_fd, ECHO_MSG, sizeof(ECHO_MSG)) < 0) |     if (write(client_fd, ECHO_MSG, strlen(ECHO_MSG)) < 0) | ||||||
|         THROW_ERROR("write failed"); |         THROW_ERROR("write failed"); | ||||||
| 
 | 
 | ||||||
|     if (read(client_fd, buf, 16) < 0) |     if (read(client_fd, buf, 16) < 0) | ||||||
|         THROW_ERROR("read failed"); |         THROW_ERROR("read failed"); | ||||||
| 
 | 
 | ||||||
|     if (strncmp(buf, RESPONSE, sizeof(RESPONSE)) != 0) { |     if (strncmp(buf, RESPONSE, strlen(RESPONSE)) != 0) { | ||||||
|         THROW_ERROR("msg recv mismatch"); |         THROW_ERROR("msg recv mismatch"); | ||||||
|     } |     } | ||||||
|     return 0; |     return 0; | ||||||
| @ -83,7 +83,7 @@ int server_recv(int client_fd) { | |||||||
|     if (recv(client_fd, buf, buf_size, 0) <= 0) |     if (recv(client_fd, buf, buf_size, 0) <= 0) | ||||||
|         THROW_ERROR("msg recv failed"); |         THROW_ERROR("msg recv failed"); | ||||||
| 
 | 
 | ||||||
|     if (strncmp(buf, ECHO_MSG, sizeof(ECHO_MSG)) != 0) { |     if (strncmp(buf, ECHO_MSG, strlen(ECHO_MSG)) != 0) { | ||||||
|         THROW_ERROR("msg recv mismatch"); |         THROW_ERROR("msg recv mismatch"); | ||||||
|     } |     } | ||||||
|     return 0; |     return 0; | ||||||
| @ -91,17 +91,21 @@ int server_recv(int client_fd) { | |||||||
| 
 | 
 | ||||||
| int server_recvmsg(int client_fd) { | int server_recvmsg(int client_fd) { | ||||||
|     int ret = 0; |     int ret = 0; | ||||||
|     const int buf_size = 1000; |     const int buf_size = 10; | ||||||
|     char buf[buf_size]; |     char buf[3][buf_size]; | ||||||
|     struct msghdr msg; |     struct msghdr msg; | ||||||
|     struct iovec iov[1]; |     struct iovec iov[3]; | ||||||
| 
 | 
 | ||||||
|     msg.msg_name  = NULL; |     msg.msg_name  = NULL; | ||||||
|     msg.msg_namelen  = 0; |     msg.msg_namelen  = 0; | ||||||
|     iov[0].iov_base = buf; |     iov[0].iov_base = buf[0]; | ||||||
|     iov[0].iov_len = buf_size; |     iov[0].iov_len = buf_size; | ||||||
|  |     iov[1].iov_base = buf[1]; | ||||||
|  |     iov[1].iov_len = buf_size; | ||||||
|  |     iov[2].iov_base = buf[2]; | ||||||
|  |     iov[2].iov_len = buf_size; | ||||||
|     msg.msg_iov = iov; |     msg.msg_iov = iov; | ||||||
|     msg.msg_iovlen = 1; |     msg.msg_iovlen = 3; | ||||||
|     msg.msg_control = 0; |     msg.msg_control = 0; | ||||||
|     msg.msg_controllen = 0; |     msg.msg_controllen = 0; | ||||||
|     msg.msg_flags = 0; |     msg.msg_flags = 0; | ||||||
| @ -110,11 +114,18 @@ int server_recvmsg(int client_fd) { | |||||||
|     if (ret <= 0) { |     if (ret <= 0) { | ||||||
|         THROW_ERROR("recvmsg failed"); |         THROW_ERROR("recvmsg failed"); | ||||||
|     } else { |     } else { | ||||||
|         if (strncmp(buf, ECHO_MSG, sizeof(ECHO_MSG)) != 0) { |         if (strncmp(buf[0], ECHO_MSG, buf_size) != 0 && | ||||||
|             printf("recvmsg : %d, msg: %s\n", ret, buf); |                 strstr(ECHO_MSG, buf[1]) != NULL && | ||||||
|  |                 strstr(ECHO_MSG, buf[2]) != NULL) { | ||||||
|  |             printf("recvmsg : %d, msg: %s,  %s, %s\n", ret, buf[0], buf[1], buf[2]); | ||||||
|             THROW_ERROR("msg recvmsg mismatch"); |             THROW_ERROR("msg recvmsg mismatch"); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |     msg.msg_iov = NULL; | ||||||
|  |     msg.msg_iovlen = 0; | ||||||
|  |     ret = recvmsg(client_fd, &msg, 0); | ||||||
|  |     if (ret != 0) | ||||||
|  |         THROW_ERROR("recvmsg empty failed"); | ||||||
|     return ret; |     return ret; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -157,7 +168,7 @@ int server_connectionless_recvmsg() { | |||||||
|     if (ret <= 0) { |     if (ret <= 0) { | ||||||
|         THROW_ERROR("recvmsg failed"); |         THROW_ERROR("recvmsg failed"); | ||||||
|     } else { |     } else { | ||||||
|         if (strncmp(buf, DEFAULT_MSG, sizeof(DEFAULT_MSG)) != 0) { |         if (strncmp(buf, DEFAULT_MSG, strlen(DEFAULT_MSG)) != 0) { | ||||||
|             printf("recvmsg : %d, msg: %s\n", ret, buf); |             printf("recvmsg : %d, msg: %s\n", ret, buf); | ||||||
|             THROW_ERROR("msg recvmsg mismatch"); |             THROW_ERROR("msg recvmsg mismatch"); | ||||||
|         } else { |         } else { | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user