ri2p/cmd/
session.rs

1use crate::error::I2pError;
2use crate::socket::I2pStreamSocket;
3use crate::parser::{Command, Subcommand, parse};
4use crate::session::SessionType;
5use crate::cmd::helper;
6
7/// Parse and validate router's SAMv3-compatible response
8///
9/// If the message is valid, return the parsed Message object to caller
10///
11/// # Arguments
12/// `response` - Router's response in text format
13///
14fn parser(response: &str) -> Result<Vec<(String, String)>, I2pError> {
15
16    let parsed = match parse(response, Command::Session, Some(Subcommand::Status)) {
17        Ok(v)  => v,
18        Err(e) => {
19            eprintln!("Failed to parse response: {:#?}", e);
20            return Err(I2pError::InvalidValue);
21        }
22    };
23
24    match helper::check_result(&parsed) {
25        Ok(_) => {
26            Ok(Vec::new())
27        },
28        Err(e) => {
29            eprintln!("Response did not contain RESULT=OK: {:#?}", e.0);
30            eprintln!("Message: {}", e.1);
31            Err(e.0)
32        }
33    }
34}
35
36pub fn datagram(
37    socket: &mut I2pStreamSocket,
38    stype:  &SessionType,
39    nick:   &str,
40    port:   u16)
41    -> Result<(), I2pError>
42{
43    let msg = match stype {
44        SessionType::RepliableDatagram => {
45            format!("SESSION CREATE STYLE=DATAGRAM ID={} PORT={} DESTINATION=TRANSIENT\n",
46                    nick, port)
47        },
48        SessionType::AnonymousDatagram => {
49            format!("SESSION CREATE STYLE=RAW ID={} PORT={} DESTINATION=TRANSIENT\n",
50                    nick, port)
51        },
52        _ => todo!(),
53    };
54
55    match helper::exchange_msg(socket, &msg, &parser) {
56        Ok(_)  => Ok(()),
57        Err(e) => Err(e),
58    }
59}
60
61pub fn stream(socket: &mut I2pStreamSocket, nick: &str) -> Result<(), I2pError> {
62
63    let msg = format!("SESSION CREATE STYLE=STREAM ID={} DESTINATION=TRANSIENT\n", nick);
64
65    match helper::exchange_msg(socket, &msg, &parser) {
66        Ok(_)  => Ok(()),
67        Err(e) => Err(e),
68    }
69}
70
71#[cfg(test)]
72mod tests {
73    use super::*;
74    use crate::socket::I2pStreamSocket;
75
76    #[test]
77    fn test_cmd_session_create() {
78        let mut socket = I2pStreamSocket::connected().unwrap();
79
80        assert_eq!(
81            stream(&mut socket, "nickname1"),
82            Ok(())
83        );
84    }
85
86    // try to create session and then another with the same nickname
87    //
88    // ignore for now as this takes several tens of seconds
89    #[test]
90    fn test_cmd_session_create_duplicate() {
91        let mut socket = I2pStreamSocket::connected().unwrap();
92
93        assert_eq!(
94            stream(&mut socket, "nickname2"),
95            Ok(())
96        );
97
98        assert_eq!(
99            stream(&mut socket, "nickname2"),
100            Err(I2pError::RouterError),
101        );
102    }
103
104    // ignore for now as this takes several tens of seconds
105    #[test]
106    fn test_cmd_session_create_session_two_sockets_same_nick() {
107        let mut socket1 = I2pStreamSocket::connected().unwrap();
108        let mut socket2 = I2pStreamSocket::connected().unwrap();
109
110        assert_eq!(
111            stream(&mut socket1, "nickname3"),
112            Ok(())
113        );
114
115        assert_eq!(
116            stream(&mut socket2, "nickname3"),
117            Err(I2pError::Duplicate),
118        );
119    }
120
121    // try to create multiple datagram sessions for one session,
122    // only the first one should succeed
123    #[test]
124    fn test_cmd_session_dgram_two_connections() {
125        let mut socket = I2pStreamSocket::connected().unwrap();
126
127        assert_eq!(
128            datagram(&mut socket, &SessionType::AnonymousDatagram, "nickname4", 8888),
129            Ok(()),
130        );
131
132        assert_eq!(
133            datagram(&mut socket, &SessionType::AnonymousDatagram, "nickname4", 8888),
134            Err(I2pError::RouterError),
135        );
136
137        assert_eq!(
138            datagram(&mut socket, &SessionType::RepliableDatagram, "nickname4", 8888),
139            Err(I2pError::RouterError),
140        );
141
142        assert_eq!(
143            datagram(&mut socket, &SessionType::RepliableDatagram, "nickname4", 9999),
144            Err(I2pError::RouterError),
145        );
146    }
147
148
149    #[test]
150    fn test_cmd_session_dgram_two_sockets() {
151        let mut socket1 = I2pStreamSocket::connected().unwrap();
152        let mut socket2 = I2pStreamSocket::connected().unwrap();
153
154        assert_eq!(
155            datagram(&mut socket1, &SessionType::AnonymousDatagram, "nickname5", 8888),
156            Ok(()),
157        );
158
159        // same port should fail even if there are two sockets
160        assert_eq!(
161            datagram(&mut socket2, &SessionType::AnonymousDatagram, "nickname5", 8888),
162            Err(I2pError::Duplicate),
163        );
164
165        // same nick but different port should be okay
166        assert_eq!(
167            datagram(&mut socket2, &SessionType::AnonymousDatagram, "nickname5", 9999),
168            Ok(()),
169        );
170    }
171}