Exemple #1
0
        /// <summary>
        /// Pushes a new AIC-Message to the client.
        /// </summary>
        /// <param name="alarms">The list of active alarms.</param>
        /// <param name="wasConnectionState">The WAS connection-state.</param>
        /// <param name="type">The type of message (request or response).</param>
        private void PushAicMessage(List <Alarm> alarms, bool wasConnectionState, MessageType type)
        {
            if (this.mTcpClient == null || !this.mTcpClient.IsConnected())
            {
                this.mLogger.LogWarning(string.Format("Can't push message because TCP-Client (IP: {0}) has already gone", this.ClientAddress), WarningType.ClientSession_CantPushMessage);
                return;
            }

            AicMessage message = new AicMessage
            {
                Alarms = alarms,
                ConnectionWasToServerOk = wasConnectionState,
                MessageType             = type
            };

            try
            {
                message.Serialize(this.mTcpClient.GetStream().GetUnderlyingStream());
                this.mLogger.LogInformation(string.Format("New {0}-push to client (IP: {1}) performed", type, this.ClientAddress), InformationType.ClientSession_PerformedPush);
            }

            catch (Exception ex)
            {
                this.mLogger.LogError("(ClientSession/PushNewState/Exception)", ErrorType.Undefined, ex);
            }
        }
Exemple #2
0
        /// <summary>
        /// Checks if two AicMessage objects have the same values.
        /// </summary>
        /// <param name="other">Another AicMessage.</param>
        /// <returns>True if the values are equal.</returns>
        public bool Equals(AicMessage other)
        {
            if (ReferenceEquals(null, other))
            {
                return(false);
            }
            if (ReferenceEquals(this, other))
            {
                return(true);
            }

            return(MessageType == other.MessageType &&
                   ConnectionWasToServerOk == other.ConnectionWasToServerOk &&
                   Alarms.SequenceEqual(other.Alarms));
        }
Exemple #3
0
        /// <summary>
        /// Sends the KeepAlive-Message to the client to avoid dirty connection states.
        /// </summary>
        private void SendKeepAliveMessage()
        {
            try
            {
                AicMessage message = new AicMessage
                {
                    Alarms = new List <Alarm>(),
                    ConnectionWasToServerOk = true,
                    MessageType             = MessageType.KeepAlive
                };

                message.Serialize(this.mTcpClient.GetStream().GetUnderlyingStream());
            }

            catch (Exception ex)
            {
                this.mLogger.LogError("(ClientListener/SendKeepAliveMessage/Exception)", ErrorType.Undefined, ex);
            }
        }
Exemple #4
0
        /// <summary>
        /// Method for handling the connection (requests / responses) with the client. You must not call this method twice or after the session got destroyed.
        /// In case the connection to the client got broken, the session will destroy itself.
        /// </summary>
        private void SessionHandling(object state)
        {
            CancellationToken cancellationToken = (CancellationToken)state;

            System.Timers.Timer timer = null;

            this.PushNewState();

            try
            {
                timer          = new System.Timers.Timer(this.mClientKeepAliveTimeout.TotalMilliseconds);
                timer.Elapsed += delegate { SendKeepAliveMessage(); };
                timer.Start();

                while (!cancellationToken.IsCancellationRequested)
                {
                    // Wait while there's no request from the client and check if the connection got refused / broken
                    while (!this.mTcpClient.GetStream().DataAvailable)
                    {
                        cancellationToken.ThrowIfCancellationRequested();

                        Thread.Sleep(Constants.ClientCycleTimeout);

                        // Check connection
                        if (!this.mTcpClient.IsConnected())
                        {
                            throw new SocketException((int)SocketError.ConnectionReset);
                        }

                        // If a response after a push is pending
                        if (this.mPushAckPending)
                        {
                            this.mAckCycleTimeElapsed += Constants.ClientCycleTimeout;

                            // Appropriate amount of time is over - now send a request again
                            if (this.mAckCycleTimeElapsed >= Constants.NetworkTimeout)
                            {
                                this.PushAicMessage(this.mGetAlarmList(), this.mGetWasConnectionState(), MessageType.Request);
                                this.mAckCycleTimeElapsed = 0;
                                this.mPushRetryCount++;

                                this.mLogger.LogWarning(
                                    string.Format("No response from client yet (IP: {0}). Retry {1} from {2}", this.ClientAddress, mPushRetryCount, Constants.MaxPushRetry),
                                    WarningType.ClientSession_NoClientResponse);

                                // No response after several retries
                                if (this.mPushRetryCount == Constants.MaxPushRetry)
                                {
                                    this.mLogger.LogError(string.Format("No response-message after {0} retries", Constants.MaxPushRetry), ErrorType.ClientSession_NoClientResponse);
                                    throw new AicException(string.Format("No response-message after {0} retries", Constants.MaxPushRetry), AicExceptionType.ClientSession_NoClientResponse);
                                }
                            }
                        }
                    }

                    AicMessage message = null;

                    try
                    {
                        using (MemoryStream memoryStream = this.mTcpClient.ReadNetworkStream(AicMessage.XmlEndTagRegex))
                        {
                            memoryStream.Position = 0;
                            message = AicMessage.Deserialize(memoryStream);
                        }
                    }

                    catch (Exception ex)
                    {
                        this.mLogger.LogError("(ClientSession/SessionHandling/Exception)", ErrorType.Undefined, ex);
                    }

                    if (message == null)
                    {
                        continue;
                    }

                    else if (message.MessageType == MessageType.Request)
                    {
                        this.mLogger.LogInformation(string.Format("Request from client (IP: {0})", this.ClientAddress), InformationType.ClientSession_ReceivedRequest);

                        PushAicMessage(this.mGetAlarmList(), this.mGetWasConnectionState(), MessageType.Response);
                    }

                    else if (message.MessageType == MessageType.Response)
                    {
                        this.mLogger.LogInformation(string.Format("Response from client (IP: {0})", this.ClientAddress), InformationType.ClientSession_ReceivedResponse);

                        lock (this.mLocker)
                        {
                            this.mPushAckPending = false;
                            this.mPushRetryCount = 0;

                            Monitor.Pulse(this.mLocker);
                        }
                    }

                    else if (message.MessageType == MessageType.KeepAlive)
                    {
                        this.mLogger.LogInformation(string.Format("Keep-Alive from client (IP: {0})", this.ClientAddress), InformationType.ClientSession_ReceivedKeepAlive);
                    }

                    else
                    {
                        this.mLogger.LogError(string.Format("Message type '{0}' isn't defined", message.MessageType), ErrorType.ClientSession_UnknownMessageType);
                        throw new AicException(string.Format("Message type '{0}' isn't defined", message.MessageType), AicExceptionType.ClientSession_UnknownMessageType);
                    }
                }
            }

            catch (OperationCanceledException)
            {
                this.mLogger.LogInformation(string.Format("Thread handling connection with client (IP: {0}) canceled", this.ClientAddress), InformationType.ClientSession_ThreadCanceled);
            }

            catch (SocketException ex)
            {
                if (ex.SocketErrorCode == SocketError.ConnectionReset)
                {
                    this.mLogger.LogInformation(string.Format("Stopped listening to client (IP: {0})", this.ClientAddress), InformationType.ClientSession_StoppedListening);
                }

                else
                {
                    this.mLogger.LogError("(ClientSession/SessionHandling/SocketException)", ErrorType.UnknownSocketException, ex);
                }
            }

            catch (Exception ex)
            {
                this.mLogger.LogError("(ClientSession/SessionHandling/Exception)", ErrorType.Undefined, ex);
            }

            finally
            {
                if (timer != null)
                {
                    timer.Dispose();
                }

                lock (this.mLocker)
                {
                    if (!this.SessionDestroyed)
                    {
                        this.DestroySession(true, false);
                    }
                }
            }
        }
 /// <summary>
 /// Initializes a new instance of the MessageReceivedEventArgs class.
 /// </summary>
 /// <param name="aicMessage">The received AicMessage.</param>
 public MessageReceivedEventArgs(AicMessage aicMessage)
 {
     AicMessage = aicMessage;
 }
        /// <summary>
        /// Starts listening to the WAS.
        /// <exception cref="InvalidOperationException">Thrown when the WAS listener is running.</exception>
        /// <exception cref="InvalidOperationException">Thrown when the reconnect process is currently running.</exception>
        /// <exception cref="AicException">If the ping to the WAS failed.</exception>
        /// </summary>
        public void StartWasListening()
        {
            lock (this.mLockerObject)
            {
                if (this.IsWasListenerRunning)
                {
                    this.mLogger.LogError("WAS listener is already running", ErrorType.ListeningManager_WasListenerAlreadyRunning);
                    throw new InvalidOperationException("WAS listener is already running");
                }

                if (this.mIsWasReconnectRunning)
                {
                    this.mLogger.LogError("The WAS reconnect process is currently running", ErrorType.ListeningManager_WasReconnectCurrentlyRunning);
                    throw new InvalidOperationException("The WAS reconnect process is currently running");
                }

                // Check if the WAS can be pinged
                if (!Network.PingAddress(AicSettings.Global.WasIp))
                {
                    this.mLogger.LogWarning("WAS can't be pinged", WarningType.ListeningManager_CantPingWas);
                    throw new AicException("WAS can't be pinged", AicExceptionType.ListeningManager_CantPingWas);
                }

                try
                {
                    // isShutdown: True if the broken connection is forced (due to shutdown)
                    this.mWasListener.WasConnectionStateChanged += delegate(bool connected, bool isShutdown)
                    {
                        this.mLogger.LogInformation(string.Format("WAS connection-state changed (Connected: {0} - Shutdown: {1})", connected, isShutdown), InformationType.ListeningManager_WasConnectionStateChanged);

                        lock (this.mLockerObject)
                        {
                            this.mIsWasListenerRunning = connected;

                            if (this.WasConnectionStateChanged != null)
                            {
                                this.WasConnectionStateChanged(connected);
                            }

                            if (MessageReceived != null)
                            {
                                var aicMessage = new AicMessage {
                                    Alarms = mAlarmState.Alarms, ConnectionWasToServerOk = connected
                                };
                                var args = new MessageReceivedEventArgs(aicMessage);
                                MessageReceived(null, args);
                            }

                            if (!connected && !isShutdown)
                            {
                                // Broken connection (not forced)
                                this.mLogger.LogWarning("WAS connection got broken", WarningType.ListeningManager_BrokenWasConnection);
                                this.TryWASReconnect();
                            }
                        }

                        if (this.mClientListener != null)
                        {
                            // Push new state of the backend to the clients
                            this.mClientListener.PushNewState();
                        }
                    };

                    this.mWasListener.WasObjectChanged += delegate(WasObject obj)
                    {
                        this.mLogger.LogInformation("New WAS-Data available", InformationType.ListeningManager_NewWasDataAvailable);

                        this.mAlarmState.UpdateAlarmObject(obj);

                        if (this.AlarmsChanged != null)
                        {
                            this.AlarmsChanged(this.mAlarmState.Alarms);
                        }

                        if (MessageReceived != null)
                        {
                            var aicMessage = new AicMessage {
                                Alarms = mAlarmState.Alarms, ConnectionWasToServerOk = true
                            };
                            var args = new MessageReceivedEventArgs(aicMessage);
                            MessageReceived(null, args);
                        }

                        if (AicSettings.Global.UploadEnabled)
                        {
                            this.mAlarmState.Alarms.ForEach(alarm =>
                                                            AlarmSend.SendAsync(AicSettings.Global.UploadUrl, alarm, (id, ex) => { this.mLogger.LogError("Error while uploading alarm (ID:" + id + ")!", ex); }));
                        }

                        if (this.mClientListener != null)
                        {
                            this.mClientListener.PushNewState();
                        }
                    };

                    this.mWasListener.StartListening();

                    this.mIsWasListenerRunning = true;
                }

                catch (Exception ex)
                {
                    this.mLogger.LogError("(ListeningManager/StartWasListening/Exception)", ErrorType.Undefined, ex);
                    throw ex;
                }
            }
        }