diff --git a/tools/GSDumpGUI/Core/Program.cs b/tools/GSDumpGUI/Core/Program.cs index 3e50e15798..9e83a3f448 100644 --- a/tools/GSDumpGUI/Core/Program.cs +++ b/tools/GSDumpGUI/Core/Program.cs @@ -8,20 +8,36 @@ using System.Threading; using System.Diagnostics; using GSDumpGUI.Properties; using System.IO; +using TCPLibrary.MessageBased.Core; namespace GSDumpGUI { static class Program { static public GSDumpGUI frmMain; + static public TCPLibrary.MessageBased.Core.BaseMessageServer Server; + static public List Clients; + static public TCPLibrary.MessageBased.Core.BaseMessageClient Client; static private Boolean ChangeIcon; + static private GSDump dump; [STAThread] static void Main(String[] args) { if (args.Length == 4) { + try + { + Client = new TCPLibrary.MessageBased.Core.BaseMessageClient(); + Client.OnMessageReceived += new TCPLibrary.MessageBased.Core.BaseMessageClient.MessageReceivedHandler(Client_OnMessageReceived); + Client.Connect("localhost", 9999); + } + catch (Exception) + { + Client = null; + } + Thread thd = new Thread(new ThreadStart(delegate { while (true) @@ -55,21 +71,101 @@ namespace GSDumpGUI Directory.SetCurrentDirectory(Path.GetDirectoryName(AppDomain.CurrentDomain.BaseDirectory + "GSDumpGSDXConfigs\\" + Path.GetFileName(DLLPath) + "\\")); if (Operation == "GSReplay") { - GSDump dump = GSDump.LoadDump(DumpPath); + dump = GSDump.LoadDump(DumpPath); wrap.Run(dump, Renderer); ChangeIcon = true; } else wrap.GSConfig(); wrap.Unload(); + + if (Client != null) + Client.Disconnect(); } else { + Clients = new List(); + + Server = new TCPLibrary.MessageBased.Core.BaseMessageServer(); + Server.OnClientMessageReceived += new BaseMessageServer.MessageReceivedHandler(Server_OnClientMessageReceived); + Server.OnClientAfterConnect += new TCPLibrary.Core.Server.ConnectedHandler(Server_OnClientAfterConnect); + Server.OnClientAfterDisconnected += new TCPLibrary.Core.Server.DisconnectedHandler(Server_OnClientAfterDisconnected); + Server.Port = 9999; + Server.Enabled = true; + Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); frmMain = new GSDumpGUI(); Application.Run(frmMain); + + Server.Enabled = false; } } + + static void Server_OnClientAfterDisconnected(TCPLibrary.Core.Server server, TCPLibrary.Core.ClientS sender) + { + Clients.Remove((TCPLibrary.MessageBased.Core.BaseMessageClientS)sender); + RefreshList(); + } + + static void Server_OnClientMessageReceived(BaseMessageServer server, BaseMessageClientS sender, TCPMessage Mess) + { + switch (Mess.MessageType) + { + case MessageType.Connect: + break; + case MessageType.MaxUsers: + break; + case MessageType.SizeDump: + frmMain.Invoke(new Action(delegate(object e) + { + frmMain.txtDumpSize.Text = (((int)Mess.Parameters[0]) / 1024f / 1024f).ToString("F2"); + }), new object[] { null }); + break; + default: + break; + } + } + + static void Client_OnMessageReceived(TCPLibrary.Core.Client sender, TCPLibrary.MessageBased.Core.TCPMessage Mess) + { + switch (Mess.MessageType) + { + case TCPLibrary.MessageBased.Core.MessageType.Connect: + break; + case TCPLibrary.MessageBased.Core.MessageType.MaxUsers: + break; + case TCPLibrary.MessageBased.Core.MessageType.SizeDump: + TCPMessage msg = new TCPMessage(); + msg.MessageType = MessageType.SizeDump; + if (dump != null) + msg.Parameters.Add(dump.Size); + else + msg.Parameters.Add(0); + Client.Send(msg); + break; + default: + break; + } + } + + static void Server_OnClientAfterConnect(TCPLibrary.Core.Server server, TCPLibrary.Core.ClientS sender) + { + Clients.Add((TCPLibrary.MessageBased.Core.BaseMessageClientS)sender); + RefreshList(); + } + + private static void RefreshList() + { + frmMain.Invoke(new Action( delegate(object e) + { + frmMain.lstProcesses.Items.Clear(); + + foreach (var itm in Clients) + { + frmMain.lstProcesses.Items.Add(itm.IPAddress); + } + }), new object[] { null}); + } } } diff --git a/tools/GSDumpGUI/Forms/frmMain.Designer.cs b/tools/GSDumpGUI/Forms/frmMain.Designer.cs index 250241ae02..9f4045a6b2 100644 --- a/tools/GSDumpGUI/Forms/frmMain.Designer.cs +++ b/tools/GSDumpGUI/Forms/frmMain.Designer.cs @@ -53,6 +53,12 @@ this.rdaNone = new System.Windows.Forms.RadioButton(); this.lblInternalLog = new System.Windows.Forms.Label(); this.txtIntLog = new System.Windows.Forms.TextBox(); + this.lblDebugger = new System.Windows.Forms.Label(); + this.lstProcesses = new System.Windows.Forms.ListBox(); + this.lblChild = new System.Windows.Forms.Label(); + this.lblDumpSize = new System.Windows.Forms.Label(); + this.txtDumpSize = new System.Windows.Forms.Label(); + this.lblWIP = new System.Windows.Forms.Label(); ((System.ComponentModel.ISupportInitialize)(this.pctBox)).BeginInit(); this.SuspendLayout(); // @@ -303,11 +309,72 @@ this.txtIntLog.TabIndex = 24; this.txtIntLog.TabStop = false; // + // lblDebugger + // + this.lblDebugger.AutoSize = true; + this.lblDebugger.Location = new System.Drawing.Point(417, 470); + this.lblDebugger.Name = "lblDebugger"; + this.lblDebugger.Size = new System.Drawing.Size(54, 13); + this.lblDebugger.TabIndex = 26; + this.lblDebugger.Text = "Debugger"; + // + // lstProcesses + // + this.lstProcesses.FormattingEnabled = true; + this.lstProcesses.Location = new System.Drawing.Point(12, 502); + this.lstProcesses.Name = "lstProcesses"; + this.lstProcesses.Size = new System.Drawing.Size(248, 251); + this.lstProcesses.TabIndex = 27; + this.lstProcesses.SelectedIndexChanged += new System.EventHandler(this.lstProcesses_SelectedIndexChanged); + // + // lblChild + // + this.lblChild.AutoSize = true; + this.lblChild.Location = new System.Drawing.Point(9, 487); + this.lblChild.Name = "lblChild"; + this.lblChild.Size = new System.Drawing.Size(82, 13); + this.lblChild.TabIndex = 28; + this.lblChild.Text = "Child Processes"; + // + // lblDumpSize + // + this.lblDumpSize.AutoSize = true; + this.lblDumpSize.Location = new System.Drawing.Point(279, 487); + this.lblDumpSize.Name = "lblDumpSize"; + this.lblDumpSize.Size = new System.Drawing.Size(58, 13); + this.lblDumpSize.TabIndex = 29; + this.lblDumpSize.Text = "Dump Size"; + // + // txtDumpSize + // + this.txtDumpSize.AutoSize = true; + this.txtDumpSize.Location = new System.Drawing.Point(279, 502); + this.txtDumpSize.Name = "txtDumpSize"; + this.txtDumpSize.Size = new System.Drawing.Size(0, 13); + this.txtDumpSize.TabIndex = 30; + // + // lblWIP + // + this.lblWIP.AutoSize = true; + this.lblWIP.Font = new System.Drawing.Font("Times New Roman", 48F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.lblWIP.ForeColor = System.Drawing.Color.Red; + this.lblWIP.Location = new System.Drawing.Point(407, 589); + this.lblWIP.Name = "lblWIP"; + this.lblWIP.Size = new System.Drawing.Size(508, 73); + this.lblWIP.TabIndex = 31; + this.lblWIP.Text = "Work in Progress"; + // // GSDumpGUI // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.ClientSize = new System.Drawing.Size(988, 467); + this.ClientSize = new System.Drawing.Size(988, 766); + this.Controls.Add(this.lblWIP); + this.Controls.Add(this.txtDumpSize); + this.Controls.Add(this.lblDumpSize); + this.Controls.Add(this.lstProcesses); + this.Controls.Add(this.lblChild); + this.Controls.Add(this.lblDebugger); this.Controls.Add(this.lblInternalLog); this.Controls.Add(this.txtIntLog); this.Controls.Add(this.rdaNone); @@ -372,6 +439,12 @@ private System.Windows.Forms.RadioButton rdaNone; private System.Windows.Forms.Label lblInternalLog; private System.Windows.Forms.TextBox txtIntLog; + private System.Windows.Forms.Label lblDebugger; + private System.Windows.Forms.Label lblChild; + public System.Windows.Forms.ListBox lstProcesses; + private System.Windows.Forms.Label lblDumpSize; + public System.Windows.Forms.Label txtDumpSize; + private System.Windows.Forms.Label lblWIP; } } diff --git a/tools/GSDumpGUI/Forms/frmMain.cs b/tools/GSDumpGUI/Forms/frmMain.cs index fab8df8856..143d882bcb 100644 --- a/tools/GSDumpGUI/Forms/frmMain.cs +++ b/tools/GSDumpGUI/Forms/frmMain.cs @@ -10,6 +10,7 @@ using System.Runtime.InteropServices; using System.Threading; using System.Diagnostics; using System.Security; +using TCPLibrary.MessageBased.Core; namespace GSDumpGUI { @@ -351,5 +352,15 @@ namespace GSDumpGUI Properties.Settings.Default.DumpDir = txtDumpsDirectory.Text; Properties.Settings.Default.Save(); } + + private void lstProcesses_SelectedIndexChanged(object sender, EventArgs e) + { + if (lstProcesses.SelectedIndex != -1) + { + TCPMessage msg = new TCPMessage(); + msg.MessageType = MessageType.SizeDump; + Program.Clients.Find(a => a.IPAddress == lstProcesses.SelectedItem.ToString()).Send(msg); + } + } } } diff --git a/tools/GSDumpGUI/GSDumpGUI.csproj b/tools/GSDumpGUI/GSDumpGUI.csproj index b3f957acfd..0ccdfd4657 100644 --- a/tools/GSDumpGUI/GSDumpGUI.csproj +++ b/tools/GSDumpGUI/GSDumpGUI.csproj @@ -59,6 +59,15 @@ + + + + + + + + + frmMain.cs diff --git a/tools/GSDumpGUI/Library/GSDXWrapper.cs b/tools/GSDumpGUI/Library/GSDXWrapper.cs index 03a740a138..c82aac18d0 100644 --- a/tools/GSDumpGUI/Library/GSDXWrapper.cs +++ b/tools/GSDumpGUI/Library/GSDXWrapper.cs @@ -186,52 +186,7 @@ namespace GSDumpGUI } foreach (var itm in dump.Data) { - switch (itm.id) - { - case GSType.Transfer: - switch (itm.data[0]) - { - case 0: - fixed (byte* gifdata = itm.data) - { - byte[] data = new byte[4]; - data[0]=*(gifdata+1); - data[1]=*(gifdata+2); - data[2]=*(gifdata+3); - data[3]=*(gifdata+4); - Int32 size = BitConverter.ToInt32(data, 0); - GSgifTransfer1(new IntPtr(gifdata + 5), 16384 - size); - } - break; - case 1: - fixed (byte* gifdata = itm.data) - { - GSgifTransfer2(new IntPtr(gifdata + 1), (itm.data.Length - 1) / 16); - } - break; - case 2: - fixed (byte* gifdata = itm.data) - { - GSgifTransfer3(new IntPtr(gifdata + 1), (itm.data.Length - 1) / 16); - } - break; - } - break; - case GSType.VSync: - GSVSync(itm.data[0]); - break; - case GSType.ReadFIFO2: - fixed (byte* FIFO = itm.data) - { - GSreadFIFO2(new IntPtr(FIFO), itm.data.Length / 16); - } - break; - case GSType.Registers: - Marshal.Copy(itm.data, 0, new IntPtr(pointer), 8192); - break; - default: - break; - } + Step(itm, pointer); } } @@ -241,6 +196,57 @@ namespace GSDumpGUI } } + private unsafe void Step(GSData itm, byte* registers) + { + switch (itm.id) + { + case GSType.Transfer: + switch (itm.data[0]) + {/* + case 0: + byte[] data = new byte[16384]; + for (int i = 0; i < itm.data; i++) + { + + } + fixed (byte* gifdata = data) + { + GSgifTransfer1(new IntPtr(gifdata + 5), 16384 - size); + } + break;*/ + case 0: + case 1: + case 2: + fixed (byte* gifdata = itm.data) + { + GSgifTransfer2(new IntPtr(gifdata + 1), (itm.data.Length - 1) / 16); + } + break;/* + case 2: + fixed (byte* gifdata = itm.data) + { + GSgifTransfer3(new IntPtr(gifdata + 1), (itm.data.Length - 1) / 16); + } + break;*/ + } + break; + case GSType.VSync: + GSVSync(itm.data[0]); + break; + case GSType.ReadFIFO2: + fixed (byte* FIFO = itm.data) + { + GSreadFIFO2(new IntPtr(FIFO), itm.data.Length / 16); + } + break; + case GSType.Registers: + Marshal.Copy(itm.data, 0, new IntPtr(registers), 8192); + break; + default: + break; + } + } + public void Stop() { Running = false; diff --git a/tools/GSDumpGUI/Library/GSDump/GSDump.cs b/tools/GSDumpGUI/Library/GSDump/GSDump.cs index c1303141c3..0fc7b8b101 100644 --- a/tools/GSDumpGUI/Library/GSDump/GSDump.cs +++ b/tools/GSDumpGUI/Library/GSDump/GSDump.cs @@ -11,6 +11,22 @@ namespace GSDumpGUI public byte[] StateData; public byte[] Registers; // 8192 bytes + public int Size + { + get + { + int size = 0; + size = 4; + size += StateData.Length; + size += Registers.Length; + foreach (var itm in Data) + { + size += itm.data.Length; + } + return size; + } + } + public List Data; public GSDump() @@ -37,31 +53,12 @@ namespace GSDumpGUI { case GSType.Transfer: byte index = br.ReadByte(); - if (index == 0) - { - Int32 size = br.ReadInt32(); + Int32 size = br.ReadInt32(); - byte[] dat = new byte[16384]; - List Data = new List(); - Data.Add(index); - Data.AddRange(BitConverter.GetBytes(size)); - Data.AddRange(dat); - - int startaddr = 16389 - size; - - for (int i = 0; i < size; i++) - Data[startaddr + i] = br.ReadByte(); - data.data = Data.ToArray(); - } - else - { - Int32 size = br.ReadInt32(); - - List Data = new List(); - Data.Add(index); - Data.AddRange(br.ReadBytes(size)); - data.data = Data.ToArray(); - } + List Data = new List(); + Data.Add(index); + Data.AddRange(br.ReadBytes(size)); + data.data = Data.ToArray(); break; case GSType.VSync: data.data = br.ReadBytes(1); diff --git a/tools/GSDumpGUI/Library/TCPLibrary/Base/CancelArgs.cs b/tools/GSDumpGUI/Library/TCPLibrary/Base/CancelArgs.cs new file mode 100644 index 0000000000..981dd56a07 --- /dev/null +++ b/tools/GSDumpGUI/Library/TCPLibrary/Base/CancelArgs.cs @@ -0,0 +1,56 @@ +/* +* Copyright (c) 2009 Ferreri Alessio +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in +* all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +* THE SOFTWARE. +*/ + +using System; +using System.Collections.Generic; +using System.Text; + +namespace TCPLibrary.Core +{ + /// + /// Class for containing information regarding the acceptance of a determinate situation. + /// + public class CancelArgs + { + /// + /// Whether the operation should be cancelled. + /// + private Boolean _cancel; + /// + /// Get/set the flag that determines if the operation should be cancelled. + /// + public Boolean Cancel + { + get { return _cancel; } + set { _cancel = value; } + } + + /// + /// Base constructor of the class. + /// + /// Whether the operation should be cancelled. + public CancelArgs(Boolean cancel) + { + this._cancel = cancel; + } + } +} diff --git a/tools/GSDumpGUI/Library/TCPLibrary/Base/Client.cs b/tools/GSDumpGUI/Library/TCPLibrary/Base/Client.cs new file mode 100644 index 0000000000..07bd8f8cfe --- /dev/null +++ b/tools/GSDumpGUI/Library/TCPLibrary/Base/Client.cs @@ -0,0 +1,323 @@ +/* +* Copyright (c) 2009 Ferreri Alessio +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in +* all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +* THE SOFTWARE. +*/ + +using System; +using System.Net.Sockets; +using System.Net; +using System.Threading; +using System.IO; +using System.ComponentModel; +using System.Text; +using System.Diagnostics; + +namespace TCPLibrary.Core +{ + /// + /// Base TCP client class wrapped around TcpClient. + /// + public class Client + { + /// + /// Lock object to assure that certain operation over the socket class are executed + /// in an exclusive way. + /// + private Object _lock; + + /// + /// Wrapper around the Network Stream of the socket. (Read-Only) + /// + private BinaryReader tr; + /// + /// Wrapper around the Network Stream of the socket. (Write-Only) + /// + private BinaryWriter tw; + /// + /// Address to which the client is connected. + /// + private IPEndPoint _address; + + /// + /// Flag to permit thread exit from the external. + /// + protected Boolean _active; + /// + /// Socket maintaining the connection. + /// + protected TcpClient _socket; + + /// + /// Get/set the address to which the client is connected. + /// + public IPEndPoint Address + { + get { return _address; } + } + + /// + /// Get the state of the connection. + /// + public Boolean Connected + { + get { return _socket != null; } + } + + /// + /// Delegate for the event of receiving/sending a line of data from/to the server. + /// + /// Sender of the event. + /// Line of data received. + public delegate void DataCommunicationHandler(Client sender, Data Data); + /// + /// Occurs when a line of data is received from the server. + /// + public event DataCommunicationHandler OnDataReceived; + /// + /// Occurs before the client send a line of data to the server. + /// + public event DataCommunicationHandler OnBeforeDataSent; + /// + /// Occurs after the client send a line of data to the server. + /// + public event DataCommunicationHandler OnAfterDataSent; + + /// + /// Delegate for the event of connection/disconnection to the server. + /// + /// Sender of the event. + public delegate void ConnectionStateHandler(Client sender); + /// + /// Occurs when the client successfully connect the server. + /// + public event ConnectionStateHandler OnConnected; + /// + /// Occurs when the client is disconnected from the server. + /// + public event ConnectionStateHandler OnDisconnected; + + /// + /// Delegate for the event of connection failed for rejection by the server. + /// + /// Sender of the event. + /// Message of fail sent by the server. + public delegate void ConnectionFailedHandler(Client sender, byte[] Message); + /// + /// Occurs when the client failed to connect to the server because the server rejected the connection. + /// + public event ConnectionFailedHandler OnConnectFailed; + + /// + /// Base constructor of the class. + /// + public Client() + { + _lock = new object(); + _address = null; + } + + /// + /// Try to connect to the server specified. + /// + /// Address of the server to connect. + /// Port of the server to connect. + /// True if the connection is successfull, false otherwise. + /// + /// + public virtual Boolean Connect(String Indirizzo, Int32 Port) + { + if (!Connected) + { + IPHostEntry addr = Dns.GetHostEntry(Indirizzo); + IPAddress ip = null; + + foreach (var itm in addr.AddressList) + { + if (itm.AddressFamily == AddressFamily.InterNetwork) + { + ip = itm; + break; + } + } + + if (ip != null) + { + _address = new IPEndPoint(ip, Port); + _socket = new TcpClient(); + + try + { + _socket.Connect(_address); + } + catch (SocketException) + { + _socket = null; + _address = null; + throw; + } + + tr = new BinaryReader(_socket.GetStream()); + tw = new BinaryWriter(_socket.GetStream()); + + // Receive the confirmation of the status of the connection to the server. + // Is CONNECTEDTCPSERVER if the connection is successfull, all other cases are wrong. + + Int32 Length = Convert.ToInt32(tr.ReadInt32()); + byte[] arr = new byte[Length]; + tr.Read(arr, 0, Length); + ASCIIEncoding ae = new ASCIIEncoding(); + String Accept = ae.GetString(arr, 0, arr.Length); + + if (Accept == "CONNECTEDTCPSERVER") + { + _active = true; + + Thread thd = new Thread(new ThreadStart(MainThread)); + thd.IsBackground = true; + thd.Name = "Client connected to " + Indirizzo + ":" + Port.ToString(); + thd.Start(); + + if (OnConnected != null) + OnConnected(this); + + return true; + } + else + { + Stop(); + if (OnConnectFailed != null) + OnConnectFailed(this, arr); + + return false; + } + } + else + return false; + } + else + throw new ArgumentException("The client is already connected!"); + } + + /// + /// Disconnect a Client if connected. + /// + public virtual void Disconnect() + { + lock (_lock) + { + _active = false; + tr.Close(); + tw.Close(); + } + } + + /// + /// Disconnect a Client if connected. + /// + protected virtual void Stop() + { + if (_socket != null) + { + tr.Close(); + tw.Close(); + _socket.Close(); + + _socket = null; + _address = null; + + if (OnDisconnected != null) + OnDisconnected(this); + } + } + + /// + /// Thread function that actually run the socket work. + /// + private void MainThread() + { + while (_active) + { + byte[] arr = null; + + try + { + int length = Convert.ToInt32(tr.ReadInt32()); + arr = new byte[length]; + int index = 0; + + while (length > 0) + { + + int receivedBytes = tr.Read(arr, index, length); + length -= receivedBytes; + index += receivedBytes; + } + } + catch (Exception) { } + + lock (_lock) + { + if (_active) + { + Boolean Stato = _socket.Client.Poll(100, SelectMode.SelectRead); + if ((arr == null) && (Stato == true)) + break; + else + if (OnDataReceived != null) + OnDataReceived(this, new Data(arr)); + } + else + break; + } + } + Stop(); + } + + /// + /// Send a line of data to the server. + /// + /// Data to send to the server. + /// + public void Send(Data msg) + { + if (_active) + { + if (OnBeforeDataSent != null) + OnBeforeDataSent(this, msg); + try + { + tw.Write(msg.Message.Length); + tw.Write(msg.Message); + tw.Flush(); + + if (OnAfterDataSent != null) + OnAfterDataSent(this, msg); + } + catch (IOException) + { + // Pensare a cosa fare quà. Questo è il caso in cui il server ha chiuso forzatamente + // la connessione mentre il client mandava roba. + } + } + else + throw new ArgumentException("The link is closed. Unable to send data."); + } + } +} diff --git a/tools/GSDumpGUI/Library/TCPLibrary/Base/ClientS.cs b/tools/GSDumpGUI/Library/TCPLibrary/Base/ClientS.cs new file mode 100644 index 0000000000..7b7443898f --- /dev/null +++ b/tools/GSDumpGUI/Library/TCPLibrary/Base/ClientS.cs @@ -0,0 +1,226 @@ +/* +* Copyright (c) 2009 Ferreri Alessio +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in +* all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +* THE SOFTWARE. +*/ + +using System; +using System.Net.Sockets; +using System.Threading; +using System.IO; +using System.Diagnostics; + +namespace TCPLibrary.Core +{ + /// + /// Base class that manages the single connection between a client and the server. + /// + public class ClientS + { + /// + /// Lock object to assure that certain operation over the socket class are executed + /// in an exclusive way. + /// + private Object _lock; + + /// + /// Wrapper around the Network Stream of the socket. (Read-Only) + /// + private BinaryReader tr; + /// + /// Wrapper around the Network Stream of the socket. (Write-Only) + /// + private BinaryWriter tw; + /// + /// Current IP address of the client. + /// + private String _ipaddress; + + /// + /// Flag to permit thread exit from the external. + /// + protected Boolean _active; + /// + /// Link to the server to which this client is connected. + /// + protected Server _server; + /// + /// Actual socket of the client. + /// + protected TcpClient _client; + + /// + /// Get the state of the connection. + /// + public Boolean Connected + { + get { return _client != null; } + } + + /// + /// IP Address of the client. + /// + public String IPAddress + { + get { return _ipaddress; } + } + + /// + /// Base class constructor. + /// + /// Server to which this client is linked to. + /// Socket of the client. + protected internal ClientS(Server server, TcpClient client) + { + _lock = new object(); + + _active = true; + _server = server; + _client = client; + _ipaddress = _client.Client.RemoteEndPoint.ToString(); + + NetworkStream ns = _client.GetStream(); + tr = new BinaryReader(ns); + tw = new BinaryWriter(ns); + } + + /// + /// Start up the thread managing this Client-Server connection. + /// + protected internal virtual void Start() + { + Thread _thread = new Thread(new ThreadStart(MainThread)); + _thread.IsBackground = true; + _thread.Name = "Thread Client " + _ipaddress; + _thread.Start(); + } + + /// + /// Thread function that actually run the socket work. + /// + private void MainThread() + { + while (_active) + { + byte[] arr = null; + + try + { + int length = Convert.ToInt32(tr.ReadInt32()); + arr = new byte[length]; + int index = 0; + + while (length > 0) + { + + int receivedBytes = tr.Read(arr, index, length); + length -= receivedBytes; + index += receivedBytes; + } + } + catch (Exception ex) + { + Debug.WriteLine(ex.ToString()); + } + + lock (_lock) + { + if (_active) + { + Boolean Stato = _client.Client.Poll(100, SelectMode.SelectRead); + if ((arr == null) && (Stato == true)) + break; + else + _server.RaiseDataReceivedEvent(this, new Data(arr)); + } + else + break; + } + } + Stop(); + } + + /// + /// Send a line of data to the client. + /// + /// Data to send to the client. + /// + public void Send(Data Data) + { + if (_active) + { + _server.RaiseBeforeDataSentEvent(this, Data); + + try + { + tw.Write(Data.Message.Length); + tw.Write(Data.Message); + tw.Flush(); + + _server.RaiseAfterDataSentEvent(this, Data); + } + catch (Exception ex) + { + Debug.Write(ex.ToString()); + // Pensare a cosa fare quà. Questo è il caso in cui il client ha chiuso forzatamente + // la connessione mentre il server mandava roba. + } + } + else + throw new ArgumentException("The link is closed. Unable to send data."); + } + + /// + /// Close the link between Client e Server. + /// + public void Disconnect() + { + lock (_lock) + { + _active = false; + tr.Close(); + tw.Close(); + } + } + + /// + /// Close the link between Client e Server. + /// + protected internal void Stop() + { + if (_client != null) + { + _server.RaiseClientBeforeDisconnectedEvent(this); + + tr.Close(); + tw.Close(); + + _client.Close(); + _client = null; + + lock (_server.Clients) + { + _server.Clients.Remove(this); + } + + _server.RaiseClientAfterDisconnectedEvent(this); + } + } + } +} diff --git a/tools/GSDumpGUI/Library/TCPLibrary/Base/Data.cs b/tools/GSDumpGUI/Library/TCPLibrary/Base/Data.cs new file mode 100644 index 0000000000..d946e09fed --- /dev/null +++ b/tools/GSDumpGUI/Library/TCPLibrary/Base/Data.cs @@ -0,0 +1,57 @@ +/* +* Copyright (c) 2009 Ferreri Alessio +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in +* all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +* THE SOFTWARE. +*/ + +using System; +using System.Collections.Generic; +using System.Text; + +namespace TCPLibrary.Core +{ + /// + /// Structure for containing the data to be sent over a base client/server + /// + public class Data + { + /// + /// Data to be sent. + /// + private byte[] _message; + + /// + /// Get/set the data to be sent. + /// + public byte[] Message + { + get { return _message; } + set { _message = value; } + } + + /// + /// Base constructor of the class. + /// + /// Data to be sent. + public Data(byte[] msg) + { + this._message = msg; + } + } +} diff --git a/tools/GSDumpGUI/Library/TCPLibrary/Base/Server.cs b/tools/GSDumpGUI/Library/TCPLibrary/Base/Server.cs new file mode 100644 index 0000000000..4c7011639e --- /dev/null +++ b/tools/GSDumpGUI/Library/TCPLibrary/Base/Server.cs @@ -0,0 +1,365 @@ +/* +* Copyright (c) 2009 Ferreri Alessio +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in +* all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +* THE SOFTWARE. +*/ + +using System; +using System.Collections.Generic; +using System.Net; +using System.Net.Sockets; +using System.Threading; +using System.IO; +using System.ComponentModel; +using System.Text; + +namespace TCPLibrary.Core +{ + /// + /// Base TCP server class wrapped around TcpListener. + /// + public class Server + { + /// + /// Socket maintaining the connection. + /// + private TcpListener _socket; + /// + /// Port to which the server will listen. + /// + private Int32 _port; + /// + /// Whether the server is enabled or not. + /// + private Boolean _enabled; + /// + /// List of the clients connected to the server. + /// + private List _clients; + /// + /// Number of connection permitted in the backlog of the server. + /// + private Int32 _connectionbacklog; + + /// + /// Delegate for the event of the Enabled property change. + /// + /// Sender of the event. + public delegate void EnabledChangedHandler(Server sender); + /// + /// Occurs when the Enabled property is changed. + /// + public event EnabledChangedHandler OnEnabledChanged; + + /// + /// Delegate for the event of receiving a line of data from a client. + /// + /// Server raising the event. + /// Client involved in the communication. + /// Line of data received. + public delegate void DataCommunicationHandler(Server server, ClientS client, Data Data); + /// + /// Occurs when a client send a line of data to the server. + /// + public event DataCommunicationHandler OnClientDataReceived; + /// + /// Occurs before the server send a line of data to a client. + /// + public event DataCommunicationHandler OnClientBeforeDataSent; + /// + /// Occurs after the server send a line of data to a client. + /// + public event DataCommunicationHandler OnClientAfterDataSent; + + /// + /// Delegate for the event of a connection of a client. + /// + /// Server raising the event. + /// The new client connected. + public delegate void ConnectedHandler(Server server, ClientS sender); + /// + /// Occurs after a client is connected to the server. + /// + public event ConnectedHandler OnClientAfterConnect; + + /// + /// Delegate for the event of a connection of a client. + /// + /// Server raising the event. + /// The new client to be connected. + /// Specify if the client should be accepted into the server. + public delegate void BeforeConnectedHandler(Server server, ClientS client, CancelArgs args); + /// + /// Occurs before a client is allowed to connect to the server. + /// + public event BeforeConnectedHandler OnClientBeforeConnect; + + /// + /// Delegate for the event of disconnection of a client. + /// + /// Server raising the event. + /// The client disconnected. + public delegate void DisconnectedHandler(Server server, ClientS sender); + /// + /// Occurs right after a client disconnect from the server. + /// + public event DisconnectedHandler OnClientAfterDisconnected; + /// + /// Occurs before a client disconnect from the server. + /// + public event DisconnectedHandler OnClientBeforeDisconnected; + + /// + /// Get/set the port number to which the server will listen. Cannot be set while the server is active. + /// + /// + public Int32 Port + { + get { return _port; } + set + { + if (Enabled == false) + _port = value; + else + throw new ArgumentException("Impossibile eseguire l'operazione a server attivo"); + } + } + + /// + /// Get/set the enabled state of the server. Setting this to true will actually activate the server. + /// + /// + public Boolean Enabled + { + get { return _enabled; } + set + { + if (value == true) + { + if (_enabled == false) + ActivateServer(); + } + else + { + if (_enabled == true) + DeactivateServer(); + } + } + } + + /// + /// Get/set the number of connection permitted in the backlog of the server. + /// + /// + public Int32 ConnectionBackLog + { + get { return _connectionbacklog; } + set + { + if (Enabled == false) + _connectionbacklog = value; + else + throw new ArgumentException("Impossibile eseguire l'operazione a server attivo"); + } + } + + /// + /// Get the list of the clients connected to the server. + /// + public List Clients + { + get { return _clients; } + } + + /// + /// Deactivate the server. + /// + protected virtual void DeactivateServer() + { + _enabled = false; + _socket.Stop(); + _socket = null; + + lock (_clients) + { + for (int i = 0; i < _clients.Count; i++) + _clients[i].Disconnect(); + } + + if (OnEnabledChanged != null) + OnEnabledChanged(this); + } + + /// + /// Activate the server. + /// + protected virtual void ActivateServer() + { + _socket = new TcpListener(IPAddress.Any, Port); + _socket.Start(ConnectionBackLog); + Thread thd = new Thread(new ThreadStart(MainThread)); + thd.Name = "Server on port " + Port.ToString(); + thd.IsBackground = true; + thd.Start(); + _enabled = true; + if (OnEnabledChanged != null) + OnEnabledChanged(this); + } + + /// + /// Broadcast a line of data to all the clients connected to the server. + /// + /// Line of data to be sent. + /// + public void Broadcast(Data Data) + { + if (Enabled) + { + lock (_clients) + { + foreach (var itm in _clients) + if (itm.Connected) + itm.Send(Data); + } + } + else + throw new ArgumentException("Unable to execute this operation when the server is inactive."); + } + + /// + /// Base constructor of the class. + /// + public Server() + { + _clients = new List(); + _port = 0; + _connectionbacklog = 0; + _enabled = false; + } + + /// + /// Thread function that actually run the server socket work. + /// + private void MainThread() + { + try + { + while (Enabled == true) + { + TcpClient client = _socket.AcceptTcpClient(); + + CancelArgs args = new CancelArgs(false); + ClientS cl = CreateClient(client); + if (OnClientBeforeConnect != null) + OnClientBeforeConnect(this, cl, args); + + if (args.Cancel != true) + { + lock (_clients) + { + _clients.Add(cl); + } + + ASCIIEncoding ae = new ASCIIEncoding(); + byte[] arr = ae.GetBytes("CONNECTEDTCPSERVER"); + + cl.Send(new Data(arr)); + + if (OnClientAfterConnect != null) + OnClientAfterConnect(this, cl); + cl.Start(); + } + else + { + client.GetStream().Close(); + client.Close(); + } + } + } + catch (SocketException) + { + Enabled = false; + } + } + + /// + /// Overridable function that create the structure to memorize the client data. + /// + /// Socket of the client. + /// The structure in which memorize all the information of the client. + protected virtual ClientS CreateClient(TcpClient socket) + { + ClientS cl = new ClientS(this, socket); + return cl; + } + + /// + /// Raise the OnClientAfterDataSent event. + /// + /// Client that raised the event. + /// Line of data sent. + internal void RaiseAfterDataSentEvent(ClientS cl, Data data) + { + if (OnClientAfterDataSent != null) + OnClientAfterDataSent(this, cl, data); + } + + /// + /// Raise the OnClientBeforeDataSent event. + /// + /// Client that raised the event. + /// Line of data sent. + internal void RaiseBeforeDataSentEvent(ClientS cl, Data data) + { + if (OnClientBeforeDataSent != null) + OnClientBeforeDataSent(this, cl, data); + } + + /// + /// Raise the OnDataReceived event. + /// + /// Client that raised the event. + /// Line of data received. + internal void RaiseDataReceivedEvent(ClientS cl, Data data) + { + if (OnClientDataReceived != null) + OnClientDataReceived(this, cl, data); + } + + /// + /// Raise the OnClientAfterDisconnected event. + /// + /// Client that raised the event. + internal void RaiseClientAfterDisconnectedEvent(ClientS cl) + { + if (OnClientAfterDisconnected != null) + OnClientAfterDisconnected(this, cl); + } + + /// + /// Raise the OnClientBeforeDisconnected event. + /// + /// Client that raised the event. + internal void RaiseClientBeforeDisconnectedEvent(ClientS cl) + { + if (OnClientBeforeDisconnected != null) + OnClientBeforeDisconnected(this, cl); + } + } +} diff --git a/tools/GSDumpGUI/Library/TCPLibrary/Message/BaseMessageClient.cs b/tools/GSDumpGUI/Library/TCPLibrary/Message/BaseMessageClient.cs new file mode 100644 index 0000000000..098cf1632a --- /dev/null +++ b/tools/GSDumpGUI/Library/TCPLibrary/Message/BaseMessageClient.cs @@ -0,0 +1,137 @@ +/* +The MIT License + +Copyright (c) 2008 Ferreri Alessio + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +using TCPLibrary.MessageBased.Core; +using TCPLibrary.Core; +using System; + +namespace TCPLibrary.MessageBased.Core +{ + /// + /// TCP Client Class that work with Message structures. + /// + public class BaseMessageClient : Client + { + /// + /// Delegate for the event of receiving a message structure from the server. + /// + /// Sender of the event. + /// Message received. + public delegate void MessageReceivedHandler(Client sender, TCPMessage Mess); + /// + /// Occurs when the client receive a message structure from the server. + /// + public event MessageReceivedHandler OnMessageReceived; + /// + /// Delegate for the event of sending a message structure to the server. + /// + /// Sender of the event. + /// Message sent. + public delegate void MessageSentHandler(Client sender, TCPMessage Mess); + /// + /// Occurs before the client send a message structure to the server. + /// + public event MessageSentHandler OnBeforeMessageSent; + /// + /// Occurs after the client send a message structure to the server. + /// + public event MessageSentHandler OnAfterMessageSent; + /// + /// Delegate for the event of connection fail for max users number reached. + /// + /// Sender of the event. + public delegate void MaxUsersReached(Client sender); + /// + /// Occurs when the connection fail as the server reached the maximum number of clients allowed. + /// + public event MaxUsersReached OnMaxUsersConnectionFail; + + /// + /// Base constructor of the class. + /// + public BaseMessageClient() + { + OnDataReceived += new DataCommunicationHandler(BaseMessageClient_OnDataReceived); + OnAfterDataSent += new DataCommunicationHandler(BaseMessageClient_OnDataSent); + OnConnectFailed += new ConnectionFailedHandler(BaseMessageClient_OnConnectFailed); + } + + /// + /// When the connection is rejected by the server raise the correct event. + /// + /// Sender of the event. + /// Message of the server. + void BaseMessageClient_OnConnectFailed(Client sender, byte[] Message) + { + if (TCPLibrary.MessageBased.Core.TCPMessage.FromByteArray(Message).MessageType == MessageType.MaxUsers) + if (OnMaxUsersConnectionFail != null) + OnMaxUsersConnectionFail(sender); + } + + /// + /// Parse the raw data sent to the server and create Message structures. + /// + /// Sender of the event. + /// Line of data sent. + void BaseMessageClient_OnDataSent(Client sender, Data Data) + { + TCPMessage msg = TCPMessage.FromByteArray(Data.Message); + if (OnAfterMessageSent != null) + OnAfterMessageSent(sender, msg); + } + + /// + /// Parse the raw data received from the server and create Message structures. + /// + /// Sender of the event. + /// Line of data received. + void BaseMessageClient_OnDataReceived(Client sender, Data Data) + { + TCPMessage msg = null; + try + { + msg = TCPMessage.FromByteArray(Data.Message); + } + catch (Exception) + { + + } + if (msg != null) + if (OnMessageReceived != null) + OnMessageReceived(sender, msg); + } + + /// + /// Send a message structure to the server. + /// + /// Message structure to be send. + /// + public void Send(TCPMessage msg) + { + if (OnBeforeMessageSent != null) + OnBeforeMessageSent(this, msg); + base.Send(new Data(msg.ToByteArray())); + } + } +} diff --git a/tools/GSDumpGUI/Library/TCPLibrary/Message/BaseMessageClientS.cs b/tools/GSDumpGUI/Library/TCPLibrary/Message/BaseMessageClientS.cs new file mode 100644 index 0000000000..d35d90fad4 --- /dev/null +++ b/tools/GSDumpGUI/Library/TCPLibrary/Message/BaseMessageClientS.cs @@ -0,0 +1,59 @@ +/* +The MIT License + +Copyright (c) 2008 Ferreri Alessio + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +using System.Net.Sockets; +using TCPLibrary.Core; +using TCPLibrary.MessageBased.Core; + +namespace TCPLibrary.MessageBased.Core +{ + /// + /// Class that manages the single connection between a client and the server based + /// on Message structures. + /// + public class BaseMessageClientS : ClientS + { + /// + /// Base constructor of the class. + /// + /// Server to which this client is linked to. + /// Socket of the client. + protected internal BaseMessageClientS(Server server, TcpClient client) + : base(server, client) + { + + } + + /// + /// Send a Message structure to the client. + /// + /// Message to be sent. + /// + public void Send(TCPMessage msg) + { + ((BaseMessageServer)_server).RaiseBeforeMessageSentEvent(this, msg); + base.Send(new Data(msg.ToByteArray())); + } + } +} diff --git a/tools/GSDumpGUI/Library/TCPLibrary/Message/BaseMessageServer.cs b/tools/GSDumpGUI/Library/TCPLibrary/Message/BaseMessageServer.cs new file mode 100644 index 0000000000..02aac1fe2e --- /dev/null +++ b/tools/GSDumpGUI/Library/TCPLibrary/Message/BaseMessageServer.cs @@ -0,0 +1,186 @@ +/* +The MIT License + +Copyright (c) 2008 Ferreri Alessio + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +using System; +using System.Collections.Generic; +using System.Text; +using TCPLibrary.MessageBased.Core; +using System.Net.Sockets; +using System.Threading; +using TCPLibrary.Core; + +namespace TCPLibrary.MessageBased.Core +{ + /// + /// TCP Server Class that work with Message structures. + /// + public class BaseMessageServer : Server + { + /// + /// Limit of user allowed inside the server. + /// + protected Int32 _userlimit; + + /// + /// Delegate for the event of receiving a Message from a client. + /// + /// Server raising the event. + /// Client sending the message. + /// Message received. + public delegate void MessageReceivedHandler(BaseMessageServer server, BaseMessageClientS sender, TCPMessage Mess); + /// + /// Occurs when a Message is received by the server. + /// + public event MessageReceivedHandler OnClientMessageReceived; + /// + /// Delegate for the event of sending a Message to a client. + /// + /// Server raising the event. + /// Client that will receive the message. + /// Message to be sent. + public delegate void MessageSentHandler(BaseMessageServer server, BaseMessageClientS receiver, TCPMessage Mess); + /// + /// Occurs when the server send a Message to a client. + /// + public event MessageSentHandler OnClientBeforeMessageSent; + /// + /// Occurs when the server send a Message to a client. + /// + public event MessageSentHandler OnClientAfterMessageSent; + + /// + /// Get/set the limit of users allowed inside the server. + /// + public Int32 UserLimit + { + get { return _userlimit; } + set { _userlimit = value; } + } + + /// + /// Base constructor of the class. + /// + public BaseMessageServer() : base() + { + OnClientBeforeConnect += new BeforeConnectedHandler(BaseMessageServer_OnClientBeforeConnect); + OnClientDataReceived += new DataCommunicationHandler(BaseMessageServer_OnDataReceived); + OnClientAfterDataSent += new DataCommunicationHandler(BaseMessageServer_OnDataSent); + _userlimit = 0; + } + + /// + /// Kick the client if the server reached the maximum allowed number of clients. + /// + /// Server raising the event. + /// Client connecting to the server. + /// Specify if the client should be accepted into the server. + void BaseMessageServer_OnClientBeforeConnect(Server server, ClientS client, CancelArgs args) + { + if ((Clients.Count >= UserLimit) && (UserLimit != 0)) + { + TCPMessage msg = new TCPMessage(); + msg.MessageType = MessageType.MaxUsers; + ((BaseMessageClientS)client).Send(msg); + + args.Cancel = true; + } + } + + /// + /// Trasform the line of data sent into a Message structure and raise + /// the event linked. + /// + /// Server raising the event. + /// Client that will receive the Message. + /// Line of data sent. + void BaseMessageServer_OnDataSent(Server server, ClientS receiver, Data Data) + { + TCPMessage msg = null; + try + { + msg = TCPMessage.FromByteArray(Data.Message); + } + catch (Exception) + { + + } + if (msg != null) + if (OnClientAfterMessageSent != null) + OnClientAfterMessageSent(this, (BaseMessageClientS)receiver, msg); + } + + /// + /// Raise the OnClientBeforeMessageSent event. + /// + /// Client that raised the event. + /// Message to be sent. + internal void RaiseBeforeMessageSentEvent(ClientS cl, TCPMessage msg) + { + if (OnClientBeforeMessageSent != null) + OnClientBeforeMessageSent(this, (BaseMessageClientS)cl, msg); + } + + /// + /// Trasform the line of data received into a Message structure and raise + /// the event linked. + /// + /// Server raising the event. + /// Client sending the data. + /// Line of data received. + void BaseMessageServer_OnDataReceived(Server server, ClientS sender, Data Data) + { + TCPMessage msg = null; + try + { + msg = TCPMessage.FromByteArray(Data.Message); + } + catch (Exception) + { + + } + if (msg != null) + if (OnClientMessageReceived != null) + OnClientMessageReceived(this, (BaseMessageClientS)sender, msg); + } + + /// + /// Function that create the structure to memorize the client data. + /// + /// Socket of the client. + /// The structure in which memorize all the information of the client. + protected override ClientS CreateClient(TcpClient socket) + { + return new BaseMessageClientS(this, socket); + } + + /// + /// Send a message to all clients in broadcast. + /// + /// Message to be sent. + public void Broadcast(TCPMessage Data) + { + base.Broadcast(new Data(Data.ToByteArray())); + } + } +} diff --git a/tools/GSDumpGUI/Library/TCPLibrary/Message/TCPMessage.cs b/tools/GSDumpGUI/Library/TCPLibrary/Message/TCPMessage.cs new file mode 100644 index 0000000000..0dc5d4facc --- /dev/null +++ b/tools/GSDumpGUI/Library/TCPLibrary/Message/TCPMessage.cs @@ -0,0 +1,114 @@ +/* +The MIT License + +Copyright (c) 2008 Ferreri Alessio + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +using System; +using System.Collections.Generic; +using System.Xml.Serialization; +using System.IO; +using System.Runtime.Serialization.Formatters.Binary; + +namespace TCPLibrary.MessageBased.Core +{ + /// + /// Message structure that contains all the information of the message exchanged between + /// Message driven server/client. + /// + [Serializable] + public class TCPMessage + { + /// + /// Message Type. + /// + private MessageType _messageType; + /// + /// Messages parameters. + /// + private List _parameters; + + /// + /// Get/set the message type. + /// + public MessageType MessageType + { + get { return _messageType; } + set { _messageType = value; } + } + + /// + /// Get/set the message parameters. + /// + public List Parameters + { + get { return _parameters; } + } + + /// + /// Base constructor of the class. + /// + public TCPMessage() + { + _messageType = MessageType.Connect; + _parameters = new List(); + } + + /// + /// Parse a string and create a Message structure. + /// + /// Raw data. + /// Parsed message structure. + static public TCPMessage FromByteArray(byte[] data) + { + MemoryStream ms = new MemoryStream(); + BinaryWriter sw = new BinaryWriter(ms); + sw.Write(data, 0, data.Length); + sw.Flush(); + ms.Position = 0; + + BinaryFormatter formatter = new BinaryFormatter(); + TCPMessage msg = formatter.Deserialize(ms) as TCPMessage; + + return msg; + } + + /// + /// Trasform the structure into a String. + /// + /// The structure in a String format. + public byte[] ToByteArray() + { + MemoryStream ms = new MemoryStream(); + BinaryFormatter formatter = new BinaryFormatter(); + formatter.Serialize(ms, this); + ms.Position = 0; + return ms.ToArray(); + } + } + + public enum MessageType + { + Connect, + MaxUsers, + SizeDump + } +}