iso8583_rs

ISO8583 library written in Rust

Crates.io

Summary of Operation

Each spec defines a set of header fields (typically the MTI or Message Type), followed by any number of messages (auth/reversal etc). For each incoming request (buffer), the header fields are parsed. The value of the parsed header field is matched against the selector defined on the message. On successful match, the incoming data is parsed against the message. Once parsed, the message is fed into the MsgProcessor defined on the server. The MsgProcessor applies its logic and generates a response which is sent back to the client.

Usage:

``` rust

extern crate byteorder; extern crate hex; extern crate lazy_static;

[macro_use]

extern crate log; extern crate simplelog;

use iso8583rs::iso8583::IsoError; use iso8583rs::iso8583::isospec::{IsoMsg, newmsg}; use iso8583rs::iso8583::server::IsoServer; use iso8583rs::iso8583::server::MsgProcessor;

// Below is an example implementation of a MsgProcessor i.e the entity responsible for handling incoming messages // at the server

[derive(Copy, Clone)]

pub struct SampleMsgProcessor {}

impl MsgProcessor for SampleMsgProcessor { fn process(&self, isoserver: &IsoServer, msg: &mut Vec) -> Result<(Vec, IsoMsg), IsoError> { match isoserver.spec.parse(msg) { Ok(isomsg) => { debug!("parsed incoming request - message = \"{}\" successfully. \n : parsed message: \n --- \n {} \n ----\n", isomsg.msg.name(), iso_msg);

            let req_msg_type = iso_msg.get_field_value(&"message_type".to_string()).unwrap();
            let resp_msg_type = if req_msg_type == "1100" {
                "1110"
            } else if req_msg_type == "1420" {
                "1430"
            } else {
                return Err(IsoError { msg: format!("unsupported msg_type {}", req_msg_type) });
            };


            let mut iso_resp_msg = new_msg(&iso_msg.spec, &iso_msg.spec.get_message_from_header(resp_msg_type).unwrap());

            if req_msg_type == "1420" {
                iso_resp_msg.set("message_type", resp_msg_type).unwrap_or_default();
                iso_resp_msg.echo_from(&iso_msg, &[2, 3, 4, 11, 14, 19, 96])?;
                iso_resp_msg.set_on(39, "400").unwrap_or_default();
            } else if req_msg_type == "1100" {
                handle_1100(&iso_msg, &mut iso_resp_msg)?
            }


            match iso_resp_msg.assemble() {
                Ok(resp_data) => Ok((resp_data, iso_resp_msg)),
                Err(e) => {
                    error!("Failed to assemble response message - {}", e.msg);
                    Err(IsoError { msg: format!("error: msg assembly failed..{} ", e.msg) })
                }
            }
        }
        Err(e) => {
            Err(IsoError { msg: e.msg })
        }
    }
}

}

// Handle the incoming 1100 message based on amount fn handle1100(isomsg: &IsoMsg, isorespmsg: &mut IsoMsg) -> Result<(), IsoError> {

// process the incoming request based on amount
match iso_msg.bmp_child_value(4) {
    Ok(amt) => {
        iso_resp_msg.set("message_type", "1110").unwrap_or_default();

        match amt.parse::<u32>() {
            Ok(i_amt) => {
                debug!("amount = {}", i_amt);
                if i_amt < 100 {
                    iso_resp_msg.set_on(38, "APPR01").unwrap_or_default();
                    iso_resp_msg.set_on(39, "000").unwrap_or_default();
                } else {
                    iso_resp_msg.set_on(39, "100").unwrap_or_default();
                }

                if iso_msg.bmp.is_on(61) {
                    let mut val = iso_msg.bmp_child_value(61).unwrap();
                    val.push_str(" - OK");
                    iso_resp_msg.set_on(61, val.as_str()).unwrap_or_default();
                }

                if iso_msg.bmp.is_on(62) {
                    let mut val = iso_msg.bmp_child_value(62).unwrap();
                    val.push_str(" - OK");
                    iso_resp_msg.set_on(62, val.as_str()).unwrap_or_default();
                }

                iso_resp_msg.set_on(63, "007").unwrap_or_default();
            }
            Err(_e) => {
                iso_resp_msg.set_on(39, "107").unwrap_or_default();
            }
        };

        iso_resp_msg.echo_from(&iso_msg, &[2, 3, 4, 11, 14, 19, 96])?;
        iso_resp_msg.fd_map.insert("bitmap".to_string(), iso_resp_msg.bmp.as_vec());

        Ok(())
    }
    Err(e) => {
        error!("No amount in request, responding with 115. error = {}", e.msg);
        iso_resp_msg.set("message_type", "1110").unwrap_or_default();
        iso_resp_msg.set_on(39, "115").unwrap_or_default();
        iso_resp_msg.echo_from(&iso_msg, &[2, 3, 4, 11, 14, 19, 96])
    }
}

}

fn main() { std::env::setvar("SPECFILE", "samplespec\samplespec.yaml");

let _ = simplelog::SimpleLogger::init(simplelog::LevelFilter::Debug, simplelog::Config::default());

let iso_spec = iso8583_rs::iso8583::iso_spec::spec("");

info!("starting iso server for spec {} at port {}", iso_spec.name(), 6666);
let server: IsoServer = match iso8583_rs::iso8583::server::new("localhost:6666".to_string(),
                                                               Box::new(iso8583_rs::iso8583::mli::MLI2E {}),
                                                               Box::new(SampleMsgProcessor {}), iso_spec) {
    Ok(server) => {
        server
    }
    Err(e) => {
        error!("failed to start ISO server - {}", e.msg);
        panic!(e)
    }
};
server.start().join().unwrap()

}

```

Sample TCP client

```rust

fn sendreversal() -> Result<(), Error> { std::env::setvar("SPECFILE", "samplespec/sample_spec.yaml");

    let spec = crate::iso8583::iso_spec::spec("");
    let msg_seg = spec.get_message_from_header("1420").unwrap();

    let mut iso_msg = iso_spec::new_msg(spec, msg_seg);

    &iso_msg.set("message_type", "1420").unwrap();
    &iso_msg.set_on(2, "123456789101").unwrap();
    &iso_msg.set_on(3, "004000").unwrap();
    &iso_msg.set_on(4, "000000000199").unwrap();
    &iso_msg.set_on(11, "779581").unwrap();
    &iso_msg.set_on(14, "2204").unwrap();
    &iso_msg.set_on(19, "840").unwrap();
    &iso_msg.set_on(96, "1234").unwrap();
    &iso_msg.set_on(160, "5678").unwrap();


    match iso_msg.assemble() {
        Ok(data) => {
            let mli = &crate::iso8583::mli::MLI2E {};
            let mut buf = mli.create(&data.len()).unwrap();
            buf.extend(data);
            send_recv(&buf)
        }
        Err(e) => {
            println!("Failed to assemble request message: {}", e.msg);
            Ok(())
        }
    }
}

```

Run ISO Server

`` C:/Users/rkbal/.cargo/bin/cargo.exe run --color=always --package iso8583_rs --bin iso8583_rs Compiling iso8583_rs v0.1.3 (C:\Users\rkbal\IdeaProjects\iso8583_rs) Finished dev [unoptimized + debuginfo] target(s) in 4.75s Runningtarget\debug\iso8583rs.exe` current-dir: C:\Users\rkbal\IdeaProjects\iso8583rs spec-file: samplespec\samplespec.yaml 20:10:04 [INFO] starting iso server for spec SampleSpec at port 6666 20:10:14 [DEBUG] (2) iso8583rs::iso8583::server: Accepted new connection .. Ok(V6([::1]:57018)) 20:10:14 [DEBUG] (3) iso8583rs::iso8583::server: received request:

|31313030 f0242000 0000100e 80000001| 1100.$ ......... 00000000 |00000000 00000001 00000000 31323132| ............1212 00000010 |33343536 37383931 30313030 34303030| 3456789101004000 00000020 |30303030 30303030 30313939 37373935| 0000000001997795 00000030 |38313232 3034f8f4 f0010203 04050607| 812204.......... 00000040 |08001152 61676861 76656e64 726111d9| ...Raghavendra.. 00000050 |81878881 a5859584 998140c2 81938789| ..........@..... 00000060 |f0f1f138 37383737 36323235 32353132| ...8787762252512 00000070 |33343838 3838| 348888 00000080 00000086

len = 134 20:10:14 [DEBUG] (3) iso8583rs::iso8583::isospec: computed header value for incoming message = 1100 20:10:14 [DEBUG] (3) iso8583rs::iso8583::isospec: parsing field : messagetype 20:10:14 [DEBUG] (3) iso8583rs::iso8583::isospec: parsing field : bitmap 20:10:14 [DEBUG] (3) iso8583rs::iso8583::bitmap: parsing field - pan 20:10:14 [DEBUG] (3) iso8583rs::iso8583::bitmap: parsing field - proccode 20:10:14 [DEBUG] (3) iso8583rs::iso8583::bitmap: parsing field - amount 20:10:14 [DEBUG] (3) iso8583rs::iso8583::bitmap: parsing field - stan 20:10:14 [DEBUG] (3) iso8583rs::iso8583::bitmap: parsing field - expirationdate 20:10:14 [DEBUG] (3) iso8583rs::iso8583::bitmap: parsing field - countrycode 20:10:14 [DEBUG] (3) iso8583rs::iso8583::bitmap: parsing field - pindata 20:10:14 [DEBUG] (3) iso8583rs::iso8583::bitmap: parsing field - private1 20:10:14 [DEBUG] (3) iso8583rs::iso8583::bitmap: parsing field - private2 20:10:14 [DEBUG] (3) iso8583rs::iso8583::bitmap: parsing field - private3 20:10:14 [DEBUG] (3) iso8583rs::iso8583::bitmap: parsing field - keymgmtdata 20:10:14 [DEBUG] (3) iso8583rs::iso8583::bitmap: parsing field - reserveddata 24 20:10:14 [DEBUG] (3) iso8583rs: parsed incoming request - message = "1100 - Authorization" successfully. : parsed message:


messagetype : 1100 bitmap : f02420000000100e80000001000000000000000100000000 pan [002]: 123456789101 proccode [003]: 004000 amount [004]: 000000000199 stan [011]: 779581 expirationdate [014]: 2204 countrycode [019]: 840 pindata [052]: 0102030405060708 private1 [061]: Raghavendra private2 [062]: Raghavendra Balgi private3 [063]: 87877622525 keymgmtdata [096]: 1234 reserved_data [160]: 8888


20:10:14 [DEBUG] (3) iso8583rs: amount = 199 20:10:14 [DEBUG] (3) iso8583rs::iso8583::isospec: echoing .. 2: 123456789101 20:10:14 [DEBUG] (3) iso8583rs::iso8583::isospec: echoing .. 3: 004000 20:10:14 [DEBUG] (3) iso8583rs::iso8583::isospec: echoing .. 4: 000000000199 20:10:14 [DEBUG] (3) iso8583rs::iso8583::isospec: echoing .. 11: 779581 20:10:14 [DEBUG] (3) iso8583rs::iso8583::isospec: echoing .. 14: 2204 20:10:14 [DEBUG] (3) iso8583rs::iso8583::isospec: echoing .. 19: 840 20:10:14 [DEBUG] (3) iso8583rs::iso8583::isospec: echoing .. 96: 1234 20:10:14 [DEBUG] (3) iso8583rs::iso8583::server: iso_response : |31313130 f0242000 0200000e 00000001| 1110.$ ......... 00000000 |00000000 31323132 33343536 37383931| ....121234567891 00000010 |30313030 34303030 30303030 30303030| 0100400000000000 00000020 |30313939 37373935 38313232 3034f8f4| 01997795812204.. 00000030 |f0313030 00165261 67686176 656e6472| .100..Raghavendr 00000040 |61202d20 4f4b16d9 81878881 a5859584| a - OK.......... 00000050 |998140c2 81938789 406040d6 d2f0f0f3| ..@.....@`@..... 00000060 |30303731 323334| 0071234 00000070 00000077

parsed :

messagetype : 1110 bitmap : f02420000200000e0000000100000000 pan [002]: 123456789101 proccode [003]: 004000 amount [004]: 000000000199 stan [011]: 779581 expirationdate [014]: 2204 countrycode [019]: 840 actioncode [039]: 100 private1 [061]: Raghavendra - OK private2 [062]: Raghavendra Balgi - OK private3 [063]: 007 keymgmtdata [096]: 1234 --

20:10:14 [INFO] client socket closed : [::1]:57018

```

ISO TCP Client

Now run src/iso8583/test.rs:testsendrecv_iso(..)

`` Testing started at 01:40 ... raw iso msg = 008631313030f02420000000100e80000001000000000000000100000000313231323334353637383931303130303430303030303030303030303031393937373935383132323034f8f4f001020304050607080011526167686176656e64726111d981878881a5859584998140c281938789f0f1f138373837373632323532353132333438383838 received response: with 119 bytes. |31313130 f0242000 0200000e 00000001| 1110.$ ......... 00000000 |00000000 31323132 33343536 37383931| ....121234567891 00000010 |30313030 34303030 30303030 30303030| 0100400000000000 00000020 |30313939 37373935 38313232 3034f8f4| 01997795812204.. 00000030 |f0313030 00165261 67686176 656e6472| .100..Raghavendr 00000040 |61202d20 4f4b16d9 81878881 a5859584| a - OK.......... 00000050 |998140c2 81938789 406040d6 d2f0f0f3| ..@.....@@..... 00000060 |30303731 323334| 0071234 00000070 00000077 current-dir: C:\Users\rkbal\IdeaProjects\iso8583rs spec-file: samplespec/sample_spec.yaml 16 parsed iso-response "1100 - Authorization"

messagetype : 1110 bitmap : f02420000200000e0000000100000000 pan [002]: 123456789101 proccode [003]: 004000 amount [004]: 000000000199 stan [011]: 779581 expirationdate [014]: 2204 countrycode [019]: 840 actioncode [039]: 100 private1 [061]: Raghavendra - OK private2 [062]: Raghavendra Balgi - OK private3 [063]: 007 keymgmtdata [096]: 1234

```