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
//! This module contains implementation of a ISO TCP client

use crate::iso8583::iso_spec::{Spec, IsoMsg};
use crate::iso8583::IsoError;
use std::net::{TcpStream, Shutdown};
use crate::iso8583::mli::{MLI, MLIType, MLI2E, MLI2I, MLI4E, MLI4I};
use std::io::{Write, Read};
use crate::iso8583::server::get_hexdump;


/// This struct represents a ISO8583 TCP client
pub struct ISOTcpClient {
    server_addr: String,
    mli: Box<dyn MLI>,
    spec: &'static Spec,
    _tcp_stream: Option<TcpStream>,
}


impl ISOTcpClient {
    /// Creates a new ISOTcpClient
    pub fn new(server_addr: &str, spec: &'static Spec, mli_type: MLIType) -> ISOTcpClient {
        let mli: Box<dyn MLI>;

        match mli_type {
            MLIType::MLI2E => mli = Box::new(MLI2E {}),
            MLIType::MLI2I => mli = Box::new(MLI2I {}),
            MLIType::MLI4E => mli = Box::new(MLI4E {}),
            MLIType::MLI4I => mli = Box::new(MLI4I {})
        }

        ISOTcpClient {
            server_addr: server_addr.to_string(),
            spec,
            mli,
            _tcp_stream: None,
        }
    }

    /// Sends a ISO message to the server and returns the response from server on success
    /// or a IsoError on failure
    pub fn send(&mut self, iso_msg: &IsoMsg) -> Result<IsoMsg, IsoError> {
        match iso_msg.assemble() {
            Ok(data) => {
                let mut buf = self.mli.create(&data.len()).unwrap();
                buf.extend(data);
                self.send_recv(&buf)
            }
            Err(e) => {
                Err(IsoError { msg: format!("Failed to assemble request message: {}", e.msg) })
            }
        }
    }

    fn send_recv(&mut self, raw_msg: &Vec<u8>) -> Result<IsoMsg, IsoError> {
        println!("raw iso msg = {}", hex::encode(raw_msg.as_slice()));

        if self._tcp_stream.is_none() {
            self._tcp_stream = match TcpStream::connect(&self.server_addr) {
                Err(e) => return Err(IsoError { msg: e.to_string() }),
                Ok(c) => {
                    println!("connected to server @ {:?}", c.local_addr());
                    Option::Some(c)
                }
            }
        }

        let client = self._tcp_stream.as_mut().unwrap();

        client.write_all(raw_msg.as_slice()).unwrap();
        client.flush().unwrap();

        // read the response
        let len: u32;
        match self.mli.parse(client) {
            Ok(n) => len = n,
            Err(e) => return Err(e)
        };

        let mut out_buf = vec![0; len as usize];

        match client.read_exact(&mut out_buf[..]) {
            Ok(()) => {
                println!("received response: with  {} bytes. \n {}\n", len, get_hexdump(&out_buf));
                match self.spec.parse(&mut out_buf) {
                    Ok(resp_iso_msg) => {
                        Ok(resp_iso_msg)
                    }
                    Err(e) => {
                        Err(IsoError { msg: e.msg })
                    }
                }
            }
            Err(e) => {
                Err(IsoError { msg: e.to_string() })
            }
        }
    }

    pub fn close(&mut self) {
        self._tcp_stream.as_ref().unwrap().shutdown(Shutdown::Both).unwrap();
    }
}