kappanhang/controlstream.go

379 lines
14 KiB
Go
Raw Normal View History

2020-10-17 23:33:09 +02:00
package main
import (
"bytes"
"errors"
"strings"
2020-10-17 23:33:09 +02:00
"time"
"github.com/nonoo/kappanhang/log"
)
2020-10-18 10:33:47 +02:00
type controlStream struct {
common streamCommon
serial serialStream
audio audioStream
deinitNeededChan chan bool
deinitFinishedChan chan bool
2020-10-18 13:02:41 +02:00
authSendSeq uint16
authInnerSendSeq uint16
authID [6]byte
2020-10-23 18:36:47 +02:00
serialAndAudioStreamOpenRequested bool
serialAndAudioStreamOpened bool
deinitializing bool
2020-10-23 16:20:09 +02:00
secondAuthTimer *time.Timer
requestSerialAndAudioTimeout *time.Timer
2020-10-17 23:33:09 +02:00
}
2020-10-23 16:20:09 +02:00
func (s *controlStream) sendPktLogin() error {
2020-10-23 22:52:14 +02:00
// The reply to the auth packet will contain a 6 bytes long auth ID with the first 2 bytes set to our ID.
authStartID := []byte{0x63, 0x00}
p := []byte{0x80, 0x00, 0x00, 0x00, 0x00, 0x00, byte(s.authSendSeq), byte(s.authSendSeq >> 8),
2020-10-18 11:01:53 +02:00
byte(s.common.localSID >> 24), byte(s.common.localSID >> 16), byte(s.common.localSID >> 8), byte(s.common.localSID),
byte(s.common.remoteSID >> 24), byte(s.common.remoteSID >> 16), byte(s.common.remoteSID >> 8), byte(s.common.remoteSID),
0x00, 0x00, 0x00, 0x70, 0x01, 0x00, 0x00, byte(s.authInnerSendSeq),
2020-10-23 22:52:14 +02:00
byte(s.authInnerSendSeq >> 8), 0x00, authStartID[0], authStartID[1], 0x00, 0x00, 0x00, 0x00,
2020-10-17 23:33:09 +02:00
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x2b, 0x3f, 0x55, 0x5c, 0x00, 0x00, 0x00, 0x00, // username: beer
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x2b, 0x3f, 0x55, 0x5c, 0x3f, 0x25, 0x77, 0x58, // pass: beerbeer
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x69, 0x63, 0x6f, 0x6d, 0x2d, 0x70, 0x63, 0x00, // icom-pc in plain text
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
if err := s.common.send(p); err != nil {
return err
}
if err := s.common.send(p); err != nil {
return err
}
2020-10-18 11:01:53 +02:00
s.authSendSeq++
s.authInnerSendSeq++
return nil
2020-10-17 23:33:09 +02:00
}
2020-10-23 23:18:37 +02:00
func (s *controlStream) sendPktAuth(magic byte) error {
2020-10-17 23:33:09 +02:00
// Example request from PC: 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00,
// 0xbb, 0x41, 0x3f, 0x2b, 0xe6, 0xb2, 0x7b, 0x7b,
// 0x00, 0x00, 0x00, 0x30, 0x01, 0x05, 0x00, 0x02,
// 0x00, 0x00, 0x5d, 0x37, 0x12, 0x82, 0x3b, 0xde,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
// Example reply from radio: 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00,
// 0xe6, 0xb2, 0x7b, 0x7b, 0xbb, 0x41, 0x3f, 0x2b,
// 0x00, 0x00, 0x00, 0x30, 0x02, 0x05, 0x00, 0x02,
// 0x00, 0x00, 0x5d, 0x37, 0x12, 0x82, 0x3b, 0xde,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
p := []byte{0x40, 0x00, 0x00, 0x00, 0x00, 0x00, byte(s.authSendSeq), byte(s.authSendSeq >> 8),
2020-10-18 11:01:53 +02:00
byte(s.common.localSID >> 24), byte(s.common.localSID >> 16), byte(s.common.localSID >> 8), byte(s.common.localSID),
byte(s.common.remoteSID >> 24), byte(s.common.remoteSID >> 16), byte(s.common.remoteSID >> 8), byte(s.common.remoteSID),
0x00, 0x00, 0x00, 0x30, 0x01, magic, 0x00, byte(s.authInnerSendSeq),
byte(s.authInnerSendSeq >> 8), 0x00, s.authID[0], s.authID[1], s.authID[2], s.authID[3], s.authID[4], s.authID[5],
2020-10-17 23:33:09 +02:00
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
if err := s.common.send(p); err != nil {
return err
}
if err := s.common.send(p); err != nil {
return err
}
2020-10-18 11:01:53 +02:00
s.authSendSeq++
s.authInnerSendSeq++
return nil
2020-10-17 23:33:09 +02:00
}
func (s *controlStream) sendPkt0() error {
2020-10-21 15:44:16 +02:00
p := []byte{0x10, 0x00, 0x00, 0x00, 0x00, 0x00, byte(s.authSendSeq), byte(s.authSendSeq >> 8),
byte(s.common.localSID >> 24), byte(s.common.localSID >> 16), byte(s.common.localSID >> 8), byte(s.common.localSID),
byte(s.common.remoteSID >> 24), byte(s.common.remoteSID >> 16), byte(s.common.remoteSID >> 8), byte(s.common.remoteSID)}
if err := s.common.send(p); err != nil {
return err
}
2020-10-21 15:44:16 +02:00
s.authSendSeq++
return nil
2020-10-21 15:44:16 +02:00
}
func (s *controlStream) sendRequestSerialAndAudio() error {
2020-10-17 23:33:09 +02:00
log.Print("requesting serial and audio stream")
p := []byte{0x90, 0x00, 0x00, 0x00, 0x00, 0x00, byte(s.authSendSeq), byte(s.authSendSeq >> 8),
2020-10-18 11:01:53 +02:00
byte(s.common.localSID >> 24), byte(s.common.localSID >> 16), byte(s.common.localSID >> 8), byte(s.common.localSID),
byte(s.common.remoteSID >> 24), byte(s.common.remoteSID >> 16), byte(s.common.remoteSID >> 8), byte(s.common.remoteSID),
0x00, 0x00, 0x00, 0x80, 0x01, 0x03, 0x00, byte(s.authInnerSendSeq),
byte(s.authInnerSendSeq >> 8), 0x00, s.authID[0], s.authID[1], s.authID[2], s.authID[3], s.authID[4], s.authID[5],
2020-10-17 23:33:09 +02:00
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,
0x80, 0x00, 0x00, 0x90, 0xc7, 0x0e, 0x86, 0x01, // The last 5 bytes from this row can be acquired from a reply starting with 0xa8 or 0x90
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x49, 0x43, 0x2d, 0x37, 0x30, 0x35, 0x00, 0x00, // IC-705 in plain text
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x2b, 0x3f, 0x55, 0x5c, 0x00, 0x00, 0x00, 0x00, // username: beer
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x01, 0x01, 0x04, 0x04, 0x00, 0x00, 0xbb, 0x80,
0x00, 0x00, 0xbb, 0x80, 0x00, 0x00, 0xc3, 0x52,
0x00, 0x00, 0xc3, 0x53, 0x00, 0x00, 0x00, 0xa0,
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
if err := s.common.send(p); err != nil {
return err
}
if err := s.common.send(p); err != nil {
return err
}
2020-10-18 11:01:53 +02:00
s.authSendSeq++
s.authInnerSendSeq++
2020-10-23 18:36:47 +02:00
s.serialAndAudioStreamOpenRequested = true
return nil
2020-10-17 23:33:09 +02:00
}
func (s *controlStream) parseNullTerminatedString(d []byte) (res string) {
nullIndex := strings.Index(string(d), "\x00")
if nullIndex > 0 {
res = string(d[:nullIndex])
}
return
}
func (s *controlStream) handleRead(r []byte) error {
2020-10-18 10:53:16 +02:00
switch len(r) {
2020-10-23 16:20:09 +02:00
case 64:
if bytes.Equal(r[:6], []byte{0x40, 0x00, 0x00, 0x00, 0x00, 0x00}) {
// Example answer from radio: 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,
// 0x33, 0x60, 0xd4, 0xe5, 0xf4, 0x67, 0x86, 0xe1,
// 0x00, 0x00, 0x00, 0x30, 0x02, 0x05, 0x00, 0x02,
// 0x00, 0x00, 0x35, 0x34, 0x76, 0x11, 0xb9, 0xd0,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
log.Print("auth ok")
if r[21] == 0x05 && !s.serialAndAudioStreamOpened { // Answer for our second auth?
s.secondAuthTimer.Stop()
2020-10-23 18:36:47 +02:00
2020-10-23 16:20:09 +02:00
if err := s.sendRequestSerialAndAudio(); err != nil {
reportError(err)
}
}
2020-10-17 23:33:09 +02:00
}
2020-10-18 10:53:16 +02:00
case 80:
if bytes.Equal(r[:6], []byte{0x50, 0x00, 0x00, 0x00, 0x00, 0x00}) && bytes.Equal(r[48:51], []byte{0xff, 0xff, 0xff}) {
2020-10-17 23:33:09 +02:00
// Example answer from radio: 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00,
// 0x86, 0x1f, 0x2f, 0xcc, 0x03, 0x03, 0x89, 0x29,
// 0x00, 0x00, 0x00, 0x40, 0x02, 0x03, 0x00, 0x52,
// 0x00, 0x00, 0xf8, 0xad, 0x06, 0x8d, 0xda, 0x7b,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,
// 0x80, 0x00, 0x00, 0x90, 0xc7, 0x0e, 0x86, 0x01,
// 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
2020-10-23 16:20:09 +02:00
return errors.New("auth failed")
2020-10-17 23:33:09 +02:00
}
2020-10-18 10:53:16 +02:00
case 144:
if !s.serialAndAudioStreamOpened && bytes.Equal(r[:6], []byte{0x90, 0x00, 0x00, 0x00, 0x00, 0x00}) && r[96] == 1 {
2020-10-17 23:33:09 +02:00
// Example answer:
// 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0x00,
// 0xc6, 0x5f, 0x6f, 0x0c, 0x5f, 0x8b, 0x1e, 0x89,
// 0x00, 0x00, 0x00, 0x80, 0x03, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x31, 0x30, 0x31, 0x47, 0x39, 0x07,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,
// 0x80, 0x00, 0x00, 0x90, 0xc7, 0x0e, 0x86, 0x01,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x49, 0x43, 0x2d, 0x37, 0x30, 0x35, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x01, 0x00, 0x00, 0x00, 0x69, 0x63, 0x6f, 0x6d,
// 0x2d, 0x70, 0x63, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0xc0, 0xa8, 0x03, 0x03,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
2020-10-23 18:36:47 +02:00
2020-10-23 22:52:14 +02:00
devName := s.parseNullTerminatedString(r[64:])
log.Print("got serial and audio request success, device name: ", devName)
2020-10-23 18:36:47 +02:00
if !s.serialAndAudioStreamOpenRequested {
2020-10-23 22:52:14 +02:00
return errors.New("not requested serial and audio streams yet")
2020-10-23 18:36:47 +02:00
}
2020-10-23 22:52:14 +02:00
// The auth ID can change in the meantime because of a previous login...
copy(s.authID[:], r[26:32])
s.secondAuthTimer.Stop()
if s.requestSerialAndAudioTimeout != nil {
s.requestSerialAndAudioTimeout.Stop()
s.requestSerialAndAudioTimeout = nil
}
if err := s.serial.start(devName); err != nil {
return err
}
if err := s.audio.start(devName); err != nil {
return err
}
s.serialAndAudioStreamOpened = true
2020-10-17 23:33:09 +02:00
}
2020-10-18 10:53:16 +02:00
}
return nil
2020-10-18 10:53:16 +02:00
}
2020-10-17 23:33:09 +02:00
func (s *controlStream) loop() {
startTime := time.Now()
2020-10-23 16:20:09 +02:00
s.secondAuthTimer = time.NewTimer(time.Second)
pkt0SendTicker := time.NewTicker(100 * time.Millisecond)
reauthTicker := time.NewTicker(60 * time.Second)
statusLogTicker := time.NewTicker(3 * time.Second)
for {
select {
2020-10-23 16:20:09 +02:00
case <-s.secondAuthTimer.C:
2020-10-23 23:18:37 +02:00
if err := s.sendPktAuth(0x05); err != nil {
reportError(err)
}
2020-10-23 16:20:09 +02:00
log.Print("second auth sent...")
case r := <-s.common.readChan:
if !s.deinitializing {
if err := s.handleRead(r); err != nil {
reportError(err)
}
}
case <-pkt0SendTicker.C:
if err := s.sendPkt0(); err != nil {
reportError(err)
}
case <-reauthTicker.C:
2020-10-23 16:20:09 +02:00
log.Print("sending auth")
2020-10-23 23:18:37 +02:00
if err := s.sendPktAuth(0x05); err != nil {
reportError(err)
}
case <-statusLogTicker.C:
if s.serialAndAudioStreamOpened {
log.Print("running for ", time.Since(startTime), " roundtrip latency ", s.common.pkt7.latency)
}
case <-s.deinitNeededChan:
2020-10-23 23:18:37 +02:00
if err := s.sendPktAuth(0x01); err != nil {
reportError(err)
}
s.deinitFinishedChan <- true
return
}
}
}
func (s *controlStream) start() error {
if err := s.common.init("control", 50001); err != nil {
return err
}
2020-10-18 10:53:16 +02:00
2020-10-23 22:52:14 +02:00
s.common.pkt7.startPeriodicSend(&s.common, 2, false)
if err := s.common.sendPkt3(); err != nil {
return err
}
if err := s.common.waitForPkt4Answer(); err != nil {
return err
}
if err := s.common.sendPkt6(); err != nil {
return err
}
if err := s.common.waitForPkt6Answer(); err != nil {
return err
}
2020-10-18 10:53:16 +02:00
s.authSendSeq = 1
2020-10-23 16:20:09 +02:00
if err := s.sendPktLogin(); err != nil {
return err
}
2020-10-18 10:53:16 +02:00
2020-10-23 16:20:09 +02:00
log.Debug("expecting login answer")
2020-10-18 10:53:16 +02:00
// Example success auth packet: 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
// 0xe6, 0xb2, 0x7b, 0x7b, 0xbb, 0x41, 0x3f, 0x2b,
// 0x00, 0x00, 0x00, 0x50, 0x02, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x5d, 0x37, 0x12, 0x82, 0x3b, 0xde,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x46, 0x54, 0x54, 0x48, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
r, err := s.common.expect(96, []byte{0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00})
if err != nil {
return err
}
2020-10-18 10:53:16 +02:00
if bytes.Equal(r[48:52], []byte{0xff, 0xff, 0xff, 0xfe}) {
return errors.New("invalid user/password")
2020-10-18 10:53:16 +02:00
}
2020-10-18 11:01:53 +02:00
copy(s.authID[:], r[26:32])
2020-10-23 23:18:37 +02:00
if err := s.sendPktAuth(0x02); err != nil {
2020-10-23 16:20:09 +02:00
reportError(err)
}
log.Print("login ok, first auth sent...")
2020-10-18 10:53:16 +02:00
2020-10-23 18:36:47 +02:00
s.requestSerialAndAudioTimeout = time.AfterFunc(5*time.Second, func() {
reportError(errors.New("login/serial/audio request timeout"))
})
s.deinitNeededChan = make(chan bool)
s.deinitFinishedChan = make(chan bool)
go s.loop()
return nil
}
2020-10-18 10:53:16 +02:00
func (s *controlStream) init() error {
log.Print("init")
if err := s.serial.init(); err != nil {
return err
}
if err := s.audio.init(); err != nil {
return err
}
return nil
}
func (s *controlStream) deinit() {
2020-10-23 16:20:09 +02:00
s.deinitializing = true
s.serialAndAudioStreamOpened = false
if s.deinitNeededChan != nil {
s.deinitNeededChan <- true
<-s.deinitFinishedChan
}
if s.requestSerialAndAudioTimeout != nil {
s.requestSerialAndAudioTimeout.Stop()
s.requestSerialAndAudioTimeout = nil
2020-10-17 23:33:09 +02:00
}
s.common.deinit()
2020-10-23 18:36:47 +02:00
s.audio.deinit()
s.serial.deinit()
2020-10-17 23:33:09 +02:00
}