kappanhang/controlstream.go

349 lines
13 KiB
Go
Raw Normal View History

2020-10-17 23:33:09 +02:00
package main
import (
"bytes"
"encoding/binary"
"errors"
"fmt"
2020-10-17 23:33:09 +02:00
"time"
)
2020-10-26 10:33:24 +01:00
const controlStreamPort = 50001
const serialStreamPort = 50002
const audioStreamPort = 50003
2020-10-26 19:46:08 +01:00
const statusLogInterval = 3 * time.Second
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
authInnerSendSeq uint16
authID [6]byte
gotAuthID bool
2020-10-23 23:42:40 +02:00
serialAndAudioStreamOpened bool
deinitializing bool
2020-10-23 16:20:09 +02:00
secondAuthTimer *time.Timer
requestSerialAndAudioTimeout *time.Timer
2020-10-26 11:32:21 +01:00
reauthTimeoutTimer *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}
2020-10-25 20:18:24 +01:00
p := []byte{0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
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}
2020-10-25 20:18:24 +01:00
if err := s.common.pkt0.sendTrackedPacket(&s.common, p); err != nil {
return err
}
2020-10-18 11:01:53 +02:00
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
2020-10-25 20:18:24 +01:00
p := []byte{0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
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}
2020-10-25 20:18:24 +01:00
if err := s.common.pkt0.sendTrackedPacket(&s.common, p); err != nil {
return err
}
2020-10-18 11:01:53 +02:00
s.authInnerSendSeq++
return nil
2020-10-17 23:33:09 +02:00
}
func (s *controlStream) sendRequestSerialAndAudio() error {
2020-10-26 09:01:39 +01:00
log.Debug("requesting serial and audio stream")
2020-10-26 10:33:24 +01:00
2020-10-25 20:18:24 +01:00
p := []byte{0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
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,
2020-10-26 10:33:24 +01:00
0x01, 0x01, 0x04, 0x04, 0x00, 0x00, byte(audioSampleRate >> 8), byte(audioSampleRate & 0xff),
0x00, 0x00, byte(audioSampleRate >> 8), byte(audioSampleRate & 0xff),
0x00, 0x00, byte(serialStreamPort >> 8), byte(serialStreamPort & 0xff),
0x00, 0x00, byte(audioStreamPort >> 8), byte(audioStreamPort & 0xff), 0x00, 0x00, 0x00, 0xa0,
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
2020-10-25 20:18:24 +01:00
if err := s.common.pkt0.sendTrackedPacket(&s.common, p); err != nil {
return err
}
2020-10-18 11:01:53 +02:00
s.authInnerSendSeq++
return nil
2020-10-17 23:33:09 +02:00
}
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
2020-10-26 11:32:21 +01:00
s.reauthTimeoutTimer.Stop()
2020-10-26 09:01:39 +01:00
log.Debug("auth ok")
2020-10-23 16:20:09 +02:00
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:
2020-10-25 10:55:05 +01:00
if bytes.Equal(r[:6], []byte{0x50, 0x00, 0x00, 0x00, 0x00, 0x00}) {
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-25 10:55:05 +01:00
if bytes.Equal(r[48:51], []byte{0xff, 0xff, 0xff}) {
return errors.New("auth failed")
}
if bytes.Equal(r[48:51], []byte{0x00, 0x00, 0x00}) && r[64] == 0x01 {
return errors.New("got radio disconnected")
}
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,
2020-10-26 10:33:24 +01:00
// 0x49, 0x43, 0x2d, 0x37, 0x30, 0x35, 0x00, 0x00, // IC-705 in plain text
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,
// 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
s.secondAuthTimer.Stop()
s.requestSerialAndAudioTimeout.Stop()
2020-10-27 09:25:36 +01:00
devName := parseNullTerminatedString(r[64:])
2020-10-23 22:52:14 +02:00
log.Print("got serial and audio request success, device name: ", devName)
// Stuff can change in the meantime because of a previous login...
s.common.remoteSID = binary.BigEndian.Uint32(r[8:12])
s.common.localSID = binary.BigEndian.Uint32(r[12:16])
2020-10-23 22:52:14 +02:00
copy(s.authID[:], r[26:32])
s.gotAuthID = true
2020-10-26 09:13:30 +01:00
if err := s.serial.init(devName); err != nil {
return errors.New("serial/" + err.Error())
}
2020-10-26 09:13:30 +01:00
if err := s.audio.init(devName); err != nil {
return errors.New("audio/" + err.Error())
}
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-26 14:59:49 +01:00
bandwidth.reset()
2020-10-23 16:20:09 +02:00
2020-10-26 09:28:47 +01:00
s.secondAuthTimer = time.NewTimer(200 * time.Millisecond)
2020-10-26 11:32:21 +01:00
s.reauthTimeoutTimer = time.NewTimer(0)
<-s.reauthTimeoutTimer.C
2020-10-26 11:33:42 +01:00
reauthTicker := time.NewTicker(25 * time.Second)
2020-10-26 19:46:08 +01:00
statusLogTicker := time.NewTicker(statusLogInterval)
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-26 09:01:39 +01:00
log.Debug("second auth sent...")
2020-10-23 16:20:09 +02:00
case r := <-s.common.readChan:
if !s.deinitializing {
if err := s.handleRead(r); err != nil {
reportError(err)
}
}
case <-reauthTicker.C:
2020-10-26 09:01:39 +01:00
log.Debug("sending auth")
2020-10-26 11:32:21 +01:00
s.reauthTimeoutTimer.Reset(3 * time.Second)
2020-10-23 23:18:37 +02:00
if err := s.sendPktAuth(0x05); err != nil {
reportError(err)
}
2020-10-26 11:32:21 +01:00
case <-s.reauthTimeoutTimer.C:
log.Error("auth timeout, audio/serial stream may stop")
case <-statusLogTicker.C:
if s.serialAndAudioStreamOpened {
up, down, loss := bandwidth.get()
2020-10-26 14:59:49 +01:00
log.Print("running for ", time.Since(startTime).Round(time.Second),
" rtt ", s.common.pkt7.latency.Milliseconds(), "ms up ",
bandwidth.formatByteCount(up), "/s down ",
bandwidth.formatByteCount(down), "/s loss ", fmt.Sprintf("%.2f", loss), "%")
}
case <-s.deinitNeededChan:
s.deinitFinishedChan <- true
return
}
}
}
2020-10-26 09:13:30 +01:00
func (s *controlStream) init() error {
log.Debug("init")
2020-10-26 10:33:24 +01:00
if err := s.common.init("control", controlStreamPort); err != nil {
return err
}
2020-10-18 10:53:16 +02:00
2020-10-26 08:56:30 +01:00
if err := s.common.start(); err != nil {
return err
}
2020-10-18 10:53:16 +02:00
2020-10-26 08:56:30 +01:00
s.common.pkt7.startPeriodicSend(&s.common, 2, false)
2020-10-25 20:18:24 +01:00
s.common.pkt0.startPeriodicSend(&s.common)
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])
s.gotAuthID = true
2020-10-23 23:18:37 +02:00
if err := s.sendPktAuth(0x02); err != nil {
2020-10-26 09:26:21 +01:00
return err
2020-10-23 16:20:09 +02:00
}
2020-10-26 09:01:39 +01:00
log.Debug("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) 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
}
if s.gotAuthID && s.common.gotRemoteSID && s.common.conn != nil {
2020-10-26 09:01:39 +01:00
log.Debug("sending deauth")
_ = s.sendPktAuth(0x01)
}
s.common.deinit()
2020-10-23 18:36:47 +02:00
s.serial.deinit()
s.audio.deinit()
2020-10-17 23:33:09 +02:00
}