Skip to main content

s2n_quic_dc/stream/socket/
send_only.rs

1// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2// SPDX-License-Identifier: Apache-2.0
3
4use super::{fd::udp, Protocol, Socket, TransportFeatures};
5use crate::msg::{addr::Addr, cmsg};
6use core::task::{Context, Poll};
7use s2n_quic_core::{ensure, inet::ExplicitCongestionNotification};
8use std::{
9    io::{self, IoSlice, IoSliceMut},
10    net::SocketAddr,
11};
12
13#[derive(Clone, Debug)]
14pub struct SendOnly<T: udp::Socket>(pub T);
15
16impl<T> Socket for SendOnly<T>
17where
18    T: udp::Socket,
19{
20    #[inline]
21    fn local_addr(&self) -> io::Result<SocketAddr> {
22        self.0.local_addr()
23    }
24
25    #[inline]
26    fn protocol(&self) -> Protocol {
27        Protocol::Udp
28    }
29
30    #[inline]
31    fn features(&self) -> TransportFeatures {
32        TransportFeatures::UDP
33    }
34
35    #[inline]
36    fn poll_peek_len(&self, _cx: &mut Context) -> Poll<io::Result<usize>> {
37        unimplemented!()
38    }
39
40    #[inline]
41    fn poll_recv(
42        &self,
43        _cx: &mut Context,
44        _addr: &mut Addr,
45        _cmsg: &mut cmsg::Receiver,
46        _buffer: &mut [IoSliceMut],
47    ) -> Poll<io::Result<usize>> {
48        unimplemented!()
49    }
50
51    #[inline]
52    fn try_send(
53        &self,
54        addr: &Addr,
55        ecn: ExplicitCongestionNotification,
56        buffer: &[IoSlice],
57    ) -> io::Result<usize> {
58        // no point in sending empty packets
59        ensure!(!buffer.is_empty(), Ok(0));
60
61        debug_assert!(
62            buffer.iter().any(|s| !s.is_empty()),
63            "trying to send from an empty buffer"
64        );
65
66        debug_assert!(
67            addr.get().port() != 0,
68            "cannot send packet to unspecified port"
69        );
70
71        loop {
72            match udp::send(&self.0, addr, ecn, buffer, libc::MSG_DONTWAIT) {
73                Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {
74                    // try the operation again if we were interrupted
75                    continue;
76                }
77                Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => {
78                    // we got a WouldBlock so pretend we sent it - we have no way of registering interest
79                    return Ok(buffer.iter().map(|s| s.len()).sum());
80                }
81                res => return res,
82            }
83        }
84    }
85
86    #[inline]
87    fn poll_send(
88        &self,
89        _cx: &mut Context,
90        addr: &Addr,
91        ecn: ExplicitCongestionNotification,
92        buffer: &[IoSlice],
93    ) -> Poll<io::Result<usize>> {
94        self.try_send(addr, ecn, buffer).into()
95    }
96
97    #[inline]
98    fn send_finish(&self) -> io::Result<()> {
99        // UDP sockets don't need a shut down
100        Ok(())
101    }
102}