moov-io / iso8583

A golang implementation to marshal and unmarshal iso8583 message.
https://moov.io
Apache License 2.0
304 stars 100 forks source link

failed to unpack MTI: failed to decode content: not enough data to decode. expected len 4, got 2 #167

Closed mahaprasadnayak closed 10 months ago

mahaprasadnayak commented 2 years ago

Why i am getting this issue while using the function UNPACK()

mahaprasadnayak commented 2 years ago

I am trying to implement the following code.

`package main

import ( "encoding/json" "fmt" "io"

"net"

"github.com/moov-io/iso8583"
"github.com/moov-io/iso8583/field"
"github.com/moov-io/iso8583/network"
"github.com/moov-io/iso8583/specs"

) type NetworkManagementRequest struct { MTI field.String index:"0" TransmissionDateTime field.String index:"7" STAN field.String index:"11" InformationCode field.String index:"70"

} type NetworkManagementResponse struct { MTI field.String index:"0" TransmissionDateTime field.String index:"7" STAN field.String index:"11" InformationCode field.String index:"70" ResponseCode field.String index:"39" } func main() { fmt.Println("In Main") conn:=client() write(conn) } func client()net.TCPConn { tcpAddr, err := net.ResolveTCPAddr("tcp","SERVER_URL:PORT") if err != nil { println("ResolveTCPAddr failed:", err.Error()) } conn, err := net.DialTCP("tcp", nil, tcpAddr) if err != nil { println("Dial failed:", err.Error()) } return conn } func write(conn *net.TCPConn){

header := network.NewBCD2BytesHeader()

reqLen, err := header.ReadFrom(conn)
if err != nil {
// handle error
    fmt.Println("error_l-1",err)
}
fmt.Println("reqlen",reqLen)
fmt.Println("headerlen",header.Length())
message := iso8583.NewMessage(specs.Spec87ASCII)

msg,merr:=json.Marshal(message)
if merr != nil {
    fmt.Println("error in marshalling",merr)
}

// Make a buffer to hold message //buf := make([]byte, 4) // Read the incoming message into the buffer. read, err := io.ReadFull(conn, msg) if err != nil { fmt.Println("error_l",err) } fmt.Println("read",read) if read != header.Length() { fmt.Println("not matched") }

err_up:=message.Unpack(msg)
if err_up != nil{
    fmt.Println("error in unpack",err_up)
}
mti, err := message.GetMTI()
if err != nil{
    fmt.Println("error in getMTI",err)
}

fmt.Println("mti",mti)
data := &NetworkManagementResponse{}

// get field values into data struct err = message.Unmarshal(data) if err != nil { fmt.Println("error in unmarshal",err) } fmt.Println(data.MTI) }

`

alovak commented 2 years ago

just an update after our conversation for someone who may find this issue.

The issue here is that amount of data read from the connection is not enough to decode the message. In the specific example shared with me and posted here (while some lines are commented now) the issue was that we create 4 bytes slice, read 4 bytes from connection and pass it to Unpack method. Smallest possible message can be 10 bytes: MTI (2 bytes if it's BCD encoded) + bitmap (8 bytes).

In example we have here:

header := network.NewBCD2BytesHeader()
_, err := header.ReadFrom(conn)
if err != nil {
    // handle error
}

// Make a buffer to hold message
buf := make([]byte, header.Length())
// Read the incoming message into the buffer.
read, err := io.ReadFull(conn, buf)
if err != nil {
    // handle error
}
if reqLen != header.Length() {
    // handle error
}

message := iso8583.NewMessage(specs.Spec87ASCII)
message.Unpack(buf)

you may see that we make buf with the size of the header.Length() which we read before. header.Length() in this case is not 4 bytes, it's the length of the message that this header contains.

Maybe, for us it's a signal to rename method Length() to MessageLength()...

alovak commented 10 months ago

I hope we will move network package into iso8583-connection. Closing this ticket as the issue was discussed and resolved.