/// <summary> /// Deletes user using its context /// </summary> /// <param name="pContext"></param> /// <returns></returns> private Boolean DeleteUser(TaskInfo pContext) { Boolean Error = true; if (pContext != null && pContext.State != null && pContext.State.Clients != null) { lock (pContext.State.Clients) { // If client is registered if (pContext.State.Clients.ContainsValue(pContext) == true) { String Key = null; // Finds it foreach (var Entry in pContext.State.Clients) { if (Entry.Value == pContext) { Key = Entry.Key; this.CleanClient(Entry.Value); Error = false; } } // Removes it try { pContext.State.Clients.Remove(Key); SmartDebug.DWL("Deleted user " + Key); } catch (Exception catchedException) { SmartDebug.DWL(catchedException.Message); SmartDebug.DWL(catchedException.StackTrace); } } } } else Error = true; return Error; }
private void CleanClient(TaskInfo pClient) { if (pClient == null) return; Routines.WriteLocking(pClient.ChatControl, MessageCodes.LOGOUT_RESPONSE_OK); if (pClient.ChatControl != null) { pClient.ChatControl.Close(); pClient.ChatControl = null; } if (pClient.Clipboard != null) { pClient.Clipboard.Close(); pClient.Clipboard = null; } }
/// <summary> /// Routine executed by spawner thread: /// + accepts connection on port /// + submits connection/task to queue of working task threads /// </summary> private void SpawnerRoutine() { while (Interlocked.Equals(this._state.WorkEnd, false)) { try { // If port is open and clients count is less than MAX_CLIENTS while (this._state.MainPort != null ) { // Accepts a new client TcpClient Client = this._state.MainPort.AcceptTcpClient(); if (this._state.Clients.Count < MAX_CLIENTS) { SmartDebug.DWL("New connection"); // Creates thread context TaskInfo Context = new TaskInfo(Client, this._state); // Submits task to a pool of NCLIENTS threads ThreadPool.QueueUserWorkItem(new WaitCallback(TaskRoutine), Context); } else { SmartDebug.DWL("Closing connection"); Client.Close(); } } } catch (Exception catchedException) { SmartDebug.DWL(catchedException.Message); SmartDebug.DWL(catchedException.StackTrace); } } SmartDebug.DWL("Spawner thread exiting"); }
/// <summary> /// Dispatch received message: /// + login /// + message /// - status /// </summary> /// <param name="pCommand"></param> /// <param name="pContext"></param> /// <returns></returns> private Boolean Dispatch(String[] pCommand, TaskInfo pContext) { Boolean End = false; // Checks command length // TODO : split + check numero comandi if (pCommand.Length > 0) { // Login request if (pCommand[0].Equals(MessageCodes.LOGIN_REQUEST)) { String[] LoginInfo = pCommand[1].Split(":".ToCharArray()); if (LoginInfo.Length != MessageCodes.LOGIN_REQUEST_FIELDS - 1) { SmartDebug.DWL("Invalid login request"); End = true; Routines.WriteLocking(pContext.ChatControl, MessageCodes.LOGOUT_RESPONSE_ERROR); } else { SmartDebug.DWL("Received login request -> Nick:" + LoginInfo[1] + " Pass:"******" ClipboardPort:" + LoginInfo[2] + " VideoPort:" + LoginInfo[3]); End = Login(LoginInfo[0], LoginInfo[1], LoginInfo[2], LoginInfo[3], pContext); if (End == false) { this.Invoke(this._state.dUpdateHistory, pContext.Name + " connected"); foreach (var Client in this._state.Clients) { Routines.WriteLocking(Client.Value.ChatControl, MessageCodes.STATUS_USER_CONNECTED + ":" + pContext.Name); } } } } // Broadcast message from client else if (pCommand[0].Equals(MessageCodes.MSG_CLIENT2SERVER_BROADCAST) && pContext.Name != String.Empty) { SmartDebug.DWL("Received broadcast message"); End = NewBroadcastMessage(pCommand[1], pContext); } // Private message from client else if (pCommand[0].Equals(MessageCodes.MSG_CLIENT2SERVER_PRIVATE) && pContext.Name != String.Empty) { SmartDebug.DWL("Received private message"); End = NewPrivateMessage(pCommand[1], pContext); } // Logout request else if (pCommand[0].Equals(MessageCodes.LOGOUT_REQUEST) && pContext.Name != String.Empty) { SmartDebug.DWL("Received logout request"); // Calling stack has to terminate End = true; } // Add new functionalities here else { SmartDebug.DWL("Invalid request"); //End = true; //TODO: informare client } } else { SmartDebug.DWL("Fields count not positive"); End = true; } return End; }
private Boolean NewPrivateMessage(String pCommand, TaskInfo pContext) { Boolean Error = false; // TODO return Error; }
/// <summary> /// Server task thread handles a new message received from its client /// + sends message to server chat window /// + sends message to all clients /// </summary> /// <param name="pCommand"></param> /// <param name="pContext"></param> /// <returns></returns> private Boolean NewBroadcastMessage(String pMessage, TaskInfo pContext) { Boolean Error = false; this.Invoke(this._state.dUpdateHistory, (pContext.Name + ": " + pMessage)); foreach (var Client in pContext.State.Clients) { Routines.WriteLocking(Client.Value.ChatControl, MessageCodes.MSG_SERVER2CLIENT + ":" + pContext.Name + ":" + pMessage); } return Error; }
/// <summary> /// Logouts client using its context /// </summary> /// <param name="pContext"></param> private void Logout(TaskInfo pContext) { // If user has been deleted correctly if (DeleteUser(pContext) == false) { // Let server user know about it this.Invoke(this._state.dUpdateHistory, pContext.Name + " disconnected"); // Let other users know about it foreach (var Client in this._state.Clients) { Routines.WriteLocking(Client.Value.ChatControl, MessageCodes.STATUS_USER_DISCONNECTED + ":" + pContext.Name); } } else { SmartDebug.DWL("Unable to delete user"); } }
/// <summary> /// Handles Login request /// </summary> /// <param name="pLoginInfo"></param> /// <param name="pContext"></param> /// <returns></returns> private Boolean Login(String pPassword, String pName, String pClipboardPort, String pVideoPort, TaskInfo pContext) { Boolean Error = false; // If password is correct if (Routines.ValidPassword(pPassword) && pPassword == pContext.State.Password) { // If username can be inserted if (pName.Length > 0 && pName.Length <= Constants.MAX_NICKNAME_LENGTH && InsertUser(pName, pClipboardPort, pVideoPort, pContext) == false) { Error = Routines.WriteLocking(pContext.ChatControl, MessageCodes.LOGIN_RESPONSE_OK); pContext.Name = pName; SmartDebug.DWL("Correctly inserted user " + pName); // Read timeout is now set to infinite because client is now // registered on database pContext.ChatControl.ReceiveTimeout = 0; } // If username cannot be inserted else { Routines.WriteLocking(pContext.ChatControl, MessageCodes.LOGIN_RESPONSE_CHANGE_NAME); Error = true; SmartDebug.DWL("Invalid name, cannot establish clipboard connection or there are not free slots"); } } // If password is not correct else { Routines.WriteLocking(pContext.ChatControl, MessageCodes.LOGIN_RESPONSE_CHANGE_PASSWORD); Error = true; SmartDebug.DWL("Invalid password"); } return Error; }
/// <summary> /// Inserts user in database and creates clipboard connection /// </summary> /// <param name="pNickname"></param> /// <param name="pContext"></param> /// <returns></returns> private Boolean InsertUser(String pNickname, String pClipboardPort, String pVideoPort, TaskInfo pContext) { Boolean Error = false; if (pContext != null && pContext.State != null && pContext.State.Clients != null && pNickname.Equals("admin") == false) { TaskInfo Client = null; // Is client name already in database? pContext.State.Clients.TryGetValue(pNickname, out Client); // No clients registered with this name if (Client == null) { try { String lClientAddress = pContext.ChatControl.Client.RemoteEndPoint.ToString().Split(":".ToCharArray())[0]; pContext.Clipboard = new TcpClient(lClientAddress, UInt16.Parse(pClipboardPort)); pContext.Video = new TcpClient(lClientAddress, UInt16.Parse(pVideoPort)); lock (pContext.State.Clients) { // There is a free slot for it if (pContext.State.Clients.Count <= MAX_CLIENTS) pContext.State.Clients[pNickname] = pContext; // Client cannot be inserted: no free slots else { Error = true; pContext.Clipboard.Close(); } } } catch (Exception catchedException) { Error = true; SmartDebug.DWL(catchedException.Message); SmartDebug.DWL(catchedException.StackTrace); } } // Client name already present else Error = true; } else Error = true; return Error; }