diff --git a/client/image.go b/client/image.go index cc39af8b..4b6042e1 100644 --- a/client/image.go +++ b/client/image.go @@ -3,13 +3,13 @@ package client import ( "bytes" "encoding/hex" - "image" "io" "math/rand" "os" "strings" "time" + "github.com/fumiama/imgsz" "github.com/pkg/errors" "github.com/Mrs4s/MiraiGo/binary" @@ -76,12 +76,9 @@ func (c *QQClient) UploadGroupImage(groupCode int64, img io.ReadSeeker) (*messag return nil, errors.Wrap(err, "upload failed") ok: _, _ = img.Seek(0, io.SeekStart) - i, _, _ := image.DecodeConfig(img) + i, t, _ := imgsz.DecodeSize(img) var imageType int32 = 1000 - _, _ = img.Seek(0, io.SeekStart) - tmp := make([]byte, 4) - _, _ = img.Read(tmp) - if bytes.Equal(tmp, []byte{0x47, 0x49, 0x46, 0x38}) { + if t == "gif" { imageType = 2000 } return message.NewGroupImage(binary.CalculateImageResourceId(fh), fh, rsp.FileId, int32(length), int32(i.Width), int32(i.Height), imageType), nil @@ -129,12 +126,9 @@ func (c *QQClient) UploadGroupImageByFile(groupCode int64, path string) (*messag return nil, errors.Wrap(err, "upload failed") ok: _, _ = img.Seek(0, io.SeekStart) - i, _, _ := image.DecodeConfig(img) + i, t, _ := imgsz.DecodeSize(img) var imageType int32 = 1000 - _, _ = img.Seek(0, io.SeekStart) - tmp := make([]byte, 4) - _, _ = img.Read(tmp) - if bytes.Equal(tmp, []byte{0x47, 0x49, 0x46, 0x38}) { + if t == "gif" { imageType = 2000 } return message.NewGroupImage(binary.CalculateImageResourceId(fh), fh, rsp.FileId, int32(length), int32(i.Width), int32(i.Height), imageType), nil diff --git a/client/internal/highway/highway.go b/client/internal/highway/highway.go index 638d5a79..7d7c1ab0 100644 --- a/client/internal/highway/highway.go +++ b/client/internal/highway/highway.go @@ -8,6 +8,7 @@ import ( "net" "net/http" "sync/atomic" + "time" "github.com/pkg/errors" @@ -27,6 +28,8 @@ type Session struct { seq int32 } +const highwayMaxResponseSize int32 = 1024 * 100 // 100k + func (s *Session) AddrLength() int { return len(s.SsoAddr) } @@ -48,7 +51,7 @@ type Input struct { func (s *Session) Upload(addr Addr, input Input) error { fh, length := utils.ComputeMd5AndLength(input.Body) _, _ = input.Body.Seek(0, io.SeekStart) - conn, err := net.DialTCP("tcp", nil, addr.asTcpAddr()) + conn, err := net.DialTimeout("tcp", addr.String(), time.Second*3) if err != nil { return errors.Wrap(err, "connect error") } @@ -246,6 +249,9 @@ func readResponse(r *binary.NetworkReader) (*pb.RspDataHighwayHead, []byte, erro } hl, _ := r.ReadInt32() a2, _ := r.ReadInt32() + if hl > highwayMaxResponseSize || a2 > highwayMaxResponseSize { + return nil, nil, errors.Errorf("highway response invild. head size: %v body size: %v", hl, a2) + } head, _ := r.ReadBytes(int(hl)) payload, _ := r.ReadBytes(int(a2)) _, _ = r.ReadByte() diff --git a/client/network.go b/client/network.go index 57b8df87..ebcdbd11 100644 --- a/client/network.go +++ b/client/network.go @@ -67,10 +67,10 @@ func (c *QQClient) ConnectionQualityTest() *ConnectionQualityInfo { }() go func() { defer wg.Done() - res := utils.RunICMPPingLoop(&net.IPAddr{IP: c.servers[c.currServerIndex].IP}, 10) + res := utils.RunTCPPingLoop(c.servers[c.currServerIndex].String(), 10) r.ChatServerPacketLoss = res.PacketsLoss if c.highwaySession.AddrLength() > 0 { - res = utils.RunICMPPingLoop(&net.IPAddr{IP: c.highwaySession.SsoAddr[0].AsNetIP()}, 10) + res = utils.RunTCPPingLoop(c.highwaySession.SsoAddr[0].String(), 10) r.SrvServerPacketLoss = res.PacketsLoss } }() diff --git a/go.mod b/go.mod index c676ed7f..83b7f008 100644 --- a/go.mod +++ b/go.mod @@ -4,6 +4,7 @@ go 1.17 require ( github.com/RomiChan/protobuf v0.0.0-20211223055824-048df49a8956 + github.com/fumiama/imgsz v0.0.2 github.com/klauspost/compress v1.13.6 github.com/pierrec/lz4/v4 v4.1.11 github.com/pkg/errors v0.9.1 diff --git a/go.sum b/go.sum index 78856e76..5c9e6c29 100644 --- a/go.sum +++ b/go.sum @@ -3,6 +3,8 @@ github.com/RomiChan/protobuf v0.0.0-20211223055824-048df49a8956/go.mod h1:CKKOWC github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/fumiama/imgsz v0.0.2 h1:fAkC0FnIscdKOXwAxlyw3EUba5NzxZdSxGaq3Uyfxak= +github.com/fumiama/imgsz v0.0.2/go.mod h1:dR71mI3I2O5u6+PCpd47M9TZptzP+39tRBcbdIkoqM4= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/klauspost/compress v1.13.6 h1:P76CopJELS0TiO2mebmnzgWaajssP/EszplttgQxcgc= diff --git a/internal/tlv/t545.go b/internal/tlv/t545.go index 756da96f..a916a047 100644 --- a/internal/tlv/t545.go +++ b/internal/tlv/t545.go @@ -4,7 +4,7 @@ import "github.com/Mrs4s/MiraiGo/binary" func T545(imei []byte) []byte { return binary.NewWriterF(func(w *binary.Writer) { - w.WriteUInt16(0x108) + w.WriteUInt16(0x545) w.WriteBytesShort(imei) }) } diff --git a/message/image.go b/message/image.go index 41b11100..1bea6d82 100644 --- a/message/image.go +++ b/message/image.go @@ -90,6 +90,14 @@ func (e *GuildImageElement) Type() ElementType { } func (e *GroupImageElement) Pack() (r []*msg.Elem) { + // width and height are required, set 720*480 if not set + if e.Width == 0 { + e.Width = 720 + } + if e.Height == 0 { + e.Height = 480 + } + cface := &msg.CustomFace{ FileType: proto.Int32(66), Useful: proto.Int32(1), diff --git a/utils/icmp.go b/utils/icmp.go deleted file mode 100644 index 394685a5..00000000 --- a/utils/icmp.go +++ /dev/null @@ -1,73 +0,0 @@ -package utils - -import ( - "math/rand" - "net" - "time" - - "github.com/pkg/errors" - "golang.org/x/net/icmp" - "golang.org/x/net/ipv4" -) - -type ICMPPingResult struct { - PacketsSent int - PacketsRecv int - PacketsLoss int - Rtts []int64 -} - -func RunICMPPingLoop(addr *net.IPAddr, count int) *ICMPPingResult { - if count <= 0 { - return nil - } - r := &ICMPPingResult{ - PacketsSent: count, - Rtts: make([]int64, count), - } - for i := 1; i <= count; i++ { - rtt, err := SendICMPRequest(addr, i) - if err != nil { - r.PacketsLoss++ - r.Rtts[i-1] = 9999 - continue - } - r.PacketsRecv++ - r.Rtts[i-1] = rtt - time.Sleep(time.Millisecond * 100) - } - return r -} - -func SendICMPRequest(addr *net.IPAddr, seq int) (int64, error) { - data := make([]byte, 32) - rand.Read(data) - body := &icmp.Echo{ - ID: 0, - Seq: seq, - Data: data, - } - msg := &icmp.Message{ - Type: ipv4.ICMPTypeEcho, - Code: 0, - Body: body, - } - msgBytes, _ := msg.Marshal(nil) - conn, err := net.DialIP("ip4:icmp", nil, addr) - if err != nil { - return 0, errors.Wrap(err, "dial icmp conn error") - } - defer func() { _ = conn.Close() }() - if _, err = conn.Write(msgBytes); err != nil { - return 0, errors.Wrap(err, "write icmp packet error") - } - start := time.Now() - _ = conn.SetReadDeadline(time.Now().Add(time.Second * 2)) - buff := make([]byte, 1024) - _, err = conn.Read(buff) - if err != nil { - return 0, errors.Wrap(err, "read icmp conn error") - } - duration := time.Since(start).Milliseconds() - return duration, nil -} diff --git a/utils/tcping.go b/utils/tcping.go new file mode 100644 index 00000000..4b899673 --- /dev/null +++ b/utils/tcping.go @@ -0,0 +1,59 @@ +package utils + +import ( + "net" + "strings" + "time" +) + +type ICMPPingResult struct { + PacketsSent int + PacketsLoss int + AvgTimeMill int64 +} + +// RunTCPPingLoop 使用 tcp 进行 ping +func RunTCPPingLoop(ipport string, count int) (r ICMPPingResult) { + r = ICMPPingResult{ + PacketsSent: count, + PacketsLoss: count, + AvgTimeMill: 9999, + } + if count <= 0 { + return + } + durs := make([]int64, 0, count) + for i := 0; i < count; i++ { + d, err := tcping(ipport) + if err == nil { + r.PacketsLoss-- + durs = append(durs, d) + } + time.Sleep(time.Millisecond * 100) + } + + if len(durs) > 0 { + r.AvgTimeMill = 0 + for _, d := range durs { + r.AvgTimeMill += d + } + if len(durs) > 1 { + r.AvgTimeMill /= int64(len(durs)) + } + } + + return +} + +func tcping(ipport string) (int64, error) { + t := time.Now().UnixMilli() + conn, err := net.DialTimeout("tcp", ipport, time.Second*2) + if err != nil { + if strings.Contains(err.Error(), "timeout") { + return 9999, err + } + } else { + _ = conn.Close() + } + return time.Now().UnixMilli() - t, nil +} diff --git a/utils/tcping_test.go b/utils/tcping_test.go new file mode 100644 index 00000000..6ad4c42c --- /dev/null +++ b/utils/tcping_test.go @@ -0,0 +1,12 @@ +package utils + +import ( + "testing" +) + +func TestPing(t *testing.T) { + r := RunTCPPingLoop("127.0.0.1:23333", 4) + if r.PacketsLoss == r.PacketsSent { + t.Fatal(r) + } +}