From 6ba02ae285bf454a955e95302cba99e35c916536 Mon Sep 17 00:00:00 2001 From: Nonoo Date: Fri, 16 Oct 2020 17:13:46 +0200 Subject: [PATCH] Init --- .gitignore | 2 + .vscode/launch.json | 16 +++++ .vscode/settings.json | 3 + .vscode/tasks.json | 17 +++++ args.go | 26 ++++++++ build/build.sh | 14 ++++ kappanhang.code-workspace | 7 ++ log/log.go | 73 ++++++++++++++++++++ main.go | 137 ++++++++++++++++++++++++++++++++++++++ 9 files changed, 295 insertions(+) create mode 100644 .gitignore create mode 100644 .vscode/launch.json create mode 100644 .vscode/settings.json create mode 100644 .vscode/tasks.json create mode 100644 args.go create mode 100755 build/build.sh create mode 100644 kappanhang.code-workspace create mode 100644 log/log.go create mode 100644 main.go diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9c7a333 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +kappanhang +__debug_bin diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3a30a08 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,16 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Launch", + "type": "go", + "request": "launch", + "mode": "auto", + "program": "${workspaceFolder}", + "args": [] + } + ] +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..9012f14 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "go.lintTool": "golangci-lint" +} \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000..539b2c6 --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,17 @@ +{ + // See https://go.microsoft.com/fwlink/?LinkId=733558 + // for the documentation about the tasks.json format + "version": "2.0.0", + "tasks": [ + { + "label": "debug", + "type": "shell", + "command": "build/build.sh", + "problemMatcher": [], + "group": { + "kind": "build", + "isDefault": true + } + } + ] +} \ No newline at end of file diff --git a/args.go b/args.go new file mode 100644 index 0000000..528fc97 --- /dev/null +++ b/args.go @@ -0,0 +1,26 @@ +package main + +import ( + "os" + + "github.com/pborman/getopt" +) + +var connectAddress string +var connectPort uint16 + +func parseArgs() { + h := getopt.BoolLong("help", 'h', "display help") + a := getopt.StringLong("address", 'a', "IC-705", "Connect to address") + p := getopt.Uint16Long("port", 'p', 50001, "Connect to UDP port") + + getopt.Parse() + + if *h || *a == "" { + getopt.Usage() + os.Exit(1) + } + + connectAddress = *a + connectPort = *p +} diff --git a/build/build.sh b/build/build.sh new file mode 100755 index 0000000..20ac3a3 --- /dev/null +++ b/build/build.sh @@ -0,0 +1,14 @@ +#!/bin/sh +self=`readlink "$0"` +if [ -z "$self" ]; then + self=$0 +fi +scriptname=`basename "$self"` +scriptdir=${self%$scriptname} + +cd $scriptdir +scriptdir=`pwd` + +cd .. + +go build diff --git a/kappanhang.code-workspace b/kappanhang.code-workspace new file mode 100644 index 0000000..362d7c2 --- /dev/null +++ b/kappanhang.code-workspace @@ -0,0 +1,7 @@ +{ + "folders": [ + { + "path": "." + } + ] +} \ No newline at end of file diff --git a/log/log.go b/log/log.go new file mode 100644 index 0000000..3caada8 --- /dev/null +++ b/log/log.go @@ -0,0 +1,73 @@ +package log + +import ( + "fmt" + "os" + "path/filepath" + "runtime" + + "go.uber.org/zap" + "go.uber.org/zap/zapcore" +) + +var logger *zap.SugaredLogger +var filenameTrimChars int + +func getCallerFileName(withLine bool) string { + _, filename, line, _ := runtime.Caller(2) + extension := filepath.Ext(filename) + if withLine { + return fmt.Sprint(filename[filenameTrimChars:len(filename)-len(extension)], "@", line) + } else { + return filename[filenameTrimChars : len(filename)-len(extension)] + } +} + +func Printf(a string, b ...interface{}) { + logger.Infof(getCallerFileName(false)+": "+a, b...) +} + +func Print(a ...interface{}) { + logger.Info(append([]interface{}{getCallerFileName(false) + ": "}, a...)...) +} + +func Debugf(a string, b ...interface{}) { + logger.Debugf(getCallerFileName(true)+": "+a, b...) +} + +func Debug(a ...interface{}) { + logger.Debug(append([]interface{}{getCallerFileName(true) + ": "}, a...)...) +} + +func Errorf(a string, b ...interface{}) { + logger.Errorf(getCallerFileName(true)+": "+a, b...) +} + +func Error(a ...interface{}) { + logger.Error(append([]interface{}{getCallerFileName(true) + ": "}, a...)...) +} + +func Fatalf(a string, b ...interface{}) { + logger.Fatalf(getCallerFileName(true)+": "+a, b...) +} + +func Fatal(a ...interface{}) { + logger.Fatal(append([]interface{}{getCallerFileName(true) + ": "}, a...)...) +} + +func Init() { + // Example: https://stackoverflow.com/questions/50933936/zap-logger-does-not-print-on-console-rather-print-in-the-log-file/50936341 + pe := zap.NewProductionEncoderConfig() + pe.EncodeTime = zapcore.ISO8601TimeEncoder + // pe.LevelKey = "" + consoleEncoder := zapcore.NewConsoleEncoder(pe) + + level := zap.DebugLevel + + core := zapcore.NewCore(consoleEncoder, zapcore.AddSync(os.Stdout), level) + logger = zap.New(core).Sugar() + + var callerFilename string + _, callerFilename, _, _ = runtime.Caller(1) + filenameTrimChars = len(filepath.Dir(callerFilename)) + 1 +} diff --git a/main.go b/main.go new file mode 100644 index 0000000..feb916a --- /dev/null +++ b/main.go @@ -0,0 +1,137 @@ +package main + +import ( + "bytes" + "encoding/binary" + "fmt" + "net" + "time" + + "github.com/nonoo/kappanhang/log" +) + +var conn *net.UDPConn + +func send(d []byte) { + _, err := conn.Write(d) + if err != nil { + log.Fatal(err) + } +} + +func read() ([]byte, error) { + err := conn.SetReadDeadline(time.Now().Add(time.Second)) + if err != nil { + log.Fatal(err) + } + + b := make([]byte, 1500) + n, _, err := conn.ReadFromUDP(b) + if err != nil { + if err, ok := err.(net.Error); ok && !err.Timeout() { + log.Fatal(err) + } + } + return b[:n], err +} + +func main() { + log.Init() + parseArgs() + + hostPort := fmt.Sprint(connectAddress, ":", connectPort) + log.Print("connecting to ", hostPort) + raddr, err := net.ResolveUDPAddr("udp", hostPort) + if err != nil { + log.Fatal(err) + } + conn, err = net.DialUDP("udp", nil, raddr) + if err != nil { + log.Fatal(err) + } + + // Constructing the local session ID by combining the local IP address and port. + laddr := conn.LocalAddr().(*net.UDPAddr) + localSID := binary.BigEndian.Uint32(laddr.IP[len(laddr.IP)-4:])<<16 | uint32(laddr.Port&0xffff) + log.Debugf("using session id %.8x", localSID) + + send([]byte{0x10, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, byte(localSID >> 24), byte(localSID >> 16), byte(localSID >> 8), byte(localSID), 0x00, 0x00, 0x00, 0x00}) + // send([]byte{0x15, 0x00, 0x00, 0x00, 0x07, 0x00, 0x01, 0x00, byte(localSID >> 24), byte(localSID >> 16), byte(localSID >> 8), byte(localSID), 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x3e, 0x10, 0x00}) + // send([]byte{0x10, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, byte(localSID >> 24), byte(localSID >> 16), byte(localSID >> 8), byte(localSID), 0x00, 0x00, 0x00, 0x00}) + // send([]byte{0x15, 0x00, 0x00, 0x00, 0x07, 0x00, 0x02, 0x00, byte(localSID >> 24), byte(localSID >> 16), byte(localSID >> 8), byte(localSID), 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x3e, 0x10, 0x00}) + // send([]byte{0x10, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, byte(localSID >> 24), byte(localSID >> 16), byte(localSID >> 8), byte(localSID), 0x00, 0x00, 0x00, 0x00}) + + var remoteSID uint32 + for { + r, _ := read() + if bytes.Equal(r[:8], []byte{0x10, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00}) { + remoteSID = binary.BigEndian.Uint32(r[8:12]) + break + } + } + + log.Debugf("got remote session id %.8x", remoteSID) + + send([]byte{0x10, 0x00, 0x00, 0x00, 0x06, 0x00, 0x01, 0x00, byte(localSID >> 24), byte(localSID >> 16), byte(localSID >> 8), byte(localSID), byte(remoteSID >> 24), byte(remoteSID >> 16), byte(remoteSID >> 8), byte(remoteSID)}) + send([]byte{0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, byte(localSID >> 24), byte(localSID >> 16), byte(localSID >> 8), byte(localSID), byte(remoteSID >> 24), byte(remoteSID >> 16), byte(remoteSID >> 8), byte(remoteSID), + 0x00, 0x00, 0x00, 0x70, 0x01, 0x00, 0x00, 0x22, + 0x00, 0x00, 0x09, 0x27, 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, 0x00, 0x00, 0x00, 0x00, + 0x3e, 0x71, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x5e, 0x3e, 0x2c, 0x54, 0x3a, 0x4f, 0x75, 0x79, + 0x00, 0x00, 0x00, 0x00, 0x00, 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}) + + var sendSeq uint8 + var lastReceivedSeq uint8 + var receivedSeq bool + var lastPingAt time.Time + var errCount int + for { + r, err := read() + if err != nil { + errCount++ + if errCount > 5 { + log.Fatal("timeout") + } + log.Error("stream break detected") + } + errCount = 0 + + if bytes.Equal(r[:6], []byte{0x00, 0x00, 0x00, 0x00, 0x07, 0x00}) { + gotSeq := r[6] + if receivedSeq && lastReceivedSeq+1 != gotSeq { + log.Error("packet loss detected") + } + lastReceivedSeq = gotSeq + receivedSeq = true + } + + if time.Since(lastPingAt) >= time.Second { + // 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0xf0, 0xa4, 0xf5, 0x9d, 0xad, 0x89, 0x2b, 0x14 + // 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x00, 0xf0, 0xa4, 0xf5, 0x9d, 0xad, 0x89, 0x2b, 0x14 + send([]byte{0x10, 0x00, 0x00, 0x00, 0x00, 0x00, sendSeq, 0x00, byte(remoteSID >> 24), byte(remoteSID >> 16), byte(remoteSID >> 8), byte(remoteSID), byte(localSID >> 24), byte(localSID >> 16), byte(localSID >> 8), byte(localSID)}) + + // 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x86, 0x08, 0xf0, 0xa4, 0xf5, 0x9d, 0xad, 0x89, 0x2b, 0x14, 0x00, 0x08, 0xdf, 0x10, 0x00 + // 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x87, 0x08, 0xf0, 0xa4, 0xf5, 0x9d, 0xad, 0x89, 0x2b, 0x14, 0x00, 0x6c, 0xdf, 0x10, 0x00 + send([]byte{0x00, 0x00, 0x00, 0x00, 0x07, 0x00, sendSeq, 0x08, byte(remoteSID >> 24), byte(remoteSID >> 16), byte(remoteSID >> 8), byte(remoteSID), byte(localSID >> 24), byte(localSID >> 16), byte(localSID >> 8), byte(localSID), 0x00, 0xd0, 0xdf, 0x10, 0x00}) + + // 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x1c, 0x00, 0xf0, 0xa4, 0xf5, 0x9d, 0xad, 0x89, 0x2b, 0x14, 0x01, 0xb2, 0x48, 0x10, 0x00 + // 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x1d, 0x00, 0xf0, 0xa4, 0xf5, 0x9d, 0xad, 0x89, 0x2b, 0x14, 0x01, 0x17, 0x49, 0x10, 0x00 + // 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x1e, 0x00, 0xf0, 0xa4, 0xf5, 0x9d, 0xad, 0x89, 0x2b, 0x14, 0x01, 0x7c, 0x49, 0x10, 0x00 + send([]byte{0x00, 0x00, 0x00, 0x00, 0x07, 0x00, sendSeq, 0x00, byte(remoteSID >> 24), byte(remoteSID >> 16), byte(remoteSID >> 8), byte(remoteSID), byte(localSID >> 24), byte(localSID >> 16), byte(localSID >> 8), byte(localSID), 0x01, 0xe1, 0x49, 0x10, 0x00}) + + sendSeq++ + + //send([]byte{0x10, 0x00, 0x00, 0x00, 0x06, 0x00, 0x01, 0x00, byte(localSID >> 24), byte(localSID >> 16), byte(localSID >> 8), byte(localSID), byte(remoteSID >> 24), byte(remoteSID >> 16), byte(remoteSID >> 8), byte(remoteSID)}) + lastPingAt = time.Now() + } + } +}