You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

920 lines
35 KiB

1 month ago
/*
Sog
2016 by zouwei
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography.X509Certificates;
using Sog;
using Sog.Crypto;
using Sog.Gate;
using Sog.IO;
using Sog.Log;
namespace Gate
{
public class GateClientService : BaseReloadableService
{
private ServerApp m_app;
ClientServiceData m_data;
private object m_clientDictLocker = new object();
private object m_needCloseClientsLocker = new object();
private long m_lastNotifyBackEndClientCountTimeMs = 0;
private int ZipClientMsgSize;
//接口实现
public override int GetServiceType()
{
return GateServiceType.GateClientService;
}
//接口实现
public override void Dispose()
{
//反注册消息处理,必须做这一步,否则内存泄漏,对象无法引用各种错误
m_data.m_socketListener.DataReceived -= socketListener_DataReceived;
m_data.m_socketListener.Connected -= socketListener_OnTcpConnectCompleted;
m_data.m_socketListener.Disconnected -= socketListener_Disconnected;
if (m_data.m_udpListener != null)
{
m_data.m_udpListener.DataReceived -= socketListener_DataReceived;
m_data.m_udpListener.Connected -= socketListener_OnUdpConnectCompleted;
m_data.m_udpListener.Disconnected -= socketListener_Disconnected;
}
if (m_data.m_webSessionListener != null)
{
m_data.m_webSessionListener.DataReceived -= socketListener_DataReceived;
m_data.m_webSessionListener.Connected -= socketListener_OnWebSocketConnectCompleted;
m_data.m_webSessionListener.Disconnected -= socketListener_Disconnected;
}
m_app = null;
m_data = null;
}
public GateClientService(ServerApp app)
{
m_app = app;
m_data = ServerDataObjMgr.GetDataObj<ClientServiceData>(GateDataObjType.ClientServiceData);
InitTCPListener();
// InitWebSocketListener();
InitUDPListener();
}
private void InitUDPListener()
{
if (m_data.m_udpListener == null)
{
m_data.m_socketSetting = new SessionSettings(10, 10, 10, 128000, GateServerUtils.GetServerConfig().listenport +1);
m_data.m_udpListener = new UdpListener(m_data.m_socketSetting, "GateClientUdpListener");
m_data.m_udpListener.DataReceived += socketListener_DataReceived;
m_data.m_udpListener.Connected += socketListener_OnUdpConnectCompleted;
m_data.m_udpListener.Disconnected += socketListener_Disconnected;
}
}
private void InitTCPListener()
{
if (m_data.m_socketListener == null)
{
SessionNetSelectMode nsMode = SessionNetSelectMode.Asynchronous;
string clusterNetmode = m_app.GetCluster().GetAppParamByKey("netmode");
var config = GateServerUtils.GetServerConfig();
m_app.GetCluster().SetNetMode(config.netMode);
if (config.netMode == 1)
{
nsMode = SessionNetSelectMode.Synchronous;
}
if (config.netMode == 0)
{
nsMode = clusterNetmode == "1" ?
SessionNetSelectMode.Synchronous : SessionNetSelectMode.Asynchronous;
}
TraceLog.Debug("GateClientService.GateClientService netmode SessionNetSelectMode is {0}", nsMode);
m_data.m_socketSetting = new SessionSettings(10, 10, 10, 128000, GateServerUtils.GetServerConfig().listenport);
m_data.m_socketListener = new SessionListener(m_app, m_data.m_socketSetting, "GateClientListener", nsMode);
if (nsMode == SessionNetSelectMode.Asynchronous)
{
TraceLog.Debug("GateClientService.GateClientService config.maxAsyncRecursionCount : {0}", config.maxAsyncRecursionCount);
m_data.m_socketListener.SetMaxAsyncRecursionCount(config.maxAsyncRecursionCount);
}
}
//注册消息处理
m_data.m_socketListener.DataReceived += socketListener_DataReceived;
m_data.m_socketListener.Connected += socketListener_OnTcpConnectCompleted;
m_data.m_socketListener.Disconnected += socketListener_Disconnected;
}
private void InitWebSocketListener()
{
TraceLog.Debug("GateClientService.InitWebSocketListener ");
if (m_data.m_webSessionListener == null)
{
SessionNetSelectMode nsMode = SessionNetSelectMode.Asynchronous;
string clusterNetmode = m_app.GetCluster().GetAppParamByKey("netmode");
var config = GateServerUtils.GetServerConfig();
m_app.GetCluster().SetNetMode(config.netMode);
if (config.netMode == 1)
{
nsMode = SessionNetSelectMode.Synchronous;
}
if (config.netMode == 0)
{
nsMode = clusterNetmode == "1" ?
SessionNetSelectMode.Synchronous : SessionNetSelectMode.Asynchronous;
}
TraceLog.Debug($"GateClientService.InitWebSocketListener {nsMode}");
var serverConfig = GateServerUtils.GetServerConfig();
m_data.m_socketSetting = new SessionSettings(10, 10, 10, 128000, serverConfig.websocketport);
m_data.m_webSessionListener = new WebSessionListener(m_app, m_data.m_socketSetting, "GateWebClientListener", nsMode);
if (serverConfig.websocketSecure)
{
TraceLog.Debug($"GateClientService.InitWebSocketListener open wss");
X509Certificate2 cert = new X509Certificate2(serverConfig.certificatePath, serverConfig.certificatePassword);
m_data.m_webSessionListener.SetSchemeAndCertificate(true, cert);
}
else
{
m_data.m_webSessionListener.SetSchemeAndCertificate(false);
}
if (nsMode == SessionNetSelectMode.Asynchronous)
{
m_data.m_webSessionListener.SetMaxAsyncRecursionCount(config.maxAsyncRecursionCount);
}
}
if (m_data.m_webSessionListener != null)
{
m_data.m_webSessionListener.DataReceived += socketListener_DataReceived;
m_data.m_webSessionListener.Connected += socketListener_OnWebSocketConnectCompleted;
m_data.m_webSessionListener.Disconnected += socketListener_Disconnected;
}
}
public void CloseListen()
{
m_data = ServerDataObjMgr.GetDataObj<ClientServiceData>(GateDataObjType.ClientServiceData);
m_data.m_socketListener.Close();
m_data.m_udpListener?.Close();
m_data.m_webSessionListener?.Close();
}
public void SetZipMsgSize(int size)
{
TraceLog.Trace("GateClientService.SetZipMsgSize {0}", size);
ZipClientMsgSize = size;
}
public void StartListen()
{
m_data.m_lastCheckTimeoutTime = m_app.GetTimeSecond();
m_data.m_socketListener?.StartListen(true);
//先取消upd
m_data.m_udpListener?.StartListen();
// m_data.m_webSessionListener?.StartListen(true);
}
public int GetClientCount()
{
return m_data.m_clientsDict.Count;
}
private void socketListener_OnTcpConnectCompleted(object sender, SessionEventArgs e)
{
try
{
long sessionID = Sog.Service.GateSessionID.GenNextID(m_app.ServerID);
e.Session.ResetSessionID(sessionID);
e.Session.SetSocketBufferSize(128000);
socketListener_OnConnectCompleted(sender, e);
}
catch (Exception ex)
{
TraceLog.Error("socketListener_OnTcpConnectCompleted error:{0}", ex);
}
}
private void socketListener_OnUdpConnectCompleted(object sender, SessionEventArgs e)
{
try
{
long sessionID = Sog.Service.GateSessionID.GenNextID(m_app.ServerID);
e.Session.ResetSessionID(sessionID);
socketListener_OnConnectCompleted(sender, e);
// debug
if (e.Session is UdpSession udpSession)
{
TraceLog.Trace("socketListener_OnUdpConnectCompleted conv {0} session {1}"
, udpSession.GetKcpConvId(), udpSession.SessionID);
}
else
{
TraceLog.Error("socketListener_OnUdpConnectCompleted session {0} not UdpSession"
, e.Session.SessionID);
}
}
catch (Exception ex)
{
TraceLog.Error("socketListener_OnUdpConnectCompleted error:{0}", ex);
}
}
private void socketListener_OnWebSocketConnectCompleted(object sender, SessionEventArgs e)
{
try
{
long sessionID = Sog.Service.GateSessionID.GenNextID(m_app.ServerID);
e.Session.ResetSessionID(sessionID);
// debug
if (e.Session is WebSession webSession)
{
TraceLog.Trace("socketListener_OnWebSocketConnectCompleted session {0}"
, webSession.SessionID);
}
else
{
TraceLog.Error("socketListener_OnTcpConnectCompleted session {0} not UdpSession"
, e.Session.SessionID);
}
socketListener_OnConnectCompleted(sender, e);
}
catch (Exception ex)
{
TraceLog.Error("socketListener_OnWebSocketConnectCompleted error:{0}", ex);
}
}
private void socketListener_Disconnected(object sender, SessionEventArgs e)
{
try
{
long sessionID = e.Session.SessionID;
TraceLog.Trace("socketListener_Disconnected session {0} disconneted ,notify to server", sessionID);
AddToNeedCloseClient(e.Session.SessionID);
}
catch (Exception err)
{
TraceLog.Error("socketListener_Disconnected Disconnected error:{0}", err);
}
}
private void socketListener_OnConnectCompleted(object sender, SessionEventArgs e)
{
try
{
long sessionID = e.Session.SessionID;
e.Session.WriteSendRecvLog = true;
GateClientInfo info = new GateClientInfo(m_app.GetTimeSecond(), e.Session);
//wait server ack
info.State = GameClientState.WaitServerAck;
lock (m_clientDictLocker)
{
m_data.m_clientsDict.Add(sessionID, info);
//加入等待队列
m_data.m_waitServerAckDict.Add(sessionID, info);
m_data.m_waitClientPublicKeyDict.Add(sessionID, info);
}
string ip = "0.0.0.0";
if(e.Session.RemoteEndPoint != null)
{
try
{
ip = e.Session.RemoteEndPoint.ToString().Split(':')[0];
}
catch(Exception)
{
}
}
if(e.Session is WebSession)
{
ip = ((WebSession)(e.Session)).clientIp;
}
TraceLog.Trace("socketListener_OnConnectCompleted session {0} ip {1} conneted, notify to server", sessionID, ip);
GateClientConnectedReq req = new GateClientConnectedReq();
req.IPAddress = ip;
GateServerUtils.GetServerMsgTrans().NotifyServerClientConnected(info, req);
}
catch (Exception err)
{
TraceLog.Error("socketListener_OnConnectCompleted ConnectCompleted error:{0}", err);
}
}
private void socketListener_DataReceived(object sender, SessionEventArgs e)
{
try
{
long sessionID = e.Session.SessionID;
int messageID = e.Message.Header.Type;
GateServerConfig configInfo = GateServerUtils.GetServerConfig();
GateClientInfo info = GetGateClientInfoThreadSafe(sessionID);
if (info == null)
{
TraceLog.Trace("socketListener_DataReceived session {0} no GateClientInfo", sessionID);
return;
}
if (configInfo.checkSeq)
{
ushort recvSeq = (ushort)(e.Message.Header.ServerID >> 16);
//检查seq
if (recvSeq != info.RecvSeq + 1)
{
TraceLog.Error("socketListener_DataReceived session {0}, seq {1} invalid last recv seq {2}"
, sessionID, recvSeq, info.RecvSeq);
AddToNeedCloseClient(info.SessionID);
return;
}
info.RecvSeq++;
ushort recvCrc = (ushort)(e.Message.Header.ServerID & 0xFFFF);
ushort crcValue = 0;
if (e.Message.Buffer.Data != null && e.Message.Buffer.Length > 0)
{
crcValue = CRC.CRC16(e.Message.Buffer.Data, e.Message.Buffer.Length);
}
if(recvCrc != crcValue)
{
TraceLog.Error("socketListener_DataReceived session {0}, calc crc {1} != recv crc {2}"
, sessionID, crcValue, recvCrc);
AddToNeedCloseClient(info.SessionID);
return;
}
}
//检查流量
if (configInfo.checkFlow)
{
GateServerUtils.OnAddOneMessage(info, configInfo, messageID, 1, e.Message.Header.Length);
if (info.FlowCheckInfo.aboveLimitTimes >= configInfo.maxLimitTimes)
{
if (configInfo.messageIgnoreLimitList == null ||
!configInfo.messageIgnoreLimitList.Contains(messageID))
{
TraceLog.Error("socketListener_DataReceived session:{0}, flow limit:{1}__{2} messageId={3}"
, sessionID, info.FlowCheckInfo.aboveLimitTimes, configInfo.maxLimitTimes,messageID);
AddToNeedCloseClient(info.SessionID);
return;
}
}
}
if (messageID == (int)SpecialMessageType.PublicKey)
{
TraceLog.TraceDetail("socketListener_DataReceived session {0} recv data len {1}, Type PublicKey"
, sessionID, e.Message.Header.Length);
OnRecvClientPublicKey(info, sessionID, e.Message);
}
else
{
TraceLog.TraceDetail("socketListener_DataReceived session {0} recv data len {1}, msg {2} trans to server"
, sessionID, e.Message.Header.Length, messageID);
//需要解密,空消息不解密
if(info.TeaKey != null && e.Message.Buffer.Data != null && e.Message.Buffer.Length > 0)
{
//解密有可能失败,需要try cache,要不然会丢很多消息
try
{
SogFastXTEA.Decrypt(e.Message.Buffer.Data, e.Message.Buffer.Length, info.TeaKey);
GateServerUtils.GetServerMsgTrans().TransClientMessageToServer(info, e.Message);
}
catch (Exception ex)
{
TraceLog.Error("socketListener_DataReceived decrypt msg data failed! session {0} MsgType {1}"
, sessionID, messageID);
TraceLog.Exception(ex);
}
}
else
{
GateServerUtils.GetServerMsgTrans().TransClientMessageToServer(info, e.Message);
}
}
}
catch (Exception ex)
{
TraceLog.Error("GateClientService.socketListener_DataReceived recv to Host:{0} error:{1}", e.Session.RemoteEndPoint, ex);
}
finally
{
e.Message.FreeData();
}
}
public GateClientInfo GetGateClientInfoThreadSafe(long sessionID)
{
GateClientInfo info;
lock (m_clientDictLocker)
{
m_data.m_clientsDict.TryGetValue(sessionID, out info);
}
if (info == null)
{
TraceLog.Trace("GateClientService.GetGateClientInfoThreadSafe session {0} no GateClientInfo", sessionID);
return null;
}
return info;
}
public void Update(long nowMs)
{
int maxClient = GateServerUtils.GetServerConfig().maxClientCount;
bool isLimit = maxClient > 0 && m_data.m_clientsDict.Count >= maxClient;
if (m_data.m_socketListener != null
&& m_data.m_socketListener.AcceptLimited != isLimit)
{
m_data.m_socketListener.AcceptLimited = isLimit;
}
if (m_data.m_webSessionListener != null
&& m_data.m_webSessionListener.AcceptLimited != isLimit)
{
m_data.m_webSessionListener.AcceptLimited = isLimit;
}
m_data.m_socketListener?.UpdateAccept();
m_data.m_socketListener?.UpdateAcceptedSessions(nowMs);
m_data.m_webSessionListener?.UpdateAccept();
m_data.m_webSessionListener?.UpdateAcceptedSessions(nowMs);
m_data.m_udpListener?.Update(nowMs);
CheckTimeoutClient();
CloseNeedCloseClients();
UpdateNotifyBackEndClientCount(nowMs);
int clientSocketCount = m_data.m_socketListener.GetClientSocketCount();
if (m_data.m_webSessionListener != null)
{
clientSocketCount += m_data.m_webSessionListener.GetClientSocketCount();
}
ServerStat.Instance.SetValue("SocketSessionMapCount", clientSocketCount);
}
private void CheckTimeoutClient()
{
long now = m_app.GetTimeSecond();
// 3秒检查一次,10超时
if(now - m_data.m_lastCheckTimeoutTime < 3)
{
return;
}
m_data.m_lastCheckTimeoutTime = now;
List<GateClientInfo> infoList;
lock (m_clientDictLocker)
{
infoList = m_data.m_waitServerAckDict.Values.ToList();
}
foreach (var info in infoList)
{
if (now - info.ConnectedTime > 30)
{
TraceLog.Error("GateClientService.CheckTimeoutClient session {0} wait server ack connet timeout", info.SessionID);
AddToNeedCloseClient(info.SessionID);
}
}
//等待公钥校验
lock (m_clientDictLocker)
{
infoList = m_data.m_waitClientPublicKeyDict.Values.ToList();
}
foreach (var info in infoList)
{
if (now - info.ConnectedTime > 30)
{
TraceLog.Error("GateClientService.CheckTimeoutClient session {0} wait client public key timeout", info.SessionID);
AddToNeedCloseClient(info.SessionID);
}
}
}
private void CloseNeedCloseClients()
{
if (m_data.m_needCloseClients.Count == 0)
{
return;
}
List<long> closeSessionID;
lock (m_needCloseClientsLocker)
{
closeSessionID = m_data.m_needCloseClients.ToList();
m_data.m_needCloseClients.Clear();
}
foreach (long sessionID in closeSessionID)
{
lock (m_clientDictLocker)
{
m_data.m_waitServerAckDict.Remove(sessionID);
m_data.m_waitClientPublicKeyDict.Remove(sessionID);
}
GateClientInfo info = GetGateClientInfoThreadSafe(sessionID);
if (info != null)
{
// 通知后端服务器客户端断线了
GateServerUtils.GetServerMsgTrans().NotifyServerClientDisconnected(info.SessionID, info.LinkServerID);
if (info.Session is WebSession)
{
if (info.Session.WorkSocket != null)
{
m_data.m_webSessionListener.ForceCloseNetSession(info.Session);
}
}
else
{
if (info.Session.WorkSocket != null)
{
m_data.m_socketListener.ForceCloseNetSession(info.Session);
}
}
lock (m_clientDictLocker)
{
m_data.m_clientsDict.Remove(sessionID);
}
}
}
}
public void OnServerAckConnected(uint remoteAppID, long sessionID)
{
GateClientInfo info;
lock (m_clientDictLocker)
{
if (m_data.m_waitServerAckDict.TryGetValue(sessionID, out info))
{
m_data.m_waitServerAckDict.Remove(sessionID);
}
}
if (info == null)
{
TraceLog.Trace("GateClientService.OnServerAckConnected server ack session {0} conneted, but client not in waitlist", sessionID);
}
info = GetGateClientInfoThreadSafe(sessionID);
if (info != null)
{
TraceLog.Trace("GateClientService.OnServerAckConnected server {0} ack session {1} conneted ,change state to normal"
, ServerIDUtils.IDToString(remoteAppID), sessionID);
info.LinkServerID = remoteAppID;
info.State = GameClientState.Noraml;
}
else
{
TraceLog.Error("GateClientService.OnServerAckConnected server ack session {0} conneted, but client not in m_clientsDict, server login error!"
, sessionID);
}
}
//服务器主动断开连接
public void OnServerReqDisconnect(uint remoteAppID,long sessionID)
{
GateClientInfo info = GetGateClientInfoThreadSafe(sessionID);
if (info != null)
{
TraceLog.Trace("GateClientService.OnServerReqDisconnect server req session {0} disconnect ,add to close list"
, sessionID);
info.State = GameClientState.Closed;
AddToNeedCloseClient(sessionID);
}
else
{
TraceLog.Trace("GateClientService.OnServerReqDisconnect server req session {0} disconnect ,but client not in m_clientsDict"
, sessionID);
//不存在了,不回包算了 zouwei 20180604
//回个包比较好,兼容性更好,比如game运行的时候可以杀gate进程,还有切服兼容 20190214
GateServerUtils.GetServerMsgTrans().NotifyServerClientDisconnected(sessionID, remoteAppID);
}
}
public void TransChannelMessageToClient(uint remoteAppID, long sessionID, MessageData channelMessage)
{
GateClientInfo info = GetGateClientInfoThreadSafe(sessionID);
if (info == null)
{
TraceLog.Trace("GateClientService.TransChannelMessageToClient can not find session {0}, drop msg"
, sessionID);
//回个包比较好,兼容性更好,比如game运行的时候可以杀gate进程,还有切服兼容 20190214
GateServerUtils.GetServerMsgTrans().NotifyServerClientDisconnected(sessionID, remoteAppID);
return;
}
if (info.State != GameClientState.Noraml)
{
TraceLog.Trace("GateClientService.TransChannelMessageToClient session {0} stat {1} need Noraml, drop msg"
, sessionID, info.State);
return;
}
int headLength = GateMsgHeaderPacker.GetLength();
MessageData message = new MessageData();
message.Header.Type = channelMessage.Header.Type;
int iChannelDataLength = channelMessage.Header.Length - headLength;
if (iChannelDataLength < 0)
{
TraceLog.Trace("GateClientService.TransChannelMessageToClient session {0} channelMessage length error"
, sessionID);
return;
}
//加个判断,大消息打个日志
if (iChannelDataLength > 60000)
{
TraceLog.Error("GateClientService.TransChannelMessageToClient session {0} channelMessage length {1} too long, msg type {2}"
, sessionID, iChannelDataLength, message.Header.Type);
}
message.MallocData(iChannelDataLength);
Buffer.BlockCopy(channelMessage.Buffer.Data, headLength, message.Buffer.Data, 0, message.Buffer.Length);
// 消息压缩
if (ZipClientMsgSize > 0 && message.Buffer.Length > ZipClientMsgSize)
{
ZipMessageData(message, info);
}
// 消息加密, 空消息不加密
if (info.TeaKey != null && iChannelDataLength > 0)
{
SogFastXTEA.Encrypt(message.Buffer.Data, message.Buffer.Length, info.TeaKey);
}
message.Header.Length = message.Buffer.Length;
message.Header.ObjectID = 0; //发给客户端的这个全部设置成空
info.SendSeq++;
TraceLog.Trace("GateClientService.TransChannelMessageToClient session {0} MsgType {1} length {2}",
sessionID, message.Header.Type, message.Header.Length);
SendSessionMessage(info.Session, message);
}
public void ZipMessageData(MessageData message, GateClientInfo info)
{
byte[] zipData = ZipUtils.CompressBytes(message.Buffer.Data, message.Buffer.Length);
if (zipData.Length < message.Buffer.Length)
{
TraceLog.Trace("GateClientService.ZipMessageData message {0} old {1} zip {2}"
, message.Header.Type, message.Buffer.Length, zipData.Length);
Buffer.BlockCopy(zipData, 0, message.Buffer.Data, 0, zipData.Length);
message.Buffer.Length = zipData.Length;
message.Header.isZip = true;
}
else
{
TraceLog.Error("GateClientService.ZipMessageData message {0} not zip, old {1} < zip {2}"
, message.Header.Type, message.Buffer.Length, zipData.Length);
}
}
public void TransChannelMessageToMultiClient(ref GateMsgMultiSessionHeader mutilsession, MessageData channelMessage)
{
//总消息长度
int headLength = GateMsgHeaderPacker.GetLength() + mutilsession.GetLength();
int iChannelDataLength = channelMessage.Header.Length - headLength;
if (iChannelDataLength < 0)
{
TraceLog.Trace("GateClientService.TransChannelMessageToMultiClient trans message {0},channelMessage length error "
, channelMessage.Header.Type);
return;
}
//加个判断,免得不知道错误
if (iChannelDataLength > 60000)
{
TraceLog.Error("GateClientService.TransChannelMessageToMultiClient trans message {0} ,channelMessage length {1} too long"
, channelMessage.Header.Type,iChannelDataLength);
return;
}
unsafe
{
for (int i = 0; i < mutilsession.Count; i++)
{
long sessionId = mutilsession.SessionIDs[i];
GateClientInfo info = GetGateClientInfoThreadSafe(sessionId);
if (info == null)
{
TraceLog.Trace("GateClientService.TransChannelMessageToMultiClient trans session {0} message ,but can not find session"
, sessionId);
continue;
}
if (info.State != GameClientState.Noraml)
{
TraceLog.Trace("GateClientService.TransChannelMessageToMultiClient trans session {0} message ,but session stat is {1}"
, sessionId, GameClientState.Noraml);
continue;
}
info.SendSeq++;
MessageData message = new MessageData();
message.Header.Type = channelMessage.Header.Type;
message.Header.ObjectID = 0; //发给客户端的这个全部设置成空
message.MallocData(iChannelDataLength);
Buffer.BlockCopy(channelMessage.Buffer.Data, headLength, message.Buffer.Data, 0, message.Buffer.Length);
// 广播应用不多, 后续可以把消息压缩改成1次
if (ZipClientMsgSize > 0 && message.Buffer.Length > ZipClientMsgSize)
{
ZipMessageData(message, info);
}
//空消息不加密
if (info.TeaKey != null && iChannelDataLength > 0)
{
SogFastXTEA.Encrypt(message.Buffer.Data, message.Buffer.Length, info.TeaKey);
}
message.Header.Length = message.Buffer.Length;
SendSessionMessage(info.Session, message);
TraceLog.Trace("GateClientService.TransChannelMessageToMultiClient trans session {0} message ,MsgType {1} length {2}",
sessionId, message.Header.Type, message.Header.Length);
}
}
}
private void AddToNeedCloseClient(long sessionID)
{
lock (m_needCloseClientsLocker)
{
if (m_data.m_needCloseClients.Contains(sessionID))
{
return;
}
m_data.m_needCloseClients.Add(sessionID);
}
}
private void OnRecvClientPublicKey(GateClientInfo info, long sessionID, MessageData message)
{
lock (m_clientDictLocker)
{
m_data.m_waitClientPublicKeyDict.Remove(sessionID);
}
if(message.Buffer.Length > 2)
{
int modLen = BitConverter.ToInt16(message.Buffer.Data, 0);
int expLen = message.Buffer.Length - modLen - 2;
if (modLen < 0 || expLen < 0)
{
TraceLog.Debug("GateClientService.OnRecvClientPublicKey session {0} length invalid"
, sessionID);
return;
}
byte[] mod = new byte[modLen];
byte[] exp = new byte[expLen];
Buffer.BlockCopy(message.Buffer.Data, 2, mod, 0, modLen);
Buffer.BlockCopy(message.Buffer.Data, 2 + modLen, exp, 0, expLen);
byte[] newTeaKey = TeaKeyGenerator.Instance.GenerateNew();
byte[] encrypteaKey = null;
if (expLen == 4)
{
//自己特殊rsa算法
encrypteaKey = CryptoConvertUtils.EncryptWithPublicKeyWithChewKeongTANBigInteger(newTeaKey, mod, exp);
TraceLog.Debug("GateClientService.OnRecvClientPublicKey EncryptWithPublicKeyWithChewKeongTANBigInteger session {0} keyLen {1}"
, sessionID, encrypteaKey.Length);
}
else
{
TraceLog.Debug("GateClientService.OnRecvClientPublicKey EncryptWithPublicKey session {0}"
, sessionID);
TraceLog.Error("GateClientService.OnRecvClientPublicKey EncryptWithPublicKey session {0} no support"
, sessionID);
return;
//通用rsa算法,和微软的实现一样
//encrypteaKey = CryptoConvertUtils.EncryptWithPublicKey(newTeaKey, mod, exp);
}
MessageData sessionKeyMessage = new MessageData();
sessionKeyMessage.Header.ObjectID = 0;
sessionKeyMessage.Header.ServerID = 0;
sessionKeyMessage.Header.Type = (int)SpecialMessageType.SessionKey;
sessionKeyMessage.Header.Length = encrypteaKey.Length;
//拷贝一份数据,目的是所有的MessageData的内存全都走cache,这样统一
sessionKeyMessage.MallocData(encrypteaKey.Length);
Buffer.BlockCopy(encrypteaKey, 0, sessionKeyMessage.Buffer.Data, 0, encrypteaKey.Length);
SendSessionMessage(info.Session, sessionKeyMessage);
info.TeaKey = new SogFastXTEAKey(newTeaKey);
}
}
private void SendSessionMessage(NetSession session, MessageData message)
{
if (session is WebSession)
{
m_data.m_webSessionListener.Send(session, message);
}
else
{
m_data.m_socketListener.Send(session, message);
}
}
/// <summary>
/// 通知后端服务器连接数量
/// </summary>
private void UpdateNotifyBackEndClientCount(long nowMs)
{
//10秒一个包
if(nowMs - m_lastNotifyBackEndClientCountTimeMs < 10000)
{
return;
}
m_lastNotifyBackEndClientCountTimeMs = nowMs;
GateServerUtils.GetServerMsgTrans().NotifyServerClientCount(GetClientCount());
}
}
}