1
+ #![ allow( deprecated) ]
2
+
1
3
//! Contains an implementation of a custom async coio based [`TcpStream`].
2
4
//!
3
5
//! ## Example
16
18
//! # };
17
19
//! ```
18
20
19
- use std:: cell:: { self , Cell } ;
21
+ use std:: cell:: Cell ;
20
22
use std:: ffi:: { CString , NulError } ;
21
23
use std:: future:: { self } ;
22
24
use std:: mem:: { self , MaybeUninit } ;
23
25
use std:: os:: fd:: { AsRawFd , FromRawFd , IntoRawFd } ;
24
26
use std:: os:: unix:: io:: RawFd ;
25
27
use std:: pin:: Pin ;
26
- use std:: rc:: { self , Rc } ;
28
+ use std:: rc:: Rc ;
27
29
use std:: task:: { Context , Poll } ;
28
30
use std:: time:: Duration ;
29
31
use std:: { io, marker, vec} ;
@@ -104,6 +106,54 @@ impl Drop for AutoCloseFd {
104
106
}
105
107
}
106
108
109
+ /// A store for raw file descriptor so we can allow cloning actual `TcpStream` properly.
110
+ #[ derive( Debug ) ]
111
+ struct TcpInner {
112
+ /// A raw tcp socket file descriptor. Replaced with `None` when the stream
113
+ /// is closed.
114
+ fd : Cell < Option < RawFd > > ,
115
+ }
116
+
117
+ impl TcpInner {
118
+ #[ inline( always) ]
119
+ #[ track_caller]
120
+ fn close ( & self ) -> io:: Result < ( ) > {
121
+ let Some ( fd) = self . fd . take ( ) else {
122
+ return Ok ( ( ) ) ;
123
+ } ;
124
+ // SAFETY: safe because we close the `fd` only once
125
+ let rc = unsafe { ffi:: coio_close ( fd) } ;
126
+ if rc != 0 {
127
+ let e = io:: Error :: last_os_error ( ) ;
128
+ if e. raw_os_error ( ) == Some ( libc:: EBADF ) {
129
+ crate :: say_error!( "close({fd}): Bad file descriptor" ) ;
130
+ if cfg ! ( debug_assertions) {
131
+ panic ! ( "close({}): Bad file descriptor" , fd) ;
132
+ }
133
+ }
134
+ return Err ( e) ;
135
+ }
136
+ Ok ( ( ) )
137
+ }
138
+
139
+ #[ inline( always) ]
140
+ fn fd ( & self ) -> io:: Result < RawFd > {
141
+ let Some ( fd) = self . fd . get ( ) else {
142
+ let e = io:: Error :: new ( io:: ErrorKind :: Other , "socket closed already" ) ;
143
+ return Err ( e) ;
144
+ } ;
145
+ Ok ( fd)
146
+ }
147
+ }
148
+
149
+ impl Drop for TcpInner {
150
+ fn drop ( & mut self ) {
151
+ if let Err ( e) = self . close ( ) {
152
+ crate :: say_error!( "TcpInner::drop: closing tcp stream inner failed: {e}" ) ;
153
+ }
154
+ }
155
+ }
156
+
107
157
/// Async TcpStream based on fibers and coio.
108
158
///
109
159
/// Use [timeout][t] on top of read or write operations on [`TcpStream`]
@@ -118,15 +168,8 @@ impl Drop for AutoCloseFd {
118
168
/// [t]: crate::fiber::async::timeout::timeout
119
169
#[ derive( Debug , Clone ) ]
120
170
pub struct TcpStream {
121
- /// A raw tcp socket file descriptor. Replaced with `None` when the stream
122
- /// is closed.
123
- ///
124
- /// Note that it's wrapped in a `Rc`, because the outer `TcpStream` needs to
125
- /// be mutably borrowable (thanks to AsyncWrite & AsyncRead traits) and it
126
- /// doesn't make sense to wrap it in a Mutex of any sort, because it's
127
- /// perfectly safe to read & write on a tcp socket even from concurrent threads,
128
- /// but we only use it from different fibers.
129
- fd : Rc < Cell < Option < RawFd > > > ,
171
+ /// An actual fd which also stored it's open/close state.
172
+ inner : Rc < TcpInner > ,
130
173
}
131
174
132
175
impl TcpStream {
@@ -248,32 +291,22 @@ impl TcpStream {
248
291
249
292
#[ inline( always) ]
250
293
#[ track_caller]
251
- pub fn close ( & mut self ) -> io:: Result < ( ) > {
252
- let Some ( fd) = self . fd . take ( ) else {
253
- // Already closed.
254
- return Ok ( ( ) ) ;
255
- } ;
256
-
257
- // SAFETY: safe because we close the `fd` only once
258
- let rc = unsafe { ffi:: coio_close ( fd) } ;
259
- if rc != 0 {
260
- let e = io:: Error :: last_os_error ( ) ;
261
- if e. raw_os_error ( ) == Some ( libc:: EBADF ) {
262
- crate :: say_error!( "close({fd}): Bad file descriptor" ) ;
263
- if cfg ! ( debug_assertions) {
264
- panic ! ( "close({}): Bad file descriptor" , fd) ;
265
- }
266
- }
267
- return Err ( e) ;
268
- }
269
- Ok ( ( ) )
294
+ pub fn close ( & self ) -> io:: Result < ( ) > {
295
+ self . inner . close ( )
270
296
}
271
297
}
272
298
299
+ /// SAFETY: completely unsafe, but we are allowed to do this cause sending/sharing following stream to/from another thread
300
+ /// SAFETY: will take no effect due to no runtime within it
301
+ unsafe impl Send for TcpStream { }
302
+ unsafe impl Sync for TcpStream { }
303
+
273
304
impl From < RawFd > for TcpStream {
274
305
fn from ( value : RawFd ) -> Self {
275
306
Self {
276
- fd : rc:: Rc :: new ( cell:: Cell :: new ( Some ( value) ) ) ,
307
+ inner : Rc :: new ( TcpInner {
308
+ fd : Cell :: new ( Some ( value) ) ,
309
+ } ) ,
277
310
}
278
311
}
279
312
}
@@ -290,10 +323,7 @@ impl AsyncWrite for TcpStream {
290
323
cx : & mut Context < ' _ > ,
291
324
buf : & [ u8 ] ,
292
325
) -> Poll < io:: Result < usize > > {
293
- let Some ( fd) = self . fd . get ( ) else {
294
- let e = io:: Error :: new ( io:: ErrorKind :: Other , "socket closed already" ) ;
295
- return Poll :: Ready ( Err ( e) ) ;
296
- } ;
326
+ let fd = self . inner . fd ( ) ?;
297
327
298
328
let ( result, err) = (
299
329
// `self.fd` must be nonblocking for this to work correctly
@@ -325,25 +355,17 @@ impl AsyncWrite for TcpStream {
325
355
}
326
356
327
357
fn poll_flush ( self : Pin < & mut Self > , _cx : & mut Context < ' _ > ) -> Poll < io:: Result < ( ) > > {
328
- if self . fd . get ( ) . is_none ( ) {
329
- let e = io:: Error :: new ( io:: ErrorKind :: Other , "socket closed already" ) ;
330
- return Poll :: Ready ( Err ( e) ) ;
331
- } ;
332
-
358
+ self . inner . fd ( ) ?;
333
359
// [`TcpStream`] similarily to std does not buffer anything,
334
360
// so there is nothing to flush.
335
361
//
336
362
// If buffering is needed use [`futures::io::BufWriter`] on top of this stream.
337
363
Poll :: Ready ( Ok ( ( ) ) )
338
364
}
339
365
340
- fn poll_close ( mut self : Pin < & mut Self > , _cx : & mut Context < ' _ > ) -> Poll < io:: Result < ( ) > > {
341
- if self . fd . get ( ) . is_none ( ) {
342
- let e = io:: Error :: new ( io:: ErrorKind :: Other , "socket closed already" ) ;
343
- return Poll :: Ready ( Err ( e) ) ;
344
- } ;
345
-
346
- let res = self . close ( ) ;
366
+ fn poll_close ( self : Pin < & mut Self > , _cx : & mut Context < ' _ > ) -> Poll < io:: Result < ( ) > > {
367
+ self . inner . fd ( ) ?;
368
+ let res = self . inner . close ( ) ;
347
369
Poll :: Ready ( res)
348
370
}
349
371
}
@@ -354,13 +376,10 @@ impl AsyncRead for TcpStream {
354
376
cx : & mut Context < ' _ > ,
355
377
buf : & mut [ u8 ] ,
356
378
) -> Poll < io:: Result < usize > > {
357
- let Some ( fd) = self . fd . get ( ) else {
358
- let e = io:: Error :: new ( io:: ErrorKind :: Other , "socket closed already" ) ;
359
- return Poll :: Ready ( Err ( e) ) ;
360
- } ;
379
+ let fd = self . inner . fd ( ) ?;
361
380
362
381
let ( result, err) = (
363
- // `self.fd` must be nonblocking for this to work correctly
382
+ // `self.inner. fd` must be nonblocking for this to work correctly
364
383
unsafe { libc:: read ( fd, buf. as_mut_ptr ( ) as * mut libc:: c_void , buf. len ( ) ) } ,
365
384
io:: Error :: last_os_error ( ) ,
366
385
) ;
@@ -389,14 +408,6 @@ impl AsyncRead for TcpStream {
389
408
}
390
409
}
391
410
392
- impl Drop for TcpStream {
393
- fn drop ( & mut self ) {
394
- if let Err ( e) = self . close ( ) {
395
- crate :: say_error!( "TcpStream::drop: closing tcp stream failed: {e}" ) ;
396
- }
397
- }
398
- }
399
-
400
411
/// Resolves provided url and port to a sequence of sock addrs.
401
412
///
402
413
/// # Returns
@@ -628,6 +639,7 @@ impl<'a> From<&'a SockAddr> for AddrInfo<'a> {
628
639
/// necessary when working with our async runtime, which is single threaded.
629
640
#[ derive( Debug , Clone ) ]
630
641
#[ repr( transparent) ]
642
+ #[ deprecated = "Use `TcpStream` instead" ]
631
643
pub struct UnsafeSendSyncTcpStream ( pub TcpStream ) ;
632
644
633
645
unsafe impl Send for UnsafeSendSyncTcpStream { }
0 commit comments