Skip to content

Commit b7ee223

Browse files
authored
Merge pull request #1257 from microsoft/enhancement-inetstack-sockopts
[libos] Add socket options
2 parents fc96ac0 + aac92af commit b7ee223

File tree

28 files changed

+793
-98
lines changed

28 files changed

+793
-98
lines changed

examples/tcp-close/client.rs

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,18 @@
77

88
use crate::{
99
helper_functions,
10+
DEFAULT_LINGER,
1011
DEFAULT_TIMEOUT,
1112
};
1213
use anyhow::Result;
1314
use demikernel::{
1415
demi_sgarray_t,
15-
runtime::types::{
16-
demi_opcode_t,
17-
demi_qresult_t,
16+
runtime::{
17+
network::socket::option::SocketOption,
18+
types::{
19+
demi_opcode_t,
20+
demi_qresult_t,
21+
},
1822
},
1923
LibOS,
2024
QDesc,
@@ -292,6 +296,9 @@ impl TcpClient {
292296
/// Issues an open socket() operation and registers the queue descriptor for cleanup.
293297
fn issue_socket(&mut self) -> Result<QDesc> {
294298
let qd: QDesc = self.libos.socket(AF_INET, SOCK_STREAM, 0)?;
299+
// Set default linger to a short period, otherwise, this test will take a long time to complete.
300+
self.libos
301+
.set_socket_option(qd, SocketOption::SO_LINGER(Some(DEFAULT_LINGER)))?;
295302
self.qds.insert(qd);
296303
Ok(qd)
297304
}

examples/tcp-close/main.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ use demikernel::{
3232
//======================================================================================================================
3333

3434
const DEFAULT_TIMEOUT: Duration = Duration::from_secs(30);
35+
const DEFAULT_LINGER: Duration = Duration::from_secs(10);
3536

3637
//======================================================================================================================
3738
// main

examples/tcp-close/server.rs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,18 @@
77

88
use crate::{
99
helper_functions,
10+
DEFAULT_LINGER,
1011
DEFAULT_TIMEOUT,
1112
};
1213
use anyhow::Result;
1314
use demikernel::{
1415
demi_sgarray_t,
15-
runtime::types::{
16-
demi_opcode_t,
17-
demi_qresult_t,
16+
runtime::{
17+
network::socket::option::SocketOption,
18+
types::{
19+
demi_opcode_t,
20+
demi_qresult_t,
21+
},
1822
},
1923
LibOS,
2024
QDesc,
@@ -77,6 +81,8 @@ impl TcpServer {
7781
pub fn new(mut libos: LibOS, local: SocketAddr) -> Result<Self> {
7882
// Create TCP socket.
7983
let sockqd: QDesc = libos.socket(AF_INET, SOCK_STREAM, 0)?;
84+
// Set default linger to a short period, otherwise, this test will take a long time to complete.
85+
libos.set_socket_option(sockqd, SocketOption::SO_LINGER(Some(DEFAULT_LINGER)))?;
8086

8187
// Bind to local address.
8288
libos.bind(sockqd, local)?;

examples/tcp-echo/client.rs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,10 @@
55
// Imports
66
//======================================================================================================================
77

8-
use crate::DEFAULT_TIMEOUT;
8+
use crate::{
9+
DEFAULT_LINGER,
10+
DEFAULT_TIMEOUT,
11+
};
912
use anyhow::Result;
1013
use demikernel::{
1114
demi_sgarray_t,
@@ -16,6 +19,7 @@ use demikernel::{
1619
LibOS,
1720
QDesc,
1821
QToken,
22+
SocketOption,
1923
};
2024
use histogram::Histogram;
2125
use std::{
@@ -104,6 +108,10 @@ impl TcpEchoClient {
104108
// Open all connections.
105109
for _ in 0..nclients {
106110
let sockqd: QDesc = self.libos.socket(AF_INET, SOCK_STREAM, 0)?;
111+
// Set default linger to a short period, otherwise, this test will take a long time to complete.
112+
self.libos
113+
.set_socket_option(sockqd, SocketOption::SO_LINGER(Some(DEFAULT_LINGER)))?;
114+
107115
self.clients.insert(sockqd, (vec![0; self.bufsize], 0));
108116
let qt: QToken = self.libos.connect(sockqd, self.remote)?;
109117
let qr: demi_qresult_t = self.libos.wait(qt, Some(DEFAULT_TIMEOUT))?;
@@ -191,6 +199,10 @@ impl TcpEchoClient {
191199
// Open several connections.
192200
for i in 0..nclients {
193201
let qd: QDesc = self.libos.socket(AF_INET, SOCK_STREAM, 0)?;
202+
// Set default linger to a short period, otherwise, this test will take a long time to complete.
203+
self.libos
204+
.set_socket_option(qd, SocketOption::SO_LINGER(Some(DEFAULT_LINGER)))?;
205+
194206
let qt: QToken = self.libos.connect(qd, self.remote)?;
195207
self.register_operation(qd, qt);
196208

examples/tcp-echo/main.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ mod server;
5050
//======================================================================================================================
5151

5252
const DEFAULT_TIMEOUT: Duration = Duration::from_secs(30);
53+
const DEFAULT_LINGER: Duration = Duration::from_secs(10);
5354

5455
//======================================================================================================================
5556
// Program Arguments

examples/tcp-echo/server.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,10 @@
55
// Imports
66
//======================================================================================================================
77

8-
use crate::DEFAULT_TIMEOUT;
8+
use crate::{
9+
DEFAULT_LINGER,
10+
DEFAULT_TIMEOUT,
11+
};
912
use anyhow::Result;
1013
use demikernel::{
1114
demi_sgarray_t,
@@ -16,6 +19,7 @@ use demikernel::{
1619
LibOS,
1720
QDesc,
1821
QToken,
22+
SocketOption,
1923
};
2024
use std::{
2125
collections::{
@@ -68,6 +72,7 @@ impl TcpEchoServer {
6872
pub fn new(mut libos: LibOS, local: SocketAddr) -> Result<Self> {
6973
// Create a TCP socket.
7074
let sockqd: QDesc = libos.socket(AF_INET, SOCK_STREAM, 0)?;
75+
libos.set_socket_option(sockqd, SocketOption::SO_LINGER(Some(DEFAULT_LINGER)))?;
7176

7277
// Bind the socket to a local address.
7378
if let Err(e) = libos.bind(sockqd, local) {

examples/tcp-wait/client.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,10 @@
55
// Imports
66
//======================================================================================================================
77

8-
use crate::DEFAULT_TIMEOUT;
8+
use crate::{
9+
DEFAULT_LINGER,
10+
DEFAULT_TIMEOUT,
11+
};
912
use ::anyhow::Result;
1013
use ::demikernel::{
1114
demi_sgarray_t,
@@ -16,6 +19,7 @@ use ::demikernel::{
1619
LibOS,
1720
QDesc,
1821
QToken,
22+
SocketOption,
1923
};
2024
use ::std::{
2125
net::SocketAddr,
@@ -296,6 +300,10 @@ impl TcpClient {
296300

297301
fn connect_to_server(&mut self, num_clients: usize) -> Result<()> {
298302
self.sockqd = Some(self.libos.socket(AF_INET, SOCK_STREAM, 0)?);
303+
// Set default linger to a short period, otherwise, this test will take a long time to complete.
304+
self.libos
305+
.set_socket_option(self.sockqd.unwrap(), SocketOption::SO_LINGER(Some(DEFAULT_LINGER)))?;
306+
299307
let qt: QToken = self
300308
.libos
301309
.connect(self.sockqd.expect("should be a valid socket"), self.remote)?;

examples/tcp-wait/main.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ use ::std::time::Duration;
3535
//======================================================================================================================
3636

3737
const DEFAULT_TIMEOUT: Duration = Duration::from_secs(30);
38+
const DEFAULT_LINGER: Duration = Duration::from_secs(10);
3839

3940
//======================================================================================================================
4041
// main

examples/tcp-wait/server.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
// Imports
66
//======================================================================================================================
77

8+
use crate::DEFAULT_LINGER;
89
use ::anyhow::Result;
910
use ::demikernel::{
1011
demi_sgarray_t,
@@ -15,6 +16,7 @@ use ::demikernel::{
1516
LibOS,
1617
QDesc,
1718
QToken,
19+
SocketOption,
1820
};
1921
use ::std::{
2022
collections::{
@@ -71,6 +73,8 @@ impl TcpServer {
7173
pub fn new(mut libos: LibOS, local: SocketAddr, nclients: usize) -> Result<Self> {
7274
// Create TCP socket.
7375
let sockqd: QDesc = libos.socket(AF_INET, SOCK_STREAM, 0)?;
76+
// Set default linger to a short period, otherwise, this test will take a long time to complete.
77+
libos.set_socket_option(sockqd, SocketOption::SO_LINGER(Some(DEFAULT_LINGER)))?;
7478

7579
// Bind to local address.
7680
libos.bind(sockqd, local)?;

src/rust/catloop/socket.rs

Lines changed: 41 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,13 @@ use crate::{
1313
conditional_yield_with_timeout,
1414
fail::Fail,
1515
memory::DemiBuffer,
16-
network::unwrap_socketaddr,
16+
network::{
17+
socket::option::{
18+
SocketOption,
19+
TcpSocketOptions,
20+
},
21+
unwrap_socketaddr,
22+
},
1723
queue::QDesc,
1824
OperationResult,
1925
SharedObject,
@@ -68,6 +74,8 @@ pub struct MemorySocket {
6874
pending_request_ids: HashSet<RequestId>,
6975
/// Random number generator for request ids.
7076
rng: SmallRng,
77+
/// SO_LINGER option, which dictates how long to wait for the connection to close.
78+
options: TcpSocketOptions,
7179
}
7280

7381
pub struct SharedMemorySocket(SharedObject<MemorySocket>);
@@ -93,6 +101,7 @@ impl SharedMemorySocket {
93101
rng: SmallRng::seed_from_u64(REQUEST_ID_SEED),
94102
#[cfg(not(debug_assertions))]
95103
rng: SmallRng::from_entropy(),
104+
options: TcpSocketOptions::default(),
96105
}))
97106
}
98107

@@ -108,9 +117,26 @@ impl SharedMemorySocket {
108117
rng: SmallRng::seed_from_u64(REQUEST_ID_SEED),
109118
#[cfg(not(debug_assertions))]
110119
rng: SmallRng::from_entropy(),
120+
options: TcpSocketOptions::default(),
111121
}))
112122
}
113123

124+
/// Set an SO_* option on the socket.
125+
pub fn set_socket_option(&mut self, option: SocketOption) -> Result<(), Fail> {
126+
match option {
127+
SocketOption::SO_LINGER(linger) => self.options.set_linger(linger),
128+
}
129+
Ok(())
130+
}
131+
132+
/// Gets an SO_* option on the socket. The option should be passed in as [option] and the value is returned in
133+
/// [option].
134+
pub fn get_socket_option(&mut self, option: SocketOption) -> Result<SocketOption, Fail> {
135+
match option {
136+
SocketOption::SO_LINGER(_) => Ok(SocketOption::SO_LINGER(self.options.get_linger())),
137+
}
138+
}
139+
114140
/// Binds the target socket to `local` address.
115141
/// TODO: Should probably move the create of the duplex pipe to listen.
116142
pub fn bind(&mut self, local: SocketAddrV4, catmem: &mut SharedCatmemLibOS) -> Result<(), Fail> {
@@ -230,11 +256,23 @@ impl SharedMemorySocket {
230256
/// Closes `socket`.
231257
pub async fn close(&mut self, catmem: SharedCatmemLibOS) -> Result<(), Fail> {
232258
if let Some(qd) = self.catmem_qd {
233-
match catmem.close_coroutine(qd).await {
259+
let result = if let Some(linger) = self.options.get_linger() {
260+
match conditional_yield_with_timeout(catmem.close_coroutine(qd), linger).await {
261+
Err(e) if e.errno == libc::ETIMEDOUT => {
262+
// This case is actually ok because we have waited out the linger time out.
263+
return Ok(());
264+
},
265+
Err(e) => return Err(e),
266+
Ok(result) => result,
267+
}
268+
} else {
269+
catmem.close_coroutine(qd).await
270+
};
271+
match result {
234272
(_, OperationResult::Close) => (),
235273
(_, OperationResult::Failed(e)) => return Err(e),
236274
_ => panic!("Should not return anything other than close or fail"),
237-
}
275+
};
238276
};
239277
Ok(())
240278
}

0 commit comments

Comments
 (0)