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
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
//! Module containg the [IntroductionRequestPayload]((crate::payloads::introductionrequestpayload::IntroductionRequestPayload)) relevant code

use crate::payloads::connectiontype::ConnectionType;
use crate::payloads::Ipv8Payload;
use crate::serialization::bits::Bits;
use crate::serialization::rawend::RawEnd;
use serde;
use serde::de::{Deserialize, Deserializer};
use serde::ser::{Serialize, SerializeStruct, Serializer};
use crate::networking::address::Address;

#[derive(Debug, PartialEq)]
/// The IntroductionRequestPayload is a payload used to send Introduction requests to other peers.
pub struct IntroductionRequestPayload {
    /// is the address of the receiver.  Effectively this should be the
    /// wan address that others can use to contact the receiver.
    pub destination_address: Address,
    /// is the lan address of the sender.  Nodes in the same LAN
    /// should use this address to communicate.
    pub source_lan_address: Address,
    /// is the wan address of the sender.  Nodes not in the same
    /// LAN should use this address to communicate.
    pub source_wan_address: Address,
    /// When True the receiver will introduce the sender to a new
    /// node. This introduction will be facilitated by the receiver sending a puncture-request
    /// to the new node.
    pub advice: bool,
    // self.identifier = identifier % 65536
    // self.extra_bytes = extra_bytes
    /// indicates the connection type that the message creator has.
    pub connection_type: ConnectionType,

    /// is a number that must be given in the associated introduction-response.  This
    /// number allows to distinguish between multiple introduction-response messages.
    /// NOTE: u16 is the max value given by the py-ipv8 implementation
    /// (https://github.com/Tribler/py-ipv8/blob/57c1aa73eee8a3b7ee6ad48482fc2e0d5849415e/ipv8/messaging/payload.py#L74)
    pub identifier: u16,

    /// is a string that can be used to piggyback extra information.
    pub extra_bytes: RawEnd,
}

impl Ipv8Payload for IntroductionRequestPayload {
    // doesnt have anything but needed for the default implementation (as of right now)
}

/// makes the IntroductionRequestPayload serializable.
/// This is less than trivial as there is no 1:1 mapping between the serialized data and the payload struct.
/// Some struct fields are combined into one byte to form the serialized data.
impl Serialize for IntroductionRequestPayload {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        let conntype = self.connection_type.encode();

        let mut state = serializer.serialize_struct("IntroductionRequestPayload", 6)?;
        state.serialize_field("destination_address", &self.destination_address)?;
        state.serialize_field("source_lan_address", &self.source_lan_address)?;
        state.serialize_field("source_wan_address", &self.source_wan_address)?;
        // the False values here correspond to unused bits in the flags field, inherited from py-ipv8.
        state.serialize_field(
            "advice",
            &Bits::from_bools((
                conntype.0,
                conntype.1,
                false,
                false,
                false,
                false,
                false,
                self.advice,
            )),
        )?;
        state.serialize_field("identifier", &self.identifier)?;
        state.serialize_field("extra_bytes", &self.extra_bytes)?;

        state.end()
    }
}

#[derive(Debug, PartialEq, serde::Deserialize)]
/// this is the actual pattern of an introductionRequestPayload.
/// Used for deserializing. This is again needed because there is no 1:1 mapping between the
/// serialized data and the payload struct. This is the intermediate representation.
struct IntroductionRequestPayloadPattern(Address, Address, Address, Bits, u16, RawEnd);

impl<'de> Deserialize<'de> for IntroductionRequestPayload {
    /// deserializes an IntroductionRequestPayload
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        // first deserialize it to a temporary struct which literally represents the packer
        let payload_temporary = IntroductionRequestPayloadPattern::deserialize(deserializer)?;

        // now build the struct for real
        Ok(IntroductionRequestPayload {
            destination_address: payload_temporary.0,
            source_lan_address: payload_temporary.1,
            source_wan_address: payload_temporary.2,
            advice: payload_temporary.3.bit7,
            connection_type: ConnectionType::decode((
                payload_temporary.3.bit0,
                payload_temporary.3.bit1,
            )),
            identifier: payload_temporary.4,
            extra_bytes: payload_temporary.5,
        })
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::serialization::Packet;
    use std::net::{Ipv4Addr, IpAddr, SocketAddr};
    use crate::networking::address::Address;

    #[test]
    fn integration_test_creation() {
        let i = IntroductionRequestPayload {
            destination_address: Address(SocketAddr::new(
                IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)),
                8000,
            )),
            source_lan_address: Address(SocketAddr::new(
                IpAddr::V4(Ipv4Addr::new(42, 42, 42, 42)),
                8000,
            )),
            source_wan_address: Address(SocketAddr::new(
                IpAddr::V4(Ipv4Addr::new(255, 255, 255, 0)),
                8000,
            )),

            advice: true,
            connection_type: ConnectionType::decode((true, true)),
            identifier: 42,
            extra_bytes: RawEnd(vec![43, 44]),
        };

        let mut packet = Packet::new(create_test_header!()).unwrap();
        packet.add(&i).unwrap();
        assert_eq!(
            packet,
            Packet(vec![
                0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 42, 127, 0, 0, 1,
                31, 64, 42, 42, 42, 42, 31, 64, 255, 255, 255, 0, 31, 64, 131, 0, 42, 43, 44
            ])
        );

        assert_eq!(
            i,
            packet
                .start_deserialize()
                .skip_header()
                .unwrap()
                .next_payload()
                .unwrap()
        );
    }
}