1
0
mirror of https://github.com/Mrs4s/MiraiGo.git synced 2025-05-04 11:07:40 +08:00

Read bytes panic (#177)

* 修复 QQClint 中 netLoop c.TCP.ReadBytes 由于 conn 被设置为 nil 导致的空指针错误

Fixes: #171
This commit is contained in:
moyrne 2021-08-11 04:39:38 -05:00 committed by GitHub
parent 6614d2383a
commit 8a3d449b7d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 53 additions and 40 deletions

8
.idea/.gitignore generated vendored
View File

@ -1,8 +0,0 @@
# Default ignored files
/shelf/
/workspace.xml
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml
# Editor-based HTTP Client requests
/httpRequests/

View File

@ -4,12 +4,13 @@ import (
"encoding/binary" "encoding/binary"
"io" "io"
"net" "net"
"time" "sync"
"github.com/pkg/errors" "github.com/pkg/errors"
) )
type TCPListener struct { type TCPListener struct {
lock sync.RWMutex
conn net.Conn conn net.Conn
plannedDisconnect func(*TCPListener) plannedDisconnect func(*TCPListener)
unexpectedDisconnect func(*TCPListener, error) unexpectedDisconnect func(*TCPListener, error)
@ -34,40 +35,38 @@ func (t *TCPListener) Connect(addr *net.TCPAddr) error {
if err != nil { if err != nil {
return errors.Wrap(err, "dial tcp error") return errors.Wrap(err, "dial tcp error")
} }
t.lock.Lock()
defer t.lock.Unlock()
t.conn = conn t.conn = conn
return nil return nil
} }
func (t *TCPListener) Write(buf []byte) error { func (t *TCPListener) Write(buf []byte) error {
if t.conn == nil { err := t.rLockDo(func() error {
return ErrConnectionClosed _, e := t.conn.Write(buf)
return e
})
if err == nil {
return nil
} }
_, err := t.conn.Write(buf)
if err != nil { t.unexpectedClose(err)
if t.conn != nil { return ErrConnectionClosed
t.close()
t.invokeUnexpectedDisconnect(err)
}
return ErrConnectionClosed
}
return nil
} }
func (t *TCPListener) ReadBytes(len int) ([]byte, error) { func (t *TCPListener) ReadBytes(len int) ([]byte, error) {
if t.conn == nil {
return nil, ErrConnectionClosed
}
buf := make([]byte, len) buf := make([]byte, len)
_, err := io.ReadFull(t.conn, buf) err := t.rLockDo(func() error {
if err != nil { _, e := io.ReadFull(t.conn, buf)
time.Sleep(time.Millisecond * 100) // 服务器会发送offline包后立即断开连接, 此时还没解析, 可能还是得加锁 return e
if t.conn != nil { })
t.close() if err == nil {
t.invokeUnexpectedDisconnect(err) return buf, nil
}
return nil, ErrConnectionClosed
} }
return buf, nil
//time.Sleep(time.Millisecond * 100) // 服务器会发送offline包后立即断开连接, 此时还没解析, 可能还是得加锁
t.unexpectedClose(err)
return nil, ErrConnectionClosed
} }
func (t *TCPListener) ReadInt32() (int32, error) { func (t *TCPListener) ReadInt32() (int32, error) {
@ -79,19 +78,26 @@ func (t *TCPListener) ReadInt32() (int32, error) {
} }
func (t *TCPListener) Close() { func (t *TCPListener) Close() {
if t.conn == nil { if !t.connIsNil() {
return t.close()
t.invokePlannedDisconnect()
}
}
func (t *TCPListener) unexpectedClose(err error) {
if !t.connIsNil() {
t.close()
t.invokeUnexpectedDisconnect(err)
} }
t.close()
t.invokePlannedDisconnect()
} }
func (t *TCPListener) close() { func (t *TCPListener) close() {
if t.conn == nil { t.lock.Lock()
return defer t.lock.Unlock()
if t.conn != nil {
_ = t.conn.Close()
t.conn = nil
} }
_ = t.conn.Close()
t.conn = nil
} }
func (t *TCPListener) invokePlannedDisconnect() { func (t *TCPListener) invokePlannedDisconnect() {
@ -105,3 +111,18 @@ func (t *TCPListener) invokeUnexpectedDisconnect(err error) {
go t.unexpectedDisconnect(t, err) go t.unexpectedDisconnect(t, err)
} }
} }
func (t *TCPListener) rLockDo(fn func() error) error {
t.lock.RLock()
defer t.lock.RUnlock()
if t.conn == nil {
return ErrConnectionClosed
}
return fn()
}
func (t *TCPListener) connIsNil() bool {
t.lock.RLock()
defer t.lock.RUnlock()
return t.conn == nil
}