private void SendMessage(CommandEtherNetIPHeader header, CIPSerializer msg) { byte[] headerBytes = header.Serialize(); byte[] msgBytes = msg?.Serialize() ?? new byte[0]; byte[] allBytes = new byte[headerBytes.Length + msgBytes.Length]; Array.Copy(headerBytes, allBytes, headerBytes.Length); Array.Copy(msgBytes, 0, allBytes, headerBytes.Length, msgBytes.Length); Trace(EventType.Full, string.Format("{0} - Msg. '{1}' queued to be send", LOG_TAG, header.Command)); m_SocketClient.SendData(allBytes); }
public void ReceiveBytes(byte[] data) { m_ActivityTimeRef = DateTime.Now; Trace(EventType.Full, string.Format("{0} - {1} bytes received!", LOG_TAG, data.Length)); m_ReceiveBuffer.Position = m_ReceiveBuffer.Length; m_ReceiveBuffer.Write(data, 0, data.Length); long pointer = 0; while (pointer < m_ReceiveBuffer.Length) { long msgHeaderSize = Marshal.SizeOf(typeof(CommandEtherNetIPHeader)); if (m_ReceiveBuffer.Length - pointer >= msgHeaderSize) { byte[] bytes = new byte[msgHeaderSize]; m_ReceiveBuffer.Position = pointer; m_ReceiveBuffer.Read(bytes, 0, bytes.Length); CommandEtherNetIPHeader headerStructObj = CommandEtherNetIPHeader.Deserialize(bytes); long msgSize = msgHeaderSize + headerStructObj.Length; if (m_ReceiveBuffer.Length - pointer >= msgSize) { byte[] bodyBytes = new byte[headerStructObj.Length]; m_ReceiveBuffer.Position = pointer + msgHeaderSize; m_ReceiveBuffer.Read(bodyBytes, 0, bodyBytes.Length); MessageFactory(headerStructObj, bodyBytes); m_WaitingRemainingBytes = DateTime.MinValue; pointer += msgSize; } else { Trace(EventType.Warning, string.Format("{0} - Waiting for the rest of msg. body", LOG_TAG)); m_WaitingRemainingBytes = DateTime.Now; break; } } else { Trace(EventType.Warning, string.Format("{0} - Waiting for the rest of msg. header", LOG_TAG)); m_WaitingRemainingBytes = DateTime.Now; break; } } if (pointer >= m_ReceiveBuffer.Length) { m_ReceiveBuffer.SetLength(0); m_ReceiveBuffer.Capacity = 0; m_ReceiveBuffer.Position = 0; Trace(EventType.Full, string.Format("{0} - Receive buffer clear!", LOG_TAG)); } }
private void ThreadTask() { try { while (!m_Terminate) { if (m_WaitingRemainingBytes != DateTime.MinValue) { if (DateTime.Now.Subtract(m_WaitingRemainingBytes).TotalSeconds > 2) { Trace(EventType.Error, string.Format("{0} - So long time waiting the rest of message bytes. The connection will be closed. {1}", LOG_TAG, m_ScktConn.RemoteEndPoint)); Close(); } } lock (m_SendMsgList) if (m_SendMsgList.Count > 0) { byte[] msgBytes = m_SendMsgList[0]; m_ScktConn.SendData(msgBytes); Trace(EventType.Full, string.Format("{0} - {1} bytes sent !!!", LOG_TAG, msgBytes.Length)); m_SendMsgList.RemoveAt(0); } if (!m_Terminate) { if (!m_ThreadResetEvent.WaitOne(2000) && m_SendMsgList.Count == 0) { CommandEtherNetIPHeader msgListServices = new CommandEtherNetIPHeader { Command = EncapsulationCommands.NOP }; SendMessage(msgListServices, null); } } } } catch (Exception exc) { Trace(exc); } }
private void MessageFactory(CommandEtherNetIPHeader header, byte[] bodyBytes) { int pointer = 0; Trace(EventType.Full, string.Format("{0} - Receive msg. '{1}' with status {2}", LOG_TAG, header.Command, header.Status)); long headerSize = Marshal.SizeOf(typeof(CommandEtherNetIPHeader)); switch (header.Command) { case EncapsulationCommands.ListServices: { if (bodyBytes.Length > 0) { MsgListServiceReply msgReply = (MsgListServiceReply)MsgListServiceReply.Deserialize(typeof(MsgListServiceReply), bodyBytes, ref pointer); if ((msgReply.CommandSpecificDataListServices.Items[0].CapabilityFlags & 0x20) == 0) { throw new Exception("The order side doesn't support TCP messages"); } m_ClientConnStates = ClientConnStates.SendRegisterSession; } break; } case EncapsulationCommands.RegisterSession: { if (header.Status == 0 && header.SessionHandle != 0) { MsgRegisterSessionReply msgReply = (MsgRegisterSessionReply)MsgRegisterSessionReply.Deserialize(typeof(MsgRegisterSessionReply), bodyBytes, ref pointer); Trace(EventType.Info, string.Format("{0} - Registration session number: {1}", LOG_TAG, header.SessionHandle)); m_SessionHandle = header.SessionHandle; m_ClientConnStates = ClientConnStates.SendReceive; OnRegistrationSession?.Invoke(m_SessionHandle); } else { throw new Exception(string.Format("Error on registration session. Error: {0}", header.Status)); } break; } case EncapsulationCommands.SendRRData: { MsgUnconnectedSendReply msgReply = (MsgUnconnectedSendReply)MsgUnconnectedSendReply.Deserialize(typeof(MsgUnconnectedSendReply), bodyBytes, ref pointer); long sendContext = BitConverter.ToInt64(header.SenderContext, 0); if (sendContext != 0 && sendContext == m_SenderContext) { m_SendStatusResult = msgReply.CommonIndustrialProtocolReply.GeneralStatus; m_SendResetEvent.Set(); } break; } case EncapsulationCommands.UnRegisterSession: { break; } default: { throw new Exception(string.Format("Command {0} not implemented", header.Command)); } } }
private void ThreadTask() { try { while (!m_Terminate) { switch (m_ClientConnStates) { case ClientConnStates.Disconnected: { break; } case ClientConnStates.SendListServices: { CommandEtherNetIPHeader msgListServices = new CommandEtherNetIPHeader { Command = EncapsulationCommands.ListServices }; SendMessage(msgListServices, null); m_ClientConnStates = ClientConnStates.WaitListServicesReply; break; } case ClientConnStates.SendRegisterSession: { MsgRegisterSessionRequest msg = new MsgRegisterSessionRequest(); CommandEtherNetIPHeader header = new CommandEtherNetIPHeader { Command = EncapsulationCommands.RegisterSession }; msg.CommandSpecificDataRegisterSession = new CommandSpecificDataRegisterSession { ProtocolVersion = 1 }; header.Length = msg.CommandSpecificDataRegisterSession.SizeOf(); SendMessage(header, msg); m_ClientConnStates = ClientConnStates.WaitRegisterSessionReply; break; } case ClientConnStates.SendReceive: { if (m_DataToSend != null) { CommandEtherNetIPHeader header = new CommandEtherNetIPHeader { Command = EncapsulationCommands.SendRRData, SessionHandle = m_SessionHandle, SenderContext = BitConverter.GetBytes(m_SenderContext) }; MsgUnconnectedSendRequest msg = new MsgUnconnectedSendRequest { CommandSpecificDataSendRRData = new CommandSpecificDataSendRRData { InterfaceHandle = 0, Timeout = 0, ItemCount = 2, List = new CommandSpecificDataSendRRDataItem[] { new CommandSpecificDataSendRRDataItem { TypeID = 0, Length = 0 }, new CommandSpecificDataSendRRDataItem { TypeID = CommonPacketItemID.UnconnectedMessage, Length = 0 } } }, CommonIndustrialProtocolRequest = new CommonIndustrialProtocolRequest { Service = 0x52, // Unconnected Send Service ID RequestPathSize = 2, PathSegmentList = new List <PathSegment> { new LogicalPathSegment8bits { PathSegmentType = 0x20, LogicalValue = 0x06 // Connection Manager Class ID }, new LogicalPathSegment8bits { PathSegmentType = 0x24, LogicalValue = 0x01 // Connection Manager Instance ID } } }, CIPConnectionManagerUnconnSnd = new CIPConnectionManagerUnconnSnd { PriorityAndPickTime = 0x07, TimeOutTicks = 233, MessageRequestSize = 0, CommonIndustrialProtocolRequest = new CommonIndustrialProtocolRequest { Service = 0x4d, // CIP Write Data Service RequestPathSize = 0, }, CIPClassGeneric = new CIPClassGeneric { DataType = m_DataTypeToSend, SpecificDataSize = (ushort)(m_DataToSend.Length / CIPClassGeneric.GetDataTypeSize(m_DataTypeToSend)), CIPClassGenericCmdSpecificData = m_DataToSend, }, Pad = null, RoutePathSize = 0, Reserved = 0, RoutePath = new List <PathSegment> { new PortPathSegment { PathSegmentType = 0x01, OptionalLinkAddressSize = null, OptionalExtendedPortIdentifier = null, LinkAddress = new byte[] { m_LinkAddress }, Pad = null } } } }; msg.CIPConnectionManagerUnconnSnd.CommonIndustrialProtocolRequest.PathSegmentList = new List <PathSegment>(); string[] segs = m_Symbol.Split(new char[] { '.' }, StringSplitOptions.RemoveEmptyEntries); foreach (string seg in segs) { msg.CIPConnectionManagerUnconnSnd.CommonIndustrialProtocolRequest.PathSegmentList.Add( new DataPathSegmentANSISymb { PathSegmentType = 0x91, DataSize = (byte)seg.Length, ANSISymbol = Encoding.ASCII.GetBytes(seg.Length % 2 == 0 ? seg : seg + "\0") }); } msg.CIPConnectionManagerUnconnSnd.Pad = (msg.CIPConnectionManagerUnconnSnd.SizeOf() % 2) == 0 ? null : (byte?)0; msg.CIPConnectionManagerUnconnSnd.RoutePathSize = (byte)(msg.CIPConnectionManagerUnconnSnd.RoutePath.Sum(a => a.SizeOf()) / 2); msg.CIPConnectionManagerUnconnSnd.CommonIndustrialProtocolRequest.RequestPathSize = (byte)(msg.CIPConnectionManagerUnconnSnd.CommonIndustrialProtocolRequest.PathSegmentList.Sum(a => a.SizeOf()) / 2); msg.CIPConnectionManagerUnconnSnd.MessageRequestSize = (ushort)(msg.CIPConnectionManagerUnconnSnd.CommonIndustrialProtocolRequest.SizeOf() + msg.CIPConnectionManagerUnconnSnd.CIPClassGeneric.SizeOf()); msg.CommandSpecificDataSendRRData.List[1].Length = (ushort)(msg.CommonIndustrialProtocolRequest.SizeOf() + msg.CIPConnectionManagerUnconnSnd.SizeOf()); header.Length = msg.SizeOf(); SendMessage(header, msg); } else { CommandEtherNetIPHeader msgListServices = new CommandEtherNetIPHeader { Command = EncapsulationCommands.NOP }; SendMessage(msgListServices, null); } break; } } if (!m_Terminate) { m_ThreadResetEvent.WaitOne(2000); } } } catch (Exception exc) { Trace(EventType.Error, string.Format("{0} - Thread exception: {1}", LOG_TAG, exc.Message)); Trace(exc); } }
private void MessageFactory(CommandEtherNetIPHeader header, byte[] bodyBytes) { try { Trace(EventType.Full, string.Format("{0} - Receive msg. '{1}'", LOG_TAG, header.Command)); long headerSize = Marshal.SizeOf(typeof(CommandEtherNetIPHeader)); switch (header.Command) { case EncapsulationCommands.ListServices: { if (bodyBytes.Length == 0) { MsgListServiceReply msg = new MsgListServiceReply(); msg.CommandSpecificDataListServices = new CommandSpecificDataListServices(); msg.CommandSpecificDataListServices.ItemCount = 1; msg.CommandSpecificDataListServices.Items = new CommandSpecificDataListServicesItem[1]; msg.CommandSpecificDataListServices.Items[0] = new CommandSpecificDataListServicesItem { TypeCode = CommonPacketItemID.ListServicesResponse, Version = 1, CapabilityFlags = Convert.ToUInt16("100100000", 2), ServiceName = Encoding.ASCII.GetBytes("Communications\0\0") }; header.Length = msg.SizeOf(); msg.CommandSpecificDataListServices.Items[0].Length = (ushort)(msg.CommandSpecificDataListServices.Items[0].SizeOf() - 2 - 2); SendMessage(header, msg); } break; } case EncapsulationCommands.RegisterSession: { int pointer = 0; CommandSpecificDataRegisterSession cmdSpecData = (CommandSpecificDataRegisterSession)CommandSpecificDataRegisterSession.Deserialize( typeof(CommandSpecificDataRegisterSession), bodyBytes, ref pointer); MsgRegisterSessionReply msg = new MsgRegisterSessionReply(); // TODO: check the protocol version to accept the registration msg.CommandSpecificDataRegisterSession = cmdSpecData; m_SessionHandle = (uint)((DateTime.Now.Ticks / 10) & 0xFFFFFFFF); header.SessionHandle = m_SessionHandle; header.Length = msg.SizeOf(); SendMessage(header, msg); Trace(EventType.Info, string.Format("{0} - Registration session number: {1}", LOG_TAG, header.SessionHandle)); break; } case EncapsulationCommands.SendRRData: { if (header.SessionHandle != m_SessionHandle) { throw new Exception(string.Format("Received invalid session handle (unregistred) in SendRRData message: ", header.SessionHandle)); } int pointer = 0; MsgUnconnectedSendRequest unconnSndReq = (MsgUnconnectedSendRequest)MsgUnconnectedSendRequest.Deserialize( typeof(MsgUnconnectedSendRequest), bodyBytes, ref pointer); string symbol = Encoding.ASCII.GetString(((DataPathSegmentANSISymb)unconnSndReq.CIPConnectionManagerUnconnSnd.CommonIndustrialProtocolRequest.PathSegmentList[0]).ANSISymbol); ElementaryDataType dataType = unconnSndReq.CIPConnectionManagerUnconnSnd.CIPClassGeneric.DataType; OnReceiveData?.Invoke(m_ScktConn.RemoteEndPoint, symbol.Replace("\0", ""), dataType, unconnSndReq.CIPConnectionManagerUnconnSnd.CIPClassGeneric.CIPClassGenericCmdSpecificData); MsgUnconnectedSendReply msg = new MsgUnconnectedSendReply(); msg.CommandSpecificDataSendRRData = unconnSndReq.CommandSpecificDataSendRRData; CommandSpecificDataSendRRDataItem item = msg.CommandSpecificDataSendRRData.List.First( a => a.TypeID == CommonPacketItemID.UnconnectedMessage); msg.CommonIndustrialProtocolReply = new CommonIndustrialProtocolReply { Service = 0xcd, Reserved = 0x0, GeneralStatus = 0x0, // <- success AdditionalStatusSize = 0x0, AdditionalStatus = new ushort[0] }; item.Length = msg.CommonIndustrialProtocolReply.SizeOf(); header.Length = msg.SizeOf(); SendMessage(header, msg); break; } case EncapsulationCommands.UnRegisterSession: { break; } default: { Trace(EventType.Error, string.Format("{0} - Command {1} not implemented", LOG_TAG, header.Command)); break; } } } catch (Exception e) { Trace(e); } }