first commit
This commit is contained in:
@@ -0,0 +1,218 @@
|
||||
package mmtls
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"sync/atomic"
|
||||
|
||||
"xiawan/wx/clientsdk/baseutils"
|
||||
|
||||
"golang.org/x/net/proxy"
|
||||
)
|
||||
|
||||
// InitMMTLSInfoLong 初始化MMTLS信息通过长链接
|
||||
func InitMMTLSInfoLong(dialer proxy.Dialer, longHostName string, shortHostName string, pskList []*Psk) (*MMInfo, error) {
|
||||
// 初始化MMInfo
|
||||
mmInfo := CreateNewMMInfo()
|
||||
mmInfo.ShortHost = shortHostName
|
||||
mmInfo.LongHost = longHostName
|
||||
mmInfo.Dialer = dialer
|
||||
// 第一次设置为空,后面设置成前面握手返回的Psk列表
|
||||
mmInfo.ShortPskList = pskList
|
||||
// 随机生成ClientEcdhKeys,握手用
|
||||
mmInfo.ClientEcdhKeys = CreateClientEcdhKeys()
|
||||
|
||||
// 开始握手
|
||||
err := MMHandShakeByLongLink(mmInfo)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 发送一次心跳包
|
||||
err = SendHeartBeat(mmInfo)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 握手成功,设置短链接的HOST 和 新的URL
|
||||
shortURL := []byte("/mmtls/")
|
||||
mmInfo.ShortURL = string(append(shortURL, []byte(baseutils.RandomSmallHexString(8))[0:]...))
|
||||
|
||||
return mmInfo, nil
|
||||
}
|
||||
|
||||
// MMHandShakeByLongLink 长链接握手(与短链接握手类似,只需选择其中一种握手方式,微信是采用长链接握手,每次登陆前都需要握手)
|
||||
func MMHandShakeByLongLink(mmInfo *MMInfo) error {
|
||||
// 发送握手请求 - ClientHello
|
||||
clientHelloData := CreateHandShakeClientHelloData(mmInfo)
|
||||
sendData := CreateRecordData(ServerHandShakeType, clientHelloData)
|
||||
|
||||
// 发送ClientHello
|
||||
err := MMTCPSendData(mmInfo, sendData)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 接收响应
|
||||
retItems, err := MMTCPRecvItems(mmInfo)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 处理握手信息
|
||||
clientFinishedData, err := DealHandShakePackItems(mmInfo, retItems, clientHelloData)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 发送clientFinished, 长链接必须要发送,但服务器不会响应
|
||||
err = MMTCPSendData(mmInfo, clientFinishedData)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// SendHeartBeat 发送心跳包
|
||||
func SendHeartBeat(mmInfo *MMInfo) error {
|
||||
// 发送心跳包
|
||||
heartData, err := GetHeartBeatData(mmInfo)
|
||||
err = MMTCPSendData(mmInfo, heartData)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 接收心跳包响应
|
||||
retItem, err := MMTCPRecvOneItem(mmInfo)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 解析心跳包响应数据,但不需处理
|
||||
_, err = MMLongUnPackData(mmInfo, retItem)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetHeartBeatData 获取心跳包数据
|
||||
func GetHeartBeatData(mmInfo *MMInfo) ([]byte, error) {
|
||||
retBytes := make([]byte, 0)
|
||||
|
||||
bodyData := make([]byte, 0)
|
||||
// LongPackTagInfo
|
||||
packTagInfo := &LongPackHeaderInfo{}
|
||||
packTagInfo.HeaderLen = 16
|
||||
packTagInfo.Version = MMLongVersion
|
||||
packTagInfo.Operation = MMLongOperationSmartHeartBeat
|
||||
packTagInfo.SequenceNumber = 0xffffffff
|
||||
tagInfoBytes := LongPackHeaderInfoSerialize(packTagInfo)
|
||||
|
||||
// BodyData
|
||||
dataLength := uint32(len(tagInfoBytes) + 4)
|
||||
bodyData = append(bodyData, baseutils.Int32ToBytes(dataLength)[0:]...)
|
||||
bodyData = append(bodyData, tagInfoBytes[0:]...)
|
||||
|
||||
// RecordHead
|
||||
tmpLen := uint16(dataLength + 16)
|
||||
recordHeader := GetRecordDataByLength(BodyType, tmpLen)
|
||||
|
||||
clientSeq := atomic.AddUint32(&mmInfo.LONGClientSeq, 1) - 1
|
||||
// 加密
|
||||
tmpNonce := GetNonce(mmInfo.LongHdkfKey.EncodeNonce, uint32(clientSeq))
|
||||
tmpAad := []byte{0x00, 0x00, 0x00, 0x00}
|
||||
tmpAad = append(tmpAad, baseutils.Int32ToBytes(uint32(clientSeq))...)
|
||||
tmpAad = append(tmpAad, recordHeader...)
|
||||
encodeData, err := AesGcmEncrypt(mmInfo.LongHdkfKey.EncodeAesKey, tmpNonce, tmpAad, bodyData)
|
||||
if err != nil {
|
||||
return retBytes, err
|
||||
}
|
||||
|
||||
// 组包
|
||||
retBytes = append(retBytes, recordHeader...)
|
||||
retBytes = append(retBytes, encodeData...)
|
||||
|
||||
return retBytes, nil
|
||||
}
|
||||
|
||||
// MMLongPackData 长链接方式 打包请求数据
|
||||
func MMLongPackData(mmInfo *MMInfo, opCode uint32, data []byte) ([]byte, error) {
|
||||
retBytes := make([]byte, 0)
|
||||
|
||||
bodyData := make([]byte, 0)
|
||||
// LongPackTagInfo
|
||||
packTagInfo := &LongPackHeaderInfo{}
|
||||
packTagInfo.HeaderLen = 16
|
||||
packTagInfo.Version = MMLongVersion
|
||||
packTagInfo.Operation = opCode
|
||||
packTagInfo.SequenceNumber = atomic.LoadUint32(&mmInfo.LONGClientSeq)
|
||||
tagInfoBytes := LongPackHeaderInfoSerialize(packTagInfo)
|
||||
|
||||
// BodyData
|
||||
dataLength := uint32(len(data) + len(tagInfoBytes) + 4)
|
||||
bodyData = append(bodyData, baseutils.Int32ToBytes(dataLength)[0:]...)
|
||||
bodyData = append(bodyData, tagInfoBytes[0:]...)
|
||||
bodyData = append(bodyData, data[0:]...)
|
||||
|
||||
// RecordHead
|
||||
tmpLen := uint16(dataLength + 16)
|
||||
recordHeader := GetRecordDataByLength(BodyType, tmpLen)
|
||||
|
||||
// 加密
|
||||
tmpNonce := GetNonce(mmInfo.LongHdkfKey.EncodeNonce, atomic.LoadUint32(&mmInfo.LONGClientSeq))
|
||||
tmpAad := []byte{0x00, 0x00, 0x00, 0x00}
|
||||
tmpAad = append(tmpAad, baseutils.Int32ToBytes(atomic.LoadUint32(&mmInfo.LONGClientSeq))...)
|
||||
tmpAad = append(tmpAad, recordHeader...)
|
||||
encodeData, err := AesGcmEncrypt(mmInfo.LongHdkfKey.EncodeAesKey, tmpNonce, tmpAad, bodyData)
|
||||
if err != nil {
|
||||
return retBytes, err
|
||||
}
|
||||
|
||||
// 组包,ClientSeq 索引值+1
|
||||
atomic.AddUint32(&mmInfo.LONGClientSeq, 1)
|
||||
//mmInfo.LONGClientSeq++
|
||||
retBytes = append(retBytes, recordHeader...)
|
||||
retBytes = append(retBytes, encodeData...)
|
||||
return retBytes, nil
|
||||
}
|
||||
|
||||
// MMLongUnPackData 长链接方式 解包数据
|
||||
func MMLongUnPackData(mmInfo *MMInfo, packItem *PackItem) (*LongRecvInfo, error) {
|
||||
// 解密
|
||||
tmpNonce := GetNonce(mmInfo.LongHdkfKey.DecodeNonce, atomic.LoadUint32(&mmInfo.LONGServerSeq))
|
||||
tmpAad := []byte{0x00, 0x00, 0x00, 0x00}
|
||||
tmpAad = append(tmpAad, baseutils.Int32ToBytes(atomic.LoadUint32(&mmInfo.LONGServerSeq))...)
|
||||
tmpAad = append(tmpAad, packItem.RecordHead...)
|
||||
DecodeData, err := AesGcmDecrypt(mmInfo.LongHdkfKey.DecodeAesKey, tmpNonce, tmpAad, packItem.PackData)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// TotalLength
|
||||
current := 0
|
||||
totalLength := baseutils.BytesToInt32(DecodeData[current : current+4])
|
||||
current = current + 4
|
||||
if totalLength != uint32(len(DecodeData)) {
|
||||
return nil, errors.New("MMLongUnPackData err: totalLength != uint32(len(DecodeData))")
|
||||
}
|
||||
|
||||
headerInfo, err := LongPackHeaderInfoDeSerialize(DecodeData[current : current+12])
|
||||
current = current + 12
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
retLongRecvInfo := &LongRecvInfo{}
|
||||
retLongRecvInfo.HeaderInfo = headerInfo
|
||||
// 如果大于 说明是业务包,如果等于则是长链接心跳包
|
||||
if totalLength > uint32(headerInfo.HeaderLen) {
|
||||
retLongRecvInfo.RespData = DecodeData[current:]
|
||||
}
|
||||
|
||||
// ServerSeq 索引值+1
|
||||
//mmInfo.LONGServerSeq = mmInfo.LONGServerSeq + 1
|
||||
atomic.AddUint32(&mmInfo.LONGServerSeq, 1)
|
||||
return retLongRecvInfo, nil
|
||||
}
|
||||
Reference in New Issue
Block a user