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
use std::{
    convert::TryInto,
    net::{Ipv4Addr, Ipv6Addr},
};

use super::*;

#[derive(Clone, Debug, Eq, PartialEq)]
pub struct CallerOptions {
    pub remote: SocketAddress,
    pub stream_id: Option<StreamId>,
    pub socket: SocketOptions,
}

impl CallerOptions {
    pub fn new(
        remote: impl TryInto<SocketAddress>,
        stream_id: Option<&str>,
    ) -> Result<Valid<Self>, OptionsError> {
        let socket = Default::default();
        Self::with(remote, stream_id, socket)
    }

    pub fn with(
        remote: impl TryInto<SocketAddress>,
        stream_id: Option<&str>,
        socket: SocketOptions,
    ) -> Result<Valid<CallerOptions>, OptionsError> {
        let remote = remote
            .try_into()
            .map_err(|_| OptionsError::InvalidRemoteAddress)?;

        let stream_id = match stream_id {
            Some(s) => Some(
                s.to_string()
                    .try_into()
                    .map_err(OptionsError::InvalidStreamId)?,
            ),
            None => None,
        };

        use SocketHost::*;
        let local_ip = socket.connect.local.ip();
        let local_ip = match (local_ip.is_ipv6(), &remote.host) {
            (false, &Ipv6(_)) if local_ip == Ipv4Addr::UNSPECIFIED => Ipv6Addr::UNSPECIFIED.into(),
            (true, &Ipv4(_)) if local_ip == Ipv6Addr::UNSPECIFIED => Ipv4Addr::UNSPECIFIED.into(),
            _ => local_ip,
        };

        let mut options = Self {
            remote,
            stream_id,
            socket,
        };

        options.socket.connect.local.set_ip(local_ip);

        options.try_validate()
    }
}

impl Validation for CallerOptions {
    type Error = OptionsError;

    fn is_valid(&self) -> Result<(), Self::Error> {
        let local = &self.socket.connect.local;
        use SocketHost::*;
        let mismatch = match (&self.remote.host, local.ip().is_ipv4()) {
            (Ipv4(ipv4), false) => Some((*ipv4).into()),
            (Ipv6(ipv6), true) => Some((*ipv6).into()),
            _ => None,
        };
        if let Some(remote_ip) = mismatch {
            return Err(OptionsError::MismatchedAddressFamilies(
                remote_ip,
                local.ip(),
            ));
        }
        self.socket.is_valid()?;
        self.is_valid_composite()
    }
}

impl CompositeValidation for CallerOptions {
    fn is_valid_composite(&self) -> Result<(), <Self as Validation>::Error> {
        Ok(())
    }
}

impl OptionsOf<SocketOptions> for CallerOptions {
    fn set_options(&mut self, value: SocketOptions) {
        self.socket = value;
    }
}

impl OptionsOf<Connect> for CallerOptions {
    fn set_options(&mut self, value: Connect) {
        self.socket.connect = value;
    }
}

impl OptionsOf<Session> for CallerOptions {
    fn set_options(&mut self, value: Session) {
        self.socket.session = value;
    }
}

impl OptionsOf<Encryption> for CallerOptions {
    fn set_options(&mut self, value: Encryption) {
        self.socket.encryption = value;
    }
}

impl OptionsOf<Sender> for CallerOptions {
    fn set_options(&mut self, value: Sender) {
        self.socket.sender = value;
    }
}

impl OptionsOf<Receiver> for CallerOptions {
    fn set_options(&mut self, value: Receiver) {
        self.socket.receiver = value;
    }
}