1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
//! Items related to the `osc::Sender` implementation.

use super::{encode, CommunicationError, Connected, Packet, Unconnected};
use std;
use std::net::{SocketAddr, SocketAddrV4, ToSocketAddrs, UdpSocket};

/// The default port bound to by the `Sender`.
///
/// In most cases, mono-directional networking tools will bind to port `0` for outgoing
/// connections, which means that the OS assigns a freely available random outgoing port.
pub const DEFAULT_PORT: u16 = 0;

/// A type used for sending OSC packets.
pub struct Sender<M = Unconnected> {
    socket: UdpSocket,
    mode: M,
}

/// The default socket address bound to by the `Sender`.
///
/// This address is the `default_ipv4_addr` with the `DEFAULT_PORT`.
pub fn default_sender_socket_addr_v4() -> SocketAddrV4 {
    SocketAddrV4::new(super::default_ipv4_addr(), DEFAULT_PORT)
}

impl<M> Sender<M> {
    /// The socket address that this `Sender`'s socket was created from.
    pub fn local_addr(&self) -> Result<SocketAddr, std::io::Error> {
        self.socket.local_addr()
    }
}

impl Sender<Unconnected> {
    /// Creates a new `Sender` with the UDP socket bound to the given address. **Note: this is
    /// not the target address**, rather it is the address of the socket used by the `Sender` to
    /// send packets. Use the `bind` constructor instead if you would like the `Sender`'s socket
    /// bound to the default address.
    ///
    /// ```no_run
    ///
    /// use nannou_osc::Sender;
    ///
    /// fn main() {
    ///     let tx = Sender::bind_to("0.0.0.0:0").expect("Couldn't bind socket to the address");
    /// }
    /// ```
    ///
    /// The returned `Sender` is `Unconnected`, meaning that it is not currently connected to a
    /// specific target address. This means that the target address will have to be specified when
    /// calling `send`. To connect the `Sender` to a specific target address, use the `connect`
    /// builder method which will return a `Sender` in the `Connected` mode.
    pub fn bind_to<A>(addr: A) -> Result<Self, std::io::Error>
    where
        A: ToSocketAddrs,
    {
        let socket = UdpSocket::bind(addr)?;
        let mode = Unconnected;
        let sender = Sender { socket, mode };
        Ok(sender)
    }

    /// The same as `bind_to` but assumes the `default_sender_socket_addr_v4` socket address.
    pub fn bind() -> Result<Self, std::io::Error> {
        Self::bind_to(default_sender_socket_addr_v4())
    }

    /// Connects the `Sender`'s UDP socket to the given target, remote address.
    ///
    /// The returned `Sender` will only send packets to the specified address.
    ///
    /// Returns an error if some IO error occurred.
    ///
    /// **Panic!**s if the given `addr` cannot resolve to a valid `SocketAddr`.
    ///
    /// ```no_run
    ///
    /// use nannou_osc::Sender;
    ///
    /// fn main() {
    ///     let tx = Sender::bind()
    ///         .expect("Couldn't bind to default socket")
    ///         .connect("127.0.0.1:34254")
    ///         .expect("Couldn't connect to socket at address");
    /// }
    /// ```
    pub fn connect<A>(self, addr: A) -> Result<Sender<Connected>, std::io::Error>
    where
        A: ToSocketAddrs,
    {
        let Sender { socket, .. } = self;
        let mut addrs = addr.to_socket_addrs()?;
        let addr = addrs.next().expect("could not resolve any `SocketAddr`s");
        socket.connect(addr)?;
        let mode = Connected { addr };
        Ok(Sender { socket, mode })
    }

    /// Sends the given packet on the `Sender`s socket to the given address.
    ///
    /// The given `packet` can be of any type that can be converted directly into a `Packet`. This
    /// includes `Message`, `Bundle` and `(String, Vec<Type>)` (which will be interpreted as a
    /// `Message`).
    ///
    /// On success, returns the number of bytes written.
    ///
    /// This will return a `CommunicationError` if:
    ///
    /// - The given packet fails to be encoded to bytes
    /// - The IP version of the local socket does not match that returned from `addr` or
    /// - The inner `UdpSocket::send_to` call fails.
    pub fn send<P, A>(&self, packet: P, addr: A) -> Result<usize, CommunicationError>
    where
        P: Into<Packet>,
        A: ToSocketAddrs,
    {
        let bytes = encode(packet.into())?;
        let bytes_written = self.socket.send_to(&bytes, addr)?;
        Ok(bytes_written)
    }
}

impl Sender<Connected> {
    /// Returns the address of the socket to which the `Sender` is `Connected`.
    pub fn remote_addr(&self) -> SocketAddr {
        self.mode.addr
    }

    /// Sends the given packet on the `Sender`s socket to the connected address.
    ///
    /// On success, returns the number of bytes written.
    ///
    /// This will return a `CommunicationError` if:
    ///
    /// - The given packet fails to be encoded to bytes
    /// - The IP version of the local socket does not match the connected socket or
    /// - The inner `UdpSocket::send` call fails.
    pub fn send<P>(&self, packet: P) -> Result<usize, CommunicationError>
    where
        P: Into<Packet>,
    {
        let bytes = encode(packet.into())?;
        let bytes_written = self.socket.send(&bytes)?;
        Ok(bytes_written)
    }
}