@@ -13,7 +13,13 @@ use crate::{
13
13
conditional_yield_with_timeout,
14
14
fail:: Fail ,
15
15
memory:: DemiBuffer ,
16
- network:: unwrap_socketaddr,
16
+ network:: {
17
+ socket:: option:: {
18
+ SocketOption ,
19
+ TcpSocketOptions ,
20
+ } ,
21
+ unwrap_socketaddr,
22
+ } ,
17
23
queue:: QDesc ,
18
24
OperationResult ,
19
25
SharedObject ,
@@ -68,6 +74,8 @@ pub struct MemorySocket {
68
74
pending_request_ids : HashSet < RequestId > ,
69
75
/// Random number generator for request ids.
70
76
rng : SmallRng ,
77
+ /// SO_LINGER option, which dictates how long to wait for the connection to close.
78
+ options : TcpSocketOptions ,
71
79
}
72
80
73
81
pub struct SharedMemorySocket ( SharedObject < MemorySocket > ) ;
@@ -93,6 +101,7 @@ impl SharedMemorySocket {
93
101
rng : SmallRng :: seed_from_u64 ( REQUEST_ID_SEED ) ,
94
102
#[ cfg( not( debug_assertions) ) ]
95
103
rng : SmallRng :: from_entropy ( ) ,
104
+ options : TcpSocketOptions :: default ( ) ,
96
105
} ) )
97
106
}
98
107
@@ -108,9 +117,26 @@ impl SharedMemorySocket {
108
117
rng : SmallRng :: seed_from_u64 ( REQUEST_ID_SEED ) ,
109
118
#[ cfg( not( debug_assertions) ) ]
110
119
rng : SmallRng :: from_entropy ( ) ,
120
+ options : TcpSocketOptions :: default ( ) ,
111
121
} ) )
112
122
}
113
123
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
+
114
140
/// Binds the target socket to `local` address.
115
141
/// TODO: Should probably move the create of the duplex pipe to listen.
116
142
pub fn bind ( & mut self , local : SocketAddrV4 , catmem : & mut SharedCatmemLibOS ) -> Result < ( ) , Fail > {
@@ -230,11 +256,23 @@ impl SharedMemorySocket {
230
256
/// Closes `socket`.
231
257
pub async fn close ( & mut self , catmem : SharedCatmemLibOS ) -> Result < ( ) , Fail > {
232
258
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 {
234
272
( _, OperationResult :: Close ) => ( ) ,
235
273
( _, OperationResult :: Failed ( e) ) => return Err ( e) ,
236
274
_ => panic ! ( "Should not return anything other than close or fail" ) ,
237
- }
275
+ } ;
238
276
} ;
239
277
Ok ( ( ) )
240
278
}
0 commit comments