RealmSession.cs 4.5 KB

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