mirror of
https://bitbucket.org/Ioncannon/project-meteor-server.git
synced 2025-06-10 06:24:38 +02:00
Cleaned up namespaces (still have to do Map Project) and removed references to FFXIV Classic from the code. Removed the Launcher Editor project as it is no longer needed (host file editing is cleaner).
This commit is contained in:
parent
7587a6e142
commit
0f61c4c0e1
544 changed files with 54548 additions and 55498 deletions
264
Lobby Server/Server.cs
Normal file
264
Lobby Server/Server.cs
Normal file
|
@ -0,0 +1,264 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2015-2019 Project Meteor Dev Team
|
||||
|
||||
This file is part of Project Meteor Server.
|
||||
|
||||
Project Meteor Server is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Project Meteor Server 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
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with Project Meteor Server. If not, see <https:www.gnu.org/licenses/>.
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Threading;
|
||||
|
||||
using Meteor.Common;
|
||||
|
||||
namespace Meteor.Lobby
|
||||
{
|
||||
class Server
|
||||
{
|
||||
public const int FFXIV_LOBBY_PORT = 54994;
|
||||
public const int BUFFER_SIZE = 0xFFFF;
|
||||
public const int BACKLOG = 100;
|
||||
|
||||
private const int CLEANUP_THREAD_SLEEP_TIME = 60;
|
||||
|
||||
private Socket mServerSocket;
|
||||
private List<ClientConnection> mConnectionList = new List<ClientConnection>();
|
||||
private PacketProcessor mProcessor;
|
||||
|
||||
private Thread cleanupThread;
|
||||
private bool killCleanupThread = false;
|
||||
|
||||
private void SocketCleanup()
|
||||
{
|
||||
Program.Log.Info("Cleanup thread started; it will run every {0} seconds.", CLEANUP_THREAD_SLEEP_TIME);
|
||||
while (!killCleanupThread)
|
||||
{
|
||||
int count = 0;
|
||||
for (int i = mConnectionList.Count - 1; i >= 0; i--)
|
||||
{
|
||||
ClientConnection conn = mConnectionList[i];
|
||||
if (conn.socket.Poll(1, SelectMode.SelectRead) && conn.socket.Available == 0)
|
||||
{
|
||||
conn.socket.Disconnect(false);
|
||||
mConnectionList.Remove(conn);
|
||||
count++;
|
||||
}
|
||||
}
|
||||
if (count != 0)
|
||||
Program.Log.Info("{0} connections were cleaned up.", count);
|
||||
Thread.Sleep(CLEANUP_THREAD_SLEEP_TIME*1000);
|
||||
}
|
||||
}
|
||||
|
||||
#region Socket Handling
|
||||
public bool StartServer()
|
||||
{
|
||||
//cleanupThread = new Thread(new ThreadStart(socketCleanup));
|
||||
//cleanupThread.Name = "LobbyThread:Cleanup";
|
||||
//cleanupThread.Start();
|
||||
|
||||
IPEndPoint serverEndPoint = new System.Net.IPEndPoint(IPAddress.Parse(ConfigConstants.OPTIONS_BINDIP), int.Parse(ConfigConstants.OPTIONS_PORT));
|
||||
|
||||
try{
|
||||
mServerSocket = new System.Net.Sockets.Socket(serverEndPoint.Address.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new ApplicationException("Could not Create socket, check to make sure not duplicating port", e);
|
||||
}
|
||||
try
|
||||
{
|
||||
mServerSocket.Bind(serverEndPoint);
|
||||
mServerSocket.Listen(BACKLOG);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new ApplicationException("Error occured while binding socket, check inner exception", e);
|
||||
}
|
||||
try
|
||||
{
|
||||
mServerSocket.BeginAccept(new AsyncCallback(AcceptCallback), mServerSocket);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new ApplicationException("Error occured starting listeners, check inner exception", e);
|
||||
}
|
||||
|
||||
Console.ForegroundColor = ConsoleColor.White;
|
||||
Program.Log.Info("Lobby Server has started @ {0}:{1}", (mServerSocket.LocalEndPoint as IPEndPoint).Address, (mServerSocket.LocalEndPoint as IPEndPoint).Port);
|
||||
Console.ForegroundColor = ConsoleColor.Gray;
|
||||
|
||||
mProcessor = new PacketProcessor();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void AcceptCallback(IAsyncResult result)
|
||||
{
|
||||
ClientConnection conn = null;
|
||||
try
|
||||
{
|
||||
System.Net.Sockets.Socket s = (System.Net.Sockets.Socket)result.AsyncState;
|
||||
conn = new ClientConnection();
|
||||
conn.socket = s.EndAccept(result);
|
||||
conn.buffer = new byte[BUFFER_SIZE];
|
||||
lock (mConnectionList)
|
||||
{
|
||||
mConnectionList.Add(conn);
|
||||
}
|
||||
//Queue recieving of data from the connection
|
||||
conn.socket.BeginReceive(conn.buffer, 0, conn.buffer.Length, SocketFlags.None, new AsyncCallback(ReceiveCallback), conn);
|
||||
//Queue the accept of the next incomming connection
|
||||
mServerSocket.BeginAccept(new AsyncCallback(AcceptCallback), mServerSocket);
|
||||
Program.Log.Info("Connection {0}:{1} has connected.", (conn.socket.RemoteEndPoint as IPEndPoint).Address, (conn.socket.RemoteEndPoint as IPEndPoint).Port);
|
||||
}
|
||||
catch (SocketException)
|
||||
{
|
||||
if (conn.socket != null)
|
||||
{
|
||||
conn.socket.Close();
|
||||
lock (mConnectionList)
|
||||
{
|
||||
mConnectionList.Remove(conn);
|
||||
}
|
||||
}
|
||||
mServerSocket.BeginAccept(new AsyncCallback(AcceptCallback), mServerSocket);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
if (conn.socket != null)
|
||||
{
|
||||
conn.socket.Close();
|
||||
lock (mConnectionList)
|
||||
{
|
||||
mConnectionList.Remove(conn);
|
||||
}
|
||||
}
|
||||
mServerSocket.BeginAccept(new AsyncCallback(AcceptCallback), mServerSocket);
|
||||
}
|
||||
}
|
||||
|
||||
private void ReceiveCallback(IAsyncResult result)
|
||||
{
|
||||
ClientConnection conn = (ClientConnection)result.AsyncState;
|
||||
|
||||
try
|
||||
{
|
||||
int bytesRead = conn.socket.EndReceive(result);
|
||||
|
||||
bytesRead += conn.lastPartialSize;
|
||||
|
||||
if (bytesRead > 0)
|
||||
{
|
||||
int offset = 0;
|
||||
|
||||
//Build packets until can no longer or out of data
|
||||
while (true)
|
||||
{
|
||||
BasePacket basePacket = BuildPacket(ref offset, conn.buffer, bytesRead);
|
||||
|
||||
//If can't build packet, break, else process another
|
||||
if (basePacket == null)
|
||||
break;
|
||||
else
|
||||
mProcessor.ProcessPacket(conn, basePacket);
|
||||
}
|
||||
|
||||
//Not all bytes consumed, transfer leftover to beginning
|
||||
if (offset < bytesRead)
|
||||
Array.Copy(conn.buffer, offset, conn.buffer, 0, bytesRead - offset);
|
||||
|
||||
Array.Clear(conn.buffer, bytesRead - offset, conn.buffer.Length - (bytesRead - offset));
|
||||
|
||||
conn.lastPartialSize = bytesRead - offset;
|
||||
|
||||
//Build any queued subpackets into basepackets and send
|
||||
conn.FlushQueuedSendPackets();
|
||||
|
||||
if (offset < bytesRead)
|
||||
//Need offset since not all bytes consumed
|
||||
conn.socket.BeginReceive(conn.buffer, bytesRead - offset, conn.buffer.Length - (bytesRead - offset), SocketFlags.None, new AsyncCallback(ReceiveCallback), conn);
|
||||
else
|
||||
//All bytes consumed, full buffer available
|
||||
conn.socket.BeginReceive(conn.buffer, 0, conn.buffer.Length, SocketFlags.None, new AsyncCallback(ReceiveCallback), conn);
|
||||
}
|
||||
else
|
||||
{
|
||||
Program.Log.Info("{0} has disconnected.", conn.currentUserId == 0 ? conn.GetAddress() : "User " + conn.currentUserId);
|
||||
|
||||
lock (mConnectionList)
|
||||
{
|
||||
conn.Disconnect();
|
||||
mConnectionList.Remove(conn);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (SocketException)
|
||||
{
|
||||
if (conn.socket != null)
|
||||
{
|
||||
Program.Log.Info("{0} has disconnected.", conn.currentUserId == 0 ? conn.GetAddress() : "User " + conn.currentUserId);
|
||||
|
||||
lock (mConnectionList)
|
||||
{
|
||||
mConnectionList.Remove(conn);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Builds a packet from the incoming buffer + offset. If a packet can be built, it is returned else null.
|
||||
/// </summary>
|
||||
/// <param name="offset">Current offset in buffer.</param>
|
||||
/// <param name="buffer">Incoming buffer.</param>
|
||||
/// <returns>Returns either a BasePacket or null if not enough data.</returns>
|
||||
public BasePacket BuildPacket(ref int offset, byte[] buffer, int bytesRead)
|
||||
{
|
||||
BasePacket newPacket = null;
|
||||
|
||||
//Too small to even get length
|
||||
if (bytesRead <= offset)
|
||||
return null;
|
||||
|
||||
ushort packetSize = BitConverter.ToUInt16(buffer, offset);
|
||||
|
||||
//Too small to whole packet
|
||||
if (bytesRead < offset + packetSize)
|
||||
return null;
|
||||
|
||||
if (buffer.Length < offset + packetSize)
|
||||
return null;
|
||||
|
||||
try
|
||||
{
|
||||
newPacket = new BasePacket(buffer, ref offset);
|
||||
}
|
||||
catch (OverflowException)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return newPacket;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue