/// <summary> /// Validates buffer capacity before writing into it. /// </summary> /// <param name="nextValueLength">length of next bytes sequence to write into buffer.</param> private void ValidateBufferSize(int nextValueLength) { if ((_mOffset + nextValueLength) > _mBuffer.Length) { L2Buffer.Extend(ref _mBuffer, nextValueLength + MDefaultOverflowValue); } }
/// <summary> /// Reads array of <see cref="byte"/> values from packet buffer. /// </summary> /// <param name="length">length of array to read.</param> /// <returns>Array of <see cref="byte"/> values.</returns> public unsafe byte[] ReadBytesArray(int length) { byte[] dest = new byte[length]; fixed(byte *buf = _mBuffer, dst = dest) L2Buffer.Copy(buf, length, dst, ref _mOffset); return(dest); }
/// <summary> /// Returns string representation of current packet. /// </summary> /// <returns>String representation of current packet.</returns> public override string ToString() { //System.Text.StringBuilder sb = new System.Text.StringBuilder(); //sb.AppendLine("Packet dump:"); //sb.AppendFormat("1s op: {0}{2}2d op: {1}{2}", FirstOpcode, SecondOpcode, Environment.NewLine); //sb.Append(L2Buffer.ToString(m_Buffer)); //return sb.ToString(); return(L2Buffer.ToString(_mBuffer)); }
/// <summary> /// Writes array of <see cref="byte"/> into packet buffer. /// </summary> /// <param name="v">Array of <see cref="byte"/> values.</param> public void WriteByteArray(byte[] v) { int length = v.Length; ValidateBufferSize(length); L2Buffer.Copy(v, 0, _mBuffer, _mOffset, length); _mOffset += length; }
/// <summary> /// Receive <see cref="AsyncCallback"/> method. /// </summary> /// <exception cref="InvalidOperationException" /> protected override unsafe void ReceiveCallback(IAsyncResult ar) { try { MReceivedLength += MSocket.EndReceive(ar); fixed(byte *buf = MReceiveBuffer) { if (!MHeaderReceived) //get packet capacity { L2Buffer.Extend(ref MReceiveBuffer, 0, *(int *)buf - sizeof(int)); MReceivedLength = 0; MHeaderReceived = true; } if (MReceivedLength == MReceiveBuffer.Length) // all data received { Handle(new Packet(2, MReceiveBuffer)); MReceivedLength = 0; MReceiveBuffer = MDefaultBuffer; MHeaderReceived = false; MSocket.BeginReceive(MReceiveBuffer, 0, 4, 0, ReceiveCallback, null); } else { if (MReceivedLength < MReceiveBuffer.Length) // not all data received { MSocket.BeginReceive(MReceiveBuffer, MReceivedLength, MReceiveBuffer.Length - MReceivedLength, 0, MReceiveCallback, null); } else { throw new InvalidOperationException(); } } } } catch (SocketException se) { Log.Info(string.Format("{0} \r\nError code: {1}", se.ToString(), se.ErrorCode)); CloseConnection(); OnDisconnected?.Invoke(se.ErrorCode, this, ConnectionId); } catch (Exception e) { Log.Error(e); CloseConnection(); OnDisconnected?.Invoke(-1, this, ConnectionId); } }
/// <summary> /// Writes array of <see cref="long"/> values into packet buffer. /// </summary> /// <param name="v">Array of <see cref="long"/> values.</param> public unsafe void WriteLong(params long[] v) { int length = v.Length * sizeof(long); ValidateBufferSize(length); fixed(byte *buf = _mBuffer) { fixed(long *w = v) L2Buffer.UnsafeCopy(w, length, buf, ref _mOffset); } }
/// <summary> /// Writes array of <see cref="double"/> values into packet buffer. /// </summary> /// <param name="v">Array of <see cref="double"/> values.</param> public unsafe void WriteDouble(params double[] v) { int length = v.Length * sizeof(double); ValidateBufferSize(length); fixed(byte *buf = _mBuffer) { fixed(double *w = v) L2Buffer.UnsafeCopy(w, length, buf, ref _mOffset); } }
/// <summary> /// Writes array of <see cref="int"/> values into packet buffer. /// </summary> /// <param name="v">Array of <see cref="int"/> values.</param> public unsafe void WriteIntArray(int[] v) { int length = v.Length * sizeof(int); ValidateBufferSize(Length); fixed(byte *buf = _mBuffer) { fixed(int *w = v) L2Buffer.UnsafeCopy(w, length, buf, ref _mOffset); } }
/// <summary> /// Writes array of <see cref="short"/> values into packet buffer. /// </summary> /// <param name="v">Array of <see cref="short"/> values.</param> public unsafe void WriteShort(params short[] v) { int length = v.Length * sizeof(short); ValidateBufferSize(length); fixed(byte *buf = _mBuffer) { fixed(short *w = v) L2Buffer.UnsafeCopy(w, length, buf, ref _mOffset); } }
/// <summary> /// Receive method. /// </summary> //72-2min protected override unsafe void ReceiveCallback(IAsyncResult ar) { try { m_ReceivedLength += m_Socket.EndReceive(ar); //Logger.WriteLine(Source.Debug, "m_ReceivedLength == {0}", m_ReceivedLength); if (m_ReceivedLength == 0) { BeginReceive(); return; } fixed(byte *buf = m_ReceiveBuffer) { if (!m_HeaderReceived) //get packet capacity { L2Buffer.Extend(ref m_ReceiveBuffer, 0, *(( short * )(buf)) - sizeof(short)); m_ReceivedLength = 0; m_HeaderReceived = true; } if (m_ReceivedLength == m_ReceiveBuffer.Length) // all data received { m_Crypt.Decrypt(ref m_ReceiveBuffer, 0, m_ReceiveBuffer.Length); Handle(new Packet(1, m_ReceiveBuffer)); m_ReceivedLength = 0; m_ReceiveBuffer = m_DefaultBuffer; m_HeaderReceived = false; m_Socket.BeginReceive(m_ReceiveBuffer, 0, 0, 0, ReceiveCallback, null); } else if (m_ReceivedLength < m_ReceiveBuffer.Length) // not all data received { m_Socket.BeginReceive(m_ReceiveBuffer, m_ReceivedLength, m_ReceiveBuffer.Length - m_ReceivedLength, 0, m_ReceiveCallback, null); } else { throw new InvalidOperationException(); } } } catch (Exception e) { //if ( e is NullReferenceException ) // user closed connection //{ // UserConnectionsListener.RemoveFromActiveConnections(this); // return; //} Logger.Exception(e); } }
/// <summary> /// Writes <see cref="string"/> object into packet buffer. /// </summary> /// <param name="s"><see cref="string"/> value.</param> public unsafe void WriteString(string s) { s += '\0'; int length = s.Length * sizeof(char); ValidateBufferSize(length); fixed(byte *buf = _mBuffer) { fixed(char *w = s) L2Buffer.UnsafeCopy(w, length, buf, ref _mOffset); } }
/// <summary> /// Writes array of <see cref="string"/> values to packet buffer. /// </summary> /// <param name="s">Array of <see cref="string"/> values.</param> public unsafe void WriteString(params string[] s) { string v = string.Join(string.Empty, s.Select(t => t + '\0').ToArray()); int length = v.Length * sizeof(char); ValidateBufferSize(length); fixed(byte *buf = _mBuffer) { fixed(char *w = v) L2Buffer.UnsafeCopy(w, length, buf, ref _mOffset); } }
/// <summary> /// Sends buffer to client socket. /// </summary> /// <param name="buffer">Buffer to send.</param> public virtual void SendData(byte[] buffer) { //#if DEBUG_NET_CLIENT Console.WriteLine("Sending:\r\n{0}", L2Buffer.ToString(buffer)); //#endif if (m_Socket != null && m_Socket.Connected) { lock (m_Lock) m_SendQueue.Enqueue(buffer); if (m_SendReadyFlag) { SendCallback(null); } } }
/// <summary> /// Resizes <see cref="Packet"/> buffer to it's actual capacity and appends buffer length to the beginning of <see cref="Packet"/> buffer. /// </summary> /// <param name="headerSize"><see cref="Packet"/> header (opcodes) capacity.</param> public unsafe void Prepare(int headerSize) { _mOffset += headerSize; L2Buffer.Extend(ref _mBuffer, headerSize, _mOffset); fixed(byte *buf = _mBuffer) { if (headerSize == sizeof(short)) { *(short *)buf = (short)_mOffset; } else { *(int *)buf = _mOffset; } } }
/// <summary> /// Sends buffer to client socket. /// </summary> /// <param name="buffer">Buffer to send.</param> public virtual void SendData(byte[] buffer) { //#if DEBUG_NET_CLIENT Log.Info($"Sending:\r\n{L2Buffer.ToString(buffer)}"); //#endif if ((MSocket == null) || !MSocket.Connected) { return; } lock (MLock) MSendQueue.Enqueue(buffer); if (MSendReadyFlag) { SendCallback(null); } }
/// <summary> /// Session start method override, instead usual ReceiveCallback. /// </summary> private unsafe void SessionReceiveCallback(IAsyncResult ar) { try { m_ReceivedLength += m_Socket.EndReceive(ar); fixed(byte *buf = m_ReceiveBuffer) { //Logger.WriteLine(Source.Debug, "Recieve :\r\n{0}", L2Buffer.ToString(m_ReceiveBuffer)); if (!m_HeaderReceived) //get packet capacity { L2Buffer.Extend(ref m_ReceiveBuffer, 0, *(( short * )(buf)) - sizeof(short)); m_ReceivedLength = 0; m_HeaderReceived = true; } if (m_ReceivedLength == m_ReceiveBuffer.Length) // all data received { Handle(new Packet(1, m_ReceiveBuffer)); m_ReceivedLength = 0; m_ReceiveBuffer = m_DefaultBuffer; m_HeaderReceived = false; m_Socket.BeginReceive(m_ReceiveBuffer, 0, 2, 0, ReceiveCallback, null); } else if (m_ReceivedLength < m_ReceiveBuffer.Length) // not all data received { m_Socket.BeginReceive(m_ReceiveBuffer, m_ReceivedLength, m_ReceiveBuffer.Length - m_ReceivedLength, 0, SessionReceiveCallback, null); } else { throw new InvalidOperationException(); } } } catch (Exception e) { Logger.Exception(e); } }
/// <summary> /// Generates next random blowfish key. /// </summary> /// <returns>Next random blowfish key.</returns> internal static byte[] GetNext() { return(L2Buffer.Replace(sk, 0, L2Random.NextBytes(8), 8)); }
/// <summary> /// Initializes <see cref="Geodata"/> engine. /// </summary> /// <returns>True, if <see cref="Geodata"/> engine was initialized successfully, otherwise false.</returns> internal static unsafe bool Initialize() { //return true; try { FileInfo[] filesInfoArray = L2FileReader.GetFiles ( Path.Combine ( AppDomain.CurrentDomain.BaseDirectory, Settings.Default.GeodataFilesPath ), m_GeoFileMask, SearchOption.TopDirectoryOnly ); FileInfo currentFile; int counter, reader, i, j, k, m; short[] heightsComplex = new short[0x40], heightsMultilayered = new short[0x900]; byte[] heightsMap = new byte[0x40]; ushort[] offsetsMap = new ushort[0x40]; GeoBlock[] nextMap; #if GEO_FIX_DATA bool flat; #endif for (i = 0; i < filesInfoArray.Length; i++) { currentFile = filesInfoArray[i]; Logger.Write(false, "Loading {0} ", currentFile.Name); counter = reader = 0; nextMap = new GeoBlock[ushort.MaxValue]; fixed(byte *buffer = L2FileReader.Read(currentFile.FullName, ( int )currentFile.Length)) { while (counter < ushort.MaxValue) { switch (*(buffer + reader++)) { case 0x00: { nextMap[counter] = new GeoBlock(null, null, *( short * )(buffer + reader)); reader += sizeof(short); break; } case 0x01: { #if GEO_FIX_DATA flat = true; #endif fixed(short *heights = heightsComplex) { for (j = 0; j < 0x40; reader += sizeof(short), j++) { *(heights + j) = ( short )(*( short * )(buffer + reader) >> 1); #if GEO_FIX_DATA if (j > 0 && *(heights + j) != *(heights + j - 1)) { flat = false; // validating that not all heights are same } #endif } } #if GEO_FIX_DATA if (flat) { nextMap[counter] = new GeoBlock(null, null, heightsComplex[0]); } else #endif nextMap[counter] = new GeoBlock(null, null, heightsComplex); break; } case 0x02: { fixed(ushort *offsets = offsetsMap) fixed(byte *map = heightsMap) fixed(short *heights = heightsMultilayered) { for (j = 0, m = 0; j < 0x40; j++) { *(map + j) = *( byte * )(buffer + reader++); for (k = 0; k < *(map + j); k++, m++) { *(heights + m) = ( short )(*( short * )(buffer + reader) >> 1); reader += sizeof(short); } *(offsets + j) = ( ushort )(k + *(offsets + j - 0x01)); } #if GEO_FIX_DATA if (offsetsMap[0x3f] == 0x40) // only 64 heights, so block is complex or flat { flat = true; for (j = 1; j < 0x40; j++) { if (offsetsMap[j] != offsetsMap[j - 1]) { flat = false; // validating that not all heights are same break; } } if (flat) { nextMap[counter] = new GeoBlock(null, null, heights[0]); } else { nextMap[counter] = new GeoBlock(null, null, L2Buffer.SpecialCopy(heights, 0x40)); } } else #endif nextMap[counter] = new GeoBlock(heightsMap, offsetsMap, L2Buffer.SpecialCopy(heights, offsetsMap[0x3f])); } break; } default: throw new InvalidOperationException(String.Format("Failed to read geodata file '{0}'", currentFile.FullName)); } counter++; if (counter % (ushort.MaxValue / 20) == 0) { Logger.Write(true, "."); } } } geodata.Add(ParseMapOffsets(currentFile), nextMap); Logger.EndWrite(" complete."); } geodata.TrimExcess(); filesInfoArray = null; currentFile = null; heightsComplex = null; heightsMultilayered = null; heightsMap = null; offsetsMap = null; nextMap = null; GC.WaitForPendingFinalizers(); GC.Collect(); return(true); } catch (Exception e) { Logger.WriteLine(Source.Geodata, "Failed to load data files."); Logger.Exception(e); } return(false); }
/// <summary> /// Handles incoming packet. /// </summary> /// <param name="packet">Incoming packet.</param> protected override void Handle(Packet packet) { Logger.WriteLine(Source.OuterNetwork, "Received: {0}", packet.ToString()); if (!CacheServiceConnection.Active) // validate if login service is active { Send(LoginFailed.ToPacket(UserAuthenticationResponseType.ServerMaintenance)); UserConnectionsListener.CloseActiveConnection(this); return; } if (QueuedRequestsPool.HasRequest(this, true)) // validate if user is awaiting response from cache service { return; } switch (packet.FirstOpcode) { case 0x07: { Send(ResponseAuthGameGuard.Static); return; } case 0x00: { m_RSADecryptor = new RSAManaged(); m_RSADecryptor.ImportParameters(UserConnectionsListener.PrivateKey); // get login and password unsafe { byte[] bytes = new byte[0x80]; fixed(byte *buf = bytes, src = packet.GetBuffer()) L2Buffer.Copy(src, 0x01, buf, 0x00, 0x80); fixed(byte *buf = m_RSADecryptor.DecryptValue(bytes)) { L2Buffer.GetTrimmedString(buf, 0x03, ref Login, 0x0e); L2Buffer.GetTrimmedString(buf, 0x11, ref Password, 0x10); } } // validate user login if (!Utils.IsValidUserLogin(Login)) { Send(LoginFailed.ToPacket(UserAuthenticationResponseType.UserOrPasswordWrong)); return; } //Password = Utils.HashPassword(Password); Session.AccountName = Login; Logger.WriteLine(Session.ToString()); long requestId = long.MinValue; // request cache to auth user if (QueuedRequestsPool.Enqueue(this, ref requestId)) { CacheServiceConnection.Send(new UserAuthenticationRequest(requestId, Login, Password, Session.ID).ToPacket()); } else { Logger.WriteLine(Source.InnerNetwork, "Failed to send UserAuthenticationRequest to cache service, request was not enqueued by QueuedRequestsPool ?..."); Send(LoginFailed.ToPacket(UserAuthenticationResponseType.SystemError)); UserConnectionsListener.CloseActiveConnection(this); } return; } case 0x05: { int login1 = packet.ReadInt(); int login2 = packet.ReadInt(); if (login1 != Session.Login1 || login2 != Session.Login2) { Logger.WriteLine(Source.OuterNetwork, "Invalid UserSession data: {0}. BAN!", Session.ToString()); CacheServiceConnection.Send(new UnCacheUser(Session.ID).ToPacket()); UserConnectionsListener.CloseActiveConnection(this); } else { long requestID = long.MinValue; if (QueuedRequestsPool.Enqueue(this, ref requestID)) { CacheServiceConnection.Send(new WorldsListRequest(requestID).ToPacket()); } else { Logger.WriteLine(Source.InnerNetwork, "Failed to send WorldsListRequest to cache service, request was not enqueued by QueuedRequestsPool ?..."); UserConnectionsListener.CloseActiveConnection(this); } } return; } case 0x02: { // skip not needed data packet.MoveOffset(8); long requestID = long.MinValue; if (QueuedRequestsPool.Enqueue(this, ref requestID)) { CacheServiceConnection.Send(new JoinWorldRequest(requestID, Session.ID, packet.ReadByte()).ToPacket()); } else { Logger.WriteLine(Source.InnerNetwork, "Failed to send JionWorldRequest to cache service, request was not enqueued by QueuedRequestsPool ?..."); UserConnectionsListener.CloseActiveConnection(this); } return; } } Logger.WriteLine(Source.OuterNetwork, "Unknown packet received: {0}", packet.ToString()); UserConnectionsListener.CloseActiveConnection(this); }
/// <summary> /// Returns packet buffer. /// </summary> /// <param name="skipFirstBytesCount">Amount of first bytes to skip.</param> /// <returns>Buffer without provided amount of first bytes.</returns> public byte[] GetBuffer(int skipFirstBytesCount) { return(L2Buffer.Copy(_mBuffer, skipFirstBytesCount, new byte[_mBuffer.Length - skipFirstBytesCount], 0, _mBuffer.Length - skipFirstBytesCount)); }
/// <summary> /// Receive <see cref="AsyncCallback"/> method. /// </summary> /// <exception cref="InvalidOperationException" /> protected override unsafe void ReceiveCallback(IAsyncResult ar) { try { m_ReceivedLength += m_Socket.EndReceive(ar); fixed(byte *buf = m_ReceiveBuffer) { if (!m_HeaderReceived) //get packet capacity { L2Buffer.Extend(ref m_ReceiveBuffer, 0, *(( int * )(buf)) - sizeof(int)); m_ReceivedLength = 0; m_HeaderReceived = true; } if (m_ReceivedLength == m_ReceiveBuffer.Length) // all data received { Handle(new Packet(2, m_ReceiveBuffer)); m_ReceivedLength = 0; m_ReceiveBuffer = m_DefaultBuffer; m_HeaderReceived = false; m_Socket.BeginReceive(m_ReceiveBuffer, 0, 4, 0, ReceiveCallback, null); } else if (m_ReceivedLength < m_ReceiveBuffer.Length) // not all data received { m_Socket.BeginReceive(m_ReceiveBuffer, m_ReceivedLength, m_ReceiveBuffer.Length - m_ReceivedLength, 0, m_ReceiveCallback, null); } else { throw new InvalidOperationException(); } } } catch (SocketException se) { if (OnDisconnected != null) { OnDisconnected(se.ErrorCode, this, ConnectionID); } else { Logger.WriteLine(Source.InnerNetwork, "{0} \r\nError code: {1}", se.ToString(), se.ErrorCode); CloseConnection(); } } catch (Exception e) { Logger.Exception(e); if (OnDisconnected != null) { OnDisconnected(-1, this, ConnectionID); } else { CloseConnection(); } } }
/// <summary> /// Reads <see cref="string"/> value from packet buffer. /// </summary> /// <returns><see cref="string"/> value.</returns> public unsafe string ReadString() { fixed(byte *buf = _mBuffer) return(L2Buffer.GetTrimmedString(buf, ref _mOffset, _mBuffer.Length)); }