/// <summary> /// Automatically Replies "Okay" to a client. /// </summary> /// <param name="clientSocket">The socket to which the "ok" message should be sent.</param> public static void ReplyOk(ReloadedSocket clientSocket) { // Send back empty message struct Message.MessageStruct messageStruct = new Message.MessageStruct(); messageStruct.MessageType = (ushort)MessageTypes.MessageType.Okay; messageStruct.Data = new byte[1]; clientSocket.SendData(messageStruct, false); }
/// <summary> /// Ran when the server receives some data from a client. /// </summary> /// <param name="asyncResult"></param> private void ReceiveDataCallback(IAsyncResult asyncResult) { try { // This socket is the same socket as in AcceptCallback ReloadedSocket clientSocket = (ReloadedSocket)asyncResult.AsyncState; // Gets the length of data that has been received. int bytesReceived = ClientSocket.Socket.EndReceive(asyncResult); clientSocket.AsyncReceivedBytes += bytesReceived; // Close if we are disconnected if 0 bytes received if (bytesReceived == 0) { clientSocket.CloseIfDisconnected(); return; } // If we have not received all of the bytes yet. if (clientSocket.AsyncReceivedBytes < clientSocket.AsyncBytesToReceive) { // The size of data to receive is the size of a message header. ClientSocket.Socket.BeginReceive(ClientSocket.ReceiveBuffer, clientSocket.AsyncReceivedBytes, clientSocket.AsyncBytesToReceive - clientSocket.AsyncReceivedBytes, SocketFlags.None, ReceiveDataCallback, clientSocket); return; } // Create the buffer for the received data. byte[] dataBuffer = new byte[clientSocket.AsyncBytesToReceive]; // Copy the received data. Array.Copy(ClientSocket.ReceiveBuffer, dataBuffer, clientSocket.AsyncReceivedBytes); // Send the buffer to the subscribing method! ProcessBytesMethods(ParseMessage(dataBuffer), clientSocket); // Re-set bytes received. clientSocket.AsyncReceivedBytes = 0; // Reset buffer size (old buffer will be Garbage Collected in due time). if (clientSocket.ReceiveBuffer.Length > clientSocket.DefaultBufferSize) { clientSocket.ReceiveBuffer = new byte[clientSocket.DefaultBufferSize]; } // Accept connections again! // Header Length! ClientSocket.Socket.BeginReceive(ClientSocket.ReceiveBuffer, 0, sizeof(UInt32), SocketFlags.None, ReceiveSizeCallback, clientSocket); } // Server was closed. catch (Exception ex) { Bindings.PrintWarning?.Invoke("[libReloaded] Exception thrown while receiving packet data, the host probably closed the connection | " + ex.Message); } }
/// <summary> /// Handles the individual assembly requests sent by the client. /// </summary> /// <param name="messageStruct">Message received from the client containing the assembly details</param> /// <param name="socket">The websocket socket used to send back the assembled bytes to the client.</param> private void ReceiveMessage(Message.MessageStruct messageStruct, ReloadedSocket socket) { switch ((MessageTypes)messageStruct.MessageType) { case MessageTypes.Assemble: Assemble(DeserializeX86Mnemonics(messageStruct.Data), socket); break; case MessageTypes.ReportAssembler: Report(socket); break; } }
/// <summary> /// Ran when the server receives some data from a client. /// </summary> /// <param name="asyncResult"></param> private void ReceiveSizeCallback(IAsyncResult asyncResult) { try { // This socket is the same socket as in AcceptCallback ReloadedSocket clientSocket = (ReloadedSocket)asyncResult.AsyncState; // Set expected data to be received to 4. (Message length) clientSocket.AsyncBytesToReceive = sizeof(UInt32); // Gets the length of data that has been received. // Increment Received Bytes int bytesReceived = ClientSocket.Socket.EndReceive(asyncResult); clientSocket.AsyncReceivedBytes += bytesReceived; // Close if we are disconnected if 0 bytes received if (bytesReceived == 0) { clientSocket.CloseIfDisconnected(); return; } // If we have not received all of the bytes yet. if (clientSocket.AsyncReceivedBytes < clientSocket.AsyncBytesToReceive) { // The size of data to receive is the size of a message header. ClientSocket.Socket.BeginReceive(ClientSocket.ReceiveBuffer, clientSocket.AsyncReceivedBytes, clientSocket.AsyncBytesToReceive - clientSocket.AsyncReceivedBytes, SocketFlags.None, ReceiveSizeCallback, clientSocket); return; } // Get the true length of the message to be received. clientSocket.AsyncBytesToReceive = BitConverter.ToInt32(ClientSocket.ReceiveBuffer, 0); clientSocket.AsyncReceivedBytes = 0; // Increase buffer size if necessary. if (clientSocket.AsyncBytesToReceive > clientSocket.ReceiveBuffer.Length) { clientSocket.ReceiveBuffer = new byte[clientSocket.AsyncBytesToReceive]; } // The size of data to receive is the size of a message header. ClientSocket.Socket.BeginReceive(ClientSocket.ReceiveBuffer, clientSocket.AsyncReceivedBytes, clientSocket.AsyncBytesToReceive - clientSocket.AsyncReceivedBytes, SocketFlags.None, ReceiveDataCallback, clientSocket); } // Server was closed. catch (Exception ex) { Bindings.PrintWarning?.Invoke("[libReloaded] Exception thrown while receiving packet size header, the host probably closed the connection | " + ex.Message); } }
/// <summary> /// Provides an easy to use implementation of a WebSocket Client, allowing /// communication with a websocket host such as the mod loader server or a generic host. /// To start the client, call SetupClient(). /// </summary> /// <param name="ipAddress">The IP Address to connect to. The IP Address can be specified by e.g. IPAddress.Parse("127.0.0.1");</param> /// <param name="port">The port over which the server will be locally hosted.</param> public Client(IPAddress ipAddress, int port) { // Initialize the ReloadedSocket Socket localSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); // Set up Reloaded ReloadedSocket ClientSocket = new ReloadedSocket(localSocket); // Set the IP Address Type IpAddressType = ipAddress; // Set the port. Port = port; }
/// <summary> /// Replies the name of the assembler back to the client. /// </summary> /// <param name="clientSocket">The socket to which the "ok" message should be sent.</param> private static void Report(ReloadedSocket clientSocket) { // Send back empty message struct. Message.MessageStruct messageStruct = new Message.MessageStruct { MessageType = (ushort)MessageTypes.ReportAssembler, // ABSOLUTELY DO NOT CHANGE THIS STRING // libReloaded EXPECTS THIS STRING AND WILL IGNORE SERVER UNTIL // THIS STRING IS RETURNED. THIS IDENTIFIES THE ASSEMBLER. Data = Encoding.ASCII.GetBytes(ReloadedCheckMessage) }; clientSocket.SendData(messageStruct, false); }
/// <summary> /// Constructor for the class allowing the user to establish a host. /// Initializes all members of the class and configures them to their defaults. /// To start the server, call StartServer(). /// </summary> /// <param name="ipAddress">The type of IP addresses to listen to. e.g. loopback, any, ipv4</param> /// <param name="port">The port over which the server will be locally hosted.</param> public Host(IPAddress ipAddress, int port) { // Initialize the ReloadedSocket Socket localSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); // Set up Reloaded ReloadedSocket ReloadedSocket = new ReloadedSocket(localSocket); // Instantiate the list of client sockets. Clients = new List <ReloadedSocket>(); // Set the socket by default to disable Nagle's Algorhithm. localSocket.NoDelay = true; // Bind the socket to an endpoint. localSocket.Bind(new IPEndPoint(ipAddress, port)); }
/// <summary> /// Handles the messages received from the individual client sockets consisting mainly of /// mods. Exposes various functionality features to mods. /// </summary> /// <param name="clientMessage">The message struct received from the individual mod loader server clients.</param> /// <param name="socket">The individual socket object to use for connection back with the mod loader clients.</param> private static void MessageHandler(Message.MessageStruct clientMessage, ReloadedSocket socket) { // Pass the relevant message. switch (clientMessage.MessageType) { // Regular Functions case (ushort)MessageType.Okay: ReplyOkay.ReplyOk(socket); break; // Text Functions case (ushort)MessageType.PrintText: Print(PrintMessageType.PrintText, clientMessage.Data, socket); break; case (ushort)MessageType.PrintInfo: Print(PrintMessageType.PrintInfo, clientMessage.Data, socket); break; case (ushort)MessageType.PrintWarning: Print(PrintMessageType.PrintWarning, clientMessage.Data, socket); break; case (ushort)MessageType.PrintError: Print(PrintMessageType.PrintError, clientMessage.Data, socket); break; } }
/// <summary> /// This will be ran when a new connection from a client is established. /// </summary> /// <param name="asyncResult"></param> public void AcceptCallback(IAsyncResult asyncResult) { // Temporarily stop accepting connections. // Set up a socket responsible for communication with the client. Socket clientSocket = ReloadedSocket.Socket.EndAccept(asyncResult); // Set up Reloaded Socket from Socket ReloadedSocket actualClientSocket = new ReloadedSocket(clientSocket); // Add this socket to the list of sockets. Clients.Add(actualClientSocket); // Start receiving data from the client asynchronously! // The size of data to receive is the size of a message header. actualClientSocket.Socket.BeginReceive(ReloadedSocket.ReceiveBuffer, 0, sizeof(UInt32), SocketFlags.None, ReceiveSizeCallback, actualClientSocket); // Start accepting new connections again! ReloadedSocket.Socket.BeginAccept(AcceptCallback, null); }
/// <summary> /// Assembles the received request and sends back information to the client. /// </summary> /// <param name="mnemonics">The assembly code to be assembled.</param> /// <param name="clientSocket">The socket used for communication with the client. which sent the request.</param> private static void Assemble(string[] mnemonics, ReloadedSocket clientSocket) { // Send back empty message struct Message.MessageStruct messageStruct = new Message.MessageStruct { // Client will likely ignore this anyway (but shouldn't). MessageType = ( ushort )MessageTypes.Assemble }; // Try Assembly // Assemble the bytes try { messageStruct.Data = FasmNet.Assemble(mnemonics); } // Failed to Assemble // Return nop on failure. catch { messageStruct.Data = new byte[1] { 0x90 }; } // Return back. clientSocket.SendData(messageStruct, false); }
/// <summary> /// Prints a message received from a client to the console/standard output. /// </summary> /// <param name="printMessageType">The message colour/type to print.</param> /// <param name="asciiMessage">The character array of ASCII bytes to parse back to string. (MessageStruct.Data)</param> /// <param name="socket">Sends a message back to signify that the message has successfully printed.</param> public static void Print(PrintMessageType printMessageType, byte[] asciiMessage, ReloadedSocket socket) { // Retrieve the message to print. string messageToPrint = Encoding.ASCII.GetString(asciiMessage); // Print to screen. switch (printMessageType) { case PrintMessageType.PrintText: ConsoleFunctions.PrintMessageWithTime(messageToPrint, ConsoleFunctions.PrintMessage); break; case PrintMessageType.PrintInfo: ConsoleFunctions.PrintMessageWithTime(messageToPrint, ConsoleFunctions.PrintInfoMessage); break; case PrintMessageType.PrintWarning: ConsoleFunctions.PrintMessageWithTime(messageToPrint, ConsoleFunctions.PrintWarningMessage); break; case PrintMessageType.PrintError: ConsoleFunctions.PrintMessageWithTime(messageToPrint, ConsoleFunctions.PrintErrorMessage); break; } }