public TestSession(IMbbsHost host) : base("test") { SendToClientMethod = Send; OutputEnabled = true; CurrentModule = host.GetModule("MBBSEMU"); SessionType = EnumSessionType.Test; SessionState = EnumSessionState.EnteringModule; }
public TestSession(IMbbsHost host, ITextVariableService textVariableService) : base(host, "test", EnumSessionState.EnteringModule, textVariableService) { SendToClientMethod = Send; OutputEnabled = true; CurrentModule = host?.GetModule("MBBSEMU"); SessionType = EnumSessionType.Test; Username = "******"; Email = "*****@*****.**"; }
/// <summary> /// Scans incoming Rlogin bytes looking for the first three nulls, accumulating them /// in the rloginStrings collection. Once found, picks out the first non-empty string /// as the UserName and sets the proper Session states. /// </summary> /// <returns>Returns true when rlogin analysis has completed</returns> private bool ProcessIncomingByte(byte b) { if (b != 0) { memoryStream.WriteByte(b); return(false); } rloginStrings.Add(Encoding.ASCII.GetString(memoryStream.ToArray())); memoryStream.SetLength(0); if (rloginStrings.Count < 3 || rloginStrings.Count(s => !string.IsNullOrEmpty(s)) < 2) { return(false); } // we have 3 strings, pick out username and launch appropriately Username = rloginStrings.First(s => !string.IsNullOrEmpty(s)); rloginStrings.Clear(); _logger.Info($"Rlogin For User: {Username}"); if (!string.IsNullOrEmpty(ModuleIdentifier)) { CurrentModule = _host.GetModule(ModuleIdentifier); SessionState = EnumSessionState.RloginEnteringModule; } else { SessionState = EnumSessionState.LoginRoutines; } //Send 0 byte to ACK Send(new byte[] { 0x0 }); return(true); }
protected override (byte[], int) ProcessIncomingClientData(byte[] clientData, int bytesReceived) { if (SessionState != EnumSessionState.Negotiating) { return(clientData, bytesReceived); } var rloginStrings = Encoding.ASCII.GetString(clientData, 0, bytesReceived).Split('\0', StringSplitOptions.RemoveEmptyEntries); if (rloginStrings.Length == 0) { CloseSocket($"Invalid rlogin negotiation, didn't receive null terminated strings"); return(null, 0); } // all we care about is the username, ignore the other fields Username = rloginStrings[0]; _logger.Info($"Rlogin For User: {Username}"); if (!string.IsNullOrEmpty(ModuleIdentifier)) { CurrentModule = _host.GetModule(ModuleIdentifier); SessionState = EnumSessionState.EnteringModule; } else { SessionState = EnumSessionState.MainMenuDisplay; } //Send 0 byte to ACK Send(new byte[] { 0x0 }); // ignore any extraneous data, since the client should wait until we ack back with // the zero byte return(null, 0); }
/// <summary> /// Thread to handle receiving data from the client /// </summary> private void ReceiveWorker() { while (SessionState != EnumSessionState.LoggedOff && _rloginConnection.IsConnected()) { var bytesReceived = _rloginConnection.Receive(socketReceiveBuffer, SocketFlags.None, out var socketState); ValidateSocketState(socketState); if (bytesReceived == 0) { continue; } //Parse RLogin Information if (SessionState == EnumSessionState.Negotiating && bytesReceived > 2 && socketReceiveBuffer[0] == 0x0) { var usernameLength = 0; var startingOrdinal = 1; if (socketReceiveBuffer[1] == 0) { startingOrdinal++; } ReadOnlySpan <byte> bufferSpan = socketReceiveBuffer; //Find End of Username for (var i = startingOrdinal; i < bytesReceived; i++) { if (socketReceiveBuffer[i] != 0x0) { continue; } usernameLength = i - startingOrdinal; break; } //Send 0 byte to ACK Send(new byte[] { 0x0 }); Username = Encoding.ASCII.GetString(bufferSpan.Slice(startingOrdinal, usernameLength)); _logger.Info($"Rlogin For User: {Username}"); if (!string.IsNullOrEmpty(ModuleIdentifier)) { CurrentModule = _host.GetModule(ModuleIdentifier); SessionState = EnumSessionState.EnteringModule; } else { SessionState = EnumSessionState.MainMenuDisplay; } continue; } //Enqueue the incoming bytes for processing for (var i = 0; i < bytesReceived; i++) { DataFromClient.Add(socketReceiveBuffer[i]); } Thread.Sleep(1); } //Cleanup if the connection was dropped SessionState = EnumSessionState.LoggedOff; //Dispose the socket connection _rloginConnection.Dispose(); }
/// <summary> /// Scans incoming Rlogin bytes looking for the first three nulls, accumulating them /// in the rloginStrings collection. Once found, picks out the first non-empty string /// as the UserName and sets the proper Session states. /// </summary> /// <returns>Returns true when rlogin analysis has completed</returns> private bool ProcessIncomingByte(byte b) { if (b != 0) { memoryStream.WriteByte(b); return(false); } rloginStrings.Add(Encoding.ASCII.GetString(memoryStream.ToArray())); memoryStream.SetLength(0); if (rloginStrings.Count < 3 || rloginStrings.Count(s => !string.IsNullOrEmpty(s)) < 2) { return(false); } //Check to see if there is an available channel if (_channelDictionary.Count > _configuration.BBSChannels) { var channelFullMsg = $"\r\n|RED||B|{_configuration.BBSTitle} has reached the maximum number of users: {_configuration.BBSChannels} -- Please try again later.\r\n|RESET|" .EncodeToANSIArray(); Send(channelFullMsg); SessionState = EnumSessionState.LoggedOff; return(false); } //Check if user is already logged in if (_channelDictionary.Values.Any(s => string.Equals(s.Username, rloginStrings.First(s => !string.IsNullOrEmpty(s)), StringComparison.CurrentCultureIgnoreCase))) { _logger.Info($"RLogin -- User already logged in"); var duplicateLoginMsg = $"\r\n|RED||B|Duplicate user already logged in -- only 1 connection allowed per user.\r\n|RESET|" .EncodeToANSIArray(); Send(duplicateLoginMsg); SessionState = EnumSessionState.LoggedOff; return(false); } // we have 3 strings, pick out username and launch appropriately Username = rloginStrings.First(s => !string.IsNullOrEmpty(s)); rloginStrings.Clear(); _logger.Info($"Rlogin For User: {Username}"); if (!string.IsNullOrEmpty(ModuleIdentifier)) { CurrentModule = _host.GetModule(ModuleIdentifier); InputBuffer.WriteByte((byte)CurrentModule.MenuOptionKey[0]); SessionState = EnumSessionState.RloginEnteringModule; } else { SessionState = EnumSessionState.LoginRoutines; } //Send 0 byte to ACK Send(new byte[] { 0x0 }); return(true); }