2020-10-20 20:55:19 -07:00
/ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* ModernUO *
* Copyright 2019 - 2020 - ModernUO Development Team *
* Email : hi @modernuo . com *
* File : NetState . cs *
* *
* 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 3 of the License , or *
* ( at your option ) any later version . *
* *
* You should have received a copy of the GNU General Public License *
* along with this program . If not , see < http : //www.gnu.org/licenses/>. *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * /
2020-08-25 18:53:35 -07:00
using System ;
2020-10-24 14:46:59 -07:00
using System.Buffers ;
2020-08-25 18:53:35 -07:00
using System.Collections.Generic ;
using System.IO ;
using System.Net ;
using System.Net.Sockets ;
2021-10-10 12:22:25 -07:00
using System.Network ;
2020-10-20 20:55:19 -07:00
using System.Runtime.CompilerServices ;
2021-10-03 18:04:53 -07:00
using System.Runtime.InteropServices ;
2020-08-25 18:53:35 -07:00
using Server.Accounting ;
2021-02-07 23:30:56 -08:00
using Server.Diagnostics ;
2020-08-25 18:53:35 -07:00
using Server.Gumps ;
using Server.HuePickers ;
using Server.Items ;
2021-04-20 08:43:54 +02:00
using Server.Logging ;
2020-08-25 18:53:35 -07:00
using Server.Menus ;
2022-03-04 12:32:25 -08:00
namespace Server.Network ;
public delegate void NetStateCreatedCallback ( NetState ns ) ;
2020-08-25 18:53:35 -07:00
2022-03-04 12:32:25 -08:00
public delegate void DecodePacket ( CircularBuffer < byte > buffer , ref int length ) ;
public delegate void EncodePacket ( ReadOnlySpan < byte > inputBuffer , CircularBuffer < byte > outputBuffer , out int length ) ;
public partial class NetState : IComparable < NetState >
{
private static readonly ILogger logger = LogFactory . GetLogger ( typeof ( NetState ) ) ;
private const int RecvPipeSize = 1024 * 64 ;
private const int SendPipeSize = 1024 * 256 ;
private const int GumpCap = 512 ;
private const int HuePickerCap = 512 ;
private const int MenuCap = 512 ;
private const int PacketPerSecondThreshold = 3000 ;
private static GCHandle [ ] _polledStates = new GCHandle [ 2048 ] ;
private static readonly IPollGroup _pollGroup = PollGroup . Create ( ) ;
2022-05-30 14:04:54 -07:00
private static readonly Queue < NetState > _flushPending = new ( 2048 ) ;
private static readonly Queue < NetState > _flushedPartials = new ( 256 ) ;
private static readonly Queue < NetState > _disposed = new ( 256 ) ;
2022-03-04 12:32:25 -08:00
public static NetStateCreatedCallback CreatedCallback { get ; set ; }
private readonly string _toString ;
private ClientVersion _version ;
private long _nextActivityCheck ;
private bool _running = true ;
private volatile DecodePacket _packetDecoder ;
private volatile EncodePacket _packetEncoder ;
private bool _flushQueued ;
private readonly long [ ] _packetThrottles = new long [ 0x100 ] ;
private readonly long [ ] _packetCounts = new long [ 0x100 ] ;
private string _disconnectReason = string . Empty ;
internal int _authId ;
internal int _seed ;
internal ParserState _parserState = ParserState . AwaitingNextPacket ;
internal ProtocolState _protocolState = ProtocolState . AwaitingSeed ;
internal GCHandle _handle ;
private bool _packetLogging ;
2022-05-30 14:04:54 -07:00
public GCHandle Handle = > _handle ;
2022-03-04 12:32:25 -08:00
internal enum ParserState
{
AwaitingNextPacket ,
AwaitingPartialPacket ,
ProcessingPacket ,
Throttled ,
Error
}
2020-10-24 21:49:28 -07:00
2022-03-04 12:32:25 -08:00
internal enum ProtocolState
2020-08-25 18:53:35 -07:00
{
2022-03-04 12:32:25 -08:00
AwaitingSeed , // Based on the way the seed arrives, we know if this is a login server or a game server connection
2021-04-20 08:43:54 +02:00
2022-03-04 12:32:25 -08:00
LoginServer_AwaitingLogin ,
LoginServer_AwaitingServerSelect ,
LoginServer_ServerSelectAck ,
2020-08-25 18:53:35 -07:00
2022-03-04 12:32:25 -08:00
GameServer_AwaitingGameServerLogin ,
GameServer_LoggedIn ,
Error
}
2020-08-25 18:53:35 -07:00
2022-03-04 12:32:25 -08:00
private static string _packetLoggingPath ;
2020-10-20 20:55:19 -07:00
2022-03-04 12:32:25 -08:00
public static void Configure ( )
{
_packetLoggingPath = ServerConfiguration . GetSetting ( "netstate.packetLoggingPath" , Path . Combine ( Core . BaseDirectory , "Packets" ) ) ;
}
2020-08-25 18:53:35 -07:00
2022-03-04 12:32:25 -08:00
public static void Initialize ( )
{
Timer . DelayCall ( TimeSpan . FromMinutes ( 1 ) , TimeSpan . FromMinutes ( 1.5 ) , CheckAllAlive ) ;
}
2021-02-07 23:30:56 -08:00
2022-03-04 12:32:25 -08:00
public NetState ( Socket connection )
{
Connection = connection ;
Seeded = false ;
Gumps = new List < Gump > ( ) ;
HuePickers = new List < HuePicker > ( ) ;
Menus = new List < IMenu > ( ) ;
Trades = new List < SecureTrade > ( ) ;
RecvPipe = new Pipe < byte > ( GC . AllocateUninitializedArray < byte > ( RecvPipeSize ) ) ;
SendPipe = new Pipe < byte > ( GC . AllocateUninitializedArray < byte > ( SendPipeSize ) ) ;
_nextActivityCheck = Core . TickCount + 30000 ;
ConnectedOn = Core . Now ;
try
2021-02-07 23:30:56 -08:00
{
2022-03-04 12:32:25 -08:00
Address = Utility . Intern ( ( Connection ? . RemoteEndPoint as IPEndPoint ) ? . Address ) ;
_toString = Address ? . ToString ( ) ? ? "(error)" ;
2021-02-07 23:30:56 -08:00
}
2022-03-04 12:32:25 -08:00
catch ( Exception ex )
2021-02-07 23:30:56 -08:00
{
2022-03-04 12:32:25 -08:00
TraceException ( ex ) ;
Address = IPAddress . None ;
_toString = "(error)" ;
2021-02-07 23:30:56 -08:00
}
2022-03-04 12:32:25 -08:00
_handle = GCHandle . Alloc ( this ) ;
2021-10-31 10:22:22 -07:00
2022-03-04 12:32:25 -08:00
try
2021-10-31 10:22:22 -07:00
{
2022-03-04 12:32:25 -08:00
_pollGroup . Add ( connection , _handle ) ;
2021-10-31 10:22:22 -07:00
}
2022-03-04 12:32:25 -08:00
catch ( Exception ex )
2020-10-20 20:55:19 -07:00
{
2022-03-04 12:32:25 -08:00
TraceException ( ex ) ;
Disconnect ( "Unable to add socket to poll group" ) ;
2020-10-20 20:55:19 -07:00
}
2022-03-04 12:32:25 -08:00
CreatedCallback ? . Invoke ( this ) ;
}
2020-08-25 18:53:35 -07:00
2022-03-04 12:32:25 -08:00
// Only use this for debugging. This will make your server very slow!
public bool PacketLogging
{
get = > _packetLogging ;
set
2021-10-31 10:22:22 -07:00
{
2022-03-04 12:32:25 -08:00
_packetLogging = value ;
2021-10-31 10:22:22 -07:00
2022-03-04 12:32:25 -08:00
if ( _packetLogging )
{
StartPacketLog ( ) ;
2021-10-31 10:22:22 -07:00
}
}
2022-03-04 12:32:25 -08:00
}
2021-10-31 10:22:22 -07:00
2022-03-04 12:32:25 -08:00
public DateTime ConnectedOn { get ; }
2020-08-25 18:53:35 -07:00
2022-03-04 12:32:25 -08:00
public TimeSpan ConnectedFor = > Core . Now - ConnectedOn ;
2020-08-25 18:53:35 -07:00
2022-03-04 12:32:25 -08:00
public IPAddress Address { get ; }
2020-08-25 18:53:35 -07:00
2022-03-04 12:32:25 -08:00
public DecodePacket PacketDecoder
{
get = > _packetDecoder ;
set = > _packetDecoder = value ;
}
2020-10-24 21:49:28 -07:00
2022-03-04 12:32:25 -08:00
public EncodePacket PacketEncoder
{
get = > _packetEncoder ;
set = > _packetEncoder = value ;
}
2020-08-25 18:53:35 -07:00
2022-03-04 12:32:25 -08:00
public int CurrentPacket { get ; internal set ; }
2021-10-16 10:48:58 -07:00
2022-03-04 12:32:25 -08:00
public bool SentFirstPacket { get ; set ; }
2020-08-25 18:53:35 -07:00
2022-03-04 12:32:25 -08:00
public bool BlockAllPackets { get ; set ; }
2020-08-25 18:53:35 -07:00
2022-03-04 12:32:25 -08:00
public List < SecureTrade > Trades { get ; }
2020-08-25 18:53:35 -07:00
2022-03-04 12:32:25 -08:00
public bool Seeded { get ; set ; }
2020-08-25 18:53:35 -07:00
2022-03-04 12:32:25 -08:00
public Pipe < byte > RecvPipe { get ; }
2020-10-25 17:40:08 -07:00
2022-03-04 12:32:25 -08:00
public Pipe < byte > SendPipe { get ; }
2020-10-25 17:40:08 -07:00
2022-03-04 12:32:25 -08:00
public bool Running = > _running ;
2021-11-27 10:06:39 -08:00
2022-03-04 12:32:25 -08:00
public Socket Connection { get ; private set ; }
2020-08-25 18:53:35 -07:00
2022-03-04 12:32:25 -08:00
public bool CompressionEnabled { get ; set ; }
2020-08-25 18:53:35 -07:00
2022-03-04 12:32:25 -08:00
public int Sequence { get ; set ; }
2020-08-25 18:53:35 -07:00
2022-03-04 12:32:25 -08:00
public List < Gump > Gumps { get ; private set ; }
2020-08-25 18:53:35 -07:00
2022-03-04 12:32:25 -08:00
public List < HuePicker > HuePickers { get ; private set ; }
2020-08-25 18:53:35 -07:00
2022-03-04 12:32:25 -08:00
public List < IMenu > Menus { get ; private set ; }
2020-08-25 18:53:35 -07:00
2022-03-04 12:32:25 -08:00
public CityInfo [ ] CityInfo { get ; set ; }
2020-08-25 18:53:35 -07:00
2022-03-04 12:32:25 -08:00
public Mobile Mobile { get ; set ; }
2020-08-25 18:53:35 -07:00
2022-03-04 12:32:25 -08:00
public ServerInfo [ ] ServerInfo { get ; set ; }
2020-08-25 18:53:35 -07:00
2022-03-04 12:32:25 -08:00
public IAccount Account { get ; set ; }
2020-08-25 18:53:35 -07:00
2022-06-28 01:05:00 -07:00
public string Assistant { get ; set ; }
2022-03-04 12:32:25 -08:00
public int CompareTo ( NetState other ) = > string . CompareOrdinal ( _toString , other ? . _toString ) ;
2020-08-25 18:53:35 -07:00
2022-03-04 12:32:25 -08:00
private void SetPacketTime ( int packetID )
{
if ( packetID is > = 0 and < 0x100 )
2021-02-07 23:30:56 -08:00
{
_packetThrottles [ packetID ] = Core . TickCount ;
}
2022-03-04 12:32:25 -08:00
}
2021-02-07 23:30:56 -08:00
2022-03-04 12:32:25 -08:00
public long GetPacketTime ( int packetID ) = > packetID is > = 0 and < 0x100 ? _packetThrottles [ packetID ] : 0 ;
2021-02-07 23:30:56 -08:00
2022-03-04 12:32:25 -08:00
private void UpdatePacketCount ( int packetID )
{
if ( packetID is > = 0 and < 0x100 )
2021-02-07 23:30:56 -08:00
{
_packetCounts [ packetID ] + + ;
}
2022-03-04 12:32:25 -08:00
}
2021-02-07 23:30:56 -08:00
2022-03-04 12:32:25 -08:00
public int CheckPacketCounts ( )
{
for ( int i = 0 ; i < _packetCounts . Length ; i + + )
2021-02-07 23:30:56 -08:00
{
2022-03-04 12:32:25 -08:00
long count = _packetCounts [ i ] ;
_packetCounts [ i ] = 0 ;
2021-02-07 23:30:56 -08:00
2022-03-04 12:32:25 -08:00
if ( count > PacketPerSecondThreshold )
{
return i ;
2021-02-07 23:30:56 -08:00
}
}
2022-03-04 12:32:25 -08:00
return 0 ;
}
public void ValidateAllTrades ( )
{
for ( var i = Trades . Count - 1 ; i > = 0 ; - - i )
2020-08-25 18:53:35 -07:00
{
2022-03-04 12:32:25 -08:00
if ( i > = Trades . Count )
2020-08-25 18:53:35 -07:00
{
2022-03-04 12:32:25 -08:00
continue ;
}
2020-08-25 18:53:35 -07:00
2022-03-04 12:32:25 -08:00
var trade = Trades [ i ] ;
2020-08-25 18:53:35 -07:00
2022-03-04 12:32:25 -08:00
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 ( ) ;
2020-08-25 18:53:35 -07:00
}
}
2022-03-04 12:32:25 -08:00
}
2020-08-25 18:53:35 -07:00
2022-03-04 12:32:25 -08:00
public void CancelAllTrades ( )
{
for ( var i = Trades . Count - 1 ; i > = 0 ; - - i )
2020-08-25 18:53:35 -07:00
{
2022-03-04 12:32:25 -08:00
if ( i < Trades . Count )
2020-09-12 00:05:38 -07:00
{
2022-03-04 12:32:25 -08:00
Trades [ i ] . Cancel ( ) ;
2020-09-12 00:05:38 -07:00
}
2020-08-25 18:53:35 -07:00
}
2022-03-04 12:32:25 -08:00
}
2020-08-25 18:53:35 -07:00
2022-03-04 12:32:25 -08:00
public void RemoveTrade ( SecureTrade trade )
{
Trades . Remove ( trade ) ;
}
2020-08-25 18:53:35 -07:00
2022-03-04 12:32:25 -08:00
public SecureTrade FindTrade ( Mobile m )
{
for ( var i = 0 ; i < Trades . Count ; + + i )
2020-08-25 18:53:35 -07:00
{
2022-03-04 12:32:25 -08:00
var trade = Trades [ i ] ;
2020-08-25 18:53:35 -07:00
2022-03-04 12:32:25 -08:00
if ( trade . From . Mobile = = m | | trade . To . Mobile = = m )
{
return trade ;
2020-08-25 18:53:35 -07:00
}
}
2022-03-04 12:32:25 -08:00
return null ;
}
2020-08-25 18:53:35 -07:00
2022-03-04 12:32:25 -08:00
public SecureTradeContainer FindTradeContainer ( Mobile m )
{
for ( var i = 0 ; i < Trades . Count ; + + i )
{
var trade = Trades [ i ] ;
2020-08-25 18:53:35 -07:00
2022-03-04 12:32:25 -08:00
var from = trade . From ;
var to = trade . To ;
2020-08-25 18:53:35 -07:00
2022-03-04 12:32:25 -08:00
if ( from . Mobile = = Mobile & & to . Mobile = = m )
{
return from . Container ;
2020-08-25 18:53:35 -07:00
}
2022-03-04 12:32:25 -08:00
if ( from . Mobile = = m & & to . Mobile = = Mobile )
{
return to . Container ;
}
2020-08-25 18:53:35 -07:00
}
2022-03-04 12:32:25 -08:00
return null ;
}
2020-08-25 18:53:35 -07:00
2022-03-04 12:32:25 -08:00
public SecureTradeContainer AddTrade ( NetState state )
{
var newTrade = new SecureTrade ( Mobile , state . Mobile ) ;
2020-08-25 18:53:35 -07:00
2022-03-04 12:32:25 -08:00
Trades . Add ( newTrade ) ;
state . Trades . Add ( newTrade ) ;
2020-08-25 18:53:35 -07:00
2022-03-04 12:32:25 -08:00
return newTrade . From . Container ;
}
2020-08-25 18:53:35 -07:00
2022-03-04 12:32:25 -08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void LogInfo ( string text )
{
2022-06-05 01:00:22 -07:00
logger . Information ( "Client: {NetState}: {Message}" , this , text ) ;
2022-03-04 12:32:25 -08:00
}
2020-08-25 18:53:35 -07:00
2022-03-04 12:32:25 -08:00
public void AddMenu ( IMenu menu )
{
Menus ? ? = new List < IMenu > ( ) ;
2020-08-25 18:53:35 -07:00
2022-03-04 12:32:25 -08:00
if ( Menus . Count < MenuCap )
2020-08-25 18:53:35 -07:00
{
2022-03-04 12:32:25 -08:00
Menus . Add ( menu ) ;
2020-08-25 18:53:35 -07:00
}
2022-03-04 12:32:25 -08:00
else
2020-08-25 18:53:35 -07:00
{
2022-03-04 12:32:25 -08:00
LogInfo ( "Exceeded menu cap, disconnecting..." ) ;
Disconnect ( "Exceeded menu cap." ) ;
2020-08-25 18:53:35 -07:00
}
2022-03-04 12:32:25 -08:00
}
2020-08-25 18:53:35 -07:00
2022-03-04 12:32:25 -08:00
public void RemoveMenu ( IMenu menu )
{
Menus ? . Remove ( menu ) ;
}
2020-08-25 18:53:35 -07:00
2022-03-04 12:32:25 -08:00
public void RemoveMenu ( int index )
{
Menus ? . RemoveAt ( index ) ;
}
2020-08-25 18:53:35 -07:00
2022-03-04 12:32:25 -08:00
public void ClearMenus ( )
{
Menus ? . Clear ( ) ;
}
2020-08-25 18:53:35 -07:00
2022-03-04 12:32:25 -08:00
public void AddHuePicker ( HuePicker huePicker )
{
HuePickers ? ? = new List < HuePicker > ( ) ;
2020-08-25 18:53:35 -07:00
2022-03-04 12:32:25 -08:00
if ( HuePickers . Count < HuePickerCap )
2020-08-25 18:53:35 -07:00
{
2022-03-04 12:32:25 -08:00
HuePickers . Add ( huePicker ) ;
2020-08-25 18:53:35 -07:00
}
2022-03-04 12:32:25 -08:00
else
2020-08-25 18:53:35 -07:00
{
2022-03-04 12:32:25 -08:00
LogInfo ( "Exceeded hue picker cap, disconnecting..." ) ;
Disconnect ( "Exceeded hue picker cap." ) ;
2020-08-25 18:53:35 -07:00
}
2022-03-04 12:32:25 -08:00
}
2020-08-25 18:53:35 -07:00
2022-03-04 12:32:25 -08:00
public void RemoveHuePicker ( HuePicker huePicker )
{
HuePickers ? . Remove ( huePicker ) ;
}
2020-08-25 18:53:35 -07:00
2022-03-04 12:32:25 -08:00
public void RemoveHuePicker ( int index )
{
HuePickers ? . RemoveAt ( index ) ;
}
2020-08-25 18:53:35 -07:00
2022-03-04 12:32:25 -08:00
public void ClearHuePickers ( )
{
HuePickers ? . Clear ( ) ;
}
2020-08-25 18:53:35 -07:00
2022-03-04 12:32:25 -08:00
public void AddGump ( Gump gump )
{
Gumps ? ? = new List < Gump > ( ) ;
2020-08-25 18:53:35 -07:00
2022-03-04 12:32:25 -08:00
if ( Gumps . Count < GumpCap )
2020-08-25 18:53:35 -07:00
{
2022-03-04 12:32:25 -08:00
Gumps . Add ( gump ) ;
2020-08-25 18:53:35 -07:00
}
2022-03-04 12:32:25 -08:00
else
2020-08-25 18:53:35 -07:00
{
2022-03-04 12:32:25 -08:00
LogInfo ( "Exceeded gump cap, disconnecting..." ) ;
Disconnect ( "Exceeded gump cap." ) ;
2020-08-25 18:53:35 -07:00
}
2022-03-04 12:32:25 -08:00
}
2020-08-25 18:53:35 -07:00
2022-03-04 12:32:25 -08:00
public void RemoveGump ( Gump gump )
{
Gumps ? . Remove ( gump ) ;
}
2020-08-25 18:53:35 -07:00
2022-03-04 12:32:25 -08:00
public void RemoveGump ( int index )
{
Gumps ? . RemoveAt ( index ) ;
}
public void ClearGumps ( )
{
Gumps ? . Clear ( ) ;
}
public void LaunchBrowser ( string url )
{
this . SendMessageLocalized ( Serial . MinusOne , - 1 , MessageType . Label , 0x35 , 3 , 501231 ) ;
this . SendLaunchBrowser ( url ) ;
}
public override string ToString ( ) = > _toString ;
public bool GetSendBuffer ( out CircularBuffer < byte > cBuffer )
{
2021-04-08 21:56:31 -07:00
#if THREADGUARD
if ( Thread . CurrentThread ! = Core . Thread )
{
Utility . PushColor ( ConsoleColor . Red ) ;
Console . WriteLine ( "Attempting to get pipe buffer from wrong thread!" ) ;
Console . WriteLine ( new StackTrace ( ) ) ;
Utility . PopColor ( ) ;
return ;
}
#endif
2022-03-04 12:32:25 -08:00
var result = SendPipe . Writer . TryGetMemory ( ) ;
cBuffer = new CircularBuffer < byte > ( result . Buffer ) ;
return ! ( result . IsClosed | | result . Length < = 0 ) ;
}
public void Send ( ReadOnlySpan < byte > span )
{
if ( span = = null | | this . CannotSendPackets ( ) )
{
return ;
}
2020-10-27 11:22:07 -07:00
2022-03-04 12:32:25 -08:00
var length = span . Length ;
if ( length < = 0 | | ! GetSendBuffer ( out var buffer ) )
{
return ;
2020-10-27 11:22:07 -07:00
}
2022-03-04 12:32:25 -08:00
try
2020-11-12 00:52:38 -08:00
{
2022-03-04 12:32:25 -08:00
PacketSendProfile prof = null ;
if ( Core . Profiling )
2020-11-29 03:24:51 -08:00
{
2022-03-04 12:32:25 -08:00
prof = PacketSendProfile . Acquire ( span [ 0 ] ) ;
prof . Start ( ) ;
2020-11-29 03:24:51 -08:00
}
2022-03-04 12:32:25 -08:00
if ( _packetEncoder ! = null )
2020-11-12 00:52:38 -08:00
{
2022-03-04 12:32:25 -08:00
_packetEncoder ( span , buffer , out length ) ;
2020-11-12 00:52:38 -08:00
}
2022-03-04 12:32:25 -08:00
else
2020-11-12 00:52:38 -08:00
{
2022-03-04 12:32:25 -08:00
buffer . CopyFrom ( span ) ;
}
2021-10-31 10:22:22 -07:00
2022-03-04 12:32:25 -08:00
if ( PacketLogging )
{
LogPacket ( span , ReadOnlySpan < byte > . Empty , span . Length , false ) ;
}
2021-01-25 21:06:46 -08:00
2022-03-04 12:32:25 -08:00
SendPipe . Writer . Advance ( ( uint ) length ) ;
2021-02-07 23:30:56 -08:00
2022-03-04 12:32:25 -08:00
if ( ! _flushQueued )
2020-11-12 00:52:38 -08:00
{
2022-05-30 14:04:54 -07:00
_flushPending . Enqueue ( this ) ;
2022-03-04 12:32:25 -08:00
_flushQueued = true ;
}
prof ? . Finish ( ) ;
}
catch ( Exception ex )
{
TraceException ( ex ) ;
Disconnect ( "Exception while sending." ) ;
2020-11-12 00:52:38 -08:00
}
2022-03-04 12:32:25 -08:00
}
2020-11-12 00:52:38 -08:00
2022-03-04 12:32:25 -08:00
private void StartPacketLog ( )
{
try
2021-10-31 10:22:22 -07:00
{
2022-03-04 12:32:25 -08:00
var logDir = Path . Combine ( _packetLoggingPath , _toString ) ;
PathUtility . EnsureDirectory ( logDir ) ;
var logPath = Path . Combine ( logDir , "packets.log" ) ;
using var op = new StreamWriter ( logPath , true ) ;
op . WriteLine ( ">>>>>>>>>> Logging started {0:yyyy/MM/dd HH:mm::ss} <<<<<<<<<<" , Core . Now ) ;
op . WriteLine ( ) ;
op . WriteLine ( ) ;
}
catch ( Exception e )
{
Console . WriteLine ( e ) ;
2021-10-31 10:22:22 -07:00
}
2022-03-04 12:32:25 -08:00
}
2021-10-31 10:22:22 -07:00
2022-03-04 12:32:25 -08:00
private void LogPacket ( ReadOnlySpan < byte > first , ReadOnlySpan < byte > second , int totalLength , bool incoming )
{
try
2021-10-31 10:22:22 -07:00
{
2022-03-04 12:32:25 -08:00
var logDir = Path . Combine ( _packetLoggingPath , _toString ) ;
PathUtility . EnsureDirectory ( logDir ) ;
var logPath = Path . Combine ( logDir , "packets.log" ) ;
const string incomingStr = "Client -> Server" ;
const string outgoingStr = "Server -> Client" ;
using var sw = new StreamWriter ( logPath , true ) ;
sw . WriteLine ( $"{Core.Now:HH:mm:ss.ffff}: {(incoming ? incomingStr : outgoingStr)} 0x{first[0]:X2} (Length: {totalLength})" ) ;
sw . FormatBuffer ( first , second , totalLength ) ;
sw . WriteLine ( ) ;
sw . WriteLine ( ) ;
}
catch
{
// ignored
2021-10-31 10:22:22 -07:00
}
2022-03-04 12:32:25 -08:00
}
2021-10-31 10:22:22 -07:00
2022-03-04 12:32:25 -08:00
public void HandleReceive ( )
{
if ( ! _running )
2021-02-07 23:30:56 -08:00
{
2022-03-04 12:32:25 -08:00
return ;
}
2021-02-07 23:30:56 -08:00
2022-03-04 12:32:25 -08:00
ReceiveData ( ) ;
2021-10-03 18:04:53 -07:00
2022-03-04 12:32:25 -08:00
var reader = RecvPipe . Reader ;
2021-02-07 23:30:56 -08:00
2022-03-04 12:32:25 -08:00
try
{
// Process as many packets as we can synchronously
while ( _running & & _parserState ! = ParserState . Error & & _protocolState ! = ProtocolState . Error )
2021-02-07 23:30:56 -08:00
{
2022-03-04 12:32:25 -08:00
var result = reader . TryRead ( ) ;
var length = result . Length ;
2021-02-07 23:30:56 -08:00
2022-03-04 12:32:25 -08:00
if ( length < = 0 )
{
break ;
}
2021-02-07 23:30:56 -08:00
2022-03-04 12:32:25 -08:00
var packetReader = new CircularBufferReader ( result . Buffer ) ;
var packetId = packetReader . ReadByte ( ) ;
int packetLength = length ;
2021-02-07 23:30:56 -08:00
2022-03-04 12:32:25 -08:00
// These can arrive at any time and are only informational
if ( _protocolState ! = ProtocolState . AwaitingSeed & & IncomingPackets . IsInfoPacket ( packetId ) )
{
_parserState = ParserState . ProcessingPacket ;
_parserState = HandlePacket ( packetReader , packetId , out packetLength ) ;
}
else
{
switch ( _protocolState )
2021-02-07 23:30:56 -08:00
{
2022-03-04 12:32:25 -08:00
case ProtocolState . AwaitingSeed :
{
if ( packetId = = 0xEF )
2021-02-07 23:30:56 -08:00
{
2022-03-04 12:32:25 -08:00
_parserState = ParserState . ProcessingPacket ;
_parserState = HandlePacket ( packetReader , packetId , out packetLength ) ;
if ( _parserState = = ParserState . AwaitingNextPacket )
2021-02-07 23:30:56 -08:00
{
2022-03-04 12:32:25 -08:00
_protocolState = ProtocolState . LoginServer_AwaitingLogin ;
2021-02-07 23:30:56 -08:00
}
}
2022-03-04 12:32:25 -08:00
else if ( length > = 4 )
2021-02-07 23:30:56 -08:00
{
2022-03-04 12:32:25 -08:00
int seed = ( packetId < < 24 ) | ( packetReader . ReadByte ( ) < < 16 ) | ( packetReader . ReadByte ( ) < < 8 ) | packetReader . ReadByte ( ) ;
if ( seed = = 0 )
2021-02-07 23:30:56 -08:00
{
2022-03-04 12:32:25 -08:00
HandleError ( 0 , 0 ) ;
2021-09-17 00:15:16 -07:00
return ;
2021-02-07 23:30:56 -08:00
}
2022-03-04 12:32:25 -08:00
_seed = seed ;
packetLength = 4 ;
_parserState = ParserState . AwaitingNextPacket ;
_protocolState = ProtocolState . GameServer_AwaitingGameServerLogin ;
}
else
{
_parserState = ParserState . AwaitingPartialPacket ;
2021-02-07 23:30:56 -08:00
}
2022-03-04 12:32:25 -08:00
break ;
}
2021-02-07 23:30:56 -08:00
2022-03-04 12:32:25 -08:00
case ProtocolState . LoginServer_AwaitingLogin :
{
if ( packetId ! = 0xCF & & packetId ! = 0x80 )
2021-02-07 23:30:56 -08:00
{
2022-03-04 12:32:25 -08:00
LogInfo ( "Possible encrypted client detected, disconnecting..." ) ;
HandleError ( packetId , packetLength ) ;
return ;
}
2021-02-07 23:30:56 -08:00
2022-03-04 12:32:25 -08:00
_parserState = ParserState . ProcessingPacket ;
_parserState = HandlePacket ( packetReader , packetId , out packetLength ) ;
if ( _parserState = = ParserState . AwaitingNextPacket )
{
_protocolState = ProtocolState . LoginServer_AwaitingServerSelect ;
2021-02-07 23:30:56 -08:00
}
2022-03-04 12:32:25 -08:00
break ;
}
2021-02-07 23:30:56 -08:00
2022-03-04 12:32:25 -08:00
case ProtocolState . LoginServer_AwaitingServerSelect :
{
if ( packetId ! = 0xA0 )
2021-02-07 23:30:56 -08:00
{
HandleError ( packetId , packetLength ) ;
2021-09-17 00:15:16 -07:00
return ;
2021-02-07 23:30:56 -08:00
}
2022-03-04 12:32:25 -08:00
_parserState = ParserState . ProcessingPacket ;
_parserState = HandlePacket ( packetReader , packetId , out packetLength ) ;
if ( _parserState = = ParserState . AwaitingNextPacket )
2021-02-07 23:30:56 -08:00
{
2022-03-04 12:32:25 -08:00
_protocolState = ProtocolState . LoginServer_ServerSelectAck ;
Disconnect ( string . Empty ) ;
2021-02-07 23:30:56 -08:00
}
2022-03-04 12:32:25 -08:00
break ;
}
2021-02-07 23:30:56 -08:00
2022-03-04 12:32:25 -08:00
case ProtocolState . LoginServer_ServerSelectAck :
{
#if STRICT_UO_PROTOCOL
HandleError ( packetId , packetLength ) ;
#else
// Reset the state because CUO/Orion do not reconnect
_parserState = ParserState . AwaitingNextPacket ;
_protocolState = ProtocolState . AwaitingSeed ;
#endif
return ;
}
case ProtocolState . GameServer_AwaitingGameServerLogin :
{
if ( packetId ! = 0x91 & & packetId ! = 0x80 )
2021-02-07 23:30:56 -08:00
{
2022-03-04 12:32:25 -08:00
HandleError ( packetId , packetLength ) ;
return ;
2021-02-07 23:30:56 -08:00
}
2022-03-04 12:32:25 -08:00
_parserState = ParserState . ProcessingPacket ;
_parserState = HandlePacket ( packetReader , packetId , out packetLength ) ;
if ( _parserState = = ParserState . AwaitingNextPacket )
{
_protocolState = ProtocolState . GameServer_LoggedIn ;
}
break ;
}
case ProtocolState . GameServer_LoggedIn :
{
_parserState = ParserState . ProcessingPacket ;
_parserState = HandlePacket ( packetReader , packetId , out packetLength ) ;
break ;
}
2021-02-07 23:30:56 -08:00
}
}
2022-03-04 12:32:25 -08:00
if ( _parserState is ParserState . AwaitingNextPacket or ParserState . Throttled )
{
reader . Advance ( ( uint ) packetLength ) ;
}
else if ( _parserState is ParserState . AwaitingPartialPacket )
{
break ;
}
else if ( _parserState is ParserState . Error )
{
HandleError ( packetId , packetLength ) ;
break ;
}
2021-02-07 23:30:56 -08:00
}
2022-03-04 12:32:25 -08:00
reader . Commit ( ) ;
}
catch ( Exception ex )
{
2021-02-07 23:30:56 -08:00
#if DEBUG
2022-07-01 11:57:08 -07:00
Console . WriteLine ( ex ) ;
2021-02-07 23:30:56 -08:00
#endif
2022-03-04 12:32:25 -08:00
TraceException ( ex ) ;
Disconnect ( "Exception during HandleReceive" ) ;
2021-02-07 23:30:56 -08:00
}
2022-03-04 12:32:25 -08:00
}
2021-02-07 23:30:56 -08:00
2022-03-04 12:32:25 -08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void HandleError ( byte packetId , int packetLength )
{
var msg =
$"{this} entered bad state on packet 0x{packetId:X2} with length {packetLength} while in protocol state {_protocolState} and parser state {_parserState}" ;
Disconnect ( msg ) ;
_parserState = ParserState . Error ;
_protocolState = ProtocolState . Error ;
}
/ *
* length is the total buffer length . We might be able to use packetReader . Capacity ( ) instead .
* packetLength is the length of the packet that this function actually found .
* /
2022-06-15 21:48:43 +02:00
private unsafe ParserState HandlePacket ( CircularBufferReader packetReader , byte packetId , out int packetLength )
2022-03-04 12:32:25 -08:00
{
PacketHandler handler = IncomingPackets . GetHandler ( packetId ) ;
int length = packetReader . Length ;
if ( handler = = null )
2021-02-07 23:30:56 -08:00
{
2022-03-04 12:32:25 -08:00
LogInfo ( $"Received unknown packet 0x{packetId:X2} while in state {_protocolState}" ) ;
packetLength = 1 ;
return ParserState . Error ;
2021-02-07 23:30:56 -08:00
}
2022-03-04 12:32:25 -08:00
packetLength = handler . GetLength ( this ) ;
if ( packetLength < = 0 )
2021-02-07 23:30:56 -08:00
{
2022-03-04 12:32:25 -08:00
// Variable length packet. See if we have pulled in the length.
if ( length < 3 )
2021-02-07 23:30:56 -08:00
{
2022-03-04 12:32:25 -08:00
return ParserState . AwaitingPartialPacket ;
2021-02-07 23:30:56 -08:00
}
2022-03-04 12:32:25 -08:00
packetLength = packetReader . ReadUInt16 ( ) ;
if ( packetLength < 3 )
2021-02-07 23:30:56 -08:00
{
2022-03-04 12:32:25 -08:00
return ParserState . Error ;
2021-02-07 23:30:56 -08:00
}
2022-03-04 12:32:25 -08:00
}
2021-02-07 23:30:56 -08:00
2022-03-04 12:32:25 -08:00
// Not enough data, let's wait for more to come in
if ( length < packetLength )
{
return ParserState . AwaitingPartialPacket ;
}
2021-02-07 23:30:56 -08:00
2022-03-04 12:32:25 -08:00
if ( handler . Ingame )
{
if ( Mobile = = null )
2021-02-07 23:30:56 -08:00
{
2022-03-04 12:32:25 -08:00
LogInfo ( $"received packet 0x{packetId:X2} before having been attached to a mobile" ) ;
return ParserState . Error ;
2021-02-07 23:30:56 -08:00
}
2022-03-04 12:32:25 -08:00
if ( Mobile . Deleted )
2021-02-07 23:30:56 -08:00
{
2022-03-04 12:32:25 -08:00
return ParserState . Error ;
2021-02-07 23:30:56 -08:00
}
2022-03-04 12:32:25 -08:00
}
2021-02-07 23:30:56 -08:00
2022-06-15 21:48:43 +02:00
var throttler = handler . ThrottleCallback ;
2022-03-04 12:32:25 -08:00
if ( throttler ! = null )
{
if ( ! throttler ( packetId , this , out bool drop ) )
2021-02-07 23:30:56 -08:00
{
2022-03-04 12:32:25 -08:00
return drop ? ParserState . Throttled : ParserState . AwaitingNextPacket ;
2021-02-07 23:30:56 -08:00
}
2022-03-04 12:32:25 -08:00
SetPacketTime ( packetId ) ;
}
2021-02-07 23:30:56 -08:00
2022-03-04 12:32:25 -08:00
PacketReceiveProfile prof = null ;
2021-10-31 10:22:22 -07:00
2022-03-04 12:32:25 -08:00
if ( Core . Profiling )
{
prof = PacketReceiveProfile . Acquire ( packetId ) ;
prof ? . Start ( ) ;
}
2021-02-07 23:30:56 -08:00
2022-03-04 12:32:25 -08:00
UpdatePacketCount ( packetId ) ;
2021-02-07 23:30:56 -08:00
2022-03-04 12:32:25 -08:00
if ( PacketLogging )
{
LogPacket ( packetReader . First , packetReader . Second , packetLength , true ) ;
2021-02-07 23:30:56 -08:00
}
2022-03-04 12:32:25 -08:00
handler . OnReceive ( this , packetReader , packetLength ) ;
2020-10-20 20:55:19 -07:00
2022-03-04 12:32:25 -08:00
prof ? . Finish ( packetLength ) ;
2021-02-07 23:30:56 -08:00
2022-03-04 12:32:25 -08:00
return ParserState . AwaitingNextPacket ;
}
2020-10-20 20:55:19 -07:00
2022-03-04 12:32:25 -08:00
private bool Flush ( )
{
_flushQueued = false ;
2021-02-07 23:30:56 -08:00
2022-03-04 12:32:25 -08:00
if ( Connection = = null )
{
return true ;
}
2021-02-07 23:30:56 -08:00
2022-03-04 12:32:25 -08:00
SendPipe . Writer . Flush ( ) ;
2021-02-07 23:30:56 -08:00
2022-03-04 12:32:25 -08:00
var reader = SendPipe . Reader ;
var result = reader . TryRead ( ) ;
if ( result . IsClosed | | result . Length = = 0 )
{
return true ;
}
var bytesWritten = 0 ;
try
{
bytesWritten = Connection . Send ( result . Buffer , SocketFlags . None ) ;
}
catch ( SocketException ex )
{
2022-05-21 20:24:46 -07:00
if ( ex . SocketErrorCode ! = SocketError . WouldBlock )
{
2022-06-05 01:00:22 -07:00
logger . Debug ( ex , "Disconnected due to a socket exception" ) ;
2022-05-21 20:24:46 -07:00
Disconnect ( string . Empty ) ;
}
2022-03-04 12:32:25 -08:00
}
catch ( Exception ex )
{
Disconnect ( $"Disconnected with error: {ex}" ) ;
TraceException ( ex ) ;
2020-08-25 18:53:35 -07:00
}
2022-03-04 12:32:25 -08:00
if ( bytesWritten > 0 )
2020-10-24 21:49:28 -07:00
{
2022-03-04 12:32:25 -08:00
_nextActivityCheck = Core . TickCount + 90000 ;
reader . Advance ( ( uint ) bytesWritten ) ;
2020-10-24 21:49:28 -07:00
}
2022-03-04 12:32:25 -08:00
return bytesWritten = = result . Length ;
}
2020-10-24 21:49:28 -07:00
2022-03-04 12:32:25 -08:00
private void DecodePacket ( ArraySegment < byte > [ ] buffer , ref int length )
{
CircularBuffer < byte > cBuffer = new CircularBuffer < byte > ( buffer ) ;
_packetDecoder ? . Invoke ( cBuffer , ref length ) ;
}
2020-08-25 18:53:35 -07:00
2022-03-04 12:32:25 -08:00
private void ReceiveData ( )
{
var writer = RecvPipe . Writer ;
var result = writer . TryGetMemory ( ) ;
2021-02-07 23:30:56 -08:00
2022-03-04 12:32:25 -08:00
if ( result . IsClosed | | result . Length = = 0 )
{
return ;
}
var bytesWritten = 0 ;
try
{
bytesWritten = Connection . Receive ( result . Buffer , SocketFlags . None ) ;
}
catch ( SocketException ex )
{
2022-05-21 20:24:46 -07:00
if ( ex . ErrorCode is not 54 and not 89 and not 995 )
{
logger . Debug ( ex , "Disconnected due to a socket exception" ) ;
}
2022-03-04 12:32:25 -08:00
Disconnect ( string . Empty ) ;
}
catch ( Exception ex )
{
Disconnect ( $"Disconnected with error: {ex}" ) ;
TraceException ( ex ) ;
}
2020-10-20 20:55:19 -07:00
2022-03-04 12:32:25 -08:00
if ( bytesWritten < = 0 )
{
Disconnect ( string . Empty ) ;
return ;
}
2020-10-20 20:55:19 -07:00
2022-03-04 12:32:25 -08:00
DecodePacket ( result . Buffer , ref bytesWritten ) ;
2020-10-20 20:55:19 -07:00
2022-03-04 12:32:25 -08:00
writer . Advance ( ( uint ) bytesWritten ) ;
_nextActivityCheck = Core . TickCount + 90000 ;
}
2020-10-20 20:55:19 -07:00
2022-03-04 12:32:25 -08:00
public static void FlushAll ( )
{
2022-05-30 14:04:54 -07:00
while ( _flushPending . Count ! = 0 )
2020-10-20 20:55:19 -07:00
{
2022-05-30 14:04:54 -07:00
_flushPending . Dequeue ( ) ? . Flush ( ) ;
2020-10-20 20:55:19 -07:00
}
2022-03-04 12:32:25 -08:00
}
2020-10-20 20:55:19 -07:00
2022-03-04 12:32:25 -08:00
public static void Slice ( )
{
2022-05-30 14:04:54 -07:00
int count = _pollGroup . Poll ( _polledStates ) ;
2021-10-03 18:04:53 -07:00
2022-03-04 12:32:25 -08:00
if ( count > 0 )
{
for ( int i = 0 ; i < count ; i + + )
2020-08-25 18:53:35 -07:00
{
2022-03-04 12:32:25 -08:00
( _polledStates [ i ] . Target as NetState ) ? . HandleReceive ( ) ;
_polledStates [ i ] = default ;
2021-10-03 18:04:53 -07:00
}
2022-03-04 12:32:25 -08:00
}
2021-10-03 18:04:53 -07:00
2022-05-30 14:04:54 -07:00
while ( _flushPending . TryDequeue ( out var ns ) )
2022-03-04 12:32:25 -08:00
{
if ( ! ns . Flush ( ) )
2021-10-03 18:04:53 -07:00
{
2022-03-04 12:32:25 -08:00
// Incomplete data, so we need to requeue
2022-05-30 14:04:54 -07:00
_flushedPartials . Enqueue ( ns ) ;
2020-10-20 20:55:19 -07:00
}
2022-03-04 12:32:25 -08:00
}
2021-01-25 21:06:46 -08:00
2022-05-30 14:04:54 -07:00
var hasDisposes = false ;
while ( _disposed . TryDequeue ( out var ns ) )
2022-03-04 12:32:25 -08:00
{
2022-05-30 14:04:54 -07:00
hasDisposes = true ;
2022-03-04 12:32:25 -08:00
ns . Dispose ( ) ;
}
2021-10-03 18:04:53 -07:00
2022-05-30 14:04:54 -07:00
// If they weren't disconnected, requeue them
while ( _flushedPartials . TryDequeue ( out var ns ) )
{
if ( ns . Running )
{
_flushPending . Enqueue ( ns ) ;
}
}
2022-03-04 12:32:25 -08:00
if ( hasDisposes )
{
2022-05-30 14:04:54 -07:00
_pollGroup . Poll ( _polledStates . Length ) ;
2020-10-20 20:55:19 -07:00
}
2022-03-04 12:32:25 -08:00
}
2020-10-20 20:55:19 -07:00
2022-03-04 12:32:25 -08:00
public void CheckAlive ( long curTicks )
{
if ( Connection ! = null & & _nextActivityCheck - curTicks < 0 )
2020-10-20 20:55:19 -07:00
{
2022-03-04 12:32:25 -08:00
LogInfo ( "Disconnecting due to inactivity..." ) ;
Disconnect ( "Disconnecting due to inactivity." ) ;
2020-08-25 18:53:35 -07:00
}
2022-03-04 12:32:25 -08:00
}
2020-08-25 18:53:35 -07:00
2022-03-04 12:32:25 -08:00
public static void CheckAllAlive ( )
{
try
2020-10-20 20:55:19 -07:00
{
2022-03-04 12:32:25 -08:00
long curTicks = Core . TickCount ;
2020-10-20 20:55:19 -07:00
2022-03-04 12:32:25 -08:00
foreach ( var ns in TcpServer . Instances )
2020-10-20 20:55:19 -07:00
{
2022-03-04 12:32:25 -08:00
ns . CheckAlive ( curTicks ) ;
2020-10-20 20:55:19 -07:00
}
}
2022-03-04 12:32:25 -08:00
catch ( Exception ex )
2020-08-25 18:53:35 -07:00
{
2022-03-04 12:32:25 -08:00
TraceException ( ex ) ;
}
}
2020-08-25 18:53:35 -07:00
2022-03-04 12:32:25 -08:00
public static void TraceException ( Exception ex )
{
try
{
using var op = new StreamWriter ( "network-errors.log" , true ) ;
op . WriteLine ( "# {0}" , Core . Now ) ;
2020-08-25 18:53:35 -07:00
2022-03-04 12:32:25 -08:00
op . WriteLine ( ex ) ;
2020-08-25 18:53:35 -07:00
2022-03-04 12:32:25 -08:00
op . WriteLine ( ) ;
op . WriteLine ( ) ;
2020-08-25 18:53:35 -07:00
}
2022-03-04 12:32:25 -08:00
catch
{
// ignored
}
Console . WriteLine ( ex ) ;
}
2020-08-25 18:53:35 -07:00
2022-03-04 12:32:25 -08:00
public void Disconnect ( string reason )
{
if ( ! _running )
2020-08-25 18:53:35 -07:00
{
2022-03-04 12:32:25 -08:00
return ;
}
2020-08-25 18:53:35 -07:00
2022-03-04 12:32:25 -08:00
_running = false ;
2021-10-03 18:04:53 -07:00
2022-05-30 14:04:54 -07:00
#if THREADGUARD
if ( Thread . CurrentThread ! = Core . Thread )
2020-08-25 18:53:35 -07:00
{
2022-05-30 14:04:54 -07:00
Utility . PushColor ( ConsoleColor . Red ) ;
Console . WriteLine ( "Attempting to disconnect a netstate from an invalid thread!" ) ;
Console . WriteLine ( new StackTrace ( ) ) ;
Utility . PopColor ( ) ;
return ;
2020-08-25 18:53:35 -07:00
}
2022-05-30 14:04:54 -07:00
#endif
2021-02-07 23:30:56 -08:00
2022-03-04 12:32:25 -08:00
_disconnectReason = reason ;
2022-05-30 14:04:54 -07:00
_disposed . Enqueue ( this ) ;
2022-03-04 12:32:25 -08:00
}
public static void TraceDisconnect ( string reason , string ip )
{
if ( reason = = string . Empty )
2021-02-07 23:30:56 -08:00
{
2022-03-04 12:32:25 -08:00
return ;
}
2021-02-07 23:30:56 -08:00
2022-03-04 12:32:25 -08:00
try
{
using StreamWriter op = new StreamWriter ( "network-disconnects.log" , true ) ;
op . WriteLine ( $"# {Core.Now}" ) ;
2021-02-07 23:30:56 -08:00
2022-03-04 12:32:25 -08:00
op . WriteLine ( $"NetState: {ip}" ) ;
op . WriteLine ( reason ) ;
2021-02-07 23:30:56 -08:00
2022-03-04 12:32:25 -08:00
op . WriteLine ( ) ;
op . WriteLine ( ) ;
2020-08-25 18:53:35 -07:00
}
2022-03-04 12:32:25 -08:00
catch ( Exception ex )
2020-08-25 18:53:35 -07:00
{
2022-03-04 12:32:25 -08:00
TraceException ( ex ) ;
}
}
2020-08-25 18:53:35 -07:00
2022-03-04 12:32:25 -08:00
private void Dispose ( )
{
TraceDisconnect ( _disconnectReason , _toString ) ;
if ( _running )
{
throw new Exception ( "Disconnected a NetState that is still running." ) ;
}
2021-10-03 18:04:53 -07:00
2021-04-08 21:56:31 -07:00
#if THREADGUARD
if ( Thread . CurrentThread ! = Core . Thread )
{
Utility . PushColor ( ConsoleColor . Red ) ;
Console . WriteLine ( "Attempting to dispose a netstate from an invalid thread!" ) ;
Console . WriteLine ( new StackTrace ( ) ) ;
Utility . PopColor ( ) ;
return ;
}
#endif
2022-03-04 12:32:25 -08:00
TcpServer . Instances . Remove ( this ) ;
try
{
2022-05-30 14:04:54 -07:00
_pollGroup . Remove ( Connection , _handle ) ;
2022-03-04 12:32:25 -08:00
}
catch ( Exception ex )
{
TraceException ( ex ) ;
}
2021-10-03 18:04:53 -07:00
2022-03-04 12:32:25 -08:00
Connection . Close ( ) ;
_handle . Free ( ) ;
2020-08-25 18:53:35 -07:00
2022-03-04 12:32:25 -08:00
var m = Mobile ;
Mobile = null ;
2021-04-08 21:56:31 -07:00
2022-03-04 12:32:25 -08:00
if ( m ? . NetState = = this )
{
m . NetState = null ;
}
2021-04-08 21:56:31 -07:00
2022-03-04 12:32:25 -08:00
var a = Account ;
2020-08-25 18:53:35 -07:00
2022-03-04 12:32:25 -08:00
Gumps . Clear ( ) ;
Menus . Clear ( ) ;
HuePickers . Clear ( ) ;
Account = null ;
ServerInfo = null ;
CityInfo = null ;
2020-08-25 18:53:35 -07:00
2022-03-04 12:32:25 -08:00
var count = TcpServer . Instances . Count ;
2020-10-20 20:55:19 -07:00
2022-06-05 01:00:22 -07:00
LogInfo ( a ! = null ? $"Disconnected. [{count} Online] [{a}]" : $"Disconnected. [{count} Online]" ) ;
2020-08-25 18:53:35 -07:00
}
}