From 9015e2825776d28becccd723ea3487f02e00c7f8 Mon Sep 17 00:00:00 2001 From: Grant Birchmeier Date: Tue, 30 Jan 2024 21:44:57 -0600 Subject: [PATCH] cleanup/nullable Socket and Session classes --- AcceptanceTest/ATApplication.cs | 112 +++---- QuickFIXn/.editorconfig | 3 + QuickFIXn/AbstractInitiator.cs | 26 +- QuickFIXn/AcceptorSocketDescriptor.cs | 38 +-- QuickFIXn/ClientHandlerThread.cs | 92 ++---- QuickFIXn/HttpServer.cs | 348 +++++++++----------- QuickFIXn/IMessageStore.cs | 2 +- QuickFIXn/MessageBuilder.cs | 53 ++- QuickFIXn/Session.cs | 438 +++++++++++-------------- QuickFIXn/SessionFactory.cs | 99 +++--- QuickFIXn/SessionState.cs | 214 ++++++------ QuickFIXn/SocketReader.cs | 115 +++---- QuickFIXn/ThreadedSocketAcceptor.cs | 27 +- QuickFIXn/ThreadedSocketReactor.cs | 128 ++++---- QuickFIXn/Transport/SocketInitiator.cs | 16 +- RELEASE_NOTES.md | 7 + UnitTests/SessionStateTest.cs | 2 +- 17 files changed, 779 insertions(+), 941 deletions(-) diff --git a/AcceptanceTest/ATApplication.cs b/AcceptanceTest/ATApplication.cs index 3e547568c..6fff73dd2 100755 --- a/AcceptanceTest/ATApplication.cs +++ b/AcceptanceTest/ATApplication.cs @@ -13,88 +13,88 @@ public ATApplication() { } - public void OnMessage(QuickFix.FIX40.NewOrderSingle nos, SessionID sessionID) + public void OnMessage(QuickFix.FIX40.NewOrderSingle nos, SessionID sessionId) { - ProcessNOS(nos, sessionID); + ProcessNOS(nos, sessionId); } - public void OnMessage(QuickFix.FIX41.NewOrderSingle nos, SessionID sessionID) + public void OnMessage(QuickFix.FIX41.NewOrderSingle nos, SessionID sessionId) { - ProcessNOS(nos, sessionID); + ProcessNOS(nos, sessionId); } - public void OnMessage(QuickFix.FIX42.NewOrderSingle nos, SessionID sessionID) + public void OnMessage(QuickFix.FIX42.NewOrderSingle nos, SessionID sessionId) { - ProcessNOS(nos, sessionID); + ProcessNOS(nos, sessionId); } - public void OnMessage(QuickFix.FIX42.SecurityDefinition message, SessionID sessionID) + public void OnMessage(QuickFix.FIX42.SecurityDefinition message, SessionID sessionId) { - Echo(message, sessionID); + Echo(message, sessionId); } - public void OnMessage(QuickFix.FIX43.NewOrderSingle nos, SessionID sessionID) + public void OnMessage(QuickFix.FIX43.NewOrderSingle nos, SessionID sessionId) { - ProcessNOS(nos, sessionID); + ProcessNOS(nos, sessionId); } - public void OnMessage(QuickFix.FIX43.SecurityDefinition message, SessionID sessionID) + public void OnMessage(QuickFix.FIX43.SecurityDefinition message, SessionID sessionId) { - Echo(message, sessionID); + Echo(message, sessionId); } - public void OnMessage(QuickFix.FIX44.NewOrderSingle nos, SessionID sessionID) + public void OnMessage(QuickFix.FIX44.NewOrderSingle nos, SessionID sessionId) { - ProcessNOS(nos, sessionID); + ProcessNOS(nos, sessionId); } - public void OnMessage(QuickFix.FIX44.SecurityDefinition message, SessionID sessionID) + public void OnMessage(QuickFix.FIX44.SecurityDefinition message, SessionID sessionId) { - Echo(message, sessionID); + Echo(message, sessionId); } - public void OnMessage(QuickFix.FIX44.QuoteRequest message, SessionID sessionID) + public void OnMessage(QuickFix.FIX44.QuoteRequest message, SessionID sessionId) { - Echo(message, sessionID); + Echo(message, sessionId); } - public void OnMessage(QuickFix.FIX50.NewOrderSingle nos, SessionID sessionID) + public void OnMessage(QuickFix.FIX50.NewOrderSingle nos, SessionID sessionId) { - ProcessNOS(nos, sessionID); + ProcessNOS(nos, sessionId); } - public void OnMessage(QuickFix.FIX50.SecurityDefinition message, SessionID sessionID) + public void OnMessage(QuickFix.FIX50.SecurityDefinition message, SessionID sessionId) { - Echo(message, sessionID); + Echo(message, sessionId); } - public void OnMessage(QuickFix.FIX50SP1.NewOrderSingle nos, SessionID sessionID) + public void OnMessage(QuickFix.FIX50SP1.NewOrderSingle nos, SessionID sessionId) { - ProcessNOS(nos, sessionID); + ProcessNOS(nos, sessionId); } - public void OnMessage(QuickFix.FIX50SP1.SecurityDefinition message, SessionID sessionID) + public void OnMessage(QuickFix.FIX50SP1.SecurityDefinition message, SessionID sessionId) { - Echo(message, sessionID); + Echo(message, sessionId); } - public void OnMessage(QuickFix.FIX50SP2.NewOrderSingle nos, SessionID sessionID) + public void OnMessage(QuickFix.FIX50SP2.NewOrderSingle nos, SessionID sessionId) { - ProcessNOS(nos, sessionID); + ProcessNOS(nos, sessionId); } - public void OnMessage(QuickFix.FIX50SP2.SecurityDefinition message, SessionID sessionID) + public void OnMessage(QuickFix.FIX50SP2.SecurityDefinition message, SessionID sessionId) { - Echo(message, sessionID); + Echo(message, sessionId); } - protected void Echo(Message message, SessionID sessionID) + private static void Echo(Message message, SessionID sessionId) { Message echo = new(message); - Session.SendToTarget(echo, sessionID); + Session.SendToTarget(echo, sessionId); } - protected void ProcessNOS(Message message, SessionID sessionID) + private void ProcessNOS(Message message, SessionID sessionId) { Message echo = new(message); @@ -102,24 +102,24 @@ protected void ProcessNOS(Message message, SessionID sessionID) if (message.Header.IsSetField(QuickFix.Fields.Tags.PossResend)) possResend = message.Header.GetBoolean(QuickFix.Fields.Tags.PossResend); - KeyValuePair pair = new(message.GetString(QuickFix.Fields.Tags.ClOrdID), sessionID); + KeyValuePair pair = new(message.GetString(QuickFix.Fields.Tags.ClOrdID), sessionId); if (possResend && _clOrdIDs.Contains(pair)) return; _clOrdIDs.Add(pair); - Session.SendToTarget(echo, sessionID); + Session.SendToTarget(echo, sessionId); } - public void OnMessage(QuickFix.FIX41.News news, SessionID sessionID) { ProcessNews(news, sessionID); } - public void OnMessage(QuickFix.FIX42.News news, SessionID sessionID) { ProcessNews(news, sessionID); } - public void OnMessage(QuickFix.FIX43.News news, SessionID sessionID) { ProcessNews(news, sessionID); } - public void OnMessage(QuickFix.FIX44.News news, SessionID sessionID) { ProcessNews(news, sessionID); } - public void OnMessage(QuickFix.FIX50.News news, SessionID sessionID) { ProcessNews(news, sessionID); } - public void OnMessage(QuickFix.FIX50SP1.News news, SessionID sessionID) { ProcessNews(news, sessionID); } - public void OnMessage(QuickFix.FIX50SP2.News news, SessionID sessionID) { ProcessNews(news, sessionID); } + public void OnMessage(QuickFix.FIX41.News news, SessionID sessionId) { ProcessNews(news, sessionId); } + public void OnMessage(QuickFix.FIX42.News news, SessionID sessionId) { ProcessNews(news, sessionId); } + public void OnMessage(QuickFix.FIX43.News news, SessionID sessionId) { ProcessNews(news, sessionId); } + public void OnMessage(QuickFix.FIX44.News news, SessionID sessionId) { ProcessNews(news, sessionId); } + public void OnMessage(QuickFix.FIX50.News news, SessionID sessionId) { ProcessNews(news, sessionId); } + public void OnMessage(QuickFix.FIX50SP1.News news, SessionID sessionId) { ProcessNews(news, sessionId); } + public void OnMessage(QuickFix.FIX50SP2.News news, SessionID sessionId) { ProcessNews(news, sessionId); } - public void ProcessNews(Message msg, SessionID sessionID) + private void ProcessNews(Message msg, SessionID sessionId) { if (msg.IsSetField(QuickFix.Fields.Tags.Headline) && (msg.GetString(QuickFix.Fields.Tags.Headline) == "STOPME")) { @@ -127,41 +127,41 @@ public void ProcessNews(Message msg, SessionID sessionID) StopMeEvent(); } else - Echo(msg, sessionID); + Echo(msg, sessionId); } - public void OnMessage(QuickFix.FIX44.TradeCaptureReportRequest msg, SessionID sessionID) + public void OnMessage(QuickFix.FIX44.TradeCaptureReportRequest msg, SessionID sessionId) { // do nothing, just swallow it. } #region Application Methods - public void OnCreate(SessionID sessionID) + public void OnCreate(SessionID sessionId) { - Session session = Session.LookupSession(sessionID); + Session? session = Session.LookupSession(sessionId); // Hey QF/N users, don't do this in a real app. session?.Reset("AT Session Reset"); } - public void OnLogout(SessionID sessionID) + public void OnLogout(SessionID sessionId) { _clOrdIDs.Clear(); } - public void OnLogon(SessionID sessionID) + public void OnLogon(SessionID sessionId) { } - public void FromApp(Message message, SessionID sessionID) + public void FromApp(Message message, SessionID sessionId) { try { - string msgType = message.Header.GetString(QuickFix.Fields.Tags.MsgType); + //string msgType = message.Header.GetString(QuickFix.Fields.Tags.MsgType); // log_.OnEvent("Got message " + msgType); // System.Console.WriteLine("===got message " + msgType); - Crack(message, sessionID); + Crack(message, sessionId); } catch (UnsupportedMessageType) { @@ -169,15 +169,15 @@ public void FromApp(Message message, SessionID sessionID) } catch (System.Exception e) { - Session.LookupSession(sessionID).Log.OnEvent("Exception during FromApp: " + e.ToString() + "\n while processing msg (" + message.ToString() + ")"); + Session.LookupSession(sessionId)?.Log.OnEvent($"Exception during FromApp: {e}\n while processing msg ({message})"); } } - public void FromAdmin(Message message, SessionID sessionID) + public void FromAdmin(Message message, SessionID sessionId) { } - public void ToAdmin(Message message, SessionID sessionID) { } - public void ToApp(Message message, SessionID sessionID) { } + public void ToAdmin(Message message, SessionID sessionId) { } + public void ToApp(Message message, SessionID sessionId) { } #endregion } diff --git a/QuickFIXn/.editorconfig b/QuickFIXn/.editorconfig index 07b1ceeb6..f48de04a0 100644 --- a/QuickFIXn/.editorconfig +++ b/QuickFIXn/.editorconfig @@ -2,3 +2,6 @@ # CA1310: Specify StringComparison for correctness dotnet_diagnostic.CA1310.severity = error + +# Initializing field by default value is redundant +dotnet_diagnostic.CA1805.severity = none diff --git a/QuickFIXn/AbstractInitiator.cs b/QuickFIXn/AbstractInitiator.cs index aefcdd9f2..a02607ca3 100644 --- a/QuickFIXn/AbstractInitiator.cs +++ b/QuickFIXn/AbstractInitiator.cs @@ -25,7 +25,7 @@ public abstract class AbstractInitiator : IInitiator #endregion - public AbstractInitiator( + protected AbstractInitiator( IApplication app, IMessageStoreFactory storeFactory, SessionSettings settings, @@ -167,8 +167,8 @@ public void Stop(bool force) { foreach (SessionID sessionId in _connected) { - Session session = Session.LookupSession(sessionId); - if (session.IsEnabled) + Session? session = Session.LookupSession(sessionId); + if (session is not null && session.IsEnabled) { session.Logout(); } @@ -185,8 +185,11 @@ public void Stop(bool force) lock (_sync) { HashSet connectedSessionIDs = new HashSet(_connected); - foreach (SessionID sessionId in connectedSessionIDs) - SetDisconnected(Session.LookupSession(sessionId).SessionID); + foreach (SessionID sessionId in connectedSessionIDs) { + Session? session = Session.LookupSession(sessionId); + if (session is not null) + SetDisconnected(session.SessionID); + } } IsStopped = true; @@ -218,7 +221,7 @@ public bool IsLoggedOn { foreach (SessionID sessionId in _connected) { - Session session = Session.LookupSession(sessionId); + Session? session = Session.LookupSession(sessionId); return session is not null && session.IsLoggedOn; } } @@ -262,12 +265,13 @@ protected virtual void OnRemove(SessionID sessionId) /// Implemented to stop a running initiator. /// protected abstract void OnStop(); + /// /// Implemented to connect a session to its target. /// - /// + /// /// - protected abstract void DoConnect(SessionID sessionId, QuickFix.Dictionary settings); + protected abstract void DoConnect(Session session, QuickFix.Dictionary settings); #endregion @@ -280,13 +284,13 @@ protected void Connect() HashSet disconnectedSessions = new HashSet(_disconnected); foreach (SessionID sessionId in disconnectedSessions) { - Session session = Session.LookupSession(sessionId); - if (session.IsEnabled) + Session? session = Session.LookupSession(sessionId); + if (session is not null && session.IsEnabled) { if (session.IsNewSession) session.Reset("New session"); if (session.IsSessionTime) - DoConnect(sessionId, _settings.Get(sessionId)); + DoConnect(session, _settings.Get(sessionId)); } } } diff --git a/QuickFIXn/AcceptorSocketDescriptor.cs b/QuickFIXn/AcceptorSocketDescriptor.cs index c80385922..0fe5f0b56 100644 --- a/QuickFIXn/AcceptorSocketDescriptor.cs +++ b/QuickFIXn/AcceptorSocketDescriptor.cs @@ -1,5 +1,5 @@ +#nullable enable using System.Collections.Generic; -using System.Linq; using System.Net; namespace QuickFix @@ -8,59 +8,51 @@ internal class AcceptorSocketDescriptor { #region Properties - public ThreadedSocketReactor SocketReactor - { - get { return socketReactor_; } - } + public ThreadedSocketReactor SocketReactor { get; } - public IPEndPoint Address - { - get { return socketEndPoint_; } - } + public IPEndPoint Address { get; } #endregion #region Private Members - private ThreadedSocketReactor socketReactor_; - private IPEndPoint socketEndPoint_; - private Dictionary acceptedSessions_ = new Dictionary(); + private readonly Dictionary _acceptedSessions = new (); #endregion public AcceptorSocketDescriptor(IPEndPoint socketEndPoint, SocketSettings socketSettings, QuickFix.Dictionary sessionDict) { - socketEndPoint_ = socketEndPoint; - socketReactor_ = new ThreadedSocketReactor(socketEndPoint_, socketSettings, sessionDict, this); + Address = socketEndPoint; + SocketReactor = new ThreadedSocketReactor(Address, socketSettings, sessionDict, this); } public void AcceptSession(Session session) { - lock (acceptedSessions_) + lock (_acceptedSessions) { - acceptedSessions_[session.SessionID] = session; + _acceptedSessions[session.SessionID] = session; } } /// /// Remove a session from those tied to this socket. /// - /// ID of session to be removed + /// ID of session to be removed /// true if session removed, false if not found - public bool RemoveSession(SessionID sessionID) + public bool RemoveSession(SessionID sessionId) { - lock (acceptedSessions_) + lock (_acceptedSessions) { - return acceptedSessions_.Remove(sessionID); + return _acceptedSessions.Remove(sessionId); } } public Dictionary GetAcceptedSessions() { - lock (acceptedSessions_) + lock (_acceptedSessions) { - return new Dictionary(acceptedSessions_); + return new Dictionary(_acceptedSessions); } } } -} \ No newline at end of file +} diff --git a/QuickFIXn/ClientHandlerThread.cs b/QuickFIXn/ClientHandlerThread.cs index 8dbfe0a30..a5cbb074f 100755 --- a/QuickFIXn/ClientHandlerThread.cs +++ b/QuickFIXn/ClientHandlerThread.cs @@ -1,18 +1,16 @@ -using System.Net.Sockets; +#nullable enable +using System.Net.Sockets; using System.Threading; using System; namespace QuickFix { - // TODO v2.0 - consider changing to internal - - /// /// Created by a ThreadedSocketReactor to handle a client connection. /// Each ClientHandlerThread has a SocketReader which reads /// from the socket. /// - public class ClientHandlerThread : IResponder, IDisposable + internal class ClientHandlerThread : IResponder, IDisposable { internal class ExitedEventArgs : EventArgs { @@ -20,35 +18,22 @@ internal class ExitedEventArgs : EventArgs public ExitedEventArgs(ClientHandlerThread clientHandlerThread) { - this.ClientHandlerThread = clientHandlerThread; + ClientHandlerThread = clientHandlerThread; } } internal delegate void ExitedEventHandler(object sender, ClientHandlerThread.ExitedEventArgs e); - internal event ExitedEventHandler Exited; + internal event ExitedEventHandler? Exited; public long Id { get; private set; } - private Thread thread_ = null; - private volatile bool isShutdownRequested_ = false; - private SocketReader socketReader_; - private FileLog log_; - - /// - /// Creates a ClientHandlerThread - /// - /// - /// - /// - /// - public ClientHandlerThread(TcpClient tcpClient, long clientId, QuickFix.Dictionary settingsDict, SocketSettings socketSettings) - : this(tcpClient, clientId, settingsDict, socketSettings, null) - { - - } + private Thread? _thread = null; + private volatile bool _isShutdownRequested = false; + private readonly SocketReader _socketReader; + private readonly FileLog _log; internal ClientHandlerThread(TcpClient tcpClient, long clientId, QuickFix.Dictionary settingsDict, - SocketSettings socketSettings, AcceptorSocketDescriptor acceptorDescriptor) + SocketSettings socketSettings, AcceptorSocketDescriptor? acceptorDescriptor) { string debugLogFilePath = "log"; if (settingsDict.Has(SessionSettings.DEBUG_FILE_LOG_PATH)) @@ -57,62 +42,60 @@ internal ClientHandlerThread(TcpClient tcpClient, long clientId, QuickFix.Dictio debugLogFilePath = settingsDict.GetString(SessionSettings.FILE_LOG_PATH); // FIXME - do something more flexible than hardcoding a filelog - log_ = new FileLog(debugLogFilePath, new SessionID( - "ClientHandlerThread", clientId.ToString(), "Debug-" + Guid.NewGuid().ToString())); + _log = new FileLog(debugLogFilePath, new SessionID( + "ClientHandlerThread", clientId.ToString(), "Debug-" + Guid.NewGuid())); - this.Id = clientId; - socketReader_ = new SocketReader(tcpClient, socketSettings, this, acceptorDescriptor); + Id = clientId; + _socketReader = new SocketReader(tcpClient, socketSettings, this, acceptorDescriptor); } public void Start() { - thread_ = new Thread(new ThreadStart(Run)); - thread_.Start(); + _thread = new Thread(Run); + _thread.Start(); } public void Shutdown(string reason) { Log("shutdown requested: " + reason); - isShutdownRequested_ = true; + _isShutdownRequested = true; } public void Join() { - if(null == thread_) + if (_thread is null) return; - if(thread_.IsAlive) - thread_.Join(5000); - thread_ = null; + if (_thread.IsAlive) + _thread.Join(5000); + _thread = null; } - public void Run() + private void Run() { - while (!isShutdownRequested_) + while (!_isShutdownRequested) { try { - socketReader_.Read(); + _socketReader.Read(); } - catch (System.Exception e) + catch (Exception e) { Shutdown(e.Message); } } - this.Log("shutdown"); + Log("shutdown"); OnExited(); } - protected void OnExited() - { - if (Exited != null) - Exited(this, new ExitedEventArgs(this)); + private void OnExited() { + Exited?.Invoke(this, new ExitedEventArgs(this)); } /// FIXME do real logging public void Log(string s) { - log_.OnEvent(s); + _log.OnEvent(s); } /// @@ -121,14 +104,14 @@ public void Log(string s) /// internal ILog GetLog() { - return log_; + return _log; } #region Responder Members public bool Send(string data) { - return socketReader_.Send(data) > 0; + return _socketReader.Send(data) > 0; } public void Disconnect() @@ -151,17 +134,8 @@ protected virtual void Dispose(bool disposing) if (_disposed) return; if (disposing) { - if (socketReader_ != null) - { - socketReader_.Dispose(); - socketReader_ = null; - } - - if (log_ != null) - { - log_.Dispose(); - log_ = null; - } + _socketReader.Dispose(); + _log.Dispose(); } _disposed = true; } diff --git a/QuickFIXn/HttpServer.cs b/QuickFIXn/HttpServer.cs index 66161d173..2de690779 100644 --- a/QuickFIXn/HttpServer.cs +++ b/QuickFIXn/HttpServer.cs @@ -1,4 +1,5 @@ -using System; +#nullable enable +using System; using System.IO; using System.Net; using System.Text; @@ -11,11 +12,9 @@ namespace Acceptor public class HttpServer : IDisposable { private readonly HttpListener _httpListener; - private Thread _connectionThread; - private Boolean _running, _disposed; + private readonly Thread _connectionThread; + private bool _running, _disposed; private readonly SessionSettings _sessionSettings; - private StringBuilder _sbHtmlHeader; - public HttpServer(string prefix, SessionSettings settings) { @@ -29,6 +28,7 @@ public HttpServer(string prefix, SessionSettings settings) _httpListener = new HttpListener(); _httpListener.Prefixes.Add(prefix); _sessionSettings = settings; + _connectionThread = new Thread(ConnectionThreadStart); } public void Start() @@ -38,7 +38,6 @@ public void Start() _httpListener.Start(); _running = true; // Use a thread to listen to the Http requests - _connectionThread = new Thread(ConnectionThreadStart); _connectionThread.Start(); } } @@ -62,41 +61,22 @@ private void ConnectionThreadStart() HttpListenerContext context = _httpListener.GetContext(); HttpListenerRequest request = context.Request; HttpListenerResponse response = context.Response; - string responseString; - _sbHtmlHeader = new StringBuilder(@"
QuickFIX Engine Web Interface

QuickFIX Engine Web Interface

"); - _sbHtmlHeader.AppendFormat(@"
[HOME] [RELOAD]

", request.Url.OriginalString); + StringBuilder pageBuilder = new StringBuilder("
QuickFIX Engine Web Interface

QuickFIX Engine Web Interface

"); + pageBuilder.Append($"
[HOME] [RELOAD]

"); - switch (request.Url.AbsolutePath) + var responseString = request.Url?.AbsolutePath switch { - case "/": - responseString = ProcessRoot(request); - break; - case "/session": - responseString = SessionDetails(request); - break; - case "/resetSession": - responseString = ResetSession(request); - break; - case "/resetSessions": - responseString = ResetSessions(request); - break; - case "/refreshSession": - responseString = RefreshSession(request); - break; - case "/refreshSessions": - responseString = RefreshSessions(request); - break; - case "/enableSessions": - responseString = EnableSessions(request); - break; - case "/disableSessions": - responseString = DisableSessions(request); - break; - default: - responseString = ProcessRoot(request); - break; - } + "/" => ProcessRoot(request, pageBuilder), + "/session" => SessionDetails(request, pageBuilder), + "/resetSession" => ResetSession(request, pageBuilder), + "/resetSessions" => ResetSessions(request, pageBuilder), + "/refreshSession" => RefreshSession(request, pageBuilder), + "/refreshSessions" => RefreshSessions(request, pageBuilder), + "/enableSessions" => EnableSessions(request, pageBuilder), + "/disableSessions" => DisableSessions(request, pageBuilder), + _ => ProcessRoot(request, pageBuilder) + }; byte[] buffer = Encoding.UTF8.GetBytes(responseString); response.ContentLength64 = buffer.Length; @@ -111,83 +91,77 @@ private void ConnectionThreadStart() } } - private string DisableSessions(HttpListenerRequest request) + private string DisableSessions(HttpListenerRequest request, StringBuilder pageBuilder) { bool confirm = false; - StringBuilder sbHtmlPageBody = _sbHtmlHeader; - if (request.QueryString["confirm"] != null) + if (request.QueryString["confirm"] is not null) { if (Convert.ToInt16(request.QueryString["confirm"]) != 0) { confirm = true; foreach (SessionID session in _sessionSettings.GetSessions()) { - Session sessionDetails = Session.LookupSession(session); - sessionDetails.Logout(); + Session.LookupSession(session)?.Logout(); } } } if (confirm) { - sbHtmlPageBody = new StringBuilder(); - sbHtmlPageBody.AppendFormat(@"
QuickFIX Engine Web Interface

QuickFIX Engine Web Interface

", "/"); - sbHtmlPageBody.AppendFormat("

Sessions have been disabled

", "/"); + pageBuilder = new StringBuilder(); + pageBuilder.Append("
QuickFIX Engine Web Interface

QuickFIX Engine Web Interface

"); + pageBuilder.Append("

Sessions have been disabled

"); } else { - sbHtmlPageBody.Append("

Are you sure you want to disable all sessions ?

"); - sbHtmlPageBody.AppendFormat("
[YES, disable sessions] [NO, do not disable sessions]
", request.Url.OriginalString); + pageBuilder.Append("

Are you sure you want to disable all sessions ?

"); + pageBuilder.Append($"
[YES, disable sessions] [NO, do not disable sessions]
"); } - return sbHtmlPageBody.ToString(); + return pageBuilder.ToString(); } - private string EnableSessions(HttpListenerRequest request) + private string EnableSessions(HttpListenerRequest request, StringBuilder pageBuilder) { bool confirm = false; - string urlOriginalString = request.Url.OriginalString; - StringBuilder sbHtmlPageBody = _sbHtmlHeader; - - if (request.QueryString["confirm"] != null) + + if (request.QueryString["confirm"] is not null) { if (Convert.ToInt16(request.QueryString["confirm"]) != 0) { confirm = true; foreach (SessionID session in _sessionSettings.GetSessions()) { - Session sessionDetails = Session.LookupSession(session); - sessionDetails.Logon(); + Session.LookupSession(session)?.SetLogonState(); } } } if (confirm) { - sbHtmlPageBody = new StringBuilder(); - sbHtmlPageBody.AppendFormat(@"
QuickFIX Engine Web Interface

QuickFIX Engine Web Interface

", "/"); - sbHtmlPageBody.AppendFormat("

Sessions have been enabled

", "/"); + pageBuilder = new StringBuilder(); + pageBuilder.Append("
QuickFIX Engine Web Interface

QuickFIX Engine Web Interface

"); + pageBuilder.Append("

Sessions have been enabled

"); } else { - sbHtmlPageBody.Append("

Are you sure you want to enable all sessions ?

"); - sbHtmlPageBody.AppendFormat("
[YES, enable sessions] [NO, do not enable sessions]
", urlOriginalString); + pageBuilder.Append("

Are you sure you want to enable all sessions ?

"); + pageBuilder.Append($"
[YES, enable sessions] [NO, do not enable sessions]
"); } - return sbHtmlPageBody.ToString(); + return pageBuilder.ToString(); } - private string RefreshSession(HttpListenerRequest request) + private string RefreshSession(HttpListenerRequest request, StringBuilder pageBuilder) { SessionID sessionId = new SessionID(request.QueryString["beginstring"], request.QueryString["sendercompid"], request.QueryString["targetcompid"]); - Session sessionDetails = Session.LookupSession(sessionId); + Session? sessionDetails = Session.LookupSession(sessionId); if (sessionDetails == null) throw new Exception("Session not found"); - StringBuilder sbHtmlPageBody = _sbHtmlHeader; bool confirm = false; - string urlOriginalString = request.Url.OriginalString; + string urlOriginalString = request.Url!.OriginalString; string url = "/session?" + GetParameterList(urlOriginalString); - if (request.QueryString["confirm"] != null) + if (request.QueryString["confirm"] is not null) { if (Convert.ToInt16(request.QueryString["confirm"]) != 0) { @@ -199,98 +173,91 @@ private string RefreshSession(HttpListenerRequest request) if (confirm) { - sbHtmlPageBody = new StringBuilder(); - sbHtmlPageBody.AppendFormat(@"
QuickFIX Engine Web Interface

QuickFIX Engine Web Interface

", GetParameterList(urlOriginalString)); - sbHtmlPageBody.AppendFormat(@"
[HOME] [RELOAD]

", urlOriginalString); - sbHtmlPageBody.AppendFormat("

{1} has been refreshed

", GetParameterList(url), sessionId); + pageBuilder = new StringBuilder(); + pageBuilder.Append($"
QuickFIX Engine Web Interface

QuickFIX Engine Web Interface

"); + pageBuilder.Append($"
[HOME] [RELOAD]

"); + pageBuilder.Append($"

{sessionId} has been refreshed

"); } else { - sbHtmlPageBody.AppendFormat("

Are you sure you want to refresh session {1}?

", url, sessionId); - sbHtmlPageBody.AppendFormat("
[YES, refresh session] [NO, do not refresh session]
", url); + pageBuilder.Append($"

Are you sure you want to refresh session {sessionId}?

"); + pageBuilder.Append($"
[YES, refresh session] [NO, do not refresh session]
"); } - return sbHtmlPageBody.ToString(); + return pageBuilder.ToString(); } - private string RefreshSessions(HttpListenerRequest request) + private string RefreshSessions(HttpListenerRequest request, StringBuilder pageBuilder) { bool confirm = false; - string urlOriginalString = request.Url.OriginalString; - StringBuilder sbHtmlPageBody = _sbHtmlHeader; - if (request.QueryString["confirm"] != null) + if (request.QueryString["confirm"] is not null) { if (Convert.ToInt16(request.QueryString["confirm"]) != 0) { confirm = true; foreach (SessionID session in _sessionSettings.GetSessions()) { - Session sessionDetails = Session.LookupSession(session); - sessionDetails.Refresh(); + Session.LookupSession(session)?.Refresh(); } } } if (confirm) { - sbHtmlPageBody = new StringBuilder(); - sbHtmlPageBody.AppendFormat(@"
QuickFIX Engine Web Interface

QuickFIX Engine Web Interface

", "/"); - sbHtmlPageBody.AppendFormat("

Sessions have been refreshed

", "/"); + pageBuilder = new StringBuilder(); + pageBuilder.Append("
QuickFIX Engine Web Interface

QuickFIX Engine Web Interface

"); + pageBuilder.Append("

Sessions have been refreshed

"); } else { - sbHtmlPageBody.Append("

Are you sure you want to refresh all sessions ?

"); - sbHtmlPageBody.AppendFormat("
[YES, refresh sessions] [NO, do not refresh sessions]
", urlOriginalString); + pageBuilder.Append("

Are you sure you want to refresh all sessions ?

"); + pageBuilder.Append($"
[YES, refresh sessions] [NO, do not refresh sessions]
"); } - return sbHtmlPageBody.ToString(); + return pageBuilder.ToString(); } - private string ResetSessions(HttpListenerRequest request) + private string ResetSessions(HttpListenerRequest request, StringBuilder pageBuilder) { bool confirm = false; - string urlOriginalString = request.Url.OriginalString; - StringBuilder sbHtmlPageBody = _sbHtmlHeader; - if (request.QueryString["confirm"] != null) + if (request.QueryString["confirm"] is not null) { if (Convert.ToInt16(request.QueryString["confirm"]) != 0) { confirm = true; foreach (SessionID session in _sessionSettings.GetSessions()) { - Session sessionDetails = Session.LookupSession(session); - sessionDetails.Reset("Reset from WebInterface"); + Session.LookupSession(session)?.Reset("Reset from WebInterface"); } } } if (confirm) { - sbHtmlPageBody = new StringBuilder(); - sbHtmlPageBody.AppendFormat(@"
QuickFIX Engine Web Interface

QuickFIX Engine Web Interface

", "/"); - sbHtmlPageBody.AppendFormat("

Sessions have been reset

", "/"); + pageBuilder = new StringBuilder(); + pageBuilder.Append("
QuickFIX Engine Web Interface

QuickFIX Engine Web Interface

"); + pageBuilder.Append("

Sessions have been reset

"); } else { - sbHtmlPageBody.Append("

Are you sure you want to reset all sessions ?

"); - sbHtmlPageBody.AppendFormat("
[YES, reset sessions] [NO, do not reset sessions]
", urlOriginalString); + pageBuilder.Append("

Are you sure you want to reset all sessions ?

"); + pageBuilder.Append($"
[YES, reset sessions] [NO, do not reset sessions]
"); } - return sbHtmlPageBody.ToString(); + return pageBuilder.ToString(); } - private string ResetSession(HttpListenerRequest request) + private string ResetSession(HttpListenerRequest request, StringBuilder pageBuilder) { SessionID sessionId = new SessionID(request.QueryString["beginstring"], request.QueryString["sendercompid"], request.QueryString["targetcompid"]); - Session sessionDetails = Session.LookupSession(sessionId); + Session? sessionDetails = Session.LookupSession(sessionId); if (sessionDetails == null) throw new Exception("Session not found"); - StringBuilder sbHtmlPageBody = _sbHtmlHeader; bool confirm = false; - string urlOriginalString = request.Url.OriginalString; + string urlOriginalString = request.Url!.OriginalString; string url = "/session?" + GetParameterList(urlOriginalString); - if (request.QueryString["confirm"] != null) + if (request.QueryString["confirm"] is not null) { if (Convert.ToInt16(request.QueryString["confirm"])!=0) { @@ -302,202 +269,199 @@ private string ResetSession(HttpListenerRequest request) if (confirm) { - sbHtmlPageBody = new StringBuilder(); - sbHtmlPageBody.AppendFormat(@"
QuickFIX Engine Web Interface

QuickFIX Engine Web Interface

", GetParameterList(urlOriginalString)); - sbHtmlPageBody.AppendFormat(@"
[HOME] [RELOAD]

", urlOriginalString); - sbHtmlPageBody.AppendFormat("

{1} has been reset

",GetParameterList(url), sessionId); + pageBuilder = new StringBuilder(); + pageBuilder.Append($"
QuickFIX Engine Web Interface

QuickFIX Engine Web Interface

"); + pageBuilder.Append($"
[HOME] [RELOAD]

"); + pageBuilder.Append($"

{sessionId} has been reset

"); } else { - sbHtmlPageBody.AppendFormat("

Are you sure you want to reset session {1}?

", url, sessionId); - sbHtmlPageBody.AppendFormat("
[YES, reset session] [NO, do not reset session]
", url); + pageBuilder.Append($"

Are you sure you want to reset session {sessionId}?

"); + pageBuilder.Append($"
[YES, reset session] [NO, do not reset session]
"); } - return sbHtmlPageBody.ToString(); + return pageBuilder.ToString(); } - private string ProcessRoot( HttpListenerRequest request) + private string ProcessRoot(HttpListenerRequest request, StringBuilder pageBuilder) { - StringBuilder sbHtmlPageBody = _sbHtmlHeader; - //Session count - sbHtmlPageBody.AppendFormat("
{0} Sessions managed by QuickFIX

", _sessionSettings.GetSessions().Count); + pageBuilder.Append($"
{_sessionSettings.GetSessions().Count} Sessions managed by QuickFIX

"); //session management links - sbHtmlPageBody.AppendFormat(@"
RESET REFRESH ENABLE DISABLE

", GetParameterList(request.Url.OriginalString)); + pageBuilder.Append($"
RESET REFRESH ENABLE DISABLE

"); //Start the table generation - sbHtmlPageBody.Append(""); + pageBuilder.Append("
"); - sbHtmlPageBody.Append(""); - sbHtmlPageBody.Append(AddCell("Session", true)); - sbHtmlPageBody.Append(AddCell("Type", true)); - sbHtmlPageBody.Append(AddCell("Enabled", true)); - sbHtmlPageBody.Append(AddCell("Session Time", true)); - sbHtmlPageBody.Append(AddCell("Logged On", true)); - sbHtmlPageBody.Append(AddCell("Next Incoming", true)); - sbHtmlPageBody.Append(AddCell("Next Outgoing", true)); - sbHtmlPageBody.Append(""); + pageBuilder.Append(""); + pageBuilder.Append(AddCell("Session", true)); + pageBuilder.Append(AddCell("Type", true)); + pageBuilder.Append(AddCell("Enabled", true)); + pageBuilder.Append(AddCell("Session Time", true)); + pageBuilder.Append(AddCell("Logged On", true)); + pageBuilder.Append(AddCell("Next Incoming", true)); + pageBuilder.Append(AddCell("Next Outgoing", true)); + pageBuilder.Append(""); foreach (SessionID session in _sessionSettings.GetSessions()) { - Session sessionDetails = Session.LookupSession(session); - sbHtmlPageBody.Append(""); - sbHtmlPageBody.Append(AddCell(String.Format( + Session sessionDetails = Session.LookupSession(session)!; + pageBuilder.Append(""); + pageBuilder.Append(AddCell(String.Format( "{0}:{1}->{2}", session.BeginString, session.SenderCompID, session.TargetCompID))); - sbHtmlPageBody.Append(AddCell(sessionDetails.IsInitiator ? "initiator" : "acceptor")); - sbHtmlPageBody.Append(AddCell(sessionDetails.IsEnabled ? "yes" : "no")); - sbHtmlPageBody.Append(AddCell(sessionDetails.IsSessionTime ? "yes" : "no")); - sbHtmlPageBody.Append(AddCell(sessionDetails.IsLoggedOn ? "yes" : "no")); - sbHtmlPageBody.Append(AddCell(sessionDetails.NextTargetMsgSeqNum.ToString())); - sbHtmlPageBody.Append(AddCell(sessionDetails.NextSenderMsgSeqNum.ToString())); - sbHtmlPageBody.Append(""); + pageBuilder.Append(AddCell(sessionDetails.IsInitiator ? "initiator" : "acceptor")); + pageBuilder.Append(AddCell(sessionDetails.IsEnabled ? "yes" : "no")); + pageBuilder.Append(AddCell(sessionDetails.IsSessionTime ? "yes" : "no")); + pageBuilder.Append(AddCell(sessionDetails.IsLoggedOn ? "yes" : "no")); + pageBuilder.Append(AddCell(sessionDetails.NextTargetMsgSeqNum.ToString())); + pageBuilder.Append(AddCell(sessionDetails.NextSenderMsgSeqNum.ToString())); + pageBuilder.Append(""); } - sbHtmlPageBody.Append("
"); - return sbHtmlPageBody.ToString(); + pageBuilder.Append(""); + return pageBuilder.ToString(); } - public string SessionDetails(HttpListenerRequest request) + private string SessionDetails(HttpListenerRequest request, StringBuilder pageBuilder) { SessionID sessionId = new SessionID(request.QueryString["beginstring"], request.QueryString["sendercompid"], request.QueryString["targetcompid"]); - Session sessionDetails = Session.LookupSession(sessionId); + Session? sessionDetails = Session.LookupSession(sessionId); if (sessionDetails == null) throw new Exception("Session not found"); - StringBuilder sbHtmlPageBody = _sbHtmlHeader; - string url = request.Url.OriginalString; - string urlOriginalString = request.Url.OriginalString; + string url = request.Url?.OriginalString ?? "(null)"; + string urlOriginalString = url; - if (request.QueryString["enabled"] != null) + if (request.QueryString["enabled"] is not null) { if (!Convert.ToBoolean(request.QueryString["enabled"])) sessionDetails.Logout(); else - sessionDetails.Logon(); + sessionDetails.SetLogonState(); url = RemoveQueryStringByKey(urlOriginalString, "Enabled"); } - if (request.QueryString["next incoming"] != null) + if (request.QueryString["next incoming"] is not null) { SeqNumType val = Convert.ToUInt64(request.QueryString["next incoming"]); sessionDetails.NextTargetMsgSeqNum = (val == 0 || val == SeqNumType.MaxValue) ? 1 : val; url = RemoveQueryStringByKey(urlOriginalString, "next incoming"); } - if (request.QueryString["Next Outgoing"] != null) + if (request.QueryString["Next Outgoing"] is not null) { SeqNumType val = Convert.ToUInt64(request.QueryString["Next Outgoing"]); sessionDetails.NextSenderMsgSeqNum = (val == 0 || val == SeqNumType.MaxValue) ? 1 : val; url = RemoveQueryStringByKey(urlOriginalString, "Next Outgoing"); } - if (request.QueryString["SendRedundantResendRequests"] != null) + if (request.QueryString["SendRedundantResendRequests"] is not null) { sessionDetails.SendRedundantResendRequests = Convert.ToBoolean(request.QueryString["SendRedundantResendRequests"]); url = RemoveQueryStringByKey(urlOriginalString, "SendRedundantResendRequests"); } - if (request.QueryString["CheckCompId"] != null) + if (request.QueryString["CheckCompId"] is not null) { sessionDetails.CheckCompID = Convert.ToBoolean(request.QueryString["CheckCompId"]); url = RemoveQueryStringByKey(urlOriginalString, "CheckCompId"); } - if (request.QueryString["CheckLatency"] != null) + if (request.QueryString["CheckLatency"] is not null) { sessionDetails.CheckLatency = Convert.ToBoolean(request.QueryString["CheckLatency"]); url = RemoveQueryStringByKey(urlOriginalString, "CheckLatency"); } - if (request.QueryString["MaxLatency"] != null) + if (request.QueryString["MaxLatency"] is not null) { int val = Convert.ToInt16(request.QueryString["MaxLatency"]); sessionDetails.MaxLatency = val <= 0 ? 1 : val; url = RemoveQueryStringByKey(urlOriginalString, "MaxLatency"); } - if (request.QueryString["LogonTimeout"] != null) + if (request.QueryString["LogonTimeout"] is not null) { int val = Convert.ToInt16(request.QueryString["LogonTimeout"]); sessionDetails.LogonTimeout = val <= 0 ? 1 : val; url = RemoveQueryStringByKey(urlOriginalString, "LogonTimeout"); } - if (request.QueryString["LogoutTimeout"] != null) + if (request.QueryString["LogoutTimeout"] is not null) { int val = Convert.ToInt16(request.QueryString["LogoutTimeout"]); sessionDetails.LogoutTimeout = val <= 0 ? 1 : val; url = RemoveQueryStringByKey(urlOriginalString, "LogoutTimeout"); } - if (request.QueryString["ResetOnLogon"] != null) + if (request.QueryString["ResetOnLogon"] is not null) { sessionDetails.ResetOnLogon = Convert.ToBoolean(request.QueryString["ResetOnLogon"]); url = RemoveQueryStringByKey(urlOriginalString, "ResetOnLogon"); } - if (request.QueryString["ResetOnLogout"] != null) + if (request.QueryString["ResetOnLogout"] is not null) { sessionDetails.ResetOnLogout = Convert.ToBoolean(request.QueryString["ResetOnLogout"]); url = RemoveQueryStringByKey(urlOriginalString, "ResetOnLogout"); } - if (request.QueryString["ResetOnDisconnect"] != null) + if (request.QueryString["ResetOnDisconnect"] is not null) { sessionDetails.ResetOnDisconnect = Convert.ToBoolean(request.QueryString["ResetOnDisconnect"]); url = RemoveQueryStringByKey(urlOriginalString, "ResetOnDisconnect"); } - if (request.QueryString["RefreshOnLogon"] != null) + if (request.QueryString["RefreshOnLogon"] is not null) { sessionDetails.RefreshOnLogon = Convert.ToBoolean(request.QueryString["RefreshOnLogon"]); url = RemoveQueryStringByKey(urlOriginalString, "RefreshOnLogon"); } - if (request.QueryString["MillisecondsInTimestamp"] != null) + if (request.QueryString["MillisecondsInTimestamp"] is not null) { sessionDetails.MillisecondsInTimeStamp = Convert.ToBoolean(request.QueryString["MillisecondsInTimestamp"]); url = RemoveQueryStringByKey(urlOriginalString, "MillisecondsInTimestamp"); } - if (request.QueryString["PersistMessages"] != null) + if (request.QueryString["PersistMessages"] is not null) { sessionDetails.PersistMessages = Convert.ToBoolean(request.QueryString["PersistMessages"]); url = RemoveQueryStringByKey(urlOriginalString, "PersistMessages"); } - sbHtmlPageBody.AppendFormat(@"
{0}

", sessionId); - sbHtmlPageBody.AppendFormat(@"
[RESET] [REFRESH]

", GetParameterList(urlOriginalString)); + pageBuilder.Append($"
{sessionId}

"); + pageBuilder.Append($"
[RESET] [REFRESH]

"); - sbHtmlPageBody.Append(""); + pageBuilder.Append("
"); - sbHtmlPageBody.Append(AddRow("Enabled", sessionDetails.IsEnabled, url)); - sbHtmlPageBody.Append(AddRow("ConnectionType", sessionDetails.IsInitiator?"initiator": "acceptor")); - sbHtmlPageBody.Append(AddRow("SessionTime", sessionDetails.IsSessionTime)); - sbHtmlPageBody.Append(AddRow("LoggedOn", sessionDetails.IsLoggedOn)); - sbHtmlPageBody.Append(AddRow("Next Incoming", sessionDetails.NextTargetMsgSeqNum, url)); - sbHtmlPageBody.Append(AddRow("Next Outgoing", sessionDetails.NextSenderMsgSeqNum, url)); - sbHtmlPageBody.Append(AddRow("SendRedundantResendRequests", sessionDetails.SendRedundantResendRequests, url)); - sbHtmlPageBody.Append(AddRow("CheckCompId", sessionDetails.CheckCompID, url)); - sbHtmlPageBody.Append(AddRow("CheckLatency", sessionDetails.CheckLatency, url)); - sbHtmlPageBody.Append(AddRow("MaxLatency", sessionDetails.MaxLatency, url)); - sbHtmlPageBody.Append(AddRow("LogonTimeout", sessionDetails.LogonTimeout, url)); - sbHtmlPageBody.Append(AddRow("LogoutTimeout", sessionDetails.LogoutTimeout, url)); - sbHtmlPageBody.Append(AddRow("ResetOnLogon", sessionDetails.ResetOnLogon, url)); - sbHtmlPageBody.Append(AddRow("ResetOnLogout", sessionDetails.ResetOnLogout, url)); - sbHtmlPageBody.Append(AddRow("ResetOnDisconnect", sessionDetails.ResetOnDisconnect, url)); - sbHtmlPageBody.Append(AddRow("RefreshOnLogon", sessionDetails.RefreshOnLogon, url)); - sbHtmlPageBody.Append(AddRow("MillisecondsInTimestamp", sessionDetails.MillisecondsInTimeStamp, url)); - sbHtmlPageBody.Append(AddRow("PersistMessages", sessionDetails.PersistMessages, url)); - - sbHtmlPageBody.Append("
"); - return sbHtmlPageBody.ToString(); + pageBuilder.Append(AddRow("Enabled", sessionDetails.IsEnabled, url)); + pageBuilder.Append(AddRow("ConnectionType", sessionDetails.IsInitiator?"initiator": "acceptor")); + pageBuilder.Append(AddRow("SessionTime", sessionDetails.IsSessionTime)); + pageBuilder.Append(AddRow("LoggedOn", sessionDetails.IsLoggedOn)); + pageBuilder.Append(AddRow("Next Incoming", sessionDetails.NextTargetMsgSeqNum, url)); + pageBuilder.Append(AddRow("Next Outgoing", sessionDetails.NextSenderMsgSeqNum, url)); + pageBuilder.Append(AddRow("SendRedundantResendRequests", sessionDetails.SendRedundantResendRequests, url)); + pageBuilder.Append(AddRow("CheckCompId", sessionDetails.CheckCompID, url)); + pageBuilder.Append(AddRow("CheckLatency", sessionDetails.CheckLatency, url)); + pageBuilder.Append(AddRow("MaxLatency", sessionDetails.MaxLatency, url)); + pageBuilder.Append(AddRow("LogonTimeout", sessionDetails.LogonTimeout, url)); + pageBuilder.Append(AddRow("LogoutTimeout", sessionDetails.LogoutTimeout, url)); + pageBuilder.Append(AddRow("ResetOnLogon", sessionDetails.ResetOnLogon, url)); + pageBuilder.Append(AddRow("ResetOnLogout", sessionDetails.ResetOnLogout, url)); + pageBuilder.Append(AddRow("ResetOnDisconnect", sessionDetails.ResetOnDisconnect, url)); + pageBuilder.Append(AddRow("RefreshOnLogon", sessionDetails.RefreshOnLogon, url)); + pageBuilder.Append(AddRow("MillisecondsInTimestamp", sessionDetails.MillisecondsInTimeStamp, url)); + pageBuilder.Append(AddRow("PersistMessages", sessionDetails.PersistMessages, url)); + + pageBuilder.Append(""); + return pageBuilder.ToString(); } - public static string RemoveQueryStringByKey(string url, string key) + private static string RemoveQueryStringByKey(string url, string key) { var uri = new Uri(url); @@ -515,9 +479,13 @@ public static string RemoveQueryStringByKey(string url, string key) : pagePathWithoutQueryString; } - public static string GetParameterList(string url) - { - return HttpUtility.ParseQueryString((new Uri(url).Query)).ToString(); + /// + /// Returns the http parameter string from a url + /// + /// e.g. + /// e.g. (or empty string if is null) + private static string GetParameterList(string? url) { + return string.IsNullOrWhiteSpace(url) ? "" : $"{HttpUtility.ParseQueryString(new Uri(url).Query)}"; } private static string AddRow(string colName, bool val, string url="") @@ -585,11 +553,9 @@ protected virtual void Dispose(bool disposing) { Stop(); } - if (_connectionThread != null) - { - _connectionThread.Abort(); - _connectionThread = null; - } +#pragma warning disable SYSLIB0006 + _connectionThread.Abort(); +#pragma warning restore SYSLIB0006 } _disposed = true; } diff --git a/QuickFIXn/IMessageStore.cs b/QuickFIXn/IMessageStore.cs index a4657ccd9..8ea8e7b84 100755 --- a/QuickFIXn/IMessageStore.cs +++ b/QuickFIXn/IMessageStore.cs @@ -33,7 +33,7 @@ public interface IMessageStore : IDisposable void IncrNextTargetMsgSeqNum(); - System.DateTime? CreationTime { get; } + DateTime? CreationTime { get; } /// /// Reset the message store. Sequence numbers are set back to 1 and stored diff --git a/QuickFIXn/MessageBuilder.cs b/QuickFIXn/MessageBuilder.cs index 1441d3e77..c7253522f 100644 --- a/QuickFIXn/MessageBuilder.cs +++ b/QuickFIXn/MessageBuilder.cs @@ -1,55 +1,52 @@ -using QuickFix.Fields; +#nullable enable namespace QuickFix { internal class MessageBuilder { - private string _msgStr; - private bool _validateLengthAndChecksum; - private DataDictionary.DataDictionary _sessionDD; - private DataDictionary.DataDictionary _appDD; - private IMessageFactory _msgFactory; + private readonly string _msgStr; + private readonly bool _validateLengthAndChecksum; + private readonly DataDictionary.DataDictionary _sessionDict; + private readonly DataDictionary.DataDictionary _appDict; + private readonly IMessageFactory _msgFactory; - private QuickFix.Fields.MsgType _msgType; - private string _beginString; + private Message? _message; + private readonly Fields.ApplVerID _defaultApplVerId; - private Message _message; - private QuickFix.Fields.ApplVerID _defaultApplVerId; - - public string OriginalString { get { return _msgStr; } } - public QuickFix.Fields.MsgType MsgType { get { return _msgType; } } + public string OriginalString => _msgStr; + public Fields.MsgType MsgType { get; } /// /// The BeginString from the raw FIX message /// - public string BeginString { get { return _beginString; } } + public string BeginString { get; } internal MessageBuilder( string msgStr, string defaultApplVerId, bool validateLengthAndChecksum, - DataDictionary.DataDictionary sessionDD, - DataDictionary.DataDictionary appDD, + DataDictionary.DataDictionary sessionDict, + DataDictionary.DataDictionary appDict, IMessageFactory msgFactory) { _msgStr = msgStr; - _defaultApplVerId = new ApplVerID(defaultApplVerId); + _defaultApplVerId = new Fields.ApplVerID(defaultApplVerId); _validateLengthAndChecksum = validateLengthAndChecksum; - _sessionDD = sessionDD; - _appDD = appDD; + _sessionDict = sessionDict; + _appDict = appDict; _msgFactory = msgFactory; - _msgType = Message.IdentifyType(_msgStr); - _beginString = Message.ExtractBeginString(_msgStr); + MsgType = Message.IdentifyType(_msgStr); + BeginString = Message.ExtractBeginString(_msgStr); } internal Message Build() { - Message message = _msgFactory.Create(_beginString, _defaultApplVerId, _msgType.Obj); + Message message = _msgFactory.Create(BeginString, _defaultApplVerId, MsgType.Obj); message.FromString( _msgStr, _validateLengthAndChecksum, - _sessionDD, - _appDD, + _sessionDict, + _appDict, _msgFactory, ignoreBody: false); _message = message; @@ -58,15 +55,15 @@ internal Message Build() internal Message RejectableMessage() { - if (_message != null) + if (_message is not null) return _message; - Message message = _msgFactory.Create(_beginString, _msgType.Obj); + Message message = _msgFactory.Create(BeginString, MsgType.Obj); message.FromString( _msgStr, false, - _sessionDD, - _appDD, + _sessionDict, + _appDict, _msgFactory, true); return message; diff --git a/QuickFIXn/Session.cs b/QuickFIXn/Session.cs index 181cd54db..3e8815653 100755 --- a/QuickFIXn/Session.cs +++ b/QuickFIXn/Session.cs @@ -1,3 +1,4 @@ +#nullable enable using System; using System.Collections.Generic; using System.Threading; @@ -18,14 +19,15 @@ public class Session : IDisposable { #region Private Members - private static readonly Dictionary _sessions = new(); + private static readonly Dictionary Sessions = new(); + private static readonly HashSet AdminMsgTypes = new() { "0", "A", "1", "2", "3", "4", "5" }; + private readonly object _sync = new(); - private IResponder _responder; + private IResponder? _responder; private readonly SessionSchedule _schedule; private readonly SessionState _state; private readonly IMessageFactory _msgFactory; private readonly bool _appDoesEarlyIntercept; - private static readonly HashSet AdminMsgTypes = new() { "0", "A", "1", "2", "3", "4", "5" }; #endregion @@ -154,7 +156,7 @@ public int LogoutTimeout public bool ValidateLengthAndChecksum { get; set; } /// - /// Validates Comp IDs for each message + /// Whether to validates Comp IDs for each message /// public bool CheckCompID { get; set; } @@ -198,7 +200,7 @@ public TimeStampPrecision TimeStampPrecision /// /// This is the FIX field value, e.g. "6" for FIX44 /// - public ApplVerID targetDefaultApplVerID { get; set; } + public ApplVerID? TargetDefaultApplVerId { get; set; } /// /// This is the FIX field value, e.g. "6" for FIX44 @@ -206,10 +208,10 @@ public TimeStampPrecision TimeStampPrecision public string SenderDefaultApplVerID { get; set; } public SessionID SessionID { get; set; } - public IApplication Application { get; set; } - public DataDictionaryProvider DataDictionaryProvider { get; set; } - public DataDictionary.DataDictionary SessionDataDictionary { get; private set; } - public DataDictionary.DataDictionary ApplicationDataDictionary { get; private set; } + public IApplication Application { get; } + public DataDictionaryProvider DataDictionaryProvider { get; } + public DataDictionary.DataDictionary SessionDataDictionary { get; } + public DataDictionary.DataDictionary ApplicationDataDictionary { get; } /// /// Returns whether the Session has a Responder. This method is synchronized @@ -225,58 +227,63 @@ public TimeStampPrecision TimeStampPrecision #endregion public Session( - bool isInitiator, IApplication app, IMessageStoreFactory storeFactory, SessionID sessID, DataDictionaryProvider dataDictProvider, - SessionSchedule sessionSchedule, int heartBtInt, ILogFactory logFactory, IMessageFactory msgFactory, string senderDefaultApplVerID) + bool isInitiator, + IApplication app, + IMessageStoreFactory storeFactory, + SessionID sessId, + DataDictionaryProvider dataDictProvider, + SessionSchedule sessionSchedule, + int heartBtInt, + ILogFactory logFactory, + IMessageFactory msgFactory, + string senderDefaultApplVerId) { _schedule = sessionSchedule; _msgFactory = msgFactory; _appDoesEarlyIntercept = app is IApplicationExt; - this.Application = app; - this.SessionID = sessID; - this.DataDictionaryProvider = new DataDictionaryProvider(dataDictProvider); - this.SenderDefaultApplVerID = senderDefaultApplVerID; + Application = app; + SessionID = sessId; + DataDictionaryProvider = new DataDictionaryProvider(dataDictProvider); + SenderDefaultApplVerID = senderDefaultApplVerId; - this.SessionDataDictionary = this.DataDictionaryProvider.GetSessionDataDictionary(this.SessionID.BeginString); - this.ApplicationDataDictionary = this.SessionID.IsFIXT - ? this.DataDictionaryProvider.GetApplicationDataDictionary(this.SenderDefaultApplVerID) - : this.SessionDataDictionary; + SessionDataDictionary = DataDictionaryProvider.GetSessionDataDictionary(SessionID.BeginString); + ApplicationDataDictionary = SessionID.IsFIXT + ? DataDictionaryProvider.GetApplicationDataDictionary(SenderDefaultApplVerID) + : SessionDataDictionary; - ILog log = logFactory is not null ? logFactory.Create(sessID) : new NullLog(); + ILog log = logFactory.Create(sessId); - _state = new SessionState(isInitiator, log, heartBtInt) - { - MessageStore = storeFactory.Create(sessID) - }; + _state = new SessionState(isInitiator, log, heartBtInt, storeFactory.Create(sessId)); // Configuration defaults. // Will be overridden by the SessionFactory with values in the user's configuration. - this.PersistMessages = true; - this.ResetOnDisconnect = false; - this.SendRedundantResendRequests = false; - this.ResendSessionLevelRejects = false; - this.ValidateLengthAndChecksum = true; - this.CheckCompID = true; - this.TimeStampPrecision = TimeStampPrecision.Millisecond; - this.EnableLastMsgSeqNumProcessed = false; - this.MaxMessagesInResendRequest = 0; - this.SendLogoutBeforeTimeoutDisconnect = false; - this.IgnorePossDupResendRequests = false; - this.RequiresOrigSendingTime = true; - this.CheckLatency = true; - this.MaxLatency = 120; + PersistMessages = true; + ResetOnDisconnect = false; + SendRedundantResendRequests = false; + ResendSessionLevelRejects = false; + ValidateLengthAndChecksum = true; + CheckCompID = true; + TimeStampPrecision = TimeStampPrecision.Millisecond; + EnableLastMsgSeqNumProcessed = false; + MaxMessagesInResendRequest = 0; + SendLogoutBeforeTimeoutDisconnect = false; + IgnorePossDupResendRequests = false; + RequiresOrigSendingTime = true; + CheckLatency = true; + MaxLatency = 120; if (!IsSessionTime) Reset("Out of SessionTime (Session construction)"); else if (IsNewSession) Reset("New session"); - lock (_sessions) + lock (Sessions) { - _sessions[this.SessionID] = this; + Sessions[SessionID] = this; } - this.Application.OnCreate(this.SessionID); + Application.OnCreate(SessionID); Log.OnEvent("Created session"); } @@ -285,12 +292,12 @@ public Session( /// /// Looks up a Session by its SessionID /// - /// the SessionID of the Session + /// the SessionID of the Session /// the Session if found, else returns null - public static Session LookupSession(SessionID sessionID) + public static Session? LookupSession(SessionID sessionId) { - lock (_sessions) { - if (_sessions.TryGetValue(sessionID, out Session result)) + lock (Sessions) { + if (Sessions.TryGetValue(sessionId, out Session? result)) return result; } @@ -300,25 +307,25 @@ public static Session LookupSession(SessionID sessionID) /// /// Looks up a Session by its SessionID /// - /// the SessionID of the Session + /// the SessionID of the Session /// the true if Session exists, false otherwise - public static bool DoesSessionExist(SessionID sessionID) + public static bool DoesSessionExist(SessionID sessionId) { - return LookupSession(sessionID) != null; + return LookupSession(sessionId) is not null; } /// /// Sends a message to the session specified by the provider session ID. /// /// FIX message - /// target SessionID + /// target SessionID /// true if send was successful, false otherwise - public static bool SendToTarget(Message message, SessionID sessionID) + public static bool SendToTarget(Message message, SessionID sessionId) { - message.SetSessionID(sessionID); - Session session = Session.LookupSession(sessionID); - if (null == session) - throw new SessionNotFound(sessionID); + message.SetSessionID(sessionId); + Session? session = Session.LookupSession(sessionId); + if (session is null) + throw new SessionNotFound(sessionId); return session.Send(message); } @@ -329,8 +336,7 @@ public static bool SendToTarget(Message message, SessionID sessionID) /// public static bool SendToTarget(Message message) { - SessionID sessionID = message.GetSessionID(message); - return SendToTarget(message, sessionID); + return SendToTarget(message, message.GetSessionID(message)); } #endregion @@ -356,37 +362,26 @@ public bool Send(string message) { lock (_sync) { - if (null == _responder) + if (_responder is null) return false; Log.OnOutgoing(message); return _responder.Send(message); } } - // TODO for v2 - rename, make internal /// - /// Sets some internal state variables. Despite the name, it does not do anything to make a logon occur. + /// Sets some internal state variables. /// - public void Logon() + internal void SetLogonState() { _state.IsEnabled = true; _state.LogoutReason = ""; } - // TODO for v2 - rename, make internal /// - /// Sets some internal state variables. Despite the name, it does not cause a logout to occur. + /// Sets some internal state variables. /// - public void Logout() - { - Logout(""); - } - - // TODO for v2 - rename, make internal - /// - /// Sets some internal state variables. Despite the name, it does not cause a logout to occur. - /// - public void Logout(string reason) + internal void Logout(string reason = "") { _state.IsEnabled = false; _state.LogoutReason = reason; @@ -402,20 +397,20 @@ public void Disconnect(string reason) { if (_responder is not null) { - Log.OnEvent("Session " + this.SessionID + " disconnecting: " + reason); + Log.OnEvent($"Session {SessionID} disconnecting: {reason}"); _responder.Disconnect(); _responder = null; } else { - Log.OnEvent("Session " + this.SessionID + " already disconnected: " + reason); + Log.OnEvent("Session {SessionID} already disconnected: {reason}"); } if (_state.ReceivedLogon || _state.SentLogon) { _state.ReceivedLogon = false; _state.SentLogon = false; - this.Application.OnLogout(this.SessionID); + Application.OnLogout(SessionID); } _state.SentLogout = false; @@ -423,7 +418,7 @@ public void Disconnect(string reason) _state.SentReset = false; _state.ClearQueue(); _state.LogoutReason = ""; - if (this.ResetOnDisconnect) + if (ResetOnDisconnect) _state.Reset("ResetOnDisconnect"); _state.SetResendRange(0, 0); } @@ -490,7 +485,7 @@ public void Next() if (_state.TimedOut()) { - if (this.SendLogoutBeforeTimeoutDisconnect) + if (SendLogoutBeforeTimeoutDisconnect) GenerateLogout(); Disconnect("Timed out waiting for heartbeat"); } @@ -498,7 +493,6 @@ public void Next() { if (_state.NeedTestRequest()) { - GenerateTestRequest("TEST"); _state.TestRequestCounter += 1; Log.OnEvent("Sent test request TEST"); @@ -531,9 +525,9 @@ private void NextMessage(string msgStr) MessageBuilder msgBuilder = new MessageBuilder( msgStr, SenderDefaultApplVerID, - this.ValidateLengthAndChecksum, - this.SessionDataDictionary, - this.ApplicationDataDictionary, + ValidateLengthAndChecksum, + SessionDataDictionary, + ApplicationDataDictionary, _msgFactory); Next(msgBuilder); @@ -554,39 +548,37 @@ internal void Next(MessageBuilder msgBuilder) if (IsNewSession) _state.Reset("New session (detected in Next(Message))"); - Message message = null; // declared outside of try-block so that catch-blocks can use it + Message? message = null; // declared outside of try-block so that catch-blocks can use it try { message = msgBuilder.Build(); if (_appDoesEarlyIntercept) - ((IApplicationExt)Application).FromEarlyIntercept(message, this.SessionID); + ((IApplicationExt)Application).FromEarlyIntercept(message, SessionID); - Header header = message.Header; string msgType = msgBuilder.MsgType.Obj; string beginString = msgBuilder.BeginString; - if (!beginString.Equals(this.SessionID.BeginString)) + if (!beginString.Equals(SessionID.BeginString)) throw new UnsupportedVersion(beginString); if (MsgType.LOGON.Equals(msgType)) { - targetDefaultApplVerID = this.SessionID.IsFIXT + TargetDefaultApplVerId = SessionID.IsFIXT ? new ApplVerID(message.GetString(Fields.Tags.DefaultApplVerID)) : Message.GetApplVerID(beginString); } - if (this.SessionID.IsFIXT && !Message.IsAdminMsgType(msgType)) + if (SessionID.IsFIXT && !Message.IsAdminMsgType(msgType)) { DataDictionary.DataDictionary.Validate(message, SessionDataDictionary, ApplicationDataDictionary, beginString, msgType); } else { - this.SessionDataDictionary.Validate(message, beginString, msgType); + SessionDataDictionary.Validate(message, beginString, msgType); } - if (MsgType.LOGON.Equals(msgType)) NextLogon(message); else if (MsgType.LOGOUT.Equals(msgType)) @@ -633,7 +625,7 @@ internal void Next(MessageBuilder msgBuilder) { if (MsgType.LOGOUT.Equals(msgBuilder.MsgType.Obj)) { - NextLogout(message); + NextLogout(message!); } else { @@ -645,12 +637,12 @@ internal void Next(MessageBuilder msgBuilder) catch (UnsupportedMessageType e) { Log.OnEvent("Unsupported message type: " + e.Message); - GenerateBusinessMessageReject(message, Fields.BusinessRejectReason.UNKNOWN_MESSAGE_TYPE, 0); + GenerateBusinessMessageReject(message!, Fields.BusinessRejectReason.UNKNOWN_MESSAGE_TYPE, 0); } catch (FieldNotFoundException e) { Log.OnEvent("Rejecting invalid message, field not found: " + e.Message); - if ((string.CompareOrdinal(SessionID.BeginString, FixValues.BeginString.FIX42) >= 0) && (message.IsApp())) + if (string.CompareOrdinal(SessionID.BeginString, FixValues.BeginString.FIX42) >= 0 && message!.IsApp()) { GenerateBusinessMessageReject(message, Fields.BusinessRejectReason.CONDITIONALLY_REQUIRED_FIELD_MISSING, e.Field); } @@ -690,9 +682,9 @@ protected void NextLogon(Message logon) } } - if (IsAcceptor && this.ResetOnLogon) + if (IsAcceptor && ResetOnLogon) _state.Reset("ResetOnLogon"); - if (this.RefreshOnLogon) + if (RefreshOnLogon) Refresh(); if (!Verify(logon, false, true)) @@ -728,8 +720,8 @@ protected void NextLogon(Message logon) _state.IncrNextTargetMsgSeqNum(); } - if (this.IsLoggedOn) - this.Application.OnLogon(this.SessionID); + if (IsLoggedOn) + Application.OnLogon(SessionID); } protected void NextTestRequest(Message testRequest) @@ -744,16 +736,15 @@ protected void NextResendRequest(Message resendReq) { if (!Verify(resendReq, false, false)) return; - try - { - SeqNumType msgSeqNum = 0; - if (!(this.IgnorePossDupResendRequests && resendReq.Header.IsSetField(Tags.PossDupFlag))) + try { + SeqNumType msgSeqNum; + if (!(IgnorePossDupResendRequests && resendReq.Header.IsSetField(Tags.PossDupFlag))) { SeqNumType begSeqNo = resendReq.GetULong(Fields.Tags.BeginSeqNo); SeqNumType endSeqNo = resendReq.GetULong(Fields.Tags.EndSeqNo); Log.OnEvent("Got resend request from " + begSeqNo + " to " + endSeqNo); - if ((endSeqNo == 999999) || (endSeqNo == 0)) + if (endSeqNo == 999999 || endSeqNo == 0) { endSeqNo = _state.NextSenderMsgSeqNum - 1; } @@ -780,15 +771,15 @@ protected void NextResendRequest(Message resendReq) foreach (string msgStr in messages) { Message msg = new Message(); - msg.FromString(msgStr, true, this.SessionDataDictionary, this.ApplicationDataDictionary, _msgFactory, ignoreBody: false); + msg.FromString(msgStr, true, SessionDataDictionary, ApplicationDataDictionary, _msgFactory, ignoreBody: false); msgSeqNum = msg.Header.GetULong(Tags.MsgSeqNum); - if ((current != msgSeqNum) && begin == 0) + if (current != msgSeqNum && begin == 0) { begin = current; } - if (IsAdminMessage(msg) && !(this.ResendSessionLevelRejects && msg.Header.GetString(Tags.MsgType) == MsgType.REJECT)) + if (IsAdminMessage(msg) && !(ResendSessionLevelRejects && msg.Header.GetString(Tags.MsgType) == MsgType.REJECT)) { if (begin == 0) { @@ -798,7 +789,7 @@ protected void NextResendRequest(Message resendReq) else { - initializeResendFields(msg); + InitializeResendFields(msg); if(!ResendApproved(msg, SessionID)) { continue; @@ -842,11 +833,11 @@ protected void NextResendRequest(Message resendReq) Log.OnEvent("ERROR during resend request " + e.Message); } } - private bool ResendApproved(Message msg, SessionID sessionID) + private bool ResendApproved(Message msg, SessionID sessionId) { try { - Application.ToApp(msg, sessionID); + Application.ToApp(msg, sessionId); } catch (DoNotSend) { @@ -877,7 +868,7 @@ protected void NextLogout(Message logout) } _state.IncrNextTargetMsgSeqNum(); - if (this.ResetOnLogout) + if (ResetOnLogout) _state.Reset("ResetOnLogout"); Disconnect(disconnectReason); } @@ -915,23 +906,18 @@ protected void NextSequenceReset(Message sequenceReset) } } - public bool Verify(Message message) - { - return Verify(message, true, true); - } - - public bool Verify(Message msg, bool checkTooHigh, bool checkTooLow) + public bool Verify(Message msg, bool checkTooHigh = true, bool checkTooLow = true) { SeqNumType msgSeqNum = 0; - string msgType = ""; + string msgType; try { msgType = msg.Header.GetString(Fields.Tags.MsgType); - string senderCompID = msg.Header.GetString(Fields.Tags.SenderCompID); - string targetCompID = msg.Header.GetString(Fields.Tags.TargetCompID); + string senderCompId = msg.Header.GetString(Fields.Tags.SenderCompID); + string targetCompId = msg.Header.GetString(Fields.Tags.TargetCompID); - if (!IsCorrectCompID(senderCompID, targetCompID)) + if (!IsCorrectCompId(senderCompId, targetCompId)) { GenerateReject(msg, FixValues.SessionRejectReason.COMPID_PROBLEM); GenerateLogout(); @@ -963,7 +949,7 @@ public bool Verify(Message msg, bool checkTooHigh, bool checkTooLow) else if (msgSeqNum >= range.ChunkEndSeqNo) { Log.OnEvent("Chunked ResendRequest for messages FROM: " + range.BeginSeqNo + " TO: " + range.ChunkEndSeqNo + " has been satisfied."); - SeqNumType newChunkEndSeqNo = Math.Min(range.EndSeqNo, range.ChunkEndSeqNo + this.MaxMessagesInResendRequest); + SeqNumType newChunkEndSeqNo = Math.Min(range.EndSeqNo, range.ChunkEndSeqNo + MaxMessagesInResendRequest); GenerateResendRequestRange(msg.Header.GetString(Fields.Tags.BeginString), range.ChunkEndSeqNo + 1, newChunkEndSeqNo); range.ChunkEndSeqNo = newChunkEndSeqNo; } @@ -977,7 +963,7 @@ public bool Verify(Message msg, bool checkTooHigh, bool checkTooLow) return false; } } - catch (System.Exception e) + catch (Exception e) { Log.OnEvent("Verify failed: " + e.Message); Disconnect("Verify failed: " + e.Message); @@ -988,9 +974,9 @@ public bool Verify(Message msg, bool checkTooHigh, bool checkTooLow) _state.TestRequestCounter = 0; if (Message.IsAdminMsgType(msgType)) - this.Application.FromAdmin(msg, this.SessionID); + Application.FromAdmin(msg, SessionID); else - this.Application.FromApp(msg, this.SessionID); + Application.FromApp(msg, SessionID); return true; } @@ -1014,29 +1000,20 @@ public void Refresh() /// /// Send a logout, disconnect, and reset session state /// - /// reason for the reset (for the log) - public void Reset(string loggedReason) + /// message to log + /// value to put in the Logout message's Text field (ignored if null/empty string) + public void Reset(string loggedReason, string? logoutMessage = null) { - Reset(loggedReason, null); - } - - /// - /// Send a logout, disconnect, and reset session state - /// - /// reason for the reset (for the log) - /// message to put in the Logout message's Text field (ignored if null/empty string) - public void Reset(string loggedReason, string logoutMessage) - { - if(this.IsLoggedOn) + if(IsLoggedOn) GenerateLogout(logoutMessage); Disconnect("Resetting..."); _state.Reset(loggedReason); } - private void initializeResendFields(Message message) + private void InitializeResendFields(Message message) { FieldMap header = message.Header; - System.DateTime sendingTime = header.GetDateTime(Fields.Tags.SendingTime); + DateTime sendingTime = header.GetDateTime(Fields.Tags.SendingTime); InsertOrigSendingTime(header, sendingTime); header.SetField(new Fields.PossDupFlag(true)); InsertSendingTime(header); @@ -1044,18 +1021,18 @@ private void initializeResendFields(Message message) protected bool ShouldSendReset() { - return (string.CompareOrdinal(SessionID.BeginString, FixValues.BeginString.FIX41) >= 0) - && (this.ResetOnLogon || this.ResetOnLogout || this.ResetOnDisconnect) - && (_state.NextSenderMsgSeqNum == 1) - && (_state.NextTargetMsgSeqNum == 1); + return string.CompareOrdinal(SessionID.BeginString, FixValues.BeginString.FIX41) >= 0 + && (ResetOnLogon || ResetOnLogout || ResetOnDisconnect) + && _state.NextSenderMsgSeqNum == 1 + && _state.NextTargetMsgSeqNum == 1; } - protected bool IsCorrectCompID(string senderCompID, string targetCompID) + protected bool IsCorrectCompId(string senderCompId, string targetCompId) { - if (!this.CheckCompID) + if (!CheckCompID) return true; - return this.SessionID.SenderCompID.Equals(targetCompID) - && this.SessionID.TargetCompID.Equals(senderCompID); + return SessionID.SenderCompID.Equals(targetCompId) + && SessionID.TargetCompID.Equals(senderCompId); } /// FIXME - this fn always returns true-- should it ever be false? @@ -1085,7 +1062,7 @@ protected void DoTargetTooHigh(Message msg, SeqNumType msgSeqNum) { ResendRange range = _state.GetResendRange(); - if (!this.SendRedundantResendRequests && msgSeqNum >= range.BeginSeqNo) + if (!SendRedundantResendRequests && msgSeqNum >= range.BeginSeqNo) { Log.OnEvent("Already sent ResendRequest FROM: " + range.BeginSeqNo + " TO: " + range.EndSeqNo + ". Not sending another."); return; @@ -1150,13 +1127,13 @@ protected void GenerateBusinessMessageReject(Message message, int err, int field Message reject; if (string.CompareOrdinal(SessionID.BeginString, FixValues.BeginString.FIX42) >= 0) { - reject = _msgFactory.Create(this.SessionID.BeginString, MsgType.BUSINESS_MESSAGE_REJECT); + reject = _msgFactory.Create(SessionID.BeginString, MsgType.BUSINESS_MESSAGE_REJECT); reject.SetField(new RefMsgType(msgType)); reject.SetField(new BusinessRejectReason(err)); } else { - reject = _msgFactory.Create(this.SessionID.BeginString, MsgType.REJECT); + reject = _msgFactory.Create(SessionID.BeginString, MsgType.REJECT); char[] reasonArray = reason.ToLower().ToCharArray(); reasonArray[0] = char.ToUpper(reasonArray[0]); reason = new string(reasonArray); @@ -1196,9 +1173,9 @@ protected void GenerateResendRequest(string beginString, SeqNumType msgSeqNum) SeqNumType beginSeqNum = _state.NextTargetMsgSeqNum; SeqNumType endRangeSeqNum = msgSeqNum - 1; SeqNumType endChunkSeqNum; - if (this.MaxMessagesInResendRequest > 0) + if (MaxMessagesInResendRequest > 0) { - endChunkSeqNum = Math.Min(endRangeSeqNum, beginSeqNum + this.MaxMessagesInResendRequest - 1); + endChunkSeqNum = Math.Min(endRangeSeqNum, beginSeqNum + MaxMessagesInResendRequest - 1); } else { @@ -1216,21 +1193,17 @@ protected void GenerateResendRequest(string beginString, SeqNumType msgSeqNum) _state.SetResendRange(beginSeqNum, endRangeSeqNum, endChunkSeqNum); } - /// - /// FIXME - /// - /// protected bool GenerateLogon() { - Message logon = _msgFactory.Create(this.SessionID.BeginString, Fields.MsgType.LOGON); + Message logon = _msgFactory.Create(SessionID.BeginString, Fields.MsgType.LOGON); logon.SetField(new Fields.EncryptMethod(0)); logon.SetField(new Fields.HeartBtInt(_state.HeartBtInt)); - if (this.SessionID.IsFIXT) - logon.SetField(new Fields.DefaultApplVerID(this.SenderDefaultApplVerID)); - if (this.RefreshOnLogon) + if (SessionID.IsFIXT) + logon.SetField(new Fields.DefaultApplVerID(SenderDefaultApplVerID)); + if (RefreshOnLogon) Refresh(); - if (this.ResetOnLogon) + if (ResetOnLogon) _state.Reset("ResetOnLogon"); if (ShouldSendReset()) logon.SetField(new Fields.ResetSeqNumFlag(true)); @@ -1238,23 +1211,19 @@ protected bool GenerateLogon() InitializeHeader(logon); _state.LastReceivedTimeDT = DateTime.UtcNow; _state.TestRequestCounter = 0; - _state.SentLogon = true; - return SendRaw(logon, 0); + _state.SentLogon = SendRaw(logon, 0); + return _state.SentLogon; } - /// - /// FIXME don't do so much operator new here - /// - /// - /// protected bool GenerateLogon(Message otherLogon) { - Message logon = _msgFactory.Create(this.SessionID.BeginString, Fields.MsgType.LOGON); + Message logon = _msgFactory.Create(SessionID.BeginString, Fields.MsgType.LOGON); logon.SetField(new Fields.EncryptMethod(0)); - if (this.SessionID.IsFIXT) - logon.SetField(new Fields.DefaultApplVerID(this.SenderDefaultApplVerID)); logon.SetField(new Fields.HeartBtInt(otherLogon.GetInt(Tags.HeartBtInt))); - if (this.EnableLastMsgSeqNumProcessed) + + if (SessionID.IsFIXT) + logon.SetField(new Fields.DefaultApplVerID(SenderDefaultApplVerID)); + if (EnableLastMsgSeqNumProcessed) logon.Header.SetField(new Fields.LastMsgSeqNumProcessed(otherLogon.Header.GetULong(Tags.MsgSeqNum))); InitializeHeader(logon); @@ -1264,7 +1233,7 @@ protected bool GenerateLogon(Message otherLogon) public void GenerateTestRequest(string id) { - Message testRequest = _msgFactory.Create(this.SessionID.BeginString, Fields.MsgType.TEST_REQUEST); + Message testRequest = _msgFactory.Create(SessionID.BeginString, Fields.MsgType.TEST_REQUEST); InitializeHeader(testRequest); testRequest.SetField(new Fields.TestReqID(id)); SendRaw(testRequest, 0); @@ -1276,7 +1245,7 @@ public void GenerateTestRequest(string id) /// public void GenerateLogout() { - GenerateLogout(null, null); + ImplGenerateLogout(); } /// @@ -1284,9 +1253,9 @@ public void GenerateLogout() /// /// written into the Text field /// - private void GenerateLogout(string text) + private void GenerateLogout(string? text) { - GenerateLogout(null, text); + ImplGenerateLogout(text: text); } /// @@ -1296,22 +1265,22 @@ private void GenerateLogout(string text) /// private void GenerateLogout(Message other) { - GenerateLogout(other, null); + ImplGenerateLogout(other: other); } /// - /// Send a Logout message + /// Common implementation for variant GenerateLogout() function interfaces /// /// used to fill MsgSeqNum field, if configuration requires it; ignored if null /// written into the Text field; ignored if empty/null /// - private void GenerateLogout(Message other, string text) + private void ImplGenerateLogout(Message? other = null, string? text = null) { - Message logout = _msgFactory.Create(this.SessionID.BeginString, Fields.MsgType.LOGOUT); + Message logout = _msgFactory.Create(SessionID.BeginString, Fields.MsgType.LOGOUT); InitializeHeader(logout); - if (text != null && text.Length > 0) + if (!string.IsNullOrEmpty(text)) logout.SetField(new Fields.Text(text)); - if (other != null && this.EnableLastMsgSeqNumProcessed) + if (other is not null && EnableLastMsgSeqNumProcessed) { try { @@ -1327,19 +1296,19 @@ private void GenerateLogout(Message other, string text) public void GenerateHeartbeat() { - Message heartbeat = _msgFactory.Create(this.SessionID.BeginString, Fields.MsgType.HEARTBEAT); + Message heartbeat = _msgFactory.Create(SessionID.BeginString, Fields.MsgType.HEARTBEAT); InitializeHeader(heartbeat); SendRaw(heartbeat, 0); } public void GenerateHeartbeat(Message testRequest) { - Message heartbeat = _msgFactory.Create(this.SessionID.BeginString, Fields.MsgType.HEARTBEAT); + Message heartbeat = _msgFactory.Create(SessionID.BeginString, Fields.MsgType.HEARTBEAT); InitializeHeader(heartbeat); try { heartbeat.SetField(new Fields.TestReqID(testRequest.GetString(Fields.Tags.TestReqID))); - if (this.EnableLastMsgSeqNumProcessed) + if (EnableLastMsgSeqNumProcessed) { heartbeat.Header.SetField(new Fields.LastMsgSeqNumProcessed(testRequest.Header.GetULong(Tags.MsgSeqNum))); } @@ -1349,35 +1318,21 @@ public void GenerateHeartbeat(Message testRequest) SendRaw(heartbeat, 0); } - - internal void GenerateReject(MessageBuilder msgBuilder, FixValues.SessionRejectReason reason) - { - GenerateReject(msgBuilder.RejectableMessage(), reason, 0); - } - internal void GenerateReject(MessageBuilder msgBuilder, FixValues.SessionRejectReason reason, int field) { GenerateReject(msgBuilder.RejectableMessage(), reason, field); } - public void GenerateReject(Message message, FixValues.SessionRejectReason reason) + public void GenerateReject(Message message, FixValues.SessionRejectReason reason, int field = 0) { - GenerateReject(message, reason, 0); - } - - public void GenerateReject(Message message, FixValues.SessionRejectReason reason, int field) - { - string beginString = this.SessionID.BeginString; + string beginString = SessionID.BeginString; Message reject = _msgFactory.Create(beginString, Fields.MsgType.REJECT); reject.ReverseRoute(message.Header); InitializeHeader(reject); - string msgType; - if (message.Header.IsSetField(Fields.Tags.MsgType)) - msgType = message.Header.GetString(Fields.Tags.MsgType); - else - msgType = ""; + string msgType = message.Header.IsSetField(Fields.Tags.MsgType) + ? message.Header.GetString(Fields.Tags.MsgType) : ""; SeqNumType msgSeqNum = 0; if (message.Header.IsSetField(Fields.Tags.MsgSeqNum)) @@ -1395,19 +1350,20 @@ public void GenerateReject(Message message, FixValues.SessionRejectReason reason { if (msgType.Length > 0) reject.SetField(new Fields.RefMsgType(msgType)); - if ((FixValues.BeginString.FIX42.Equals(beginString) && reason.Value <= FixValues.SessionRejectReason.INVALID_MSGTYPE.Value) || (string.CompareOrdinal(beginString, FixValues.BeginString.FIX42) > 0)) + if ((FixValues.BeginString.FIX42.Equals(beginString) && reason.Value <= FixValues.SessionRejectReason.INVALID_MSGTYPE.Value) + || string.CompareOrdinal(beginString, FixValues.BeginString.FIX42) > 0) { reject.SetField(new Fields.SessionRejectReason(reason.Value)); } } if (!MsgType.LOGON.Equals(msgType) && !MsgType.SEQUENCE_RESET.Equals(msgType) - && (msgSeqNum == _state.NextTargetMsgSeqNum)) + && msgSeqNum == _state.NextTargetMsgSeqNum) { _state.IncrNextTargetMsgSeqNum(); } - if ((0 != field) || FixValues.SessionRejectReason.INVALID_TAG_NUMBER.Equals(reason)) + if (0 != field || FixValues.SessionRejectReason.INVALID_TAG_NUMBER.Equals(reason)) { if (FixValues.SessionRejectReason.INVALID_MSGTYPE.Equals(reason)) { @@ -1454,57 +1410,46 @@ protected void PopulateRejectReason(Message reject, string text) reject.SetField(new Fields.Text(text)); } - /// - /// FIXME don't do so much operator new here - /// - /// - /// - protected void InitializeHeader(Message m, SeqNumType msgSeqNum) + protected void InitializeHeader(Message m, SeqNumType msgSeqNum = 0) { _state.LastSentTimeDT = DateTime.UtcNow; - m.Header.SetField(new Fields.BeginString(this.SessionID.BeginString)); - m.Header.SetField(new Fields.SenderCompID(this.SessionID.SenderCompID)); - if (SessionID.IsSet(this.SessionID.SenderSubID)) - m.Header.SetField(new Fields.SenderSubID(this.SessionID.SenderSubID)); - if (SessionID.IsSet(this.SessionID.SenderLocationID)) - m.Header.SetField(new Fields.SenderLocationID(this.SessionID.SenderLocationID)); - m.Header.SetField(new Fields.TargetCompID(this.SessionID.TargetCompID)); - if (SessionID.IsSet(this.SessionID.TargetSubID)) - m.Header.SetField(new Fields.TargetSubID(this.SessionID.TargetSubID)); - if (SessionID.IsSet(this.SessionID.TargetLocationID)) - m.Header.SetField(new Fields.TargetLocationID(this.SessionID.TargetLocationID)); + m.Header.SetField(new Fields.BeginString(SessionID.BeginString)); + m.Header.SetField(new Fields.SenderCompID(SessionID.SenderCompID)); + if (SessionID.IsSet(SessionID.SenderSubID)) + m.Header.SetField(new Fields.SenderSubID(SessionID.SenderSubID)); + if (SessionID.IsSet(SessionID.SenderLocationID)) + m.Header.SetField(new Fields.SenderLocationID(SessionID.SenderLocationID)); + m.Header.SetField(new Fields.TargetCompID(SessionID.TargetCompID)); + if (SessionID.IsSet(SessionID.TargetSubID)) + m.Header.SetField(new Fields.TargetSubID(SessionID.TargetSubID)); + if (SessionID.IsSet(SessionID.TargetLocationID)) + m.Header.SetField(new Fields.TargetLocationID(SessionID.TargetLocationID)); if (msgSeqNum > 0) m.Header.SetField(new Fields.MsgSeqNum(msgSeqNum)); else m.Header.SetField(new Fields.MsgSeqNum(_state.NextSenderMsgSeqNum)); - if (this.EnableLastMsgSeqNumProcessed && !m.Header.IsSetField(Tags.LastMsgSeqNumProcessed)) - { - m.Header.SetField(new LastMsgSeqNumProcessed(this.NextTargetMsgSeqNum - 1)); - } + if (EnableLastMsgSeqNumProcessed && !m.Header.IsSetField(Tags.LastMsgSeqNumProcessed)) + m.Header.SetField(new LastMsgSeqNumProcessed(NextTargetMsgSeqNum - 1)); InsertSendingTime(m.Header); } - protected void InitializeHeader(Message m) - { - InitializeHeader(m, 0); - } private bool IsFix42OrAbove() { - return this.SessionID.BeginString == FixValues.BeginString.FIXT11 + return SessionID.BeginString == FixValues.BeginString.FIXT11 || string.CompareOrdinal(SessionID.BeginString, FixValues.BeginString.FIX42) >= 0; } protected void InsertSendingTime(FieldMap header) { header.SetField(new Fields.SendingTime( - System.DateTime.UtcNow, IsFix42OrAbove() ? TimeStampPrecision : TimeStampPrecision.Second ) ); + DateTime.UtcNow, IsFix42OrAbove() ? TimeStampPrecision : TimeStampPrecision.Second ) ); } protected void Persist(Message message, string messageString) { - if (this.PersistMessages) + if (PersistMessages) { SeqNumType msgSeqNum = message.Header.GetULong(Fields.Tags.MsgSeqNum); _state.Set(msgSeqNum, messageString); @@ -1518,13 +1463,13 @@ protected bool IsGoodTime(Message msg) return true; var sendingTime = msg.Header.GetDateTime(Fields.Tags.SendingTime); - System.TimeSpan tmSpan = System.DateTime.UtcNow - sendingTime; - return System.Math.Abs(tmSpan.TotalSeconds) <= MaxLatency; + TimeSpan tmSpan = DateTime.UtcNow - sendingTime; + return Math.Abs(tmSpan.TotalSeconds) <= MaxLatency; } private void GenerateSequenceReset(Message receivedMessage, SeqNumType beginSeqNo, SeqNumType endSeqNo) { - string beginString = this.SessionID.BeginString; + string beginString = SessionID.BeginString; Message sequenceReset = _msgFactory.Create(beginString, Fields.MsgType.SEQUENCE_RESET); InitializeHeader(sequenceReset); SeqNumType newSeqNo = endSeqNo; @@ -1534,7 +1479,7 @@ private void GenerateSequenceReset(Message receivedMessage, SeqNumType beginSeqN sequenceReset.Header.SetField(new MsgSeqNum(beginSeqNo)); sequenceReset.SetField(new NewSeqNo(newSeqNo)); sequenceReset.SetField(new GapFillFlag(true)); - if (receivedMessage != null && this.EnableLastMsgSeqNumProcessed) + if (EnableLastMsgSeqNumProcessed) { try { @@ -1549,7 +1494,7 @@ private void GenerateSequenceReset(Message receivedMessage, SeqNumType beginSeqN Log.OnEvent("Sent SequenceReset TO: " + newSeqNo); } - protected void InsertOrigSendingTime(FieldMap header, System.DateTime sendingTime) + protected void InsertOrigSendingTime(FieldMap header, DateTime sendingTime) { header.SetField(new OrigSendingTime( sendingTime, IsFix42OrAbove() ? TimeStampPrecision : TimeStampPrecision.Second ) ); @@ -1565,7 +1510,7 @@ protected void NextQueued() protected bool NextQueued(SeqNumType num) { - Message msg = _state.Dequeue(num); + Message? msg = _state.Dequeue(num); if (msg is not null) { @@ -1585,7 +1530,7 @@ protected bool NextQueued(SeqNumType num) return false; } - private bool IsAdminMessage(Message msg) + private static bool IsAdminMessage(Message msg) { var msgType = msg.Header.GetString(Fields.Tags.MsgType); return AdminMsgTypes.Contains(msgType); @@ -1601,11 +1546,11 @@ protected bool SendRaw(Message message, SeqNumType seqNum) if (Message.IsAdminMsgType(msgType)) { - this.Application.ToAdmin(message, this.SessionID); + Application.ToAdmin(message, SessionID); if (MsgType.LOGON.Equals(msgType) && !_state.ReceivedReset) { - Fields.ResetSeqNumFlag resetSeqNumFlag = new QuickFix.Fields.ResetSeqNumFlag(false); + Fields.ResetSeqNumFlag resetSeqNumFlag = new Fields.ResetSeqNumFlag(false); if (message.IsSetField(resetSeqNumFlag)) message.GetField(resetSeqNumFlag); if (resetSeqNumFlag.getValue()) @@ -1620,7 +1565,7 @@ protected bool SendRaw(Message message, SeqNumType seqNum) { try { - this.Application.ToApp(message, this.SessionID); + Application.ToApp(message, SessionID); } catch (DoNotSend) { @@ -1645,13 +1590,14 @@ public void Dispose() protected virtual void Dispose(bool disposing) { - if (Disposed) return; + if (Disposed) + return; if (disposing) { - if (_state != null) { _state.Dispose(); } - lock (_sessions) + _state.Dispose(); + lock (Sessions) { - _sessions.Remove(this.SessionID); + Sessions.Remove(SessionID); } } Disposed = true; diff --git a/QuickFIXn/SessionFactory.cs b/QuickFIXn/SessionFactory.cs index 7349684ec..eb433a8a1 100755 --- a/QuickFIXn/SessionFactory.cs +++ b/QuickFIXn/SessionFactory.cs @@ -1,4 +1,5 @@ -using System; +#nullable enable +using System; using System.Collections.Generic; using QuickFix.Util; @@ -9,21 +10,17 @@ namespace QuickFix /// public class SessionFactory { - protected IApplication application_; - protected IMessageStoreFactory messageStoreFactory_; - protected ILogFactory logFactory_; - protected IMessageFactory messageFactory_; - protected Dictionary dictionariesByPath_ = new Dictionary(); - - public SessionFactory(IApplication app, IMessageStoreFactory storeFactory) - : this(app, storeFactory, null, null) - { } - - public SessionFactory(IApplication app, IMessageStoreFactory storeFactory, ILogFactory logFactory) - : this(app, storeFactory, logFactory, null) - { } - - public SessionFactory(IApplication app, IMessageStoreFactory storeFactory, ILogFactory logFactory, IMessageFactory messageFactory) + protected IApplication _application; + protected IMessageStoreFactory _messageStoreFactory; + protected ILogFactory _logFactory; + protected IMessageFactory _messageFactory; + protected Dictionary _dictionariesByPath = new(); + + public SessionFactory( + IApplication app, + IMessageStoreFactory storeFactory, + ILogFactory? logFactory = null, + IMessageFactory? messageFactory = null) { // TODO: for V2, consider ONLY instantiating MessageFactory in the Create() method, // and removing instance var messageFactory_ altogether. @@ -31,13 +28,13 @@ public SessionFactory(IApplication app, IMessageStoreFactory storeFactory, ILogF // and thus can't create the right FIX-Version factory because we don't know what // session to use to look up the BeginString and DefaultApplVerID. - application_ = app; - messageStoreFactory_ = storeFactory; - logFactory_ = logFactory ?? new NullLogFactory(); - messageFactory_ = messageFactory ?? new DefaultMessageFactory(); + _application = app; + _messageStoreFactory = storeFactory; + _logFactory = logFactory ?? new NullLogFactory(); + _messageFactory = messageFactory ?? new DefaultMessageFactory(); } - static private bool DetectIfInitiator(QuickFix.Dictionary settings) + private static bool DetectIfInitiator(QuickFix.Dictionary settings) { switch (settings.GetString(SessionSettings.CONNECTION_TYPE)) { @@ -47,7 +44,7 @@ static private bool DetectIfInitiator(QuickFix.Dictionary settings) throw new ConfigError("Invalid ConnectionType"); } - public Session Create(SessionID sessionID, QuickFix.Dictionary settings) + public Session Create(SessionID sessionId, QuickFix.Dictionary settings) { bool isInitiator = SessionFactory.DetectIfInitiator(settings); @@ -58,9 +55,9 @@ public Session Create(SessionID sessionID, QuickFix.Dictionary settings) if (settings.Has(SessionSettings.USE_DATA_DICTIONARY)) useDataDictionary = settings.GetBool(SessionSettings.USE_DATA_DICTIONARY); - QuickFix.Fields.ApplVerID defaultApplVerID = null; - IMessageFactory sessionMsgFactory = messageFactory_; - if (sessionID.IsFIXT) + QuickFix.Fields.ApplVerID? defaultApplVerId = null; + IMessageFactory sessionMsgFactory = _messageFactory; + if (sessionId.IsFIXT) { if (!settings.Has(SessionSettings.DEFAULT_APPLVERID)) { @@ -68,13 +65,13 @@ public Session Create(SessionID sessionID, QuickFix.Dictionary settings) } string rawDefaultApplVerIdSetting = settings.GetString(SessionSettings.DEFAULT_APPLVERID); - defaultApplVerID = Message.GetApplVerID(rawDefaultApplVerIdSetting); + defaultApplVerId = Message.GetApplVerID(rawDefaultApplVerIdSetting); // DefaultMessageFactory as created in the SessionFactory ctor cannot // tell the difference between FIX50 versions (same BeginString, unknown defaultApplVerId). // But we have the real session settings here, so we can fix that. - // This is, of course, kind of a hack, and it should be reworked in V2 (TODO!). - if (messageFactory_ is DefaultMessageFactory) + // This is, of course, kind of a hack, and it should be reworked (TODO!). + if (_messageFactory is DefaultMessageFactory) { sessionMsgFactory = new DefaultMessageFactory( FixValues.ApplVerID.FromBeginString(rawDefaultApplVerIdSetting)); @@ -84,10 +81,10 @@ public Session Create(SessionID sessionID, QuickFix.Dictionary settings) DataDictionaryProvider dd = new DataDictionaryProvider(); if (useDataDictionary) { - if (sessionID.IsFIXT) - ProcessFixTDataDictionaries(sessionID, settings, dd); + if (sessionId.IsFIXT) + ProcessFixTDataDictionaries(sessionId, settings, dd); else - ProcessFixDataDictionary(sessionID, settings, dd); + ProcessFixDataDictionary(sessionId, settings, dd); } int heartBtInt = 0; @@ -98,18 +95,18 @@ public Session Create(SessionID sessionID, QuickFix.Dictionary settings) throw new ConfigError($"{SessionSettings.HEARTBTINT} must be greater or equal to zero"); } string senderDefaultApplVerId = ""; - if(defaultApplVerID != null) - senderDefaultApplVerId = defaultApplVerID.Obj; + if(defaultApplVerId is not null) + senderDefaultApplVerId = defaultApplVerId.Obj; Session session = new Session( isInitiator, - application_, - messageStoreFactory_, - sessionID, + _application, + _messageStoreFactory, + sessionId, dd, new SessionSchedule(settings), heartBtInt, - logFactory_, + _logFactory, sessionMsgFactory, senderDefaultApplVerId); @@ -159,9 +156,8 @@ public Session Create(SessionID sessionID, QuickFix.Dictionary settings) return session; } - protected DataDictionary.DataDictionary createDataDictionary(SessionID sessionID, QuickFix.Dictionary settings, string settingsKey, string beginString) + protected DataDictionary.DataDictionary CreateDataDictionary(SessionID sessionId, QuickFix.Dictionary settings, string settingsKey, string beginString) { - DataDictionary.DataDictionary dd; string path; if (settings.Has(settingsKey)) path = settings.GetString(settingsKey); @@ -170,10 +166,11 @@ protected DataDictionary.DataDictionary createDataDictionary(SessionID sessionID path = StringUtil.FixSlashes(path); - if (!dictionariesByPath_.TryGetValue(path, out dd)) + DataDictionary.DataDictionary? dd; + if (!_dictionariesByPath.TryGetValue(path, out dd)) { dd = new DataDictionary.DataDictionary(path); - dictionariesByPath_[path] = dd; + _dictionariesByPath[path] = dd; } DataDictionary.DataDictionary ddCopy = new DataDictionary.DataDictionary(dd); @@ -190,9 +187,9 @@ protected DataDictionary.DataDictionary createDataDictionary(SessionID sessionID return ddCopy; } - protected void ProcessFixTDataDictionaries(SessionID sessionID, Dictionary settings, DataDictionaryProvider provider) + protected void ProcessFixTDataDictionaries(SessionID sessionId, Dictionary settings, DataDictionaryProvider provider) { - provider.AddTransportDataDictionary(sessionID.BeginString, createDataDictionary(sessionID, settings, SessionSettings.TRANSPORT_DATA_DICTIONARY, sessionID.BeginString)); + provider.AddTransportDataDictionary(sessionId.BeginString, CreateDataDictionary(sessionId, settings, SessionSettings.TRANSPORT_DATA_DICTIONARY, sessionId.BeginString)); foreach (KeyValuePair setting in settings) { @@ -201,29 +198,29 @@ protected void ProcessFixTDataDictionaries(SessionID sessionID, Dictionary setti if (setting.Key.Equals(SessionSettings.APP_DATA_DICTIONARY, System.StringComparison.CurrentCultureIgnoreCase)) { Fields.ApplVerID applVerId = Message.GetApplVerID(settings.GetString(SessionSettings.DEFAULT_APPLVERID)); - DataDictionary.DataDictionary dd = createDataDictionary(sessionID, settings, SessionSettings.APP_DATA_DICTIONARY, sessionID.BeginString); + DataDictionary.DataDictionary dd = CreateDataDictionary(sessionId, settings, SessionSettings.APP_DATA_DICTIONARY, sessionId.BeginString); provider.AddApplicationDataDictionary(applVerId.Obj, dd); } else { int offset = setting.Key.IndexOf('.'); if (offset == -1) - throw new System.ArgumentException(string.Format("Malformed {0} : {1}", SessionSettings.APP_DATA_DICTIONARY, setting.Key)); + throw new ArgumentException( + $"Malformed {SessionSettings.APP_DATA_DICTIONARY} : {setting.Key}"); string beginStringQualifier = setting.Key.Substring(offset); - DataDictionary.DataDictionary dd = createDataDictionary(sessionID, settings, setting.Key, beginStringQualifier); + DataDictionary.DataDictionary dd = CreateDataDictionary(sessionId, settings, setting.Key, beginStringQualifier); provider.AddApplicationDataDictionary(Message.GetApplVerID(beginStringQualifier).Obj, dd); } } } } - protected void ProcessFixDataDictionary(SessionID sessionID, Dictionary settings, DataDictionaryProvider provider) + protected void ProcessFixDataDictionary(SessionID sessionId, Dictionary settings, DataDictionaryProvider provider) { - DataDictionary.DataDictionary dataDictionary = createDataDictionary(sessionID, settings, SessionSettings.DATA_DICTIONARY, sessionID.BeginString); - provider.AddTransportDataDictionary(sessionID.BeginString, dataDictionary); - provider.AddApplicationDataDictionary(FixValues.ApplVerID.FromBeginString(sessionID.BeginString), dataDictionary); + DataDictionary.DataDictionary dataDictionary = CreateDataDictionary(sessionId, settings, SessionSettings.DATA_DICTIONARY, sessionId.BeginString); + provider.AddTransportDataDictionary(sessionId.BeginString, dataDictionary); + provider.AddApplicationDataDictionary(FixValues.ApplVerID.FromBeginString(sessionId.BeginString), dataDictionary); } - } } diff --git a/QuickFIXn/SessionState.cs b/QuickFIXn/SessionState.cs index 5563a4ada..e6524410f 100755 --- a/QuickFIXn/SessionState.cs +++ b/QuickFIXn/SessionState.cs @@ -1,3 +1,4 @@ +#nullable enable using System; using System.Collections.Generic; using MessagesBySeqNum = System.Collections.Generic.Dictionary; @@ -12,43 +13,39 @@ public class SessionState : IDisposable { #region Private Members - private object sync_ = new object(); - private bool isEnabled_ = true; - private bool receivedLogon_ = false; - private bool receivedReset_ = false; - private bool sentLogon_ = false; - private bool sentLogout_ = false; - private bool sentReset_ = false; - private string logoutReason_ = ""; - private int testRequestCounter_ = 0; - private int heartBtInt_ = 0; - private int heartBtIntAsMilliSecs_ = 0; - private DateTime lastReceivedTimeDT_ = DateTime.MinValue; - private DateTime lastSentTimeDT_ = DateTime.MinValue; - private int logonTimeout_ = 10; - private long logonTimeoutAsMilliSecs_ = 10 * 1000; - private int logoutTimeout_ = 2; - private long logoutTimeoutAsMilliSecs_ = 2 * 1000; - private ResendRange resendRange_ = new ResendRange(); - private MessagesBySeqNum msgQueue = new MessagesBySeqNum(); - - private ILog log_; + private readonly object _sync = new object(); + private bool _isEnabled = true; + private bool _receivedLogon = false; + private bool _receivedReset = false; + private bool _sentLogon = false; + private bool _sentLogout = false; + private bool _sentReset = false; + private string _logoutReason = ""; + private int _testRequestCounter = 0; + private int _heartBtInt = 0; + private int _heartBtIntAsMilliSecs = 0; + private DateTime _lastReceivedTimeDt = DateTime.MinValue; + private DateTime _lastSentTimeDt = DateTime.MinValue; + private int _logonTimeout = 10; + private long _logonTimeoutAsMilliSecs = 10 * 1000; + private int _logoutTimeout = 2; + private long _logoutTimeoutAsMilliSecs = 2 * 1000; + private readonly ResendRange _resendRange = new (); + private MessagesBySeqNum _msgQueue = new (); #endregion #region Unsynchronized Properties public IMessageStore MessageStore - { get; set; } + { get; } public bool IsInitiator { get; set; } - public bool ShouldSendLogon - { get { return IsInitiator && !SentLogon; } } + public bool ShouldSendLogon => IsInitiator && !SentLogon; - public ILog Log - { get { return log_; } } + public ILog Log { get; } #endregion @@ -56,113 +53,114 @@ public ILog Log public bool IsEnabled { - get { lock (sync_) { return isEnabled_; } } - set { lock (sync_) { isEnabled_ = value; } } + get { lock (_sync) { return _isEnabled; } } + set { lock (_sync) { _isEnabled = value; } } } public bool ReceivedLogon { - get { lock (sync_) { return receivedLogon_; } } - set { lock (sync_) { receivedLogon_ = value; } } + get { lock (_sync) { return _receivedLogon; } } + set { lock (_sync) { _receivedLogon = value; } } } public bool ReceivedReset { - get { lock (sync_) { return receivedReset_; } } - set { lock (sync_) { receivedReset_ = value; } } + get { lock (_sync) { return _receivedReset; } } + set { lock (_sync) { _receivedReset = value; } } } public bool SentLogon { - get { lock (sync_) { return sentLogon_; } } - set { lock (sync_) { sentLogon_ = value; } } + get { lock (_sync) { return _sentLogon; } } + set { lock (_sync) { _sentLogon = value; } } } public bool SentLogout { - get { lock (sync_) { return sentLogout_; } } - set { lock (sync_) { sentLogout_ = value; } } + get { lock (_sync) { return _sentLogout; } } + set { lock (_sync) { _sentLogout = value; } } } public bool SentReset { - get { lock (sync_) { return sentReset_; } } - set { lock (sync_) { sentReset_ = value; } } + get { lock (_sync) { return _sentReset; } } + set { lock (_sync) { _sentReset = value; } } } public string LogoutReason { - get { lock (sync_) { return logoutReason_; } } - set { lock (sync_) { logoutReason_ = value; } } + get { lock (_sync) { return _logoutReason; } } + set { lock (_sync) { _logoutReason = value; } } } public int TestRequestCounter { - get { lock (sync_) { return testRequestCounter_; } } - set { lock (sync_) { testRequestCounter_ = value; } } + get { lock (_sync) { return _testRequestCounter; } } + set { lock (_sync) { _testRequestCounter = value; } } } public int HeartBtInt { - get { lock (sync_) { return heartBtInt_; } } - set { lock (sync_) { heartBtInt_ = value; heartBtIntAsMilliSecs_ = 1000 * value; } } + get { lock (_sync) { return _heartBtInt; } } + set { lock (_sync) { _heartBtInt = value; _heartBtIntAsMilliSecs = 1000 * value; } } } public int HeartBtIntAsMilliSecs { - get { lock (sync_) { return heartBtIntAsMilliSecs_; } } + get { lock (_sync) { return _heartBtIntAsMilliSecs; } } } public DateTime LastReceivedTimeDT { - get { lock (sync_) { return lastReceivedTimeDT_; } } - set { lock (sync_) { lastReceivedTimeDT_ = value; } } + get { lock (_sync) { return _lastReceivedTimeDt; } } + set { lock (_sync) { _lastReceivedTimeDt = value; } } } public DateTime LastSentTimeDT { - get { lock (sync_) { return lastSentTimeDT_; } } - set { lock (sync_) { lastSentTimeDT_ = value; } } + get { lock (_sync) { return _lastSentTimeDt; } } + set { lock (_sync) { _lastSentTimeDt = value; } } } public int LogonTimeout { - get { lock (sync_) { return logonTimeout_; } } - set { lock (sync_) { logonTimeout_ = value; logonTimeoutAsMilliSecs_ = 1000 * value; } } + get { lock (_sync) { return _logonTimeout; } } + set { lock (_sync) { _logonTimeout = value; _logonTimeoutAsMilliSecs = 1000 * value; } } } public long LogonTimeoutAsMilliSecs { - get { lock (sync_) { return logonTimeoutAsMilliSecs_; } } + get { lock (_sync) { return _logonTimeoutAsMilliSecs; } } } public int LogoutTimeout { - get { lock (sync_) { return logoutTimeout_; } } - set { lock (sync_) { logoutTimeout_ = value; logoutTimeoutAsMilliSecs_ = 1000 * value; } } + get { lock (_sync) { return _logoutTimeout; } } + set { lock (_sync) { _logoutTimeout = value; _logoutTimeoutAsMilliSecs = 1000 * value; } } } public long LogoutTimeoutAsMilliSecs { - get { lock (sync_) { return logoutTimeoutAsMilliSecs_; } } + get { lock (_sync) { return _logoutTimeoutAsMilliSecs; } } } private MessagesBySeqNum MsgQueue { - get { lock (sync_) { return msgQueue; } } - set { lock (sync_) { msgQueue = value; } } + get { lock (_sync) { return _msgQueue; } } + set { lock (_sync) { _msgQueue = value; } } } #endregion - public SessionState(bool isInitiator, ILog log, int heartBtInt) + public SessionState(bool isInitiator, ILog log, int heartBtInt, IMessageStore messageStore) { - log_ = log; - this.HeartBtInt = heartBtInt; - this.IsInitiator = isInitiator; - lastReceivedTimeDT_ = DateTime.UtcNow; - lastSentTimeDT_ = DateTime.UtcNow; + Log = log; + HeartBtInt = heartBtInt; + IsInitiator = isInitiator; + _lastReceivedTimeDt = DateTime.UtcNow; + _lastSentTimeDt = DateTime.UtcNow; + MessageStore = messageStore; } /// @@ -174,11 +172,11 @@ public SessionState(bool isInitiator, ILog log, int heartBtInt) /// public static bool LogonTimedOut(DateTime now, long logonTimeout, DateTime lastReceivedTime) { - return (now.Subtract(lastReceivedTime).TotalMilliseconds) >= logonTimeout; + return now.Subtract(lastReceivedTime).TotalMilliseconds >= logonTimeout; } public bool LogonTimedOut() { - return LogonTimedOut(DateTime.UtcNow, this.LogonTimeoutAsMilliSecs, this.LastReceivedTimeDT); + return LogonTimedOut(DateTime.UtcNow, LogonTimeoutAsMilliSecs, LastReceivedTimeDT); } /// @@ -195,7 +193,7 @@ public static bool TimedOut(DateTime now, int heartBtIntMillis, DateTime lastRec } public bool TimedOut() { - return TimedOut(DateTime.UtcNow, this.HeartBtIntAsMilliSecs, this.LastReceivedTimeDT); + return TimedOut(DateTime.UtcNow, HeartBtIntAsMilliSecs, LastReceivedTimeDT); } /// @@ -208,11 +206,11 @@ public bool TimedOut() /// public static bool LogoutTimedOut(DateTime now, bool sentLogout, long logoutTimeout, DateTime lastSentTime) { - return sentLogout && ((now.Subtract(lastSentTime).TotalMilliseconds) >= logoutTimeout); + return sentLogout && (now.Subtract(lastSentTime).TotalMilliseconds >= logoutTimeout); } public bool LogoutTimedOut() { - return LogoutTimedOut(DateTime.UtcNow, this.SentLogout, this.LogoutTimeoutAsMilliSecs, this.LastSentTimeDT); + return LogoutTimedOut(DateTime.UtcNow, SentLogout, LogoutTimeoutAsMilliSecs, LastSentTimeDT); } /// @@ -230,7 +228,7 @@ public static bool NeedTestRequest(DateTime now, int heartBtIntMillis, DateTime } public bool NeedTestRequest() { - return NeedTestRequest(DateTime.UtcNow, this.HeartBtIntAsMilliSecs, this.LastReceivedTimeDT, this.TestRequestCounter); + return NeedTestRequest(DateTime.UtcNow, HeartBtIntAsMilliSecs, LastReceivedTimeDT, TestRequestCounter); } /// @@ -248,7 +246,7 @@ public static bool NeedHeartbeat(DateTime now, int heartBtIntMillis, DateTime la } public bool NeedHeartbeat() { - return NeedHeartbeat(DateTime.UtcNow, this.HeartBtIntAsMilliSecs, this.LastSentTimeDT, this.TestRequestCounter); + return NeedHeartbeat(DateTime.UtcNow, HeartBtIntAsMilliSecs, LastSentTimeDT, TestRequestCounter); } /// @@ -261,42 +259,37 @@ public bool NeedHeartbeat() /// true if within heartbeat interval public static bool WithinHeartbeat(DateTime now, int heartBtIntMillis, DateTime lastSentTime, DateTime lastReceivedTime) { - return ((now.Subtract(lastSentTime).TotalMilliseconds) < Convert.ToDouble(heartBtIntMillis)) - && ((now.Subtract(lastReceivedTime).TotalMilliseconds) < Convert.ToDouble(heartBtIntMillis)); + return (now.Subtract(lastSentTime).TotalMilliseconds < Convert.ToDouble(heartBtIntMillis)) + && (now.Subtract(lastReceivedTime).TotalMilliseconds < Convert.ToDouble(heartBtIntMillis)); } public bool WithinHeartbeat() { - return WithinHeartbeat(DateTime.UtcNow, this.HeartBtIntAsMilliSecs, this.LastSentTimeDT, this.LastReceivedTimeDT); + return WithinHeartbeat(DateTime.UtcNow, HeartBtIntAsMilliSecs, LastSentTimeDT, LastReceivedTimeDT); } public ResendRange GetResendRange() { - return resendRange_; + return _resendRange; } public void Get(SeqNumType begSeqNo, SeqNumType endSeqNo, List messages) { - lock (sync_) + lock (_sync) { MessageStore.Get(begSeqNo, endSeqNo, messages); } } - public void SetResendRange(SeqNumType begin, SeqNumType end) + public void SetResendRange(SeqNumType begin, SeqNumType end, SeqNumType chunkEnd = ResendRange.NOT_SET) { - SetResendRange(begin, end, ResendRange.NOT_SET); - } - - public void SetResendRange(SeqNumType begin, SeqNumType end, SeqNumType chunkEnd) - { - resendRange_.BeginSeqNo = begin; - resendRange_.EndSeqNo = end; - resendRange_.ChunkEndSeqNo = chunkEnd == ResendRange.NOT_SET ? end : chunkEnd; + _resendRange.BeginSeqNo = begin; + _resendRange.EndSeqNo = end; + _resendRange.ChunkEndSeqNo = chunkEnd == ResendRange.NOT_SET ? end : chunkEnd; } public bool ResendRequested() { - return !(resendRange_.BeginSeqNo == 0 && resendRange_.EndSeqNo == 0); + return !(_resendRange.BeginSeqNo == 0 && _resendRange.EndSeqNo == 0); } public void Queue(SeqNumType msgSeqNum, Message msg) @@ -312,7 +305,7 @@ public void ClearQueue() MsgQueue.Clear(); } - public QuickFix.Message Dequeue(SeqNumType num) + public QuickFix.Message? Dequeue(SeqNumType num) { if (MsgQueue.ContainsKey(num)) { @@ -323,15 +316,16 @@ public QuickFix.Message Dequeue(SeqNumType num) return null; } - public Message Retrieve(SeqNumType msgSeqNum) + public Message? Retrieve(SeqNumType msgSeqNum) { - Message msg = null; if (MsgQueue.ContainsKey(msgSeqNum)) { - msg = MsgQueue[msgSeqNum]; + Message msg = MsgQueue[msgSeqNum]; MsgQueue.Remove(msgSeqNum); + return msg; } - return msg; + + return null; } /// @@ -342,10 +336,10 @@ public override string ToString() { return new System.Text.StringBuilder("SessionState ") .Append("[ Now=").Append(DateTime.UtcNow) - .Append(", HeartBtInt=").Append(this.HeartBtIntAsMilliSecs) - .Append(", LastSentTime=").Append(this.LastSentTimeDT) - .Append(", LastReceivedTime=").Append(this.LastReceivedTimeDT) - .Append(", TestRequestCounter=").Append(this.TestRequestCounter) + .Append(", HeartBtInt=").Append(HeartBtIntAsMilliSecs) + .Append(", LastSentTime=").Append(LastSentTimeDT) + .Append(", LastReceivedTime=").Append(LastReceivedTimeDT) + .Append(", TestRequestCounter=").Append(TestRequestCounter) .Append(", WithinHeartbeat=").Append(WithinHeartbeat()) .Append(", NeedHeartbeat=").Append(NeedHeartbeat()) .Append(", NeedTestRequest=").Append(NeedTestRequest()) @@ -358,51 +352,51 @@ public override string ToString() public bool Set(SeqNumType msgSeqNum, string msg) { - lock (sync_) { return this.MessageStore.Set(msgSeqNum, msg); } + lock (_sync) { return MessageStore.Set(msgSeqNum, msg); } } public SeqNumType NextSenderMsgSeqNum { - get { lock (sync_) { return this.MessageStore.NextSenderMsgSeqNum; } } - set { lock (sync_) { this.MessageStore.NextSenderMsgSeqNum = value; } } + get { lock (_sync) { return MessageStore.NextSenderMsgSeqNum; } } + set { lock (_sync) { MessageStore.NextSenderMsgSeqNum = value; } } } public SeqNumType NextTargetMsgSeqNum { - get { lock (sync_) { return this.MessageStore.NextTargetMsgSeqNum; } } - set { lock (sync_) { this.MessageStore.NextTargetMsgSeqNum = value; } } + get { lock (_sync) { return MessageStore.NextTargetMsgSeqNum; } } + set { lock (_sync) { MessageStore.NextTargetMsgSeqNum = value; } } } public void IncrNextSenderMsgSeqNum() { - lock (sync_) { this.MessageStore.IncrNextSenderMsgSeqNum(); } + lock (_sync) { MessageStore.IncrNextSenderMsgSeqNum(); } } public void IncrNextTargetMsgSeqNum() { - lock (sync_) { this.MessageStore.IncrNextTargetMsgSeqNum(); } + lock (_sync) { MessageStore.IncrNextTargetMsgSeqNum(); } } - public System.DateTime? CreationTime + public DateTime? CreationTime { get { - lock (sync_) { return this.MessageStore.CreationTime; } + lock (_sync) { return MessageStore.CreationTime; } } } public void Reset(string reason) { - lock (sync_) + lock (_sync) { - this.MessageStore.Reset(); - this.Log.OnEvent("Session reset: " + reason); + MessageStore.Reset(); + Log.OnEvent("Session reset: " + reason); } } public void Refresh() { - lock (sync_) { this.MessageStore.Refresh(); } + lock (_sync) { MessageStore.Refresh(); } } #endregion @@ -419,14 +413,12 @@ protected virtual void Dispose(bool disposing) if (_disposed) return; if (disposing) { - if (log_ != null) { log_.Dispose(); } - if (MessageStore != null) { MessageStore.Dispose(); } + Log.Dispose(); + MessageStore.Dispose(); } _disposed = true; } ~SessionState() => Dispose(false); - } } - diff --git a/QuickFIXn/SocketReader.cs b/QuickFIXn/SocketReader.cs index 30d0397c0..4d8eb7e88 100755 --- a/QuickFIXn/SocketReader.cs +++ b/QuickFIXn/SocketReader.cs @@ -1,4 +1,5 @@ -using System.Net.Sockets; +#nullable enable +using System.Net.Sockets; using System.IO; using System; using System.Linq; @@ -13,26 +14,22 @@ public class SocketReader : IDisposable public const int BUF_SIZE = 4096; private readonly byte[] _readBuffer = new byte[BUF_SIZE]; private readonly Parser _parser = new(); - private Session _qfSession; //will be null when initialized - private readonly Stream _stream; //will be null when initialized + private Session? _qfSession; //will be null when initialized + private readonly Stream _stream; private readonly TcpClient _tcpClient; private readonly ClientHandlerThread _responder; - private readonly AcceptorSocketDescriptor _acceptorDescriptor; + private readonly AcceptorSocketDescriptor? _acceptorDescriptor; /// /// Keep a handle to the current outstanding read request (if any) /// - private IAsyncResult _currentReadRequest; - - public SocketReader(TcpClient tcpClient, SocketSettings settings, ClientHandlerThread responder) - : this(tcpClient, settings, responder, null) - { } + private IAsyncResult? _currentReadRequest; internal SocketReader( TcpClient tcpClient, SocketSettings settings, ClientHandlerThread responder, - AcceptorSocketDescriptor acceptorDescriptor) + AcceptorSocketDescriptor? acceptorDescriptor) { _tcpClient = tcpClient; _responder = responder; @@ -40,7 +37,6 @@ internal SocketReader( _stream = Transport.StreamFactory.CreateServerStream(tcpClient, settings, responder.GetLog()); } - /// FIXME public void Read() { try @@ -48,8 +44,8 @@ public void Read() int bytesRead = ReadSome(_readBuffer, 1000); if (bytesRead > 0) _parser.AddToStream(_readBuffer, bytesRead); - else if (_qfSession is not null) - _qfSession.Next(); + else + _qfSession?.Next(); ProcessStream(); } @@ -87,7 +83,7 @@ protected virtual int ReadSome(byte[] buffer, int timeoutMilliseconds) if (_currentReadRequest.IsCompleted) { - // Make sure to set currentReadRequest_ to before retreiving result + // Make sure to set _currentReadRequest to before retreiving result // so a new read can be started next time even if an exception is thrown var request = _currentReadRequest; _currentReadRequest = null; @@ -109,7 +105,7 @@ protected virtual int ReadSome(byte[] buffer, int timeoutMilliseconds) // Nothing read return 0; } - else if (inner != null) + else if (inner is not null) { throw inner; //rethrow SocketException part (which we have exception logic for) } @@ -122,27 +118,28 @@ private void OnMessageFound(string msg) { try { - if (null == _qfSession) + if (_qfSession is null) { _qfSession = Session.LookupSession(Message.GetReverseSessionId(msg)); - if (null == _qfSession) + if (_qfSession is null || IsAssumedSession(_qfSession.SessionID)) { - this.Log("ERROR: Disconnecting; received message for unknown session: " + msg); + Log("ERROR: Disconnecting; received message for unknown session: " + msg); + _qfSession = null; DisconnectClient(); return; } - else if(IsAssumedSession(_qfSession.SessionID)) + + if (_qfSession.HasResponder) { - this.Log("ERROR: Disconnecting; received message for unknown session: " + msg); + _qfSession.Log.OnIncoming(msg); + _qfSession.Log.OnEvent("Multiple logons/connections for this session are not allowed (" + _tcpClient.Client.RemoteEndPoint + ")"); _qfSession = null; DisconnectClient(); return; } - else - { - if (!HandleNewSession(msg)) - return; - } + + _qfSession.Log.OnEvent(_qfSession.SessionID + " Socket Reader " + GetHashCode() + " accepting session " + _qfSession.SessionID + " from " + _tcpClient.Client.RemoteEndPoint); + _qfSession.SetResponder(_responder); } try @@ -151,7 +148,7 @@ private void OnMessageFound(string msg) } catch (Exception e) { - this.Log("Error on Session '" + _qfSession.SessionID + "': " + e.ToString()); + Log($"Error on Session '{_qfSession.SessionID}': {e}"); } } catch (InvalidMessage e) @@ -170,12 +167,12 @@ protected void HandleBadMessage(string msg, Exception e) { if (Fields.MsgType.LOGON.Equals(Message.GetMsgType(msg))) { - this.Log("ERROR: Invalid LOGON message, disconnecting: " + e.Message); + Log("ERROR: Invalid LOGON message, disconnecting: " + e.Message); DisconnectClient(); } else { - this.Log("ERROR: Invalid message: " + e.Message); + Log("ERROR: Invalid message: " + e.Message); } } catch (InvalidMessage) @@ -207,30 +204,14 @@ protected void DisconnectClient() _tcpClient.Close(); } - protected bool HandleNewSession(string msg) - { - if (_qfSession.HasResponder) - { - _qfSession.Log.OnIncoming(msg); - _qfSession.Log.OnEvent("Multiple logons/connections for this session are not allowed (" + _tcpClient.Client.RemoteEndPoint + ")"); - _qfSession = null; - DisconnectClient(); - return false; - } - _qfSession.Log.OnEvent(_qfSession.SessionID + " Socket Reader " + GetHashCode() + " accepting session " + _qfSession.SessionID + " from " + _tcpClient.Client.RemoteEndPoint); - _qfSession.SetResponder(_responder); - return true; - } - private bool IsAssumedSession(SessionID sessionId) { - return _acceptorDescriptor != null - && !_acceptorDescriptor.GetAcceptedSessions().Any(kv => kv.Key.Equals(sessionId)); + return _acceptorDescriptor is not null + && !_acceptorDescriptor.GetAcceptedSessions().Any(kv => kv.Key.Equals(sessionId)); } - private void HandleExceptionInternal(Session quickFixSession, Exception cause) { + private void HandleExceptionInternal(Session? quickFixSession, Exception cause) { bool disconnectNeeded = false; - string reason = cause.Message; Exception realCause = cause; @@ -238,30 +219,34 @@ private void HandleExceptionInternal(Session quickFixSession, Exception cause) { if (realCause is IOException && realCause.InnerException is SocketException) realCause = realCause.InnerException; - if (realCause is SocketException) - { - if (quickFixSession != null && quickFixSession.IsEnabled) - reason = "Socket exception (" + _tcpClient.Client.RemoteEndPoint + "): " + cause.Message; - else - reason = "Socket (" + _tcpClient.Client.RemoteEndPoint + "): " + cause.Message; - disconnectNeeded = true; - } - else if (realCause is MessageParseError) - { - reason = "Protocol handler exception: " + cause; - if (quickFixSession is null) + string? reason; + switch (realCause) { + case SocketException: + { + if (quickFixSession is not null && quickFixSession.IsEnabled) + reason = "Socket exception (" + _tcpClient.Client.RemoteEndPoint + "): " + cause.Message; + else + reason = "Socket (" + _tcpClient.Client.RemoteEndPoint + "): " + cause.Message; disconnectNeeded = true; - } - else - { - reason = cause.ToString(); + break; + } + case MessageParseError: + { + reason = "Protocol handler exception: " + cause; + if (quickFixSession is null) + disconnectNeeded = true; + break; + } + default: + reason = cause.ToString(); + break; } - this.Log("SocketReader Error: " + reason); + Log($"SocketReader Error: {reason}"); if (disconnectNeeded) { - if (null != quickFixSession && quickFixSession.HasResponder) + if (quickFixSession is not null && quickFixSession.HasResponder) quickFixSession.Disconnect(reason); else DisconnectClient(); diff --git a/QuickFIXn/ThreadedSocketAcceptor.cs b/QuickFIXn/ThreadedSocketAcceptor.cs index 912ef065b..ce9993aa3 100755 --- a/QuickFIXn/ThreadedSocketAcceptor.cs +++ b/QuickFIXn/ThreadedSocketAcceptor.cs @@ -22,27 +22,6 @@ public class ThreadedSocketAcceptor : IAcceptor #region Constructors - /// - /// Create a ThreadedSocketAcceptor with a NullLogFactory and DefaultMessageFactory - /// - /// - /// - /// - public ThreadedSocketAcceptor(IApplication application, IMessageStoreFactory storeFactory, SessionSettings settings) - : this(application, storeFactory, settings, null, null) - { } - - /// - /// Create a ThreadedSocketAcceptor with a DefaultMessageFactory - /// - /// - /// - /// - /// - public ThreadedSocketAcceptor(IApplication application, IMessageStoreFactory storeFactory, SessionSettings settings, ILogFactory logFactory) - : this(application, storeFactory, settings, logFactory, null) - { } - /// /// Create a ThreadedSocketAcceptor /// @@ -55,8 +34,8 @@ public ThreadedSocketAcceptor( IApplication application, IMessageStoreFactory storeFactory, SessionSettings settings, - ILogFactory? logFactory, - IMessageFactory? messageFactory) + ILogFactory? logFactory = null, + IMessageFactory? messageFactory = null) { ILogFactory lf = logFactory ?? new NullLogFactory(); IMessageFactory mf = messageFactory ?? new DefaultMessageFactory(); @@ -197,7 +176,6 @@ private void LogoutAllSessions(bool force) } catch (Exception e) { - // FIXME logError(session.getSessionID(), "Error during logout", e); System.Console.WriteLine("Error during logout of Session " + session.SessionID + ": " + e.Message); } } @@ -213,7 +191,6 @@ private void LogoutAllSessions(bool force) } catch (Exception e) { - // FIXME logError(session.getSessionID(), "Error during disconnect", e); System.Console.WriteLine("Error during disconnect of Session " + session.SessionID + ": " + e.Message); } } diff --git a/QuickFIXn/ThreadedSocketReactor.cs b/QuickFIXn/ThreadedSocketReactor.cs index 012e66539..17b54215c 100755 --- a/QuickFIXn/ThreadedSocketReactor.cs +++ b/QuickFIXn/ThreadedSocketReactor.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +#nullable enable +using System.Collections.Generic; using System.Net; using System.Net.Sockets; using System.Threading; @@ -20,98 +21,101 @@ public enum State { RUNNING, SHUTDOWN_REQUESTED, SHUTDOWN_COMPLETE } public State ReactorState { - get { lock (sync_) { return state_; } } + get { lock (_sync) { return _state; } } } #endregion #region Private Members - private object sync_ = new object(); - private State state_ = State.RUNNING; - private long nextClientId_ = 0; - private Thread serverThread_ = null; - private Dictionary clientThreads_ = new Dictionary(); - private TcpListener tcpListener_; - private SocketSettings socketSettings_; - private QuickFix.Dictionary sessionDict_; - private IPEndPoint serverSocketEndPoint_; - private readonly AcceptorSocketDescriptor acceptorDescriptor_; + private readonly object _sync = new (); + private State _state = State.RUNNING; + private long _nextClientId = 0; + private Thread? _serverThread = null; + private readonly Dictionary _clientThreads = new (); + private readonly TcpListener _tcpListener; + private readonly SocketSettings _socketSettings; + private readonly QuickFix.Dictionary _sessionDict; + private readonly IPEndPoint _serverSocketEndPoint; + private readonly AcceptorSocketDescriptor? _acceptorSocketDescriptor; #endregion - public ThreadedSocketReactor(IPEndPoint serverSocketEndPoint, SocketSettings socketSettings, - QuickFix.Dictionary sessionDict) : this(serverSocketEndPoint, socketSettings, sessionDict, null) - { - + public ThreadedSocketReactor( + IPEndPoint serverSocketEndPoint, + SocketSettings socketSettings, + QuickFix.Dictionary sessionDict + ) : this(serverSocketEndPoint, socketSettings, sessionDict, null) { } - internal ThreadedSocketReactor(IPEndPoint serverSocketEndPoint, SocketSettings socketSettings, QuickFix.Dictionary sessionDict, AcceptorSocketDescriptor acceptorDescriptor) + + internal ThreadedSocketReactor( + IPEndPoint serverSocketEndPoint, + SocketSettings socketSettings, + QuickFix.Dictionary sessionDict, + AcceptorSocketDescriptor? acceptorSocketDescriptor) { - socketSettings_ = socketSettings; - serverSocketEndPoint_ = serverSocketEndPoint; - tcpListener_ = new TcpListener(serverSocketEndPoint_); - sessionDict_ = sessionDict; - acceptorDescriptor_ = acceptorDescriptor; + _socketSettings = socketSettings; + _serverSocketEndPoint = serverSocketEndPoint; + _tcpListener = new TcpListener(_serverSocketEndPoint); + _sessionDict = sessionDict; + _acceptorSocketDescriptor = acceptorSocketDescriptor; } public void Start() { - lock (sync_) + lock (_sync) { - if (state_ == State.RUNNING && serverThread_ == null) + if (_state == State.RUNNING && _serverThread is null) { - serverThread_ = new Thread(Run); - serverThread_.Start(); + _serverThread = new Thread(Run); + _serverThread.Start(); } } } public void Shutdown() { - lock (sync_) + lock (_sync) { - if (State.RUNNING == state_) + if (State.RUNNING == _state) { try { - state_ = State.SHUTDOWN_REQUESTED; + _state = State.SHUTDOWN_REQUESTED; using (TcpClient killer = new TcpClient()) { try { - IPEndPoint killerEndPoint = new IPEndPoint(IPAddress.Loopback, serverSocketEndPoint_.Port); + IPEndPoint killerEndPoint = new IPEndPoint(IPAddress.Loopback, _serverSocketEndPoint.Port); killer.Connect(killerEndPoint); } - catch (System.Exception e) + catch (Exception e) { - this.Log("Tried to interrupt server socket but was already closed: " + e.Message); + Log("Tried to interrupt server socket but was already closed: " + e.Message); } } } - catch (System.Exception e) + catch (Exception e) { - this.Log("Error while closing server socket: " + e.Message); + Log("Error while closing server socket: " + e.Message); } } } } - /// - /// TODO apply networking options, e.g. NO DELAY, LINGER, etc. - /// public void Run() { - lock (sync_) + lock (_sync) { - if (State.SHUTDOWN_REQUESTED != state_) + if (State.SHUTDOWN_REQUESTED != _state) { try { - tcpListener_.Start(); + _tcpListener.Start(); } catch(Exception e) { - this.Log("Error starting listener: " + e.Message); + Log("Error starting listener: " + e.Message); throw; } } @@ -121,16 +125,16 @@ public void Run() { try { - TcpClient client = tcpListener_.AcceptTcpClient(); + TcpClient client = _tcpListener.AcceptTcpClient(); if (State.RUNNING == ReactorState) { - ApplySocketOptions(client, socketSettings_); + ApplySocketOptions(client, _socketSettings); ClientHandlerThread t = - new ClientHandlerThread(client, nextClientId_++, sessionDict_, socketSettings_, acceptorDescriptor_); + new ClientHandlerThread(client, _nextClientId++, _sessionDict, _socketSettings, _acceptorSocketDescriptor); t.Exited += OnClientHandlerThreadExited; - lock (sync_) + lock (_sync) { - clientThreads_.Add(t.Id, t); + _clientThreads.Add(t.Id, t); } // FIXME set the client thread's exception handler here @@ -142,27 +146,25 @@ public void Run() client.Dispose(); } } - catch (System.Exception e) + catch (Exception e) { if (State.RUNNING == ReactorState) - this.Log("Error accepting connection: " + e.Message); + Log("Error accepting connection: " + e.Message); } } - tcpListener_.Server.Close(); - tcpListener_.Stop(); + _tcpListener.Server.Close(); + _tcpListener.Stop(); ShutdownClientHandlerThreads(); } internal void OnClientHandlerThreadExited(object sender, ClientHandlerThread.ExitedEventArgs e) { - lock(sync_) + lock(_sync) { - ClientHandlerThread t = null; - if(clientThreads_.TryGetValue(e.ClientHandlerThread.Id, out t)) + if(_clientThreads.TryGetValue(e.ClientHandlerThread.Id, out var t)) { - clientThreads_.Remove(t.Id); + _clientThreads.Remove(t.Id); t.Dispose(); - t = null; } } } @@ -196,13 +198,13 @@ public static void ApplySocketOptions(TcpClient client, SocketSettings socketSet private void ShutdownClientHandlerThreads() { - lock (sync_) + lock (_sync) { - if (State.SHUTDOWN_COMPLETE != state_) + if (State.SHUTDOWN_COMPLETE != _state) { - this.Log("shutting down..."); + Log("shutting down..."); - foreach (ClientHandlerThread t in clientThreads_.Values) + foreach (ClientHandlerThread t in _clientThreads.Values) { t.Exited -= OnClientHandlerThreadExited; t.Shutdown("reactor is shutting down"); @@ -210,14 +212,14 @@ private void ShutdownClientHandlerThreads() { t.Join(); } - catch (System.Exception e) + catch (Exception e) { t.Log("Error shutting down: " + e.Message); } t.Dispose(); } - clientThreads_.Clear(); - state_ = State.SHUTDOWN_COMPLETE; + _clientThreads.Clear(); + _state = State.SHUTDOWN_COMPLETE; } } } @@ -228,7 +230,7 @@ private void ShutdownClientHandlerThreads() /// private void Log(string s) { - System.Console.WriteLine(s); + Console.WriteLine(s); } } } diff --git a/QuickFIXn/Transport/SocketInitiator.cs b/QuickFIXn/Transport/SocketInitiator.cs index 68cc47ab7..af1b5dc51 100755 --- a/QuickFIXn/Transport/SocketInitiator.cs +++ b/QuickFIXn/Transport/SocketInitiator.cs @@ -225,32 +225,28 @@ protected override void OnStop() _shutdownRequested = true; } - protected override void DoConnect(SessionID sessionId, Dictionary settings) + protected override void DoConnect(Session session, Dictionary settings) { - Session? session = null; - try { - session = Session.LookupSession(sessionId); if (!session.IsSessionTime) return; - IPEndPoint socketEndPoint = GetNextSocketEndPoint(sessionId, settings); - SetPending(sessionId); - session.Log.OnEvent("Connecting to " + socketEndPoint.Address + " on port " + socketEndPoint.Port); + IPEndPoint socketEndPoint = GetNextSocketEndPoint(session.SessionID, settings); + SetPending(session.SessionID); + session.Log.OnEvent($"Connecting to {socketEndPoint.Address} on port {socketEndPoint.Port}"); //Setup socket settings based on current section var socketSettings = _socketSettings.Clone(); socketSettings.Configure(settings); // Create a Ssl-SocketInitiatorThread if a certificate is given - SocketInitiatorThread t = new SocketInitiatorThread(this, session, socketEndPoint, socketSettings); + SocketInitiatorThread t = new SocketInitiatorThread(this, session, socketEndPoint, socketSettings); t.Start(); AddThread(t); - } catch (Exception e) { - session?.Log.OnEvent(e.Message); + session.Log.OnEvent(e.Message); } } diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 2ae7cc0c1..e4d27b1a9 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -35,6 +35,13 @@ What's New (Message no longer stores a DD instance var.) These functions are new, probably not widely used yet. Function docs are now clear on this behavior. +* #826 - cleanup/nullable-ize Socket & Session classes (gbirchmeier) + * ClientHandlerThread is now internal. Unlikely anyone will notice. + * SocketReader: delete public ctor. Probably no one is using it. + * Session: rename (capitalize) TargetDefaultApplVerId property + * Session: Logon() and Logout() made internal and renamed. No one should be using these. + * SessionState: ctor now requires a MessageStore. (Existing callers used an object initializer anyway) + * Many protected functions were altered, but probably no user code is touching them **Non-breaking changes** * #400 - added DDTool, a C#-based codegen, and deleted Ruby-based generator (gbirchmeier) diff --git a/UnitTests/SessionStateTest.cs b/UnitTests/SessionStateTest.cs index d16747b06..28722cff2 100755 --- a/UnitTests/SessionStateTest.cs +++ b/UnitTests/SessionStateTest.cs @@ -152,7 +152,7 @@ public void ThreadSafeSetAndGet() { NullLog log = new NullLog(); //Set up sessionstate - SessionState state = new SessionState(true, log, 1) {MessageStore = store}; + SessionState state = new SessionState(true, log, 1, store); Hashtable errorsTable = Hashtable.Synchronized(new Hashtable());//used in more than 1 thread at a time Hashtable setTable = new Hashtable(1000);//only used in 1 thread at a time