oftp.go 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253
  1. package main
  2. import (
  3. "encoding/binary"
  4. "encoding/json"
  5. "errors"
  6. "fmt"
  7. "net"
  8. "os"
  9. "strconv"
  10. "time"
  11. )
  12. func (o *Oftp) New(filename string) error {
  13. // Set default values
  14. newOftp := Oftp{
  15. LocalCode: "LOCALCODE",
  16. LocalPassword: "LOCALPWD",
  17. PartnerCode: "1234567890CODE",
  18. PartnerPassword: "SUPERSECRET",
  19. OftpLevel: 4,
  20. OftpBuffer: 512,
  21. OftpDuplex: "S",
  22. OftpCompression: "N",
  23. OftpRestart: "N",
  24. OftpCredit: 7,
  25. OftpAuthentication: "N",
  26. NetworkHost: "localhost",
  27. NetworkPort: 3305,
  28. NetworkTimeout: 10,
  29. NetworkTLS: false,
  30. }
  31. f, err := os.Open(filename)
  32. if err != nil {
  33. return err
  34. }
  35. defer f.Close()
  36. d := json.NewDecoder(f)
  37. if err := d.Decode(&newOftp); err != nil {
  38. return err
  39. }
  40. *o = newOftp
  41. return nil
  42. }
  43. func (o Oftp) Call() error {
  44. // 1. Open connection
  45. // 2. Wait for SSRM
  46. // 3. Send SSID
  47. // 4. Wait for SSID
  48. // 5. Validate SSID
  49. // 6. Send ESID
  50. // 1. Open connection
  51. conn, err := net.DialTimeout("tcp", fmt.Sprintf("%s:%d", o.NetworkHost, o.NetworkPort), time.Duration(o.NetworkTimeout)*time.Second)
  52. if err != nil {
  53. return err
  54. }
  55. defer conn.Close()
  56. fmt.Printf("Connected to %s:%d\n", o.NetworkHost, o.NetworkPort)
  57. // 2. Wait for SSRM
  58. headerBuf := make([]byte, 4)
  59. dataBuf := make([]byte, o.OftpBuffer)
  60. // Read STH (header)
  61. readCnt, err := conn.Read(headerBuf)
  62. if err != nil {
  63. conn.Close()
  64. return err
  65. }
  66. _, err = parseSTH(headerBuf[:4])
  67. if err != nil {
  68. conn.Close()
  69. return err
  70. }
  71. // Read OFTP command
  72. readCnt, err = conn.Read(dataBuf)
  73. if err != nil {
  74. conn.Close()
  75. return err
  76. }
  77. if string(dataBuf[:readCnt]) != "IODETTE FTP READY \r" && string(dataBuf[:readCnt]) != "IODETTE FTP READY \n" {
  78. conn.Close()
  79. return errors.New(fmt.Sprintf("Expected SSRM (%x), got %x", "IODETTE FTP READY \r", dataBuf[:readCnt]))
  80. }
  81. fmt.Printf("Received SSRM (%d)\n", readCnt)
  82. // 3. Send SSID
  83. writtenCnt, err := conn.Write(o.LocalSSID())
  84. if err != nil {
  85. conn.Close()
  86. return err
  87. }
  88. fmt.Printf("Sent SSID (%d)\n", writtenCnt)
  89. // 4. Wait for SSID
  90. // Read STH (header)
  91. readCnt, err = conn.Read(headerBuf)
  92. if err != nil {
  93. conn.Close()
  94. return err
  95. }
  96. _, err = parseSTH(headerBuf[:4])
  97. if err != nil {
  98. conn.Close()
  99. return err
  100. }
  101. // Read OFTP command
  102. readCnt, err = conn.Read(dataBuf)
  103. if err != nil {
  104. conn.Close()
  105. return err
  106. }
  107. // 5. Validate SSID
  108. ESIDCode := o.ValidateSSID(dataBuf[:readCnt])
  109. if ESIDCode < 0 {
  110. fmt.Println(ESIDCode)
  111. var err error
  112. if ESIDCode > -100 {
  113. // ESID error, disconnect
  114. err = errors.New(fmt.Sprintf("Received negative ESID with reason code %d", ESIDCode*-1))
  115. } else {
  116. err = errors.New("Bad non-ESID reply to SSID")
  117. }
  118. conn.Close()
  119. return err
  120. }
  121. fmt.Printf("Received SSID (%d)\n", readCnt)
  122. // 6. Send ESID
  123. writtenCnt, err = conn.Write(o.ESID(ESIDCode))
  124. if err != nil {
  125. conn.Close()
  126. return err
  127. }
  128. fmt.Printf("Sent ESID (%d) with code %d\n", writtenCnt, ESIDCode)
  129. // Wait for partner to disconnect
  130. conn.SetReadDeadline(time.Now().Add(10 * time.Second))
  131. conn.Read(dataBuf)
  132. conn.Close()
  133. fmt.Println("Disconnected")
  134. if ESIDCode != 0 {
  135. return errors.New(fmt.Sprintf("Ended session with ESID reason code %d", ESIDCode))
  136. }
  137. return nil
  138. }
  139. func (o Oftp) LocalSSID() []byte {
  140. dataBuf := [61]byte{}
  141. copy(dataBuf[0:1], "X")
  142. copy(dataBuf[1:2], fmt.Sprintf("%d", o.OftpLevel))
  143. copy(dataBuf[2:27], o.LocalCode)
  144. copy(dataBuf[27:35], o.LocalPassword)
  145. copy(dataBuf[35:40], fmt.Sprintf("%05d", o.OftpBuffer))
  146. copy(dataBuf[40:41], o.OftpDuplex)
  147. copy(dataBuf[41:42], o.OftpCompression)
  148. copy(dataBuf[42:43], o.OftpRestart)
  149. copy(dataBuf[43:44], "N")
  150. copy(dataBuf[44:47], fmt.Sprintf("%03d", o.OftpCredit))
  151. copy(dataBuf[47:48], o.OftpAuthentication)
  152. copy(dataBuf[60:61], "\r")
  153. sth := buildSTH(len(dataBuf))
  154. stb := []byte{}
  155. stb = append(stb, sth...)
  156. stb = append(stb, dataBuf[:]...)
  157. return stb
  158. }
  159. func (o Oftp) ESID(code int) []byte {
  160. dataBuf := [7]byte{}
  161. copy(dataBuf[0:1], "F")
  162. copy(dataBuf[1:3], fmt.Sprintf("%02d", code))
  163. copy(dataBuf[3:6], fmt.Sprintf("%03d", 0))
  164. copy(dataBuf[6:7], "\r")
  165. sth := buildSTH(len(dataBuf))
  166. stb := []byte{}
  167. stb = append(stb, sth...)
  168. stb = append(stb, dataBuf[:]...)
  169. return stb
  170. }
  171. func (o Oftp) ValidateSSID(SSIDBytes []byte) int {
  172. // Validate cmd, code and password only
  173. cmdByte := string(SSIDBytes[0:1])
  174. if cmdByte == "F" {
  175. ESIDCodeStr := string(SSIDBytes[1:3])
  176. ESIDCodeInt, _ := strconv.Atoi(ESIDCodeStr)
  177. return -1 * ESIDCodeInt
  178. }
  179. if cmdByte != "X" {
  180. return -100
  181. }
  182. codeBytes := string(SSIDBytes[2:27])
  183. if codeBytes != fmt.Sprintf("%-25s", o.PartnerCode) {
  184. return 3
  185. }
  186. passwordBytes := string(SSIDBytes[27:35])
  187. if passwordBytes != fmt.Sprintf("%-8s", o.PartnerPassword) {
  188. return 4
  189. }
  190. return 0
  191. }
  192. func parseSTH(sth []byte) (int32, error) {
  193. sth[0] = 0
  194. length := binary.BigEndian.Uint32(sth)
  195. return int32(length), nil
  196. }
  197. func buildSTH(length int) []byte {
  198. sth := make([]byte, 4)
  199. sth[0] = 16
  200. lengthBytes := make([]byte, 4)
  201. binary.BigEndian.PutUint32(lengthBytes, uint32(length+4))
  202. copy(sth[1:4], lengthBytes[1:4])
  203. return sth
  204. }