/// <summary> /// Transmit message via TCP. /// </summary> /// <param name="message">Message to send via TCP.</param> /// <returns></returns> private bool TransmitMessage(NiawaNetMessage message) { bool succeeded = false; System.Net.Sockets.NetworkStream stream = null; /* //attempt lock bool tryLock = lockSection.WaitOne(60000); if (!tryLock) throw new TimeoutException("[" + _logInstanceName + "-T] Could not obtain lock while sending message"); */ try { //send message Byte[] messageBytes = message.ToByteArray(); //set message length Byte[] messageLengthBytes = BitConverter.GetBytes((int)messageBytes.Length); //set message type Byte[] messageTypeBytes = BitConverter.GetBytes((int)NiawaNetMessage.MSG_TYPE_NIAWA_NET_MESSAGE); //get stream //stream = _netClient.GetStream(); stream = new System.Net.Sockets.NetworkStream(_netClientSocket); //write len bytes stream.Write(messageLengthBytes, 0, 4); //write msg type bytes stream.Write(messageTypeBytes, 0, 4); //write msg data bytes stream.Write(messageBytes, 0, messageBytes.Length); stream.Flush(); //messageInProgressGuid = string.Empty; succeeded = true; logger.Info("[" + _description + "-T] Message sent: Type [" + message.MessageType + "] SerialID [" + message.SerialID + "] Guid [" + message.Guid.ToString() + "]"); //ipcLoggerMsg.Write("SentMessage", "[" + _logInstanceName + "]: " + message.MessageContents); _evtRaiser.RaiseEvent("Message", "Message Sent [" + message.SerialID + "]" , Niawa.Utilities.InlineSortedListCreator.CreateStrStr("NiawaNetMessage", message.ToJson()) , _threadStatus.NodeID , _threadStatus.ParentNodeID); _threadStatus.MessageCount += 1; } catch (Exception ex) { logger.Error("[" + _description + "-M] Error while transmitting message: " + ex.Message, ex); throw ex; } finally { if(stream!=null) stream.Close(); /* //release lock lockSection.Release(); */ } return succeeded; }
/// <summary> /// Loop thread that receives TCP messages and adds items to the receive queue. /// </summary> /// <param name="data"></param> private void ListenThreadImpl(object data) { _threadStatus.IsThreadActive = true; logger.Info("[" + _description + "-T] Receiver active"); try { while (_threadStatus.IsThreadEnabled) { _threadStatus.ThreadHealthDate = DateTime.Now; //listening bool receivingMessage = false; try { logger.Info("[" + _description + "-T] Waiting for network data"); //wait for data System.Net.Sockets.TcpClient netClient = _netListener.AcceptTcpClient(); logger.Info("[" + _description + "-T] Received network data"); receivingMessage = true; //attempt lock bool tryLock = lockSection.WaitOne(60000); if (!tryLock) throw new TimeoutException("[" + _description + "-T] Could not obtain lock while receiving message"); try { //get stream System.Net.Sockets.NetworkStream stream = netClient.GetStream(); bool atLeastOneMessageRead = false; bool doneReading = false; while (!doneReading) { byte[] msgLengthBytes = new byte[4]; byte[] msgTypeBytes = new byte[4]; int msgLength = 0; int msgType = 0; //read len bytes int msgLengthBytesLen = stream.Read(msgLengthBytes, 0, 4); if (msgLengthBytesLen != 4) { //0 bytes is expected (end of stream). if (msgLengthBytesLen != 0 || !atLeastOneMessageRead) { logger.Warn("[" + _description + "-T] Incorrect data size in buffer while reading message length. Expected [4] bytes. Received [" + msgLengthBytesLen + "] bytes."); _evtRaiser.RaiseEvent("MessageError", "Cannot receive message - Incorrect data size in buffer while reading message length. Expected [4] bytes. Received [" + msgLengthBytesLen + "] bytes", null, _threadStatus.NodeID, _threadStatus.ParentNodeID); _threadStatus.MessageErrorCount += 1; } doneReading = true; break; } msgLength = BitConverter.ToInt32(msgLengthBytes, 0); //read msg type bytes int msgTypeBytesLen = stream.Read(msgTypeBytes, 0, 4); if (msgTypeBytesLen != 4) { logger.Warn("[" + _description + "-T] Incorrect data size in buffer while reading message type. Expected [4] bytes. Received [" + msgTypeBytesLen + "] bytes."); _evtRaiser.RaiseEvent("MessageError", "Cannot receive message - Incorrect data size in buffer while reading message type. Expected [4] bytes. Received [" + msgTypeBytesLen + "] bytes", null, _threadStatus.NodeID, _threadStatus.ParentNodeID); _threadStatus.MessageErrorCount += 1; doneReading = true; break; } msgType = BitConverter.ToInt32(msgTypeBytes, 0); //read msg data byte[] msgDataBytes = new byte[msgLength]; int msgDataBytesLen = stream.Read(msgDataBytes, 0, msgLength); if (msgDataBytesLen != msgLength) { logger.Warn("[" + _description + "-T] Incorrect data size in buffer while reading message data. Expected [" + msgLength + "] bytes. Received [" + msgDataBytesLen + "] bytes."); _evtRaiser.RaiseEvent("MessageError", "Cannot receive message - Incorrect data size in buffer while reading message data. Expected [" + msgLength + "] bytes. Received [" + msgDataBytesLen + "] bytes", null, _threadStatus.NodeID, _threadStatus.ParentNodeID); _threadStatus.MessageErrorCount += 1; doneReading = true; break; } NiawaNetMessage message; if (msgType == NiawaNetMessage.MSG_TYPE_NIAWA_NET_MESSAGE) { message = new NiawaNetMessage(msgDataBytes); } else { _evtRaiser.RaiseEvent("MessageError", "Cannot receive message - Message type [" + msgType + "] is not recognized", null, _threadStatus.NodeID, _threadStatus.ParentNodeID); _threadStatus.MessageErrorCount += 1; throw new InvalidMessageException("[" + _description + "-T] Message type [" + msgType + "] is not recognized."); } //enqueue received message _receiveQueue.Enqueue(message); receivingMessage = false; _threadStatus.MessageCount += 1; logger.Info("[" + _description + "-T] Received message: Type [" + message.MessageType + "] SerialID [" + message.SerialID + "]"); //ipcLoggerMsg.Write("ReceiveMessage", "[" + _logInstanceName + "]: " + message.MessageContents); _evtRaiser.RaiseEvent("Message", "Received message [" + message.SerialID + "]", Niawa.Utilities.InlineSortedListCreator.CreateStrStr("NiawaNetMessage", message.ToJson()), _threadStatus.NodeID, _threadStatus.ParentNodeID); _threadStatus.MessageCount += 1; atLeastOneMessageRead = true; } //done with messages in stream } finally { if (netClient !=null) netClient.Close(); //release lock lockSection.Release(); } } catch (System.Threading.ThreadAbortException) // ex1) { //thread was aborted if (receivingMessage == true) { logger.Error("[" + _description + "-T] Could not receive message: Thread aborted"); //ipcLoggerMsg.Write("ReceiveMessageError", "[" + _logInstanceName + "]: " + "Thread aborted"); //_evtRaiser.RaiseEvent("Error", "Cannot receive message - Thread aborted", string.Empty); //_threadStatus.ErrorCount += 1; _evtRaiser.RaiseEvent("MessageError", "Cannot receive message - Thread aborted", null, _threadStatus.NodeID, _threadStatus.ParentNodeID); _threadStatus.MessageErrorCount += 1; } else { logger.Debug("[" + _description + "-T] Thread aborted"); } break; } catch (System.Threading.ThreadInterruptedException) // ex1) { //thread was interrupted if (receivingMessage == true) { logger.Error("[" + _description + "-T] Could not receive message: Thread interrupted"); //ipcLoggerMsg.Write("ReceiveMessageError", "[" + _logInstanceName + "]: " + "Thread interrupted"); //_evtRaiser.RaiseEvent("Error", "Cannot receive message - Thread interrupted", string.Empty); //_threadStatus.ErrorCount += 1; _evtRaiser.RaiseEvent("MessageError", "Cannot receive message - Thread interrupted", null, _threadStatus.NodeID, _threadStatus.ParentNodeID); _threadStatus.MessageErrorCount += 1; } else { logger.Debug("[" + _description + "-T] Thread interrupted"); } break; } catch (System.Net.Sockets.SocketException ex2) { //socket exception if (ex2.Message.Contains("A blocking operation was interrupted by a call to WSACancelBlockingCall")) { if (receivingMessage == true) { logger.Error("[" + _description + "-T] Could not receive message: Blocking operation interrupted"); //ipcLoggerMsg.Write("ReceiveMessageError", "[" + _logInstanceName + "]: " + "Blocking operation interrupted"); //_evtRaiser.RaiseEvent("Error", "Cannot receive message - Blocking operation interrupted", string.Empty); //_threadStatus.ErrorCount += 1; _evtRaiser.RaiseEvent("MessageError", "Cannot receive message - Blocking operation interrupted", null, _threadStatus.NodeID, _threadStatus.ParentNodeID); _threadStatus.MessageErrorCount += 1; } else { logger.Debug("[" + _description + "-T] Blocking operation interrupted"); } } else { if (receivingMessage == true) { logger.Error("[" + _description + "-T] Could not receive message: Socket error [" + ex2.Message + "]", ex2); //ipcLoggerMsg.Write("ReceiveMessageError", "[" + _logInstanceName + "]: " + "Socket error: " + ex2.Message); //_evtRaiser.RaiseEvent("Error", "Cannot receive message - Socket error while receiving message [" + ex2.Message + "]", string.Empty); //_threadStatus.ErrorCount += 1; _evtRaiser.RaiseEvent("MessageError", "Cannot receive message - Socket error while receiving message [" + ex2.Message + "]", null, _threadStatus.NodeID, _threadStatus.ParentNodeID); _threadStatus.MessageErrorCount += 1; } else { logger.Debug("[" + _description + "-T] Socket error while receiving messages [" + ex2.Message + "]"); } } } catch (Exception ex) { //exception if (receivingMessage == true) { logger.Error("[" + _description + "-T] Could not receive message: Error [" + ex.Message + "]", ex); //ipcLoggerMsg.Write("ReceiveMessageError", "[" + _logInstanceName + "]: " + "Error: " + ex.Message); _evtRaiser.RaiseEvent("Error", "Cannot receive message - Error while receiving message [" + ex.Message + "]", null, _threadStatus.NodeID, _threadStatus.ParentNodeID); _threadStatus.ErrorCount += 1; _evtRaiser.RaiseEvent("MessageError", "Cannot receive message - Error while receiving message [" + ex.Message + "]", null, _threadStatus.NodeID, _threadStatus.ParentNodeID); _threadStatus.MessageErrorCount += 1; } else { logger.Warn("[" + _description + "-T] Error while receiving messages [" + ex.Message + "]"); } System.Threading.Thread.Sleep(100); } System.Threading.Thread.Sleep(10); } //done with thread (stopped) } catch (Exception ex) { logger.Error("[" + _description + "-T] Error in listen thread: " + ex.Message, ex); _evtRaiser.RaiseEvent("Error", "[" + _description + "-T] Error in listen thread: " + ex.Message, null, _threadStatus.NodeID, _threadStatus.ParentNodeID); _threadStatus.ErrorCount += 1; throw ex; } finally { _threadStatus.IsThreadActive = false; _threadStatus.IsThreadEnabled = false; logger.Info("[" + _description + "-T] Receiver inactive"); } }
/// <summary> /// Send TCP message synchonously. Wait for message to send before returning. /// </summary> /// <param name="message"></param> public void SendMessageSynchronous(NiawaNetMessage message, int timeoutMs) { try { DateTime now = DateTime.Now; DateTime timeoutBy1 = now.AddMilliseconds(timeoutMs / 2); DateTime timeoutBy2 = now.AddMilliseconds(timeoutMs); //wait up to timeout seconds / 2 for transmitter to start int i1 = 0; while (!_threadStatus.IsThreadEnabled && !_threadStatus.IsThreadActive && timeoutBy1 < DateTime.Now) { i1++; System.Threading.Thread.Sleep(10); } if (timeoutBy1 < DateTime.Now) logger.Warn("[" + _description + "-M] Timed out waiting for transmitter to start while sending message synchronously"); System.Threading.Thread.Sleep(100); /****************/ /* send message */ //get next serial ID id = Niawa.Utilities.IdGeneratorUtils.IncrementSerialId(id); message.SerialID = id.ToString(); logger.Info("[" + _description + "-M] Queueing message: Type [" + message.MessageType + "] SerialID [" + message.SerialID + "]"); _sendQueue.Enqueue(message); /* send message */ /****************/ System.Threading.Thread.Sleep(100); //wait up to timeout seconds for message to send int i = 0; while (CountMessagesInBuffer() > 0 && timeoutBy2 < DateTime.Now) { i++; System.Threading.Thread.Sleep(10); } if (timeoutBy2 < DateTime.Now) logger.Warn("[" + _description + "-M] Timed out waiting for message to send while sending message synchronously"); } catch (Exception ex) { logger.Error("[" + _description + "-M] Error sending message synchronously: " + ex.Message, ex); throw ex; } }
/// <summary> /// Send TCP message /// </summary> /// <param name="message">Message to send via TCP</param> public void SendMessage(NiawaNetMessage message) { try { if (!_threadStatus.IsThreadEnabled || !_threadStatus.IsThreadActive) { _evtRaiser.RaiseEvent("MessageError", "Cannot send message - transmitter is not active" , Niawa.Utilities.InlineSortedListCreator.CreateStrStr("NiawaNetMessage", message.ToJson()) , _threadStatus.NodeID , _threadStatus.ParentNodeID); _threadStatus.MessageErrorCount += 1; throw new MessageNotSentException("Cannot send message - transmitter is not active"); } //get next serial ID id = Niawa.Utilities.IdGeneratorUtils.IncrementSerialId(id); message.SerialID = id.ToString(); logger.Info("[" + _description + "-M] Queueing message: Type [" + message.MessageType + "] SerialID [" + message.SerialID + "]"); _sendQueue.Enqueue(message); } catch (Exception ex) { logger.Error("[" + _description + "-M] Error sending message: " + ex.Message, ex); throw ex; } }
/// <summary> /// Used to establish a TCP session with a remote host (connection information is sent to the remote host). /// Transmits the local receiver port to the remote host. /// </summary> /// <param name="remoteIpAddress"></param> /// <param name="remoteHandshakePort"></param> /// <param name="localSessionData"></param> public void TransmitSessionInitialization(string remoteIpAddress, int remoteHandshakePort, string remoteHostname, MessageContent.SessionInitMessageContent localSessionData) { if (!_initialized) { _evtRaiser.RaiseEvent("SessionError", "Cannot transmit session initialization to [" + remoteIpAddress + "]: TcpSessionManager has not been initialized" , Niawa.Utilities.InlineSortedListCreator.CreateStrStr("SessionInitMessageContent", localSessionData.ToJson()) , _t2_SRL_ThreadStatus.NodeID , _t2_SRL_ThreadStatus.ParentNodeID); throw new Exception("[" + _description + "-M] Cannot transmit session initialization to [" + remoteIpAddress + "]: TcpSessionManager has not been initialized."); } logger.Info("[" + _description + "-M] Transmitting session initialization [" + remoteIpAddress + "]"); //attempt lock bool tryLock = lockSection.WaitOne(60000); if (!tryLock) throw new TimeoutException("[" + _description + "-M] Could not obtain lock while transmitting session initialization"); try { /*session was already created and receiver is listening*/ //make sure the session exists if (!_tcpSessions.ContainsKey(remoteIpAddress)) { _evtRaiser.RaiseEvent("SessionError", "Cannot transmit session initialization: Cannot find session for address [" + remoteIpAddress + "]" , Niawa.Utilities.InlineSortedListCreator.CreateStrStr("SessionInitMessageContent", localSessionData.ToJson()) , _t2_SRL_ThreadStatus.NodeID , _t2_SRL_ThreadStatus.ParentNodeID); throw new Exception("[" + _description + "-M] Cannot transmit session initialization: Cannot find session for address [" + remoteIpAddress + "]"); } /*transmit message on stand-alone TCP transmitter to remoteIPAddress and remotePort*/ //create transmitter and start transmitting TcpTransmitter transmitter = new TcpTransmitter(remoteIpAddress, remoteHandshakePort, _evtConsumer, _utilsBus, _applicationName + ".TcpSessionManager", _t1_HR_ThreadStatus.NodeID); transmitter.StartTransmitting(_applicationName + ".TcpSessionManager.TransmitSessionInitialization"); //create and send message NiawaNetMessage message = new NiawaNetMessage(_ipAddress, _handshakePort, _hostname, remoteIpAddress, remoteHandshakePort, remoteHostname, Guid.NewGuid(), _applicationName, MessageContent.SessionInitMessageContent.MESSAGE_CONTENT_TYPE, localSessionData.ToJson()); //send message synchrnously transmitter.SendMessageSynchronous(message, 30000); //mark as init sent TcpSession session = _tcpSessions[remoteIpAddress]; session.IsSessionInitSent = true; //shut down transmitter transmitter.StopTransmitting(_applicationName + ".TcpSessionManager.TransmitSessionInitialization", false); transmitter.Dispose(); /* //wait up to 30 seconds for transmitter to start int i1 = 0; while (!transmitter.IsThreadActive && i1 < 3000) { i1++; System.Threading.Thread.Sleep(10); } //send message transmitter.SendMessage(message); //mark as init sent TcpSession session = _tcpSessions[remoteIpAddress]; session.IsSessionInitSent = true; //wait up to 30 seconds for message to send int i = 0; while (transmitter.CountMessagesInBuffer() > 0 && i < 3000) { i++; System.Threading.Thread.Sleep(10); } //shut down transmitter transmitter.StopTransmitting(_applicationName + ".TcpSessionManager.TransmitSessionInitialization", false); //wait up to 30 seconds for transmitter thread to stop int i2 = 0; while (!transmitter.IsStopped && i2 < 3000) { i2++; System.Threading.Thread.Sleep(10); } transmitter.Dispose(); */ logger.Info("[" + _description + "-M] Session initialization sent to remote [" + remoteIpAddress + "]"); //raise event _evtRaiser.RaiseEvent("Session", "Session initialization sent to remote [" + remoteIpAddress + "]" , Niawa.Utilities.InlineSortedListCreator.CreateStrStr("SessionInitMessageContent", localSessionData.ToJson()) , _t2_SRL_ThreadStatus.NodeID , _t2_SRL_ThreadStatus.ParentNodeID); } catch (Exception ex) { logger.Error("[" + _description + "-M] Error while transmitting session initialization [" + remoteIpAddress + "]:" + ex.Message, ex); _evtRaiser.RaiseEvent("Error", "Error while transmitting session initialization [" + remoteIpAddress + "]:" + ex.Message, null, _t2_SRL_ThreadStatus.NodeID, _t2_SRL_ThreadStatus.ParentNodeID); throw ex; } finally { //release lock lockSection.Release(); } }
/// <summary> /// Creates and sends a message to a specific TCP session /// </summary> /// <param name="applicationName"></param> /// <param name="messageType"></param> /// <param name="messageContents"></param> public void SendMessage(string remoteIpAddress, string applicationName, string messageType, string messageContents) { Guid newMessageGuid = Guid.NewGuid(); //create partial message for logging NiawaNetMessage partialMsg = new NiawaNetMessage(); partialMsg.Guid = newMessageGuid; partialMsg.MessageType = messageType; partialMsg.MessageContents = messageContents; if (!_initialized) { _evtRaiser.RaiseEvent("MessageError", "Cannot send message - TcpSessionManager has not been initialized" , Niawa.Utilities.InlineSortedListCreator.CreateStrStr("NiawaNetMessage", partialMsg.ToJson()) , _t2_SRL_ThreadStatus.NodeID , _t2_SRL_ThreadStatus.ParentNodeID); throw new Exception("[" + _description + "-M] Cannot send message: TcpSessionManager has not been initialized."); } logger.Info("[" + _description + "-M] Sending message to [" + remoteIpAddress + "]: Type [" + messageType + "] Guid [" + newMessageGuid + "]"); //attempt lock bool tryLock = lockSection.WaitOne(60000); if (!tryLock) throw new TimeoutException("[" + _description + "-M] Could not obtain lock while sending message"); try { //raise event _evtRaiser.RaiseEvent("Message", "Sending message to [" + remoteIpAddress + "]" , Niawa.Utilities.InlineSortedListCreator.CreateStrStr("NiawaNetMessage", partialMsg.ToJson()) , _t2_SRL_ThreadStatus.NodeID , _t2_SRL_ThreadStatus.ParentNodeID); //send message on a specific transmitter if (_tcpSessions.ContainsKey(remoteIpAddress)) { TcpSession session = _tcpSessions[remoteIpAddress]; //create a new message NiawaNetMessage message = new NiawaNetMessage(); //user passed in info message.ApplicationName = applicationName; message.MessageContents = messageContents; message.MessageType = messageType; message.Guid = newMessageGuid; //get info from session message.DestinationHostname = session.RemoteHostname; message.DestinationIpAddress = session.RemoteIpAddress; message.DestinationPort = session.RemoteSessionPort; message.SenderHostname = _hostname; message.SenderIpAddress = session.LocalIpAddress; message.SenderPort = session.LocalPort; //send message session.TransmitterSendMessage(message); } else { _evtRaiser.RaiseEvent("MessageError", "Cannot send message: Session [" + remoteIpAddress + "] cannot be found" , Niawa.Utilities.InlineSortedListCreator.CreateStrStr("NiawaNetMessage", partialMsg.ToJson()) , _t2_SRL_ThreadStatus.NodeID , _t2_SRL_ThreadStatus.ParentNodeID); throw new MessageNotSentException("[" + _description + "-M] Cannot send message: Session [" + remoteIpAddress + "] cannot be found"); } } catch (Exception ex) { logger.Error("[" + _description + "-M] Error sending message [" + newMessageGuid + "]: " + ex.Message, ex); throw ex; } finally { //release lock lockSection.Release(); } }
/// <summary> /// Send a message on the TCP Transmitter. /// </summary> /// <param name="message"></param> public void TransmitterSendMessage(NiawaNetMessage message) { try { if (_transmitter != null) _transmitter.SendMessage(message); if (_transmitter == null) logger.Warn("[" + _sessionIdentifier + "] Could not send message [" + message.SerialID + "]: transmitter has not been added to the session"); } catch (Exception ex) { logger.Error("[" + _sessionIdentifier + "] Error while transmitter sending message: " + ex.Message, ex); throw ex; } }