RealmSession.cs 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. using System;
  2. using System.Net;
  3. using System.Net.Sockets;
  4. using System.Threading.Tasks;
  5. using Helper;
  6. using Log;
  7. using Org.BouncyCastle.Crypto.Digests;
  8. using Org.BouncyCastle.Utilities.Encoders;
  9. using Robot.Protos;
  10. namespace Robot
  11. {
  12. public class RealmSession: IDisposable
  13. {
  14. private readonly NetworkStream networkStream;
  15. private readonly RealmInfo realmInfo = new RealmInfo();
  16. public RealmSession(string host, ushort port)
  17. {
  18. Socket socket = ConnectSocket(host, port);
  19. this.networkStream = new NetworkStream(socket);
  20. }
  21. public void Dispose()
  22. {
  23. this.networkStream.Dispose();
  24. }
  25. public static Socket ConnectSocket(string host, ushort port)
  26. {
  27. IPHostEntry hostEntry = Dns.GetHostEntry(host);
  28. foreach (IPAddress address in hostEntry.AddressList)
  29. {
  30. var ipe = new IPEndPoint(address, port);
  31. var tempSocket = new Socket(ipe.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
  32. tempSocket.Connect(ipe);
  33. if (!tempSocket.Connected)
  34. {
  35. continue;
  36. }
  37. return tempSocket;
  38. }
  39. Logger.Debug("socket is null, address: {0}:{1}", host, port);
  40. throw new SocketException(10000);
  41. }
  42. public async void SendMessage<T>(ushort opcode, T message)
  43. {
  44. byte[] protoBytes = ProtobufHelper.ToBytes(message);
  45. var neworkBytes = new byte[sizeof (int) + sizeof (ushort) + protoBytes.Length];
  46. int totalSize = sizeof (ushort) + protoBytes.Length;
  47. var totalSizeBytes = BitConverter.GetBytes(totalSize);
  48. totalSizeBytes.CopyTo(neworkBytes, 0);
  49. var opcodeBytes = BitConverter.GetBytes(opcode);
  50. opcodeBytes.CopyTo(neworkBytes, sizeof (int));
  51. protoBytes.CopyTo(neworkBytes, sizeof (int) + sizeof (ushort));
  52. await this.networkStream.WriteAsync(neworkBytes, 0, neworkBytes.Length);
  53. }
  54. public async Task<bool> Handle_CMSG_AuthLogonPermit_Response()
  55. {
  56. var result = await this.RecvMessage();
  57. ushort opcode = result.Item1;
  58. byte[] message = result.Item2;
  59. if (opcode == 0)
  60. {
  61. Logger.Trace("opcode == 0");
  62. throw new RealmException("opcode == 0");
  63. }
  64. if (opcode == MessageOpcode.SMSG_LOCK_FOR_SAFE_TIME)
  65. {
  66. var smsgLockForSafeTime = ProtobufHelper.FromBytes<SMSG_Lock_For_Safe_Time>(message);
  67. Logger.Trace("account lock time: {0}", smsgLockForSafeTime.Time);
  68. return false;
  69. }
  70. if (opcode != MessageOpcode.SMSG_PASSWORD_PROTECT_TYPE)
  71. {
  72. throw new RealmException(string.Format("error opcode: {0}", opcode));
  73. }
  74. var smsgPasswordProtectType = ProtobufHelper.FromBytes<SMSG_Password_Protect_Type>(message);
  75. this.realmInfo.SmsgPasswordProtectType = smsgPasswordProtectType;
  76. Logger.Trace("message: {0}", JsonHelper.ToString(smsgPasswordProtectType));
  77. if (smsgPasswordProtectType.Code != 200)
  78. {
  79. return false;
  80. }
  81. return true;
  82. }
  83. public async Task<Tuple<ushort, byte[]>> RecvMessage()
  84. {
  85. int totalReadSize = 0;
  86. int needReadSize = sizeof (int);
  87. var packetBytes = new byte[needReadSize];
  88. while (totalReadSize != needReadSize)
  89. {
  90. int readSize = await this.networkStream.ReadAsync(
  91. packetBytes, totalReadSize, packetBytes.Length);
  92. if (readSize == 0)
  93. {
  94. return new Tuple<ushort, byte[]>(0, new byte[] { });
  95. }
  96. totalReadSize += readSize;
  97. }
  98. int packetSize = BitConverter.ToInt32(packetBytes, 0);
  99. // 读opcode和message
  100. totalReadSize = 0;
  101. needReadSize = packetSize;
  102. var contentBytes = new byte[needReadSize];
  103. while (totalReadSize != needReadSize)
  104. {
  105. int readSize = await this.networkStream.ReadAsync(
  106. contentBytes, totalReadSize, contentBytes.Length);
  107. if (readSize == 0)
  108. {
  109. return new Tuple<ushort, byte[]>(0, new byte[] { });
  110. }
  111. totalReadSize += readSize;
  112. }
  113. ushort opcode = BitConverter.ToUInt16(contentBytes, 0);
  114. var messageBytes = new byte[needReadSize - sizeof (ushort)];
  115. Array.Copy(contentBytes, sizeof (ushort), messageBytes, 0, messageBytes.Length);
  116. return new Tuple<ushort, byte[]>(opcode, messageBytes);
  117. }
  118. public async Task<bool> Login(string account, string password)
  119. {
  120. byte[] passwordBytes = password.ToByteArray();
  121. var digest = new MD5Digest();
  122. var passwordMd5 = new byte[digest.GetDigestSize()];
  123. digest.BlockUpdate(passwordBytes, 0, passwordBytes.Length);
  124. digest.DoFinal(passwordMd5, 0);
  125. var cmsgAuthLogonPermit = new CMSG_AuthLogonPermit
  126. {
  127. Account = account,
  128. PasswordMd5 = Hex.ToHexString(passwordMd5)
  129. };
  130. this.SendMessage(MessageOpcode.CMSG_AUTHLOGONPERMIT, cmsgAuthLogonPermit);
  131. bool result = await this.Handle_CMSG_AuthLogonPermit_Response();
  132. if (result == false)
  133. {
  134. return false;
  135. }
  136. var cmsgAuthLogonChallenge = new CMSG_AuthLogonChallenge { };
  137. return true;
  138. }
  139. }
  140. }