mirror of
https://github.com/FlourishingWorld/hk4e.git
synced 2026-02-17 03:12:27 +08:00
init commit
This commit is contained in:
387
gate-hk4e/net/kcp_connect_manager.go
Normal file
387
gate-hk4e/net/kcp_connect_manager.go
Normal file
@@ -0,0 +1,387 @@
|
||||
package net
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"flswld.com/common/config"
|
||||
"flswld.com/common/utils/random"
|
||||
"flswld.com/logger"
|
||||
"gate-hk4e/kcp"
|
||||
"io/ioutil"
|
||||
"strconv"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
type KcpXorKey struct {
|
||||
encKey []byte
|
||||
decKey []byte
|
||||
}
|
||||
|
||||
type KcpConnectManager struct {
|
||||
openState bool
|
||||
connMap map[uint64]*kcp.UDPSession
|
||||
connMapLock sync.RWMutex
|
||||
protoMsgInput chan *ProtoMsg
|
||||
protoMsgOutput chan *ProtoMsg
|
||||
kcpEventInput chan *KcpEvent
|
||||
kcpEventOutput chan *KcpEvent
|
||||
// 发送协程分发
|
||||
kcpRawSendChanMap map[uint64]chan *ProtoMsg
|
||||
kcpRawSendChanMapLock sync.RWMutex
|
||||
// 收包发包监听标志
|
||||
kcpRecvListenMap map[uint64]bool
|
||||
kcpRecvListenMapLock sync.RWMutex
|
||||
kcpSendListenMap map[uint64]bool
|
||||
kcpSendListenMapLock sync.RWMutex
|
||||
// key
|
||||
dispatchKey []byte
|
||||
secretKey []byte
|
||||
kcpKeyMap map[uint64]*KcpXorKey
|
||||
kcpKeyMapLock sync.RWMutex
|
||||
// conv短时间内唯一生成
|
||||
convGenMap map[uint64]int64
|
||||
convGenMapLock sync.RWMutex
|
||||
}
|
||||
|
||||
func NewKcpConnectManager(protoMsgInput chan *ProtoMsg, protoMsgOutput chan *ProtoMsg,
|
||||
kcpEventInput chan *KcpEvent, kcpEventOutput chan *KcpEvent) (r *KcpConnectManager) {
|
||||
r = new(KcpConnectManager)
|
||||
r.openState = true
|
||||
r.connMap = make(map[uint64]*kcp.UDPSession)
|
||||
r.protoMsgInput = protoMsgInput
|
||||
r.protoMsgOutput = protoMsgOutput
|
||||
r.kcpEventInput = kcpEventInput
|
||||
r.kcpEventOutput = kcpEventOutput
|
||||
r.kcpRawSendChanMap = make(map[uint64]chan *ProtoMsg)
|
||||
r.kcpRecvListenMap = make(map[uint64]bool)
|
||||
r.kcpSendListenMap = make(map[uint64]bool)
|
||||
r.kcpKeyMap = make(map[uint64]*KcpXorKey)
|
||||
r.convGenMap = make(map[uint64]int64)
|
||||
return r
|
||||
}
|
||||
|
||||
func (k *KcpConnectManager) Start() {
|
||||
go func() {
|
||||
// key
|
||||
var err error = nil
|
||||
k.dispatchKey, err = ioutil.ReadFile("static/dispatchKey.bin")
|
||||
if err != nil {
|
||||
logger.LOG.Error("open dispatchKey.bin error")
|
||||
return
|
||||
}
|
||||
k.secretKey, err = ioutil.ReadFile("static/secretKey.bin")
|
||||
if err != nil {
|
||||
logger.LOG.Error("open secretKey.bin error")
|
||||
return
|
||||
}
|
||||
// kcp
|
||||
port := strconv.FormatInt(int64(config.CONF.Hk4e.KcpPort), 10)
|
||||
listener, err := kcp.ListenWithOptions("0.0.0.0:"+port, nil, 0, 0)
|
||||
if err != nil {
|
||||
logger.LOG.Error("listen kcp err: %v", err)
|
||||
return
|
||||
} else {
|
||||
go k.enetHandle(listener)
|
||||
go k.chanSendHandle()
|
||||
go k.eventHandle()
|
||||
for {
|
||||
conn, err := listener.AcceptKCP()
|
||||
if err != nil {
|
||||
logger.LOG.Error("accept kcp err: %v", err)
|
||||
return
|
||||
}
|
||||
if k.openState == false {
|
||||
_ = conn.Close()
|
||||
continue
|
||||
}
|
||||
conn.SetACKNoDelay(true)
|
||||
conn.SetWriteDelay(false)
|
||||
convId := conn.GetConv()
|
||||
logger.LOG.Debug("client connect, convId: %v", convId)
|
||||
// 连接建立成功通知
|
||||
k.kcpEventOutput <- &KcpEvent{
|
||||
ConvId: convId,
|
||||
EventId: KcpConnEstNotify,
|
||||
EventMessage: conn.RemoteAddr().String(),
|
||||
}
|
||||
k.connMapLock.Lock()
|
||||
k.connMap[convId] = conn
|
||||
k.connMapLock.Unlock()
|
||||
k.kcpKeyMapLock.Lock()
|
||||
k.kcpKeyMap[convId] = &KcpXorKey{
|
||||
encKey: k.dispatchKey,
|
||||
decKey: k.dispatchKey,
|
||||
}
|
||||
k.kcpKeyMapLock.Unlock()
|
||||
go k.recvHandle(convId)
|
||||
kcpRawSendChan := make(chan *ProtoMsg, 10000)
|
||||
k.kcpRawSendChanMapLock.Lock()
|
||||
k.kcpRawSendChanMap[convId] = kcpRawSendChan
|
||||
k.kcpRawSendChanMapLock.Unlock()
|
||||
go k.sendHandle(convId, kcpRawSendChan)
|
||||
go k.rttMonitor(convId)
|
||||
}
|
||||
}
|
||||
}()
|
||||
go k.clearDeadConv()
|
||||
}
|
||||
|
||||
func (k *KcpConnectManager) clearDeadConv() {
|
||||
ticker := time.NewTicker(time.Minute)
|
||||
for {
|
||||
k.convGenMapLock.Lock()
|
||||
now := time.Now().UnixNano()
|
||||
oldConvList := make([]uint64, 0)
|
||||
for conv, timestamp := range k.convGenMap {
|
||||
if now-timestamp > int64(time.Hour) {
|
||||
oldConvList = append(oldConvList, conv)
|
||||
}
|
||||
}
|
||||
delConvList := make([]uint64, 0)
|
||||
k.connMapLock.RLock()
|
||||
for _, conv := range oldConvList {
|
||||
_, exist := k.connMap[conv]
|
||||
if !exist {
|
||||
delConvList = append(delConvList, conv)
|
||||
delete(k.convGenMap, conv)
|
||||
}
|
||||
}
|
||||
k.connMapLock.RUnlock()
|
||||
k.convGenMapLock.Unlock()
|
||||
logger.LOG.Info("clean dead conv list: %v", delConvList)
|
||||
<-ticker.C
|
||||
}
|
||||
}
|
||||
|
||||
func (k *KcpConnectManager) enetHandle(listener *kcp.Listener) {
|
||||
for {
|
||||
enetNotify := <-listener.EnetNotify
|
||||
logger.LOG.Info("[Enet Notify], addr: %v, conv: %v, conn: %v, enet: %v", enetNotify.Addr, enetNotify.ConvId, enetNotify.ConnType, enetNotify.EnetType)
|
||||
switch enetNotify.ConnType {
|
||||
case kcp.ConnEnetSyn:
|
||||
if enetNotify.EnetType == kcp.EnetClientConnectKey {
|
||||
var conv uint64
|
||||
k.convGenMapLock.Lock()
|
||||
for {
|
||||
convData := random.GetRandomByte(8)
|
||||
convDataBuffer := bytes.NewBuffer(convData)
|
||||
_ = binary.Read(convDataBuffer, binary.LittleEndian, &conv)
|
||||
_, exist := k.convGenMap[conv]
|
||||
if exist {
|
||||
continue
|
||||
} else {
|
||||
k.convGenMap[conv] = time.Now().UnixNano()
|
||||
break
|
||||
}
|
||||
}
|
||||
k.convGenMapLock.Unlock()
|
||||
listener.SendEnetNotifyToClient(&kcp.Enet{
|
||||
Addr: enetNotify.Addr,
|
||||
ConvId: conv,
|
||||
ConnType: kcp.ConnEnetEst,
|
||||
EnetType: enetNotify.EnetType,
|
||||
})
|
||||
}
|
||||
case kcp.ConnEnetEst:
|
||||
case kcp.ConnEnetFin:
|
||||
k.closeKcpConn(enetNotify.ConvId, enetNotify.EnetType)
|
||||
case kcp.ConnEnetAddrChange:
|
||||
// 连接地址改变通知
|
||||
k.kcpEventOutput <- &KcpEvent{
|
||||
ConvId: enetNotify.ConvId,
|
||||
EventId: KcpConnAddrChangeNotify,
|
||||
EventMessage: enetNotify.Addr,
|
||||
}
|
||||
default:
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (k *KcpConnectManager) chanSendHandle() {
|
||||
// 分发到每个连接具体的发送协程
|
||||
for {
|
||||
protoMsg := <-k.protoMsgInput
|
||||
k.kcpRawSendChanMapLock.RLock()
|
||||
kcpRawSendChan := k.kcpRawSendChanMap[protoMsg.ConvId]
|
||||
k.kcpRawSendChanMapLock.RUnlock()
|
||||
if kcpRawSendChan != nil {
|
||||
select {
|
||||
case kcpRawSendChan <- protoMsg:
|
||||
default:
|
||||
logger.LOG.Error("kcpRawSendChan is full, convId: %v", protoMsg.ConvId)
|
||||
}
|
||||
} else {
|
||||
logger.LOG.Error("kcpRawSendChan is nil, convId: %v", protoMsg.ConvId)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (k *KcpConnectManager) recvHandle(convId uint64) {
|
||||
// 接收
|
||||
k.connMapLock.RLock()
|
||||
conn := k.connMap[convId]
|
||||
k.connMapLock.RUnlock()
|
||||
pktFreqLimitCounter := 0
|
||||
pktFreqLimitTimer := time.Now().UnixNano()
|
||||
protoEnDecode := NewProtoEnDecode()
|
||||
recvBuf := make([]byte, conn.GetMaxPayloadLen())
|
||||
for {
|
||||
_ = conn.SetReadDeadline(time.Now().Add(time.Second * 30))
|
||||
recvLen, err := conn.Read(recvBuf)
|
||||
if err != nil {
|
||||
logger.LOG.Error("exit recv loop, conn read err: %v, convId: %v", err, convId)
|
||||
k.closeKcpConn(convId, kcp.EnetServerKick)
|
||||
break
|
||||
}
|
||||
pktFreqLimitCounter++
|
||||
now := time.Now().UnixNano()
|
||||
if now-pktFreqLimitTimer > int64(time.Second) {
|
||||
if pktFreqLimitCounter > 1000 {
|
||||
logger.LOG.Error("exit recv loop, client packet send freq too high, convId: %v, pps: %v", convId, pktFreqLimitCounter)
|
||||
k.closeKcpConn(convId, kcp.EnetPacketFreqTooHigh)
|
||||
break
|
||||
} else {
|
||||
pktFreqLimitCounter = 0
|
||||
}
|
||||
pktFreqLimitTimer = now
|
||||
}
|
||||
recvData := recvBuf[:recvLen]
|
||||
k.kcpRecvListenMapLock.RLock()
|
||||
flag := k.kcpRecvListenMap[convId]
|
||||
k.kcpRecvListenMapLock.RUnlock()
|
||||
if flag {
|
||||
// 收包通知
|
||||
//recvMsg := make([]byte, len(recvData))
|
||||
//copy(recvMsg, recvData)
|
||||
k.kcpEventOutput <- &KcpEvent{
|
||||
ConvId: convId,
|
||||
EventId: KcpPacketRecvNotify,
|
||||
EventMessage: recvData,
|
||||
}
|
||||
}
|
||||
kcpMsgList := make([]*KcpMsg, 0)
|
||||
k.decodeBinToPayload(recvData, convId, &kcpMsgList)
|
||||
for _, v := range kcpMsgList {
|
||||
protoMsgList := protoEnDecode.protoDecode(v)
|
||||
for _, vv := range protoMsgList {
|
||||
k.protoMsgOutput <- vv
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (k *KcpConnectManager) sendHandle(convId uint64, kcpRawSendChan chan *ProtoMsg) {
|
||||
// 发送
|
||||
k.connMapLock.RLock()
|
||||
conn := k.connMap[convId]
|
||||
k.connMapLock.RUnlock()
|
||||
protoEnDecode := NewProtoEnDecode()
|
||||
for {
|
||||
protoMsg, ok := <-kcpRawSendChan
|
||||
if !ok {
|
||||
logger.LOG.Error("exit send loop, send chan close, convId: %v", convId)
|
||||
k.closeKcpConn(convId, kcp.EnetServerKick)
|
||||
break
|
||||
}
|
||||
kcpMsg := protoEnDecode.protoEncode(protoMsg)
|
||||
if kcpMsg == nil {
|
||||
logger.LOG.Error("decode kcp msg is nil, convId: %v", convId)
|
||||
continue
|
||||
}
|
||||
bin := k.encodePayloadToBin(kcpMsg)
|
||||
_ = conn.SetWriteDeadline(time.Now().Add(time.Second * 10))
|
||||
_, err := conn.Write(bin)
|
||||
if err != nil {
|
||||
logger.LOG.Error("exit send loop, conn write err: %v, convId: %v", err, convId)
|
||||
k.closeKcpConn(convId, kcp.EnetServerKick)
|
||||
break
|
||||
}
|
||||
k.kcpSendListenMapLock.RLock()
|
||||
flag := k.kcpSendListenMap[convId]
|
||||
k.kcpSendListenMapLock.RUnlock()
|
||||
if flag {
|
||||
// 发包通知
|
||||
k.kcpEventOutput <- &KcpEvent{
|
||||
ConvId: convId,
|
||||
EventId: KcpPacketSendNotify,
|
||||
EventMessage: bin,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (k *KcpConnectManager) rttMonitor(convId uint64) {
|
||||
ticker := time.NewTicker(time.Second * 10)
|
||||
for {
|
||||
select {
|
||||
case <-ticker.C:
|
||||
k.connMapLock.RLock()
|
||||
conn := k.connMap[convId]
|
||||
k.connMapLock.RUnlock()
|
||||
if conn == nil {
|
||||
break
|
||||
}
|
||||
logger.LOG.Debug("convId: %v, RTO: %v, SRTT: %v, RTTVar: %v", convId, conn.GetRTO(), conn.GetSRTT(), conn.GetSRTTVar())
|
||||
k.kcpEventOutput <- &KcpEvent{
|
||||
ConvId: convId,
|
||||
EventId: KcpConnRttNotify,
|
||||
EventMessage: conn.GetSRTT(),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (k *KcpConnectManager) closeKcpConn(convId uint64, enetType uint32) {
|
||||
k.connMapLock.RLock()
|
||||
conn, exist := k.connMap[convId]
|
||||
k.connMapLock.RUnlock()
|
||||
if !exist {
|
||||
return
|
||||
}
|
||||
// 获取待关闭的发送管道
|
||||
k.kcpRawSendChanMapLock.RLock()
|
||||
kcpRawSendChan := k.kcpRawSendChanMap[convId]
|
||||
k.kcpRawSendChanMapLock.RUnlock()
|
||||
// 清理数据
|
||||
k.connMapLock.Lock()
|
||||
delete(k.connMap, convId)
|
||||
k.connMapLock.Unlock()
|
||||
k.kcpRawSendChanMapLock.Lock()
|
||||
delete(k.kcpRawSendChanMap, convId)
|
||||
k.kcpRawSendChanMapLock.Unlock()
|
||||
k.kcpRecvListenMapLock.Lock()
|
||||
delete(k.kcpRecvListenMap, convId)
|
||||
k.kcpRecvListenMapLock.Unlock()
|
||||
k.kcpSendListenMapLock.Lock()
|
||||
delete(k.kcpSendListenMap, convId)
|
||||
k.kcpSendListenMapLock.Unlock()
|
||||
k.kcpKeyMapLock.Lock()
|
||||
delete(k.kcpKeyMap, convId)
|
||||
k.kcpKeyMapLock.Unlock()
|
||||
// 关闭连接
|
||||
conn.SendEnetNotify(&kcp.Enet{
|
||||
ConnType: kcp.ConnEnetFin,
|
||||
EnetType: enetType,
|
||||
})
|
||||
_ = conn.Close()
|
||||
// 关闭发送管道
|
||||
close(kcpRawSendChan)
|
||||
// 连接关闭通知
|
||||
k.kcpEventOutput <- &KcpEvent{
|
||||
ConvId: convId,
|
||||
EventId: KcpConnCloseNotify,
|
||||
}
|
||||
}
|
||||
|
||||
func (k *KcpConnectManager) closeAllKcpConn() {
|
||||
closeConnList := make([]*kcp.UDPSession, 0)
|
||||
k.connMapLock.RLock()
|
||||
for _, v := range k.connMap {
|
||||
closeConnList = append(closeConnList, v)
|
||||
}
|
||||
k.connMapLock.RUnlock()
|
||||
for _, v := range closeConnList {
|
||||
k.closeKcpConn(v.GetConv(), kcp.EnetServerShutdown)
|
||||
}
|
||||
}
|
||||
187
gate-hk4e/net/kcp_endecode.go
Normal file
187
gate-hk4e/net/kcp_endecode.go
Normal file
@@ -0,0 +1,187 @@
|
||||
package net
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"flswld.com/common/utils/endec"
|
||||
"flswld.com/logger"
|
||||
)
|
||||
|
||||
/*
|
||||
原神KCP协议(带*为xor加密数据)
|
||||
0 1 2 4 8(字节)
|
||||
+---------------------------------------------------------------------------------------+
|
||||
| conv |
|
||||
+---------------------------------------------------------------------------------------+
|
||||
| cmd | frg | wnd | ts |
|
||||
+---------------------------------------------------------------------------------------+
|
||||
| sn | una |
|
||||
+---------------------------------------------------------------------------------------+
|
||||
| len | 0X4567* | apiId* |
|
||||
+---------------------------------------------------------------------------------------+
|
||||
| headLen* | payloadLen* | head* |
|
||||
+---------------------------------------------------------------------------------------+
|
||||
| payload* | 0X89AB* |
|
||||
+---------------------------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
type KcpMsg struct {
|
||||
ConvId uint64
|
||||
ApiId uint16
|
||||
HeadData []byte
|
||||
ProtoData []byte
|
||||
}
|
||||
|
||||
func (k *KcpConnectManager) decodeBinToPayload(data []byte, convId uint64, kcpMsgList *[]*KcpMsg) {
|
||||
// xor解密
|
||||
k.kcpKeyMapLock.RLock()
|
||||
xorKey, exist := k.kcpKeyMap[convId]
|
||||
k.kcpKeyMapLock.RUnlock()
|
||||
if !exist {
|
||||
logger.LOG.Error("kcp xor key not exist, convId: %v", convId)
|
||||
return
|
||||
}
|
||||
endec.Xor(data, xorKey.decKey)
|
||||
k.decodeRecur(data, convId, kcpMsgList)
|
||||
}
|
||||
|
||||
func (k *KcpConnectManager) decodeRecur(data []byte, convId uint64, kcpMsgList *[]*KcpMsg) {
|
||||
// 长度太短
|
||||
if len(data) < 12 {
|
||||
logger.LOG.Debug("packet len less 12 byte")
|
||||
return
|
||||
}
|
||||
// 头部标志错误
|
||||
if data[0] != 0x45 || data[1] != 0x67 {
|
||||
logger.LOG.Error("packet head magic 0x4567 error")
|
||||
return
|
||||
}
|
||||
// 协议号
|
||||
apiIdByteSlice := make([]byte, 8)
|
||||
apiIdByteSlice[6] = data[2]
|
||||
apiIdByteSlice[7] = data[3]
|
||||
apiIdBuffer := bytes.NewBuffer(apiIdByteSlice)
|
||||
var apiId int64
|
||||
err := binary.Read(apiIdBuffer, binary.BigEndian, &apiId)
|
||||
if err != nil {
|
||||
logger.LOG.Error("packet api id parse fail: %v", err)
|
||||
return
|
||||
}
|
||||
// 头部长度
|
||||
headLenByteSlice := make([]byte, 8)
|
||||
headLenByteSlice[6] = data[4]
|
||||
headLenByteSlice[7] = data[5]
|
||||
headLenBuffer := bytes.NewBuffer(headLenByteSlice)
|
||||
var headLen int64
|
||||
err = binary.Read(headLenBuffer, binary.BigEndian, &headLen)
|
||||
if err != nil {
|
||||
logger.LOG.Error("packet head len parse fail: %v", err)
|
||||
return
|
||||
}
|
||||
// proto长度
|
||||
protoLenByteSlice := make([]byte, 8)
|
||||
protoLenByteSlice[4] = data[6]
|
||||
protoLenByteSlice[5] = data[7]
|
||||
protoLenByteSlice[6] = data[8]
|
||||
protoLenByteSlice[7] = data[9]
|
||||
protoLenBuffer := bytes.NewBuffer(protoLenByteSlice)
|
||||
var protoLen int64
|
||||
err = binary.Read(protoLenBuffer, binary.BigEndian, &protoLen)
|
||||
if err != nil {
|
||||
logger.LOG.Error("packet proto len parse fail: %v", err)
|
||||
return
|
||||
}
|
||||
// 检查最小长度
|
||||
if len(data) < int(headLen+protoLen)+12 {
|
||||
logger.LOG.Error("packet len error")
|
||||
return
|
||||
}
|
||||
// 尾部标志错误
|
||||
if data[headLen+protoLen+10] != 0x89 || data[headLen+protoLen+11] != 0xAB {
|
||||
logger.LOG.Error("packet tail magic 0x89AB error")
|
||||
return
|
||||
}
|
||||
// 判断是否有不止一个包
|
||||
haveMoreData := false
|
||||
if len(data) > int(headLen+protoLen)+12 {
|
||||
haveMoreData = true
|
||||
}
|
||||
// 头部数据
|
||||
headData := data[10 : 10+headLen]
|
||||
// proto数据
|
||||
protoData := data[10+headLen : 10+headLen+protoLen]
|
||||
// 返回数据
|
||||
kcpMsg := new(KcpMsg)
|
||||
kcpMsg.ConvId = convId
|
||||
kcpMsg.ApiId = uint16(apiId)
|
||||
//kcpMsg.HeadData = make([]byte, len(headData))
|
||||
//copy(kcpMsg.HeadData, headData)
|
||||
//kcpMsg.ProtoData = make([]byte, len(protoData))
|
||||
//copy(kcpMsg.ProtoData, protoData)
|
||||
kcpMsg.HeadData = headData
|
||||
kcpMsg.ProtoData = protoData
|
||||
*kcpMsgList = append(*kcpMsgList, kcpMsg)
|
||||
// 递归解析
|
||||
if haveMoreData {
|
||||
k.decodeRecur(data[int(headLen+protoLen)+12:], convId, kcpMsgList)
|
||||
}
|
||||
}
|
||||
|
||||
func (k *KcpConnectManager) encodePayloadToBin(kcpMsg *KcpMsg) (bin []byte) {
|
||||
if kcpMsg.HeadData == nil {
|
||||
kcpMsg.HeadData = make([]byte, 0)
|
||||
}
|
||||
if kcpMsg.ProtoData == nil {
|
||||
kcpMsg.ProtoData = make([]byte, 0)
|
||||
}
|
||||
bin = make([]byte, len(kcpMsg.HeadData)+len(kcpMsg.ProtoData)+12)
|
||||
// 头部标志
|
||||
bin[0] = 0x45
|
||||
bin[1] = 0x67
|
||||
// 协议号
|
||||
apiIdBuffer := bytes.NewBuffer([]byte{})
|
||||
err := binary.Write(apiIdBuffer, binary.BigEndian, kcpMsg.ApiId)
|
||||
if err != nil {
|
||||
logger.LOG.Error("api id encode err: %v", err)
|
||||
return nil
|
||||
}
|
||||
bin[2] = (apiIdBuffer.Bytes())[0]
|
||||
bin[3] = (apiIdBuffer.Bytes())[1]
|
||||
// 头部长度
|
||||
headLenBuffer := bytes.NewBuffer([]byte{})
|
||||
err = binary.Write(headLenBuffer, binary.BigEndian, uint16(len(kcpMsg.HeadData)))
|
||||
if err != nil {
|
||||
logger.LOG.Error("head len encode err: %v", err)
|
||||
return nil
|
||||
}
|
||||
bin[4] = (headLenBuffer.Bytes())[0]
|
||||
bin[5] = (headLenBuffer.Bytes())[1]
|
||||
// proto长度
|
||||
protoLenBuffer := bytes.NewBuffer([]byte{})
|
||||
err = binary.Write(protoLenBuffer, binary.BigEndian, uint32(len(kcpMsg.ProtoData)))
|
||||
if err != nil {
|
||||
logger.LOG.Error("proto len encode err: %v", err)
|
||||
return nil
|
||||
}
|
||||
bin[6] = (protoLenBuffer.Bytes())[0]
|
||||
bin[7] = (protoLenBuffer.Bytes())[1]
|
||||
bin[8] = (protoLenBuffer.Bytes())[2]
|
||||
bin[9] = (protoLenBuffer.Bytes())[3]
|
||||
// 头部数据
|
||||
copy(bin[10:], kcpMsg.HeadData)
|
||||
// proto数据
|
||||
copy(bin[10+len(kcpMsg.HeadData):], kcpMsg.ProtoData)
|
||||
// 尾部标志
|
||||
bin[len(bin)-2] = 0x89
|
||||
bin[len(bin)-1] = 0xAB
|
||||
// xor加密
|
||||
k.kcpKeyMapLock.RLock()
|
||||
xorKey, exist := k.kcpKeyMap[kcpMsg.ConvId]
|
||||
k.kcpKeyMapLock.RUnlock()
|
||||
if !exist {
|
||||
logger.LOG.Error("kcp xor key not exist, convId: %v", kcpMsg.ConvId)
|
||||
return
|
||||
}
|
||||
endec.Xor(bin, xorKey.encKey)
|
||||
return bin
|
||||
}
|
||||
134
gate-hk4e/net/kcp_event.go
Normal file
134
gate-hk4e/net/kcp_event.go
Normal file
@@ -0,0 +1,134 @@
|
||||
package net
|
||||
|
||||
import "flswld.com/logger"
|
||||
|
||||
const (
|
||||
KcpXorKeyChange = iota
|
||||
KcpPacketRecvListen
|
||||
KcpPacketSendListen
|
||||
KcpConnForceClose
|
||||
KcpAllConnForceClose
|
||||
KcpGateOpenState
|
||||
KcpPacketRecvNotify
|
||||
KcpPacketSendNotify
|
||||
KcpConnCloseNotify
|
||||
KcpConnEstNotify
|
||||
KcpConnRttNotify
|
||||
KcpConnAddrChangeNotify
|
||||
)
|
||||
|
||||
type KcpEvent struct {
|
||||
ConvId uint64
|
||||
EventId int
|
||||
EventMessage any
|
||||
}
|
||||
|
||||
func (k *KcpConnectManager) eventHandle() {
|
||||
// 事件处理
|
||||
for {
|
||||
event := <-k.kcpEventInput
|
||||
logger.LOG.Info("kcp manager recv event, ConvId: %v, EventId: %v, EventMessage: %v", event.ConvId, event.EventId, event.EventMessage)
|
||||
switch event.EventId {
|
||||
case KcpXorKeyChange:
|
||||
// XOR密钥切换
|
||||
k.connMapLock.RLock()
|
||||
_, exist := k.connMap[event.ConvId]
|
||||
k.connMapLock.RUnlock()
|
||||
if !exist {
|
||||
logger.LOG.Error("conn not exist, convId: %v", event.ConvId)
|
||||
continue
|
||||
}
|
||||
flag, ok := event.EventMessage.(string)
|
||||
if !ok {
|
||||
logger.LOG.Error("event KcpXorKeyChange msg type error")
|
||||
continue
|
||||
}
|
||||
if flag == "ENC" {
|
||||
k.kcpKeyMapLock.Lock()
|
||||
k.kcpKeyMap[event.ConvId].encKey = k.secretKey
|
||||
k.kcpKeyMapLock.Unlock()
|
||||
} else if flag == "DEC" {
|
||||
k.kcpKeyMapLock.Lock()
|
||||
k.kcpKeyMap[event.ConvId].decKey = k.secretKey
|
||||
k.kcpKeyMapLock.Unlock()
|
||||
}
|
||||
case KcpPacketRecvListen:
|
||||
// 收包监听
|
||||
k.connMapLock.RLock()
|
||||
_, exist := k.connMap[event.ConvId]
|
||||
k.connMapLock.RUnlock()
|
||||
if !exist {
|
||||
logger.LOG.Error("conn not exist, convId: %v", event.ConvId)
|
||||
continue
|
||||
}
|
||||
flag, ok := event.EventMessage.(string)
|
||||
if !ok {
|
||||
logger.LOG.Error("event KcpXorKeyChange msg type error")
|
||||
continue
|
||||
}
|
||||
if flag == "Enable" {
|
||||
k.kcpRecvListenMapLock.Lock()
|
||||
k.kcpRecvListenMap[event.ConvId] = true
|
||||
k.kcpRecvListenMapLock.Unlock()
|
||||
} else if flag == "Disable" {
|
||||
k.kcpRecvListenMapLock.Lock()
|
||||
k.kcpRecvListenMap[event.ConvId] = false
|
||||
k.kcpRecvListenMapLock.Unlock()
|
||||
}
|
||||
case KcpPacketSendListen:
|
||||
// 发包监听
|
||||
k.connMapLock.RLock()
|
||||
_, exist := k.connMap[event.ConvId]
|
||||
k.connMapLock.RUnlock()
|
||||
if !exist {
|
||||
logger.LOG.Error("conn not exist, convId: %v", event.ConvId)
|
||||
continue
|
||||
}
|
||||
flag, ok := event.EventMessage.(string)
|
||||
if !ok {
|
||||
logger.LOG.Error("event KcpXorKeyChange msg type error")
|
||||
continue
|
||||
}
|
||||
if flag == "Enable" {
|
||||
k.kcpSendListenMapLock.Lock()
|
||||
k.kcpSendListenMap[event.ConvId] = true
|
||||
k.kcpSendListenMapLock.Unlock()
|
||||
} else if flag == "Disable" {
|
||||
k.kcpSendListenMapLock.Lock()
|
||||
k.kcpSendListenMap[event.ConvId] = false
|
||||
k.kcpSendListenMapLock.Unlock()
|
||||
}
|
||||
case KcpConnForceClose:
|
||||
// 强制关闭某个连接
|
||||
k.connMapLock.RLock()
|
||||
_, exist := k.connMap[event.ConvId]
|
||||
k.connMapLock.RUnlock()
|
||||
if !exist {
|
||||
logger.LOG.Error("conn not exist, convId: %v", event.ConvId)
|
||||
continue
|
||||
}
|
||||
reason, ok := event.EventMessage.(uint32)
|
||||
if !ok {
|
||||
logger.LOG.Error("event KcpConnForceClose msg type error")
|
||||
continue
|
||||
}
|
||||
k.closeKcpConn(event.ConvId, reason)
|
||||
logger.LOG.Info("conn has been force close, convId: %v", event.ConvId)
|
||||
case KcpAllConnForceClose:
|
||||
// 强制关闭所有连接
|
||||
k.closeAllKcpConn()
|
||||
logger.LOG.Info("all conn has been force close")
|
||||
case KcpGateOpenState:
|
||||
// 改变网关开放状态
|
||||
openState, ok := event.EventMessage.(bool)
|
||||
if !ok {
|
||||
logger.LOG.Error("event KcpGateOpenState msg type error")
|
||||
continue
|
||||
}
|
||||
k.openState = openState
|
||||
if openState == false {
|
||||
k.closeAllKcpConn()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
160
gate-hk4e/net/proto_endecode.go
Normal file
160
gate-hk4e/net/proto_endecode.go
Normal file
@@ -0,0 +1,160 @@
|
||||
package net
|
||||
|
||||
import (
|
||||
"flswld.com/gate-hk4e-api/proto"
|
||||
"flswld.com/logger"
|
||||
pb "google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
type ProtoEnDecode struct {
|
||||
apiProtoMap *proto.ApiProtoMap
|
||||
}
|
||||
|
||||
func NewProtoEnDecode() (r *ProtoEnDecode) {
|
||||
r = new(ProtoEnDecode)
|
||||
r.apiProtoMap = proto.NewApiProtoMap()
|
||||
return r
|
||||
}
|
||||
|
||||
type ProtoMsg struct {
|
||||
ConvId uint64
|
||||
ApiId uint16
|
||||
HeadMessage *proto.PacketHead
|
||||
PayloadMessage pb.Message
|
||||
}
|
||||
|
||||
type ProtoMessage struct {
|
||||
apiId uint16
|
||||
message pb.Message
|
||||
}
|
||||
|
||||
func (p *ProtoEnDecode) protoDecode(kcpMsg *KcpMsg) (protoMsgList []*ProtoMsg) {
|
||||
protoMsgList = make([]*ProtoMsg, 0)
|
||||
protoMsg := new(ProtoMsg)
|
||||
protoMsg.ConvId = kcpMsg.ConvId
|
||||
protoMsg.ApiId = kcpMsg.ApiId
|
||||
// head msg
|
||||
if kcpMsg.HeadData != nil && len(kcpMsg.HeadData) != 0 {
|
||||
headMsg := new(proto.PacketHead)
|
||||
err := pb.Unmarshal(kcpMsg.HeadData, headMsg)
|
||||
if err != nil {
|
||||
logger.LOG.Error("unmarshal head data err: %v", err)
|
||||
return protoMsgList
|
||||
}
|
||||
protoMsg.HeadMessage = headMsg
|
||||
} else {
|
||||
protoMsg.HeadMessage = nil
|
||||
}
|
||||
// payload msg
|
||||
protoMessageList := make([]*ProtoMessage, 0)
|
||||
p.protoDecodePayloadCore(kcpMsg.ApiId, kcpMsg.ProtoData, &protoMessageList)
|
||||
if len(protoMessageList) == 0 {
|
||||
logger.LOG.Error("decode proto object is nil")
|
||||
return protoMsgList
|
||||
}
|
||||
if kcpMsg.ApiId == proto.ApiUnionCmdNotify {
|
||||
for _, protoMessage := range protoMessageList {
|
||||
msg := new(ProtoMsg)
|
||||
msg.ConvId = kcpMsg.ConvId
|
||||
msg.ApiId = protoMessage.apiId
|
||||
msg.HeadMessage = protoMsg.HeadMessage
|
||||
msg.PayloadMessage = protoMessage.message
|
||||
//logger.LOG.Debug("[recv] union proto msg, convId: %v, apiId: %v", msg.ConvId, msg.ApiId)
|
||||
if protoMessage.apiId == proto.ApiUnionCmdNotify {
|
||||
// 聚合消息自身不再往后发送
|
||||
continue
|
||||
}
|
||||
//logger.LOG.Debug("[recv] proto msg, convId: %v, apiId: %v, headMsg: %v", protoMsg.ConvId, protoMsg.ApiId, protoMsg.HeadMessage)
|
||||
protoMsgList = append(protoMsgList, msg)
|
||||
}
|
||||
// 聚合消息自身不再往后发送
|
||||
return protoMsgList
|
||||
} else {
|
||||
protoMsg.PayloadMessage = protoMessageList[0].message
|
||||
}
|
||||
//logger.LOG.Debug("[recv] proto msg, convId: %v, apiId: %v, headMsg: %v", protoMsg.ConvId, protoMsg.ApiId, protoMsg.HeadMessage)
|
||||
protoMsgList = append(protoMsgList, protoMsg)
|
||||
return protoMsgList
|
||||
}
|
||||
|
||||
func (p *ProtoEnDecode) protoDecodePayloadCore(apiId uint16, protoData []byte, protoMessageList *[]*ProtoMessage) {
|
||||
protoObj := p.decodePayloadToProto(apiId, protoData)
|
||||
if protoObj == nil {
|
||||
logger.LOG.Error("decode proto object is nil")
|
||||
return
|
||||
}
|
||||
if apiId == proto.ApiUnionCmdNotify {
|
||||
// 处理聚合消息
|
||||
unionCmdNotify, ok := protoObj.(*proto.UnionCmdNotify)
|
||||
if !ok {
|
||||
logger.LOG.Error("parse union cmd error")
|
||||
return
|
||||
}
|
||||
for _, cmd := range unionCmdNotify.GetCmdList() {
|
||||
p.protoDecodePayloadCore(uint16(cmd.MessageId), cmd.Body, protoMessageList)
|
||||
}
|
||||
}
|
||||
*protoMessageList = append(*protoMessageList, &ProtoMessage{
|
||||
apiId: apiId,
|
||||
message: protoObj,
|
||||
})
|
||||
}
|
||||
|
||||
func (p *ProtoEnDecode) protoEncode(protoMsg *ProtoMsg) (kcpMsg *KcpMsg) {
|
||||
//logger.LOG.Debug("[send] proto msg, convId: %v, apiId: %v, headMsg: %v", protoMsg.ConvId, protoMsg.ApiId, protoMsg.HeadMessage)
|
||||
kcpMsg = new(KcpMsg)
|
||||
kcpMsg.ConvId = protoMsg.ConvId
|
||||
kcpMsg.ApiId = protoMsg.ApiId
|
||||
// head msg
|
||||
if protoMsg.HeadMessage != nil {
|
||||
headData, err := pb.Marshal(protoMsg.HeadMessage)
|
||||
if err != nil {
|
||||
logger.LOG.Error("marshal head data err: %v", err)
|
||||
return nil
|
||||
}
|
||||
kcpMsg.HeadData = headData
|
||||
} else {
|
||||
kcpMsg.HeadData = nil
|
||||
}
|
||||
// payload msg
|
||||
if protoMsg.PayloadMessage != nil {
|
||||
apiId, protoData := p.encodeProtoToPayload(protoMsg.PayloadMessage)
|
||||
if apiId == 0 || protoData == nil {
|
||||
logger.LOG.Error("encode proto data is nil")
|
||||
return nil
|
||||
}
|
||||
if apiId != 65535 && apiId != protoMsg.ApiId {
|
||||
logger.LOG.Error("api id is not match with proto obj, src api id: %v, found api id: %v", protoMsg.ApiId, apiId)
|
||||
return nil
|
||||
}
|
||||
kcpMsg.ProtoData = protoData
|
||||
} else {
|
||||
kcpMsg.ProtoData = nil
|
||||
}
|
||||
return kcpMsg
|
||||
}
|
||||
|
||||
func (p *ProtoEnDecode) decodePayloadToProto(apiId uint16, protoData []byte) (protoObj pb.Message) {
|
||||
protoObj = p.apiProtoMap.GetProtoObjByApiId(apiId)
|
||||
if protoObj == nil {
|
||||
logger.LOG.Error("get new proto object is nil")
|
||||
return nil
|
||||
}
|
||||
err := pb.Unmarshal(protoData, protoObj)
|
||||
if err != nil {
|
||||
logger.LOG.Error("unmarshal proto data err: %v", err)
|
||||
return nil
|
||||
}
|
||||
return protoObj
|
||||
}
|
||||
|
||||
func (p *ProtoEnDecode) encodeProtoToPayload(protoObj pb.Message) (apiId uint16, protoData []byte) {
|
||||
apiId = p.apiProtoMap.GetApiIdByProtoObj(protoObj)
|
||||
var err error = nil
|
||||
protoData, err = pb.Marshal(protoObj)
|
||||
if err != nil {
|
||||
logger.LOG.Error("marshal proto object err: %v", err)
|
||||
return 0, nil
|
||||
}
|
||||
return apiId, protoData
|
||||
}
|
||||
Reference in New Issue
Block a user