/// Last Modified: 9/12/10 /// <summary> /// Disconnects the node depending on the hosting state. /// Hosting Enabled: Shuts down the server immediately (synchronously) and notifies the children that the server is no longer available. /// Hosting Disabled: Disconnects from the host immediately (synchronously). /// </summary> /// ----------------------------------------------------- /// PRECONDITIONS: /// 1) The child node must be connected to the host. /// ----------------------------------------------------- /// Parameters: /// ----------------------------------------------------- /// POSTCONDITIONS: /// 1) The host server will no longer be running and all children will be notified. /// 2) The child node will no longer be connected to the host. /// ----------------------------------------------------- /// Return Value: private void Disconnect() { //Clean-up all open chats. m_Chats.Clear(); //Disconnect the node. if (m_Node != null) { m_Node.Close(); m_Node = null; } //Update the interface. //Both of the host & child terminate their services immediately. SafelyToggleInterfaceState(false); //Red-Max is angry and notifies users they are disconnected. SafelySetIcon(DSChat.Properties.Resources.RedMax); //Control the connection flag via the disconnect & connect methods as they may be called out // of their original content. m_mutexIsConnected.WaitOne(MUTEX_TIMEOUT); IsConnected = ConnectionState.Disconnected; m_mutexIsConnected.ReleaseMutex(); //Clear all of the individuals. UpdateRegisteredUsersListBox(null, ListViewArgumentType.RemoveAllItems, 0); }
/// Last Modified: 10/24/10 /// <summary> /// An event that is triggered when an event occurs on a parent node. /// </summary> /// ----------------------------------------------------- /// PRECONDITIONS: NA -- No preconditions exist. /// ----------------------------------------------------- /// Parameters: /// <param name="nodeEvent"> /// The node event that has occcurred. /// </param> /// <param name="sEntityId"> /// The id or name of the entity that spawned the event. /// </param> /// <param name="sData"> /// Associated data with the event. /// </param> /// ----------------------------------------------------- /// POSTCONDITIONS: NA -- No postconditions exist. /// ----------------------------------------------------- /// Return Value: public void ParentNode_OnNodeEvent(RootNode.NodeEvent nodeEvent, string sEntityId, string sData) { switch (nodeEvent) { case RootNode.NodeEvent.REGISTERED: { UpdateRegisteredUsersListBox(sEntityId, ListViewArgumentType.AddItem, 0); SetStatusLog("User " + sEntityId + " has joined on " + sData); } break; case RootNode.NodeEvent.UNREGISTERED: { UpdateRegisteredUsersListBox(sEntityId, ListViewArgumentType.RemoveItem, 0); SetStatusLog("User " + sEntityId + " has left."); } break; case RootNode.NodeEvent.ALREADY_REGISTERED: { SetStatusLog("User " + sEntityId + " has already joined."); } break; case RootNode.NodeEvent.NETWORK_ERROR: { SetStatusLog(sData); } break; case RootNode.NodeEvent.SEVERE_NETWORK_ERRROR: { SetStatusLog(sData); //Need synchronization here. Disconnect(); } break; } //END OF switch (nodeEvent)... }
/// Last Modified: 10/24/10 /// <summary> /// Connect the node depending on the hosting state. /// Hosting Enabled: Begin running the server. /// Hosting Disabled: Connects to the host. /// </summary> /// ----------------------------------------------------- /// PRECONDITIONS: NA -- No preconditions exist. /// ----------------------------------------------------- /// Parameters: /// ----------------------------------------------------- /// POSTCONDITIONS: /// 1) The host server will be running. /// 2) The child node will attempt to connect to the server. /// ----------------------------------------------------- /// Return Value: private void Connect() { try { NodeSimpleSecurityModel nssm = null; if(!String.IsNullOrEmpty(txtPassphrase.Text)) nssm = new NodeSimpleSecurityModel(SimpleCryptography.EncryptionScheme.DES, txtPassphrase.Text); //The host never generates an asynchronous event and either fails // or succeeds immediately. SafelyToggleInterfaceState(true); //Determine if the node will be a host/parent. if (m_IsHosting) { //Obtain the port to listen on. int nPort = int.Parse(txtListeningPort.Text); //Create the parent node and start listening. ParentNode pn = new ParentNode(nPort, nssm); pn.NodeEventCallback = ParentNode_OnNodeEvent; pn.Start(); //Update the hosting status. lblStatus.Text = "Running..."; m_Node = pn; //Update the notification icon to reflect the node's name. cmiNodeType.Text = notificationIcon.Text = "DSChat [Parent]"; //Neutral Max means everything is okay. SafelySetIcon(DSChat.Properties.Resources.MAX); IsConnected = ConnectionState.Connected; } //This would be a child node. else { //Obtain the port to listen on for responses. int nListeningPort = int.Parse(txtListeningPort.Text); //Obtain the server address & port of the parent\host. int nHostPort = int.Parse(txtHostPort.Text); IPAddress ipAddy = NodeSocket.GetIP4HostAddresses(txtServer.Text); //Create the child node and register it with the parent with the // node name provided. ChildNode cn = new ChildNode(nListeningPort, nssm); cn.NodeName = txtName.Text; cn.NodeEventCallback = ChildNode_OnNodeEvent; cn.Start(ipAddy, nHostPort); m_Node = cn; //Update the notification icon to reflect the node's name. cmiNodeType.Text = notificationIcon.Text = "DSChat [" + txtName.Text + "]"; //The connection has not been made and synchornization is not required here // as the thread has not been spun up yet. IsConnected = ConnectionState.IsConnecting; SetStatusLabel("Connecting..."); m_connectionWaitingThread = new Thread(ThreadProc_WaitingForConnection); m_connectionWaitingThread.Start((object)this); } } catch (Exception ex) { SetStatusLog(ex.Message); Disconnect(); } }
/// Last Modified: 9/18/10 /// <summary> /// An event that is triggered when an event occurs on a child node. /// </summary> /// ----------------------------------------------------- /// PRECONDITIONS: NA -- No preconditions exist. /// ----------------------------------------------------- /// Parameters: /// <param name="nodeEvent"> /// The node event that has occcurred. /// </param> /// <param name="sEntityId"> /// The id or name of the entity that spawned the event. /// </param> /// <param name="sData"> /// Associated data with the event. /// </param> /// ----------------------------------------------------- /// POSTCONDITIONS: NA -- No postconditions exist. /// ----------------------------------------------------- /// Return Value: public void ChildNode_OnNodeEvent(RootNode.NodeEvent nodeEvent, string sEntityId, string sData) { switch (nodeEvent) { case RootNode.NodeEvent.REGISTRATION_SUCCESSFUL: { //If the string is empty, don't bother. if (!String.IsNullOrEmpty(sData)) { //Tokenize the string and update the registered users list box // with the current list of active users. string[] sUsersList = sData.Split(new char[] { '~' }); foreach (string s in sUsersList) UpdateRegisteredUsersListBox(s, ListViewArgumentType.AddItem, 0); } SafelyToggleInterfaceState(true); //Notify the form that a successful connection has been made. m_mutexIsConnected.WaitOne(MUTEX_TIMEOUT); IsConnected = ConnectionState.Connected; m_mutexIsConnected.ReleaseMutex(); SetStatusLabel("Connected"); SetStatusLog("Successfully registered with the host."); //Neutral Max means everything is okay. SafelySetIcon(DSChat.Properties.Resources.MAX); } break; case RootNode.NodeEvent.REGISTRATION_FAILURE: { Disconnect(); SetStatusLabel("Not connected"); SetStatusLog(sEntityId + " has already registered. Use a different name."); } break; case RootNode.NodeEvent.NODE_ADDED: { UpdateRegisteredUsersListBox(sData, ListViewArgumentType.AddItem, 0); SetStatusLog("User " + sData + " has joined."); } break; case RootNode.NodeEvent.NODE_REMOVED: { UpdateRegisteredUsersListBox(sData, ListViewArgumentType.RemoveItem, 0); SetStatusLog("User " + sData + " has left."); //Ignore any invalid ChatIntermediaries. ChatIntermediary ci = null; if (m_Chats.ContainsKey(sData)) { ci = m_Chats[sData]; } else { ci = new ChatIntermediary(); m_Chats.Add(sData, ci); } ci.WriteToChatLog("User " + sData + " has left."); } break; case RootNode.NodeEvent.INVALID_NODE: { SetStatusLog(sData + " is not a valid node."); } break; case RootNode.NodeEvent.PARENT_SHUTDOWN: { Disconnect(); SetStatusLabel("Not connected"); SetStatusLog("The server has shutdown."); } break; case RootNode.NodeEvent.NETWORK_ERROR: { SetStatusLog(sData); } break; case RootNode.NodeEvent.MESSAGE: { //Ignore any invalid ChatIntermediaries. ChatIntermediary ci = null; if (m_Chats.ContainsKey(sEntityId)) { ci = m_Chats[sEntityId]; } else { ci = new ChatIntermediary(); m_Chats.Add(sEntityId, ci); } //END OF if (m_Chats.ContainsKey(sEntityId))... ci.WriteToChatLog(sData); UpdateRegisteredUsersListBox(sEntityId, ListViewArgumentType.ModifyItem, (ci.IsVisible ? 0 : 1)); SafelySetIcon(DSChat.Properties.Resources.GreenMax); } break; case RootNode.NodeEvent.SEVERE_NETWORK_ERRROR: { SetStatusLog(sData); //Need synchronization here. Disconnect(); } break; } //END OF switch (nodeEvent)... }