/* Thor Server 2.0 Project - Codenamed "Stockholm" Copyright 2008 - 2009 Joe Hegarty This file is part of The Thor Server 2.0 Project - Codenamed "Stockholm". The Thor Server 2.0 Project - Codenamed "Stockholm" is free software: you can redistribute it and/or modify it under the terms of the Microsoft Public License The Thor Server Project is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the Microsoft Public License for more details. You should have received a copy of the Microsoft Public License along with The Thor Server Project. If not, see http://www.opensource.org/licenses/ms-pl.html */ #define TRACE using System; using System.Net; using System.Net.Sockets; using System.Text; using System.Collections.Generic; using System.Threading.Tasks; using StockholmLibrary.Util; using StockholmLibrary.Game.Packets.Server; using StockholmLibrary.Game.Sessions; namespace StockholmLibrary.Net { //------------------------------------ public class Peer { private uint _peerId; private Socket _socket; private AsyncCallback _dataReceivedCallback; private byte[] _dataBuffer = new byte[ClientPacket.LENGTH_HEADER_LENGTH]; private Decoder _dataDecoder = Encoding.GetEncoding("iso-8859-1").GetDecoder(); private ConnectionManager _connectionManager; private Task _receiveTask = null; private Session _session = null; //********************************************** public uint PeerID { get { return _peerId; } } //********************************************** public Socket Socket { get { return _socket; } } //********************************************** public Session Session { get { return _session; } set { _session = value; } } //********************************************** public Peer(ConnectionManager connectionManager, uint peerId, Socket socket) { _peerId = peerId; _socket = socket; _connectionManager = connectionManager; _dataReceivedCallback = new AsyncCallback(OnDataReceived); _socket.BeginReceive(_dataBuffer, 0, _dataBuffer.Length, SocketFlags.None, _dataReceivedCallback, null); // Send hello message EnqueuePacket(new ServerPacket(EServerPacket.HELLO)); } //********************************************** private void OnDataReceived(IAsyncResult asyn) { try { int dataSize = _socket.EndReceive(asyn); if (dataSize == 0) { throw new ObjectDisposedException("Socket"); } else { // Not a full header, we need to wait while (dataSize < _dataBuffer.Length) { byte[] thisByte = new byte[1]; if (_socket.Receive(thisByte, 1, SocketFlags.None) != 0) { _dataBuffer[dataSize++] = thisByte[0]; } else { throw new ObjectDisposedException("Socket"); } } ProcessIncomingData(_dataBuffer); _socket.BeginReceive(_dataBuffer, 0, _dataBuffer.Length, SocketFlags.None, _dataReceivedCallback, null); } } catch (ObjectDisposedException) { OnDisconnect(); } catch (SocketException e) { Logging.LogEvent("Peer " + _peerId, "Unhandled socket error: " + e.ToString(), Logging.ELogLevel.ERROR); OnDisconnect(); } } //********************************************** private void OnDisconnect() { Logging.LogEvent("Peer " + _peerId, "Connection closed.", Logging.ELogLevel.INFO); try { _socket.Close(); _connectionManager.OnClientDisconnect(this); } catch { } } //********************************************** private void ProcessIncomingData(byte[] dataReceived) { int packetLength = B64Encoding.DecodeInt(dataReceived); byte[] packetData = new byte[packetLength]; int currentPosition = 0; while (currentPosition < packetLength) { byte[] thisByte = new byte[1]; if (_socket.Receive(thisByte, 1, SocketFlags.None) != 0) { packetData[currentPosition++] = thisByte[0]; } else { throw new ObjectDisposedException("Socket"); } } #if DEBUG System.String szData = Conversion.ByteToStringArray(packetData); Logging.LogEvent("Peer " + _peerId, "Received " + packetLength + " bytes. \"" + szData + "\"", Logging.ELogLevel.DEBUG); #else Logging.LogEvent("Peer " + _peerId, "Received " + packetLength + " bytes", Logging.ELogLevel.DEBUG); #endif ClientPacket packet = new ClientPacket(); packet.InitialisePacket(this, packetData); if (_receiveTask == null) { _receiveTask = new Task(() => Stockholm.Get().PacketManager.ForwardPacket(packet)); _receiveTask.Start(); } else { _receiveTask.ContinueWith(( o ) => Stockholm.Get().PacketManager.ForwardPacket(packet)); } } //********************************************** public void EnqueuePacket(ServerPacket packet) { SendPacket(packet.Serialise()); } //********************************************** private void SendPacket(byte[] dataToSend) { #if DEBUG System.String szData = Conversion.ByteToStringArray(dataToSend); Logging.LogEvent("Peer " + _peerId, "Sending " + dataToSend.Length + " bytes. \"" + szData + "\"", Logging.ELogLevel.DEBUG); #else Logging.LogEvent("Peer " + _peerId, "Sending " + dataToSend.Length + " bytes", Logging.ELogLevel.DEBUG); #endif _socket.Send(dataToSend); } } }