1use std::{any, fmt, hash, io, ptr};
2
3use ntex_bytes::{BytePage, BytePages, BytesMut};
4use ntex_codec::{Decoder, Encoder};
5use ntex_service::cfg::SharedCfg;
6use ntex_util::time::Seconds;
7
8use crate::ops::{Id, Iops, TimerHandle};
9use crate::{Decoded, Filter, FilterBuf, Flags, IoConfig, IoContext, IoRef, types};
10
11impl IoRef {
12 #[inline]
13 pub fn id(&self) -> Id {
15 self.0.id()
16 }
17
18 #[inline]
19 pub fn tag(&self) -> &'static str {
21 self.0.tag()
22 }
23
24 #[doc(hidden)]
25 pub fn flags(&self) -> Flags {
27 self.0.flags.clone()
28 }
29
30 #[inline]
31 pub(crate) fn filter(&self) -> &dyn Filter {
33 self.0.filter()
34 }
35
36 #[inline]
37 pub fn cfg(&self) -> &IoConfig {
39 &self.0.cfg
40 }
41
42 #[inline]
43 pub fn shared(&self) -> SharedCfg {
45 self.0.cfg.shared()
46 }
47
48 #[inline]
49 pub fn is_closed(&self) -> bool {
51 self.0.flags.is_closed()
52 }
53
54 #[inline]
55 pub fn is_wr_backpressure(&self) -> bool {
57 self.0.flags.is_wr_backpressure()
58 }
59
60 pub fn close(&self) {
64 self.0.start_shutdown();
65 }
66
67 pub fn terminate(&self) {
72 log::trace!("{}: Terminate io stream object", self.tag());
73 self.0.terminate_connection(None);
74 }
75
76 #[doc(hidden)]
77 #[deprecated(since = "3.10.0", note = "use IoRef::terminate() instead")]
78 pub fn force_close(&self) {
83 self.terminate();
84 }
85
86 #[doc(hidden)]
87 #[deprecated(since = "3.11.0", note = "use IoRef::close() instead")]
88 pub fn wants_shutdown(&self) {
90 self.0.start_shutdown();
91 }
92
93 pub fn query<T: 'static>(&self) -> types::QueryItem<T> {
95 types::QueryItem::new(self.filter().query(any::TypeId::of::<T>()))
96 }
97
98 #[inline]
99 pub fn encode<U>(&self, item: U::Item, codec: &U) -> Result<(), <U as Encoder>::Error>
101 where
102 U: Encoder,
103 {
104 self.with_write_buf(|buf| codec.encodev(item, buf))
105 .unwrap_or_else(|_| Ok(()))
106 }
107
108 #[inline]
109 pub fn encode_slice(&self, src: &[u8]) -> io::Result<()> {
111 self.with_write_buf(|buf| buf.extend_from_slice(src))
112 }
113
114 #[inline]
115 pub fn encode_bytes<B>(&self, src: B) -> io::Result<()>
117 where
118 BytePage: From<B>,
119 {
120 self.with_write_buf(|buf| buf.append(src))
121 }
122
123 pub fn decode<U>(
125 &self,
126 codec: &U,
127 ) -> Result<Option<<U as Decoder>::Item>, <U as Decoder>::Error>
128 where
129 U: Decoder,
130 {
131 self.0.buffer.with_read_dst(self, |buf| {
132 let res = codec.decode(buf);
133 self.0.flags.unset_read_ready();
134 self.update_read_destination(buf);
135 res
136 })
137 }
138
139 pub fn decode_item<U>(
141 &self,
142 codec: &U,
143 ) -> Result<Decoded<<U as Decoder>::Item>, <U as Decoder>::Error>
144 where
145 U: Decoder,
146 {
147 self.0.buffer.with_read_dst(self, |buf| {
148 let len = buf.len();
149 let res = codec.decode(buf).map(|item| Decoded {
150 item,
151 remains: buf.len(),
152 consumed: len - buf.len(),
153 });
154 self.0.flags.unset_read_ready();
155 self.update_read_destination(buf);
156 res
157 })
158 }
159
160 pub fn send_buf(&self) -> io::Result<()> {
165 self.consolidate_write_state(true);
167
168 if self.0.flags.is_stopping_any()
169 && let Some(err) = self.0.error.take()
170 {
171 Err(err)
172 } else {
173 Ok(())
174 }
175 }
176
177 pub(crate) fn ops_send_buf(&self) {
178 let st = &self.0;
179 #[cfg(feature = "trace")]
180 log::trace!(
181 "{}: ops-send == buf:{} flags:{:?}",
182 st.tag(),
183 st.buffer.write_buf_size(),
184 st.flags
185 );
186
187 if st.flags.is_wr_send_scheduled() {
188 st.flags.unset_wr_send_scheduled();
189
190 if st.flags.is_write_paused() {
191 if self.call_write() == WakeWriteTask::Yes {
195 st.wake_write_task();
196 st.flags.unset_write_paused();
197 }
198 } else {
199 st.wake_write_task();
200 }
201 }
202 }
203
204 pub fn with_buf<F, R>(&self, f: F) -> io::Result<R>
206 where
207 F: FnOnce(&mut FilterBuf<'_>) -> R,
208 {
209 let result = self.0.buffer.with_filter(self, |ctx| ctx.with_buffer(f));
210 self.consolidate_write_state(false);
211 Ok(result)
212 }
213
214 pub fn with_read_buf<F, R>(&self, f: F) -> R
216 where
217 F: FnOnce(&mut BytesMut) -> R,
218 {
219 self.0.buffer.with_read_dst(self, |buf| {
220 let res = f(buf);
221 self.update_read_destination(buf);
222 res
223 })
224 }
225
226 pub fn with_write_buf<F, R>(&self, f: F) -> io::Result<R>
228 where
229 F: FnOnce(&mut BytePages) -> R,
230 {
231 let st = &self.0;
232
233 if st.flags.is_stopping_any() {
234 if st.flags.is_closed() {
235 Err(st.error_or_disconnected())
236 } else {
237 Err(io::Error::other("I/O stream is closing"))
238 }
239 } else {
240 let result = st.buffer.with_write_src(f);
241 self.consolidate_write_state(false);
242 Ok(result)
243 }
244 }
245
246 #[inline]
247 pub fn with_write_dst_buf<F, R>(&self, f: F) -> R
249 where
250 F: FnOnce(&mut BytePages) -> R,
251 {
252 self.0.buffer.with_write_dst(f)
253 }
254
255 pub(crate) fn consolidate_write_state(&self, force: bool) {
256 let st = &self.0;
257
258 let size = st.buffer.write_buf_size();
260
261 #[cfg(feature = "trace")]
262 log::trace!("{}: write-upd == buf:{size} flags:{:?}", st.tag(), st.flags);
263
264 if size > 0 && st.flags.is_write_paused() {
265 if st.flags.is_direct_wr_enabled()
276 && (force || size >= st.cfg.write_buf_threshold())
277 {
278 if self.call_write() == WakeWriteTask::Yes {
280 #[cfg(feature = "trace")]
281 log::trace!(
282 "{}: write-upd == schedule(more):{} flags:{:?}",
283 st.tag(),
284 st.buffer.write_buf_size(),
285 st.flags
286 );
287 if !st.flags.is_wr_send_scheduled() {
288 st.flags.set_wr_send_scheduled();
290 Iops::schedule_write(st.id());
291 }
292 } else {
293 st.flags.unset_wr_send_scheduled();
294 }
295 } else if !st.flags.is_wr_send_scheduled() {
296 #[cfg(feature = "trace")]
297 log::trace!("{}: write-upd == schedule(too small)", st.tag());
298 st.flags.set_wr_send_scheduled();
299 Iops::schedule_write(st.id());
300 }
301 }
302 if !st.flags.is_wr_backpressure() && st.is_wr_backpressure_needed(size) {
304 st.flags.set_wr_backpressure();
305 st.wake_dispatch_task();
306 }
307 }
308
309 fn update_read_destination(&self, buf: &mut BytesMut) {
310 let st = &self.0;
311
312 #[cfg(feature = "trace")]
313 log::trace!(
314 "{}: read-upd == buf:{} flags:{:?}",
315 st.tag(),
316 buf.len(),
317 st.flags
318 );
319
320 if st.flags.is_rd_backpressure() {
321 if st.is_rd_backpressure_needed(buf.len()) {
323 return;
324 }
325 st.flags.unset_all_read_flags();
326 } else {
327 st.flags.unset_read_ready();
328 }
329
330 if st.flags.is_read_paused() {
331 st.wake_read_task();
332 st.flags.unset_read_paused();
333 }
334 }
335
336 pub fn resize_read_buf(&self, buf: &mut BytesMut) {
338 self.0.cfg.read_buf().resize(buf);
339 }
340
341 #[doc(hidden)]
342 #[deprecated(since = "3.10.3", note = "Use .notify_disapatcher()")]
343 pub fn wake(&self) {
345 self.notify_dispatcher();
346 }
347
348 pub fn notify_dispatcher(&self) {
350 log::trace!("{}: Timer, notify dispatcher", self.tag());
351 self.0.wake_dispatch_task();
352 }
353
354 pub fn notify_timeout(&self) {
356 self.0.notify_timeout();
357 }
358
359 pub fn timer_handle(&self) -> TimerHandle {
361 self.0.timeout.get()
362 }
363
364 pub fn start_timer(&self, timeout: Seconds) -> TimerHandle {
366 let cur_hnd = self.0.timeout.get();
367
368 if timeout.is_zero() {
369 if cur_hnd.is_set() {
370 self.0.timeout.set(TimerHandle::ZERO);
371 cur_hnd.unregister(self);
372 }
373 TimerHandle::ZERO
374 } else if cur_hnd.is_set() {
375 let hnd = cur_hnd.update(timeout, self);
376 if hnd != cur_hnd {
377 log::trace!("{}: Update timer {:?}", self.tag(), timeout);
378 self.0.timeout.set(hnd);
379 }
380 hnd
381 } else {
382 log::trace!("{}: Start timer {:?}", self.tag(), timeout);
383 let hnd = TimerHandle::register(timeout, self);
384 self.0.timeout.set(hnd);
385 hnd
386 }
387 }
388
389 pub fn stop_timer(&self) {
391 let hnd = self.0.timeout.get();
392 if hnd.is_set() {
393 log::trace!("{}: Stop timer", self.tag());
394 self.0.timeout.set(TimerHandle::ZERO);
395 hnd.unregister(self);
396 }
397 }
398
399 pub fn on_disconnect(&self) -> crate::OnDisconnect {
401 crate::OnDisconnect::new(self.0.clone())
402 }
403
404 fn call_write(&self) -> WakeWriteTask {
407 if let Some(hnd) = self.0.handle.take() {
408 self.0.flags.unset_write_paused();
409 #[cfg(feature = "trace")]
410 log::trace!(
411 "{}: call-write ({}), flags:{:?}",
412 self.tag(),
413 self.0.buffer.write_buf_size(),
414 self.0.flags
415 );
416 let ctx = unsafe { &*(ptr::from_ref(self).cast::<IoContext>()) };
417 hnd.write(ctx);
418 self.0.handle.set(Some(hnd));
419 }
420 if self.0.flags.is_write_paused() {
421 WakeWriteTask::No
422 } else {
423 WakeWriteTask::Yes
424 }
425 }
426
427 pub(crate) fn call_notify(&self) {
428 if let Some(hnd) = self.0.handle.take() {
429 let ctx = unsafe { &*(ptr::from_ref(self).cast::<IoContext>()) };
430 hnd.notify(ctx);
431 self.0.handle.set(Some(hnd));
432 }
433 }
434}
435
436#[derive(Copy, Clone, PartialEq, Eq, Debug)]
437enum WakeWriteTask {
438 Yes,
439 No,
440}
441
442impl Eq for IoRef {}
443
444impl PartialEq for IoRef {
445 #[inline]
446 fn eq(&self, other: &Self) -> bool {
447 self.0.eq(&other.0)
448 }
449}
450
451impl hash::Hash for IoRef {
452 #[inline]
453 fn hash<H: hash::Hasher>(&self, state: &mut H) {
454 self.0.hash(state);
455 }
456}
457
458impl fmt::Debug for IoRef {
459 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
460 f.debug_struct("IoRef")
461 .field("state", self.0.as_ref())
462 .finish()
463 }
464}
465
466#[cfg(test)]
467mod tests {
468 use std::cell::{Cell, RefCell};
469 use std::{future::Future, future::poll_fn, pin::Pin, rc::Rc, task::Poll};
470
471 use ntex_bytes::Bytes;
472 use ntex_codec::BytesCodec;
473 use ntex_util::{future::lazy, time::Millis, time::sleep};
474
475 use super::*;
476 use crate::{FilterCtx, Io, testing::IoTest};
477
478 const BIN: &[u8] = b"GET /test HTTP/1\r\n\r\n";
479 const TEXT: &str = "GET /test HTTP/1\r\n\r\n";
480
481 #[ntex::test]
482 async fn utils() {
483 let (client, server) = IoTest::create();
484 client.remote_buffer_cap(1024);
485 client.write(TEXT);
486
487 let state = Io::from(server);
488 assert_eq!(state.get_ref(), state.get_ref());
489
490 let msg = state.recv(&BytesCodec).await.unwrap().unwrap();
491 assert_eq!(msg, Bytes::from_static(BIN));
492 assert_eq!(state.get_ref(), state.as_ref().clone());
493 assert!(format!("{state:?}").find("Io {").is_some());
494 assert!(format!("{:?}", state.get_ref()).find("IoRef {").is_some());
495
496 let res = poll_fn(|cx| Poll::Ready(state.poll_recv(&BytesCodec, cx))).await;
497 assert!(res.is_pending());
498 client.write(TEXT);
499 sleep(Millis(50)).await;
500 let res = poll_fn(|cx| Poll::Ready(state.poll_recv(&BytesCodec, cx))).await;
501 if let Poll::Ready(msg) = res {
502 assert_eq!(msg.unwrap(), Bytes::from_static(BIN));
503 }
504
505 client.read_error(io::Error::other("err"));
506 let msg = state.recv(&BytesCodec).await;
507 assert!(msg.is_err());
508 assert!(state.flags().is_terminated());
509
510 let (client, server) = IoTest::create();
511 client.remote_buffer_cap(1024);
512 let state = Io::from(server);
513
514 client.read_error(io::Error::other("err"));
515 let res = poll_fn(|cx| Poll::Ready(state.poll_recv(&BytesCodec, cx))).await;
516 if let Poll::Ready(msg) = res {
517 assert!(msg.is_err());
518 assert!(state.flags().is_terminated());
519 }
520
521 let (client, server) = IoTest::create();
522 client.remote_buffer_cap(1024);
523 let state = Io::from(server);
524 assert_eq!(0, state.with_write_dst_buf(|b| b.len()));
525 state.encode_slice(b"test").unwrap();
526 assert_eq!(4, state.with_write_dst_buf(|b| b.len()));
527 let buf = client.read().await.unwrap();
528 assert_eq!(buf, Bytes::from_static(b"test"));
529
530 client.write(b"test");
531 state.read_ready().await.unwrap();
532 let buf = state.decode(&BytesCodec).unwrap().unwrap();
533 assert_eq!(buf, Bytes::from_static(b"test"));
534
535 client.write_error(io::Error::other("err"));
536 state
537 .send(Bytes::from_static(b"test"), &BytesCodec)
538 .await
539 .unwrap();
540 assert!(state.flags().is_terminated());
541
542 let res = state.send(Bytes::from_static(b"test"), &BytesCodec).await;
543 assert!(res.is_err());
544
545 let (client, server) = IoTest::create();
546 client.remote_buffer_cap(1024);
547 let state = Io::from(server);
548 state.terminate();
549 assert!(state.flags().is_stopping());
550 assert!(state.flags().is_terminated());
551 }
552
553 #[ntex::test]
554 #[allow(clippy::unit_cmp)]
555 async fn on_disconnect() {
556 let (client, server) = IoTest::create();
557 let state = Io::from(server);
558 let mut waiter = state.on_disconnect();
559 assert_eq!(
560 lazy(|cx| Pin::new(&mut waiter).poll(cx)).await,
561 Poll::Pending
562 );
563 let mut waiter2 = waiter.clone();
564 assert_eq!(
565 lazy(|cx| Pin::new(&mut waiter2).poll(cx)).await,
566 Poll::Pending
567 );
568 client.close().await;
569 assert_eq!(waiter.await, ());
570 assert_eq!(waiter2.await, ());
571
572 let mut waiter = state.on_disconnect();
573 assert_eq!(
574 lazy(|cx| Pin::new(&mut waiter).poll(cx)).await,
575 Poll::Ready(())
576 );
577
578 let (client, server) = IoTest::create();
579 let state = Io::from(server);
580 let mut waiter = state.on_disconnect();
581 assert_eq!(
582 lazy(|cx| Pin::new(&mut waiter).poll(cx)).await,
583 Poll::Pending
584 );
585 client.read_error(io::Error::other("err"));
586 assert_eq!(waiter.await, ());
587 }
588
589 #[ntex::test]
590 async fn write_to_closed_io() {
591 let (client, server) = IoTest::create();
592 let state = Io::from(server);
593 client.close().await;
594
595 assert!(state.is_closed());
596 assert!(state.encode_slice(TEXT.as_bytes()).is_err());
597 assert!(state.encode_bytes(Bytes::from_static(BIN)).is_err());
598 assert!(
599 state
600 .with_write_buf(|buf| buf.extend_from_slice(BIN))
601 .is_err()
602 );
603 }
604
605 #[derive(Debug)]
606 struct Counter<F> {
607 layer: F,
608 idx: usize,
609 in_bytes: Rc<Cell<usize>>,
610 out_bytes: Rc<Cell<usize>>,
611 read_order: Rc<RefCell<Vec<usize>>>,
612 write_order: Rc<RefCell<Vec<usize>>>,
613 }
614
615 impl<F: Filter> Filter for Counter<F> {
616 fn process_read_buf(&self, ctx: &mut FilterCtx<'_>) -> io::Result<()> {
617 self.read_order.borrow_mut().push(self.idx);
618 let result = self.layer.process_read_buf(ctx);
619 self.in_bytes
620 .set(self.in_bytes.get() + ctx.new_read_bytes());
621 result
622 }
623
624 fn process_write_buf(&self, ctx: &mut FilterCtx<'_>) -> io::Result<()> {
625 self.write_order.borrow_mut().push(self.idx);
626 ctx.with_buffer(|buf| {
627 buf.with_write_buffers(|src, _| {
628 self.out_bytes.set(self.out_bytes.get() + src.len());
629 });
630 });
631 self.layer.process_write_buf(ctx)
632 }
633
634 crate::forward_ready!(layer);
635 crate::forward_query!(layer);
636 crate::forward_shutdown!(layer);
637 }
638
639 #[ntex::test]
640 async fn filter() {
641 let in_bytes = Rc::new(Cell::new(0));
642 let out_bytes = Rc::new(Cell::new(0));
643 let read_order = Rc::new(RefCell::new(Vec::new()));
644 let write_order = Rc::new(RefCell::new(Vec::new()));
645
646 let (client, server) = IoTest::create();
647 let io = Io::from(server)
648 .map_filter(|layer| Counter {
649 layer,
650 idx: 1,
651 in_bytes: in_bytes.clone(),
652 out_bytes: out_bytes.clone(),
653 read_order: read_order.clone(),
654 write_order: write_order.clone(),
655 })
656 .seal();
657
658 client.remote_buffer_cap(1024);
659 client.write(TEXT);
660 let msg = io.recv(&BytesCodec).await.unwrap().unwrap();
661 assert_eq!(msg, Bytes::from_static(BIN));
662
663 io.send(Bytes::from_static(b"test"), &BytesCodec)
664 .await
665 .unwrap();
666 let buf = client.read().await.unwrap();
667 assert_eq!(buf, Bytes::from_static(b"test"));
668
669 client.write(TEXT);
670 let msg = io.recv(&BytesCodec).await.unwrap().unwrap();
671 assert_eq!(msg, Bytes::from_static(BIN));
672
673 assert_eq!(in_bytes.get(), BIN.len() * 2);
674 assert_eq!(out_bytes.get(), 8);
675 }
676
677 #[ntex::test]
678 async fn boxed_filter() {
679 let in_bytes = Rc::new(Cell::new(0));
680 let out_bytes = Rc::new(Cell::new(0));
681 let read_order = Rc::new(RefCell::new(Vec::new()));
682 let write_order = Rc::new(RefCell::new(Vec::new()));
683
684 let (client, server) = IoTest::create();
685 let state = Io::from(server)
686 .map_filter(|layer| Counter {
687 layer,
688 idx: 2,
689 in_bytes: in_bytes.clone(),
690 out_bytes: out_bytes.clone(),
691 read_order: read_order.clone(),
692 write_order: write_order.clone(),
693 })
694 .map_filter(|layer| Counter {
695 layer,
696 idx: 1,
697 in_bytes: in_bytes.clone(),
698 out_bytes: out_bytes.clone(),
699 read_order: read_order.clone(),
700 write_order: write_order.clone(),
701 });
702 let state = state.seal();
703
704 client.remote_buffer_cap(1024);
705 client.write(TEXT);
706 let msg = state.recv(&BytesCodec).await.unwrap().unwrap();
707 assert_eq!(msg, Bytes::from_static(BIN));
708
709 state
710 .send(Bytes::from_static(b"test"), &BytesCodec)
711 .await
712 .unwrap();
713 let buf = client.read().await.unwrap();
714 assert_eq!(buf, Bytes::from_static(b"test"));
715
716 assert_eq!(in_bytes.get(), BIN.len() * 2);
717 assert_eq!(out_bytes.get(), 16);
718 assert_eq!(state.0.buffer.with_write_dst(|b| b.len()), 0);
719
720 assert_eq!(Rc::strong_count(&in_bytes), 3);
722 drop(state);
723 assert_eq!(Rc::strong_count(&in_bytes), 1);
724 assert_eq!(*read_order.borrow(), &[1, 2][..]);
725 assert_eq!(*write_order.borrow(), &[1, 2, 1, 2, 1, 2][..]);
726 }
727}