#W# Initial Commit: Avatars Conquest

This commit is contained in:
WarrentyExpired 2026-07-03 20:19:48 -04:00
commit 8eae46895e
7512 changed files with 416187 additions and 0 deletions

View file

@ -0,0 +1,102 @@
/***************************************************************************
* BufferPool.cs
* -------------------
* begin : May 1, 2002
* copyright : (C) The RunUO Software Team
* email : info@runuo.com
*
* $Id$
*
***************************************************************************/
/***************************************************************************
*
* 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
Source/Network/ByteQueue.cs Normal file
View file

@ -0,0 +1,153 @@
/***************************************************************************
* ByteQueue.cs
* -------------------
* begin : May 1, 2002
* copyright : (C) The RunUO Software Team
* email : info@runuo.com
*
* $Id$
*
***************************************************************************/
/***************************************************************************
*
* 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;
}
}
}

View file

@ -0,0 +1,388 @@
/***************************************************************************
* Compression.cs
* -------------------
* begin : May 1, 2002
* copyright : (C) The RunUO Software Team
* email : info@runuo.com
*
* $Id$
*
***************************************************************************/
/***************************************************************************
*
* 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 static class Compression {
private static int[] _huffmanTable = 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 const int CountIndex = 0;
private const int ValueIndex = 1;
// UO packets may not exceed 64kb in length
private const int BufferSize = 0x10000;
// Optimal compression ratio is 2 / 8; worst compression ratio is 11 / 8
private const int MinimalCodeLength = 2;
private const int MaximalCodeLength = 11;
// Fixed overhead, in bits, per compression call
private const int TerminalCodeLength = 4;
// If our input exceeds this length, we cannot possibly compress it within the buffer
private const int DefiniteOverflow = ( ( BufferSize * 8 ) - TerminalCodeLength ) / MinimalCodeLength;
// If our input exceeds this length, we may potentially overflow the buffer
private const int PossibleOverflow = ( ( BufferSize * 8 ) - TerminalCodeLength ) / MaximalCodeLength;
private static object _syncRoot = new object();
private static byte[] _outputBuffer = new byte[BufferSize];
[Obsolete( "Use Compress( byte[], int, int, ref int ) instead.", false )]
public static void Compress( byte[] input, int length, out byte[] output, out int outputLength ) {
outputLength = 0;
output = Compress( input, 0, length, ref outputLength );
}
public unsafe static byte[] Compress( byte[] input, int offset, int count, ref int length ) {
if ( input == null ) {
throw new ArgumentNullException( "input" );
} else if ( offset < 0 || offset >= input.Length ) {
throw new ArgumentOutOfRangeException( "offset" );
} else if ( count < 0 || count > input.Length ) {
throw new ArgumentOutOfRangeException( "count" );
} else if ( ( input.Length - offset ) < count ) {
throw new ArgumentException();
}
length = 0;
if ( count > DefiniteOverflow ) {
return null;
}
lock ( _syncRoot ) {
int bitCount = 0;
int bitValue = 0;
fixed ( int* pTable = _huffmanTable ) {
int* pEntry;
fixed ( byte* pInputBuffer = input ) {
byte* pInput = pInputBuffer + offset, pInputEnd = pInput + count;
fixed ( byte* pOutputBuffer = _outputBuffer ) {
byte* pOutput = pOutputBuffer, pOutputEnd = pOutput + BufferSize;
while ( pInput < pInputEnd ) {
pEntry = &pTable[*pInput++ << 1];
bitCount += pEntry[CountIndex];
bitValue <<= pEntry[CountIndex];
bitValue |= pEntry[ValueIndex];
while ( bitCount >= 8 ) {
bitCount -= 8;
if ( pOutput < pOutputEnd ) {
*pOutput++ = ( byte ) ( bitValue >> bitCount );
} else {
return null;
}
}
}
// terminal code
pEntry = &pTable[0x200];
bitCount += pEntry[CountIndex];
bitValue <<= pEntry[CountIndex];
bitValue |= pEntry[ValueIndex];
// align on byte boundary
if ( ( bitCount & 7 ) != 0 ) {
bitValue <<= ( 8 - ( bitCount & 7 ) );
bitCount += ( 8 - ( bitCount & 7 ) );
}
while ( bitCount >= 8 ) {
bitCount -= 8;
if ( pOutput < pOutputEnd ) {
*pOutput++ = ( byte ) ( bitValue >> bitCount );
} else {
return null;
}
}
length = ( int ) ( pOutput - pOutputBuffer );
return _outputBuffer;
}
}
}
}
}
public static readonly ICompressor Compressor;
static Compression() {
if ( Core.Unix ) {
if ( Core.Is64Bit ) {
Compressor = new CompressorUnix64();
} else {
Compressor = new CompressorUnix32();
}
} else 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 sealed class CompressorUnix32 : ICompressor {
[DllImport( "libz" )]
private static extern string zlibVersion();
[DllImport( "libz" )]
private static extern ZLibError compress( byte[] dest, ref int destLength, byte[] source, int sourceLength );
[DllImport( "libz" )]
private static extern ZLibError compress2( byte[] dest, ref int destLength, byte[] source, int sourceLength, ZLibQuality quality );
[DllImport( "libz" )]
private static extern ZLibError uncompress( byte[] dest, ref int destLen, byte[] source, int sourceLen );
public CompressorUnix32() {
}
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 CompressorUnix64 : ICompressor {
[DllImport( "libz" )]
private static extern string zlibVersion();
[DllImport( "libz" )]
private static extern ZLibError compress( byte[] dest, ref ulong destLength, byte[] source, int sourceLength );
[DllImport( "libz" )]
private static extern ZLibError compress2( byte[] dest, ref ulong destLength, byte[] source, int sourceLength, ZLibQuality quality );
[DllImport( "libz" )]
private static extern ZLibError uncompress( byte[] dest, ref ulong destLen, byte[] source, int sourceLen );
public CompressorUnix64() {
}
public string Version {
get {
return zlibVersion();
}
}
public ZLibError Compress( byte[] dest, ref int destLength, byte[] source, int sourceLength ) {
ulong destLengthLong = (ulong)destLength;
ZLibError z = compress( dest, ref destLengthLong, source, sourceLength );
destLength = (int)destLengthLong;
return z;
}
public ZLibError Compress( byte[] dest, ref int destLength, byte[] source, int sourceLength, ZLibQuality quality ) {
ulong destLengthLong = (ulong)destLength;
ZLibError z = compress2( dest, ref destLengthLong, source, sourceLength, quality );
destLength = (int)destLengthLong;
return z;
}
public ZLibError Decompress( byte[] dest, ref int destLength, byte[] source, int sourceLength ) {
ulong destLengthLong = (ulong)destLength;
ZLibError z = uncompress( dest, ref destLengthLong, source, sourceLength );
destLength = (int)destLengthLong;
return z;
}
}
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
}
}

View file

@ -0,0 +1,64 @@
/***************************************************************************
* EncodedPacketHandler.cs
* -------------------
* begin : May 1, 2002
* copyright : (C) The RunUO Software Team
* email : info@runuo.com
*
* $Id$
*
***************************************************************************/
/***************************************************************************
*
* 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;
}
}
}
}

View file

@ -0,0 +1,85 @@
/***************************************************************************
* EncodedReader.cs
* -------------------
* begin : May 1, 2002
* copyright : (C) The RunUO Software Team
* email : info@runuo.com
*
* $Id$
*
***************************************************************************/
/***************************************************************************
*
* 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 );
}
}
}

279
Source/Network/Listener.cs Normal file
View file

@ -0,0 +1,279 @@
/***************************************************************************
* Listener.cs
* -------------------
* begin : May 1, 2002
* copyright : (C) The RunUO Software Team
* email : info@runuo.com
*
* $Id$
*
***************************************************************************/
/***************************************************************************
*
* 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.NetworkInformation;
using System.Net.Sockets;
using System.Threading;
using Server;
namespace Server.Network
{
public class Listener : IDisposable
{
private Socket m_Listener;
private Queue<Socket> m_Accepted;
private object m_AcceptedSyncRoot;
#if Framework_4_0
private SocketAsyncEventArgs m_EventArgs;
#else
private AsyncCallback m_OnAccept;
#endif
private static Socket[] m_EmptySockets = new Socket[0];
private static IPEndPoint[] m_EndPoints;
public static IPEndPoint[] EndPoints {
get { return m_EndPoints; }
set { m_EndPoints = value; }
}
public Listener( IPEndPoint ipep )
{
m_Accepted = new Queue<Socket>();
m_AcceptedSyncRoot = ((ICollection)m_Accepted).SyncRoot;
m_Listener = Bind( ipep );
if ( m_Listener == null )
return;
DisplayListener();
#if Framework_4_0
m_EventArgs = new SocketAsyncEventArgs();
m_EventArgs.Completed += new EventHandler<SocketAsyncEventArgs>( Accept_Completion );
Accept_Start();
#else
m_OnAccept = new AsyncCallback( OnAccept );
try {
IAsyncResult res = m_Listener.BeginAccept( m_OnAccept, m_Listener );
} catch ( SocketException ex ) {
NetState.TraceException( ex );
} catch ( ObjectDisposedException ) {
}
#endif
}
private Socket Bind( IPEndPoint ipep )
{
Socket s = new Socket( ipep.AddressFamily, SocketType.Stream, ProtocolType.Tcp );
try
{
s.LingerState.Enabled = false;
#if !MONO
s.ExclusiveAddressUse = false;
#endif
s.Bind( ipep );
s.Listen( 8 );
return s;
}
catch ( Exception e )
{
if ( e is SocketException ) {
SocketException se = (SocketException)e;
if ( se.ErrorCode == 10048 ) { // WSAEADDRINUSE
Console.WriteLine( "Listener Failed: {0}:{1} (In Use)", ipep.Address, ipep.Port );
}
else if ( se.ErrorCode == 10049 ) { // WSAEADDRNOTAVAIL
Console.WriteLine( "Listener Failed: {0}:{1} (Unavailable)", ipep.Address, ipep.Port );
}
else {
Console.WriteLine( "Listener Exception:" );
Console.WriteLine( e );
}
}
return null;
}
}
private void DisplayListener()
{
IPEndPoint ipep = m_Listener.LocalEndPoint as IPEndPoint;
if ( ipep == null )
return;
if ( ipep.Address.Equals( IPAddress.Any ) || ipep.Address.Equals( IPAddress.IPv6Any ) ) {
NetworkInterface[] adapters = NetworkInterface.GetAllNetworkInterfaces();
foreach ( NetworkInterface adapter in adapters ) {
IPInterfaceProperties properties = adapter.GetIPProperties();
foreach ( IPAddressInformation unicast in properties.UnicastAddresses ) {
if ( ipep.AddressFamily == unicast.Address.AddressFamily )
Console.WriteLine( "Listening: {0}:{1}", unicast.Address, ipep.Port );
}
}
/*
try {
Console.WriteLine( "Listening: {0}:{1}", IPAddress.Loopback, ipep.Port );
IPHostEntry iphe = Dns.GetHostEntry( Dns.GetHostName() );
IPAddress[] ip = iphe.AddressList;
for ( int i = 0; i < ip.Length; ++i )
Console.WriteLine( "Listening: {0}:{1}", ip[i], ipep.Port );
}
catch { }
*/
}
else {
Console.WriteLine( "Listening: {0}:{1}", ipep.Address, ipep.Port );
}
}
#if Framework_4_0
private void Accept_Start()
{
bool result = false;
do {
try {
result = !m_Listener.AcceptAsync( m_EventArgs );
} catch ( SocketException ex ) {
NetState.TraceException( ex );
break;
} catch ( ObjectDisposedException ) {
break;
}
if ( result )
Accept_Process( m_EventArgs );
} while ( result );
}
private void Accept_Completion( object sender, SocketAsyncEventArgs e )
{
Accept_Process( e );
Accept_Start();
}
private void Accept_Process( SocketAsyncEventArgs e )
{
if ( e.SocketError == SocketError.Success && VerifySocket( e.AcceptSocket ) ) {
Enqueue( e.AcceptSocket );
} else {
Release( e.AcceptSocket );
}
e.AcceptSocket = null;
}
#else
private void OnAccept( IAsyncResult asyncResult ) {
Socket listener = (Socket) asyncResult.AsyncState;
Socket accepted = null;
try {
accepted = listener.EndAccept( asyncResult );
} catch ( SocketException ex ) {
NetState.TraceException( ex );
} catch ( ObjectDisposedException ) {
return;
}
if ( accepted != null ) {
if ( VerifySocket( accepted ) ) {
Enqueue( accepted );
} else {
Release( accepted );
}
}
try {
listener.BeginAccept( m_OnAccept, listener );
} catch ( SocketException ex ) {
NetState.TraceException( ex );
} catch ( ObjectDisposedException ) {
}
}
#endif
private bool VerifySocket( Socket socket ) {
try {
SocketConnectEventArgs args = new SocketConnectEventArgs( socket );
EventSink.InvokeSocketConnect( args );
return args.AllowConnection;
} catch ( Exception ex ) {
NetState.TraceException( ex );
return false;
}
}
private void Enqueue( Socket socket ) {
lock ( m_AcceptedSyncRoot ) {
m_Accepted.Enqueue( socket );
}
Core.Set();
}
private void Release( Socket socket ) {
try {
socket.Shutdown( SocketShutdown.Both );
} catch ( SocketException ex ) {
NetState.TraceException( ex );
}
try {
socket.Close();
} catch ( SocketException ex ) {
NetState.TraceException( ex );
}
}
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() {
Socket socket = Interlocked.Exchange<Socket>( ref m_Listener, null );
if ( socket != null ) {
socket.Close();
}
}
}
}

View file

@ -0,0 +1,282 @@
/***************************************************************************
* MessagePump.cs
* -------------------
* begin : May 1, 2002
* copyright : (C) The RunUO Software Team
* email : info@runuo.com
*
* $Id$
*
***************************************************************************/
/***************************************************************************
*
* 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 System.Threading;
using Server;
using Server.Diagnostics;
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()
{
IPEndPoint[] ipep = Listener.EndPoints;
m_Listeners = new Listener[ipep.Length];
bool success = false;
do {
for ( int i = 0; i < ipep.Length; i++ ) {
Listener l = new Listener( ipep[i] );
if ( !success && l != null )
success = true;
m_Listeners[i] = l;
}
if ( !success ) {
Console.WriteLine( "Retrying..." );
Thread.Sleep( 10000 );
}
} while ( !success );
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 );
Core.Set();
}
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.GetPacketID() == 0xEF )
{
// new packet in client 6.0.5.0 replaces the traditional seed method with a seed packet
// 0xEF = 239 = multicast IP, so this should never appear in a normal seed. So this is backwards compatible with older clients.
ns.Seeded = true;
}
else 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();
PacketHandler handler = ns.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;
}
PacketReceiveProfile prof = PacketReceiveProfile.Acquire( packetID );
if ( prof != null ) {
prof.Start();
}
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 ( prof != null ) {
prof.Finish( packetLength );
}
}
}
else
{
break;
}
}
}
return true;
}
}
}

1221
Source/Network/NetState.cs Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,82 @@
/***************************************************************************
* PacketHandler.cs
* -------------------
* begin : May 1, 2002
* copyright : (C) The RunUO Software Team
* email : info@runuo.com
*
* $Id$
*
***************************************************************************/
/***************************************************************************
*
* 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;
}
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,457 @@
/***************************************************************************
* PacketReader.cs
* -------------------
* begin : May 1, 2002
* copyright : (C) The RunUO Software Team
* email : info@runuo.com
*
* $Id$
*
***************************************************************************/
/***************************************************************************
*
* 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();
}
}
}

View file

@ -0,0 +1,470 @@
/***************************************************************************
* PacketWriter.cs
* -------------------
* begin : May 1, 2002
* copyright : (C) The RunUO Software Team
* email : info@runuo.com
*
* $Id$
*
***************************************************************************/
/***************************************************************************
*
* 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;
}
int length = value.Length;
m_Stream.SetLength( m_Stream.Length + size );
if ( length >= size )
m_Stream.Position += Encoding.ASCII.GetBytes( value, 0, size, m_Stream.GetBuffer(), (int)m_Stream.Position );
else
{
Encoding.ASCII.GetBytes( value, 0, length, m_Stream.GetBuffer(), (int)m_Stream.Position );
m_Stream.Position += size;
}
/*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;
}
int length = value.Length;
m_Stream.SetLength( m_Stream.Length + length + 1 );
Encoding.ASCII.GetBytes( value, 0, length, m_Stream.GetBuffer(), (int)m_Stream.Position );
m_Stream.Position += length + 1;
/*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;
}
int length = value.Length;
m_Stream.SetLength( m_Stream.Length + ( ( length + 1 ) * 2 ) );
m_Stream.Position += Encoding.Unicode.GetBytes( value, 0, length, m_Stream.GetBuffer(), (int)m_Stream.Position );
m_Stream.Position += 2;
/*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;
int length = value.Length;
m_Stream.SetLength( m_Stream.Length + size );
if ( ( length * 2 ) >= size )
m_Stream.Position += Encoding.Unicode.GetBytes( value, 0, length, m_Stream.GetBuffer(), (int)m_Stream.Position );
else
{
Encoding.Unicode.GetBytes( value, 0, length, m_Stream.GetBuffer(), (int)m_Stream.Position );
m_Stream.Position += size;
}
/*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;
}
int length = value.Length;
m_Stream.SetLength( m_Stream.Length + ( ( length + 1 ) * 2 ) );
m_Stream.Position += Encoding.BigEndianUnicode.GetBytes( value, 0, length, m_Stream.GetBuffer(), (int)m_Stream.Position );
m_Stream.Position += 2;
/*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;
int length = value.Length;
m_Stream.SetLength( m_Stream.Length + size );
if ( ( length * 2 ) >= size )
m_Stream.Position += Encoding.BigEndianUnicode.GetBytes( value, 0, length, m_Stream.GetBuffer(), (int)m_Stream.Position );
else
{
Encoding.BigEndianUnicode.GetBytes( value, 0, length, m_Stream.GetBuffer(), (int)m_Stream.Position );
m_Stream.Position += size;
}
/*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();
}
}
}

4284
Source/Network/Packets.cs Normal file

File diff suppressed because it is too large Load diff

237
Source/Network/SendQueue.cs Normal file
View file

@ -0,0 +1,237 @@
/***************************************************************************
* SendQueue.cs
* -------------------
* begin : May 1, 2002
* copyright : (C) The RunUO Software Team
* email : info@runuo.com
*
* $Id$
*
***************************************************************************/
/***************************************************************************
*
* 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 class SendQueue {
public class Gram {
private static Stack<Gram> _pool = new Stack<Gram>();
public static Gram Acquire() {
lock ( _pool ) {
Gram gram;
if ( _pool.Count > 0 ) {
gram = _pool.Pop();
} else {
gram = new Gram();
}
gram._buffer = AcquireBuffer();
gram._length = 0;
return gram;
}
}
private byte[] _buffer;
private int _length;
public byte[] Buffer {
get {
return _buffer;
}
}
public int Length {
get {
return _length;
}
}
public int Available {
get {
return ( _buffer.Length - _length );
}
}
public bool IsFull {
get {
return ( _length == _buffer.Length );
}
}
private Gram() {
}
public int Write( byte[] buffer, int offset, int length ) {
int write = Math.Min( length, this.Available );
System.Buffer.BlockCopy( buffer, offset, _buffer, _length, write );
_length += write;
return write;
}
public void Release() {
lock ( _pool ) {
_pool.Push( this );
ReleaseBuffer( _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[] AcquireBuffer() {
return m_UnusedBuffers.AcquireBuffer();
}
public static void ReleaseBuffer( byte[] buffer ) {
if ( buffer != null && buffer.Length == m_CoalesceBufferSize ) {
m_UnusedBuffers.ReleaseBuffer( buffer );
}
}
private Queue<Gram> _pending;
private Gram _buffered;
public bool IsFlushReady {
get {
return ( _pending.Count == 0 && _buffered != null );
}
}
public bool IsEmpty {
get {
return ( _pending.Count == 0 && _buffered == null );
}
}
public SendQueue() {
_pending = new Queue<Gram>();
}
public Gram CheckFlushReady() {
Gram gram = null;
if ( _pending.Count == 0 && _buffered != null ) {
gram = _buffered;
_pending.Enqueue( _buffered );
_buffered = null;
}
return gram;
}
public Gram Dequeue() {
Gram gram = null;
if ( _pending.Count > 0 ) {
_pending.Dequeue().Release();
if ( _pending.Count > 0 ) {
gram = _pending.Peek();
}
}
return gram;
}
private const int PendingCap = 96 * 1024;
public Gram Enqueue( byte[] buffer, int length ) {
return Enqueue( buffer, 0, length );
}
public Gram Enqueue( byte[] buffer, int offset, int length ) {
if ( buffer == null ) {
throw new ArgumentNullException( "buffer" );
} else if ( !(offset >= 0 && offset < buffer.Length) ) {
throw new ArgumentOutOfRangeException( "offset", offset, "Offset must be greater than or equal to zero and less than the size of the buffer." );
} else if ( length < 0 || length > buffer.Length ) {
throw new ArgumentOutOfRangeException( "length", length, "Length cannot be less than zero or greater than the size of the buffer." );
} else if ( ( buffer.Length - offset ) < length ) {
throw new ArgumentException( "Offset and length do not point to a valid segment within the buffer." );
}
int existingBytes = ( _pending.Count * m_CoalesceBufferSize ) + ( _buffered == null ? 0 : _buffered.Length );
if ( ( existingBytes + length ) > PendingCap ) {
throw new CapacityExceededException();
}
Gram gram = null;
while ( length > 0 ) {
if ( _buffered == null ) { // nothing yet buffered
_buffered = Gram.Acquire();
}
int bytesWritten = _buffered.Write( buffer, offset, length );
offset += bytesWritten;
length -= bytesWritten;
if ( _buffered.IsFull ) {
if ( _pending.Count == 0 ) {
gram = _buffered;
}
_pending.Enqueue( _buffered );
_buffered = null;
}
}
return gram;
}
public void Clear() {
if ( _buffered != null ) {
_buffered.Release();
_buffered = null;
}
while ( _pending.Count > 0 ) {
_pending.Dequeue().Release();
}
}
}
public sealed class CapacityExceededException : Exception {
public CapacityExceededException()
: base( "Too much data pending." ) {
}
}
}