2016-11-13 00:26:03 +00:00
|
|
|
|
using Galactic_Colors_Control_Common;
|
|
|
|
|
using Galactic_Colors_Control_Common.Protocol;
|
2016-10-30 14:15:27 +00:00
|
|
|
|
using System;
|
2016-10-17 11:09:45 +00:00
|
|
|
|
using System.Collections.Generic;
|
2016-10-09 12:18:14 +00:00
|
|
|
|
using System.Linq;
|
2016-10-09 12:22:40 +00:00
|
|
|
|
using System.Net;
|
2016-10-09 15:58:14 +00:00
|
|
|
|
using System.Net.NetworkInformation;
|
2016-10-09 12:22:40 +00:00
|
|
|
|
using System.Net.Sockets;
|
|
|
|
|
using System.Threading;
|
2016-10-09 12:18:14 +00:00
|
|
|
|
|
2016-10-17 11:09:45 +00:00
|
|
|
|
namespace Galactic_Colors_Control
|
2016-10-09 12:18:14 +00:00
|
|
|
|
{
|
2016-11-13 00:26:03 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Client CrossPlatform Core
|
|
|
|
|
/// </summary>
|
2016-10-17 11:09:45 +00:00
|
|
|
|
public class Client
|
2016-10-09 12:18:14 +00:00
|
|
|
|
{
|
2016-10-17 11:09:45 +00:00
|
|
|
|
private Socket ClientSocket = new Socket
|
2016-10-09 12:22:40 +00:00
|
|
|
|
(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
|
|
|
|
|
|
2016-11-13 00:26:03 +00:00
|
|
|
|
public string IP = null; //Server IP
|
|
|
|
|
public int PORT = 0; //Server Port
|
2016-10-17 11:09:45 +00:00
|
|
|
|
|
2016-11-13 00:26:03 +00:00
|
|
|
|
public struct CoreConfig
|
|
|
|
|
{
|
|
|
|
|
public int resultsBuffer; //Max amount of waiting results
|
|
|
|
|
public int timeout; //Request timeout in ms
|
|
|
|
|
public int refresh; //Threads sleep in ms
|
|
|
|
|
|
|
|
|
|
public CoreConfig(int buffer, int time, int speed)
|
|
|
|
|
{
|
|
|
|
|
resultsBuffer = buffer;
|
|
|
|
|
timeout = time;
|
|
|
|
|
refresh = speed;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public CoreConfig config = new CoreConfig(20, 2000, 200); //Set default config
|
|
|
|
|
|
|
|
|
|
private int _errorCount = 0; //Leave if > 5
|
|
|
|
|
|
|
|
|
|
private bool _run = true; //Thread Stop
|
2016-10-17 11:09:45 +00:00
|
|
|
|
public bool isRunning { get { return _run; } }
|
2016-10-09 12:22:40 +00:00
|
|
|
|
|
2016-11-12 11:33:10 +00:00
|
|
|
|
private int RequestId = 0;
|
2016-11-13 00:26:03 +00:00
|
|
|
|
private List<ResultData> Results = new List<ResultData>();
|
|
|
|
|
private Thread RecieveThread; //Main Thread
|
|
|
|
|
public EventHandler OnEvent; //Execute on EventData reception (must be short or async)
|
2016-10-17 11:09:45 +00:00
|
|
|
|
|
2016-11-13 00:26:03 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Soft Server Reset
|
|
|
|
|
/// </summary>
|
2016-10-17 11:09:45 +00:00
|
|
|
|
public void ResetHost()
|
2016-10-09 12:22:40 +00:00
|
|
|
|
{
|
2016-10-17 11:09:45 +00:00
|
|
|
|
IP = null;
|
|
|
|
|
PORT = 0;
|
2016-10-09 12:22:40 +00:00
|
|
|
|
}
|
|
|
|
|
|
2016-11-13 00:26:03 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Test and Convert Hostname to Address
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="text">Hostname</param>
|
|
|
|
|
/// <returns>Address(IP:PORT) or Error(*'text')</returns>
|
2016-10-17 11:09:45 +00:00
|
|
|
|
public string ValidateHost(string text)
|
2016-10-09 12:22:40 +00:00
|
|
|
|
{
|
2016-11-13 00:26:03 +00:00
|
|
|
|
if (text == null) { text = ""; } //Prevent NullException
|
|
|
|
|
string[] parts = text.Split(new char[] { ':' }, 2, StringSplitOptions.RemoveEmptyEntries); //Split IP and Port
|
|
|
|
|
if (parts.Length == 0) //Default config (localhost)
|
2016-10-17 11:09:45 +00:00
|
|
|
|
{
|
|
|
|
|
parts = new string[] { "" };
|
|
|
|
|
PORT = 25001;
|
|
|
|
|
}
|
|
|
|
|
else
|
2016-10-09 12:22:40 +00:00
|
|
|
|
{
|
2016-10-17 11:09:45 +00:00
|
|
|
|
if (parts.Length > 1)
|
2016-10-09 12:22:40 +00:00
|
|
|
|
{
|
2016-11-13 00:26:03 +00:00
|
|
|
|
if (!int.TryParse(parts[1], out PORT)) { PORT = 0; } //Check Port
|
2016-10-17 11:09:45 +00:00
|
|
|
|
if (PORT < 0 || PORT > 65535) { PORT = 0; }
|
2016-10-09 12:22:40 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2016-10-17 11:09:45 +00:00
|
|
|
|
PORT = 25001;
|
2016-10-09 12:22:40 +00:00
|
|
|
|
}
|
2016-10-17 11:09:45 +00:00
|
|
|
|
}
|
|
|
|
|
if (PORT != 0)
|
|
|
|
|
{
|
|
|
|
|
try
|
2016-10-09 12:22:40 +00:00
|
|
|
|
{
|
2016-11-13 00:26:03 +00:00
|
|
|
|
IPHostEntry ipHostEntry = Dns.GetHostEntry(parts[0]);//Resolve Hostname
|
|
|
|
|
IPAddress host = ipHostEntry.AddressList.First(a => a.AddressFamily == AddressFamily.InterNetwork);//Get IPv4
|
2016-10-17 11:09:45 +00:00
|
|
|
|
IP = host.ToString();
|
|
|
|
|
return IP + ":" + PORT;
|
2016-10-09 12:22:40 +00:00
|
|
|
|
}
|
2016-10-17 11:09:45 +00:00
|
|
|
|
catch (Exception e)
|
2016-10-09 12:22:40 +00:00
|
|
|
|
{
|
2016-10-17 11:09:45 +00:00
|
|
|
|
PORT = 0;
|
2016-11-13 00:26:03 +00:00
|
|
|
|
return "*" + e.Message;
|
2016-10-09 12:22:40 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2016-10-17 11:09:45 +00:00
|
|
|
|
else
|
|
|
|
|
{
|
2016-11-13 00:26:03 +00:00
|
|
|
|
return "*Port Format";
|
2016-10-17 11:09:45 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2016-11-13 00:26:03 +00:00
|
|
|
|
/// Start Server connection
|
2016-10-17 11:09:45 +00:00
|
|
|
|
/// </summary>
|
2016-11-13 00:26:03 +00:00
|
|
|
|
/// <remarks>Setup IP and Port before</remarks>
|
|
|
|
|
/// <returns>connection success</returns>
|
2016-10-17 11:09:45 +00:00
|
|
|
|
public bool ConnectHost()
|
|
|
|
|
{
|
|
|
|
|
int attempts = 0;
|
2016-10-09 12:22:40 +00:00
|
|
|
|
|
|
|
|
|
while (!ClientSocket.Connected && attempts < 5)
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
attempts++;
|
|
|
|
|
ClientSocket.Connect(IP, PORT);
|
|
|
|
|
}
|
2016-11-13 00:26:03 +00:00
|
|
|
|
catch (SocketException) { }
|
2016-10-09 12:22:40 +00:00
|
|
|
|
}
|
2016-11-13 00:26:03 +00:00
|
|
|
|
if (attempts < 5) //Connection success
|
2016-10-09 12:22:40 +00:00
|
|
|
|
{
|
2016-10-17 11:09:45 +00:00
|
|
|
|
_run = true;
|
2016-11-13 00:26:03 +00:00
|
|
|
|
RecieveThread = new Thread(ReceiveLoop); //Starting Main Thread
|
2016-10-17 11:09:45 +00:00
|
|
|
|
RecieveThread.Start();
|
|
|
|
|
return true;
|
2016-10-09 12:22:40 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2016-10-17 11:09:45 +00:00
|
|
|
|
ResetSocket();
|
|
|
|
|
return false;
|
2016-10-09 12:22:40 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-13 00:26:03 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Hard Reset (unsafe)
|
|
|
|
|
/// </summary>
|
2016-10-17 11:09:45 +00:00
|
|
|
|
private void ResetSocket()
|
2016-10-09 12:22:40 +00:00
|
|
|
|
{
|
2016-10-17 11:09:45 +00:00
|
|
|
|
ClientSocket.Close();
|
|
|
|
|
ClientSocket = new Socket
|
|
|
|
|
(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
|
2016-10-09 12:22:40 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Close socket and exit program.
|
|
|
|
|
/// </summary>
|
2016-10-17 11:09:45 +00:00
|
|
|
|
public void ExitHost()
|
2016-10-09 12:22:40 +00:00
|
|
|
|
{
|
2016-11-16 21:27:28 +00:00
|
|
|
|
try { Send(new RequestData(GetRequestId(), new string[1] { "exit" })); } catch { }// Tell the server we are exiting
|
2016-11-13 00:26:03 +00:00
|
|
|
|
_run = false; //Stopping Thread
|
2016-11-12 11:33:10 +00:00
|
|
|
|
RecieveThread.Join(2000);
|
2016-10-09 12:22:40 +00:00
|
|
|
|
ClientSocket.Shutdown(SocketShutdown.Both);
|
|
|
|
|
ClientSocket.Close();
|
2016-10-17 11:09:45 +00:00
|
|
|
|
ResetHost();
|
2016-10-09 12:22:40 +00:00
|
|
|
|
}
|
|
|
|
|
|
2016-11-13 00:26:03 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Send RequestData to server
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="args">Request args</param>
|
|
|
|
|
/// <returns>ResultData or Timeout</returns>
|
|
|
|
|
public ResultData Request(string[] args)
|
2016-10-09 12:22:40 +00:00
|
|
|
|
{
|
2016-11-15 17:54:13 +00:00
|
|
|
|
switch(args[0])
|
|
|
|
|
{
|
|
|
|
|
case "exit":
|
|
|
|
|
ExitHost();
|
|
|
|
|
return new ResultData(GetRequestId(), ResultTypes.OK);
|
|
|
|
|
|
|
|
|
|
case "ping":
|
|
|
|
|
return PingHost();
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
return Execute(args);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Send row command to server
|
|
|
|
|
/// </summary>
|
|
|
|
|
private ResultData Execute(string[] args)
|
|
|
|
|
{
|
2016-11-13 00:26:03 +00:00
|
|
|
|
RequestData req = new RequestData(GetRequestId(), args);
|
|
|
|
|
if (!Send(req))
|
|
|
|
|
return new ResultData(req.id, ResultTypes.Error, Common.Strings("Send Exception"));
|
2016-10-20 21:09:48 +00:00
|
|
|
|
|
2016-11-13 00:26:03 +00:00
|
|
|
|
DateTime timeoutDate = DateTime.Now.AddMilliseconds(config.timeout); //Create timeout DataTime
|
|
|
|
|
while (timeoutDate > DateTime.Now)
|
|
|
|
|
{
|
|
|
|
|
foreach (ResultData res in Results.ToArray()) //Check all results
|
|
|
|
|
{
|
|
|
|
|
if (res.id == req.id)
|
2016-11-12 11:33:10 +00:00
|
|
|
|
{
|
2016-11-13 00:26:03 +00:00
|
|
|
|
Results.Remove(res);
|
|
|
|
|
return res;
|
2016-11-12 11:33:10 +00:00
|
|
|
|
}
|
2016-11-13 00:26:03 +00:00
|
|
|
|
}
|
|
|
|
|
Thread.Sleep(config.refresh);
|
2016-10-09 15:58:14 +00:00
|
|
|
|
}
|
2016-11-13 00:26:03 +00:00
|
|
|
|
return new ResultData(req.id, ResultTypes.Error, Common.Strings("Timeout"));
|
2016-10-09 15:58:14 +00:00
|
|
|
|
}
|
|
|
|
|
|
2016-11-13 00:26:03 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Ping Current Server IP
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <returns>Time in ms or 'Timeout'</returns>
|
2016-11-15 17:54:13 +00:00
|
|
|
|
private ResultData PingHost()
|
2016-10-09 15:58:14 +00:00
|
|
|
|
{
|
2016-11-13 00:26:03 +00:00
|
|
|
|
Ping ping = new Ping();
|
|
|
|
|
PingReply reply;
|
2016-10-09 15:58:14 +00:00
|
|
|
|
|
2016-11-13 00:26:03 +00:00
|
|
|
|
reply = ping.Send(IP);
|
|
|
|
|
if (reply.Status == IPStatus.Success)
|
2016-11-15 17:54:13 +00:00
|
|
|
|
return new ResultData(GetRequestId(), ResultTypes.OK, Common.SplitArgs(reply.RoundtripTime.ToString() + "ms"));
|
2016-10-09 12:22:40 +00:00
|
|
|
|
|
2016-11-15 17:54:13 +00:00
|
|
|
|
return new ResultData(GetRequestId(), ResultTypes.Error, Common.SplitArgs("Timeout"));
|
2016-10-09 12:22:40 +00:00
|
|
|
|
}
|
|
|
|
|
|
2016-11-13 00:26:03 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Send Data object to server
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <returns>Send success</returns>
|
|
|
|
|
private bool Send(Data packet)
|
2016-10-09 12:18:14 +00:00
|
|
|
|
{
|
2016-11-18 09:40:07 +00:00
|
|
|
|
try
|
|
|
|
|
{
|
2016-11-12 11:33:10 +00:00
|
|
|
|
ClientSocket.Send(packet.ToBytes());
|
2016-11-13 00:26:03 +00:00
|
|
|
|
return true;
|
2016-11-18 09:40:07 +00:00
|
|
|
|
}
|
2016-11-13 00:26:03 +00:00
|
|
|
|
catch //Can't contact server
|
2016-10-09 12:22:40 +00:00
|
|
|
|
{
|
|
|
|
|
_errorCount++;
|
|
|
|
|
}
|
2016-11-18 09:40:07 +00:00
|
|
|
|
return false;
|
2016-10-09 12:22:40 +00:00
|
|
|
|
}
|
|
|
|
|
|
2016-11-13 00:26:03 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Main Thread
|
|
|
|
|
/// </summary>
|
2016-10-17 11:09:45 +00:00
|
|
|
|
private void ReceiveLoop()
|
2016-10-09 12:22:40 +00:00
|
|
|
|
{
|
|
|
|
|
while (_run)
|
|
|
|
|
{
|
|
|
|
|
var buffer = new byte[2048];
|
|
|
|
|
int received = 0;
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
received = ClientSocket.Receive(buffer, SocketFlags.None);
|
|
|
|
|
}
|
|
|
|
|
catch
|
|
|
|
|
{
|
2016-11-13 00:26:03 +00:00
|
|
|
|
_errorCount++;
|
|
|
|
|
}
|
|
|
|
|
if (_errorCount >= 5)
|
|
|
|
|
{
|
|
|
|
|
_run = false;
|
2016-10-09 12:22:40 +00:00
|
|
|
|
}
|
|
|
|
|
if (received == 0) return;
|
|
|
|
|
_errorCount = 0;
|
|
|
|
|
var data = new byte[received];
|
|
|
|
|
Array.Copy(buffer, data, received);
|
2016-10-17 11:09:45 +00:00
|
|
|
|
|
2016-11-13 00:26:03 +00:00
|
|
|
|
Data packet = Data.FromBytes(ref data); //Create Data object from recieve bytes
|
2016-11-12 11:33:10 +00:00
|
|
|
|
if (packet != null)
|
|
|
|
|
{
|
|
|
|
|
switch (packet.GetType().Name)
|
|
|
|
|
{
|
|
|
|
|
case "EventData":
|
|
|
|
|
EventData eve = (EventData)packet;
|
2016-11-13 00:26:03 +00:00
|
|
|
|
if (OnEvent != null)
|
|
|
|
|
OnEvent.Invoke(this, new EventDataArgs(eve));
|
2016-11-12 11:33:10 +00:00
|
|
|
|
break;
|
2016-10-09 12:22:40 +00:00
|
|
|
|
|
2016-11-12 11:33:10 +00:00
|
|
|
|
case "ResultData":
|
|
|
|
|
ResultData res = (ResultData)packet;
|
2016-11-13 00:26:03 +00:00
|
|
|
|
ResultAdd(res);
|
2016-11-12 11:33:10 +00:00
|
|
|
|
break;
|
2016-11-06 09:59:05 +00:00
|
|
|
|
|
2016-11-13 00:26:03 +00:00
|
|
|
|
default: //Ignore others Packets
|
2016-11-12 11:33:10 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-11-13 00:26:03 +00:00
|
|
|
|
Thread.Sleep(config.refresh);
|
2016-10-09 12:22:40 +00:00
|
|
|
|
}
|
2016-11-13 00:26:03 +00:00
|
|
|
|
//TODOOutput.Add("/*exit*/");
|
2016-10-09 12:18:14 +00:00
|
|
|
|
}
|
2016-11-12 11:33:10 +00:00
|
|
|
|
|
|
|
|
|
public int GetRequestId(bool indent = true)
|
|
|
|
|
{
|
|
|
|
|
if (indent) { RequestId++; }
|
|
|
|
|
return RequestId;
|
|
|
|
|
}
|
2016-11-13 00:26:03 +00:00
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Add to Results
|
|
|
|
|
/// </summary>
|
|
|
|
|
public void ResultAdd(ResultData res)
|
|
|
|
|
{
|
|
|
|
|
while (Results.Count + 1 > config.resultsBuffer) { Results.RemoveAt(0); } //Removes firsts
|
|
|
|
|
Results.Add(res);
|
|
|
|
|
}
|
2016-10-09 12:18:14 +00:00
|
|
|
|
}
|
2016-10-09 12:22:40 +00:00
|
|
|
|
}
|