public static void Main(string[] args) { log4net.Config.XmlConfigurator.Configure(); log.Info("=== Matrix Master Server Launching ==="); keyDb = new EncryptionKeyDB("EncryptionKeys"); manager = new NodeManager("CompiledNodes"); manager.Initialize(); manager.LogLoadedModules(); INodeController controller = manager.InstantiateNodeController(); if(controller == null) { log.Error("No INodeController found, the server will not do anything! Exiting..."); manager.Shutdown(); Console.ReadLine(); return; } hostInterface = new HostInterface(Settings.Default.Port, controller); pool = new NodePool(hostInterface); hostInterface.Startup(); nodeLibraryManager = new NodeLibraryManager("CompiledNodes"); nodeLibraryManager.Initialize(); host = new NodeHost("CompiledNodes"); log.Debug("Test download uri: "+host.GetDownloadUrl("MMOController.dll")); var controllerRmiType = manager.ControllerRMIType(); if(controllerRmiType == null) { log.Error("The node controller does not have an RMI interface! It will not function properly!"); } else pool.RegisterNode(new NodeInfo() { HostID = new byte[1], Id = 0, RMITypeName = controllerRmiType.FullName, RMIResolvedType = controllerRmiType }); var webServer = NodeWebServer.Create(Settings.Default.HTTPPort); Console.WriteLine("Press any key to quit..."); Console.ReadLine(); Console.WriteLine("Shutting down..."); webServer.Stop(); manager.Shutdown(); Console.WriteLine("Manager shutdown..."); hostInterface.Shutdown(); }
/// <summary> /// Create a new Host Interface server. /// </summary> /// <param name="port">Port to bind to.</param> public HostInterface(int port, INodeController controller) { log.Info("Host server interface launching..."); this.port = port; context = ZmqContext.Create(); server = context.CreateSocket(SocketType.ROUTER); server.TcpKeepalive = TcpKeepaliveBehaviour.Enable; this.controller = controller; var controllerPortal = new ControllerPortal(); controllerPortal.SetNodeID(0); controller.Initialize(controllerPortal); Instance = this; }
/// <summary> /// Process a message for response. /// </summary> /// <param name="inter">Interface.</param> /// <param name="message">Received message.</param> public void ProcessMessage(HostInterface inter, byte[] message) { lastInter = inter; if (status == HostStatus.Disconnected) return; //Reset heartbeat heartbeat.Stop (); heartbeat.Start (); if (status > HostStatus.NoEncryption && message.Length > 1) { //Decrypt message var decrypt = encryption.Decrypt (message.Skip (1).ToArray ()); byte[] finalMessage = new byte[1 + decrypt.Length]; decrypt.CopyTo (finalMessage, 1); finalMessage [0] = message [0]; message = finalMessage; } if (message [0] != (byte)MessageIdentifier.Heartbeat) log.Debug ("Received message: " + Enum.GetName (typeof(MessageIdentifier), message [0])); switch ((MessageIdentifier)message [0]) { case MessageIdentifier.Heartbeat: inter.SendTo (hostInfo, BuildMessage (MessageIdentifier.Heartbeat, null)); break; //Coming from client, this is confirming an identity. case MessageIdentifier.SetIdentity: if (status != HostStatus.NoIdentity) { log.Debug ("Host already has registered."); break; } log.Debug ("Identity confirmed, beginning encryption sequence."); status = HostStatus.NoEncryption; //Begin encryption exchange inter.SendTo (hostInfo, BuildMessage (MessageIdentifier.BeginEncryption, null)); break; //Coming from client, this is the encryption md5. case MessageIdentifier.BeginEncryption: if (status != HostStatus.NoEncryption) { log.Error ("Unexpected BeginEncryption from host."); break; } //Get the encryption key MD5. byte[] keymd5 = message.Skip (1).ToArray (); log.Debug ("Encryption key confirmation request: " + BitConverter.ToString (keymd5).Replace ("-", "").ToLower ()); AES encrypt = EncryptionKeyDB.Instance.ByHash (keymd5); if (encrypt == null) { log.Info ("Key not valid for host, rejecting and disconnecting."); inter.SendTo (hostInfo, BuildMessage (MessageIdentifier.InvalidKey, null)); inter.DisconnectHost (hostInfo); status = HostStatus.Disconnected; } else { log.Debug ("Host accepted, beginning node sync."); status = HostStatus.SyncNodes; inter.SendTo (hostInfo, BuildMessage (MessageIdentifier.ConfirmEncryption, null)); encryption = encrypt; } break; case MessageIdentifier.NodeSync: var inputIndex = Serializer.Deserialize<Dictionary<string, byte[]>> (new MemoryStream (message.Skip (1).ToArray ())); var syncJob = NodeLibraryManager.Instance.CreateSyncJob (inputIndex); if (syncJob == null) { inter.SendTo (hostInfo, BuildMessage (MessageIdentifier.BeginOperation, null)); status = HostStatus.LoadingNodes; } else { byte[] serializedJob; using (var ms = new MemoryStream ()) { Serializer.Serialize (ms, syncJob); serializedJob = ms.ToArray (); status = HostStatus.SyncNodes; } inter.SendTo (hostInfo, BuildMessage (MessageIdentifier.NodeSync, serializedJob)); } break; case MessageIdentifier.GetLibraryURL: //Retreive the library url for the path string dataString = Encoding.Unicode.GetString (message, 1, message.Length - 1); int reqId = int.Parse (dataString.Split (':') [0]); string library = dataString.Split (':') [1]; var libraryUrl = Encoding.UTF8.GetBytes (reqId + ":" + NodeHost.Instance.GetDownloadUrl (library)); inter.SendTo (hostInfo, BuildMessage (MessageIdentifier.GetLibraryURL, libraryUrl)); break; case MessageIdentifier.BeginOperation: if (status == HostStatus.LoadingNodes) { status = HostStatus.Operating; log.Info ("New host ready for operation."); try { Task.Factory.StartNew (() => inter.Controller.OnHostAdded (hostInfo)); } catch (Exception ex) { log.Error ("Error not caught by Controller, " + ex.ToString ()); } } break; case MessageIdentifier.NodeVerify: int verId = BitConverter.ToInt32 (message, 1); NodeInfo info; using (MemoryStream ms = new MemoryStream ()) { var inputBytes = message.Skip (1 + sizeof(int)).ToArray (); ms.Write (inputBytes, 0, inputBytes.Length); ms.Position = 0; info = Serializer.Deserialize<NodeInfo> (ms); } var response = NodePool.Instance.CheckNodeExists (info); var respBytes = new byte[sizeof(int) + sizeof(bool)]; BitConverter.GetBytes (verId).CopyTo (respBytes, 0); BitConverter.GetBytes (response).CopyTo (respBytes, sizeof(int)); inter.SendTo (hostInfo, BuildMessage (MessageIdentifier.NodeVerify, respBytes)); break; case MessageIdentifier.RMIResponse: if (status != HostStatus.Operating) return; var data = message.Skip (1).ToArray (); var rmi = data.Deserialize<NodeRMI> (); var destoNode = NodePool.Instance.NodeForId (rmi.SNodeID); if (destoNode == null) return; if (destoNode.Id == 0) NodePool.Instance.HandleRMIResponse (rmi); else { lastInter.RouteRMIResponse (rmi); } break; case MessageIdentifier.ReqNodeList: if (status != HostStatus.Operating) return; SendEntireNodeList (); break; case MessageIdentifier.RMIInvoke: if (status != HostStatus.Operating) return; NodeRMI trmi = message.Skip (1).ToArray ().Deserialize<NodeRMI> (); var tdestoNode = NodePool.Instance.NodeForId (trmi.NodeID); if (tdestoNode == null) { trmi.SerializeReturnValue (new NodeNotExistException ()); lastInter.SendTo (hostInfo, BuildMessage (MessageIdentifier.RMIResponse, trmi.Serialize ())); break; } lastInter.RouteRMIRequest (trmi, tdestoNode); break; } }