2019-02-14 16:39:18 +01:00
|
|
|
// Copyright 2019 Parity Technologies (UK) Ltd.
|
|
|
|
//
|
|
|
|
// Permission is hereby granted, free of charge, to any person obtaining a
|
|
|
|
// copy of this software and associated documentation files (the "Software"),
|
|
|
|
// to deal in the Software without restriction, including without limitation
|
|
|
|
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
|
|
// and/or sell copies of the Software, and to permit persons to whom the
|
|
|
|
// Software is furnished to do so, subject to the following conditions:
|
|
|
|
//
|
|
|
|
// The above copyright notice and this permission notice shall be included in
|
|
|
|
// all copies or substantial portions of the Software.
|
|
|
|
//
|
|
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
|
|
|
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
|
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
|
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
|
|
// DEALINGS IN THE SOFTWARE.
|
|
|
|
|
2022-12-19 11:26:19 +04:00
|
|
|
use crate::core::muxing::{StreamMuxer, StreamMuxerEvent};
|
2020-07-27 11:05:59 +02:00
|
|
|
|
2019-11-22 14:30:21 +01:00
|
|
|
use futures::{
|
|
|
|
io::{IoSlice, IoSliceMut},
|
|
|
|
prelude::*,
|
|
|
|
ready,
|
|
|
|
};
|
2020-07-27 11:05:59 +02:00
|
|
|
use std::{
|
|
|
|
convert::TryFrom as _,
|
|
|
|
io,
|
|
|
|
pin::Pin,
|
2022-05-12 06:05:33 +02:00
|
|
|
sync::{
|
|
|
|
atomic::{AtomicU64, Ordering},
|
|
|
|
Arc,
|
|
|
|
},
|
2020-07-27 11:05:59 +02:00
|
|
|
task::{Context, Poll},
|
|
|
|
};
|
2019-02-14 16:39:18 +01:00
|
|
|
|
2022-12-19 11:26:19 +04:00
|
|
|
/// Wraps around a [`StreamMuxer`] and counts the number of bytes that go through all the opened
|
|
|
|
/// streams.
|
2019-02-14 16:39:18 +01:00
|
|
|
#[derive(Clone)]
|
2022-07-04 04:16:57 +02:00
|
|
|
#[pin_project::pin_project]
|
2022-12-19 11:26:19 +04:00
|
|
|
pub(crate) struct BandwidthLogging<SMInner> {
|
2022-07-04 04:16:57 +02:00
|
|
|
#[pin]
|
2022-12-19 11:26:19 +04:00
|
|
|
inner: SMInner,
|
2019-02-14 16:39:18 +01:00
|
|
|
sinks: Arc<BandwidthSinks>,
|
|
|
|
}
|
|
|
|
|
2022-12-19 11:26:19 +04:00
|
|
|
impl<SMInner> BandwidthLogging<SMInner> {
|
|
|
|
/// Creates a new [`BandwidthLogging`] around the stream muxer.
|
|
|
|
pub(crate) fn new(inner: SMInner, sinks: Arc<BandwidthSinks>) -> Self {
|
|
|
|
Self { inner, sinks }
|
2019-02-14 16:39:18 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-12-19 11:26:19 +04:00
|
|
|
impl<SMInner> StreamMuxer for BandwidthLogging<SMInner>
|
2019-02-14 16:39:18 +01:00
|
|
|
where
|
2022-12-19 11:26:19 +04:00
|
|
|
SMInner: StreamMuxer,
|
2019-02-14 16:39:18 +01:00
|
|
|
{
|
2022-12-19 11:26:19 +04:00
|
|
|
type Substream = InstrumentedStream<SMInner::Substream>;
|
|
|
|
type Error = SMInner::Error;
|
2019-02-14 16:39:18 +01:00
|
|
|
|
2022-07-04 04:16:57 +02:00
|
|
|
fn poll(
|
|
|
|
self: Pin<&mut Self>,
|
|
|
|
cx: &mut Context<'_>,
|
2022-12-19 11:26:19 +04:00
|
|
|
) -> Poll<Result<StreamMuxerEvent, Self::Error>> {
|
2022-07-04 04:16:57 +02:00
|
|
|
let this = self.project();
|
2022-12-19 11:26:19 +04:00
|
|
|
this.inner.poll(cx)
|
2022-07-04 04:16:57 +02:00
|
|
|
}
|
|
|
|
|
2022-12-19 11:26:19 +04:00
|
|
|
fn poll_inbound(
|
|
|
|
self: Pin<&mut Self>,
|
|
|
|
cx: &mut Context<'_>,
|
|
|
|
) -> Poll<Result<Self::Substream, Self::Error>> {
|
|
|
|
let this = self.project();
|
|
|
|
let inner = ready!(this.inner.poll_inbound(cx)?);
|
|
|
|
let logged = InstrumentedStream {
|
|
|
|
inner,
|
|
|
|
sinks: this.sinks.clone(),
|
|
|
|
};
|
|
|
|
Poll::Ready(Ok(logged))
|
2021-01-12 13:35:11 +01:00
|
|
|
}
|
2019-02-14 16:39:18 +01:00
|
|
|
|
2022-12-19 11:26:19 +04:00
|
|
|
fn poll_outbound(
|
|
|
|
self: Pin<&mut Self>,
|
|
|
|
cx: &mut Context<'_>,
|
|
|
|
) -> Poll<Result<Self::Substream, Self::Error>> {
|
2020-01-14 12:03:10 +01:00
|
|
|
let this = self.project();
|
2022-12-19 11:26:19 +04:00
|
|
|
let inner = ready!(this.inner.poll_outbound(cx)?);
|
|
|
|
let logged = InstrumentedStream {
|
2020-01-14 12:03:10 +01:00
|
|
|
inner,
|
|
|
|
sinks: this.sinks.clone(),
|
|
|
|
};
|
2019-11-22 14:30:21 +01:00
|
|
|
Poll::Ready(Ok(logged))
|
2019-02-14 16:39:18 +01:00
|
|
|
}
|
2022-12-19 11:26:19 +04:00
|
|
|
|
|
|
|
fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
|
|
|
let this = self.project();
|
|
|
|
this.inner.poll_close(cx)
|
|
|
|
}
|
2019-02-14 16:39:18 +01:00
|
|
|
}
|
|
|
|
|
2022-12-19 11:26:19 +04:00
|
|
|
/// Allows obtaining the average bandwidth of the streams.
|
2019-02-14 16:39:18 +01:00
|
|
|
pub struct BandwidthSinks {
|
2022-05-12 06:05:33 +02:00
|
|
|
inbound: AtomicU64,
|
|
|
|
outbound: AtomicU64,
|
2019-02-14 16:39:18 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
impl BandwidthSinks {
|
2022-12-19 11:26:19 +04:00
|
|
|
/// Returns a new [`BandwidthSinks`].
|
|
|
|
pub(crate) fn new() -> Arc<Self> {
|
|
|
|
Arc::new(Self {
|
|
|
|
inbound: AtomicU64::new(0),
|
|
|
|
outbound: AtomicU64::new(0),
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns the total number of bytes that have been downloaded on all the streams.
|
2020-07-27 11:05:59 +02:00
|
|
|
///
|
|
|
|
/// > **Note**: This method is by design subject to race conditions. The returned value should
|
|
|
|
/// > only ever be used for statistics purposes.
|
|
|
|
pub fn total_inbound(&self) -> u64 {
|
|
|
|
self.inbound.load(Ordering::Relaxed)
|
2019-02-14 16:39:18 +01:00
|
|
|
}
|
|
|
|
|
2022-12-19 11:26:19 +04:00
|
|
|
/// Returns the total number of bytes that have been uploaded on all the streams.
|
2020-07-27 11:05:59 +02:00
|
|
|
///
|
|
|
|
/// > **Note**: This method is by design subject to race conditions. The returned value should
|
|
|
|
/// > only ever be used for statistics purposes.
|
|
|
|
pub fn total_outbound(&self) -> u64 {
|
|
|
|
self.outbound.load(Ordering::Relaxed)
|
2019-02-14 16:39:18 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-12-19 11:26:19 +04:00
|
|
|
/// Wraps around an [`AsyncRead`] + [`AsyncWrite`] and logs the bandwidth that goes through it.
|
2020-01-14 12:03:10 +01:00
|
|
|
#[pin_project::pin_project]
|
2022-12-19 11:26:19 +04:00
|
|
|
pub(crate) struct InstrumentedStream<SMInner> {
|
2020-01-14 12:03:10 +01:00
|
|
|
#[pin]
|
2022-12-19 11:26:19 +04:00
|
|
|
inner: SMInner,
|
2019-02-14 16:39:18 +01:00
|
|
|
sinks: Arc<BandwidthSinks>,
|
|
|
|
}
|
|
|
|
|
2022-12-19 11:26:19 +04:00
|
|
|
impl<SMInner: AsyncRead> AsyncRead for InstrumentedStream<SMInner> {
|
2020-07-27 20:27:33 +00:00
|
|
|
fn poll_read(
|
|
|
|
self: Pin<&mut Self>,
|
|
|
|
cx: &mut Context<'_>,
|
|
|
|
buf: &mut [u8],
|
|
|
|
) -> Poll<io::Result<usize>> {
|
2020-01-14 12:03:10 +01:00
|
|
|
let this = self.project();
|
|
|
|
let num_bytes = ready!(this.inner.poll_read(cx, buf))?;
|
2020-07-27 11:05:59 +02:00
|
|
|
this.sinks.inbound.fetch_add(
|
|
|
|
u64::try_from(num_bytes).unwrap_or(u64::max_value()),
|
|
|
|
Ordering::Relaxed,
|
|
|
|
);
|
2019-11-22 14:30:21 +01:00
|
|
|
Poll::Ready(Ok(num_bytes))
|
2019-02-14 16:39:18 +01:00
|
|
|
}
|
|
|
|
|
2020-07-27 20:27:33 +00:00
|
|
|
fn poll_read_vectored(
|
|
|
|
self: Pin<&mut Self>,
|
|
|
|
cx: &mut Context<'_>,
|
|
|
|
bufs: &mut [IoSliceMut<'_>],
|
|
|
|
) -> Poll<io::Result<usize>> {
|
2020-01-14 12:03:10 +01:00
|
|
|
let this = self.project();
|
|
|
|
let num_bytes = ready!(this.inner.poll_read_vectored(cx, bufs))?;
|
2020-07-27 11:05:59 +02:00
|
|
|
this.sinks.inbound.fetch_add(
|
|
|
|
u64::try_from(num_bytes).unwrap_or(u64::max_value()),
|
|
|
|
Ordering::Relaxed,
|
|
|
|
);
|
2019-11-22 14:30:21 +01:00
|
|
|
Poll::Ready(Ok(num_bytes))
|
2019-05-10 11:26:18 +02:00
|
|
|
}
|
2019-11-22 14:30:21 +01:00
|
|
|
}
|
2019-05-10 11:26:18 +02:00
|
|
|
|
2022-12-19 11:26:19 +04:00
|
|
|
impl<SMInner: AsyncWrite> AsyncWrite for InstrumentedStream<SMInner> {
|
2020-07-27 20:27:33 +00:00
|
|
|
fn poll_write(
|
|
|
|
self: Pin<&mut Self>,
|
|
|
|
cx: &mut Context<'_>,
|
|
|
|
buf: &[u8],
|
|
|
|
) -> Poll<io::Result<usize>> {
|
2020-01-14 12:03:10 +01:00
|
|
|
let this = self.project();
|
|
|
|
let num_bytes = ready!(this.inner.poll_write(cx, buf))?;
|
2020-07-27 11:05:59 +02:00
|
|
|
this.sinks.outbound.fetch_add(
|
|
|
|
u64::try_from(num_bytes).unwrap_or(u64::max_value()),
|
|
|
|
Ordering::Relaxed,
|
|
|
|
);
|
2019-11-22 14:30:21 +01:00
|
|
|
Poll::Ready(Ok(num_bytes))
|
2019-05-10 11:26:18 +02:00
|
|
|
}
|
2019-02-14 16:39:18 +01:00
|
|
|
|
2020-07-27 20:27:33 +00:00
|
|
|
fn poll_write_vectored(
|
|
|
|
self: Pin<&mut Self>,
|
|
|
|
cx: &mut Context<'_>,
|
|
|
|
bufs: &[IoSlice<'_>],
|
|
|
|
) -> Poll<io::Result<usize>> {
|
2020-01-14 12:03:10 +01:00
|
|
|
let this = self.project();
|
|
|
|
let num_bytes = ready!(this.inner.poll_write_vectored(cx, bufs))?;
|
2020-07-27 11:05:59 +02:00
|
|
|
this.sinks.outbound.fetch_add(
|
|
|
|
u64::try_from(num_bytes).unwrap_or(u64::max_value()),
|
|
|
|
Ordering::Relaxed,
|
|
|
|
);
|
2019-11-22 14:30:21 +01:00
|
|
|
Poll::Ready(Ok(num_bytes))
|
2019-02-14 16:39:18 +01:00
|
|
|
}
|
|
|
|
|
2020-07-27 20:27:33 +00:00
|
|
|
fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
|
2020-01-14 12:03:10 +01:00
|
|
|
let this = self.project();
|
|
|
|
this.inner.poll_flush(cx)
|
2019-02-14 16:39:18 +01:00
|
|
|
}
|
|
|
|
|
2020-07-27 20:27:33 +00:00
|
|
|
fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
|
2020-01-14 12:03:10 +01:00
|
|
|
let this = self.project();
|
|
|
|
this.inner.poll_close(cx)
|
2019-02-14 16:39:18 +01:00
|
|
|
}
|
|
|
|
}
|