From eb41b233551937ae298fe40277cf5f693f03e019 Mon Sep 17 00:00:00 2001 From: davidge20 Date: Mon, 15 Jul 2024 22:51:19 +0000 Subject: [PATCH 01/13] Initial comments on send syscall --- src/safeposix/syscalls/net_calls.rs | 116 +++++++++++++++++++++++++++- 1 file changed, 115 insertions(+), 1 deletion(-) diff --git a/src/safeposix/syscalls/net_calls.rs b/src/safeposix/syscalls/net_calls.rs index 22ebf9af8..5d654b72e 100644 --- a/src/safeposix/syscalls/net_calls.rs +++ b/src/safeposix/syscalls/net_calls.rs @@ -1363,15 +1363,122 @@ impl Cage { } } + /// ### Description + /// + /// `send_syscall` sends a message on a socket + /// + /// The send() call may be used only when the socket is in a + /// connected state (so that the intended recipient is known). + /// + /// ### Arguments + /// + /// it accepts two parameters: + /// * `fd` - the file descriptor that refers to the listening socket + /// * `buf` - the message is found in buf + /// * `buflen` - the len of the message found in buf + /// * `flags` - bitwise OR of zero or more flags. Refer to man page to find + /// possible args + /// + /// ### Returns + /// + /// On success, these calls return the number of bytes sent. On error, a + /// negative error number is returned, with the errorno set to represent + /// the corresponding error + /// + /// ### Errors + /// + /// These are some standard errors generated by the socket layer. + /// Additional errors may be generated and returned from the + /// underlying protocol modules; see their respective manual pages. + /// + /// * EACCES - (For UNIX domain sockets, which are identified by pathname) + /// Write permission is denied on the destination socket file, or search + /// permission is denied for one of the directories the path prefix. (See + /// path_resolution(7).) (For UDP sockets) An attempt was made to send to + /// a network/broadcast address as though it was a unicast address. + /// + /// * EAGAIN or EWOULDBLOCK - The socket is marked nonblocking and the + /// requested operation would block. POSIX.1-2001 allows either error to + /// be returned for this case, and does not require these constants to + /// have the same value, so a portable application should check for both + /// possibilities. + /// + /// * EAGAIN - (Internet domain datagram sockets) The socket referred to by + /// sockfd had not previously been bound to an address and, upon + /// attempting to bind it to an ephemeral port, it was determined that all + /// port numbers in the ephemeral port range are currently in use. See + /// the discussion of /proc/sys/net/ipv4/ip_local_port_range in ip(7). + /// + /// * EALREADY - Another Fast Open is in progress. + /// + /// * EBADF - sockfd is not a valid open file descriptor. + /// + /// * ECONNRESET - Connection reset by peer. + /// + /// * EDESTADDRREQ - The socket is not connection-mode, and no peer address + /// is set. + /// + /// * EFAULT - An invalid user space address was specified for an argument. + /// + /// * EINTR - A signal occurred before any data was transmitted; see + /// signal(7). + /// + /// * EINVAL - Invalid argument passed. + /// + /// * EISCONN - The connection-mode socket was connected already but a + /// recipient was specified. (Now either this error is returned, or the + /// recipient specification is ignored.) + /// + /// * EMSGSIZE - The socket type requires that message be sent atomically, + /// and the size of the message to be sent made this impossible. + /// + /// * ENOBUFS - The output queue for a network interface was full. This + /// generally indicates that the interface has stopped sending, but may be + /// caused by transient congestion. (Normally, this does not occur in + /// Linux. Packets are just silently dropped when a device queue + /// overflows.) + /// + /// * ENOMEM - No memory available. + /// + /// * ENOTCONN - The socket is not connected, and no target has been given. + /// + /// * ENOTSOCK - The file descriptor sockfd does not refer to a socket. + /// + /// * EOPNOTSUPP - Some bit in the flags argument is inappropriate for the + /// socket type. + /// + /// * EPIPE - The local end has been shut down on a connection oriented + /// socket. In this case, the process will also receive a SIGPIPE unless + /// MSG_NOSIGNAL is set. + /// + /// ** Indicates the error may be returned from RustPOSIX + /// + /// ### Panics TODO: + /// + /// * invalid or out-of-bounds file descriptor, calling unwrap() on it will + /// cause a panic. + /// * Unknown errno value from fcntl returned, will cause panic. + /// + /// for more detailed description of all the commands and return values, see + /// [send(2)](https://linux.die.net/man/2/send) pub fn send_syscall(&self, fd: i32, buf: *const u8, buflen: usize, flags: i32) -> i32 { + //BUG: + //If fd is out of range of [0,MAXFD], process will panic + //Otherwise, we obtain a write gaurd to the Option object let checkedfd = self.get_filedescriptor(fd).unwrap(); let mut unlocked_fd = checkedfd.write(); + //If the write gaurd holds a valid FileDescriptor if let Some(filedesc_enum) = &mut *unlocked_fd { match filedesc_enum { + //The file descriptor refers to a socket Socket(ref mut sockfdobj) => { + //Grab a write guard to the socket handle let sock_tmp = sockfdobj.handle.clone(); let sockhandle = sock_tmp.write(); + //** Check if this is a bug */ + //If the flags given as an argument includes a flag that + //is not MSG_NOSIGNAL, return with error if (flags & !MSG_NOSIGNAL) != 0 { return syscall_error( Errno::EOPNOTSUPP, @@ -1380,7 +1487,9 @@ impl Cage { ); } - // check if this is a domain socket + //Pattern match based on the domain of the socket + //Lind handles the send syscall of UNIX sockets internally, + //but will call send from libc for INET sockets let socket_type = sockhandle.domain; match socket_type { AF_UNIX => { @@ -1488,6 +1597,8 @@ impl Cage { ); } }, + //If the domain of the socket is not UNIX or INET + //lind does not support it _ => { return syscall_error( Errno::EINVAL, @@ -1497,6 +1608,8 @@ impl Cage { } } } + //If the file descriptor does not refer to a socket, + //return with error _ => { return syscall_error( Errno::ENOTSOCK, @@ -1505,6 +1618,7 @@ impl Cage { ); } } + //Otherwise, the write gaurd does not hold a FileDescriptor } else { return syscall_error(Errno::EBADF, "send", "invalid file descriptor"); } From 19f7495e6260b63efa8c43e1b37659ef56da2266 Mon Sep 17 00:00:00 2001 From: davidge20 Date: Tue, 16 Jul 2024 04:54:09 +0000 Subject: [PATCH 02/13] Small comments --- src/safeposix/syscalls/net_calls.rs | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/src/safeposix/syscalls/net_calls.rs b/src/safeposix/syscalls/net_calls.rs index 5d654b72e..f40a42686 100644 --- a/src/safeposix/syscalls/net_calls.rs +++ b/src/safeposix/syscalls/net_calls.rs @@ -1476,8 +1476,12 @@ impl Cage { let sock_tmp = sockfdobj.handle.clone(); let sockhandle = sock_tmp.write(); - //** Check if this is a bug */ - //If the flags given as an argument includes a flag that + //** Seems like a BUG: + //The current conditional statement checks if theres + //a flag besides MSG_NOSIGNAL, and if so, return + //that the flag is not supported + //Why would only 1 flag be supported? */ + //If the flags given as an argument includes a flag that //is not MSG_NOSIGNAL, return with error if (flags & !MSG_NOSIGNAL) != 0 { return syscall_error( @@ -1488,15 +1492,20 @@ impl Cage { } //Pattern match based on the domain of the socket - //Lind handles the send syscall of UNIX sockets internally, + //Lind handles UNIX sockets internally, //but will call send from libc for INET sockets let socket_type = sockhandle.domain; match socket_type { AF_UNIX => { + //Pattern match based on the socket protocol match sockhandle.protocol { + //TCP socket + // ** Why isn't the protocol 0?? */ + // ** If this is fine, why don't we handle UDP sockets ?? // IPPROTO_TCP => { - // to be able to send here we either need to be fully connected, - // or connected for write only + //For a TCP socket + //to be able to send here we either need to be fully connected, + //or connected for write only if (sockhandle.state != ConnState::CONNECTED) && (sockhandle.state != ConnState::CONNWRONLY) { @@ -1608,7 +1617,7 @@ impl Cage { } } } - //If the file descriptor does not refer to a socket, + //If the file descriptor does not refer to a socket, //return with error _ => { return syscall_error( From 4df0ad895f52bb429ee2bb604750e7b4ebb23110 Mon Sep 17 00:00:00 2001 From: davidge20 Date: Tue, 16 Jul 2024 05:36:22 +0000 Subject: [PATCH 03/13] More small changes --- src/safeposix/syscalls/net_calls.rs | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/src/safeposix/syscalls/net_calls.rs b/src/safeposix/syscalls/net_calls.rs index f40a42686..b61073501 100644 --- a/src/safeposix/syscalls/net_calls.rs +++ b/src/safeposix/syscalls/net_calls.rs @@ -1503,9 +1503,9 @@ impl Cage { // ** Why isn't the protocol 0?? */ // ** If this is fine, why don't we handle UDP sockets ?? // IPPROTO_TCP => { - //For a TCP socket - //to be able to send here we either need to be fully connected, - //or connected for write only + //For a TCP socket to be able to send here we + //either need to be fully connected, or connected for write + // only if (sockhandle.state != ConnState::CONNECTED) && (sockhandle.state != ConnState::CONNWRONLY) { @@ -1517,14 +1517,30 @@ impl Cage { } // get the socket pipe, write to it, and return bytes written let sockinfo = &sockhandle.unix_info.as_ref().unwrap(); + //When the message does not fit into the send buffer of the + // socket, send() normally + // blocks, unless the socket has been placed in + // nonblocking I/O mode. In nonblocking mode it would fail with + // the error EAGAIN or + // EWOULDBLOCK in this case. let mut nonblocking = false; if sockfdobj.flags & O_NONBLOCK != 0 { nonblocking = true; } let retval = match sockinfo.sendpipe.as_ref() { + //sendpipe is available in unix socket info Some(sendpipe) => { + //write_to_pipe writes a specified number of bytes + // starting at the given + // pointer to a circular buffer. Upon successful + // completion, the amount of bytes written is returned. + // In case of a failure, an error is returned to the + // calling syscall. + // Refer to src/interface/pipe.rs for errors sendpipe.write_to_pipe(buf, buflen, nonblocking) as i32 } + //sendpipe is not available in unix socket info + //transmission of data is not possible so return with error None => { return syscall_error(Errno::EAGAIN, "writev", "there is no data available right now, try again later"); } @@ -1532,7 +1548,8 @@ impl Cage { if retval == -(Errno::EPIPE as i32) { interface::lind_kill_from_id(self.cageid, SIGPIPE); } // Trigger SIGPIPE - retval + retval //return number of bytes written to + // buf } _ => { return syscall_error( From e7de7f6f7d882f29142ebf469ba6643a9478157f Mon Sep 17 00:00:00 2001 From: davidge20 Date: Tue, 16 Jul 2024 21:24:46 +0000 Subject: [PATCH 04/13] Added two tests for send sys call and removed MSG_NOSIGNAL flag checking --- src/safeposix/syscalls/net_calls.rs | 195 ++++++++++++++++------------ src/tests/networking_tests.rs | 159 +++++++++++++++++++++++ 2 files changed, 268 insertions(+), 86 deletions(-) diff --git a/src/safeposix/syscalls/net_calls.rs b/src/safeposix/syscalls/net_calls.rs index b61073501..e97cf80cc 100644 --- a/src/safeposix/syscalls/net_calls.rs +++ b/src/safeposix/syscalls/net_calls.rs @@ -1279,13 +1279,6 @@ impl Cage { "An address with an invalid family for the given domain was specified", ); } - if (flags & !MSG_NOSIGNAL) != 0 { - return syscall_error( - Errno::EOPNOTSUPP, - "sendto", - "The flags are not understood!", - ); - } if sockhandle.state != ConnState::NOTCONNECTED { return syscall_error( @@ -1373,7 +1366,7 @@ impl Cage { /// ### Arguments /// /// it accepts two parameters: - /// * `fd` - the file descriptor that refers to the listening socket + /// * `fd` - the file descriptor of the sending socket /// * `buf` - the message is found in buf /// * `buflen` - the len of the message found in buf /// * `flags` - bitwise OR of zero or more flags. Refer to man page to find @@ -1457,7 +1450,7 @@ impl Cage { /// /// * invalid or out-of-bounds file descriptor, calling unwrap() on it will /// cause a panic. - /// * Unknown errno value from fcntl returned, will cause panic. + /// * Unknown errno value from sendto returned, will cause panic. /// /// for more detailed description of all the commands and return values, see /// [send(2)](https://linux.die.net/man/2/send) @@ -1476,21 +1469,6 @@ impl Cage { let sock_tmp = sockfdobj.handle.clone(); let sockhandle = sock_tmp.write(); - //** Seems like a BUG: - //The current conditional statement checks if theres - //a flag besides MSG_NOSIGNAL, and if so, return - //that the flag is not supported - //Why would only 1 flag be supported? */ - //If the flags given as an argument includes a flag that - //is not MSG_NOSIGNAL, return with error - if (flags & !MSG_NOSIGNAL) != 0 { - return syscall_error( - Errno::EOPNOTSUPP, - "send", - "The flags are not understood!", - ); - } - //Pattern match based on the domain of the socket //Lind handles UNIX sockets internally, //but will call send from libc for INET sockets @@ -1509,6 +1487,9 @@ impl Cage { if (sockhandle.state != ConnState::CONNECTED) && (sockhandle.state != ConnState::CONNWRONLY) { + //Otherwise, return with an error as + //TCP sockets taht aren't connected + //can't send messages return syscall_error( Errno::ENOTCONN, "writev", @@ -1529,14 +1510,9 @@ impl Cage { } let retval = match sockinfo.sendpipe.as_ref() { //sendpipe is available in unix socket info + //it is needed to send the message found in buf + //to the connected socket Some(sendpipe) => { - //write_to_pipe writes a specified number of bytes - // starting at the given - // pointer to a circular buffer. Upon successful - // completion, the amount of bytes written is returned. - // In case of a failure, an error is returned to the - // calling syscall. - // Refer to src/interface/pipe.rs for errors sendpipe.write_to_pipe(buf, buflen, nonblocking) as i32 } //sendpipe is not available in unix socket info @@ -1545,12 +1521,27 @@ impl Cage { return syscall_error(Errno::EAGAIN, "writev", "there is no data available right now, try again later"); } }; + //In the case that the write_to_pipe call returns EPIPE, + // meaning The local end has been shut down on a connection + // oriented socket. In this case, the process will also receive + // a SIGPIPE unless + // MSG_NOSIGNAL is set. if retval == -(Errno::EPIPE as i32) { + // The default action for SIGPIPE is to terminate the + // process without a core dump. This simplifies error + // handling in programs that + // are meant to run as part of a shell pipeline: reading + // input, transforming it, and then writing it to another + // process. SIGPIPE allows the program to skip error + // handling and blindly write data until it’s killed + + //TODO only send kill if MSG_NOSIGNAL not set interface::lind_kill_from_id(self.cageid, SIGPIPE); } // Trigger SIGPIPE - retval //return number of bytes written to - // buf + retval //return number of bytes sent } + //If PROTOCOL is not TCP + // ** Why is this the case for unix ?? **// _ => { return syscall_error( Errno::EOPNOTSUPP, @@ -1560,69 +1551,101 @@ impl Cage { } } } - // for inet - AF_INET | AF_INET6 => match sockhandle.protocol { - IPPROTO_TCP => { - if (sockhandle.state != ConnState::CONNECTED) - && (sockhandle.state != ConnState::CONNWRONLY) - { - return syscall_error( - Errno::ENOTCONN, - "send", - "The descriptor is not connected", - ); + //Pattern match based on the socket protocol + AF_INET | AF_INET6 => { + match sockhandle.protocol { + //For a TCP socket to be able to send here we + //either need to be fully connected, or connected for write + // only + IPPROTO_TCP => { + if (sockhandle.state != ConnState::CONNECTED) + && (sockhandle.state != ConnState::CONNWRONLY) + { + //Otherwise, return with an error as + //TCP sockets taht aren't connected + //can't send messages + return syscall_error( + Errno::ENOTCONN, + "send", + "The descriptor is not connected", + ); + } + + //We passed the above check so the TCP socket must be connected + //Hence, it must have a valid inner socket/raw sys fd + //Call sendto from libc to send the buff + let retval = sockhandle + .innersocket + .as_ref() + .unwrap() + .sendto(buf, buflen, None); + //If the call to sendto from libc return + //-1, indicating an error, retrieve the err + //and return appropriately + //Otherwise, return the number of bytes + //written to the connected socket + if retval < 0 { + match Errno::from_discriminant(interface::get_errno()) { + Ok(i) => { + return syscall_error( + i, + "send", + "The libc call to sendto failed!", + ); + } + Err(()) => panic!( + "Unknown errno value from socket sendto returned!" + ), + }; + } else { + return retval; //return the number of + // bytes written to the + // connected socket + } } - //because socket must be connected it must have an inner socket - let retval = sockhandle - .innersocket - .as_ref() - .unwrap() - .sendto(buf, buflen, None); - if retval < 0 { - match Errno::from_discriminant(interface::get_errno()) { - Ok(i) => { + //For INET sockets following the UDP protocol, + //we don't need to check for connection status + //as UDP is connection-less. This lets us grab + //the remote address of the socket and send the + //message in buf to it by calling sendto_syscall + IPPROTO_UDP => { + let remoteaddr = match &sockhandle.remoteaddr { + Some(x) => x.clone(), + None => { return syscall_error( - i, + Errno::ENOTCONN, "send", - "The libc call to sendto failed!", + "The descriptor is not connected", ); } - Err(()) => panic!( - "Unknown errno value from socket sendto returned!" - ), }; - } else { - return retval; + //** Why is it necessary to drop here?? */ + drop(unlocked_fd); + drop(sockhandle); + //remote address is set in sendto from libc + //as UDP socket is connection-less + return self.sendto_syscall( + fd, + buf, + buflen, + flags, + &remoteaddr, + ); //return the number of bytes written to the connected socket + //** TODO: Add error checking on the return value */ } - } - - IPPROTO_UDP => { - let remoteaddr = match &sockhandle.remoteaddr { - Some(x) => x.clone(), - None => { - return syscall_error( - Errno::ENOTCONN, - "send", - "The descriptor is not connected", - ); - } - }; - drop(unlocked_fd); - drop(sockhandle); - //send from a udp socket is just shunted off to sendto with the - // remote address set - return self.sendto_syscall(fd, buf, buflen, flags, &remoteaddr); - } - _ => { - return syscall_error( - Errno::EOPNOTSUPP, - "send", - "Unkown protocol in send", - ); + //Protcol besides UDP and TCP are not supported + //for INET sockets in lind + _ => { + return syscall_error( + Errno::EOPNOTSUPP, + "send", + "Unkown protocol in send", + ); + } } - }, + } //If the domain of the socket is not UNIX or INET //lind does not support it _ => { diff --git a/src/tests/networking_tests.rs b/src/tests/networking_tests.rs index da94213b3..64a942885 100644 --- a/src/tests/networking_tests.rs +++ b/src/tests/networking_tests.rs @@ -1659,6 +1659,165 @@ pub mod net_tests { lindrustfinalize(); } + #[test] + //The connection between the client and the server ends early as the + //server socket fd is closed. The expected behavior is that errno is set + //to EBADF from the recvfrom_syscall + pub fn ut_lind_net_send_close_server_socket_early() { + //acquiring a lock on TESTMUTEX prevents other tests from running concurrently, + // and also performs clean env setup + let _thelock = setup::lock_and_init(); + + let cage = interface::cagetable_getref(1); + + let serversockfd = cage.socket_syscall(AF_INET, SOCK_STREAM, 0); + let clientsockfd = cage.socket_syscall(AF_INET, SOCK_STREAM, 0); + + //making sure that the assigned fd's are valid + assert!(serversockfd > 0); + assert!(clientsockfd > 0); + let port: u16 = generate_random_port(); + //binding to a socket + let sockaddr = interface::SockaddrV4 { + sin_family: AF_INET as u16, + sin_port: port.to_be(), + sin_addr: interface::V4Addr { + s_addr: u32::from_ne_bytes([127, 0, 0, 1]), + }, + padding: 0, + }; + let socket = interface::GenSockaddr::V4(sockaddr); //127.0.0.1 + assert_eq!(cage.bind_syscall(serversockfd, &socket), 0); + assert_eq!(cage.listen_syscall(serversockfd, 1), 0); //we are only allowing for one client at a time + + //forking the cage to get another cage with the same information + assert_eq!(cage.fork_syscall(2), 0); + + //creating a thread for the server so that the information can be sent between + // the two threads + let thread = interface::helper_thread(move || { + let cage2 = interface::cagetable_getref(2); + interface::sleep(interface::RustDuration::from_millis(100)); + let port: u16 = generate_random_port(); + + //Address of the socket to be accepted + let mut socket2 = interface::GenSockaddr::V4(interface::SockaddrV4 { + sin_family: AF_INET as u16, + sin_port: port.to_be(), + sin_addr: interface::V4Addr { + s_addr: u32::from_ne_bytes([127, 0, 0, 1]), + }, + padding: 0, + }); //127.0.0.1 + let sockfd = cage2.accept_syscall(serversockfd, &mut socket2); + //really can only make sure that the fd is valid + assert!(sockfd > 0); + + //process the first test... + //Writing 100, read 100 + let mut buf = sizecbuf(100); + assert_eq!( + cage2.recvfrom_syscall(sockfd, buf.as_mut_ptr(), 100, 0, &mut Some(&mut socket2)), + 100 + ); //reading the input message + + interface::sleep(interface::RustDuration::from_millis(500)); + + assert_eq!(cage2.close_syscall(sockfd), 0); + + //attempt to process the second test... + //Writing 100, read 100 + buf = sizecbuf(100); + assert_eq!( + cage2.recvfrom_syscall(sockfd, buf.as_mut_ptr(), 100, 0, &mut Some(&mut socket2)), + -(Errno::EBADF as i32) + ); //reading the input message + + interface::sleep(interface::RustDuration::from_millis(500)); + + assert_eq!(cage2.close_syscall(serversockfd), 0); + assert_eq!(cage2.exit_syscall(EXIT_SUCCESS), EXIT_SUCCESS); + }); + + //connect to the server + assert_eq!(cage.connect_syscall(clientsockfd, &socket), 0); + + //send the data with delays so that the server can process the information + // cleanly + assert_eq!( + cage.send_syscall(clientsockfd, str2cbuf(&"A".repeat(100)), 100, 0), + 100 + ); + interface::sleep(interface::RustDuration::from_millis(100)); + + assert_eq!( + cage.send_syscall(clientsockfd, str2cbuf(&"A".repeat(100)), 100, 0), + 100 + ); + interface::sleep(interface::RustDuration::from_millis(100)); + + thread.join().unwrap(); + + assert_eq!(cage.exit_syscall(EXIT_SUCCESS), EXIT_SUCCESS); + lindrustfinalize(); + } + + #[test] + //The client does not have a peer address set. The expected behavior is that + // errno is set to ENOTCONN from the send_syscall + pub fn ut_lind_net_send_no_peer_address() { + //acquiring a lock on TESTMUTEX prevents other tests from running concurrently, + // and also performs clean env setup + let _thelock = setup::lock_and_init(); + + let cage = interface::cagetable_getref(1); + + let serverfd = cage.socket_syscall(AF_INET, SOCK_DGRAM, 0); + let clientfd = cage.socket_syscall(AF_INET, SOCK_DGRAM, 0); + + //making sure that the assigned fd's are valid + assert!(serverfd > 0); + assert!(clientfd > 0); + let port: u16 = generate_random_port(); + //binding to a socket + let sockaddr = interface::SockaddrV4 { + sin_family: AF_INET as u16, + sin_port: port.to_be(), + sin_addr: interface::V4Addr { + s_addr: u32::from_ne_bytes([127, 0, 0, 1]), + }, + padding: 0, + }; + let socket = interface::GenSockaddr::V4(sockaddr); //127.0.0.1 + + //forking the cage to get another cage with the same information + assert_eq!(cage.fork_syscall(2), 0); + + //starting a new cage to handle server side connection + let thread = interface::helper_thread(move || { + let cage2 = interface::cagetable_getref(2); + assert_eq!(cage2.bind_syscall(serverfd, &socket), 0); + + interface::sleep(interface::RustDuration::from_millis(30)); + + assert_eq!(cage2.close_syscall(serverfd), 0); + assert_eq!(cage2.exit_syscall(EXIT_SUCCESS), EXIT_SUCCESS); + }); + + interface::sleep(interface::RustDuration::from_millis(50)); + let buf2 = str2cbuf("test"); + assert_eq!( + cage.send_syscall(clientfd, buf2, 4, 0), + -(Errno::ENOTCONN as i32) + ); + + thread.join().unwrap(); + + assert_eq!(cage.close_syscall(clientfd), 0); + assert_eq!(cage.exit_syscall(EXIT_SUCCESS), EXIT_SUCCESS); + lindrustfinalize(); + } + #[test] pub fn ut_lind_net_select_badinput() { // this test is used for testing select with error cases From a642766eb264d18fc50b136d654023b295149119 Mon Sep 17 00:00:00 2001 From: davidge20 Date: Wed, 17 Jul 2024 18:54:11 +0000 Subject: [PATCH 05/13] updated sendto func --- src/safeposix/syscalls/net_calls.rs | 211 +++++++++++++++++++++++----- 1 file changed, 176 insertions(+), 35 deletions(-) diff --git a/src/safeposix/syscalls/net_calls.rs b/src/safeposix/syscalls/net_calls.rs index e97cf80cc..478e36d15 100644 --- a/src/safeposix/syscalls/net_calls.rs +++ b/src/safeposix/syscalls/net_calls.rs @@ -1242,6 +1242,108 @@ impl Cage { } } + /// ### Description + /// + /// `sendto_syscall` sends a message on a socket + /// + /// Note: + /// send(fd, buf, buflen, flags); + /// is equivalent to + /// sendto(fd, buf, buflen, flags, destaddr); + /// where destaddr has an unspecified port or IP + /// + /// ### Arguments + /// + /// it accepts five parameters: + /// * `fd` - the file descriptor of the sending socket + /// * `buf` - the message is found in buf + /// * `buflen` - the len of the message found in buf + /// * `flags` - bitwise OR of zero or more flags. Refer to man page to find + /// possible args + /// * 'destaddr' - the address of the target socket + /// + /// ### Returns + /// + /// On success, the call returns the number of bytes sent. On error, a + /// negative error number is returned, with the errorno set to represent + /// the corresponding error + /// + /// ### Errors + /// + /// These are some standard errors generated by the socket layer. + /// Additional errors may be generated and returned from the + /// underlying protocol modules; see their respective manual pages. + /// + /// * EACCES - (For UNIX domain sockets, which are identified by pathname) + /// Write permission is denied on the destination socket file, or search + /// permission is denied for one of the directories the path prefix. (See + /// path_resolution(7).) (For UDP sockets) An attempt was made to send to + /// a network/broadcast address as though it was a unicast address. + /// + /// ** EAGAIN or EWOULDBLOCK - The socket is marked nonblocking and the + /// requested operation would block. POSIX.1-2001 allows either error to + /// be returned for this case, and does not require these constants to + /// have the same value, so a portable application should check for both + /// possibilities. + /// + /// ** EAGAIN - (Internet domain datagram sockets) The socket referred to by + /// sockfd had not previously been bound to an address and, upon + /// attempting to bind it to an ephemeral port, it was determined that all + /// port numbers in the ephemeral port range are currently in use. See + /// the discussion of /proc/sys/net/ipv4/ip_local_port_range in ip(7). + /// + /// * EALREADY - Another Fast Open is in progress. + /// + /// ** EBADF - sockfd is not a valid open file descriptor. + /// + /// * ECONNRESET - Connection reset by peer. + /// + /// * EDESTADDRREQ - The socket is not connection-mode, and no peer address + /// is set. + /// + /// * EFAULT - An invalid user space address was specified for an argument. + /// + /// * EINTR - A signal occurred before any data was transmitted; see + /// signal(7). + /// + /// ** EINVAL - Invalid argument passed. + /// + /// * EISCONN - The connection-mode socket was connected already but a + /// recipient was specified. (Now either this error is returned, or the + /// recipient specification is ignored.) + /// + /// * EMSGSIZE - The socket type requires that message be sent atomically, + /// and the size of the message to be sent made this impossible. + /// + /// * ENOBUFS - The output queue for a network interface was full. This + /// generally indicates that the interface has stopped sending, but may be + /// caused by transient congestion. (Normally, this does not occur in + /// Linux. Packets are just silently dropped when a device queue + /// overflows.) + /// + /// * ENOMEM - No memory available. + /// + /// ** ENOTCONN - The socket is not connected, and no target has been given. + /// + /// ** ENOTSOCK - The file descriptor sockfd does not refer to a socket. + /// + /// ** EOPNOTSUPP - Some bit in the flags argument is inappropriate for the + /// socket type. + /// + /// ** EPIPE - The local end has been shut down on a connection oriented + /// socket. In this case, the process will also receive a SIGPIPE unless + /// MSG_NOSIGNAL is set. + /// + /// ** Indicates the error may be returned from RustPOSIX + /// + /// ### Panics TODO: + /// + /// * invalid or out-of-bounds file descriptor, calling unwrap() on it will + /// cause a panic. + /// * Unknown errno value from sendto returned, will cause panic. + /// + /// for more detailed description of all the commands and return values, see + /// [send(2)](https://linux.die.net/man/2/send) pub fn sendto_syscall( &self, fd: i32, @@ -1251,19 +1353,28 @@ impl Cage { dest_addr: &interface::GenSockaddr, ) -> i32 { //if ip and port are not specified, shunt off to send + //to check for a possible connection to another socket that may exist if dest_addr.port() == 0 && dest_addr.addr().is_unspecified() { return self.send_syscall(fd, buf, buflen, flags); } - + //BUG: + //If fd is out of range of [0,MAXFD], process will panic + //Otherwise, we obtain a write gaurd to the Option object let checkedfd = self.get_filedescriptor(fd).unwrap(); let mut unlocked_fd = checkedfd.write(); + //Check if the write gaurd holds a valid FileDescriptor if let Some(filedesc_enum) = &mut *unlocked_fd { match filedesc_enum { + //In this case, the file descriptor refers to a socket Socket(ref mut sockfdobj) => { + //Grab a write guard to the socket handle let sock_tmp = sockfdobj.handle.clone(); let mut sockhandle = sock_tmp.write(); - // check if this is a domain socket + //If the socket's domain is UNIX, return with error as UNIX + //sockets are connection based. + //TODO: Check whether the socket is connected and return + //EISCONN or ENOTCONN accordingly. if sockhandle.domain == AF_UNIX { return syscall_error( Errno::EISCONN, @@ -1272,6 +1383,8 @@ impl Cage { ); } + //The destaddr's address family must match that of the + //socket's address from 'fd'. Otherwise, a message can't be sent if dest_addr.get_family() != sockhandle.domain as u16 { return syscall_error( Errno::EINVAL, @@ -1280,6 +1393,9 @@ impl Cage { ); } + //If sendto_syscall is used on a connection-mode socket, then + // the error EISCONN may be returned when destaddr is not NULL, + // as we checked above if sockhandle.state != ConnState::NOTCONNECTED { return syscall_error( Errno::EISCONN, @@ -1288,8 +1404,12 @@ impl Cage { ); } + //Pattern match based on the socket's protocol match sockhandle.protocol { - //Sendto doesn't make sense for the TCP protocol, it's connection oriented + //The TCP protocol is a connection-mode + //If sendto_syscall is used on a connection-mode socket, then + // the error EISCONN may be returned when destaddr is not NULL, + // as we checked above IPPROTO_TCP => { return syscall_error( Errno::EISCONN, @@ -1298,23 +1418,36 @@ impl Cage { ); } + //UDP protocol IPPROTO_UDP => { + //An implicit bind refers to the automatic binding of a socket to an + // address and port by the system, without + // an explicit call to the bind() function by + // the programmer. let tmpdest = *dest_addr; let ibindret = self._implicit_bind(&mut *sockhandle, tmpdest.get_family() as i32); + //Call to _implicit_bind may panic upon unknown error values + //Otherwise, the error value is returned here and passed through if ibindret < 0 { return ibindret; } - //unwrap ok because we implicit_bind_right before + //unwrap is safe because of the call to _implicit_bind + //above. innersocket/raw_sys_fd will be set since + //lind passes TCP sockets to the OS to partially handle. + //Here we call sendto from libc let sockret = sockhandle.innersocket.as_ref().unwrap().sendto( buf, buflen, Some(dest_addr), ); - //we don't mind if this fails for now and we will just get the error - //from calling sendto + //If the call to sendto from libc returns + //-1, indicating an error, retrieve the err + //and return appropriately + //Otherwise, return the number of bytes + //written to the connected socket if sockret < 0 { match Errno::from_discriminant(interface::get_errno()) { Ok(i) => { @@ -1329,10 +1462,12 @@ impl Cage { } }; } else { - return sockret; + return sockret; //on success, return the number + // of bytes sent } } - + //If the protocol of the socket is not TCP or UDP, + //lind does not support it _ => { return syscall_error( Errno::EOPNOTSUPP, @@ -1342,7 +1477,8 @@ impl Cage { } } } - + //If the file descriptor does not refer to a socket, + //return with error _ => { return syscall_error( Errno::ENOTSOCK, @@ -1351,6 +1487,7 @@ impl Cage { ); } } + //Otherwise, the write gaurd does not hold a FileDescriptor } else { return syscall_error(Errno::EBADF, "sendto", "invalid file descriptor"); } @@ -1365,7 +1502,7 @@ impl Cage { /// /// ### Arguments /// - /// it accepts two parameters: + /// it accepts four parameters: /// * `fd` - the file descriptor of the sending socket /// * `buf` - the message is found in buf /// * `buflen` - the len of the message found in buf @@ -1374,7 +1511,7 @@ impl Cage { /// /// ### Returns /// - /// On success, these calls return the number of bytes sent. On error, a + /// On success, the call returns the number of bytes sent. On error, a /// negative error number is returned, with the errorno set to represent /// the corresponding error /// @@ -1390,13 +1527,13 @@ impl Cage { /// path_resolution(7).) (For UDP sockets) An attempt was made to send to /// a network/broadcast address as though it was a unicast address. /// - /// * EAGAIN or EWOULDBLOCK - The socket is marked nonblocking and the + /// ** EAGAIN or EWOULDBLOCK - The socket is marked nonblocking and the /// requested operation would block. POSIX.1-2001 allows either error to /// be returned for this case, and does not require these constants to /// have the same value, so a portable application should check for both /// possibilities. /// - /// * EAGAIN - (Internet domain datagram sockets) The socket referred to by + /// ** EAGAIN - (Internet domain datagram sockets) The socket referred to by /// sockfd had not previously been bound to an address and, upon /// attempting to bind it to an ephemeral port, it was determined that all /// port numbers in the ephemeral port range are currently in use. See @@ -1404,7 +1541,7 @@ impl Cage { /// /// * EALREADY - Another Fast Open is in progress. /// - /// * EBADF - sockfd is not a valid open file descriptor. + /// ** EBADF - sockfd is not a valid open file descriptor. /// /// * ECONNRESET - Connection reset by peer. /// @@ -1416,7 +1553,7 @@ impl Cage { /// * EINTR - A signal occurred before any data was transmitted; see /// signal(7). /// - /// * EINVAL - Invalid argument passed. + /// ** EINVAL - Invalid argument passed. /// /// * EISCONN - The connection-mode socket was connected already but a /// recipient was specified. (Now either this error is returned, or the @@ -1433,14 +1570,14 @@ impl Cage { /// /// * ENOMEM - No memory available. /// - /// * ENOTCONN - The socket is not connected, and no target has been given. + /// ** ENOTCONN - The socket is not connected, and no target has been given. /// - /// * ENOTSOCK - The file descriptor sockfd does not refer to a socket. + /// ** ENOTSOCK - The file descriptor sockfd does not refer to a socket. /// - /// * EOPNOTSUPP - Some bit in the flags argument is inappropriate for the + /// ** EOPNOTSUPP - Some bit in the flags argument is inappropriate for the /// socket type. /// - /// * EPIPE - The local end has been shut down on a connection oriented + /// ** EPIPE - The local end has been shut down on a connection oriented /// socket. In this case, the process will also receive a SIGPIPE unless /// MSG_NOSIGNAL is set. /// @@ -1460,10 +1597,10 @@ impl Cage { //Otherwise, we obtain a write gaurd to the Option object let checkedfd = self.get_filedescriptor(fd).unwrap(); let mut unlocked_fd = checkedfd.write(); - //If the write gaurd holds a valid FileDescriptor + //Check if the write gaurd holds a valid FileDescriptor if let Some(filedesc_enum) = &mut *unlocked_fd { match filedesc_enum { - //The file descriptor refers to a socket + //In this case, the file descriptor refers to a socket Socket(ref mut sockfdobj) => { //Grab a write guard to the socket handle let sock_tmp = sockfdobj.handle.clone(); @@ -1478,8 +1615,11 @@ impl Cage { //Pattern match based on the socket protocol match sockhandle.protocol { //TCP socket - // ** Why isn't the protocol 0?? */ - // ** If this is fine, why don't we handle UDP sockets ?? // + //Across UNIX connections, it rarely exists + //that it is preferable to use UDP sockets + //rather than TCP sockets. + //As of right now, lind only implements + //UNIX sockets with the TCP protocol IPPROTO_TCP => { //For a TCP socket to be able to send here we //either need to be fully connected, or connected for write @@ -1522,11 +1662,12 @@ impl Cage { } }; //In the case that the write_to_pipe call returns EPIPE, - // meaning The local end has been shut down on a connection - // oriented socket. In this case, the process will also receive - // a SIGPIPE unless - // MSG_NOSIGNAL is set. - if retval == -(Errno::EPIPE as i32) { + // meaning the local end has been shut down on a connection + // oriented socket. Then, the process will also receive + // a SIGPIPE unless MSG_NOSIGNAL is set. + if (retval == -(Errno::EPIPE as i32)) + && ((flags & MSG_NOSIGNAL) == 0) + { // The default action for SIGPIPE is to terminate the // process without a core dump. This simplifies error // handling in programs that @@ -1534,14 +1675,14 @@ impl Cage { // input, transforming it, and then writing it to another // process. SIGPIPE allows the program to skip error // handling and blindly write data until it’s killed - - //TODO only send kill if MSG_NOSIGNAL not set + // + // Trigger SIGPIPE interface::lind_kill_from_id(self.cageid, SIGPIPE); - } // Trigger SIGPIPE - retval //return number of bytes sent + } + retval //on success, return number of bytes + // sent } - //If PROTOCOL is not TCP - // ** Why is this the case for unix ?? **// + //PROTOCOL is not TCP _ => { return syscall_error( Errno::EOPNOTSUPP, @@ -1579,7 +1720,7 @@ impl Cage { .as_ref() .unwrap() .sendto(buf, buflen, None); - //If the call to sendto from libc return + //If the call to sendto from libc returns //-1, indicating an error, retrieve the err //and return appropriately //Otherwise, return the number of bytes From 706589271af3c95cbb3200f5b679e7c28c242e9a Mon Sep 17 00:00:00 2001 From: davidge20 Date: Thu, 18 Jul 2024 18:57:06 +0000 Subject: [PATCH 06/13] Comments on recv helper functions --- src/safeposix/syscalls/net_calls.rs | 307 +++++++++++++++++++++++++--- 1 file changed, 282 insertions(+), 25 deletions(-) diff --git a/src/safeposix/syscalls/net_calls.rs b/src/safeposix/syscalls/net_calls.rs index 478e36d15..7c346d22a 100644 --- a/src/safeposix/syscalls/net_calls.rs +++ b/src/safeposix/syscalls/net_calls.rs @@ -1424,6 +1424,7 @@ impl Cage { // address and port by the system, without // an explicit call to the bind() function by // the programmer. + //This is necessary if the socket isn't assigned an address let tmpdest = *dest_addr; let ibindret = self._implicit_bind(&mut *sockhandle, tmpdest.get_family() as i32); @@ -1814,6 +1815,7 @@ impl Cage { } } + //Helper function of recv_common, for recv and recvfrom syscalls fn recv_common_inner( &self, filedesc_enum: &mut FileDescriptor, @@ -1823,9 +1825,13 @@ impl Cage { addr: &mut Option<&mut interface::GenSockaddr>, ) -> i32 { match &mut *filedesc_enum { + //Verify that the file descriptor refers to a socket Socket(ref mut sockfdobj) => { + //Grab a write guard to the socket handle let sock_tmp = sockfdobj.handle.clone(); let mut sockhandle = sock_tmp.write(); + //Pattern match based on the socket protocol + //and call the appropriate function to handle each case match sockhandle.protocol { IPPROTO_TCP => { return self.recv_common_inner_tcp( @@ -1847,6 +1853,8 @@ impl Cage { ) } + //In the case that the protocol is neither TCP nor UDP, + //return with error as lind does not support it _ => { return syscall_error( Errno::EOPNOTSUPP, @@ -1856,6 +1864,8 @@ impl Cage { } } } + //If the file descriptor does not refer to a socket, + //return with error _ => { return syscall_error( Errno::ENOTSOCK, @@ -1866,6 +1876,8 @@ impl Cage { } } + //Helper function of recv_common_inner, for recv and recvfrom syscalls + //Handles TCP sockets fn recv_common_inner_tcp( &self, sockhandle: &mut interface::RustLockWriteGuard, @@ -1875,8 +1887,13 @@ impl Cage { flags: i32, addr: &mut Option<&mut interface::GenSockaddr>, ) -> i32 { - // maybe select reported a INPROGRESS tcp socket as readable, so re-check the - // state here + //In the case that the socket is nonblocking and the connection can not + //be completed immediately, the connection state of the socket will + //be set to INPROGRESS. + //It is possible that select_syscall or poll_syscall had reported + //the INPROGRESS TCP socket as readable. If so, we can adjust the + //state of the socket to CONNECTED. + //** In what case would this happen?? */ if sockhandle.state == ConnState::INPROGRESS && sockhandle .innersocket @@ -1887,6 +1904,9 @@ impl Cage { sockhandle.state = ConnState::CONNECTED; } + //In the case that the socket is neither connected to another socket + //nor connected to another socket in a read-only mode, return with error + //as data can not be read otherwise. if (sockhandle.state != ConnState::CONNECTED) && (sockhandle.state != ConnState::CONNRDONLY) { return syscall_error( @@ -1901,15 +1921,25 @@ impl Cage { //if we have peeked some data before, fill our buffer with that data before // moving on + // ** Why is this a step ?? ** // if !sockhandle.last_peek.is_empty() { + //Grab the minimum of the two values let bytecount = interface::rust_min(sockhandle.last_peek.len(), newbuflen); + //Copy the bytes from the previous peek into buf interface::copy_fromrustdeque_sized(buf, bytecount, &sockhandle.last_peek); + //newbufptr now points to the first byte available in the buffer + //newbuflen reflects the number of bytes that are available in the buffer newbuflen -= bytecount; newbufptr = newbufptr.wrapping_add(bytecount); //if we're not still peeking data, consume the data we peeked from our peek // buffer and if the bytecount is more than the length of the peeked // data, then we remove the entire buffer + // ** What is the point of the if else statement being passed in as the + // parameter ?? bytecount = min(sockhandle.last_peek.len(), + // newbuflen) so how can bytecount be greater than + // sockhandle.last_peek.len() ?? Seems like it always returns + // bytecount regardless ** // if flags & MSG_PEEK == 0 { let len = sockhandle.last_peek.len(); sockhandle @@ -1917,34 +1947,55 @@ impl Cage { .drain(..(if bytecount > len { len } else { bytecount })); } + //if we've filled all of the buffer with peeked data, return with success if newbuflen == 0 { - //if we've filled all of the buffer with peeked data, return - return bytecount as i32; + return bytecount as i32; //return number of bytes read into + // buff } } + //Initialize variables to indicate a pointer to the first available + //byte in the buff and remaining buffer length, respectively let bufleft = newbufptr; let buflenleft = newbuflen; let mut retval; + //The domain of the socket is UNIX + //lind handles UNIX communication using pipes if sockhandle.domain == AF_UNIX { // get the remote socket pipe, read from it, and return bytes read + // + //Check if the socket is non-blocking + //If no messages are available at the socket, the receive calls + //wait for a message to arrive, unless the socket is nonblocking + //(see fcntl(2)), in which case the value -1 is returned and errno + //is set to EAGAIN or EWOULDBLOCK. let mut nonblocking = false; if sockfdobj.flags & O_NONBLOCK != 0 { nonblocking = true; } + //we loop here so we can cancel blocking recvs, if necessary loop { + //Grab the receive pipe from the socket to read the data + //into the remaining space in the buffer ** let sockinfo = &sockhandle.unix_info.as_ref().unwrap(); let receivepipe = sockinfo.receivepipe.as_ref().unwrap(); retval = receivepipe.read_from_pipe(bufleft, buflenleft, nonblocking) as i32; + //In the case of an error from reading from the receive pipe if retval < 0 { + //** This step seems weird + // Even if the call fails we return with the previous peeked data? */ //If we have already read from a peek but have failed to read more, exit! if buflen != buflenleft { - return (buflen - buflenleft) as i32; + return (buflen - buflenleft) as i32; //return number of + // bytes read from + // peek } + //In the case that the socket is blocking and errno = EAGAIN, + //a receive timeout has expired before data was received. + //Check for cancellation of recv call before looping back to + //read again if sockfdobj.flags & O_NONBLOCK == 0 && retval == -(Errno::EAGAIN as i32) { - // with blocking sockets, we return EAGAIN here to check for cancellation, - // then return to reading if self .cancelstatus .load(interface::RustAtomicOrdering::Relaxed) @@ -1956,20 +2007,31 @@ impl Cage { interface::cancelpoint(self.cageid) } } - // in order to prevent deadlock + //in order to prevent deadlock, + //temporarily yield the lock on the socket handle + //to a waiting thread, if one exists interface::RustLockWriteGuard::::bump(sockhandle); - continue; + continue; //read again from receive pipe, as errno = + // EAGAIN on a blocking socket } else { - //if not EAGAIN, return the error + //In the case that the error is not EAGAIN, return the error return retval; } } - break; + break; //upon a successful read from the receive pipe, break + // from the loop } + //The domain of the socket is INET or INET6 + //We will call recvfrom from libc to handle the reading of data } else { + //we loop here so we can cancel blocking recvs, if necessary loop { - // we loop here so we can cancel blocking recvs - //socket must be connected so unwrap ok + //socket must be connected so the innersocket/raw_sys_fd is filled + //the unwrap won't cause a panic + // + //Depending on whether the socket is blocking or non-blocking, + //call the relevant corresponding function + //to read into the remaining space in the buffer ** ?? if sockfdobj.flags & O_NONBLOCK != 0 { retval = sockhandle .innersocket @@ -1984,10 +2046,13 @@ impl Cage { .recvfrom(bufleft, buflenleft, addr); } + //In the case that the libc call returns with an error if retval < 0 { //If we have already read from a peek but have failed to read more, exit! if buflen != buflenleft { - return (buflen - buflenleft) as i32; + return (buflen - buflenleft) as i32; //return number of + // bytes read from + // peek } match Errno::from_discriminant(interface::get_errno()) { @@ -2009,8 +2074,12 @@ impl Cage { interface::cancelpoint(self.cageid); } } + //in order to prevent deadlock, + //temporarily yield the lock on the socket handle + //to a waiting thread, if one exists interface::RustLockWriteGuard::::bump(sockhandle); - continue; // EAGAIN, try again + continue; //read again from receive pipe, as + // errno = EAGAIN on a blocking socket } return syscall_error( @@ -2019,22 +2088,34 @@ impl Cage { "Internal call to recvfrom failed", ); } + //In the case that recvfrom from libc returns an unknown errno + //value, panic Err(()) => panic!("Unknown errno value from socket recvfrom returned!"), }; } - break; // we're okay to move on + break; //upon a successful read from the receive pipe, break + // from the loop } } + //sum the total number of bytes from the last peak plus the additional + //bytes from the current read. This equates to the number of bytes + //return to our buff let totalbyteswritten = (buflen - buflenleft) as i32 + retval; + //If the MSG_PEEK flag is on, write the new bytes read from the receive pipe + //into the last_peek field of the socket handle to keep track of + //the last peek if flags & MSG_PEEK != 0 { //extend from the point after we read our previously peeked bytes interface::extend_fromptr_sized(newbufptr, retval as usize, &mut sockhandle.last_peek); } - return totalbyteswritten; + return totalbyteswritten; //upon success, return the number of bytes + // written into buff } + //Helper function of recv_common_inner, for recv and recvfrom syscalls + //Handles UDP sockets fn recv_common_inner_udp( &self, sockhandle: &mut interface::RustLockWriteGuard, @@ -2043,21 +2124,33 @@ impl Cage { buflen: usize, addr: &mut Option<&mut interface::GenSockaddr>, ) -> i32 { + //If the source address of the message is not NULL, grab the domain of + //the address. Otherwise, use AF_INET as it is unlikely a UNIX socket + //would send a message over a UDP connection ?? let binddomain = if let Some(baddr) = addr { baddr.get_family() as i32 } else { AF_INET }; + //An implicit bind refers to the automatic binding of a socket to an + // address and port by the system, without + // an explicit call to the bind() function by + // the programmer. + //This is necessary if the socket isn't assigned an address + //Call to _implicit_bind may panic upon unknown error values + //Otherwise, the error value is returned here and passed through let ibindret = self._implicit_bind(&mut *sockhandle, binddomain); if ibindret < 0 { return ibindret; } + //we loop here so we can cancel blocking recvs, if necessary loop { - // loop for blocking sockets - //if the remoteaddr is set and addr is not, use remoteaddr - //unwrap is ok because of implicit bind + //if the remoteaddr is set and addr is not, use remoteaddr buff + //to grab the address from which the message is sent from + //otherwise, use addr to grab the address from which the message is sent from + // ?? unwrap will not cause panic because of implicit bind let retval = if let (None, Some(ref mut remoteaddr)) = (&addr, sockhandle.remoteaddr) { sockhandle.innersocket.as_ref().unwrap().recvfrom( buf, @@ -2072,8 +2165,14 @@ impl Cage { .recvfrom(buf, buflen, addr) }; + //In the case that the libc call to recvfrom returns with an error if retval < 0 { match Errno::from_discriminant(interface::get_errno()) { + //We have the recieve timeout set to every one second, so + //if our blocking socket ever returns EAGAIN, it must be + //the case that this recv timeout was exceeded, and we + //should thus not treat this as a failure in our emulated + //socket; see comment in Socket::new in interface/comm.rs Ok(i) => { if sockfdobj.flags & O_NONBLOCK == 0 && i == Errno::EAGAIN { if self @@ -2087,6 +2186,9 @@ impl Cage { interface::cancelpoint(self.cageid); } } + //in order to prevent deadlock, + //temporarily yield the lock on the socket handle + //to a waiting thread, if one exists interface::RustLockWriteGuard::::bump(sockhandle); continue; //received EAGAIN on blocking socket, try // again @@ -2096,11 +2198,13 @@ impl Cage { Err(()) => panic!("Unknown errno value from socket recvfrom returned!"), }; } else { - return retval; // we can proceed + return retval; //upon success, return the number of bytes + // written into buff } } } + //Helper function of recv_syscall and recvfrom_syscall pub fn recv_common( &self, fd: i32, @@ -2109,8 +2213,14 @@ impl Cage { flags: i32, addr: &mut Option<&mut interface::GenSockaddr>, ) -> i32 { + //BUG: + //If fd is out of range of [0,MAXFD], process will panic + //Otherwise, we obtain a write gaurd to the Option object let checkedfd = self.get_filedescriptor(fd).unwrap(); let mut unlocked_fd = checkedfd.write(); + //Check if the write gaurd holds a valid FileDescriptor, and if so + //call recv_common_inner. + //Otherwise, return with an error if let Some(ref mut filedesc_enum) = &mut *unlocked_fd { return self.recv_common_inner(filedesc_enum, buf, buflen, flags, addr); } else { @@ -2118,6 +2228,82 @@ impl Cage { } } + /// ### Description + /// + /// `recvfrom_syscall` receives a message from a socket + /// + /// The recvfrom() call receives messages from a socket, and may be used + /// to receive data on a socket whether or not it is connection-oriented. + /// recvfrom(fd, buf, buflen, flags, NULL); + /// It is equivalent to the call: + /// recv(fd, buf, buflen, flags); + /// + /// ### Arguments + /// + /// it accepts five parameters: + /// * `fd` - the file descriptor of the socket receiving a message + /// * `buf` - the message is found in buf + /// * `buflen` - the len of the message found in buf + /// * `flags` - bitwise OR of zero or more flags. Refer to man page to find + /// possible args + /// * 'addr' - the source address of the message received + /// + /// ### Returns + /// + /// * On success, the call returns the number of bytes received. On error, a + /// negative error number is returned, with the errorno set to represent + /// the corresponding error + /// * When a stream socket peer has performed an orderly shutdown, the + /// return value will be 0 (the traditional "end-of-file" return). + /// * Datagram sockets in various domains (e.g., the UNIX and Internet + /// domains) permit zero-length datagrams. When such a datagram is + /// received, the return value is 0. + /// * The value 0 may also be returned if the requested number of bytes + /// to receive from a stream socket was 0. + /// + /// ### Errors + /// + /// These are some standard errors generated by the socket layer. + /// Additional errors may be generated and returned from the + /// underlying protocol modules; see their respective manual pages. + /// + /// ** EAGAIN or EWOULDBLOCK - The socket is marked nonblocking and the + /// receive operation would block, or a receive timeout had been set and + /// the timeout expired before data was received. POSIX.1 allows + /// either error to be returned for this case, and does not + /// require these constants to have the same value, so a + /// portable application should check for both possibilities. + /// + /// * EBADF - The argument sockfd is an invalid file descriptor. + /// + /// * ECONNREFUSED - A remote host refused to allow the network connection + /// (typically because it is not running the requested service). + /// + /// * EFAULT - The receive buffer pointer(s) point outside the process's + /// address space. + /// + /// * EINTR - The receive was interrupted by delivery of a signal before any + /// data was available; see signal(7). + /// + /// * EINVAL - Invalid argument passed. + /// + /// * ENOMEM - Could not allocate memory for recvmsg(). + /// + /// * ENOTCONN - The socket is associated with a connection-oriented + /// protocol and has not been connected (see connect(2) and accept(2)). + /// + /// * ENOTSOCK - The file descriptor sockfd does not refer to a socket. + /// + /// ** Indicates the error may be returned from RustPOSIX + /// + /// ### Panics TODO: + /// + /// * invalid or out-of-bounds file descriptor, calling unwrap() on it will + /// cause a panic. + /// * Unknown errno value from recvfrom returned, will cause panic. + /// + /// for more detailed description of all the commands and return values, see + /// [recvfrom(2)](https://linux.die.net/man/2/recvfrom) pub fn recvfrom_syscall( &self, fd: i32, @@ -2129,6 +2315,79 @@ impl Cage { return self.recv_common(fd, buf, buflen, flags, addr); } + /// ### Description + /// + /// `recv_syscall` receives a message from a socket + /// + /// The recv() call is normally used only on a connected socket. + /// It is equivalent to the call: + /// recvfrom(fd, buf, buflen, flags, NULL); + /// + /// ### Arguments + /// + /// it accepts four parameters: + /// * `fd` - the file descriptor of the socket receiving a message + /// * `buf` - the message is found in buf + /// * `buflen` - the len of the message found in buf + /// * `flags` - bitwise OR of zero or more flags. Refer to man page to find + /// possible args + /// + /// ### Returns + /// + /// * On success, the call returns the number of bytes received. On error, a + /// negative error number is returned, with the errorno set to represent + /// the corresponding error + /// * When a stream socket peer has performed an orderly shutdown, the + /// return value will be 0 (the traditional "end-of-file" return). + /// * Datagram sockets in various domains (e.g., the UNIX and Internet + /// domains) permit zero-length datagrams. When such a datagram is + /// received, the return value is 0. + /// * The value 0 may also be returned if the requested number of bytes + /// to receive from a stream socket was 0. + /// + /// ### Errors + /// + /// These are some standard errors generated by the socket layer. + /// Additional errors may be generated and returned from the + /// underlying protocol modules; see their respective manual pages. + /// + /// ** EAGAIN or EWOULDBLOCK - The socket is marked nonblocking and the + /// receive operation would block, or a receive timeout had been set and + /// the timeout expired before data was received. POSIX.1 allows + /// either error to be returned for this case, and does not + /// require these constants to have the same value, so a + /// portable application should check for both possibilities. + /// + /// * EBADF - The argument sockfd is an invalid file descriptor. + /// + /// * ECONNREFUSED - A remote host refused to allow the network connection + /// (typically because it is not running the requested service). + /// + /// * EFAULT - The receive buffer pointer(s) point outside the process's + /// address space. + /// + /// * EINTR - The receive was interrupted by delivery of a signal before any + /// data was available; see signal(7). + /// + /// * EINVAL - Invalid argument passed. + /// + /// * ENOMEM - Could not allocate memory for recvmsg(). + /// + /// * ENOTCONN - The socket is associated with a connection-oriented + /// protocol and has not been connected (see connect(2) and accept(2)). + /// + /// * ENOTSOCK - The file descriptor sockfd does not refer to a socket. + /// + /// ** Indicates the error may be returned from RustPOSIX + /// + /// ### Panics TODO: + /// + /// * invalid or out-of-bounds file descriptor, calling unwrap() on it will + /// cause a panic. + /// * Unknown errno value from recvfrom returned, will cause panic. + /// + /// for more detailed description of all the commands and return values, see + /// [recv(2)](https://linux.die.net/man/2/recv) pub fn recv_syscall(&self, fd: i32, buf: *mut u8, buflen: usize, flags: i32) -> i32 { return self.recv_common(fd, buf, buflen, flags, &mut None); } @@ -2173,7 +2432,7 @@ impl Cage { /// /// ### Panics /// - /// * invalid or out-of-bounds file descriptor), calling unwrap() on it will + /// * invalid or out-of-bounds file descriptor, calling unwrap() on it will /// cause a panic. /// * unknown errno value from socket bind sys call from libc in the case /// that the socket isn't assigned an address @@ -2181,10 +2440,8 @@ impl Cage { /// /// for more detailed description of all the commands and return values, see /// [listen(2)](https://linux.die.net/man/2/listen) - // - // TODO: We are currently ignoring backlog pub fn listen_syscall(&self, fd: i32, backlog: i32) -> i32 { - //BUG:s + //BUG: //If fd is out of range of [0,MAXFD], process will panic //Otherwise, we obtain a write gaurd to the Option object let checkedfd = self.get_filedescriptor(fd).unwrap(); From f9084a49f3ca2a9a58feefb307944a6578741658 Mon Sep 17 00:00:00 2001 From: davidge20 Date: Thu, 18 Jul 2024 21:15:49 +0000 Subject: [PATCH 07/13] Unix send/recv test --- src/tests/networking_tests.rs | 209 ++++++++++++++++++++++++++++++++++ 1 file changed, 209 insertions(+) diff --git a/src/tests/networking_tests.rs b/src/tests/networking_tests.rs index 64a942885..54454a1a0 100644 --- a/src/tests/networking_tests.rs +++ b/src/tests/networking_tests.rs @@ -1446,6 +1446,7 @@ pub mod net_tests { } #[test] + //INET Sockets pub fn ut_lind_net_recvfrom() { //acquiring a lock on TESTMUTEX prevents other tests from running concurrently, // and also performs clean env setup @@ -1659,6 +1660,214 @@ pub mod net_tests { lindrustfinalize(); } + #[test] + //UNIX Sockets + pub fn ut_lind_net_recvfrom_unix() { + //acquiring a lock on TESTMUTEX prevents other tests from running concurrently, + // and also performs clean env setup + let _thelock = setup::lock_and_init(); + + let cage = interface::cagetable_getref(1); + + let serversockfd = cage.socket_syscall(AF_UNIX, SOCK_STREAM, 0); + let clientsockfd = cage.socket_syscall(AF_UNIX, SOCK_STREAM, 0); + + //making sure that the assigned fd's are valid + assert!(serversockfd > 0); + assert!(clientsockfd > 0); + + //binding to a socket + let serversockaddr_unix = + interface::new_sockaddr_unix(AF_UNIX as u16, "server_select".as_bytes()); + let serversocket_unix = interface::GenSockaddr::Unix(serversockaddr_unix); + + let clientsockaddr_unix = + interface::new_sockaddr_unix(AF_UNIX as u16, "client_select".as_bytes()); + let mut clientsocket_unix = interface::GenSockaddr::Unix(clientsockaddr_unix); + + assert_eq!(cage.bind_syscall(serversockfd, &serversocket_unix), 0); + assert_eq!(cage.bind_syscall(clientsockfd, &clientsocket_unix), 0); + assert_eq!(cage.listen_syscall(serversockfd, 1), 0); //we are only allowing for one client at a time + + //forking the cage to get another cage with the same information + assert_eq!(cage.fork_syscall(2), 0); + + //creating a thread for the server so that the information can be sent between + // the two threads + let thread = interface::helper_thread(move || { + let cage2 = interface::cagetable_getref(2); + + //accept connection from client + let mut socket2 = clientsocket_unix; + let sockfd = cage2.accept_syscall(serversockfd, &mut clientsocket_unix); + + assert!(sockfd > 0); + + //process the first test... + //Writing 100, then peek 100, then read 100 + let mut buf = sizecbuf(100); + assert_eq!( + cage2.recvfrom_syscall( + sockfd, + buf.as_mut_ptr(), + 100, + MSG_PEEK, + &mut Some(&mut socket2) + ), + 100 + ); //peeking at the input message + buf = sizecbuf(100); + assert_eq!( + cage2.recvfrom_syscall(sockfd, buf.as_mut_ptr(), 100, 0, &mut Some(&mut socket2)), + 100 + ); //reading the input message + buf = sizecbuf(100); + + interface::sleep(interface::RustDuration::from_millis(200)); + + //process the second test... + //Writing 100, read 20, peek 20, read 80 + assert_eq!( + cage2.recvfrom_syscall(sockfd, buf.as_mut_ptr(), 20, 0, &mut Some(&mut socket2)), + 20 + ); + buf = sizecbuf(100); + assert_eq!( + cage2.recvfrom_syscall( + sockfd, + buf.as_mut_ptr(), + 20, + MSG_PEEK, + &mut Some(&mut socket2) + ), + 20 + ); + buf = sizecbuf(100); + assert_eq!( + cage2.recvfrom_syscall(sockfd, buf.as_mut_ptr(), 80, 0, &mut Some(&mut socket2)), + 80 + ); + buf = sizecbuf(100); + + interface::sleep(interface::RustDuration::from_millis(200)); + + //process the third test... + //Writing 100, peek several times, read 100 + for _ in 0..4 { + assert_eq!( + cage2.recvfrom_syscall( + sockfd, + buf.as_mut_ptr(), + 10, + MSG_PEEK, + &mut Some(&mut socket2) + ), + 10 + ); + buf = sizecbuf(100); + } + for _ in 0..4 { + assert_eq!( + cage2.recvfrom_syscall( + sockfd, + buf.as_mut_ptr(), + 20, + MSG_PEEK, + &mut Some(&mut socket2) + ), + 20 + ); + buf = sizecbuf(100); + } + for _ in 0..4 { + assert_eq!( + cage2.recvfrom_syscall( + sockfd, + buf.as_mut_ptr(), + 30, + MSG_PEEK, + &mut Some(&mut socket2) + ), + 30 + ); + buf = sizecbuf(100); + } + for _ in 0..4 { + assert_eq!( + cage2.recvfrom_syscall( + sockfd, + buf.as_mut_ptr(), + 40, + MSG_PEEK, + &mut Some(&mut socket2) + ), + 40 + ); + buf = sizecbuf(100); + } + assert_eq!( + cage2.recvfrom_syscall(sockfd, buf.as_mut_ptr(), 100, 0, &mut Some(&mut socket2)), + 100 + ); + buf = sizecbuf(100); + + interface::sleep(interface::RustDuration::from_millis(200)); + + //process the fourth test... + //Writing 50, peek 50 + assert_eq!( + cage2.recvfrom_syscall( + sockfd, + buf.as_mut_ptr(), + 50, + MSG_PEEK, + &mut Some(&mut socket2) + ), + 50 + ); + + interface::sleep(interface::RustDuration::from_millis(100)); + + assert_eq!(cage2.close_syscall(sockfd), 0); + assert_eq!(cage2.close_syscall(serversockfd), 0); + assert_eq!(cage2.exit_syscall(EXIT_SUCCESS), EXIT_SUCCESS); + }); + + //connect to the server + assert_eq!(cage.connect_syscall(clientsockfd, &serversocket_unix), 0); + + //send the data with delays so that the server can process the information + // cleanly + assert_eq!( + cage.send_syscall(clientsockfd, str2cbuf(&"A".repeat(100)), 100, 0), + 100 + ); + interface::sleep(interface::RustDuration::from_millis(100)); + + assert_eq!( + cage.send_syscall(clientsockfd, str2cbuf(&"A".repeat(100)), 100, 0), + 100 + ); + interface::sleep(interface::RustDuration::from_millis(100)); + + assert_eq!( + cage.send_syscall(clientsockfd, str2cbuf(&"A".repeat(100)), 100, 0), + 100 + ); + interface::sleep(interface::RustDuration::from_millis(100)); + + assert_eq!( + cage.send_syscall(clientsockfd, str2cbuf(&"A".repeat(50)), 50, 0), + 50 + ); + interface::sleep(interface::RustDuration::from_millis(100)); + + thread.join().unwrap(); + + assert_eq!(cage.exit_syscall(EXIT_SUCCESS), EXIT_SUCCESS); + lindrustfinalize(); + } + #[test] //The connection between the client and the server ends early as the //server socket fd is closed. The expected behavior is that errno is set From bd52d54dc03118339ffe5f440e6a93b062d5a265 Mon Sep 17 00:00:00 2001 From: davidge20 Date: Fri, 19 Jul 2024 18:57:29 +0000 Subject: [PATCH 08/13] updates from qianxi and vlad --- src/safeposix/syscalls/net_calls.rs | 30 +++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/src/safeposix/syscalls/net_calls.rs b/src/safeposix/syscalls/net_calls.rs index 7c346d22a..bbf1f65d9 100644 --- a/src/safeposix/syscalls/net_calls.rs +++ b/src/safeposix/syscalls/net_calls.rs @@ -1372,7 +1372,8 @@ impl Cage { let mut sockhandle = sock_tmp.write(); //If the socket's domain is UNIX, return with error as UNIX - //sockets are connection based. + //sockets are connection based. Currently, lind + //does not implement UDP sends/recvs over UNIX sockets //TODO: Check whether the socket is connected and return //EISCONN or ENOTCONN accordingly. if sockhandle.domain == AF_UNIX { @@ -1396,13 +1397,14 @@ impl Cage { //If sendto_syscall is used on a connection-mode socket, then // the error EISCONN may be returned when destaddr is not NULL, // as we checked above - if sockhandle.state != ConnState::NOTCONNECTED { - return syscall_error( - Errno::EISCONN, - "sendto", - "The descriptor is connected", - ); - } + // Can we delete the check below ?? + // if sockhandle.state != ConnState::NOTCONNECTED { + // return syscall_error( + // Errno::EISCONN, + // "sendto", + // "The descriptor is connected", + // ); + // } //Pattern match based on the socket's protocol match sockhandle.protocol { @@ -1659,7 +1661,7 @@ impl Cage { //sendpipe is not available in unix socket info //transmission of data is not possible so return with error None => { - return syscall_error(Errno::EAGAIN, "writev", "there is no data available right now, try again later"); + panic!("sendpipe is not available in unix socket info in send syscall"); } }; //In the case that the write_to_pipe call returns EPIPE, @@ -1677,6 +1679,7 @@ impl Cage { // process. SIGPIPE allows the program to skip error // handling and blindly write data until it’s killed // + // BUG: Issue #306 -> https://github.com/Lind-Project/safeposix-rust/issues/306 // Trigger SIGPIPE interface::lind_kill_from_id(self.cageid, SIGPIPE); } @@ -1762,7 +1765,9 @@ impl Cage { ); } }; - //** Why is it necessary to drop here?? */ + //in sendto_syscall, we need to acquire the + //fd/sockhandle with write/read lock again. + //If we do not release the lock here, deadlock will happen drop(unlocked_fd); drop(sockhandle); //remote address is set in sendto from libc @@ -1793,7 +1798,7 @@ impl Cage { _ => { return syscall_error( Errno::EINVAL, - "connect", + "send", "Unsupported domain provided", ) } @@ -1893,7 +1898,6 @@ impl Cage { //It is possible that select_syscall or poll_syscall had reported //the INPROGRESS TCP socket as readable. If so, we can adjust the //state of the socket to CONNECTED. - //** In what case would this happen?? */ if sockhandle.state == ConnState::INPROGRESS && sockhandle .innersocket @@ -1983,8 +1987,6 @@ impl Cage { retval = receivepipe.read_from_pipe(bufleft, buflenleft, nonblocking) as i32; //In the case of an error from reading from the receive pipe if retval < 0 { - //** This step seems weird - // Even if the call fails we return with the previous peeked data? */ //If we have already read from a peek but have failed to read more, exit! if buflen != buflenleft { return (buflen - buflenleft) as i32; //return number of From 83fff98e9565e42b6af4d96c6755400b4b5f715c Mon Sep 17 00:00:00 2001 From: davidge20 Date: Fri, 19 Jul 2024 20:24:54 +0000 Subject: [PATCH 09/13] Small comment --- src/safeposix/syscalls/net_calls.rs | 28 ++++++++++++---------------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/src/safeposix/syscalls/net_calls.rs b/src/safeposix/syscalls/net_calls.rs index bbf1f65d9..d7822c258 100644 --- a/src/safeposix/syscalls/net_calls.rs +++ b/src/safeposix/syscalls/net_calls.rs @@ -1397,14 +1397,14 @@ impl Cage { //If sendto_syscall is used on a connection-mode socket, then // the error EISCONN may be returned when destaddr is not NULL, // as we checked above - // Can we delete the check below ?? - // if sockhandle.state != ConnState::NOTCONNECTED { - // return syscall_error( - // Errno::EISCONN, - // "sendto", - // "The descriptor is connected", - // ); - // } + // UDP sockets may be connected + if sockhandle.state != ConnState::NOTCONNECTED { + return syscall_error( + Errno::EISCONN, + "sendto", + "The descriptor is connected", + ); + } //Pattern match based on the socket's protocol match sockhandle.protocol { @@ -1939,11 +1939,6 @@ impl Cage { //if we're not still peeking data, consume the data we peeked from our peek // buffer and if the bytecount is more than the length of the peeked // data, then we remove the entire buffer - // ** What is the point of the if else statement being passed in as the - // parameter ?? bytecount = min(sockhandle.last_peek.len(), - // newbuflen) so how can bytecount be greater than - // sockhandle.last_peek.len() ?? Seems like it always returns - // bytecount regardless ** // if flags & MSG_PEEK == 0 { let len = sockhandle.last_peek.len(); sockhandle @@ -2126,9 +2121,10 @@ impl Cage { buflen: usize, addr: &mut Option<&mut interface::GenSockaddr>, ) -> i32 { - //If the source address of the message is not NULL, grab the domain of - //the address. Otherwise, use AF_INET as it is unlikely a UNIX socket - //would send a message over a UDP connection ?? + //Unlikely the following sequence occurs. + //Only happens if the sockhandle isn't binded to an address. + // + //If the sending address's domain isn't specified, assume INET let binddomain = if let Some(baddr) = addr { baddr.get_family() as i32 } else { From 8fa95d3d77b798863339c8057f292c1e734e5576 Mon Sep 17 00:00:00 2001 From: davidge20 Date: Tue, 23 Jul 2024 20:19:08 +0000 Subject: [PATCH 10/13] minor touches --- src/safeposix/syscalls/net_calls.rs | 30 +++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/src/safeposix/syscalls/net_calls.rs b/src/safeposix/syscalls/net_calls.rs index d7822c258..fd94b0021 100644 --- a/src/safeposix/syscalls/net_calls.rs +++ b/src/safeposix/syscalls/net_calls.rs @@ -1336,7 +1336,7 @@ impl Cage { /// /// ** Indicates the error may be returned from RustPOSIX /// - /// ### Panics TODO: + /// ### Panics: /// /// * invalid or out-of-bounds file descriptor, calling unwrap() on it will /// cause a panic. @@ -1586,7 +1586,7 @@ impl Cage { /// /// ** Indicates the error may be returned from RustPOSIX /// - /// ### Panics TODO: + /// ### Panics: /// /// * invalid or out-of-bounds file descriptor, calling unwrap() on it will /// cause a panic. @@ -1765,21 +1765,22 @@ impl Cage { ); } }; - //in sendto_syscall, we need to acquire the - //fd/sockhandle with write/read lock again. + //in sendto_syscall, we need to acquire the + //fd/sockhandle with write/read lock again. //If we do not release the lock here, deadlock will happen drop(unlocked_fd); drop(sockhandle); //remote address is set in sendto from libc //as UDP socket is connection-less + //error checking is handled in sento_syscall return self.sendto_syscall( fd, buf, buflen, flags, &remoteaddr, - ); //return the number of bytes written to the connected socket - //** TODO: Add error checking on the return value */ + ); //return the number of bytes written to + // the connected socket } //Protcol besides UDP and TCP are not supported @@ -1923,9 +1924,10 @@ impl Cage { let mut newbuflen = buflen; let mut newbufptr = buf; - //if we have peeked some data before, fill our buffer with that data before - // moving on - // ** Why is this a step ?? ** // + //if we have peeked some data before, fill our buffer with that data + //before moving on. This step is neccessary as we read the data from + //the pipe into the last peek field of the socket handle during our + //last peek if !sockhandle.last_peek.is_empty() { //Grab the minimum of the two values let bytecount = interface::rust_min(sockhandle.last_peek.len(), newbuflen); @@ -1976,7 +1978,7 @@ impl Cage { //we loop here so we can cancel blocking recvs, if necessary loop { //Grab the receive pipe from the socket to read the data - //into the remaining space in the buffer ** + //into the remaining space in the buffer let sockinfo = &sockhandle.unix_info.as_ref().unwrap(); let receivepipe = sockinfo.receivepipe.as_ref().unwrap(); retval = receivepipe.read_from_pipe(bufleft, buflenleft, nonblocking) as i32; @@ -2028,7 +2030,7 @@ impl Cage { // //Depending on whether the socket is blocking or non-blocking, //call the relevant corresponding function - //to read into the remaining space in the buffer ** ?? + //to read into the remaining space in the buffer if sockfdobj.flags & O_NONBLOCK != 0 { retval = sockhandle .innersocket @@ -2148,7 +2150,7 @@ impl Cage { //if the remoteaddr is set and addr is not, use remoteaddr buff //to grab the address from which the message is sent from //otherwise, use addr to grab the address from which the message is sent from - // ?? unwrap will not cause panic because of implicit bind + //note: unwrap will not cause panic because of implicit bind let retval = if let (None, Some(ref mut remoteaddr)) = (&addr, sockhandle.remoteaddr) { sockhandle.innersocket.as_ref().unwrap().recvfrom( buf, @@ -2294,7 +2296,7 @@ impl Cage { /// /// ** Indicates the error may be returned from RustPOSIX /// - /// ### Panics TODO: + /// ### Panics: /// /// * invalid or out-of-bounds file descriptor, calling unwrap() on it will /// cause a panic. @@ -2378,7 +2380,7 @@ impl Cage { /// /// ** Indicates the error may be returned from RustPOSIX /// - /// ### Panics TODO: + /// ### Panics: /// /// * invalid or out-of-bounds file descriptor, calling unwrap() on it will /// cause a panic. From a15d148c64348340342d1d57dd0f81c8805e3aa3 Mon Sep 17 00:00:00 2001 From: davidge20 Date: Thu, 1 Aug 2024 01:05:06 +0000 Subject: [PATCH 11/13] Small changes in style --- src/safeposix/syscalls/net_calls.rs | 67 +++++++++++------------------ 1 file changed, 25 insertions(+), 42 deletions(-) diff --git a/src/safeposix/syscalls/net_calls.rs b/src/safeposix/syscalls/net_calls.rs index fd94b0021..b0e06c25b 100644 --- a/src/safeposix/syscalls/net_calls.rs +++ b/src/safeposix/syscalls/net_calls.rs @@ -638,7 +638,7 @@ impl Cage { Socket(ref mut sockfdobj) => { //Clone the socket handle let sock_tmp = sockfdobj.handle.clone(); - //Obtain write gaurd for socket handle + //Obtain write guard for socket handle let mut sockhandle = sock_tmp.write(); //We would like to pass the socket handle data to the function //without giving it ownership sockfdobj, which may be in use @@ -874,7 +874,7 @@ impl Cage { /// [connect(3)](https://linux.die.net/man/3/connect) pub fn connect_syscall(&self, fd: i32, remoteaddr: &interface::GenSockaddr) -> i32 { //If fd is out of range of [0,MAXFD], process will panic - //Otherwise, we obtain a write gaurd to the Option object + //Otherwise, we obtain a write guard to the Option object let checkedfd = self.get_filedescriptor(fd).unwrap(); let mut unlocked_fd = checkedfd.write(); //Pattern match such that FileDescriptor object must be the Socket variant @@ -1280,11 +1280,8 @@ impl Cage { /// path_resolution(7).) (For UDP sockets) An attempt was made to send to /// a network/broadcast address as though it was a unicast address. /// - /// ** EAGAIN or EWOULDBLOCK - The socket is marked nonblocking and the - /// requested operation would block. POSIX.1-2001 allows either error to - /// be returned for this case, and does not require these constants to - /// have the same value, so a portable application should check for both - /// possibilities. + /// ** EAGAIN - The socket is marked nonblocking and the + /// requested operation would block. /// /// ** EAGAIN - (Internet domain datagram sockets) The socket referred to by /// sockfd had not previously been bound to an address and, upon @@ -1359,10 +1356,10 @@ impl Cage { } //BUG: //If fd is out of range of [0,MAXFD], process will panic - //Otherwise, we obtain a write gaurd to the Option object + //Otherwise, we obtain a write guard to the Option object let checkedfd = self.get_filedescriptor(fd).unwrap(); let mut unlocked_fd = checkedfd.write(); - //Check if the write gaurd holds a valid FileDescriptor + //Check if the write guard holds a valid FileDescriptor if let Some(filedesc_enum) = &mut *unlocked_fd { match filedesc_enum { //In this case, the file descriptor refers to a socket @@ -1490,7 +1487,7 @@ impl Cage { ); } } - //Otherwise, the write gaurd does not hold a FileDescriptor + //Otherwise, the write guard does not hold a FileDescriptor } else { return syscall_error(Errno::EBADF, "sendto", "invalid file descriptor"); } @@ -1530,11 +1527,8 @@ impl Cage { /// path_resolution(7).) (For UDP sockets) An attempt was made to send to /// a network/broadcast address as though it was a unicast address. /// - /// ** EAGAIN or EWOULDBLOCK - The socket is marked nonblocking and the - /// requested operation would block. POSIX.1-2001 allows either error to - /// be returned for this case, and does not require these constants to - /// have the same value, so a portable application should check for both - /// possibilities. + /// ** EAGAIN - The socket is marked nonblocking and the + /// requested operation would block. /// /// ** EAGAIN - (Internet domain datagram sockets) The socket referred to by /// sockfd had not previously been bound to an address and, upon @@ -1597,10 +1591,10 @@ impl Cage { pub fn send_syscall(&self, fd: i32, buf: *const u8, buflen: usize, flags: i32) -> i32 { //BUG: //If fd is out of range of [0,MAXFD], process will panic - //Otherwise, we obtain a write gaurd to the Option object + //Otherwise, we obtain a write guard to the Option object let checkedfd = self.get_filedescriptor(fd).unwrap(); let mut unlocked_fd = checkedfd.write(); - //Check if the write gaurd holds a valid FileDescriptor + //Check if the write guard holds a valid FileDescriptor if let Some(filedesc_enum) = &mut *unlocked_fd { match filedesc_enum { //In this case, the file descriptor refers to a socket @@ -1645,8 +1639,7 @@ impl Cage { // socket, send() normally // blocks, unless the socket has been placed in // nonblocking I/O mode. In nonblocking mode it would fail with - // the error EAGAIN or - // EWOULDBLOCK in this case. + // the error EAGAIN in this case. let mut nonblocking = false; if sockfdobj.flags & O_NONBLOCK != 0 { nonblocking = true; @@ -1815,7 +1808,7 @@ impl Cage { ); } } - //Otherwise, the write gaurd does not hold a FileDescriptor + //Otherwise, the write guard does not hold a FileDescriptor } else { return syscall_error(Errno::EBADF, "send", "invalid file descriptor"); } @@ -1970,7 +1963,7 @@ impl Cage { //If no messages are available at the socket, the receive calls //wait for a message to arrive, unless the socket is nonblocking //(see fcntl(2)), in which case the value -1 is returned and errno - //is set to EAGAIN or EWOULDBLOCK. + //is set to EAGAIN. let mut nonblocking = false; if sockfdobj.flags & O_NONBLOCK != 0 { nonblocking = true; @@ -2096,7 +2089,7 @@ impl Cage { // from the loop } } - //sum the total number of bytes from the last peak plus the additional + //sum the total number of bytes from the last peek plus the additional //bytes from the current read. This equates to the number of bytes //return to our buff let totalbyteswritten = (buflen - buflenleft) as i32 + retval; @@ -2215,10 +2208,10 @@ impl Cage { ) -> i32 { //BUG: //If fd is out of range of [0,MAXFD], process will panic - //Otherwise, we obtain a write gaurd to the Option object + //Otherwise, we obtain a write guard to the Option object let checkedfd = self.get_filedescriptor(fd).unwrap(); let mut unlocked_fd = checkedfd.write(); - //Check if the write gaurd holds a valid FileDescriptor, and if so + //Check if the write guard holds a valid FileDescriptor, and if so //call recv_common_inner. //Otherwise, return with an error if let Some(ref mut filedesc_enum) = &mut *unlocked_fd { @@ -2267,12 +2260,9 @@ impl Cage { /// Additional errors may be generated and returned from the /// underlying protocol modules; see their respective manual pages. /// - /// ** EAGAIN or EWOULDBLOCK - The socket is marked nonblocking and the + /// ** EAGAIN - The socket is marked nonblocking and the /// receive operation would block, or a receive timeout had been set and - /// the timeout expired before data was received. POSIX.1 allows - /// either error to be returned for this case, and does not - /// require these constants to have the same value, so a - /// portable application should check for both possibilities. + /// the timeout expired before data was received. /// /// * EBADF - The argument sockfd is an invalid file descriptor. /// @@ -2351,12 +2341,9 @@ impl Cage { /// Additional errors may be generated and returned from the /// underlying protocol modules; see their respective manual pages. /// - /// ** EAGAIN or EWOULDBLOCK - The socket is marked nonblocking and the + /// ** EAGAIN - The socket is marked nonblocking and the /// receive operation would block, or a receive timeout had been set and - /// the timeout expired before data was received. POSIX.1 allows - /// either error to be returned for this case, and does not - /// require these constants to have the same value, so a - /// portable application should check for both possibilities. + /// the timeout expired before data was received. /// /// * EBADF - The argument sockfd is an invalid file descriptor. /// @@ -2443,7 +2430,7 @@ impl Cage { pub fn listen_syscall(&self, fd: i32, backlog: i32) -> i32 { //BUG: //If fd is out of range of [0,MAXFD], process will panic - //Otherwise, we obtain a write gaurd to the Option object + //Otherwise, we obtain a write guard to the Option object let checkedfd = self.get_filedescriptor(fd).unwrap(); let mut unlocked_fd = checkedfd.write(); if let Some(filedesc_enum) = &mut *unlocked_fd { @@ -2784,12 +2771,8 @@ impl Cage { /// /// ### Errors /// - /// ** EAGAIN or EWOULDBLOCK - The socket is marked nonblocking and no - /// connections are present to be accepted. - /// POSIX.1-2001 and POSIX.1-2008 - /// allow either error to be returned for this case, and do - /// not require these constants to have the same value, so a - /// portable application should check for both possibilities. + /// ** EAGAIN - The socket is marked nonblocking and no + /// connections are present to be accepted. /// /// ** EBADF - sockfd is not an open file descriptor. /// @@ -2839,7 +2822,7 @@ impl Cage { /// [accept(2)](https://linux.die.net/man/2/accept) pub fn accept_syscall(&self, fd: i32, addr: &mut interface::GenSockaddr) -> i32 { //If fd is out of range of [0,MAXFD], process will panic - //Otherwise, we obtain a write gaurd to the Option object + //Otherwise, we obtain a write guard to the Option object let checkedfd = self.get_filedescriptor(fd).unwrap(); let mut unlocked_fd = checkedfd.write(); if let Some(filedesc_enum) = &mut *unlocked_fd { From d086b46b329bdb2e67789f775d84bf2b5386b76e Mon Sep 17 00:00:00 2001 From: davidge20 Date: Thu, 1 Aug 2024 01:08:40 +0000 Subject: [PATCH 12/13] Changed panic to syscall error --- src/safeposix/syscalls/net_calls.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/safeposix/syscalls/net_calls.rs b/src/safeposix/syscalls/net_calls.rs index b0e06c25b..e0124fc7f 100644 --- a/src/safeposix/syscalls/net_calls.rs +++ b/src/safeposix/syscalls/net_calls.rs @@ -1629,7 +1629,7 @@ impl Cage { //can't send messages return syscall_error( Errno::ENOTCONN, - "writev", + "send", "The descriptor is not connected", ); } @@ -1654,7 +1654,11 @@ impl Cage { //sendpipe is not available in unix socket info //transmission of data is not possible so return with error None => { - panic!("sendpipe is not available in unix socket info in send syscall"); + return syscall_error( + Errno::ENOTCONN, + "send", + "sendpipe is not available", + ) } }; //In the case that the write_to_pipe call returns EPIPE, From 81e9438e2d8f57d825d5b5fc82858b0f0a73e6c3 Mon Sep 17 00:00:00 2001 From: davidge20 Date: Thu, 15 Aug 2024 02:31:35 +0000 Subject: [PATCH 13/13] updated errno formatting --- src/safeposix/syscalls/net_calls.rs | 131 ++++++++++++++-------------- 1 file changed, 65 insertions(+), 66 deletions(-) diff --git a/src/safeposix/syscalls/net_calls.rs b/src/safeposix/syscalls/net_calls.rs index e0124fc7f..b6f6eb301 100644 --- a/src/safeposix/syscalls/net_calls.rs +++ b/src/safeposix/syscalls/net_calls.rs @@ -811,19 +811,21 @@ impl Cage { /// address family of the specified socket. /// * EALREADY - A connection request is already in progress for the /// specified socket. - /// ** EBADF - The socket argument is not a valid file descriptor. + /// * EBADF - The socket argument is not a valid file descriptor. May be + /// returned by RustPOSIX /// * ECONNREFUSED - The target address was not listening for connections or /// refused the connection request. - /// ** EINPROGRESS - O_NONBLOCK is set for the file descriptor for the - /// socket and the connection cannot be immediately established; the - /// connection shall be established asynchronously. + /// * EINPROGRESS - O_NONBLOCK is set for the file descriptor for the socket + /// and the connection cannot be immediately established; the connection + /// shall be established asynchronously. (May be returned by RustPOSIX) /// * EINTR - The attempt to establish a connection was interrupted by /// delivery of a signal that was caught; the connection shall be /// established asynchronously. - /// ** EISCONN - The specified socket is connection-mode and is already - /// connected. + /// * EISCONN - The specified socket is connection-mode and is already + /// connected. (May be returned by RustPOSIX) /// * ENETUNREACH - No route to the network is present. - /// ** ENOTSOCK - The socket argument does not refer to a socket. + /// * ENOTSOCK - The socket argument does not refer to a socket. May be + /// returned by RustPOSIX /// * EPROTOTYPE - The specified address has a different type than the /// socket bound to the specified peer address. /// * ETIMEDOUT - The attempt to connect timed out before a connection was @@ -838,8 +840,8 @@ impl Cage { /// of the pathname in address. /// * ENAMETOOLONG - A component of a pathname exceeded {NAME_MAX} /// characters, or an entire pathname exceeded {PATH_MAX} characters. - /// ** ENOENT - A component of the pathname does not name an existing file - /// or the pathname is an empty string. + /// * ENOENT - A component of the pathname does not name an existing file or + /// the pathname is an empty string. (May be returned by RustPOSIX) /// * ENOTDIR - A component of the path prefix of the pathname in address is /// not a directory. /// @@ -852,8 +854,9 @@ impl Cage { /// * ECONNRESET - Remote host reset the connection request. /// * EHOSTUNREACH - The destination host cannot be reached (probably /// because the host is down or a remote router cannot reach it). - /// ** EINVAL - The address_len argument is not a valid length for the - /// address family; or invalid address family in the sockaddr structure. + /// * EINVAL - The address_len argument is not a valid length for the + /// address family; or invalid address family in the sockaddr structure. + /// (May be returned by RustPOSIX) /// * ELOOP - More than {SYMLOOP_MAX} symbolic links were encountered during /// resolution of the pathname in address. /// * ENAMETOOLONG - Pathname resolution of a symbolic link produced an @@ -861,14 +864,13 @@ impl Cage { /// * ENETDOWN - The local network interface used to reach the destination /// is down. /// * ENOBUFS- No buffer space is available. - /// ** EOPNOTSUPP - The socket is listening and cannot be connected. - /// - /// ** Indicates the error may be returned from RustPOSIX + /// * EOPNOTSUPP - The socket is listening and cannot be connected. May be + /// returned by RustPOSIX /// /// ### Panics /// - /// * Unknown errno value from bind libc call, will cause panic - /// * Unknown errno value from connect libc call, will cause panic. + /// * Unknown errno value from bind libc call will cause panic. + /// * Unknown errno value from connect libc call will cause panic. /// /// for more detailed description of all the commands and return values, see /// [connect(3)](https://linux.die.net/man/3/connect) @@ -1280,18 +1282,18 @@ impl Cage { /// path_resolution(7).) (For UDP sockets) An attempt was made to send to /// a network/broadcast address as though it was a unicast address. /// - /// ** EAGAIN - The socket is marked nonblocking and the - /// requested operation would block. - /// - /// ** EAGAIN - (Internet domain datagram sockets) The socket referred to by - /// sockfd had not previously been bound to an address and, upon + /// * EAGAIN - The socket is marked nonblocking and the requested operation + /// would block. Or (Internet domain datagram sockets) The socket referred + /// to by sockfd had not previously been bound to an address and, upon /// attempting to bind it to an ephemeral port, it was determined that all /// port numbers in the ephemeral port range are currently in use. See - /// the discussion of /proc/sys/net/ipv4/ip_local_port_range in ip(7). + /// the discussion of /proc/sys/net/ipv4/ip_local_port_range in ip(7). May + /// be returned by RustPOSIX /// /// * EALREADY - Another Fast Open is in progress. /// - /// ** EBADF - sockfd is not a valid open file descriptor. + /// * EBADF - sockfd is not a valid open file descriptor. (May be returned + /// by RustPOSIX) /// /// * ECONNRESET - Connection reset by peer. /// @@ -1303,7 +1305,7 @@ impl Cage { /// * EINTR - A signal occurred before any data was transmitted; see /// signal(7). /// - /// ** EINVAL - Invalid argument passed. + /// * EINVAL - Invalid argument passed. (May be returned by RustPOSIX) /// /// * EISCONN - The connection-mode socket was connected already but a /// recipient was specified. (Now either this error is returned, or the @@ -1320,18 +1322,18 @@ impl Cage { /// /// * ENOMEM - No memory available. /// - /// ** ENOTCONN - The socket is not connected, and no target has been given. + /// * ENOTCONN - The socket is not connected, and no target has been given. + /// (May be returned by RustPOSIX) /// - /// ** ENOTSOCK - The file descriptor sockfd does not refer to a socket. + /// * ENOTSOCK - The file descriptor sockfd does not refer to a socket. (May + /// be returned by RustPOSIX) /// - /// ** EOPNOTSUPP - Some bit in the flags argument is inappropriate for the - /// socket type. + /// * EOPNOTSUPP - Some bit in the flags argument is inappropriate for the + /// socket type. (May be returned by RustPOSIX) /// - /// ** EPIPE - The local end has been shut down on a connection oriented + /// * EPIPE - The local end has been shut down on a connection oriented /// socket. In this case, the process will also receive a SIGPIPE unless - /// MSG_NOSIGNAL is set. - /// - /// ** Indicates the error may be returned from RustPOSIX + /// MSG_NOSIGNAL is set. (May be returned by RustPOSIX) /// /// ### Panics: /// @@ -1527,18 +1529,18 @@ impl Cage { /// path_resolution(7).) (For UDP sockets) An attempt was made to send to /// a network/broadcast address as though it was a unicast address. /// - /// ** EAGAIN - The socket is marked nonblocking and the - /// requested operation would block. - /// - /// ** EAGAIN - (Internet domain datagram sockets) The socket referred to by - /// sockfd had not previously been bound to an address and, upon + /// * EAGAIN - The socket is marked nonblocking and the requested operation + /// would block. Or (Internet domain datagram sockets) The socket referred + /// to by sockfd had not previously been bound to an address and, upon /// attempting to bind it to an ephemeral port, it was determined that all /// port numbers in the ephemeral port range are currently in use. See /// the discussion of /proc/sys/net/ipv4/ip_local_port_range in ip(7). + /// (May be returned by RustPOSIX) /// /// * EALREADY - Another Fast Open is in progress. /// - /// ** EBADF - sockfd is not a valid open file descriptor. + /// * EBADF - sockfd is not a valid open file descriptor. (May be returned + /// by RustPOSIX) /// /// * ECONNRESET - Connection reset by peer. /// @@ -1550,7 +1552,7 @@ impl Cage { /// * EINTR - A signal occurred before any data was transmitted; see /// signal(7). /// - /// ** EINVAL - Invalid argument passed. + /// * EINVAL - Invalid argument passed. (May be returned by RustPOSIX) /// /// * EISCONN - The connection-mode socket was connected already but a /// recipient was specified. (Now either this error is returned, or the @@ -1567,18 +1569,18 @@ impl Cage { /// /// * ENOMEM - No memory available. /// - /// ** ENOTCONN - The socket is not connected, and no target has been given. + /// * ENOTCONN - The socket is not connected, and no target has been given. + /// (May be returned by RustPOSIX) /// - /// ** ENOTSOCK - The file descriptor sockfd does not refer to a socket. + /// * ENOTSOCK - The file descriptor sockfd does not refer to a socket. (May + /// be returned by RustPOSIX) /// - /// ** EOPNOTSUPP - Some bit in the flags argument is inappropriate for the - /// socket type. + /// * EOPNOTSUPP - Some bit in the flags argument is inappropriate for the + /// socket type. (May be returned by RustPOSIX) /// - /// ** EPIPE - The local end has been shut down on a connection oriented + /// * EPIPE - The local end has been shut down on a connection oriented /// socket. In this case, the process will also receive a SIGPIPE unless - /// MSG_NOSIGNAL is set. - /// - /// ** Indicates the error may be returned from RustPOSIX + /// MSG_NOSIGNAL is set. (May be returned by RustPOSIX) /// /// ### Panics: /// @@ -2264,9 +2266,9 @@ impl Cage { /// Additional errors may be generated and returned from the /// underlying protocol modules; see their respective manual pages. /// - /// ** EAGAIN - The socket is marked nonblocking and the - /// receive operation would block, or a receive timeout had been set and - /// the timeout expired before data was received. + /// * EAGAIN - The socket is marked nonblocking and the receive operation + /// would block, or a receive timeout had been set and the timeout expired + /// before data was received. (May be returned by RustPOSIX) /// /// * EBADF - The argument sockfd is an invalid file descriptor. /// @@ -2288,8 +2290,6 @@ impl Cage { /// /// * ENOTSOCK - The file descriptor sockfd does not refer to a socket. /// - /// ** Indicates the error may be returned from RustPOSIX - /// /// ### Panics: /// /// * invalid or out-of-bounds file descriptor, calling unwrap() on it will @@ -2345,9 +2345,9 @@ impl Cage { /// Additional errors may be generated and returned from the /// underlying protocol modules; see their respective manual pages. /// - /// ** EAGAIN - The socket is marked nonblocking and the - /// receive operation would block, or a receive timeout had been set and - /// the timeout expired before data was received. + /// * EAGAIN - The socket is marked nonblocking and the receive operation + /// would block, or a receive timeout had been set and the timeout expired + /// before data was received. (May be returned by RustPOSIX) /// /// * EBADF - The argument sockfd is an invalid file descriptor. /// @@ -2369,8 +2369,6 @@ impl Cage { /// /// * ENOTSOCK - The file descriptor sockfd does not refer to a socket. /// - /// ** Indicates the error may be returned from RustPOSIX - /// /// ### Panics: /// /// * invalid or out-of-bounds file descriptor, calling unwrap() on it will @@ -2775,10 +2773,11 @@ impl Cage { /// /// ### Errors /// - /// ** EAGAIN - The socket is marked nonblocking and no - /// connections are present to be accepted. + /// * EAGAIN - The socket is marked nonblocking and no connections are + /// present to be accepted. (May be returned by RustPOSIX) /// - /// ** EBADF - sockfd is not an open file descriptor. + /// * EBADF - sockfd is not an open file descriptor. (May be returned by + /// RustPOSIX) /// /// * ECONNABORTED - A connection has been aborted. /// @@ -2788,8 +2787,8 @@ impl Cage { /// * EINTR - The system call was interrupted by a signal that was caught /// before a valid connection arrived; see signal(7). /// - /// ** EINVAL - Socket is not listening for connections, or addrlen is - /// invalid (e.g., is negative). + /// * EINVAL - Socket is not listening for connections, or addrlen is + /// invalid (e.g., is negative). (May be returned by RustPOSIX) /// /// * EMFILE - The per-process limit on the number of open file descriptors /// has been reached. @@ -2801,9 +2800,11 @@ impl Cage { /// allocation is limited by the socket buffer limits, not by the system /// memory. /// - /// ** ENOTSOCK - The file descriptor sockfd does not refer to a socket. + /// * ENOTSOCK - The file descriptor sockfd does not refer to a socket. (May + /// be returned by RustPOSIX) /// - /// ** EOPNOTSUPP - The referenced socket is not of type SOCK_STREAM. + /// * EOPNOTSUPP - The referenced socket is not of type SOCK_STREAM. (May be + /// returned by RustPOSIX) /// /// * EPERM - Firewall rules forbid connection. /// @@ -2814,8 +2815,6 @@ impl Cage { /// other errors such as ENOSR, ESOCKTNOSUPPORT, EPROTONOSUPPORT, /// ETIMEDOUT. The value ERESTARTSYS may be seen during a trace. /// - /// ** Indicates the error may be returned from RustPOSIX - /// /// ### Panics /// /// * invalid or out-of-bounds file descriptor), calling unwrap() on it will