Skip to content

Commit e3f3442

Browse files
authored
Merge pull request #1270 from microsoft/bugfix-pdpix-sockopt
[libos] Disallow Setting SO_LINGER When Socket is Closing
2 parents 0fcdcdc + 6d2231b commit e3f3442

File tree

5 files changed

+129
-22
lines changed

5 files changed

+129
-22
lines changed

man/demi_getsockopt.md

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
# `demi_setsockopt()`
2+
3+
## Name
4+
5+
`demi_setsockopt` - Gets a socket option on a socket I/O queue.
6+
7+
## Synopsis
8+
9+
```c
10+
#include <demi/libos.h>
11+
#include <sys/socket.h> /* For SOL_SOCKET. */
12+
13+
int demi_setsockopt(int sockqd, int level, int optname, const void *optval, socklen_t optlen);
14+
```
15+
16+
## Description
17+
18+
`demi_getsockopt()` gets the option specified by the `optname` argument, at the protocol level specified by the `level` argument, to the value pointed to by the `optval` argument for the socket I/O queue associated with queue descriptor specified by the `socketqd` argument.
19+
20+
Currently the following values for `level` are supported:
21+
22+
- `SOL_SOCKET` - Socket-level options.
23+
24+
Currently the following values for `option` are supported:
25+
26+
- `SO_LINGER` - Linger on/off and linger time in seconds, for queued, unsent data on `demi_close()`.
27+
28+
## Return Value
29+
30+
On success, zero is returned. On error, a positive error code is returned.
31+
32+
## Errors
33+
34+
On error, one of the following positive error codes is returned:
35+
36+
- `EBADF` - The specified `sockqd` is invalid.
37+
- `EINVAL` - The specified `optval` is invalid.
38+
- `EINVAL` - The specified `optlen` is invalid.
39+
- `ENOPROTOOPT` - The specified `optname` is not supported.
40+
- `ENOTSUP` - The specified `level` is not supported.
41+
42+
## Disclaimer
43+
44+
Any behavior that is not documented in this manual page is unintentional and should be reported.
45+
46+
## See Also
47+
48+
`demi_setsockopt()`

man/demi_setsockopt.md

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
# `demi_setsockopt()`
2+
3+
## Name
4+
5+
`demi_setsockopt` - Sets a socket option on a socket I/O queue.
6+
7+
## Synopsis
8+
9+
```c
10+
#include <demi/libos.h>
11+
#include <sys/socket.h> /* For SOL_SOCKET. */
12+
13+
int demi_setsockopt(int sockqd, int level, int optname, const void *optval, socklen_t optlen);
14+
```
15+
16+
## Description
17+
18+
`demi_setsockopt()` sets the option specified by the `optname` argument, at the protocol level specified by the `level`
19+
argument, to the value pointed to by the `optval` argument for the socket I/O queue associated with queue descriptor
20+
specified by the `socketqd` argument.
21+
22+
Currently the following values for `level` are supported:
23+
24+
- `SOL_SOCKET` - Socket-level options.
25+
26+
Currently the following values for `option` are supported:
27+
28+
- `SO_LINGER` - Linger on/off and linger time in seconds, for queued, unsent data on `demi_close()`.
29+
30+
## Return Value
31+
32+
On success, zero is returned. On error, a positive error code is returned.
33+
34+
## Errors
35+
36+
On error, one of the following positive error codes is returned:
37+
38+
- `EBADF` - The specified `sockqd` is invalid.
39+
- `EBUSY` - Cannot set option because socket is busy.
40+
- `EINVAL` - The specified `optval` is invalid.
41+
- `EINVAL` - The specified `optlen` is invalid.
42+
- `ENOPROTOOPT` - The specified `optname` is not supported.
43+
- `ENOTSUP` - The specified `level` is not supported.
44+
45+
## Disclaimer
46+
47+
Any behavior that is not documented in this manual page is unintentional and should be reported.
48+
49+
## See Also
50+
51+
`demi_getsockopt()`

src/rust/demikernel/bindings.rs

Lines changed: 17 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -793,21 +793,20 @@ pub extern "C" fn demi_setsockopt(
793793

794794
// Check inputs.
795795
if level != SOL_SOCKET {
796-
let cause: String = format!("Only options at the socket level are supported");
797-
error!("demi_setsockopt(): {}", cause);
798-
return libc::EINVAL;
796+
error!("demi_setsockopt(): only options in SOL_SOCKET level are supported");
797+
return libc::ENOTSUP;
799798
}
800799

801800
let opt: SocketOption = match optname {
802801
SO_LINGER => {
803802
// Check for invalid storage locations.
804803
if optval.is_null() {
805-
warn!("demi_setsockopt() linger value is a null pointer");
804+
error!("demi_setsockopt(): linger value is a null pointer");
806805
return libc::EINVAL;
807806
}
808807

809808
if optlen as usize != mem::size_of::<Linger>() {
810-
warn!("demi_setsockopt() linger len is incorrect");
809+
warn!("demi_setsockopt(): linger len is incorrect");
811810
return libc::EINVAL;
812811
}
813812

@@ -818,25 +817,24 @@ pub extern "C" fn demi_setsockopt(
818817
}
819818
},
820819
_ => {
821-
let cause: String = format!("Only SO_LINGER is supported right now");
822-
error!("demi_setsockopt(): {}", cause);
823-
return libc::EINVAL;
820+
error!("demi_setsockopt(): only SO_LINGER is supported right now");
821+
return libc::ENOPROTOOPT;
824822
},
825823
};
826824

827825
// Issue socket operation.
828826
let ret: Result<(), Fail> = match do_syscall(|libos| libos.set_socket_option(qd.into(), opt)) {
829827
Ok(result) => result,
830828
Err(e) => {
831-
trace!("demi_getsockopt() failed: {:?}", e);
829+
trace!("demi_getsockopt(): {:?}", e);
832830
return e.errno;
833831
},
834832
};
835833

836834
match ret {
837835
Ok(_) => 0,
838836
Err(e) => {
839-
trace!("demi_getsockopt() failed: {:?}", e);
837+
trace!("demi_getsockopt(): {:?}", e);
840838
e.errno
841839
},
842840
}
@@ -858,36 +856,34 @@ pub extern "C" fn demi_getsockopt(
858856

859857
// Check inputs.
860858
if level != SOL_SOCKET {
861-
let cause: String = format!("Only options at the socket level are supported");
862-
error!("demi_getsockopt(): {}", cause);
863-
return libc::EINVAL;
859+
error!("demi_getsockopt(): only options in SOL_SOCKET level are supported");
860+
return libc::ENOTSUP;
864861
}
865862

866863
let opt: SocketOption = match optname {
867864
SO_LINGER => SocketOption::SO_LINGER(None),
868865
_ => {
869-
let cause: String = format!("Only SO_LINGER is supported right now");
870-
error!("demi_getsockopt(): {}", cause);
871-
return libc::EINVAL;
866+
error!("demi_getsockopt(): only SO_LINGER is supported right now");
867+
return libc::ENOPROTOOPT;
872868
},
873869
};
874870

875871
// Check for invalid storage locations.
876872
if optval.is_null() {
877-
warn!("demi_getsockopt() option value is a null pointer");
873+
warn!("demi_getsockopt(): option value is a null pointer");
878874
return libc::EINVAL;
879875
}
880876

881877
if optlen.is_null() {
882-
warn!("demi_getsockopt() option len is a null pointer");
878+
warn!("demi_getsockopt(): option len is a null pointer");
883879
return libc::EINVAL;
884880
}
885881

886882
// Issue socket operation.
887883
let ret: Result<SocketOption, Fail> = match do_syscall(|libos| libos.get_socket_option(qd.into(), opt)) {
888884
Ok(result) => result,
889885
Err(e) => {
890-
trace!("demi_getsockopt() failed: {:?}", e);
886+
trace!("demi_getsockopt(): {:?}", e);
891887
return e.errno;
892888
},
893889
};
@@ -912,7 +908,7 @@ pub extern "C" fn demi_getsockopt(
912908
},
913909
};
914910

915-
let result_length = mem::size_of::<Linger>();
911+
let result_length: usize = mem::size_of::<Linger>();
916912
unsafe {
917913
ptr::copy(&result as *const Linger as *const c_void, optval, result_length);
918914
*optlen = result_length as Socklen;
@@ -922,7 +918,7 @@ pub extern "C" fn demi_getsockopt(
922918
0
923919
},
924920
Err(e) => {
925-
trace!("demi_getsockopt() failed: {:?}", e);
921+
trace!("demi_getsockopt(): {:?}", e);
926922
return e.errno;
927923
},
928924
}

src/rust/demikernel/libos/network/queue.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,18 @@ impl<T: NetworkTransport> SharedNetworkQueue<T> {
9696

9797
/// Sets a socket option on the socket.
9898
pub fn set_socket_option(&mut self, option: SocketOption) -> Result<(), Fail> {
99+
// Ensure that option can be set, depending on the state of the socket.
100+
#[allow(unreachable_patterns)]
101+
match option {
102+
SocketOption::SO_LINGER(_) => {
103+
if let Err(_) = self.state_machine.ensure_not_closing() {
104+
let cause: String = format!("catnnot set SO_LINGER when socket is closing");
105+
warn!("set_socket_option(): {}", cause);
106+
return Err(Fail::new(libc::EBUSY, &cause));
107+
}
108+
},
109+
_ => (),
110+
}
99111
self.transport.clone().set_socket_option(&mut self.socket, option)
100112
}
101113

src/rust/runtime/network/socket/state.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -351,7 +351,7 @@ impl SocketStateMachine {
351351
}
352352

353353
/// Ensures that the target [SocketState] is not closing.
354-
fn ensure_not_closing(&self) -> Result<(), Fail> {
354+
pub fn ensure_not_closing(&self) -> Result<(), Fail> {
355355
if self.current.get() == SocketState::Closing {
356356
let cause: String = format!("socket is closing");
357357
error!("ensure_not_closing(): {}", cause);

0 commit comments

Comments
 (0)