From d72696a0c80bb8890df1bd87db0ba93944dba855 Mon Sep 17 00:00:00 2001 From: fumiama Date: Sun, 26 Dec 2021 13:08:38 +0800 Subject: [PATCH 01/14] feat: use udp to simulate icmp echo --- client/network.go | 4 +- utils/icmp.go | 104 ++++++++++++++++++++++++--------------------- utils/icmp_test.go | 12 ++++++ 3 files changed, 69 insertions(+), 51 deletions(-) create mode 100644 utils/icmp_test.go diff --git a/client/network.go b/client/network.go index bab7565e..0cfdd864 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.RunICMPPingLoop(c.servers[c.currServerIndex].IP.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.RunICMPPingLoop(c.highwaySession.SsoAddr[0].AsNetIP().String(), 10) r.SrvServerPacketLoss = res.PacketsLoss } }() diff --git a/utils/icmp.go b/utils/icmp.go index 394685a5..7f6600ae 100644 --- a/utils/icmp.go +++ b/utils/icmp.go @@ -1,73 +1,79 @@ package utils import ( + "errors" "math/rand" "net" + "strconv" "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 + AvgTimeMill int64 } -func RunICMPPingLoop(addr *net.IPAddr, count int) *ICMPPingResult { - if count <= 0 { - return nil - } - r := &ICMPPingResult{ +// RunICMPPingLoop unix 下的 ping +func RunICMPPingLoop(ip string, count int) (r ICMPPingResult) { + r = ICMPPingResult{ PacketsSent: count, - Rtts: make([]int64, count), + PacketsLoss: count, + AvgTimeMill: 9999, } - for i := 1; i <= count; i++ { - rtt, err := SendICMPRequest(addr, i) - if err != nil { - r.PacketsLoss++ - r.Rtts[i-1] = 9999 - continue + if count <= 0 { + return + } + durs := make([]int64, 0, count) + for i := 0; i < count; i++ { + d, err := pingudp(ip) + if err == nil { + r.PacketsLoss-- + durs = append(durs, d) } - r.PacketsRecv++ - r.Rtts[i-1] = rtt - time.Sleep(time.Millisecond * 100) } - return r + + 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 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) +func pingudp(ip string) (int64, error) { + var buf [256]byte + ch := make(chan error, 1) + + port := rand.Intn(10000) + 50000 + conn, err := net.Dial("udp", ip+":"+strconv.Itoa(port)) if err != nil { - return 0, errors.Wrap(err, "dial icmp conn error") + return 9999, err } - 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) + + t := time.Now().UnixMilli() + + _, err = conn.Write([]byte("fill")) if err != nil { - return 0, errors.Wrap(err, "read icmp conn error") + return 0, err } - duration := time.Since(start).Milliseconds() - return duration, nil + go func() { + _, err := conn.Read(buf[:]) + ch <- err + }() + select { + case <-time.NewTimer(time.Second * 4).C: + err = errors.New("timeout") + case err = <-ch: + } + + if err != nil && err.Error() == "timeout" { + return 9999, err + } + return time.Now().UnixMilli() - t, nil } diff --git a/utils/icmp_test.go b/utils/icmp_test.go new file mode 100644 index 00000000..286e1d4b --- /dev/null +++ b/utils/icmp_test.go @@ -0,0 +1,12 @@ +package utils + +import ( + "testing" +) + +func TestPing(t *testing.T) { + r := RunICMPPingLoop("127.0.0.1", 4) + if r.PacketsLoss == r.PacketsSent { + t.Fatal(r) + } +} From b8023f445a1ea726aac7e014c5123c343d1e7fe8 Mon Sep 17 00:00:00 2001 From: fumiama Date: Sun, 26 Dec 2021 13:32:51 +0800 Subject: [PATCH 02/14] feat: use tcp handshake to simulate icmp echo --- client/network.go | 4 ++-- utils/icmp.go | 43 +++++++++++-------------------------------- utils/icmp_test.go | 2 +- 3 files changed, 14 insertions(+), 35 deletions(-) diff --git a/client/network.go b/client/network.go index 0cfdd864..ac609b0f 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(c.servers[c.currServerIndex].IP.String(), 10) + res := utils.RunICMPPingLoop(c.servers[c.currServerIndex].String(), 10) r.ChatServerPacketLoss = res.PacketsLoss if c.highwaySession.AddrLength() > 0 { - res = utils.RunICMPPingLoop(c.highwaySession.SsoAddr[0].AsNetIP().String(), 10) + res = utils.RunICMPPingLoop(c.highwaySession.SsoAddr[0].String(), 10) r.SrvServerPacketLoss = res.PacketsLoss } }() diff --git a/utils/icmp.go b/utils/icmp.go index 7f6600ae..825ae709 100644 --- a/utils/icmp.go +++ b/utils/icmp.go @@ -1,10 +1,8 @@ package utils import ( - "errors" - "math/rand" "net" - "strconv" + "strings" "time" ) @@ -14,8 +12,8 @@ type ICMPPingResult struct { AvgTimeMill int64 } -// RunICMPPingLoop unix 下的 ping -func RunICMPPingLoop(ip string, count int) (r ICMPPingResult) { +// RunICMPPingLoop tcp 伪装的 icmp +func RunICMPPingLoop(ipport string, count int) (r ICMPPingResult) { r = ICMPPingResult{ PacketsSent: count, PacketsLoss: count, @@ -26,7 +24,7 @@ func RunICMPPingLoop(ip string, count int) (r ICMPPingResult) { } durs := make([]int64, 0, count) for i := 0; i < count; i++ { - d, err := pingudp(ip) + d, err := pingtcp(ipport) if err == nil { r.PacketsLoss-- durs = append(durs, d) @@ -46,34 +44,15 @@ func RunICMPPingLoop(ip string, count int) (r ICMPPingResult) { return } -func pingudp(ip string) (int64, error) { - var buf [256]byte - ch := make(chan error, 1) - - port := rand.Intn(10000) + 50000 - conn, err := net.Dial("udp", ip+":"+strconv.Itoa(port)) - if err != nil { - return 9999, err - } - +func pingtcp(ipport string) (int64, error) { t := time.Now().UnixMilli() - - _, err = conn.Write([]byte("fill")) + conn, err := net.DialTimeout("tcp", ipport, time.Second*2) if err != nil { - return 0, err - } - go func() { - _, err := conn.Read(buf[:]) - ch <- err - }() - select { - case <-time.NewTimer(time.Second * 4).C: - err = errors.New("timeout") - case err = <-ch: - } - - if err != nil && err.Error() == "timeout" { - return 9999, err + if strings.Contains(err.Error(), "timeout") { + return 9999, err + } + } else { + _ = conn.Close() } return time.Now().UnixMilli() - t, nil } diff --git a/utils/icmp_test.go b/utils/icmp_test.go index 286e1d4b..b173b3b5 100644 --- a/utils/icmp_test.go +++ b/utils/icmp_test.go @@ -5,7 +5,7 @@ import ( ) func TestPing(t *testing.T) { - r := RunICMPPingLoop("127.0.0.1", 4) + r := RunICMPPingLoop("127.0.0.1:23333", 4) if r.PacketsLoss == r.PacketsSent { t.Fatal(r) } From 2c56abf4d81204cf168686d45b8ce62e596586b1 Mon Sep 17 00:00:00 2001 From: fumiama Date: Sun, 26 Dec 2021 14:15:10 +0800 Subject: [PATCH 03/14] fix: add wait --- utils/icmp.go | 1 + 1 file changed, 1 insertion(+) diff --git a/utils/icmp.go b/utils/icmp.go index 825ae709..886c3beb 100644 --- a/utils/icmp.go +++ b/utils/icmp.go @@ -29,6 +29,7 @@ func RunICMPPingLoop(ipport string, count int) (r ICMPPingResult) { r.PacketsLoss-- durs = append(durs, d) } + time.Sleep(time.Millisecond * 100) } if len(durs) > 0 { From 9d618e2d9f3e2231900661cec40ba84621975ab3 Mon Sep 17 00:00:00 2001 From: wdvxdr Date: Tue, 28 Dec 2021 21:44:10 +0800 Subject: [PATCH 04/14] message: remove GroupImage Width & Height sometimes these fields may be zero causing send failures --- client/image.go | 13 ++++--------- message/image.go | 10 +++------- message/message.go | 4 ---- 3 files changed, 7 insertions(+), 20 deletions(-) diff --git a/client/image.go b/client/image.go index e3736b9f..34fd57c8 100644 --- a/client/image.go +++ b/client/image.go @@ -3,7 +3,6 @@ package client import ( "bytes" "encoding/hex" - "image" "io" "math/rand" "os" @@ -81,8 +80,6 @@ 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) var imageType int32 = 1000 _, _ = img.Seek(0, io.SeekStart) tmp := make([]byte, 4) @@ -90,7 +87,7 @@ ok: if bytes.Equal(tmp, []byte{0x47, 0x49, 0x46, 0x38}) { imageType = 2000 } - return message.NewGroupImage(binary.CalculateImageResourceId(fh), fh, rsp.FileId, int32(length), int32(i.Width), int32(i.Height), imageType), nil + return message.NewGroupImage(binary.CalculateImageResourceId(fh), fh, rsp.FileId, int32(length), imageType), nil } func (c *QQClient) UploadGroupImageByFile(groupCode int64, path string) (*message.GroupImageElement, error) { @@ -134,8 +131,6 @@ 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) var imageType int32 = 1000 _, _ = img.Seek(0, io.SeekStart) tmp := make([]byte, 4) @@ -143,7 +138,7 @@ ok: if bytes.Equal(tmp, []byte{0x47, 0x49, 0x46, 0x38}) { imageType = 2000 } - return message.NewGroupImage(binary.CalculateImageResourceId(fh), fh, rsp.FileId, int32(length), int32(i.Width), int32(i.Height), imageType), nil + return message.NewGroupImage(binary.CalculateImageResourceId(fh), fh, rsp.FileId, int32(length), imageType), nil } func (c *QQClient) UploadPrivateImage(target int64, img io.ReadSeeker) (*message.FriendImageElement, error) { @@ -191,7 +186,7 @@ func (c *QQClient) ImageOcr(img interface{}) (*OcrResponse, error) { } _ = b.Close() } - rsp, err := c.sendAndWait(c.buildImageOcrRequestPacket(url, strings.ToUpper(hex.EncodeToString(e.Md5)), e.Size, e.Width, e.Height)) + rsp, err := c.sendAndWait(c.buildImageOcrRequestPacket(url, strings.ToUpper(hex.EncodeToString(e.Md5)), e.Size, 480, 720)) if err != nil { return nil, err } @@ -210,7 +205,7 @@ func (c *QQClient) QueryGroupImage(groupCode int64, hash []byte, size int32) (*m return nil, errors.New(rsp.Message) } if rsp.IsExists { - return message.NewGroupImage(binary.CalculateImageResourceId(hash), hash, rsp.FileId, size, rsp.Width, rsp.Height, 1000), nil + return message.NewGroupImage(binary.CalculateImageResourceId(hash), hash, rsp.FileId, size, 1000), nil } return nil, errors.New("image does not exist") } diff --git a/message/image.go b/message/image.go index 41b11100..92c9db84 100644 --- a/message/image.go +++ b/message/image.go @@ -16,8 +16,6 @@ type GroupImageElement struct { ImageType int32 ImageBizType ImageBizType Size int32 - Width int32 - Height int32 Md5 []byte Url string @@ -64,15 +62,13 @@ const ( /* ------ Implementations ------ */ -func NewGroupImage(id string, md5 []byte, fid int64, size, width, height, imageType int32) *GroupImageElement { +func NewGroupImage(id string, md5 []byte, fid int64, size, imageType int32) *GroupImageElement { return &GroupImageElement{ ImageId: id, FileId: fid, Md5: md5, Size: size, ImageType: imageType, - Width: width, - Height: height, Url: "https://gchat.qpic.cn/gchatpic_new/1/0-0-" + strings.ReplaceAll(binary.CalculateImageResourceId(md5)[1:37], "-", "") + "/0?term=2", } } @@ -95,8 +91,8 @@ func (e *GroupImageElement) Pack() (r []*msg.Elem) { Useful: proto.Int32(1), // Origin: 1, BizType: proto.Int32(5), - Width: &e.Width, - Height: &e.Height, + Width: proto.Int32(720), + Height: proto.Int32(480), FileId: proto.Int32(int32(e.FileId)), FilePath: &e.ImageId, ImageType: &e.ImageType, diff --git a/message/message.go b/message/message.go index c585c009..c1189862 100644 --- a/message/message.go +++ b/message/message.go @@ -462,8 +462,6 @@ func ParseMessageElems(elems []*msg.Elem) []IMessageElement { FileId: int64(elem.CustomFace.GetFileId()), ImageId: elem.CustomFace.GetFilePath(), Size: elem.CustomFace.GetSize(), - Width: elem.CustomFace.GetWidth(), - Height: elem.CustomFace.GetHeight(), Url: url, ImageBizType: func() ImageBizType { if len(elem.CustomFace.PbReserve) == 0 { @@ -561,8 +559,6 @@ func ParseMessageElems(elems []*msg.Elem) []IMessageElement { FileId: int64(flash.FlashTroopPic.GetFileId()), ImageId: flash.FlashTroopPic.GetFilePath(), Size: flash.FlashTroopPic.GetSize(), - Width: flash.FlashTroopPic.GetWidth(), - Height: flash.FlashTroopPic.GetHeight(), Md5: flash.FlashTroopPic.Md5, Flash: true, }) From ab72f3dc28dac523879e8790f8c121653bfac087 Mon Sep 17 00:00:00 2001 From: wdvxdr Date: Tue, 28 Dec 2021 22:05:30 +0800 Subject: [PATCH 05/14] Revert "message: remove GroupImage Width & Height" This reverts commit 9d618e2d9f3e2231900661cec40ba84621975ab3. handle zero width and height in another way. --- client/image.go | 13 +++++++++---- message/image.go | 18 +++++++++++++++--- message/message.go | 4 ++++ 3 files changed, 28 insertions(+), 7 deletions(-) diff --git a/client/image.go b/client/image.go index 34fd57c8..e3736b9f 100644 --- a/client/image.go +++ b/client/image.go @@ -3,6 +3,7 @@ package client import ( "bytes" "encoding/hex" + "image" "io" "math/rand" "os" @@ -80,6 +81,8 @@ 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) var imageType int32 = 1000 _, _ = img.Seek(0, io.SeekStart) tmp := make([]byte, 4) @@ -87,7 +90,7 @@ ok: if bytes.Equal(tmp, []byte{0x47, 0x49, 0x46, 0x38}) { imageType = 2000 } - return message.NewGroupImage(binary.CalculateImageResourceId(fh), fh, rsp.FileId, int32(length), imageType), nil + return message.NewGroupImage(binary.CalculateImageResourceId(fh), fh, rsp.FileId, int32(length), int32(i.Width), int32(i.Height), imageType), nil } func (c *QQClient) UploadGroupImageByFile(groupCode int64, path string) (*message.GroupImageElement, error) { @@ -131,6 +134,8 @@ 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) var imageType int32 = 1000 _, _ = img.Seek(0, io.SeekStart) tmp := make([]byte, 4) @@ -138,7 +143,7 @@ ok: if bytes.Equal(tmp, []byte{0x47, 0x49, 0x46, 0x38}) { imageType = 2000 } - return message.NewGroupImage(binary.CalculateImageResourceId(fh), fh, rsp.FileId, int32(length), imageType), nil + return message.NewGroupImage(binary.CalculateImageResourceId(fh), fh, rsp.FileId, int32(length), int32(i.Width), int32(i.Height), imageType), nil } func (c *QQClient) UploadPrivateImage(target int64, img io.ReadSeeker) (*message.FriendImageElement, error) { @@ -186,7 +191,7 @@ func (c *QQClient) ImageOcr(img interface{}) (*OcrResponse, error) { } _ = b.Close() } - rsp, err := c.sendAndWait(c.buildImageOcrRequestPacket(url, strings.ToUpper(hex.EncodeToString(e.Md5)), e.Size, 480, 720)) + rsp, err := c.sendAndWait(c.buildImageOcrRequestPacket(url, strings.ToUpper(hex.EncodeToString(e.Md5)), e.Size, e.Width, e.Height)) if err != nil { return nil, err } @@ -205,7 +210,7 @@ func (c *QQClient) QueryGroupImage(groupCode int64, hash []byte, size int32) (*m return nil, errors.New(rsp.Message) } if rsp.IsExists { - return message.NewGroupImage(binary.CalculateImageResourceId(hash), hash, rsp.FileId, size, 1000), nil + return message.NewGroupImage(binary.CalculateImageResourceId(hash), hash, rsp.FileId, size, rsp.Width, rsp.Height, 1000), nil } return nil, errors.New("image does not exist") } diff --git a/message/image.go b/message/image.go index 92c9db84..1bea6d82 100644 --- a/message/image.go +++ b/message/image.go @@ -16,6 +16,8 @@ type GroupImageElement struct { ImageType int32 ImageBizType ImageBizType Size int32 + Width int32 + Height int32 Md5 []byte Url string @@ -62,13 +64,15 @@ const ( /* ------ Implementations ------ */ -func NewGroupImage(id string, md5 []byte, fid int64, size, imageType int32) *GroupImageElement { +func NewGroupImage(id string, md5 []byte, fid int64, size, width, height, imageType int32) *GroupImageElement { return &GroupImageElement{ ImageId: id, FileId: fid, Md5: md5, Size: size, ImageType: imageType, + Width: width, + Height: height, Url: "https://gchat.qpic.cn/gchatpic_new/1/0-0-" + strings.ReplaceAll(binary.CalculateImageResourceId(md5)[1:37], "-", "") + "/0?term=2", } } @@ -86,13 +90,21 @@ 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), // Origin: 1, BizType: proto.Int32(5), - Width: proto.Int32(720), - Height: proto.Int32(480), + Width: &e.Width, + Height: &e.Height, FileId: proto.Int32(int32(e.FileId)), FilePath: &e.ImageId, ImageType: &e.ImageType, diff --git a/message/message.go b/message/message.go index c1189862..c585c009 100644 --- a/message/message.go +++ b/message/message.go @@ -462,6 +462,8 @@ func ParseMessageElems(elems []*msg.Elem) []IMessageElement { FileId: int64(elem.CustomFace.GetFileId()), ImageId: elem.CustomFace.GetFilePath(), Size: elem.CustomFace.GetSize(), + Width: elem.CustomFace.GetWidth(), + Height: elem.CustomFace.GetHeight(), Url: url, ImageBizType: func() ImageBizType { if len(elem.CustomFace.PbReserve) == 0 { @@ -559,6 +561,8 @@ func ParseMessageElems(elems []*msg.Elem) []IMessageElement { FileId: int64(flash.FlashTroopPic.GetFileId()), ImageId: flash.FlashTroopPic.GetFilePath(), Size: flash.FlashTroopPic.GetSize(), + Width: flash.FlashTroopPic.GetWidth(), + Height: flash.FlashTroopPic.GetHeight(), Md5: flash.FlashTroopPic.Md5, Flash: true, }) From 41a6cb05a7daed2e2dd3ce0ebc50af66b47b98ab Mon Sep 17 00:00:00 2001 From: Lin <36601667+buhuang28@users.noreply.github.com> Date: Thu, 6 Jan 2022 20:52:09 +0800 Subject: [PATCH 06/14] fix socket block (#236) --- client/internal/highway/highway.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/client/internal/highway/highway.go b/client/internal/highway/highway.go index 638d5a79..0e74b5a8 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" @@ -48,7 +49,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") } From 9a45e430f12b96d04690a24684c2a18f86ad671b Mon Sep 17 00:00:00 2001 From: lz1998 <875543533@qq.com> Date: Fri, 14 Jan 2022 20:16:41 +0800 Subject: [PATCH 07/14] fix 0x545 (#242) --- internal/tlv/t545.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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) }) } From a5670ccc4348b7bb7b483138b121388273521c97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=BA=90=E6=96=87=E9=9B=A8?= <41315874+fumiama@users.noreply.github.com> Date: Fri, 14 Jan 2022 20:21:06 +0800 Subject: [PATCH 08/14] feat: use the decoder which only parses size info (#238) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: add GroupImage Width & Height for webp * fix: 简化写法 * feat: use imgsz package and drop image --- client/image.go | 6 +++--- go.mod | 1 + go.sum | 2 ++ 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/client/image.go b/client/image.go index e3736b9f..3e3ebb69 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" @@ -82,7 +82,7 @@ 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, _, _ := imgsz.DecodeSize(img) var imageType int32 = 1000 _, _ = img.Seek(0, io.SeekStart) tmp := make([]byte, 4) @@ -135,7 +135,7 @@ 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, _, _ := imgsz.DecodeSize(img) var imageType int32 = 1000 _, _ = img.Seek(0, io.SeekStart) tmp := make([]byte, 4) 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= From e22965eb0c013d7f3218b265a4cb559c4f8d9d65 Mon Sep 17 00:00:00 2001 From: wdvxdr Date: Tue, 28 Dec 2021 21:44:10 +0800 Subject: [PATCH 09/14] message: remove GroupImage Width & Height sometimes these fields may be zero causing send failures --- client/image.go | 13 ++++--------- message/image.go | 10 +++------- message/message.go | 4 ---- 3 files changed, 7 insertions(+), 20 deletions(-) diff --git a/client/image.go b/client/image.go index e3736b9f..34fd57c8 100644 --- a/client/image.go +++ b/client/image.go @@ -3,7 +3,6 @@ package client import ( "bytes" "encoding/hex" - "image" "io" "math/rand" "os" @@ -81,8 +80,6 @@ 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) var imageType int32 = 1000 _, _ = img.Seek(0, io.SeekStart) tmp := make([]byte, 4) @@ -90,7 +87,7 @@ ok: if bytes.Equal(tmp, []byte{0x47, 0x49, 0x46, 0x38}) { imageType = 2000 } - return message.NewGroupImage(binary.CalculateImageResourceId(fh), fh, rsp.FileId, int32(length), int32(i.Width), int32(i.Height), imageType), nil + return message.NewGroupImage(binary.CalculateImageResourceId(fh), fh, rsp.FileId, int32(length), imageType), nil } func (c *QQClient) UploadGroupImageByFile(groupCode int64, path string) (*message.GroupImageElement, error) { @@ -134,8 +131,6 @@ 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) var imageType int32 = 1000 _, _ = img.Seek(0, io.SeekStart) tmp := make([]byte, 4) @@ -143,7 +138,7 @@ ok: if bytes.Equal(tmp, []byte{0x47, 0x49, 0x46, 0x38}) { imageType = 2000 } - return message.NewGroupImage(binary.CalculateImageResourceId(fh), fh, rsp.FileId, int32(length), int32(i.Width), int32(i.Height), imageType), nil + return message.NewGroupImage(binary.CalculateImageResourceId(fh), fh, rsp.FileId, int32(length), imageType), nil } func (c *QQClient) UploadPrivateImage(target int64, img io.ReadSeeker) (*message.FriendImageElement, error) { @@ -191,7 +186,7 @@ func (c *QQClient) ImageOcr(img interface{}) (*OcrResponse, error) { } _ = b.Close() } - rsp, err := c.sendAndWait(c.buildImageOcrRequestPacket(url, strings.ToUpper(hex.EncodeToString(e.Md5)), e.Size, e.Width, e.Height)) + rsp, err := c.sendAndWait(c.buildImageOcrRequestPacket(url, strings.ToUpper(hex.EncodeToString(e.Md5)), e.Size, 480, 720)) if err != nil { return nil, err } @@ -210,7 +205,7 @@ func (c *QQClient) QueryGroupImage(groupCode int64, hash []byte, size int32) (*m return nil, errors.New(rsp.Message) } if rsp.IsExists { - return message.NewGroupImage(binary.CalculateImageResourceId(hash), hash, rsp.FileId, size, rsp.Width, rsp.Height, 1000), nil + return message.NewGroupImage(binary.CalculateImageResourceId(hash), hash, rsp.FileId, size, 1000), nil } return nil, errors.New("image does not exist") } diff --git a/message/image.go b/message/image.go index 41b11100..92c9db84 100644 --- a/message/image.go +++ b/message/image.go @@ -16,8 +16,6 @@ type GroupImageElement struct { ImageType int32 ImageBizType ImageBizType Size int32 - Width int32 - Height int32 Md5 []byte Url string @@ -64,15 +62,13 @@ const ( /* ------ Implementations ------ */ -func NewGroupImage(id string, md5 []byte, fid int64, size, width, height, imageType int32) *GroupImageElement { +func NewGroupImage(id string, md5 []byte, fid int64, size, imageType int32) *GroupImageElement { return &GroupImageElement{ ImageId: id, FileId: fid, Md5: md5, Size: size, ImageType: imageType, - Width: width, - Height: height, Url: "https://gchat.qpic.cn/gchatpic_new/1/0-0-" + strings.ReplaceAll(binary.CalculateImageResourceId(md5)[1:37], "-", "") + "/0?term=2", } } @@ -95,8 +91,8 @@ func (e *GroupImageElement) Pack() (r []*msg.Elem) { Useful: proto.Int32(1), // Origin: 1, BizType: proto.Int32(5), - Width: &e.Width, - Height: &e.Height, + Width: proto.Int32(720), + Height: proto.Int32(480), FileId: proto.Int32(int32(e.FileId)), FilePath: &e.ImageId, ImageType: &e.ImageType, diff --git a/message/message.go b/message/message.go index c585c009..c1189862 100644 --- a/message/message.go +++ b/message/message.go @@ -462,8 +462,6 @@ func ParseMessageElems(elems []*msg.Elem) []IMessageElement { FileId: int64(elem.CustomFace.GetFileId()), ImageId: elem.CustomFace.GetFilePath(), Size: elem.CustomFace.GetSize(), - Width: elem.CustomFace.GetWidth(), - Height: elem.CustomFace.GetHeight(), Url: url, ImageBizType: func() ImageBizType { if len(elem.CustomFace.PbReserve) == 0 { @@ -561,8 +559,6 @@ func ParseMessageElems(elems []*msg.Elem) []IMessageElement { FileId: int64(flash.FlashTroopPic.GetFileId()), ImageId: flash.FlashTroopPic.GetFilePath(), Size: flash.FlashTroopPic.GetSize(), - Width: flash.FlashTroopPic.GetWidth(), - Height: flash.FlashTroopPic.GetHeight(), Md5: flash.FlashTroopPic.Md5, Flash: true, }) From 7bec167fa74551f884f951e20b842b34ba8d30fe Mon Sep 17 00:00:00 2001 From: wdvxdr Date: Tue, 28 Dec 2021 22:05:30 +0800 Subject: [PATCH 10/14] Revert "message: remove GroupImage Width & Height" This reverts commit 9d618e2d9f3e2231900661cec40ba84621975ab3. handle zero width and height in another way. --- client/image.go | 13 +++++++++---- message/image.go | 18 +++++++++++++++--- message/message.go | 4 ++++ 3 files changed, 28 insertions(+), 7 deletions(-) diff --git a/client/image.go b/client/image.go index 34fd57c8..e3736b9f 100644 --- a/client/image.go +++ b/client/image.go @@ -3,6 +3,7 @@ package client import ( "bytes" "encoding/hex" + "image" "io" "math/rand" "os" @@ -80,6 +81,8 @@ 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) var imageType int32 = 1000 _, _ = img.Seek(0, io.SeekStart) tmp := make([]byte, 4) @@ -87,7 +90,7 @@ ok: if bytes.Equal(tmp, []byte{0x47, 0x49, 0x46, 0x38}) { imageType = 2000 } - return message.NewGroupImage(binary.CalculateImageResourceId(fh), fh, rsp.FileId, int32(length), imageType), nil + return message.NewGroupImage(binary.CalculateImageResourceId(fh), fh, rsp.FileId, int32(length), int32(i.Width), int32(i.Height), imageType), nil } func (c *QQClient) UploadGroupImageByFile(groupCode int64, path string) (*message.GroupImageElement, error) { @@ -131,6 +134,8 @@ 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) var imageType int32 = 1000 _, _ = img.Seek(0, io.SeekStart) tmp := make([]byte, 4) @@ -138,7 +143,7 @@ ok: if bytes.Equal(tmp, []byte{0x47, 0x49, 0x46, 0x38}) { imageType = 2000 } - return message.NewGroupImage(binary.CalculateImageResourceId(fh), fh, rsp.FileId, int32(length), imageType), nil + return message.NewGroupImage(binary.CalculateImageResourceId(fh), fh, rsp.FileId, int32(length), int32(i.Width), int32(i.Height), imageType), nil } func (c *QQClient) UploadPrivateImage(target int64, img io.ReadSeeker) (*message.FriendImageElement, error) { @@ -186,7 +191,7 @@ func (c *QQClient) ImageOcr(img interface{}) (*OcrResponse, error) { } _ = b.Close() } - rsp, err := c.sendAndWait(c.buildImageOcrRequestPacket(url, strings.ToUpper(hex.EncodeToString(e.Md5)), e.Size, 480, 720)) + rsp, err := c.sendAndWait(c.buildImageOcrRequestPacket(url, strings.ToUpper(hex.EncodeToString(e.Md5)), e.Size, e.Width, e.Height)) if err != nil { return nil, err } @@ -205,7 +210,7 @@ func (c *QQClient) QueryGroupImage(groupCode int64, hash []byte, size int32) (*m return nil, errors.New(rsp.Message) } if rsp.IsExists { - return message.NewGroupImage(binary.CalculateImageResourceId(hash), hash, rsp.FileId, size, 1000), nil + return message.NewGroupImage(binary.CalculateImageResourceId(hash), hash, rsp.FileId, size, rsp.Width, rsp.Height, 1000), nil } return nil, errors.New("image does not exist") } diff --git a/message/image.go b/message/image.go index 92c9db84..1bea6d82 100644 --- a/message/image.go +++ b/message/image.go @@ -16,6 +16,8 @@ type GroupImageElement struct { ImageType int32 ImageBizType ImageBizType Size int32 + Width int32 + Height int32 Md5 []byte Url string @@ -62,13 +64,15 @@ const ( /* ------ Implementations ------ */ -func NewGroupImage(id string, md5 []byte, fid int64, size, imageType int32) *GroupImageElement { +func NewGroupImage(id string, md5 []byte, fid int64, size, width, height, imageType int32) *GroupImageElement { return &GroupImageElement{ ImageId: id, FileId: fid, Md5: md5, Size: size, ImageType: imageType, + Width: width, + Height: height, Url: "https://gchat.qpic.cn/gchatpic_new/1/0-0-" + strings.ReplaceAll(binary.CalculateImageResourceId(md5)[1:37], "-", "") + "/0?term=2", } } @@ -86,13 +90,21 @@ 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), // Origin: 1, BizType: proto.Int32(5), - Width: proto.Int32(720), - Height: proto.Int32(480), + Width: &e.Width, + Height: &e.Height, FileId: proto.Int32(int32(e.FileId)), FilePath: &e.ImageId, ImageType: &e.ImageType, diff --git a/message/message.go b/message/message.go index c1189862..c585c009 100644 --- a/message/message.go +++ b/message/message.go @@ -462,6 +462,8 @@ func ParseMessageElems(elems []*msg.Elem) []IMessageElement { FileId: int64(elem.CustomFace.GetFileId()), ImageId: elem.CustomFace.GetFilePath(), Size: elem.CustomFace.GetSize(), + Width: elem.CustomFace.GetWidth(), + Height: elem.CustomFace.GetHeight(), Url: url, ImageBizType: func() ImageBizType { if len(elem.CustomFace.PbReserve) == 0 { @@ -559,6 +561,8 @@ func ParseMessageElems(elems []*msg.Elem) []IMessageElement { FileId: int64(flash.FlashTroopPic.GetFileId()), ImageId: flash.FlashTroopPic.GetFilePath(), Size: flash.FlashTroopPic.GetSize(), + Width: flash.FlashTroopPic.GetWidth(), + Height: flash.FlashTroopPic.GetHeight(), Md5: flash.FlashTroopPic.Md5, Flash: true, }) From 4f3862fd875086e3dd88e118aab5a0c9b40ae65b Mon Sep 17 00:00:00 2001 From: Lin <36601667+buhuang28@users.noreply.github.com> Date: Thu, 6 Jan 2022 20:52:09 +0800 Subject: [PATCH 11/14] fix socket block (#236) --- client/internal/highway/highway.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/client/internal/highway/highway.go b/client/internal/highway/highway.go index 638d5a79..0e74b5a8 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" @@ -48,7 +49,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") } From 49cec45733affc04216444d0c29e9b7a1e4b492d Mon Sep 17 00:00:00 2001 From: fumiama Date: Sat, 15 Jan 2022 17:15:27 +0800 Subject: [PATCH 12/14] fix: rename icmp to tcp --- client/network.go | 4 ++-- utils/{icmp.go => tcping.go} | 8 ++++---- utils/{icmp_test.go => tcping_test.go} | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) rename utils/{icmp.go => tcping.go} (82%) rename utils/{icmp_test.go => tcping_test.go} (73%) diff --git a/client/network.go b/client/network.go index ac609b0f..d5cbf229 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(c.servers[c.currServerIndex].String(), 10) + res := utils.RunTCPPingLoop(c.servers[c.currServerIndex].String(), 10) r.ChatServerPacketLoss = res.PacketsLoss if c.highwaySession.AddrLength() > 0 { - res = utils.RunICMPPingLoop(c.highwaySession.SsoAddr[0].String(), 10) + res = utils.RunTCPPingLoop(c.highwaySession.SsoAddr[0].String(), 10) r.SrvServerPacketLoss = res.PacketsLoss } }() diff --git a/utils/icmp.go b/utils/tcping.go similarity index 82% rename from utils/icmp.go rename to utils/tcping.go index 886c3beb..4b899673 100644 --- a/utils/icmp.go +++ b/utils/tcping.go @@ -12,8 +12,8 @@ type ICMPPingResult struct { AvgTimeMill int64 } -// RunICMPPingLoop tcp 伪装的 icmp -func RunICMPPingLoop(ipport string, count int) (r ICMPPingResult) { +// RunTCPPingLoop 使用 tcp 进行 ping +func RunTCPPingLoop(ipport string, count int) (r ICMPPingResult) { r = ICMPPingResult{ PacketsSent: count, PacketsLoss: count, @@ -24,7 +24,7 @@ func RunICMPPingLoop(ipport string, count int) (r ICMPPingResult) { } durs := make([]int64, 0, count) for i := 0; i < count; i++ { - d, err := pingtcp(ipport) + d, err := tcping(ipport) if err == nil { r.PacketsLoss-- durs = append(durs, d) @@ -45,7 +45,7 @@ func RunICMPPingLoop(ipport string, count int) (r ICMPPingResult) { return } -func pingtcp(ipport string) (int64, error) { +func tcping(ipport string) (int64, error) { t := time.Now().UnixMilli() conn, err := net.DialTimeout("tcp", ipport, time.Second*2) if err != nil { diff --git a/utils/icmp_test.go b/utils/tcping_test.go similarity index 73% rename from utils/icmp_test.go rename to utils/tcping_test.go index b173b3b5..6ad4c42c 100644 --- a/utils/icmp_test.go +++ b/utils/tcping_test.go @@ -5,7 +5,7 @@ import ( ) func TestPing(t *testing.T) { - r := RunICMPPingLoop("127.0.0.1:23333", 4) + r := RunTCPPingLoop("127.0.0.1:23333", 4) if r.PacketsLoss == r.PacketsSent { t.Fatal(r) } From 38bb31b5a66607f4af0b0f86cd781a711c3c9b0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=BA=90=E6=96=87=E9=9B=A8?= <41315874+fumiama@users.noreply.github.com> Date: Sat, 15 Jan 2022 18:37:26 +0800 Subject: [PATCH 13/14] feat(image): drop redundant bytewise comparing of gif (#243) * feat(image): drop rebundant bytewise comparing of gif * feat(image): drop redundant bytewise comparing of gif --- client/image.go | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/client/image.go b/client/image.go index 3e3ebb69..1ca5de55 100644 --- a/client/image.go +++ b/client/image.go @@ -82,12 +82,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, _, _ := imgsz.DecodeSize(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 @@ -135,12 +132,9 @@ func (c *QQClient) UploadGroupImageByFile(groupCode int64, path string) (*messag return nil, errors.Wrap(err, "upload failed") ok: _, _ = img.Seek(0, io.SeekStart) - i, _, _ := imgsz.DecodeSize(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 From 3b461554b747257ab08651a6d7ebd711decda3b4 Mon Sep 17 00:00:00 2001 From: Mrs4s Date: Tue, 18 Jan 2022 00:50:08 +0800 Subject: [PATCH 14/14] fix highway memory leak --- client/internal/highway/highway.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/client/internal/highway/highway.go b/client/internal/highway/highway.go index 0e74b5a8..7d7c1ab0 100644 --- a/client/internal/highway/highway.go +++ b/client/internal/highway/highway.go @@ -28,6 +28,8 @@ type Session struct { seq int32 } +const highwayMaxResponseSize int32 = 1024 * 100 // 100k + func (s *Session) AddrLength() int { return len(s.SsoAddr) } @@ -247,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()