mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-22 17:03:23 +00:00
Set socket errors after connecting
This commit is contained in:
committed by
Tate, Hongliang Tian
parent
27c5c27fd0
commit
698e748150
@ -204,6 +204,8 @@ impl StreamSocket {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn check_connect(&self) -> Result<()> {
|
fn check_connect(&self) -> Result<()> {
|
||||||
|
// Hold the lock in advance to avoid deadlocks.
|
||||||
|
let mut options = self.options.write();
|
||||||
let mut state = self.state.write();
|
let mut state = self.state.write();
|
||||||
|
|
||||||
match state.as_mut() {
|
match state.as_mut() {
|
||||||
@ -212,8 +214,9 @@ impl StreamSocket {
|
|||||||
}
|
}
|
||||||
State::Connected(connected_stream) => connected_stream.check_new(),
|
State::Connected(connected_stream) => connected_stream.check_new(),
|
||||||
State::Init(_) | State::Listen(_) => {
|
State::Init(_) | State::Listen(_) => {
|
||||||
// FIXME: The error code should be retrieved via the `SO_ERROR` socket option
|
let sock_errors = options.socket.sock_errors();
|
||||||
return_errno_with_message!(Errno::ECONNREFUSED, "the connection is refused");
|
options.socket.set_sock_errors(None);
|
||||||
|
sock_errors.map(Err).unwrap_or(Ok(()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -518,13 +521,24 @@ impl Socket for StreamSocket {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn get_option(&self, option: &mut dyn SocketOption) -> Result<()> {
|
fn get_option(&self, option: &mut dyn SocketOption) -> Result<()> {
|
||||||
let options = self.options.read();
|
// Note that the socket error has to be handled separately, because it is automatically
|
||||||
|
// cleared after reading.
|
||||||
match_sock_option_mut!(option, {
|
match_sock_option_mut!(option, {
|
||||||
// Socket Options
|
|
||||||
socket_errors: SocketError => {
|
socket_errors: SocketError => {
|
||||||
|
let mut options = self.options.write();
|
||||||
let sock_errors = options.socket.sock_errors();
|
let sock_errors = options.socket.sock_errors();
|
||||||
socket_errors.set(sock_errors);
|
socket_errors.set(sock_errors);
|
||||||
|
options.socket.set_sock_errors(None);
|
||||||
|
|
||||||
|
return Ok(());
|
||||||
},
|
},
|
||||||
|
_ => ()
|
||||||
|
});
|
||||||
|
|
||||||
|
let options = self.options.read();
|
||||||
|
|
||||||
|
match_sock_option_mut!(option, {
|
||||||
|
// Socket options:
|
||||||
socket_reuse_addr: ReuseAddr => {
|
socket_reuse_addr: ReuseAddr => {
|
||||||
let reuse_addr = options.socket.reuse_addr();
|
let reuse_addr = options.socket.reuse_addr();
|
||||||
socket_reuse_addr.set(reuse_addr);
|
socket_reuse_addr.set(reuse_addr);
|
||||||
@ -541,7 +555,7 @@ impl Socket for StreamSocket {
|
|||||||
let reuse_port = options.socket.reuse_port();
|
let reuse_port = options.socket.reuse_port();
|
||||||
socket_reuse_port.set(reuse_port);
|
socket_reuse_port.set(reuse_port);
|
||||||
},
|
},
|
||||||
// Tcp Options
|
// TCP options:
|
||||||
tcp_no_delay: NoDelay => {
|
tcp_no_delay: NoDelay => {
|
||||||
let no_delay = options.tcp.no_delay();
|
let no_delay = options.tcp.no_delay();
|
||||||
tcp_no_delay.set(no_delay);
|
tcp_no_delay.set(no_delay);
|
||||||
@ -565,17 +579,19 @@ impl Socket for StreamSocket {
|
|||||||
let window_clamp = options.tcp.window_clamp();
|
let window_clamp = options.tcp.window_clamp();
|
||||||
tcp_window_clamp.set(window_clamp);
|
tcp_window_clamp.set(window_clamp);
|
||||||
},
|
},
|
||||||
_ => return_errno_with_message!(Errno::ENOPROTOOPT, "get unknown option")
|
_ => return_errno_with_message!(Errno::ENOPROTOOPT, "the socket option to get is unknown")
|
||||||
});
|
});
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_option(&self, option: &dyn SocketOption) -> Result<()> {
|
fn set_option(&self, option: &dyn SocketOption) -> Result<()> {
|
||||||
let mut options = self.options.write();
|
let mut options = self.options.write();
|
||||||
|
|
||||||
// FIXME: here we have only set the value of the option, without actually
|
// FIXME: here we have only set the value of the option, without actually
|
||||||
// making any real modifications.
|
// making any real modifications.
|
||||||
match_sock_option_ref!(option, {
|
match_sock_option_ref!(option, {
|
||||||
// Socket options
|
// Socket options:
|
||||||
socket_recv_buf: RecvBuf => {
|
socket_recv_buf: RecvBuf => {
|
||||||
let recv_buf = socket_recv_buf.get().unwrap();
|
let recv_buf = socket_recv_buf.get().unwrap();
|
||||||
if *recv_buf <= MIN_RECVBUF {
|
if *recv_buf <= MIN_RECVBUF {
|
||||||
@ -604,7 +620,7 @@ impl Socket for StreamSocket {
|
|||||||
let linger = socket_linger.get().unwrap();
|
let linger = socket_linger.get().unwrap();
|
||||||
options.socket.set_linger(*linger);
|
options.socket.set_linger(*linger);
|
||||||
},
|
},
|
||||||
// Tcp options
|
// TCP options:
|
||||||
tcp_no_delay: NoDelay => {
|
tcp_no_delay: NoDelay => {
|
||||||
let no_delay = tcp_no_delay.get().unwrap();
|
let no_delay = tcp_no_delay.get().unwrap();
|
||||||
options.tcp.set_no_delay(*no_delay);
|
options.tcp.set_no_delay(*no_delay);
|
||||||
@ -616,12 +632,11 @@ impl Socket for StreamSocket {
|
|||||||
tcp_maxseg: MaxSegment => {
|
tcp_maxseg: MaxSegment => {
|
||||||
const MIN_MAXSEG: u32 = 536;
|
const MIN_MAXSEG: u32 = 536;
|
||||||
const MAX_MAXSEG: u32 = 65535;
|
const MAX_MAXSEG: u32 = 65535;
|
||||||
|
|
||||||
let maxseg = tcp_maxseg.get().unwrap();
|
let maxseg = tcp_maxseg.get().unwrap();
|
||||||
|
|
||||||
if *maxseg < MIN_MAXSEG || *maxseg > MAX_MAXSEG {
|
if *maxseg < MIN_MAXSEG || *maxseg > MAX_MAXSEG {
|
||||||
return_errno_with_message!(Errno::EINVAL, "New maxseg should be in allowed range.");
|
return_errno_with_message!(Errno::EINVAL, "the maximum segment size is out of bounds");
|
||||||
}
|
}
|
||||||
|
|
||||||
options.tcp.set_maxseg(*maxseg);
|
options.tcp.set_maxseg(*maxseg);
|
||||||
},
|
},
|
||||||
tcp_window_clamp: WindowClamp => {
|
tcp_window_clamp: WindowClamp => {
|
||||||
@ -633,8 +648,9 @@ impl Socket for StreamSocket {
|
|||||||
options.tcp.set_window_clamp(*window_clamp);
|
options.tcp.set_window_clamp(*window_clamp);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
_ => return_errno_with_message!(Errno::ENOPROTOOPT, "set unknown option")
|
_ => return_errno_with_message!(Errno::ENOPROTOOPT, "the socket option to be set is unknown")
|
||||||
});
|
});
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -644,9 +660,11 @@ impl Observer<()> for StreamSocket {
|
|||||||
let conn_ready = self.update_io_events();
|
let conn_ready = self.update_io_events();
|
||||||
|
|
||||||
if conn_ready {
|
if conn_ready {
|
||||||
// FIXME: The error code should be stored as the `SO_ERROR` socket option. Since it
|
// Hold the lock in advance to avoid race conditions.
|
||||||
// does not exist yet, we ignore the return value below.
|
let mut options = self.options.write();
|
||||||
let _ = self.finish_connect();
|
|
||||||
|
let result = self.finish_connect();
|
||||||
|
options.socket.set_sock_errors(result.err());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -268,3 +268,25 @@ FN_TEST(connect)
|
|||||||
TEST_ERRNO(connect(sk_accepted, psaddr, addrlen), EISCONN);
|
TEST_ERRNO(connect(sk_accepted, psaddr, addrlen), EISCONN);
|
||||||
}
|
}
|
||||||
END_TEST()
|
END_TEST()
|
||||||
|
|
||||||
|
FN_TEST(async_connect)
|
||||||
|
{
|
||||||
|
struct pollfd pfd = { .fd = sk_bound, .events = POLLOUT };
|
||||||
|
int err;
|
||||||
|
socklen_t errlen = sizeof(err);
|
||||||
|
|
||||||
|
sk_addr.sin_port = 0xbeef;
|
||||||
|
TEST_ERRNO(connect(sk_bound, (struct sockaddr *)&sk_addr,
|
||||||
|
sizeof(sk_addr)),
|
||||||
|
EINPROGRESS);
|
||||||
|
|
||||||
|
TEST_RES(poll(&pfd, 1, 60), pfd.revents & POLLOUT);
|
||||||
|
|
||||||
|
TEST_RES(getsockopt(sk_bound, SOL_SOCKET, SO_ERROR, &err, &errlen),
|
||||||
|
errlen == sizeof(err) && err == ECONNREFUSED);
|
||||||
|
|
||||||
|
// Reading the socket error will cause it to be cleared
|
||||||
|
TEST_RES(getsockopt(sk_bound, SOL_SOCKET, SO_ERROR, &err, &errlen),
|
||||||
|
errlen == sizeof(err) && err == 0);
|
||||||
|
}
|
||||||
|
END_TEST()
|
||||||
|
Reference in New Issue
Block a user