/// <summary> /// Initializes <see cref="OutputAdapterBase"/>. /// </summary> public override void Initialize() { base.Initialize(); Dictionary <string, string> settings = Settings; string setting; // Load optional parameters if (settings.TryGetValue("inputSourceIDs", out setting) || settings.TryGetValue("sourceids", out setting)) { InputSourceIDs = setting.Split(','); } else { InputSourceIDs = null; } if (settings.TryGetValue("requeueOnException", out setting)) { RequeueOnException = setting.ParseBoolean(); } // Start data monitor... if (m_monitorTimer != null) { m_monitorTimer.Start(); } }
/// <summary> /// Handles the confirmation message received from the /// subscriber to indicate that a buffer block was received. /// </summary> /// <param name="sequenceNumber">The sequence number of the buffer block.</param> /// <returns>A list of buffer block sequence numbers for blocks that need to be retransmitted.</returns> public void ConfirmBufferBlock(uint sequenceNumber) { DataPublisher parent = m_parent; int sequenceIndex; int removalCount; // We are still receiving confirmations, // so stop the retransmission timer m_bufferBlockRetransmissionTimer.Stop(); lock (m_bufferBlockCacheLock) { // Find the buffer block's location in the cache sequenceIndex = (int)(sequenceNumber - m_expectedBufferBlockConfirmationNumber); if (sequenceIndex >= 0 && sequenceIndex < m_bufferBlockCache.Count && (object)m_bufferBlockCache[sequenceIndex] != null) { // Remove the confirmed block from the cache m_bufferBlockCache[sequenceIndex] = null; if (sequenceNumber == m_expectedBufferBlockConfirmationNumber) { // Get the number of elements to trim from the start of the cache removalCount = m_bufferBlockCache.TakeWhile(m => (object)m == null).Count(); // Trim the cache m_bufferBlockCache.RemoveRange(0, removalCount); // Increase the expected confirmation number m_expectedBufferBlockConfirmationNumber += (uint)removalCount; } else { // Retransmit if confirmations are received out of order for (int i = 0; i < sequenceIndex; i++) { if ((object)m_bufferBlockCache[i] != null) { parent?.SendClientResponse(m_clientID, ServerResponse.BufferBlock, ServerCommand.Subscribe, m_bufferBlockCache[i]); OnBufferBlockRetransmission(); } } } } // If there are any objects lingering in the // cache, start the retransmission timer if (m_bufferBlockCache.Count > 0) { m_bufferBlockRetransmissionTimer.Start(); } } }
private void m_dataChannel_ServerStopped(object sender, EventArgs e) { if (m_connectionEstablished) { m_parent.OnStatusMessage(MessageLevel.Info, "Data channel stopped unexpectedly, restarting data channel..."); if ((object)m_reconnectTimer != null) { m_reconnectTimer.Start(); } } else { m_parent.OnStatusMessage(MessageLevel.Info, "Data channel stopped."); } }
/// <summary> /// Creates a new <see cref="SubscriberConnection"/> instance. /// </summary> /// <param name="parent">Parent data publisher.</param> /// <param name="clientID">Client ID of associated connection.</param> /// <param name="serverCommandChannel"><see cref="TcpServer"/> command channel used to lookup connection information.</param> /// <param name="clientCommandChannel"><see cref="TcpClient"/> command channel used to lookup connection information.</param> public SubscriberConnection(DataPublisher parent, Guid clientID, IServer serverCommandChannel, IClient clientCommandChannel) { m_parent = parent; ClientID = clientID; ServerCommandChannel = serverCommandChannel; ClientCommandChannel = clientCommandChannel; m_subscriberID = clientID; m_keyIVs = null; m_cipherIndex = 0; CacheUpdateLock = new(); PendingCacheUpdateLock = new(); // Setup ping timer m_pingTimer = Common.TimerScheduler.CreateTimer(5000); m_pingTimer.AutoReset = true; m_pingTimer.Elapsed += PingTimer_Elapsed; m_pingTimer.Start(); // Setup reconnect timer m_reconnectTimer = Common.TimerScheduler.CreateTimer(1000); m_reconnectTimer.AutoReset = false; m_reconnectTimer.Elapsed += ReconnectTimer_Elapsed; LookupEndPointInfo(clientID, GetCommandChannelSocket().RemoteEndPoint as IPEndPoint, ref m_ipAddress, ref m_hostName, ref m_connectionID); }
/// <summary> /// Connects to the <see cref="FileStream"/>. /// </summary> private void OpenFile() { int connectionAttempts = 0; while (MaxConnectionAttempts == -1 || connectionAttempts < MaxConnectionAttempts) { try { OnConnectionAttempt(); // Open the file. m_fileClient.Provider = new FileStream(FilePath.GetAbsolutePath(m_connectData["file"]), m_fileOpenMode, m_fileAccessMode, m_fileShareMode); // Move to the specified offset. m_fileClient.Provider.Seek(m_startingOffset, SeekOrigin.Begin); m_connectionHandle.Set(); OnConnectionEstablished(); if (!m_receiveOnDemand) { if (m_receiveInterval > 0) { // Start receiving data at interval. m_receiveDataTimer.Interval = m_receiveInterval; m_receiveDataTimer.Start(); } else { // Start receiving data continuously. while (true) { ReadData(); // Read all available data. Thread.Sleep(1000); // Wait for more data to be available. } } } break; // We're done here. } catch (Exception ex) { // Keep retrying connecting to the file. Thread.Sleep(1000); connectionAttempts++; OnConnectionException(ex); } } }
/// <summary> /// Starts the <see cref="UnsynchronizedClientSubscription"/> or restarts it if it is already running. /// </summary> public override void Start() { if (!Enabled) { m_startTimeSent = false; } // Reset compressor on successful resubscription m_resetTsscEncoder = true; base.Start(); if ((object)m_baseTimeRotationTimer != null && m_includeTime) { m_baseTimeRotationTimer.Start(); } }
/// <summary> /// Creates a new <see cref="ClientConnection"/> instance. /// </summary> /// <param name="parent">Parent data publisher.</param> /// <param name="clientID">Client ID of associated connection.</param> /// <param name="commandChannel"><see cref="TcpServer"/> command channel used to lookup connection information.</param> public ClientConnection(DataPublisher parent, Guid clientID, IServer commandChannel) { m_parent = parent; m_clientID = clientID; m_commandChannel = commandChannel; m_subscriberID = clientID; m_keyIVs = null; m_cipherIndex = 0; // Setup ping timer m_pingTimer = Common.TimerScheduler.CreateTimer(5000); m_pingTimer.AutoReset = true; m_pingTimer.Elapsed += m_pingTimer_Elapsed; m_pingTimer.Start(); // Setup reconnect timer m_reconnectTimer = Common.TimerScheduler.CreateTimer(1000); m_reconnectTimer.AutoReset = false; m_reconnectTimer.Elapsed += m_reconnectTimer_Elapsed; // Attempt to lookup remote connection identification for logging purposes try { Socket commandChannelSocket = GetCommandChannelSocket(); IPEndPoint remoteEndPoint = null; if ((object)commandChannel != null) { remoteEndPoint = commandChannelSocket.RemoteEndPoint as IPEndPoint; } if ((object)remoteEndPoint != null) { m_ipAddress = remoteEndPoint.Address; if (remoteEndPoint.AddressFamily == AddressFamily.InterNetworkV6) { m_connectionID = "[" + m_ipAddress + "]:" + remoteEndPoint.Port; } else { m_connectionID = m_ipAddress + ":" + remoteEndPoint.Port; } try { IPHostEntry ipHost = Dns.GetHostEntry(remoteEndPoint.Address); if (!string.IsNullOrWhiteSpace(ipHost.HostName)) { m_hostName = ipHost.HostName; m_connectionID = m_hostName + " (" + m_connectionID + ")"; } } // Just ignoring possible DNS lookup failures... catch (ArgumentNullException) { // The hostNameOrAddress parameter is null. } catch (ArgumentOutOfRangeException) { // The length of hostNameOrAddress parameter is greater than 255 characters. } catch (ArgumentException) { // The hostNameOrAddress parameter is an invalid IP address. } catch (SocketException) { // An error was encountered when resolving the hostNameOrAddress parameter. } } } catch { // At worst we'll just use the client GUID for identification m_connectionID = m_subscriberID == Guid.Empty ? clientID.ToString() : m_subscriberID.ToString(); } if (string.IsNullOrWhiteSpace(m_connectionID)) { m_connectionID = "unavailable"; } if (string.IsNullOrWhiteSpace(m_hostName)) { if ((object)m_ipAddress != null) { m_hostName = m_ipAddress.ToString(); } else { m_hostName = m_connectionID; } } if ((object)m_ipAddress == null) { m_ipAddress = IPAddress.None; } }