This commit is contained in:
commit
47711d616e
2644 changed files with 479454 additions and 0 deletions
102
Server/Network/BufferPool.cs
Normal file
102
Server/Network/BufferPool.cs
Normal file
|
|
@ -0,0 +1,102 @@
|
|||
/***************************************************************************
|
||||
* BufferPool.cs
|
||||
* -------------------
|
||||
* begin : May 1, 2002
|
||||
* copyright : (C) The RunUO Software Team
|
||||
* email : info@runuo.com
|
||||
*
|
||||
* $Id: BufferPool.cs 43 2006-01-20 05:39:57Z krrios $
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Server.Network
|
||||
{
|
||||
public class BufferPool
|
||||
{
|
||||
private static List<BufferPool> m_Pools = new List<BufferPool>();
|
||||
|
||||
public static List<BufferPool> Pools{ get{ return m_Pools; } set{ m_Pools = value; } }
|
||||
|
||||
private string m_Name;
|
||||
|
||||
private int m_InitialCapacity;
|
||||
private int m_BufferSize;
|
||||
|
||||
private int m_Misses;
|
||||
|
||||
private Queue<byte[]> m_FreeBuffers;
|
||||
|
||||
public void GetInfo( out string name, out int freeCount, out int initialCapacity, out int currentCapacity, out int bufferSize, out int misses )
|
||||
{
|
||||
lock ( this )
|
||||
{
|
||||
name = m_Name;
|
||||
freeCount = m_FreeBuffers.Count;
|
||||
initialCapacity = m_InitialCapacity;
|
||||
currentCapacity = m_InitialCapacity * (1 + m_Misses);
|
||||
bufferSize = m_BufferSize;
|
||||
misses = m_Misses;
|
||||
}
|
||||
}
|
||||
|
||||
public BufferPool( string name, int initialCapacity, int bufferSize )
|
||||
{
|
||||
m_Name = name;
|
||||
|
||||
m_InitialCapacity = initialCapacity;
|
||||
m_BufferSize = bufferSize;
|
||||
|
||||
m_FreeBuffers = new Queue<byte[]>( initialCapacity );
|
||||
|
||||
for ( int i = 0; i < initialCapacity; ++i )
|
||||
m_FreeBuffers.Enqueue( new byte[bufferSize] );
|
||||
|
||||
lock ( m_Pools )
|
||||
m_Pools.Add( this );
|
||||
}
|
||||
|
||||
public byte[] AcquireBuffer()
|
||||
{
|
||||
lock ( this )
|
||||
{
|
||||
if ( m_FreeBuffers.Count > 0 )
|
||||
return m_FreeBuffers.Dequeue();
|
||||
|
||||
++m_Misses;
|
||||
|
||||
for ( int i = 0; i < m_InitialCapacity; ++i )
|
||||
m_FreeBuffers.Enqueue( new byte[m_BufferSize] );
|
||||
|
||||
return m_FreeBuffers.Dequeue();
|
||||
}
|
||||
}
|
||||
|
||||
public void ReleaseBuffer( byte[] buffer )
|
||||
{
|
||||
if ( buffer == null )
|
||||
return;
|
||||
|
||||
lock ( this )
|
||||
m_FreeBuffers.Enqueue( buffer );
|
||||
}
|
||||
|
||||
public void Free()
|
||||
{
|
||||
lock ( m_Pools )
|
||||
m_Pools.Remove( this );
|
||||
}
|
||||
}
|
||||
}
|
||||
153
Server/Network/ByteQueue.cs
Normal file
153
Server/Network/ByteQueue.cs
Normal file
|
|
@ -0,0 +1,153 @@
|
|||
/***************************************************************************
|
||||
* ByteQueue.cs
|
||||
* -------------------
|
||||
* begin : May 1, 2002
|
||||
* copyright : (C) The RunUO Software Team
|
||||
* email : info@runuo.com
|
||||
*
|
||||
* $Id: ByteQueue.cs 20 2006-01-15 23:50:35Z asayre $
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace Server.Network
|
||||
{
|
||||
public class ByteQueue
|
||||
{
|
||||
private int m_Head;
|
||||
private int m_Tail;
|
||||
private int m_Size;
|
||||
|
||||
private byte[] m_Buffer;
|
||||
|
||||
public int Length{ get{ return m_Size; } }
|
||||
|
||||
public ByteQueue()
|
||||
{
|
||||
m_Buffer = new byte[2048];
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
m_Head = 0;
|
||||
m_Tail = 0;
|
||||
m_Size = 0;
|
||||
}
|
||||
|
||||
private void SetCapacity( int capacity )
|
||||
{
|
||||
byte[] newBuffer = new byte[capacity];
|
||||
|
||||
if ( m_Size > 0 )
|
||||
{
|
||||
if ( m_Head < m_Tail )
|
||||
{
|
||||
Buffer.BlockCopy( m_Buffer, m_Head, newBuffer, 0, m_Size );
|
||||
}
|
||||
else
|
||||
{
|
||||
Buffer.BlockCopy( m_Buffer, m_Head, newBuffer, 0, m_Buffer.Length - m_Head );
|
||||
Buffer.BlockCopy( m_Buffer, 0, newBuffer, m_Buffer.Length - m_Head, m_Tail );
|
||||
}
|
||||
}
|
||||
|
||||
m_Head = 0;
|
||||
m_Tail = m_Size;
|
||||
m_Buffer = newBuffer;
|
||||
}
|
||||
|
||||
public byte GetPacketID()
|
||||
{
|
||||
if ( m_Size >= 1 )
|
||||
return m_Buffer[m_Head];
|
||||
|
||||
return 0xFF;
|
||||
}
|
||||
|
||||
public int GetPacketLength()
|
||||
{
|
||||
if ( m_Size >= 3 )
|
||||
return (m_Buffer[(m_Head + 1) % m_Buffer.Length] << 8) | m_Buffer[(m_Head + 2) % m_Buffer.Length];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public int Dequeue( byte[] buffer, int offset, int size )
|
||||
{
|
||||
if ( size > m_Size )
|
||||
size = m_Size;
|
||||
|
||||
if ( size == 0 )
|
||||
return 0;
|
||||
|
||||
if ( m_Head < m_Tail )
|
||||
{
|
||||
Buffer.BlockCopy( m_Buffer, m_Head, buffer, offset, size );
|
||||
}
|
||||
else
|
||||
{
|
||||
int rightLength = ( m_Buffer.Length - m_Head );
|
||||
|
||||
if ( rightLength >= size )
|
||||
{
|
||||
Buffer.BlockCopy( m_Buffer, m_Head, buffer, offset, size );
|
||||
}
|
||||
else
|
||||
{
|
||||
Buffer.BlockCopy( m_Buffer, m_Head, buffer, offset, rightLength );
|
||||
Buffer.BlockCopy( m_Buffer, 0, buffer, offset + rightLength, size - rightLength );
|
||||
}
|
||||
}
|
||||
|
||||
m_Head = ( m_Head + size ) % m_Buffer.Length;
|
||||
m_Size -= size;
|
||||
|
||||
if ( m_Size == 0 )
|
||||
{
|
||||
m_Head = 0;
|
||||
m_Tail = 0;
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
public void Enqueue( byte[] buffer, int offset, int size )
|
||||
{
|
||||
if ( (m_Size + size) > m_Buffer.Length )
|
||||
SetCapacity( (m_Size + size + 2047) & ~2047 );
|
||||
|
||||
if ( m_Head < m_Tail )
|
||||
{
|
||||
int rightLength = ( m_Buffer.Length - m_Tail );
|
||||
|
||||
if ( rightLength >= size )
|
||||
{
|
||||
Buffer.BlockCopy( buffer, offset, m_Buffer, m_Tail, size );
|
||||
}
|
||||
else
|
||||
{
|
||||
Buffer.BlockCopy( buffer, offset, m_Buffer, m_Tail, rightLength );
|
||||
Buffer.BlockCopy( buffer, offset + rightLength, m_Buffer, 0, size - rightLength );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Buffer.BlockCopy( buffer, offset, m_Buffer, m_Tail, size );
|
||||
}
|
||||
|
||||
m_Tail = ( m_Tail + size ) % m_Buffer.Length;
|
||||
m_Size += size;
|
||||
}
|
||||
}
|
||||
}
|
||||
281
Server/Network/Compression.cs
Normal file
281
Server/Network/Compression.cs
Normal file
|
|
@ -0,0 +1,281 @@
|
|||
/***************************************************************************
|
||||
* Compression.cs
|
||||
* -------------------
|
||||
* begin : May 1, 2002
|
||||
* copyright : (C) The RunUO Software Team
|
||||
* email : info@runuo.com
|
||||
*
|
||||
* $Id: Compression.cs 131 2006-04-21 03:29:53Z mark $
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Server.Network
|
||||
{
|
||||
/// <summary>
|
||||
/// Handles outgoing packet compression for the network.
|
||||
/// </summary>
|
||||
public class Compression
|
||||
{
|
||||
private static int[] m_Table = new int[514]
|
||||
{
|
||||
0x2, 0x000, 0x5, 0x01F, 0x6, 0x022, 0x7, 0x034, 0x7, 0x075, 0x6, 0x028, 0x6, 0x03B, 0x7, 0x032,
|
||||
0x8, 0x0E0, 0x8, 0x062, 0x7, 0x056, 0x8, 0x079, 0x9, 0x19D, 0x8, 0x097, 0x6, 0x02A, 0x7, 0x057,
|
||||
0x8, 0x071, 0x8, 0x05B, 0x9, 0x1CC, 0x8, 0x0A7, 0x7, 0x025, 0x7, 0x04F, 0x8, 0x066, 0x8, 0x07D,
|
||||
0x9, 0x191, 0x9, 0x1CE, 0x7, 0x03F, 0x9, 0x090, 0x8, 0x059, 0x8, 0x07B, 0x8, 0x091, 0x8, 0x0C6,
|
||||
0x6, 0x02D, 0x9, 0x186, 0x8, 0x06F, 0x9, 0x093, 0xA, 0x1CC, 0x8, 0x05A, 0xA, 0x1AE, 0xA, 0x1C0,
|
||||
0x9, 0x148, 0x9, 0x14A, 0x9, 0x082, 0xA, 0x19F, 0x9, 0x171, 0x9, 0x120, 0x9, 0x0E7, 0xA, 0x1F3,
|
||||
0x9, 0x14B, 0x9, 0x100, 0x9, 0x190, 0x6, 0x013, 0x9, 0x161, 0x9, 0x125, 0x9, 0x133, 0x9, 0x195,
|
||||
0x9, 0x173, 0x9, 0x1CA, 0x9, 0x086, 0x9, 0x1E9, 0x9, 0x0DB, 0x9, 0x1EC, 0x9, 0x08B, 0x9, 0x085,
|
||||
0x5, 0x00A, 0x8, 0x096, 0x8, 0x09C, 0x9, 0x1C3, 0x9, 0x19C, 0x9, 0x08F, 0x9, 0x18F, 0x9, 0x091,
|
||||
0x9, 0x087, 0x9, 0x0C6, 0x9, 0x177, 0x9, 0x089, 0x9, 0x0D6, 0x9, 0x08C, 0x9, 0x1EE, 0x9, 0x1EB,
|
||||
0x9, 0x084, 0x9, 0x164, 0x9, 0x175, 0x9, 0x1CD, 0x8, 0x05E, 0x9, 0x088, 0x9, 0x12B, 0x9, 0x172,
|
||||
0x9, 0x10A, 0x9, 0x08D, 0x9, 0x13A, 0x9, 0x11C, 0xA, 0x1E1, 0xA, 0x1E0, 0x9, 0x187, 0xA, 0x1DC,
|
||||
0xA, 0x1DF, 0x7, 0x074, 0x9, 0x19F, 0x8, 0x08D, 0x8, 0x0E4, 0x7, 0x079, 0x9, 0x0EA, 0x9, 0x0E1,
|
||||
0x8, 0x040, 0x7, 0x041, 0x9, 0x10B, 0x9, 0x0B0, 0x8, 0x06A, 0x8, 0x0C1, 0x7, 0x071, 0x7, 0x078,
|
||||
0x8, 0x0B1, 0x9, 0x14C, 0x7, 0x043, 0x8, 0x076, 0x7, 0x066, 0x7, 0x04D, 0x9, 0x08A, 0x6, 0x02F,
|
||||
0x8, 0x0C9, 0x9, 0x0CE, 0x9, 0x149, 0x9, 0x160, 0xA, 0x1BA, 0xA, 0x19E, 0xA, 0x39F, 0x9, 0x0E5,
|
||||
0x9, 0x194, 0x9, 0x184, 0x9, 0x126, 0x7, 0x030, 0x8, 0x06C, 0x9, 0x121, 0x9, 0x1E8, 0xA, 0x1C1,
|
||||
0xA, 0x11D, 0xA, 0x163, 0xA, 0x385, 0xA, 0x3DB, 0xA, 0x17D, 0xA, 0x106, 0xA, 0x397, 0xA, 0x24E,
|
||||
0x7, 0x02E, 0x8, 0x098, 0xA, 0x33C, 0xA, 0x32E, 0xA, 0x1E9, 0x9, 0x0BF, 0xA, 0x3DF, 0xA, 0x1DD,
|
||||
0xA, 0x32D, 0xA, 0x2ED, 0xA, 0x30B, 0xA, 0x107, 0xA, 0x2E8, 0xA, 0x3DE, 0xA, 0x125, 0xA, 0x1E8,
|
||||
0x9, 0x0E9, 0xA, 0x1CD, 0xA, 0x1B5, 0x9, 0x165, 0xA, 0x232, 0xA, 0x2E1, 0xB, 0x3AE, 0xB, 0x3C6,
|
||||
0xB, 0x3E2, 0xA, 0x205, 0xA, 0x29A, 0xA, 0x248, 0xA, 0x2CD, 0xA, 0x23B, 0xB, 0x3C5, 0xA, 0x251,
|
||||
0xA, 0x2E9, 0xA, 0x252, 0x9, 0x1EA, 0xB, 0x3A0, 0xB, 0x391, 0xA, 0x23C, 0xB, 0x392, 0xB, 0x3D5,
|
||||
0xA, 0x233, 0xA, 0x2CC, 0xB, 0x390, 0xA, 0x1BB, 0xB, 0x3A1, 0xB, 0x3C4, 0xA, 0x211, 0xA, 0x203,
|
||||
0x9, 0x12A, 0xA, 0x231, 0xB, 0x3E0, 0xA, 0x29B, 0xB, 0x3D7, 0xA, 0x202, 0xB, 0x3AD, 0xA, 0x213,
|
||||
0xA, 0x253, 0xA, 0x32C, 0xA, 0x23D, 0xA, 0x23F, 0xA, 0x32F, 0xA, 0x11C, 0xA, 0x384, 0xA, 0x31C,
|
||||
0xA, 0x17C, 0xA, 0x30A, 0xA, 0x2E0, 0xA, 0x276, 0xA, 0x250, 0xB, 0x3E3, 0xA, 0x396, 0xA, 0x18F,
|
||||
0xA, 0x204, 0xA, 0x206, 0xA, 0x230, 0xA, 0x265, 0xA, 0x212, 0xA, 0x23E, 0xB, 0x3AC, 0xB, 0x393,
|
||||
0xB, 0x3E1, 0xA, 0x1DE, 0xB, 0x3D6, 0xA, 0x31D, 0xB, 0x3E5, 0xB, 0x3E4, 0xA, 0x207, 0xB, 0x3C7,
|
||||
0xA, 0x277, 0xB, 0x3D4, 0x8, 0x0C0, 0xA, 0x162, 0xA, 0x3DA, 0xA, 0x124, 0xA, 0x1B4, 0xA, 0x264,
|
||||
0xA, 0x33D, 0xA, 0x1D1, 0xA, 0x1AF, 0xA, 0x39E, 0xA, 0x24F, 0xB, 0x373, 0xA, 0x249, 0xB, 0x372,
|
||||
0x9, 0x167, 0xA, 0x210, 0xA, 0x23A, 0xA, 0x1B8, 0xB, 0x3AF, 0xA, 0x18E, 0xA, 0x2EC, 0x7, 0x062,
|
||||
0x4, 0x00D
|
||||
};
|
||||
|
||||
private static byte[] m_OutputBuffer = new byte[0x40000];
|
||||
private static object m_SyncRoot = new object();
|
||||
|
||||
public unsafe static void Compress( byte[] input, int length, out byte[] output, out int outputLength )
|
||||
{
|
||||
if ( length >= m_OutputBuffer.Length )
|
||||
{
|
||||
output = null;
|
||||
outputLength = length;
|
||||
return;
|
||||
}
|
||||
|
||||
lock ( m_SyncRoot )
|
||||
{
|
||||
int holdCount = 0;
|
||||
int holdValue = 0;
|
||||
|
||||
int packCount = 0;
|
||||
int packValue = 0;
|
||||
|
||||
int byteValue = 0;
|
||||
|
||||
int inputLength = length;
|
||||
int inputIndex = 0;
|
||||
|
||||
int outputCount = 0;
|
||||
|
||||
fixed ( int *pTable = m_Table )
|
||||
{
|
||||
fixed ( byte *pOutputBuffer = m_OutputBuffer )
|
||||
{
|
||||
while ( inputIndex < inputLength )
|
||||
{
|
||||
byteValue = input[inputIndex++] << 1;
|
||||
|
||||
packCount = pTable[byteValue];
|
||||
packValue = pTable[byteValue | 1];
|
||||
|
||||
holdValue <<= packCount;
|
||||
holdValue |= packValue;
|
||||
holdCount += packCount;
|
||||
|
||||
while ( holdCount >= 8 )
|
||||
{
|
||||
holdCount -= 8;
|
||||
|
||||
pOutputBuffer[outputCount++] = (byte)(holdValue >> holdCount);
|
||||
}
|
||||
}
|
||||
|
||||
packCount = pTable[0x200];
|
||||
packValue = pTable[0x201];
|
||||
|
||||
holdValue <<= packCount;
|
||||
holdValue |= packValue;
|
||||
holdCount += packCount;
|
||||
|
||||
while ( holdCount >= 8 )
|
||||
{
|
||||
holdCount -= 8;
|
||||
|
||||
pOutputBuffer[outputCount++] = (byte)(holdValue >> holdCount);
|
||||
}
|
||||
|
||||
if ( holdCount > 0 )
|
||||
pOutputBuffer[outputCount++] = (byte)(holdValue << (8 - holdCount));
|
||||
}
|
||||
}
|
||||
|
||||
output = m_OutputBuffer;
|
||||
outputLength = outputCount;
|
||||
}
|
||||
}
|
||||
|
||||
public static readonly ICompressor Compressor;
|
||||
|
||||
static Compression()
|
||||
{
|
||||
if ( Core.Is64Bit )
|
||||
Compressor = new Compressor64();
|
||||
else
|
||||
Compressor = new Compressor32();
|
||||
}
|
||||
|
||||
public static ZLibError Pack( byte[] dest, ref int destLength, byte[] source, int sourceLength )
|
||||
{
|
||||
return Compressor.Compress( dest, ref destLength, source, sourceLength );
|
||||
}
|
||||
|
||||
public static ZLibError Pack( byte[] dest, ref int destLength, byte[] source, int sourceLength, ZLibQuality quality )
|
||||
{
|
||||
return Compressor.Compress( dest, ref destLength, source, sourceLength, quality );
|
||||
}
|
||||
|
||||
public static ZLibError Unpack( byte[] dest, ref int destLength, byte[] source, int sourceLength )
|
||||
{
|
||||
return Compressor.Decompress( dest, ref destLength, source, sourceLength );
|
||||
}
|
||||
}
|
||||
|
||||
public interface ICompressor
|
||||
{
|
||||
string Version { get; }
|
||||
|
||||
ZLibError Compress( byte[] dest, ref int destLength, byte[] source, int sourceLength );
|
||||
ZLibError Compress( byte[] dest, ref int destLength, byte[] source, int sourceLength, ZLibQuality quality );
|
||||
|
||||
ZLibError Decompress( byte[] dest, ref int destLength, byte[] source, int sourceLength );
|
||||
}
|
||||
|
||||
public sealed class Compressor32 : ICompressor
|
||||
{
|
||||
[DllImport( "zlib32" )]
|
||||
private static extern string zlibVersion();
|
||||
|
||||
[DllImport( "zlib32" )]
|
||||
private static extern ZLibError compress( byte[] dest, ref int destLength, byte[] source, int sourceLength );
|
||||
|
||||
[DllImport( "zlib32" )]
|
||||
private static extern ZLibError compress2( byte[] dest, ref int destLength, byte[] source, int sourceLength, ZLibQuality quality );
|
||||
|
||||
[DllImport( "zlib32" )]
|
||||
private static extern ZLibError uncompress( byte[] dest, ref int destLen, byte[] source, int sourceLen );
|
||||
|
||||
public Compressor32()
|
||||
{
|
||||
}
|
||||
|
||||
public string Version
|
||||
{
|
||||
get { return zlibVersion(); }
|
||||
}
|
||||
|
||||
public ZLibError Compress( byte[] dest, ref int destLength, byte[] source, int sourceLength )
|
||||
{
|
||||
return compress( dest, ref destLength, source, sourceLength );
|
||||
}
|
||||
|
||||
public ZLibError Compress( byte[] dest, ref int destLength, byte[] source, int sourceLength, ZLibQuality quality )
|
||||
{
|
||||
return compress2( dest, ref destLength, source, sourceLength, quality );
|
||||
}
|
||||
|
||||
public ZLibError Decompress( byte[] dest, ref int destLength, byte[] source, int sourceLength )
|
||||
{
|
||||
return uncompress( dest, ref destLength, source, sourceLength );
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class Compressor64 : ICompressor
|
||||
{
|
||||
[DllImport( "zlib64" )]
|
||||
private static extern string zlibVersion();
|
||||
|
||||
[DllImport( "zlib64" )]
|
||||
private static extern ZLibError compress( byte[] dest, ref int destLength, byte[] source, int sourceLength );
|
||||
|
||||
[DllImport( "zlib64" )]
|
||||
private static extern ZLibError compress2( byte[] dest, ref int destLength, byte[] source, int sourceLength, ZLibQuality quality );
|
||||
|
||||
[DllImport( "zlib64" )]
|
||||
private static extern ZLibError uncompress( byte[] dest, ref int destLen, byte[] source, int sourceLen );
|
||||
|
||||
public Compressor64()
|
||||
{
|
||||
}
|
||||
|
||||
public string Version
|
||||
{
|
||||
get { return zlibVersion(); }
|
||||
}
|
||||
|
||||
public ZLibError Compress( byte[] dest, ref int destLength, byte[] source, int sourceLength )
|
||||
{
|
||||
return compress( dest, ref destLength, source, sourceLength );
|
||||
}
|
||||
|
||||
public ZLibError Compress( byte[] dest, ref int destLength, byte[] source, int sourceLength, ZLibQuality quality )
|
||||
{
|
||||
return compress2( dest, ref destLength, source, sourceLength, quality );
|
||||
}
|
||||
|
||||
public ZLibError Decompress( byte[] dest, ref int destLength, byte[] source, int sourceLength )
|
||||
{
|
||||
return uncompress( dest, ref destLength, source, sourceLength );
|
||||
}
|
||||
}
|
||||
|
||||
public enum ZLibError : int
|
||||
{
|
||||
VersionError = -6,
|
||||
BufferError = -5,
|
||||
MemoryError = -4,
|
||||
DataError = -3,
|
||||
StreamError = -2,
|
||||
FileError = -1,
|
||||
|
||||
Okay = 0,
|
||||
|
||||
StreamEnd = 1,
|
||||
NeedDictionary = 2
|
||||
}
|
||||
|
||||
public enum ZLibQuality : int
|
||||
{
|
||||
Default = -1,
|
||||
|
||||
None = 0,
|
||||
|
||||
Speed = 1,
|
||||
Size = 9
|
||||
}
|
||||
}
|
||||
64
Server/Network/EncodedPacketHandler.cs
Normal file
64
Server/Network/EncodedPacketHandler.cs
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
/***************************************************************************
|
||||
* EncodedPacketHandler.cs
|
||||
* -------------------
|
||||
* begin : May 1, 2002
|
||||
* copyright : (C) The RunUO Software Team
|
||||
* email : info@runuo.com
|
||||
*
|
||||
* $Id: EncodedPacketHandler.cs 20 2006-01-15 23:50:35Z asayre $
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
using System;
|
||||
|
||||
namespace Server.Network
|
||||
{
|
||||
public delegate void OnEncodedPacketReceive( NetState state, IEntity ent, EncodedReader pvSrc );
|
||||
|
||||
public class EncodedPacketHandler
|
||||
{
|
||||
private int m_PacketID;
|
||||
private bool m_Ingame;
|
||||
private OnEncodedPacketReceive m_OnReceive;
|
||||
|
||||
public EncodedPacketHandler( int packetID, bool ingame, OnEncodedPacketReceive onReceive )
|
||||
{
|
||||
m_PacketID = packetID;
|
||||
m_Ingame = ingame;
|
||||
m_OnReceive = onReceive;
|
||||
}
|
||||
|
||||
public int PacketID
|
||||
{
|
||||
get
|
||||
{
|
||||
return m_PacketID;
|
||||
}
|
||||
}
|
||||
|
||||
public OnEncodedPacketReceive OnReceive
|
||||
{
|
||||
get
|
||||
{
|
||||
return m_OnReceive;
|
||||
}
|
||||
}
|
||||
|
||||
public bool Ingame
|
||||
{
|
||||
get
|
||||
{
|
||||
return m_Ingame;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
85
Server/Network/EncodedReader.cs
Normal file
85
Server/Network/EncodedReader.cs
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
/***************************************************************************
|
||||
* EncodedReader.cs
|
||||
* -------------------
|
||||
* begin : May 1, 2002
|
||||
* copyright : (C) The RunUO Software Team
|
||||
* email : info@runuo.com
|
||||
*
|
||||
* $Id: EncodedReader.cs 20 2006-01-15 23:50:35Z asayre $
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Text;
|
||||
using System.IO;
|
||||
|
||||
namespace Server.Network
|
||||
{
|
||||
public class EncodedReader
|
||||
{
|
||||
private PacketReader m_Reader;
|
||||
|
||||
public EncodedReader( PacketReader reader )
|
||||
{
|
||||
m_Reader = reader;
|
||||
}
|
||||
|
||||
public byte[] Buffer
|
||||
{
|
||||
get
|
||||
{
|
||||
return m_Reader.Buffer;
|
||||
}
|
||||
}
|
||||
|
||||
public void Trace( NetState state )
|
||||
{
|
||||
m_Reader.Trace( state );
|
||||
}
|
||||
|
||||
public int ReadInt32()
|
||||
{
|
||||
if ( m_Reader.ReadByte() != 0 )
|
||||
return 0;
|
||||
|
||||
return m_Reader.ReadInt32();
|
||||
}
|
||||
|
||||
public Point3D ReadPoint3D()
|
||||
{
|
||||
if ( m_Reader.ReadByte() != 3 )
|
||||
return Point3D.Zero;
|
||||
|
||||
return new Point3D( m_Reader.ReadInt16(), m_Reader.ReadInt16(), m_Reader.ReadByte() );
|
||||
}
|
||||
|
||||
public string ReadUnicodeStringSafe()
|
||||
{
|
||||
if ( m_Reader.ReadByte() != 2 )
|
||||
return "";
|
||||
|
||||
int length = m_Reader.ReadUInt16();
|
||||
|
||||
return m_Reader.ReadUnicodeStringSafe( length );
|
||||
}
|
||||
|
||||
public string ReadUnicodeString()
|
||||
{
|
||||
if ( m_Reader.ReadByte() != 2 )
|
||||
return "";
|
||||
|
||||
int length = m_Reader.ReadUInt16();
|
||||
|
||||
return m_Reader.ReadUnicodeString( length );
|
||||
}
|
||||
}
|
||||
}
|
||||
193
Server/Network/Listener.cs
Normal file
193
Server/Network/Listener.cs
Normal file
|
|
@ -0,0 +1,193 @@
|
|||
/***************************************************************************
|
||||
* Listener.cs
|
||||
* -------------------
|
||||
* begin : May 1, 2002
|
||||
* copyright : (C) The RunUO Software Team
|
||||
* email : info@runuo.com
|
||||
*
|
||||
* $Id: Listener.cs 102 2006-02-04 01:52:29Z mark $
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using Server;
|
||||
|
||||
namespace Server.Network
|
||||
{
|
||||
public class Listener : IDisposable
|
||||
{
|
||||
private Socket m_Listener;
|
||||
private bool m_Disposed;
|
||||
private int m_ThisPort;
|
||||
|
||||
private Queue<Socket> m_Accepted;
|
||||
private object m_AcceptedSyncRoot;
|
||||
|
||||
private AsyncCallback m_OnAccept;
|
||||
|
||||
private static Socket[] m_EmptySockets = new Socket[0];
|
||||
|
||||
public int UsedPort
|
||||
{
|
||||
get{ return m_ThisPort; }
|
||||
}
|
||||
|
||||
private static int m_Port = 2593;
|
||||
|
||||
public static int Port
|
||||
{
|
||||
get
|
||||
{
|
||||
return m_Port;
|
||||
}
|
||||
set
|
||||
{
|
||||
m_Port = value;
|
||||
}
|
||||
}
|
||||
|
||||
public Listener( int port )
|
||||
{
|
||||
m_ThisPort = port;
|
||||
m_Disposed = false;
|
||||
m_Accepted = new Queue<Socket>();
|
||||
m_AcceptedSyncRoot = ((ICollection)m_Accepted).SyncRoot;
|
||||
m_OnAccept = new AsyncCallback( OnAccept );
|
||||
|
||||
m_Listener = Bind( IPAddress.Any, port );
|
||||
|
||||
try
|
||||
{
|
||||
IPHostEntry iphe = Dns.GetHostEntry( Dns.GetHostName() );
|
||||
|
||||
Console.WriteLine( "Address: {0}:{1}", IPAddress.Loopback, port );
|
||||
|
||||
IPAddress[] ip = iphe.AddressList;
|
||||
|
||||
for ( int i = 0; i < ip.Length; ++i )
|
||||
Console.WriteLine( "Address: {0}:{1}", ip[i], port );
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
private Socket Bind( IPAddress ip, int port )
|
||||
{
|
||||
IPEndPoint ipep = new IPEndPoint( ip, port );
|
||||
|
||||
Socket s = new Socket( AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp );
|
||||
|
||||
try
|
||||
{
|
||||
s.LingerState.Enabled = false;
|
||||
s.ExclusiveAddressUse = false;
|
||||
|
||||
s.Bind( ipep );
|
||||
s.Listen( 8 );
|
||||
|
||||
IAsyncResult res = s.BeginAccept( m_OnAccept, s );
|
||||
|
||||
return s;
|
||||
}
|
||||
catch ( Exception e )
|
||||
{
|
||||
Console.WriteLine( "Listener bind exception:" );
|
||||
Console.WriteLine( e );
|
||||
|
||||
try { s.Shutdown( SocketShutdown.Both ); }
|
||||
catch{}
|
||||
|
||||
try { s.Close(); }
|
||||
catch{}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnAccept( IAsyncResult asyncResult )
|
||||
{
|
||||
Socket listener = asyncResult.AsyncState as Socket;
|
||||
|
||||
try
|
||||
{
|
||||
Socket socket = listener.EndAccept( asyncResult );
|
||||
|
||||
if ( socket != null )
|
||||
{
|
||||
SocketConnectEventArgs e = new SocketConnectEventArgs( socket );
|
||||
EventSink.InvokeSocketConnect( e );
|
||||
|
||||
if ( e.AllowConnection )
|
||||
{
|
||||
lock ( m_AcceptedSyncRoot )
|
||||
m_Accepted.Enqueue( socket );
|
||||
}
|
||||
else
|
||||
{
|
||||
try { socket.Shutdown( SocketShutdown.Both ); }
|
||||
catch { }
|
||||
|
||||
try { socket.Close(); }
|
||||
catch { }
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
finally
|
||||
{
|
||||
IAsyncResult res = listener.BeginAccept( m_OnAccept, listener );
|
||||
}
|
||||
}
|
||||
|
||||
public Socket[] Slice()
|
||||
{
|
||||
Socket[] array;
|
||||
|
||||
lock ( m_AcceptedSyncRoot )
|
||||
{
|
||||
if ( m_Accepted.Count == 0 )
|
||||
return m_EmptySockets;
|
||||
|
||||
array = m_Accepted.ToArray();
|
||||
m_Accepted.Clear();
|
||||
}
|
||||
|
||||
return array;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if ( !m_Disposed )
|
||||
{
|
||||
m_Disposed = true;
|
||||
|
||||
if ( m_Listener != null )
|
||||
{
|
||||
try { m_Listener.Shutdown( SocketShutdown.Both ); }
|
||||
catch {}
|
||||
|
||||
try { m_Listener.Close(); }
|
||||
catch {}
|
||||
|
||||
m_Listener = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
256
Server/Network/MessagePump.cs
Normal file
256
Server/Network/MessagePump.cs
Normal file
|
|
@ -0,0 +1,256 @@
|
|||
/***************************************************************************
|
||||
* MessagePump.cs
|
||||
* -------------------
|
||||
* begin : May 1, 2002
|
||||
* copyright : (C) The RunUO Software Team
|
||||
* email : info@runuo.com
|
||||
*
|
||||
* $Id: MessagePump.cs 43 2006-01-20 05:39:57Z krrios $
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using Server;
|
||||
using Server.Network;
|
||||
|
||||
namespace Server.Network
|
||||
{
|
||||
public class MessagePump
|
||||
{
|
||||
private Listener[] m_Listeners;
|
||||
private Queue<NetState> m_Queue;
|
||||
private Queue<NetState> m_WorkingQueue;
|
||||
private Queue<NetState> m_Throttled;
|
||||
private byte[] m_Peek;
|
||||
|
||||
public MessagePump( Listener l )
|
||||
{
|
||||
m_Listeners = new Listener[]{ l };
|
||||
m_Queue = new Queue<NetState>();
|
||||
m_WorkingQueue = new Queue<NetState>();
|
||||
m_Throttled = new Queue<NetState>();
|
||||
m_Peek = new byte[4];
|
||||
}
|
||||
|
||||
public Listener[] Listeners
|
||||
{
|
||||
get{ return m_Listeners; }
|
||||
set{ m_Listeners = value; }
|
||||
}
|
||||
|
||||
public void AddListener( Listener l )
|
||||
{
|
||||
Listener[] old = m_Listeners;
|
||||
|
||||
m_Listeners = new Listener[old.Length + 1];
|
||||
|
||||
for ( int i = 0; i < old.Length; ++i )
|
||||
m_Listeners[i] = old[i];
|
||||
|
||||
m_Listeners[old.Length] = l;
|
||||
}
|
||||
|
||||
private void CheckListener()
|
||||
{
|
||||
for ( int j = 0; j < m_Listeners.Length; ++j )
|
||||
{
|
||||
Socket[] accepted = m_Listeners[j].Slice();
|
||||
|
||||
for ( int i = 0; i < accepted.Length; ++i )
|
||||
{
|
||||
NetState ns = new NetState( accepted[i], this );
|
||||
ns.Start();
|
||||
|
||||
if ( ns.Running )
|
||||
Console.WriteLine( "Client: {0}: Connected. [{1} Online]", ns, NetState.Instances.Count );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void OnReceive( NetState ns )
|
||||
{
|
||||
lock ( this )
|
||||
m_Queue.Enqueue( ns );
|
||||
}
|
||||
|
||||
public void Slice()
|
||||
{
|
||||
CheckListener();
|
||||
|
||||
lock ( this )
|
||||
{
|
||||
Queue<NetState> temp = m_WorkingQueue;
|
||||
m_WorkingQueue = m_Queue;
|
||||
m_Queue = temp;
|
||||
}
|
||||
|
||||
while ( m_WorkingQueue.Count > 0 )
|
||||
{
|
||||
NetState ns = m_WorkingQueue.Dequeue();
|
||||
|
||||
if ( ns.Running )
|
||||
HandleReceive( ns );
|
||||
}
|
||||
|
||||
lock ( this )
|
||||
{
|
||||
while ( m_Throttled.Count > 0 )
|
||||
m_Queue.Enqueue( m_Throttled.Dequeue() );
|
||||
}
|
||||
}
|
||||
|
||||
private const int BufferSize = 4096;
|
||||
private BufferPool m_Buffers = new BufferPool( "Processor", 4, BufferSize );
|
||||
|
||||
public bool HandleReceive( NetState ns )
|
||||
{
|
||||
ByteQueue buffer = ns.Buffer;
|
||||
|
||||
if ( buffer == null || buffer.Length <= 0 )
|
||||
return true;
|
||||
|
||||
lock ( buffer )
|
||||
{
|
||||
int length = buffer.Length;
|
||||
|
||||
if ( !ns.Seeded )
|
||||
{
|
||||
if ( buffer.Length >= 4 )
|
||||
{
|
||||
buffer.Dequeue( m_Peek, 0, 4 );
|
||||
|
||||
int seed = (m_Peek[0] << 24) | (m_Peek[1] << 16) | (m_Peek[2] << 8) | m_Peek[3];
|
||||
|
||||
if ( seed == 0 )
|
||||
{
|
||||
Console.WriteLine( "Login: {0}: Invalid client detected, disconnecting", ns );
|
||||
ns.Dispose();
|
||||
return false;
|
||||
}
|
||||
|
||||
ns.m_Seed = seed;
|
||||
ns.Seeded = true;
|
||||
|
||||
length = buffer.Length;
|
||||
}
|
||||
else
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
while ( length > 0 && ns.Running )
|
||||
{
|
||||
int packetID = buffer.GetPacketID();
|
||||
|
||||
if ( !ns.SentFirstPacket && packetID != 0xF1 && packetID != 0xCF && packetID != 0x80 && packetID != 0x91 && packetID != 0xA4 )
|
||||
{
|
||||
Console.WriteLine( "Client: {0}: Encrypted client detected, disconnecting", ns );
|
||||
ns.Dispose();
|
||||
break;
|
||||
}
|
||||
|
||||
PacketHandler handler = PacketHandlers.GetHandler( packetID );
|
||||
|
||||
if ( handler == null )
|
||||
{
|
||||
byte[] data = new byte[length];
|
||||
length = buffer.Dequeue( data, 0, length );
|
||||
|
||||
new PacketReader( data, length, false ).Trace( ns );
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
int packetLength = handler.Length;
|
||||
|
||||
if ( packetLength <= 0 )
|
||||
{
|
||||
if ( length >= 3 )
|
||||
{
|
||||
packetLength = buffer.GetPacketLength();
|
||||
|
||||
if ( packetLength < 3 )
|
||||
{
|
||||
ns.Dispose();
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( length >= packetLength )
|
||||
{
|
||||
if ( handler.Ingame && ns.Mobile == null )
|
||||
{
|
||||
Console.WriteLine( "Client: {0}: Sent ingame packet (0x{1:X2}) before having been attached to a mobile", ns, packetID );
|
||||
ns.Dispose();
|
||||
break;
|
||||
}
|
||||
else if ( handler.Ingame && ns.Mobile.Deleted )
|
||||
{
|
||||
ns.Dispose();
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
ThrottlePacketCallback throttler = handler.ThrottleCallback;
|
||||
|
||||
if ( throttler != null && !throttler( ns ) )
|
||||
{
|
||||
m_Throttled.Enqueue( ns );
|
||||
return false;
|
||||
}
|
||||
|
||||
PacketProfile profile = PacketProfile.GetIncomingProfile( packetID );
|
||||
DateTime start = ( profile == null ? DateTime.MinValue : DateTime.Now );
|
||||
|
||||
byte[] packetBuffer;
|
||||
|
||||
if ( BufferSize >= packetLength )
|
||||
packetBuffer = m_Buffers.AcquireBuffer();
|
||||
else
|
||||
packetBuffer = new byte[packetLength];
|
||||
|
||||
packetLength = buffer.Dequeue( packetBuffer, 0, packetLength );
|
||||
|
||||
PacketReader r = new PacketReader( packetBuffer, packetLength, handler.Length != 0 );
|
||||
|
||||
handler.OnReceive( ns, r );
|
||||
length = buffer.Length;
|
||||
|
||||
if ( BufferSize >= packetLength )
|
||||
m_Buffers.ReleaseBuffer( packetBuffer );
|
||||
|
||||
if ( profile != null )
|
||||
profile.Record( packetLength, DateTime.Now - start );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
907
Server/Network/NetState.cs
Normal file
907
Server/Network/NetState.cs
Normal file
|
|
@ -0,0 +1,907 @@
|
|||
/***************************************************************************
|
||||
* NetState.cs
|
||||
* -------------------
|
||||
* begin : May 1, 2002
|
||||
* copyright : (C) The RunUO Software Team
|
||||
* email : info@runuo.com
|
||||
*
|
||||
* $Id: NetState.cs 156 2006-06-11 09:36:25Z asayre $
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using Server;
|
||||
using Server.Accounting;
|
||||
using Server.Network;
|
||||
using Server.Items;
|
||||
using Server.Gumps;
|
||||
using Server.Menus;
|
||||
using Server.HuePickers;
|
||||
|
||||
namespace Server.Network
|
||||
{
|
||||
public interface IPacketEncoder
|
||||
{
|
||||
void EncodeOutgoingPacket( NetState to, ref byte[] buffer, ref int length );
|
||||
void DecodeIncomingPacket( NetState from, ref byte[] buffer, ref int length );
|
||||
}
|
||||
|
||||
public delegate void NetStateCreatedCallback( NetState ns );
|
||||
|
||||
public class NetState
|
||||
{
|
||||
private Socket m_Socket;
|
||||
private IPAddress m_Address;
|
||||
private ByteQueue m_Buffer;
|
||||
private byte[] m_RecvBuffer;
|
||||
private SendQueue m_SendQueue;
|
||||
private bool m_Seeded;
|
||||
private bool m_Running;
|
||||
private AsyncCallback m_OnReceive, m_OnSend;
|
||||
private MessagePump m_MessagePump;
|
||||
private ServerInfo[] m_ServerInfo;
|
||||
private IAccount m_Account;
|
||||
private Mobile m_Mobile;
|
||||
private CityInfo[] m_CityInfo;
|
||||
private List<Gump> m_Gumps;
|
||||
private List<HuePicker> m_HuePickers;
|
||||
private List<IMenu> m_Menus;
|
||||
private List<SecureTrade> m_Trades;
|
||||
private int m_Sequence;
|
||||
private bool m_CompressionEnabled;
|
||||
private string m_ToString;
|
||||
private ClientVersion m_Version;
|
||||
private bool m_SentFirstPacket;
|
||||
private bool m_BlockAllPackets;
|
||||
|
||||
private DateTime m_ConnectedOn;
|
||||
|
||||
public DateTime ConnectedOn
|
||||
{
|
||||
get { return m_ConnectedOn; }
|
||||
}
|
||||
|
||||
public TimeSpan ConnectedFor
|
||||
{
|
||||
get { return ( DateTime.Now - m_ConnectedOn ); }
|
||||
}
|
||||
|
||||
internal int m_Seed;
|
||||
internal int m_AuthID;
|
||||
|
||||
public IPAddress Address
|
||||
{
|
||||
get{ return m_Address; }
|
||||
}
|
||||
|
||||
private int m_Flags;
|
||||
|
||||
private static bool m_Paused;
|
||||
|
||||
[Flags]
|
||||
private enum AsyncState
|
||||
{
|
||||
Pending = 0x01,
|
||||
Paused = 0x02
|
||||
}
|
||||
|
||||
private AsyncState m_AsyncState;
|
||||
private object m_AsyncLock = new object();
|
||||
|
||||
public static void Pause()
|
||||
{
|
||||
m_Paused = true;
|
||||
|
||||
for ( int i = 0; i < m_Instances.Count; ++i )
|
||||
{
|
||||
NetState ns = m_Instances[i];
|
||||
|
||||
lock ( ns.m_AsyncLock )
|
||||
ns.m_AsyncState |= AsyncState.Paused;
|
||||
}
|
||||
}
|
||||
|
||||
private void InternalBeginReceive()
|
||||
{
|
||||
m_AsyncState |= AsyncState.Pending;
|
||||
|
||||
IAsyncResult res = m_Socket.BeginReceive( m_RecvBuffer, 0, m_RecvBuffer.Length, SocketFlags.None, m_OnReceive, null );
|
||||
}
|
||||
|
||||
public static void Resume()
|
||||
{
|
||||
m_Paused = false;
|
||||
|
||||
for ( int i = 0; i < m_Instances.Count; ++i )
|
||||
{
|
||||
NetState ns = m_Instances[i];
|
||||
|
||||
if ( ns.m_Socket == null )
|
||||
continue;
|
||||
|
||||
lock ( ns.m_AsyncLock )
|
||||
{
|
||||
ns.m_AsyncState &= ~AsyncState.Paused;
|
||||
|
||||
try
|
||||
{
|
||||
if ( (ns.m_AsyncState & AsyncState.Pending) == 0 )
|
||||
ns.InternalBeginReceive();
|
||||
}
|
||||
catch
|
||||
{
|
||||
ns.Dispose( false );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private IPacketEncoder m_Encoder = null;
|
||||
|
||||
public IPacketEncoder PacketEncoder
|
||||
{
|
||||
get{ return m_Encoder; }
|
||||
set{ m_Encoder = value; }
|
||||
}
|
||||
|
||||
private static NetStateCreatedCallback m_CreatedCallback;
|
||||
|
||||
public static NetStateCreatedCallback CreatedCallback
|
||||
{
|
||||
get{ return m_CreatedCallback; }
|
||||
set{ m_CreatedCallback = value; }
|
||||
}
|
||||
|
||||
public bool SentFirstPacket{ get{ return m_SentFirstPacket; } set{ m_SentFirstPacket = value; } }
|
||||
|
||||
public bool BlockAllPackets
|
||||
{
|
||||
get
|
||||
{
|
||||
return m_BlockAllPackets;
|
||||
}
|
||||
set
|
||||
{
|
||||
m_BlockAllPackets = value;
|
||||
}
|
||||
}
|
||||
|
||||
public int Flags
|
||||
{
|
||||
get
|
||||
{
|
||||
return m_Flags;
|
||||
}
|
||||
set
|
||||
{
|
||||
m_Flags = value;
|
||||
}
|
||||
}
|
||||
|
||||
public ClientVersion Version
|
||||
{
|
||||
get
|
||||
{
|
||||
return m_Version;
|
||||
}
|
||||
set
|
||||
{
|
||||
m_Version = value;
|
||||
}
|
||||
}
|
||||
|
||||
public List<SecureTrade> Trades
|
||||
{
|
||||
get
|
||||
{
|
||||
return m_Trades;
|
||||
}
|
||||
}
|
||||
|
||||
public void ValidateAllTrades()
|
||||
{
|
||||
for ( int i = m_Trades.Count - 1; i >= 0; --i )
|
||||
{
|
||||
if ( i >= m_Trades.Count )
|
||||
continue;
|
||||
|
||||
SecureTrade trade = m_Trades[i];
|
||||
|
||||
if ( trade.From.Mobile.Deleted || trade.To.Mobile.Deleted || !trade.From.Mobile.Alive || !trade.To.Mobile.Alive || !trade.From.Mobile.InRange( trade.To.Mobile, 2 ) || trade.From.Mobile.Map != trade.To.Mobile.Map )
|
||||
trade.Cancel();
|
||||
}
|
||||
}
|
||||
|
||||
public void CancelAllTrades()
|
||||
{
|
||||
for ( int i = m_Trades.Count - 1; i >= 0; --i )
|
||||
if ( i < m_Trades.Count )
|
||||
m_Trades[i].Cancel();
|
||||
}
|
||||
|
||||
public void RemoveTrade( SecureTrade trade )
|
||||
{
|
||||
m_Trades.Remove( trade );
|
||||
}
|
||||
|
||||
public SecureTrade FindTrade( Mobile m )
|
||||
{
|
||||
for ( int i = 0; i < m_Trades.Count; ++i )
|
||||
{
|
||||
SecureTrade trade = m_Trades[i];
|
||||
|
||||
if ( trade.From.Mobile == m || trade.To.Mobile == m )
|
||||
return trade;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public SecureTradeContainer FindTradeContainer( Mobile m )
|
||||
{
|
||||
for ( int i = 0; i < m_Trades.Count; ++i )
|
||||
{
|
||||
SecureTrade trade = m_Trades[i];
|
||||
SecureTradeInfo from = trade.From;
|
||||
SecureTradeInfo to = trade.To;
|
||||
|
||||
if ( from.Mobile == m_Mobile && to.Mobile == m )
|
||||
return from.Container;
|
||||
else if ( from.Mobile == m && to.Mobile == m_Mobile )
|
||||
return to.Container;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public SecureTradeContainer AddTrade( NetState state )
|
||||
{
|
||||
SecureTrade newTrade = new SecureTrade( m_Mobile, state.m_Mobile );
|
||||
|
||||
m_Trades.Add( newTrade );
|
||||
state.m_Trades.Add( newTrade );
|
||||
|
||||
return newTrade.From.Container;
|
||||
}
|
||||
|
||||
public bool CompressionEnabled
|
||||
{
|
||||
get
|
||||
{
|
||||
return m_CompressionEnabled;
|
||||
}
|
||||
set
|
||||
{
|
||||
m_CompressionEnabled = value;
|
||||
}
|
||||
}
|
||||
|
||||
public int Sequence
|
||||
{
|
||||
get
|
||||
{
|
||||
return m_Sequence;
|
||||
}
|
||||
set
|
||||
{
|
||||
m_Sequence = value;
|
||||
}
|
||||
}
|
||||
|
||||
public List<Gump> Gumps{ get{ return m_Gumps; } }
|
||||
public List<HuePicker> HuePickers{ get{ return m_HuePickers; } }
|
||||
public List<IMenu> Menus{ get{ return m_Menus; } }
|
||||
|
||||
private static int m_GumpCap = 512, m_HuePickerCap = 512, m_MenuCap = 512;
|
||||
|
||||
public static int GumpCap{ get{ return m_GumpCap; } set{ m_GumpCap = value; } }
|
||||
public static int HuePickerCap{ get{ return m_HuePickerCap; } set{ m_HuePickerCap = value; } }
|
||||
public static int MenuCap{ get{ return m_MenuCap; } set{ m_MenuCap = value; } }
|
||||
|
||||
public void AddMenu( IMenu menu )
|
||||
{
|
||||
if ( m_Menus == null )
|
||||
return;
|
||||
|
||||
if ( m_Menus.Count >= m_MenuCap )
|
||||
{
|
||||
Console.WriteLine( "Client: {0}: Exceeded menu cap, disconnecting...", this );
|
||||
Dispose();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_Menus.Add( menu );
|
||||
}
|
||||
}
|
||||
|
||||
public void RemoveMenu( int index )
|
||||
{
|
||||
if ( m_Menus == null )
|
||||
return;
|
||||
|
||||
m_Menus.RemoveAt( index );
|
||||
}
|
||||
|
||||
public void AddHuePicker( HuePicker huePicker )
|
||||
{
|
||||
if ( m_HuePickers == null )
|
||||
return;
|
||||
|
||||
if ( m_HuePickers.Count >= m_HuePickerCap )
|
||||
{
|
||||
Console.WriteLine( "Client: {0}: Exceeded hue picker cap, disconnecting...", this );
|
||||
Dispose();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_HuePickers.Add( huePicker );
|
||||
}
|
||||
}
|
||||
|
||||
public void RemoveHuePicker( int index )
|
||||
{
|
||||
if ( m_HuePickers == null )
|
||||
return;
|
||||
|
||||
m_HuePickers.RemoveAt( index );
|
||||
}
|
||||
|
||||
public void AddGump( Gump g )
|
||||
{
|
||||
if ( m_Gumps == null )
|
||||
return;
|
||||
|
||||
if ( m_Gumps.Count >= m_GumpCap )
|
||||
{
|
||||
Console.WriteLine( "Client: {0}: Exceeded gump cap, disconnecting...", this );
|
||||
Dispose();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_Gumps.Add( g );
|
||||
}
|
||||
}
|
||||
|
||||
public void RemoveGump( int index )
|
||||
{
|
||||
if ( m_Gumps == null )
|
||||
return;
|
||||
else if( index >= m_Gumps.Count )
|
||||
{
|
||||
Console.WriteLine( "Error: Attempting to remove Gump with index not in bounds of array." );
|
||||
return;
|
||||
}
|
||||
|
||||
m_Gumps.RemoveAt( index );
|
||||
}
|
||||
|
||||
public CityInfo[] CityInfo
|
||||
{
|
||||
get
|
||||
{
|
||||
return m_CityInfo;
|
||||
}
|
||||
set
|
||||
{
|
||||
m_CityInfo = value;
|
||||
}
|
||||
}
|
||||
|
||||
public Mobile Mobile
|
||||
{
|
||||
get
|
||||
{
|
||||
return m_Mobile;
|
||||
}
|
||||
set
|
||||
{
|
||||
m_Mobile = value;
|
||||
}
|
||||
}
|
||||
|
||||
public ServerInfo[] ServerInfo
|
||||
{
|
||||
get
|
||||
{
|
||||
return m_ServerInfo;
|
||||
}
|
||||
set
|
||||
{
|
||||
m_ServerInfo = value;
|
||||
}
|
||||
}
|
||||
|
||||
public IAccount Account
|
||||
{
|
||||
get
|
||||
{
|
||||
return m_Account;
|
||||
}
|
||||
set
|
||||
{
|
||||
m_Account = value;
|
||||
}
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return m_ToString;
|
||||
}
|
||||
|
||||
private static List<NetState> m_Instances = new List<NetState>();
|
||||
|
||||
public static List<NetState> Instances
|
||||
{
|
||||
get
|
||||
{
|
||||
return m_Instances;
|
||||
}
|
||||
}
|
||||
|
||||
private static BufferPool m_ReceiveBufferPool = new BufferPool( "Receive", 2048, 2048 );
|
||||
|
||||
public NetState( Socket socket, MessagePump messagePump )
|
||||
{
|
||||
m_Socket = socket;
|
||||
m_Buffer = new ByteQueue();
|
||||
m_Seeded = false;
|
||||
m_Running = false;
|
||||
m_RecvBuffer = m_ReceiveBufferPool.AcquireBuffer();
|
||||
m_MessagePump = messagePump;
|
||||
m_Gumps = new List<Gump>();
|
||||
m_HuePickers = new List<HuePicker>();
|
||||
m_Menus = new List<IMenu>();
|
||||
m_Trades = new List<SecureTrade>();
|
||||
|
||||
m_SendQueue = new SendQueue();
|
||||
|
||||
m_NextCheckActivity = DateTime.Now + TimeSpan.FromMinutes( 0.5 );
|
||||
|
||||
m_Instances.Add( this );
|
||||
|
||||
try{ m_Address = ((IPEndPoint)m_Socket.RemoteEndPoint).Address; m_ToString = m_Address.ToString(); }
|
||||
catch{ m_Address = IPAddress.None; m_ToString = "(error)"; }
|
||||
|
||||
m_ConnectedOn = DateTime.Now;
|
||||
|
||||
if ( m_CreatedCallback != null )
|
||||
m_CreatedCallback( this );
|
||||
}
|
||||
|
||||
public void Send( Packet p )
|
||||
{
|
||||
if ( m_Socket == null || m_BlockAllPackets )
|
||||
{
|
||||
p.OnSend();
|
||||
return;
|
||||
}
|
||||
|
||||
PacketProfile prof = PacketProfile.GetOutgoingProfile( (byte)p.PacketID );
|
||||
DateTime start = ( prof == null ? DateTime.MinValue : DateTime.Now );
|
||||
|
||||
int length;
|
||||
byte[] buffer = p.Compile( m_CompressionEnabled, out length );
|
||||
|
||||
if ( buffer != null )
|
||||
{
|
||||
if ( buffer.Length <= 0 || length <= 0 )
|
||||
{
|
||||
p.OnSend();
|
||||
return;
|
||||
}
|
||||
|
||||
if ( m_Encoder != null )
|
||||
m_Encoder.EncodeOutgoingPacket( this, ref buffer, ref length );
|
||||
|
||||
SendEnqueueResult enqueueResult;
|
||||
|
||||
lock ( m_SendQueue )
|
||||
enqueueResult = ( m_SendQueue.Enqueue( buffer, length ) );
|
||||
|
||||
if ( enqueueResult == SendEnqueueResult.Begin )
|
||||
{
|
||||
int sendLength = 0;
|
||||
byte[] sendBuffer = m_SendQueue.Peek( ref sendLength );
|
||||
|
||||
try
|
||||
{
|
||||
IAsyncResult res = m_Socket.BeginSend( sendBuffer, 0, sendLength, SocketFlags.None, m_OnSend, null );
|
||||
//Console.WriteLine( "Send: {0}: Begin send of {1} bytes", this, sendLength );
|
||||
}
|
||||
catch // ( Exception ex )
|
||||
{
|
||||
//Console.WriteLine(ex);
|
||||
Dispose( false );
|
||||
}
|
||||
}
|
||||
else if ( enqueueResult == SendEnqueueResult.Overflow )
|
||||
{
|
||||
Console.WriteLine( "Client: {0}: Too much data pending, disconnecting...", this );
|
||||
Dispose( false );
|
||||
}
|
||||
|
||||
p.OnSend();
|
||||
|
||||
if ( prof != null )
|
||||
prof.Record( length, DateTime.Now - start );
|
||||
}
|
||||
else
|
||||
{
|
||||
Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
public static void FlushAll()
|
||||
{
|
||||
for ( int i = 0; i < m_Instances.Count; ++i )
|
||||
{
|
||||
NetState ns = m_Instances[i];
|
||||
|
||||
ns.Flush();
|
||||
}
|
||||
}
|
||||
|
||||
public bool Flush()
|
||||
{
|
||||
if ( m_Socket == null || !m_SendQueue.IsFlushReady )
|
||||
return false;
|
||||
|
||||
int length = 0;
|
||||
byte[] buffer;
|
||||
|
||||
lock ( m_SendQueue )
|
||||
buffer = m_SendQueue.CheckFlushReady( ref length );
|
||||
|
||||
if ( buffer != null )
|
||||
{
|
||||
try
|
||||
{
|
||||
IAsyncResult res = m_Socket.BeginSend( buffer, 0, length, SocketFlags.None, m_OnSend, null );
|
||||
return true;
|
||||
//Console.WriteLine( "Flush: {0}: Begin send of {1} bytes", this, length );
|
||||
}
|
||||
catch // ( Exception ex )
|
||||
{
|
||||
//Console.WriteLine(ex);
|
||||
Dispose( false );
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static int m_CoalesceSleep = -1;
|
||||
|
||||
public static int CoalesceSleep
|
||||
{
|
||||
get{ return m_CoalesceSleep; }
|
||||
set{ m_CoalesceSleep = value; }
|
||||
}
|
||||
|
||||
private void OnSend( IAsyncResult asyncResult )
|
||||
{
|
||||
if ( m_Socket == null )
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
int bytes = m_Socket.EndSend( asyncResult );
|
||||
|
||||
if ( bytes <= 0 )
|
||||
{
|
||||
Dispose( false );
|
||||
return;
|
||||
}
|
||||
|
||||
//Console.WriteLine( "OnSend: {0}: Complete send of {1} bytes", this, bytes );
|
||||
|
||||
m_NextCheckActivity = DateTime.Now + TimeSpan.FromMinutes( 1.2 );
|
||||
|
||||
if ( m_CoalesceSleep >= 0 )
|
||||
System.Threading.Thread.Sleep( m_CoalesceSleep );
|
||||
|
||||
int length = 0;
|
||||
byte[] queued;
|
||||
|
||||
lock ( m_SendQueue )
|
||||
queued = m_SendQueue.Dequeue( ref length );
|
||||
|
||||
if ( queued != null )
|
||||
{
|
||||
IAsyncResult res = m_Socket.BeginSend( queued, 0, length, SocketFlags.None, m_OnSend, null );
|
||||
//Console.WriteLine( "OnSend: {0}: Begin send of {1} bytes", this, length );
|
||||
}
|
||||
}
|
||||
catch // ( Exception ex )
|
||||
{
|
||||
//Console.WriteLine(ex);
|
||||
Dispose( false );
|
||||
}
|
||||
}
|
||||
|
||||
public void Start()
|
||||
{
|
||||
m_OnReceive = new AsyncCallback( OnReceive );
|
||||
m_OnSend = new AsyncCallback( OnSend );
|
||||
|
||||
m_Running = true;
|
||||
|
||||
if ( m_Socket == null || m_Paused )
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
lock ( m_AsyncLock )
|
||||
{
|
||||
if ( (m_AsyncState & (AsyncState.Pending | AsyncState.Paused)) == 0 )
|
||||
InternalBeginReceive();
|
||||
}
|
||||
}
|
||||
catch // ( Exception ex )
|
||||
{
|
||||
//Console.WriteLine(ex);
|
||||
Dispose( false );
|
||||
}
|
||||
}
|
||||
|
||||
public void LaunchBrowser( string url )
|
||||
{
|
||||
Send( new MessageLocalized( Serial.MinusOne, -1, MessageType.Label, 0x35, 3, 501231, "", "" ) );
|
||||
Send( new LaunchBrowser( url ) );
|
||||
}
|
||||
|
||||
private DateTime m_NextCheckActivity;
|
||||
|
||||
public bool CheckAlive()
|
||||
{
|
||||
if ( m_Socket == null )
|
||||
return false;
|
||||
|
||||
if ( DateTime.Now < m_NextCheckActivity )
|
||||
return true;
|
||||
|
||||
Console.WriteLine( "Client: {0}: Disconnecting due to inactivity...", this );
|
||||
|
||||
Dispose();
|
||||
return false;
|
||||
}
|
||||
|
||||
private void OnReceive( IAsyncResult asyncResult )
|
||||
{
|
||||
if ( m_Socket == null )
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
int byteCount = m_Socket.EndReceive( asyncResult );
|
||||
|
||||
if ( byteCount > 0 )
|
||||
{
|
||||
m_NextCheckActivity = DateTime.Now + TimeSpan.FromMinutes( 1.2 );
|
||||
|
||||
byte[] buffer = m_RecvBuffer;
|
||||
|
||||
if ( m_Encoder != null )
|
||||
m_Encoder.DecodeIncomingPacket( this, ref buffer, ref byteCount );
|
||||
|
||||
lock ( m_Buffer )
|
||||
m_Buffer.Enqueue( buffer, 0, byteCount );
|
||||
|
||||
m_MessagePump.OnReceive( this );
|
||||
|
||||
lock ( m_AsyncLock )
|
||||
{
|
||||
m_AsyncState &= ~AsyncState.Pending;
|
||||
|
||||
if ( (m_AsyncState & AsyncState.Paused) == 0 )
|
||||
InternalBeginReceive();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Dispose( false );
|
||||
}
|
||||
}
|
||||
catch // ( Exception ex )
|
||||
{
|
||||
//Console.WriteLine(ex);
|
||||
Dispose( false );
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose( true );
|
||||
}
|
||||
|
||||
private bool m_Disposing;
|
||||
|
||||
public void Dispose( bool flush )
|
||||
{
|
||||
if ( m_Socket == null || m_Disposing )
|
||||
return;
|
||||
|
||||
m_Disposing = true;
|
||||
|
||||
if ( flush )
|
||||
flush = Flush();
|
||||
|
||||
try { m_Socket.Shutdown( SocketShutdown.Both ); }
|
||||
catch {}
|
||||
|
||||
try { m_Socket.Close(); }
|
||||
catch {}
|
||||
|
||||
if ( m_RecvBuffer != null )
|
||||
m_ReceiveBufferPool.ReleaseBuffer( m_RecvBuffer );
|
||||
|
||||
m_Socket = null;
|
||||
|
||||
m_Buffer = null;
|
||||
m_RecvBuffer = null;
|
||||
m_OnReceive = null;
|
||||
m_OnSend = null;
|
||||
m_Running = false;
|
||||
|
||||
m_Disposed.Enqueue( this );
|
||||
|
||||
if ( /*!flush &&*/ !m_SendQueue.IsEmpty )
|
||||
{
|
||||
lock ( m_SendQueue )
|
||||
m_SendQueue.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
public static void Initialize()
|
||||
{
|
||||
Timer.DelayCall( TimeSpan.FromMinutes( 1.0 ), TimeSpan.FromMinutes( 1.5 ), new TimerCallback( CheckAllAlive ) );
|
||||
}
|
||||
|
||||
public static void CheckAllAlive()
|
||||
{
|
||||
try
|
||||
{
|
||||
for ( int i = 0; i < m_Instances.Count; ++i )
|
||||
m_Instances[i].CheckAlive();
|
||||
}
|
||||
catch // ( Exception ex )
|
||||
{
|
||||
//Console.WriteLine(ex);
|
||||
}
|
||||
}
|
||||
|
||||
private static Queue m_Disposed = Queue.Synchronized( new Queue() );
|
||||
|
||||
public static void ProcessDisposedQueue()
|
||||
{
|
||||
int breakout = 0;
|
||||
|
||||
while ( breakout < 200 && m_Disposed.Count > 0 )
|
||||
{
|
||||
++breakout;
|
||||
|
||||
NetState ns = (NetState)m_Disposed.Dequeue();
|
||||
|
||||
Mobile m = ns.m_Mobile;
|
||||
IAccount a = ns.m_Account;
|
||||
|
||||
if ( m != null )
|
||||
{
|
||||
m.NetState = null;
|
||||
ns.m_Mobile = null;
|
||||
}
|
||||
|
||||
ns.m_Gumps.Clear();
|
||||
ns.m_Menus.Clear();
|
||||
ns.m_HuePickers.Clear();
|
||||
ns.m_Account = null;
|
||||
ns.m_ServerInfo = null;
|
||||
ns.m_CityInfo = null;
|
||||
|
||||
m_Instances.Remove( ns );
|
||||
|
||||
if ( a != null )
|
||||
Console.WriteLine( "Client: {0}: Disconnected. [{1} Online] [{2}]", ns, m_Instances.Count, a );
|
||||
else
|
||||
Console.WriteLine( "Client: {0}: Disconnected. [{1} Online]", ns, m_Instances.Count );
|
||||
}
|
||||
}
|
||||
|
||||
public bool Running
|
||||
{
|
||||
get
|
||||
{
|
||||
return m_Running;
|
||||
}
|
||||
}
|
||||
|
||||
public bool Seeded
|
||||
{
|
||||
get
|
||||
{
|
||||
return m_Seeded;
|
||||
}
|
||||
set
|
||||
{
|
||||
m_Seeded = value;
|
||||
}
|
||||
}
|
||||
|
||||
public Socket Socket
|
||||
{
|
||||
get
|
||||
{
|
||||
return m_Socket;
|
||||
}
|
||||
}
|
||||
|
||||
public ByteQueue Buffer
|
||||
{
|
||||
get
|
||||
{
|
||||
return m_Buffer;
|
||||
}
|
||||
}
|
||||
|
||||
public ExpansionInfo ExpansionInfo
|
||||
{
|
||||
get
|
||||
{
|
||||
for( int i = ExpansionInfo.Table.Length -1; i >= 0; i-- )
|
||||
{
|
||||
ExpansionInfo info = ExpansionInfo.Table[i];
|
||||
|
||||
if ( (info.RequiredClient != null && this.Version >= info.RequiredClient) || ((this.Flags & info.NetStateFlag) != 0) )
|
||||
return info;
|
||||
}
|
||||
|
||||
return ExpansionInfo.GetInfo( Expansion.None );
|
||||
}
|
||||
}
|
||||
|
||||
public Expansion Expansion
|
||||
{
|
||||
get{ return (Expansion)this.ExpansionInfo.ID; }
|
||||
}
|
||||
|
||||
public bool SupportsExpansion( ExpansionInfo info, bool checkCoreExpansion )
|
||||
{
|
||||
if( info == null || ( checkCoreExpansion && (int)Core.Expansion < info.ID ) )
|
||||
return false;
|
||||
|
||||
if ( info.RequiredClient != null )
|
||||
return (this.Version >= info.RequiredClient);
|
||||
|
||||
return ( (this.Flags & info.NetStateFlag) != 0);
|
||||
}
|
||||
|
||||
public bool SupportsExpansion( Expansion ex, bool checkCoreExpansion )
|
||||
{
|
||||
return SupportsExpansion( ExpansionInfo.GetInfo( ex ), checkCoreExpansion );
|
||||
}
|
||||
|
||||
public bool SupportsExpansion( Expansion ex )
|
||||
{
|
||||
return SupportsExpansion( ex, true );
|
||||
}
|
||||
|
||||
public bool SupportsExpansion( ExpansionInfo info )
|
||||
{
|
||||
return SupportsExpansion( info, true );
|
||||
}
|
||||
}
|
||||
}
|
||||
82
Server/Network/PacketHandler.cs
Normal file
82
Server/Network/PacketHandler.cs
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
/***************************************************************************
|
||||
* PacketHandler.cs
|
||||
* -------------------
|
||||
* begin : May 1, 2002
|
||||
* copyright : (C) The RunUO Software Team
|
||||
* email : info@runuo.com
|
||||
*
|
||||
* $Id: PacketHandler.cs 20 2006-01-15 23:50:35Z asayre $
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
using System;
|
||||
|
||||
namespace Server.Network
|
||||
{
|
||||
public delegate void OnPacketReceive( NetState state, PacketReader pvSrc );
|
||||
public delegate bool ThrottlePacketCallback( NetState state );
|
||||
|
||||
public class PacketHandler
|
||||
{
|
||||
private int m_PacketID;
|
||||
private int m_Length;
|
||||
private bool m_Ingame;
|
||||
private OnPacketReceive m_OnReceive;
|
||||
private ThrottlePacketCallback m_ThrottleCallback;
|
||||
|
||||
public PacketHandler( int packetID, int length, bool ingame, OnPacketReceive onReceive )
|
||||
{
|
||||
m_PacketID = packetID;
|
||||
m_Length = length;
|
||||
m_Ingame = ingame;
|
||||
m_OnReceive = onReceive;
|
||||
}
|
||||
|
||||
public int PacketID
|
||||
{
|
||||
get
|
||||
{
|
||||
return m_PacketID;
|
||||
}
|
||||
}
|
||||
|
||||
public int Length
|
||||
{
|
||||
get
|
||||
{
|
||||
return m_Length;
|
||||
}
|
||||
}
|
||||
|
||||
public OnPacketReceive OnReceive
|
||||
{
|
||||
get
|
||||
{
|
||||
return m_OnReceive;
|
||||
}
|
||||
}
|
||||
|
||||
public ThrottlePacketCallback ThrottleCallback
|
||||
{
|
||||
get{ return m_ThrottleCallback; }
|
||||
set{ m_ThrottleCallback = value; }
|
||||
}
|
||||
|
||||
public bool Ingame
|
||||
{
|
||||
get
|
||||
{
|
||||
return m_Ingame;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
2261
Server/Network/PacketHandlers.cs
Normal file
2261
Server/Network/PacketHandlers.cs
Normal file
File diff suppressed because it is too large
Load diff
159
Server/Network/PacketProfile.cs
Normal file
159
Server/Network/PacketProfile.cs
Normal file
|
|
@ -0,0 +1,159 @@
|
|||
/***************************************************************************
|
||||
* PacketProfile.cs
|
||||
* -------------------
|
||||
* begin : May 1, 2002
|
||||
* copyright : (C) The RunUO Software Team
|
||||
* email : info@runuo.com
|
||||
*
|
||||
* $Id: PacketProfile.cs 20 2006-01-15 23:50:35Z asayre $
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
using System;
|
||||
|
||||
namespace Server.Network
|
||||
{
|
||||
public class PacketProfile
|
||||
{
|
||||
private int m_Constructed;
|
||||
private int m_Count;
|
||||
private int m_TotalByteLength;
|
||||
private TimeSpan m_TotalProcTime;
|
||||
private TimeSpan m_PeakProcTime;
|
||||
private bool m_Outgoing;
|
||||
|
||||
[CommandProperty( AccessLevel.Administrator )]
|
||||
public bool Outgoing
|
||||
{
|
||||
get{ return m_Outgoing; }
|
||||
}
|
||||
|
||||
[CommandProperty( AccessLevel.Administrator )]
|
||||
public int Constructed
|
||||
{
|
||||
get{ return m_Constructed; }
|
||||
}
|
||||
|
||||
[CommandProperty( AccessLevel.Administrator )]
|
||||
public int TotalByteLength
|
||||
{
|
||||
get{ return m_TotalByteLength; }
|
||||
}
|
||||
|
||||
[CommandProperty( AccessLevel.Administrator )]
|
||||
public TimeSpan TotalProcTime
|
||||
{
|
||||
get{ return m_TotalProcTime; }
|
||||
}
|
||||
|
||||
[CommandProperty( AccessLevel.Administrator )]
|
||||
public TimeSpan PeakProcTime
|
||||
{
|
||||
get{ return m_PeakProcTime; }
|
||||
}
|
||||
|
||||
[CommandProperty( AccessLevel.Administrator )]
|
||||
public int Count
|
||||
{
|
||||
get{ return m_Count; }
|
||||
}
|
||||
|
||||
[CommandProperty( AccessLevel.Administrator )]
|
||||
public double AverageByteLength
|
||||
{
|
||||
get
|
||||
{
|
||||
if ( m_Count == 0 )
|
||||
return 0;
|
||||
|
||||
return Math.Round( (double) m_TotalByteLength / m_Count, 2 );
|
||||
}
|
||||
}
|
||||
|
||||
[CommandProperty( AccessLevel.Administrator )]
|
||||
public TimeSpan AverageProcTime
|
||||
{
|
||||
get
|
||||
{
|
||||
if ( m_Count == 0 )
|
||||
return TimeSpan.Zero;
|
||||
|
||||
return TimeSpan.FromTicks( m_TotalProcTime.Ticks / m_Count );
|
||||
}
|
||||
}
|
||||
|
||||
public void Record( int byteLength, TimeSpan processTime )
|
||||
{
|
||||
++m_Count;
|
||||
m_TotalByteLength += byteLength;
|
||||
m_TotalProcTime += processTime;
|
||||
|
||||
if ( processTime > m_PeakProcTime )
|
||||
m_PeakProcTime = processTime;
|
||||
}
|
||||
|
||||
public void RegConstruct()
|
||||
{
|
||||
++m_Constructed;
|
||||
}
|
||||
|
||||
public PacketProfile( bool outgoing )
|
||||
{
|
||||
m_Outgoing = outgoing;
|
||||
}
|
||||
|
||||
private static PacketProfile[] m_OutgoingProfiles;
|
||||
private static PacketProfile[] m_IncomingProfiles;
|
||||
|
||||
public static PacketProfile GetOutgoingProfile( int packetID )
|
||||
{
|
||||
if ( !Core.Profiling )
|
||||
return null;
|
||||
|
||||
PacketProfile prof = m_OutgoingProfiles[packetID];
|
||||
|
||||
if ( prof == null )
|
||||
m_OutgoingProfiles[packetID] = prof = new PacketProfile( true );
|
||||
|
||||
return prof;
|
||||
}
|
||||
|
||||
public static PacketProfile GetIncomingProfile( int packetID )
|
||||
{
|
||||
if ( !Core.Profiling )
|
||||
return null;
|
||||
|
||||
PacketProfile prof = m_IncomingProfiles[packetID];
|
||||
|
||||
if ( prof == null )
|
||||
m_IncomingProfiles[packetID] = prof = new PacketProfile( false );
|
||||
|
||||
return prof;
|
||||
}
|
||||
|
||||
public static PacketProfile[] OutgoingProfiles
|
||||
{
|
||||
get{ return m_OutgoingProfiles; }
|
||||
}
|
||||
|
||||
public static PacketProfile[] IncomingProfiles
|
||||
{
|
||||
get{ return m_IncomingProfiles; }
|
||||
}
|
||||
|
||||
static PacketProfile()
|
||||
{
|
||||
m_OutgoingProfiles = new PacketProfile[0x100];
|
||||
m_IncomingProfiles = new PacketProfile[0x100];
|
||||
}
|
||||
}
|
||||
}
|
||||
457
Server/Network/PacketReader.cs
Normal file
457
Server/Network/PacketReader.cs
Normal file
|
|
@ -0,0 +1,457 @@
|
|||
/***************************************************************************
|
||||
* PacketReader.cs
|
||||
* -------------------
|
||||
* begin : May 1, 2002
|
||||
* copyright : (C) The RunUO Software Team
|
||||
* email : info@runuo.com
|
||||
*
|
||||
* $Id: PacketReader.cs 20 2006-01-15 23:50:35Z asayre $
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Text;
|
||||
using System.IO;
|
||||
|
||||
namespace Server.Network
|
||||
{
|
||||
public class PacketReader
|
||||
{
|
||||
private byte[] m_Data;
|
||||
private int m_Size;
|
||||
private int m_Index;
|
||||
|
||||
public PacketReader( byte[] data, int size, bool fixedSize )
|
||||
{
|
||||
m_Data = data;
|
||||
m_Size = size;
|
||||
m_Index = fixedSize ? 1 : 3;
|
||||
}
|
||||
|
||||
public byte[] Buffer
|
||||
{
|
||||
get
|
||||
{
|
||||
return m_Data;
|
||||
}
|
||||
}
|
||||
|
||||
public int Size
|
||||
{
|
||||
get
|
||||
{
|
||||
return m_Size;
|
||||
}
|
||||
}
|
||||
|
||||
public void Trace( NetState state )
|
||||
{
|
||||
try
|
||||
{
|
||||
using ( StreamWriter sw = new StreamWriter( "Packets.log", true ) )
|
||||
{
|
||||
byte[] buffer = m_Data;
|
||||
|
||||
if ( buffer.Length > 0 )
|
||||
sw.WriteLine( "Client: {0}: Unhandled packet 0x{1:X2}", state, buffer[0] );
|
||||
|
||||
using ( MemoryStream ms = new MemoryStream( buffer ) )
|
||||
Utility.FormatBuffer( sw, ms, buffer.Length );
|
||||
|
||||
sw.WriteLine();
|
||||
sw.WriteLine();
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public int Seek( int offset, SeekOrigin origin )
|
||||
{
|
||||
switch ( origin )
|
||||
{
|
||||
case SeekOrigin.Begin: m_Index = offset; break;
|
||||
case SeekOrigin.Current: m_Index += offset; break;
|
||||
case SeekOrigin.End: m_Index = m_Size - offset; break;
|
||||
}
|
||||
|
||||
return m_Index;
|
||||
}
|
||||
|
||||
public int ReadInt32()
|
||||
{
|
||||
if ( (m_Index + 4) > m_Size )
|
||||
return 0;
|
||||
|
||||
return (m_Data[m_Index++] << 24)
|
||||
| (m_Data[m_Index++] << 16)
|
||||
| (m_Data[m_Index++] << 8)
|
||||
| m_Data[m_Index++];
|
||||
}
|
||||
|
||||
public short ReadInt16()
|
||||
{
|
||||
if ( (m_Index + 2) > m_Size )
|
||||
return 0;
|
||||
|
||||
return (short)((m_Data[m_Index++] << 8) | m_Data[m_Index++]);
|
||||
}
|
||||
|
||||
public byte ReadByte()
|
||||
{
|
||||
if ( (m_Index + 1) > m_Size )
|
||||
return 0;
|
||||
|
||||
return m_Data[m_Index++];
|
||||
}
|
||||
|
||||
public uint ReadUInt32()
|
||||
{
|
||||
if ( (m_Index + 4) > m_Size )
|
||||
return 0;
|
||||
|
||||
return (uint)((m_Data[m_Index++] << 24) | (m_Data[m_Index++] << 16) | (m_Data[m_Index++] << 8) | m_Data[m_Index++]);
|
||||
}
|
||||
|
||||
public ushort ReadUInt16()
|
||||
{
|
||||
if ( (m_Index + 2) > m_Size )
|
||||
return 0;
|
||||
|
||||
return (ushort)((m_Data[m_Index++] << 8) | m_Data[m_Index++]);
|
||||
}
|
||||
|
||||
public sbyte ReadSByte()
|
||||
{
|
||||
if ( (m_Index + 1) > m_Size )
|
||||
return 0;
|
||||
|
||||
return (sbyte)m_Data[m_Index++];
|
||||
}
|
||||
|
||||
public bool ReadBoolean()
|
||||
{
|
||||
if ( (m_Index + 1) > m_Size )
|
||||
return false;
|
||||
|
||||
return ( m_Data[m_Index++] != 0 );
|
||||
}
|
||||
|
||||
public string ReadUnicodeStringLE()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
int c;
|
||||
|
||||
while ( (m_Index + 1) < m_Size && (c = (m_Data[m_Index++] | (m_Data[m_Index++] << 8))) != 0 )
|
||||
sb.Append( (char)c );
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
public string ReadUnicodeStringLESafe( int fixedLength )
|
||||
{
|
||||
int bound = m_Index + (fixedLength << 1);
|
||||
int end = bound;
|
||||
|
||||
if ( bound > m_Size )
|
||||
bound = m_Size;
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
int c;
|
||||
|
||||
while ( (m_Index + 1) < bound && (c = (m_Data[m_Index++] | (m_Data[m_Index++] << 8))) != 0 )
|
||||
{
|
||||
if ( IsSafeChar( c ) )
|
||||
sb.Append( (char)c );
|
||||
}
|
||||
|
||||
m_Index = end;
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
public string ReadUnicodeStringLESafe()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
int c;
|
||||
|
||||
while ( (m_Index + 1) < m_Size && (c = (m_Data[m_Index++] | (m_Data[m_Index++] << 8))) != 0 )
|
||||
{
|
||||
if ( IsSafeChar( c ) )
|
||||
sb.Append( (char)c );
|
||||
}
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
public string ReadUnicodeStringSafe()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
int c;
|
||||
|
||||
while ( (m_Index + 1) < m_Size && (c = ((m_Data[m_Index++] << 8) | m_Data[m_Index++])) != 0 )
|
||||
{
|
||||
if ( IsSafeChar( c ) )
|
||||
sb.Append( (char)c );
|
||||
}
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
public string ReadUnicodeString()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
int c;
|
||||
|
||||
while ( (m_Index + 1) < m_Size && (c = ((m_Data[m_Index++] << 8) | m_Data[m_Index++])) != 0 )
|
||||
sb.Append( (char)c );
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
public bool IsSafeChar( int c )
|
||||
{
|
||||
return ( c >= 0x20 && c < 0xFFFE );
|
||||
}
|
||||
|
||||
public string ReadUTF8StringSafe( int fixedLength )
|
||||
{
|
||||
if ( m_Index >= m_Size )
|
||||
{
|
||||
m_Index += fixedLength;
|
||||
return String.Empty;
|
||||
}
|
||||
|
||||
int bound = m_Index + fixedLength;
|
||||
//int end = bound;
|
||||
|
||||
if ( bound > m_Size )
|
||||
bound = m_Size;
|
||||
|
||||
int count = 0;
|
||||
int index = m_Index;
|
||||
int start = m_Index;
|
||||
|
||||
while ( index < bound && m_Data[index++] != 0 )
|
||||
++count;
|
||||
|
||||
index = 0;
|
||||
|
||||
byte[] buffer = new byte[count];
|
||||
int value = 0;
|
||||
|
||||
while ( m_Index < bound && (value = m_Data[m_Index++]) != 0 )
|
||||
buffer[index++] = (byte)value;
|
||||
|
||||
string s = Utility.UTF8.GetString( buffer );
|
||||
|
||||
bool isSafe = true;
|
||||
|
||||
for ( int i = 0; isSafe && i < s.Length; ++i )
|
||||
isSafe = IsSafeChar( (int) s[i] );
|
||||
|
||||
m_Index = start + fixedLength;
|
||||
|
||||
if ( isSafe )
|
||||
return s;
|
||||
|
||||
StringBuilder sb = new StringBuilder( s.Length );
|
||||
|
||||
for ( int i = 0; i < s.Length; ++i )
|
||||
if ( IsSafeChar( (int) s[i] ) )
|
||||
sb.Append( s[i] );
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
public string ReadUTF8StringSafe()
|
||||
{
|
||||
if ( m_Index >= m_Size )
|
||||
return String.Empty;
|
||||
|
||||
int count = 0;
|
||||
int index = m_Index;
|
||||
|
||||
while ( index < m_Size && m_Data[index++] != 0 )
|
||||
++count;
|
||||
|
||||
index = 0;
|
||||
|
||||
byte[] buffer = new byte[count];
|
||||
int value = 0;
|
||||
|
||||
while ( m_Index < m_Size && (value = m_Data[m_Index++]) != 0 )
|
||||
buffer[index++] = (byte)value;
|
||||
|
||||
string s = Utility.UTF8.GetString( buffer );
|
||||
|
||||
bool isSafe = true;
|
||||
|
||||
for ( int i = 0; isSafe && i < s.Length; ++i )
|
||||
isSafe = IsSafeChar( (int) s[i] );
|
||||
|
||||
if ( isSafe )
|
||||
return s;
|
||||
|
||||
StringBuilder sb = new StringBuilder( s.Length );
|
||||
|
||||
for ( int i = 0; i < s.Length; ++i )
|
||||
{
|
||||
if ( IsSafeChar( (int) s[i] ) )
|
||||
sb.Append( s[i] );
|
||||
}
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
public string ReadUTF8String()
|
||||
{
|
||||
if ( m_Index >= m_Size )
|
||||
return String.Empty;
|
||||
|
||||
int count = 0;
|
||||
int index = m_Index;
|
||||
|
||||
while ( index < m_Size && m_Data[index++] != 0 )
|
||||
++count;
|
||||
|
||||
index = 0;
|
||||
|
||||
byte[] buffer = new byte[count];
|
||||
int value = 0;
|
||||
|
||||
while ( m_Index < m_Size && (value = m_Data[m_Index++]) != 0 )
|
||||
buffer[index++] = (byte)value;
|
||||
|
||||
return Utility.UTF8.GetString( buffer );
|
||||
}
|
||||
|
||||
public string ReadString()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
int c;
|
||||
|
||||
while ( m_Index < m_Size && (c = m_Data[m_Index++]) != 0 )
|
||||
sb.Append( (char)c );
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
public string ReadStringSafe()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
int c;
|
||||
|
||||
while ( m_Index < m_Size && (c = m_Data[m_Index++]) != 0 )
|
||||
{
|
||||
if ( IsSafeChar( c ) )
|
||||
sb.Append( (char)c );
|
||||
}
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
public string ReadUnicodeStringSafe( int fixedLength )
|
||||
{
|
||||
int bound = m_Index + (fixedLength << 1);
|
||||
int end = bound;
|
||||
|
||||
if ( bound > m_Size )
|
||||
bound = m_Size;
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
int c;
|
||||
|
||||
while ( (m_Index + 1) < bound && (c = ((m_Data[m_Index++] << 8) | m_Data[m_Index++])) != 0 )
|
||||
{
|
||||
if ( IsSafeChar( c ) )
|
||||
sb.Append( (char)c );
|
||||
}
|
||||
|
||||
m_Index = end;
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
public string ReadUnicodeString( int fixedLength )
|
||||
{
|
||||
int bound = m_Index + (fixedLength << 1);
|
||||
int end = bound;
|
||||
|
||||
if ( bound > m_Size )
|
||||
bound = m_Size;
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
int c;
|
||||
|
||||
while ( (m_Index + 1) < bound && (c = ((m_Data[m_Index++] << 8) | m_Data[m_Index++])) != 0 )
|
||||
sb.Append( (char)c );
|
||||
|
||||
m_Index = end;
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
public string ReadStringSafe( int fixedLength )
|
||||
{
|
||||
int bound = m_Index + fixedLength;
|
||||
int end = bound;
|
||||
|
||||
if ( bound > m_Size )
|
||||
bound = m_Size;
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
int c;
|
||||
|
||||
while ( m_Index < bound && (c = m_Data[m_Index++]) != 0 )
|
||||
{
|
||||
if ( IsSafeChar( c ) )
|
||||
sb.Append( (char)c );
|
||||
}
|
||||
|
||||
m_Index = end;
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
public string ReadString( int fixedLength )
|
||||
{
|
||||
int bound = m_Index + fixedLength;
|
||||
int end = bound;
|
||||
|
||||
if ( bound > m_Size )
|
||||
bound = m_Size;
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
int c;
|
||||
|
||||
while ( m_Index < bound && (c = m_Data[m_Index++]) != 0 )
|
||||
sb.Append( (char)c );
|
||||
|
||||
m_Index = end;
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
409
Server/Network/PacketWriter.cs
Normal file
409
Server/Network/PacketWriter.cs
Normal file
|
|
@ -0,0 +1,409 @@
|
|||
/***************************************************************************
|
||||
* PacketWriter.cs
|
||||
* -------------------
|
||||
* begin : May 1, 2002
|
||||
* copyright : (C) The RunUO Software Team
|
||||
* email : info@runuo.com
|
||||
*
|
||||
* $Id: PacketWriter.cs 43 2006-01-20 05:39:57Z krrios $
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Server.Network
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides functionality for writing primitive binary data.
|
||||
/// </summary>
|
||||
public class PacketWriter
|
||||
{
|
||||
private static Stack<PacketWriter> m_Pool = new Stack<PacketWriter>();
|
||||
|
||||
public static PacketWriter CreateInstance()
|
||||
{
|
||||
return CreateInstance( 32 );
|
||||
}
|
||||
|
||||
public static PacketWriter CreateInstance( int capacity )
|
||||
{
|
||||
PacketWriter pw = null;
|
||||
|
||||
lock ( m_Pool )
|
||||
{
|
||||
if ( m_Pool.Count > 0 )
|
||||
{
|
||||
pw = m_Pool.Pop();
|
||||
|
||||
if ( pw != null )
|
||||
{
|
||||
pw.m_Capacity = capacity;
|
||||
pw.m_Stream.SetLength( 0 );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( pw == null )
|
||||
pw = new PacketWriter( capacity );
|
||||
|
||||
return pw;
|
||||
}
|
||||
|
||||
public static void ReleaseInstance( PacketWriter pw )
|
||||
{
|
||||
lock ( m_Pool )
|
||||
{
|
||||
if ( !m_Pool.Contains( pw ) )
|
||||
{
|
||||
m_Pool.Push( pw );
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
using ( StreamWriter op = new StreamWriter( "neterr.log" ) )
|
||||
{
|
||||
op.WriteLine( "{0}\tInstance pool contains writer", DateTime.Now );
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
Console.WriteLine( "net error" );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Internal stream which holds the entire packet.
|
||||
/// </summary>
|
||||
private MemoryStream m_Stream;
|
||||
|
||||
private int m_Capacity;
|
||||
|
||||
/// <summary>
|
||||
/// Internal format buffer.
|
||||
/// </summary>
|
||||
private static byte[] m_Buffer = new byte[4];
|
||||
|
||||
/// <summary>
|
||||
/// Instantiates a new PacketWriter instance with the default capacity of 4 bytes.
|
||||
/// </summary>
|
||||
public PacketWriter() : this( 32 )
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Instantiates a new PacketWriter instance with a given capacity.
|
||||
/// </summary>
|
||||
/// <param name="capacity">Initial capacity for the internal stream.</param>
|
||||
public PacketWriter( int capacity )
|
||||
{
|
||||
m_Stream = new MemoryStream( capacity );
|
||||
m_Capacity = capacity;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a 1-byte boolean value to the underlying stream. False is represented by 0, true by 1.
|
||||
/// </summary>
|
||||
public void Write( bool value )
|
||||
{
|
||||
m_Stream.WriteByte( (byte)(value ? 1 : 0) );
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a 1-byte unsigned integer value to the underlying stream.
|
||||
/// </summary>
|
||||
public void Write( byte value )
|
||||
{
|
||||
m_Stream.WriteByte( value );
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a 1-byte signed integer value to the underlying stream.
|
||||
/// </summary>
|
||||
public void Write( sbyte value )
|
||||
{
|
||||
m_Stream.WriteByte( (byte) value );
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a 2-byte signed integer value to the underlying stream.
|
||||
/// </summary>
|
||||
public void Write( short value )
|
||||
{
|
||||
m_Buffer[0] = (byte)(value >> 8);
|
||||
m_Buffer[1] = (byte) value;
|
||||
|
||||
m_Stream.Write( m_Buffer, 0, 2 );
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a 2-byte unsigned integer value to the underlying stream.
|
||||
/// </summary>
|
||||
public void Write( ushort value )
|
||||
{
|
||||
m_Buffer[0] = (byte)(value >> 8);
|
||||
m_Buffer[1] = (byte) value;
|
||||
|
||||
m_Stream.Write( m_Buffer, 0, 2 );
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a 4-byte signed integer value to the underlying stream.
|
||||
/// </summary>
|
||||
public void Write( int value )
|
||||
{
|
||||
m_Buffer[0] = (byte)(value >> 24);
|
||||
m_Buffer[1] = (byte)(value >> 16);
|
||||
m_Buffer[2] = (byte)(value >> 8);
|
||||
m_Buffer[3] = (byte) value;
|
||||
|
||||
m_Stream.Write( m_Buffer, 0, 4 );
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a 4-byte unsigned integer value to the underlying stream.
|
||||
/// </summary>
|
||||
public void Write( uint value )
|
||||
{
|
||||
m_Buffer[0] = (byte)(value >> 24);
|
||||
m_Buffer[1] = (byte)(value >> 16);
|
||||
m_Buffer[2] = (byte)(value >> 8);
|
||||
m_Buffer[3] = (byte) value;
|
||||
|
||||
m_Stream.Write( m_Buffer, 0, 4 );
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a sequence of bytes to the underlying stream
|
||||
/// </summary>
|
||||
public void Write( byte[] buffer, int offset, int size )
|
||||
{
|
||||
m_Stream.Write( buffer, offset, size );
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a fixed-length ASCII-encoded string value to the underlying stream. To fit (size), the string content is either truncated or padded with null characters.
|
||||
/// </summary>
|
||||
public void WriteAsciiFixed( string value, int size )
|
||||
{
|
||||
if ( value == null )
|
||||
{
|
||||
Console.WriteLine( "Network: Attempted to WriteAsciiFixed() with null value" );
|
||||
value = String.Empty;
|
||||
}
|
||||
|
||||
byte[] buffer = Encoding.ASCII.GetBytes( value );
|
||||
|
||||
if ( buffer.Length >= size )
|
||||
{
|
||||
m_Stream.Write( buffer, 0, size );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_Stream.Write( buffer, 0, buffer.Length );
|
||||
Fill( size - buffer.Length );
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a dynamic-length ASCII-encoded string value to the underlying stream, followed by a 1-byte null character.
|
||||
/// </summary>
|
||||
public void WriteAsciiNull( string value )
|
||||
{
|
||||
if ( value == null )
|
||||
{
|
||||
Console.WriteLine( "Network: Attempted to WriteAsciiNull() with null value" );
|
||||
value = String.Empty;
|
||||
}
|
||||
|
||||
byte[] buffer = Encoding.ASCII.GetBytes( value );
|
||||
|
||||
m_Stream.Write( buffer, 0, buffer.Length );
|
||||
m_Stream.WriteByte( 0 );
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a dynamic-length little-endian unicode string value to the underlying stream, followed by a 2-byte null character.
|
||||
/// </summary>
|
||||
public void WriteLittleUniNull( string value )
|
||||
{
|
||||
if ( value == null )
|
||||
{
|
||||
Console.WriteLine( "Network: Attempted to WriteLittleUniNull() with null value" );
|
||||
value = String.Empty;
|
||||
}
|
||||
|
||||
byte[] buffer = Encoding.Unicode.GetBytes( value );
|
||||
|
||||
m_Stream.Write( buffer, 0, buffer.Length );
|
||||
|
||||
m_Buffer[0] = 0;
|
||||
m_Buffer[1] = 0;
|
||||
m_Stream.Write( m_Buffer, 0, 2 );
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a fixed-length little-endian unicode string value to the underlying stream. To fit (size), the string content is either truncated or padded with null characters.
|
||||
/// </summary>
|
||||
public void WriteLittleUniFixed( string value, int size )
|
||||
{
|
||||
if ( value == null )
|
||||
{
|
||||
Console.WriteLine( "Network: Attempted to WriteLittleUniFixed() with null value" );
|
||||
value = String.Empty;
|
||||
}
|
||||
|
||||
size *= 2;
|
||||
|
||||
byte[] buffer = Encoding.Unicode.GetBytes( value );
|
||||
|
||||
if ( buffer.Length >= size )
|
||||
{
|
||||
m_Stream.Write( buffer, 0, size );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_Stream.Write( buffer, 0, buffer.Length );
|
||||
Fill( size - buffer.Length );
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a dynamic-length big-endian unicode string value to the underlying stream, followed by a 2-byte null character.
|
||||
/// </summary>
|
||||
public void WriteBigUniNull( string value )
|
||||
{
|
||||
if ( value == null )
|
||||
{
|
||||
Console.WriteLine( "Network: Attempted to WriteBigUniNull() with null value" );
|
||||
value = String.Empty;
|
||||
}
|
||||
|
||||
byte[] buffer = Encoding.BigEndianUnicode.GetBytes( value );
|
||||
|
||||
m_Stream.Write( buffer, 0, buffer.Length );
|
||||
|
||||
m_Buffer[0] = 0;
|
||||
m_Buffer[1] = 0;
|
||||
m_Stream.Write( m_Buffer, 0, 2 );
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a fixed-length big-endian unicode string value to the underlying stream. To fit (size), the string content is either truncated or padded with null characters.
|
||||
/// </summary>
|
||||
public void WriteBigUniFixed( string value, int size )
|
||||
{
|
||||
if ( value == null )
|
||||
{
|
||||
Console.WriteLine( "Network: Attempted to WriteBigUniFixed() with null value" );
|
||||
value = String.Empty;
|
||||
}
|
||||
|
||||
size *= 2;
|
||||
|
||||
byte[] buffer = Encoding.BigEndianUnicode.GetBytes( value );
|
||||
|
||||
if ( buffer.Length >= size )
|
||||
{
|
||||
m_Stream.Write( buffer, 0, size );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_Stream.Write( buffer, 0, buffer.Length );
|
||||
Fill( size - buffer.Length );
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fills the stream from the current position up to (capacity) with 0x00's
|
||||
/// </summary>
|
||||
public void Fill()
|
||||
{
|
||||
Fill( (int) (m_Capacity - m_Stream.Length) );
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a number of 0x00 byte values to the underlying stream.
|
||||
/// </summary>
|
||||
public void Fill( int length )
|
||||
{
|
||||
if ( m_Stream.Position == m_Stream.Length )
|
||||
{
|
||||
m_Stream.SetLength( m_Stream.Length + length );
|
||||
m_Stream.Seek( 0, SeekOrigin.End );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_Stream.Write( new byte[length], 0, length );
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the total stream length.
|
||||
/// </summary>
|
||||
public long Length
|
||||
{
|
||||
get
|
||||
{
|
||||
return m_Stream.Length;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the current stream position.
|
||||
/// </summary>
|
||||
public long Position
|
||||
{
|
||||
get
|
||||
{
|
||||
return m_Stream.Position;
|
||||
}
|
||||
set
|
||||
{
|
||||
m_Stream.Position = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The internal stream used by this PacketWriter instance.
|
||||
/// </summary>
|
||||
public MemoryStream UnderlyingStream
|
||||
{
|
||||
get
|
||||
{
|
||||
return m_Stream;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Offsets the current position from an origin.
|
||||
/// </summary>
|
||||
public long Seek( long offset, SeekOrigin origin )
|
||||
{
|
||||
return m_Stream.Seek( offset, origin );
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the entire stream content as a byte array.
|
||||
/// </summary>
|
||||
public byte[] ToArray()
|
||||
{
|
||||
return m_Stream.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
3678
Server/Network/Packets.cs
Normal file
3678
Server/Network/Packets.cs
Normal file
File diff suppressed because it is too large
Load diff
223
Server/Network/SendQueue.cs
Normal file
223
Server/Network/SendQueue.cs
Normal file
|
|
@ -0,0 +1,223 @@
|
|||
/***************************************************************************
|
||||
* SendQueue.cs
|
||||
* -------------------
|
||||
* begin : May 1, 2002
|
||||
* copyright : (C) The RunUO Software Team
|
||||
* email : info@runuo.com
|
||||
*
|
||||
* $Id: SendQueue.cs 43 2006-01-20 05:39:57Z krrios $
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Server.Network
|
||||
{
|
||||
public enum SendEnqueueResult
|
||||
{
|
||||
Begin,
|
||||
Delay,
|
||||
Overflow
|
||||
}
|
||||
|
||||
public class SendQueue
|
||||
{
|
||||
private class Entry
|
||||
{
|
||||
public byte[] m_Buffer;
|
||||
public int m_Length;
|
||||
|
||||
private Entry( byte[] buffer, int length )
|
||||
{
|
||||
m_Buffer = buffer;
|
||||
m_Length = length;
|
||||
}
|
||||
|
||||
private static Stack<Entry> m_Pool = new Stack<Entry>();
|
||||
|
||||
public static Entry Pool( byte[] buffer, int length )
|
||||
{
|
||||
lock ( m_Pool )
|
||||
{
|
||||
if ( m_Pool.Count == 0 )
|
||||
return new Entry( buffer, length );
|
||||
|
||||
Entry e = m_Pool.Pop();
|
||||
|
||||
e.m_Buffer = buffer;
|
||||
e.m_Length = length;
|
||||
|
||||
return e;
|
||||
}
|
||||
}
|
||||
|
||||
public static void Release( Entry e )
|
||||
{
|
||||
lock ( m_Pool )
|
||||
{
|
||||
m_Pool.Push( e );
|
||||
ReleaseBuffer( e.m_Buffer );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static int m_CoalesceBufferSize = 512;
|
||||
private static BufferPool m_UnusedBuffers = new BufferPool( "Coalesced", 2048, m_CoalesceBufferSize );
|
||||
|
||||
public static int CoalesceBufferSize
|
||||
{
|
||||
get{ return m_CoalesceBufferSize; }
|
||||
set
|
||||
{
|
||||
if ( m_CoalesceBufferSize == value )
|
||||
return;
|
||||
|
||||
if ( m_UnusedBuffers != null )
|
||||
m_UnusedBuffers.Free();
|
||||
|
||||
m_CoalesceBufferSize = value;
|
||||
m_UnusedBuffers = new BufferPool( "Coalesced", 2048, m_CoalesceBufferSize );
|
||||
}
|
||||
}
|
||||
|
||||
public static byte[] GetUnusedBuffer()
|
||||
{
|
||||
return m_UnusedBuffers.AcquireBuffer();
|
||||
}
|
||||
|
||||
public static void ReleaseBuffer( byte[] buffer )
|
||||
{
|
||||
if ( buffer == null )
|
||||
Console.WriteLine( "Warning: Attempting to release null packet buffer" );
|
||||
else if ( buffer.Length == m_CoalesceBufferSize )
|
||||
m_UnusedBuffers.ReleaseBuffer( buffer );
|
||||
}
|
||||
|
||||
private Queue<Entry> m_Queue;
|
||||
|
||||
private Entry m_Buffered;
|
||||
|
||||
public bool IsFlushReady{ get{ return ( m_Queue.Count == 0 && m_Buffered != null ); } }
|
||||
public bool IsEmpty{ get{ return ( m_Queue.Count == 0 && m_Buffered == null ); } }
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
if ( m_Buffered != null )
|
||||
{
|
||||
Entry.Release( m_Buffered );
|
||||
m_Buffered = null;
|
||||
}
|
||||
|
||||
while ( m_Queue.Count > 0 )
|
||||
Entry.Release( m_Queue.Dequeue() );
|
||||
}
|
||||
|
||||
public byte[] CheckFlushReady( ref int length )
|
||||
{
|
||||
Entry buffered = m_Buffered;
|
||||
|
||||
if ( m_Queue.Count == 0 && buffered != null )
|
||||
{
|
||||
m_Buffered = null;
|
||||
|
||||
m_Queue.Enqueue( buffered );
|
||||
length = buffered.m_Length;
|
||||
return buffered.m_Buffer;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public SendQueue()
|
||||
{
|
||||
m_Queue = new Queue<Entry>();
|
||||
}
|
||||
|
||||
public byte[] Peek( ref int length )
|
||||
{
|
||||
if ( m_Queue.Count > 0 )
|
||||
{
|
||||
Entry entry = m_Queue.Peek();
|
||||
|
||||
length = entry.m_Length;
|
||||
return entry.m_Buffer;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public byte[] Dequeue( ref int length )
|
||||
{
|
||||
Entry.Release( m_Queue.Dequeue() );
|
||||
|
||||
if ( m_Queue.Count > 0 )
|
||||
{
|
||||
Entry entry = m_Queue.Peek();
|
||||
|
||||
length = entry.m_Length;
|
||||
return entry.m_Buffer;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private const int PendingCap = 96*1024;
|
||||
|
||||
public SendEnqueueResult Enqueue( byte[] buffer, int length )
|
||||
{
|
||||
if ( buffer == null )
|
||||
{
|
||||
Console.WriteLine( "Warning: Attempting to send null packet buffer" );
|
||||
return SendEnqueueResult.Delay;
|
||||
}
|
||||
|
||||
int existingBytes = ( m_Queue.Count * m_CoalesceBufferSize ) + ( m_Buffered == null ? 0 : m_Buffered.m_Length );
|
||||
|
||||
if ( (existingBytes + length) > PendingCap )
|
||||
return SendEnqueueResult.Overflow;
|
||||
|
||||
int offset = 0; // offset into buffer
|
||||
int remaining = length; // byte count remaining
|
||||
|
||||
bool startNow = false; // should we start sending the first chunk?
|
||||
|
||||
while ( remaining > 0 )
|
||||
{
|
||||
if ( m_Buffered == null ) // nothing yet buffered
|
||||
m_Buffered = Entry.Pool( GetUnusedBuffer(), 0 );
|
||||
|
||||
byte[] page = m_Buffered.m_Buffer; // buffer page
|
||||
int pageSpace = page.Length - m_Buffered.m_Length; // available bytes in page
|
||||
int byteCount = ( remaining > pageSpace ? pageSpace : remaining ); // how many we can copy over
|
||||
|
||||
Buffer.BlockCopy( buffer, offset, page, m_Buffered.m_Length, byteCount ); // copy the data
|
||||
|
||||
// apply offsets
|
||||
m_Buffered.m_Length += byteCount;
|
||||
offset += byteCount;
|
||||
remaining -= byteCount;
|
||||
|
||||
if ( m_Buffered.m_Length == page.Length ) // page full
|
||||
{
|
||||
startNow = ( startNow || m_Queue.Count == 0 );
|
||||
m_Queue.Enqueue( m_Buffered );
|
||||
m_Buffered = null;
|
||||
}
|
||||
}
|
||||
|
||||
return ( startNow ? SendEnqueueResult.Begin : SendEnqueueResult.Delay );
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue