|
@@ -1,243 +1,253 @@
|
|
|
package main
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
import (
|
|
|
- "os"
|
|
|
|
|
- "time"
|
|
|
|
|
- "encoding/json"
|
|
|
|
|
- "encoding/binary"
|
|
|
|
|
- "net"
|
|
|
|
|
- "fmt"
|
|
|
|
|
- "errors"
|
|
|
|
|
|
|
+ "encoding/binary"
|
|
|
|
|
+ "encoding/json"
|
|
|
|
|
+ "errors"
|
|
|
|
|
+ "fmt"
|
|
|
|
|
+ "net"
|
|
|
|
|
+ "os"
|
|
|
|
|
+ "strconv"
|
|
|
|
|
+ "time"
|
|
|
)
|
|
)
|
|
|
|
|
|
|
|
func (o *Oftp) New(filename string) error {
|
|
func (o *Oftp) New(filename string) error {
|
|
|
- // Set default values
|
|
|
|
|
- newOftp := Oftp{
|
|
|
|
|
- LocalCode: "LOCALCODE",
|
|
|
|
|
- LocalPassword: "LOCALPWD",
|
|
|
|
|
- PartnerCode: "1234567890CODE",
|
|
|
|
|
- PartnerPassword: "SUPERSECRET",
|
|
|
|
|
- OftpLevel: 4,
|
|
|
|
|
- OftpBuffer: 512,
|
|
|
|
|
- OftpDuplex: "S",
|
|
|
|
|
- OftpCompression: "N",
|
|
|
|
|
- OftpRestart: "N",
|
|
|
|
|
- OftpCredit: 7,
|
|
|
|
|
- OftpAuthentication: "N",
|
|
|
|
|
- NetworkHost: "localhost",
|
|
|
|
|
- NetworkPort: 3305,
|
|
|
|
|
- NetworkTLS: false,
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- f, err := os.Open(filename)
|
|
|
|
|
- if err != nil {
|
|
|
|
|
- return err
|
|
|
|
|
- }
|
|
|
|
|
- defer f.Close()
|
|
|
|
|
-
|
|
|
|
|
- d := json.NewDecoder(f)
|
|
|
|
|
-
|
|
|
|
|
- if err := d.Decode(&newOftp); err != nil {
|
|
|
|
|
- return err
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- *o = newOftp
|
|
|
|
|
-
|
|
|
|
|
- return nil
|
|
|
|
|
|
|
+ // Set default values
|
|
|
|
|
+ newOftp := Oftp{
|
|
|
|
|
+ LocalCode: "LOCALCODE",
|
|
|
|
|
+ LocalPassword: "LOCALPWD",
|
|
|
|
|
+ PartnerCode: "1234567890CODE",
|
|
|
|
|
+ PartnerPassword: "SUPERSECRET",
|
|
|
|
|
+ OftpLevel: 4,
|
|
|
|
|
+ OftpBuffer: 512,
|
|
|
|
|
+ OftpDuplex: "S",
|
|
|
|
|
+ OftpCompression: "N",
|
|
|
|
|
+ OftpRestart: "N",
|
|
|
|
|
+ OftpCredit: 7,
|
|
|
|
|
+ OftpAuthentication: "N",
|
|
|
|
|
+ NetworkHost: "localhost",
|
|
|
|
|
+ NetworkPort: 3305,
|
|
|
|
|
+ NetworkTimeout: 10,
|
|
|
|
|
+ NetworkTLS: false,
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ f, err := os.Open(filename)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return err
|
|
|
|
|
+ }
|
|
|
|
|
+ defer f.Close()
|
|
|
|
|
+
|
|
|
|
|
+ d := json.NewDecoder(f)
|
|
|
|
|
+
|
|
|
|
|
+ if err := d.Decode(&newOftp); err != nil {
|
|
|
|
|
+ return err
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ *o = newOftp
|
|
|
|
|
+
|
|
|
|
|
+ return nil
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
func (o Oftp) Call() error {
|
|
func (o Oftp) Call() error {
|
|
|
- // 1. Open connection
|
|
|
|
|
- // 2. Wait for SSRM
|
|
|
|
|
- // 3. Send SSID
|
|
|
|
|
- // 4. Wait for SSID
|
|
|
|
|
- // 5. Validate SSID
|
|
|
|
|
- // 6. Send ESID
|
|
|
|
|
-
|
|
|
|
|
- // 1. Open connection
|
|
|
|
|
- addr, err := net.ResolveTCPAddr("tcp", fmt.Sprintf("%s:%d", o.NetworkHost, o.NetworkPort))
|
|
|
|
|
- if err != nil {
|
|
|
|
|
- return err
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- conn, err := net.DialTCP("tcp", nil, addr)
|
|
|
|
|
- if err != nil {
|
|
|
|
|
- return err
|
|
|
|
|
- }
|
|
|
|
|
- defer conn.Close()
|
|
|
|
|
-
|
|
|
|
|
- fmt.Printf("Connected to %s\n", addr.String())
|
|
|
|
|
-
|
|
|
|
|
- // 2. Wait for SSRM
|
|
|
|
|
- headerBuf := make([]byte, 4)
|
|
|
|
|
- dataBuf := make([]byte, o.OftpBuffer)
|
|
|
|
|
-
|
|
|
|
|
- // Read STH (header)
|
|
|
|
|
- readCnt, err := conn.Read(headerBuf)
|
|
|
|
|
- if err != nil {
|
|
|
|
|
- conn.Close()
|
|
|
|
|
- return err
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- length, err := parseSTH(headerBuf[:4])
|
|
|
|
|
- if err != nil {
|
|
|
|
|
- conn.Close()
|
|
|
|
|
- return err
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- fmt.Printf("STH says STB is %d long\n", length)
|
|
|
|
|
-
|
|
|
|
|
- // Read OFTP command
|
|
|
|
|
- readCnt, err = conn.Read(dataBuf)
|
|
|
|
|
- if err != nil {
|
|
|
|
|
- conn.Close()
|
|
|
|
|
- return err
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- fmt.Printf("Read %d, should be %d\n", readCnt, length - 4)
|
|
|
|
|
-
|
|
|
|
|
- if string(dataBuf[:readCnt]) != "IODETTE FTP READY \r" && string(dataBuf[:readCnt]) != "IODETTE FTP READY \n"{
|
|
|
|
|
- conn.Close()
|
|
|
|
|
- return errors.New(fmt.Sprintf("Expected SSRM (%x), got %x", "IODETTE FTP READY \r", dataBuf[:readCnt]))
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // 3. Send SSID
|
|
|
|
|
- fmt.Println(string(o.LocalSSID()))
|
|
|
|
|
- writtenCnt, err := conn.Write(o.LocalSSID())
|
|
|
|
|
- if err != nil {
|
|
|
|
|
- conn.Close()
|
|
|
|
|
- return err
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- fmt.Printf("Write %d bytes to %s\n", writtenCnt, addr.String())
|
|
|
|
|
-
|
|
|
|
|
- // 4. Wait for SSID
|
|
|
|
|
- // Read STH (header)
|
|
|
|
|
- readCnt, err = conn.Read(headerBuf)
|
|
|
|
|
- if err != nil {
|
|
|
|
|
- conn.Close()
|
|
|
|
|
- return err
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- length, err = parseSTH(headerBuf[:4])
|
|
|
|
|
- if err != nil {
|
|
|
|
|
- conn.Close()
|
|
|
|
|
- return err
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- fmt.Printf("STH says STB is %d long\n", length)
|
|
|
|
|
-
|
|
|
|
|
- // Read OFTP command
|
|
|
|
|
- readCnt, err = conn.Read(dataBuf)
|
|
|
|
|
- if err != nil {
|
|
|
|
|
- conn.Close()
|
|
|
|
|
- return err
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- fmt.Printf("Read %d, should be %d\n", readCnt, length - 4)
|
|
|
|
|
-
|
|
|
|
|
- // 5. Validate SSID
|
|
|
|
|
- ESIDCode := o.ValidateSSID(dataBuf[:readCnt]);
|
|
|
|
|
- if ESIDCode < 0 {
|
|
|
|
|
- // If ESID is received, disconnect
|
|
|
|
|
- conn.Close()
|
|
|
|
|
- return err
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // 6. Send ESID
|
|
|
|
|
- fmt.Println(string(o.ESID(ESIDCode)))
|
|
|
|
|
- writtenCnt, err = conn.Write(o.ESID(ESIDCode))
|
|
|
|
|
- if err != nil {
|
|
|
|
|
- conn.Close()
|
|
|
|
|
- return err
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- fmt.Printf("Write %d bytes to %s\n", writtenCnt, addr.String())
|
|
|
|
|
-
|
|
|
|
|
- // Wait for partner to disconnect
|
|
|
|
|
- conn.SetReadDeadline(time.Now().Add(10 * time.Second))
|
|
|
|
|
- conn.Read(dataBuf)
|
|
|
|
|
- conn.Close()
|
|
|
|
|
- return nil
|
|
|
|
|
|
|
+ // 1. Open connection
|
|
|
|
|
+ // 2. Wait for SSRM
|
|
|
|
|
+ // 3. Send SSID
|
|
|
|
|
+ // 4. Wait for SSID
|
|
|
|
|
+ // 5. Validate SSID
|
|
|
|
|
+ // 6. Send ESID
|
|
|
|
|
+
|
|
|
|
|
+ // 1. Open connection
|
|
|
|
|
+
|
|
|
|
|
+ conn, err := net.DialTimeout("tcp", fmt.Sprintf("%s:%d", o.NetworkHost, o.NetworkPort), time.Duration(o.NetworkTimeout)*time.Second)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return err
|
|
|
|
|
+ }
|
|
|
|
|
+ defer conn.Close()
|
|
|
|
|
+
|
|
|
|
|
+ fmt.Printf("Connected to %s:%d\n", o.NetworkHost, o.NetworkPort)
|
|
|
|
|
+
|
|
|
|
|
+ // 2. Wait for SSRM
|
|
|
|
|
+ headerBuf := make([]byte, 4)
|
|
|
|
|
+ dataBuf := make([]byte, o.OftpBuffer)
|
|
|
|
|
+
|
|
|
|
|
+ // Read STH (header)
|
|
|
|
|
+ readCnt, err := conn.Read(headerBuf)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ conn.Close()
|
|
|
|
|
+ return err
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ _, err = parseSTH(headerBuf[:4])
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ conn.Close()
|
|
|
|
|
+ return err
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // Read OFTP command
|
|
|
|
|
+ readCnt, err = conn.Read(dataBuf)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ conn.Close()
|
|
|
|
|
+ return err
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if string(dataBuf[:readCnt]) != "IODETTE FTP READY \r" && string(dataBuf[:readCnt]) != "IODETTE FTP READY \n" {
|
|
|
|
|
+ conn.Close()
|
|
|
|
|
+ return errors.New(fmt.Sprintf("Expected SSRM (%x), got %x", "IODETTE FTP READY \r", dataBuf[:readCnt]))
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ fmt.Printf("Received SSRM (%d)\n", readCnt)
|
|
|
|
|
+
|
|
|
|
|
+ // 3. Send SSID
|
|
|
|
|
+ writtenCnt, err := conn.Write(o.LocalSSID())
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ conn.Close()
|
|
|
|
|
+ return err
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ fmt.Printf("Sent SSID (%d)\n", writtenCnt)
|
|
|
|
|
+
|
|
|
|
|
+ // 4. Wait for SSID
|
|
|
|
|
+ // Read STH (header)
|
|
|
|
|
+ readCnt, err = conn.Read(headerBuf)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ conn.Close()
|
|
|
|
|
+ return err
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ _, err = parseSTH(headerBuf[:4])
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ conn.Close()
|
|
|
|
|
+ return err
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // Read OFTP command
|
|
|
|
|
+ readCnt, err = conn.Read(dataBuf)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ conn.Close()
|
|
|
|
|
+ return err
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 5. Validate SSID
|
|
|
|
|
+ ESIDCode := o.ValidateSSID(dataBuf[:readCnt])
|
|
|
|
|
+ if ESIDCode < 0 {
|
|
|
|
|
+ fmt.Println(ESIDCode)
|
|
|
|
|
+ var err error
|
|
|
|
|
+ if ESIDCode > -100 {
|
|
|
|
|
+ // ESID error, disconnect
|
|
|
|
|
+ err = errors.New(fmt.Sprintf("Received negative ESID with reason code %d", ESIDCode*-1))
|
|
|
|
|
+ } else {
|
|
|
|
|
+ err = errors.New("Bad non-ESID reply to SSID")
|
|
|
|
|
+ }
|
|
|
|
|
+ conn.Close()
|
|
|
|
|
+ return err
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ fmt.Printf("Received SSID (%d)\n", readCnt)
|
|
|
|
|
+
|
|
|
|
|
+ // 6. Send ESID
|
|
|
|
|
+ writtenCnt, err = conn.Write(o.ESID(ESIDCode))
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ conn.Close()
|
|
|
|
|
+ return err
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ fmt.Printf("Sent ESID (%d) with code %d\n", writtenCnt, ESIDCode)
|
|
|
|
|
+
|
|
|
|
|
+ // Wait for partner to disconnect
|
|
|
|
|
+ conn.SetReadDeadline(time.Now().Add(10 * time.Second))
|
|
|
|
|
+ conn.Read(dataBuf)
|
|
|
|
|
+ conn.Close()
|
|
|
|
|
+
|
|
|
|
|
+ fmt.Println("Disconnected")
|
|
|
|
|
+
|
|
|
|
|
+ if ESIDCode != 0 {
|
|
|
|
|
+ return errors.New(fmt.Sprintf("Ended session with ESID reason code %d", ESIDCode))
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return nil
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
func (o Oftp) LocalSSID() []byte {
|
|
func (o Oftp) LocalSSID() []byte {
|
|
|
- dataBuf := [61]byte{}
|
|
|
|
|
- copy(dataBuf[0:1], "X")
|
|
|
|
|
- copy(dataBuf[1:2], fmt.Sprintf("%d", o.OftpLevel))
|
|
|
|
|
- copy(dataBuf[2:27], o.LocalCode)
|
|
|
|
|
- copy(dataBuf[27:35], o.LocalPassword)
|
|
|
|
|
- copy(dataBuf[35:40], fmt.Sprintf("%05d", o.OftpBuffer))
|
|
|
|
|
- copy(dataBuf[40:41], o.OftpDuplex)
|
|
|
|
|
- copy(dataBuf[41:42], o.OftpCompression)
|
|
|
|
|
- copy(dataBuf[42:43], o.OftpRestart)
|
|
|
|
|
- copy(dataBuf[43:44], "N")
|
|
|
|
|
- copy(dataBuf[44:47], fmt.Sprintf("%03d", o.OftpCredit))
|
|
|
|
|
- copy(dataBuf[47:48], o.OftpAuthentication)
|
|
|
|
|
- copy(dataBuf[60:61], "\r")
|
|
|
|
|
-
|
|
|
|
|
- sth := buildSTH(len(dataBuf))
|
|
|
|
|
-
|
|
|
|
|
- stb := []byte{}
|
|
|
|
|
-
|
|
|
|
|
- stb = append(stb, sth...)
|
|
|
|
|
- stb = append(stb, dataBuf[:]...)
|
|
|
|
|
-
|
|
|
|
|
- return stb
|
|
|
|
|
|
|
+ dataBuf := [61]byte{}
|
|
|
|
|
+ copy(dataBuf[0:1], "X")
|
|
|
|
|
+ copy(dataBuf[1:2], fmt.Sprintf("%d", o.OftpLevel))
|
|
|
|
|
+ copy(dataBuf[2:27], o.LocalCode)
|
|
|
|
|
+ copy(dataBuf[27:35], o.LocalPassword)
|
|
|
|
|
+ copy(dataBuf[35:40], fmt.Sprintf("%05d", o.OftpBuffer))
|
|
|
|
|
+ copy(dataBuf[40:41], o.OftpDuplex)
|
|
|
|
|
+ copy(dataBuf[41:42], o.OftpCompression)
|
|
|
|
|
+ copy(dataBuf[42:43], o.OftpRestart)
|
|
|
|
|
+ copy(dataBuf[43:44], "N")
|
|
|
|
|
+ copy(dataBuf[44:47], fmt.Sprintf("%03d", o.OftpCredit))
|
|
|
|
|
+ copy(dataBuf[47:48], o.OftpAuthentication)
|
|
|
|
|
+ copy(dataBuf[60:61], "\r")
|
|
|
|
|
+
|
|
|
|
|
+ sth := buildSTH(len(dataBuf))
|
|
|
|
|
+
|
|
|
|
|
+ stb := []byte{}
|
|
|
|
|
+
|
|
|
|
|
+ stb = append(stb, sth...)
|
|
|
|
|
+ stb = append(stb, dataBuf[:]...)
|
|
|
|
|
+
|
|
|
|
|
+ return stb
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
func (o Oftp) ESID(code int) []byte {
|
|
func (o Oftp) ESID(code int) []byte {
|
|
|
- dataBuf := [7]byte{}
|
|
|
|
|
- copy(dataBuf[0:1], "F")
|
|
|
|
|
- copy(dataBuf[1:3], fmt.Sprintf("%02d", code))
|
|
|
|
|
- copy(dataBuf[3:6], fmt.Sprintf("%03d", 0))
|
|
|
|
|
- copy(dataBuf[6:7], "\r")
|
|
|
|
|
|
|
+ dataBuf := [7]byte{}
|
|
|
|
|
+ copy(dataBuf[0:1], "F")
|
|
|
|
|
+ copy(dataBuf[1:3], fmt.Sprintf("%02d", code))
|
|
|
|
|
+ copy(dataBuf[3:6], fmt.Sprintf("%03d", 0))
|
|
|
|
|
+ copy(dataBuf[6:7], "\r")
|
|
|
|
|
|
|
|
- sth := buildSTH(len(dataBuf))
|
|
|
|
|
- stb := []byte{}
|
|
|
|
|
|
|
+ sth := buildSTH(len(dataBuf))
|
|
|
|
|
+ stb := []byte{}
|
|
|
|
|
|
|
|
- stb = append(stb, sth...)
|
|
|
|
|
- stb = append(stb, dataBuf[:]...)
|
|
|
|
|
|
|
+ stb = append(stb, sth...)
|
|
|
|
|
+ stb = append(stb, dataBuf[:]...)
|
|
|
|
|
|
|
|
- return stb
|
|
|
|
|
|
|
+ return stb
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
func (o Oftp) ValidateSSID(SSIDBytes []byte) int {
|
|
func (o Oftp) ValidateSSID(SSIDBytes []byte) int {
|
|
|
- // Validate cmd, code and password only
|
|
|
|
|
- fmt.Println(string(SSIDBytes))
|
|
|
|
|
- cmdByte := string(SSIDBytes[0:1])
|
|
|
|
|
- if cmdByte != "X" {
|
|
|
|
|
- return -1
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- codeBytes := string(SSIDBytes[2:27])
|
|
|
|
|
- if codeBytes != fmt.Sprintf("%-25s", o.PartnerCode) {
|
|
|
|
|
- return 3
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- passwordBytes := string(SSIDBytes[27:35])
|
|
|
|
|
- if passwordBytes != fmt.Sprintf("%-8s", o.PartnerPassword) {
|
|
|
|
|
- return 4
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- return 0
|
|
|
|
|
|
|
+ // Validate cmd, code and password only
|
|
|
|
|
+ cmdByte := string(SSIDBytes[0:1])
|
|
|
|
|
+ if cmdByte == "F" {
|
|
|
|
|
+ ESIDCodeStr := string(SSIDBytes[1:3])
|
|
|
|
|
+ ESIDCodeInt, _ := strconv.Atoi(ESIDCodeStr)
|
|
|
|
|
+ return -1 * ESIDCodeInt
|
|
|
|
|
+ }
|
|
|
|
|
+ if cmdByte != "X" {
|
|
|
|
|
+ return -100
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ codeBytes := string(SSIDBytes[2:27])
|
|
|
|
|
+ if codeBytes != fmt.Sprintf("%-25s", o.PartnerCode) {
|
|
|
|
|
+ return 3
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ passwordBytes := string(SSIDBytes[27:35])
|
|
|
|
|
+ if passwordBytes != fmt.Sprintf("%-8s", o.PartnerPassword) {
|
|
|
|
|
+ return 4
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return 0
|
|
|
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
func parseSTH(sth []byte) (int32, error) {
|
|
func parseSTH(sth []byte) (int32, error) {
|
|
|
- sth[0] = 0
|
|
|
|
|
- length := binary.BigEndian.Uint32(sth)
|
|
|
|
|
- return int32(length), nil
|
|
|
|
|
|
|
+ sth[0] = 0
|
|
|
|
|
+ length := binary.BigEndian.Uint32(sth)
|
|
|
|
|
+ return int32(length), nil
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
func buildSTH(length int) []byte {
|
|
func buildSTH(length int) []byte {
|
|
|
- sth := make([]byte, 4)
|
|
|
|
|
- sth[0] = 16
|
|
|
|
|
|
|
+ sth := make([]byte, 4)
|
|
|
|
|
+ sth[0] = 16
|
|
|
|
|
|
|
|
- lengthBytes := make([]byte, 4)
|
|
|
|
|
- binary.BigEndian.PutUint32(lengthBytes, uint32(length + 4))
|
|
|
|
|
- copy(sth[1:4], lengthBytes[1:4])
|
|
|
|
|
|
|
+ lengthBytes := make([]byte, 4)
|
|
|
|
|
+ binary.BigEndian.PutUint32(lengthBytes, uint32(length+4))
|
|
|
|
|
+ copy(sth[1:4], lengthBytes[1:4])
|
|
|
|
|
|
|
|
- return sth
|
|
|
|
|
|
|
+ return sth
|
|
|
|
|
|
|
|
}
|
|
}
|