///<summary> ///Parse AARQ request that client send and returns AARE request. /// </summary> ///<returns> ///Reply to the client. ///</returns> private void HandleAarqRequest(GXByteBuffer data, GXDLMSConnectionEventArgs connectionInfo) { AssociationResult result = AssociationResult.Accepted; Settings.CtoSChallenge = null; if (!Settings.UseCustomChallenge) { Settings.StoCChallenge = null; } // Reset settings for wrapper. if (Settings.InterfaceType == InterfaceType.WRAPPER) { Reset(true); } SourceDiagnostic diagnostic = GXAPDU.ParsePDU(Settings, Settings.Cipher, data, null); if (diagnostic != SourceDiagnostic.None) { result = AssociationResult.PermanentRejected; diagnostic = SourceDiagnostic.ApplicationContextNameNotSupported; InvalidConnection(connectionInfo); } else { diagnostic = ValidateAuthentication(Settings.Authentication, Settings.Password); if (diagnostic != SourceDiagnostic.None) { result = AssociationResult.PermanentRejected; InvalidConnection(connectionInfo); } else if (Settings.Authentication > Authentication.Low) { // If High authentication is used. if (!Settings.UseCustomChallenge) { Settings.StoCChallenge = GXSecure.GenerateChallenge(Settings.Authentication); } result = AssociationResult.Accepted; diagnostic = SourceDiagnostic.AuthenticationRequired; } else { Connected(connectionInfo); Settings.Connected = true; } } Settings.IsAuthenticationRequired = diagnostic == SourceDiagnostic.AuthenticationRequired; if (Settings.InterfaceType == Enums.InterfaceType.HDLC) { replyData.Set(GXCommon.LLCReplyBytes); } // Generate AARE packet. GXAPDU.GenerateAARE(Settings, replyData, result, diagnostic, Settings.Cipher, null); }
/// <summary> /// Handles release reuest. /// </summary> /// <param name="data">Received data.</param> /// <param name="connectionInfo">Connection info.</param> private void HandleReleaseRequest(GXByteBuffer data, GXDLMSConnectionEventArgs connectionInfo) { //Return error if connection is not established. if (!Settings.Connected && !Settings.IsAuthenticationRequired && !Settings.AllowAnonymousAccess) { replyData.Add(GenerateConfirmedServiceError(ConfirmedServiceError.InitiateError, ServiceError.Service, (byte)Service.Unsupported)); return; } if (Settings.InterfaceType == InterfaceType.HDLC) { replyData.Set(0, GXCommon.LLCReplyBytes); } replyData.SetUInt8(0x63); //LEN. replyData.SetUInt8(0x03); replyData.SetUInt8(0x80); replyData.SetUInt8(0x01); replyData.SetUInt8(0x00); }
///<summary> /// Handle received command. ///</summary> private byte[] HandleCommand(Command cmd, GXByteBuffer data, GXDLMSConnectionEventArgs connectionInfo) { byte frame = 0; switch (cmd) { case Command.AccessRequest: GXDLMSLNCommandHandler.HandleAccessRequest(Settings, this, data, replyData, null); break; case Command.SetRequest: GXDLMSLNCommandHandler.HandleSetRequest(Settings, this, data, replyData, null); break; case Command.WriteRequest: GXDLMSSNCommandHandler.HandleWriteRequest(Settings, this, data, replyData, null); break; case Command.GetRequest: if (data.Size != 0) { GXDLMSLNCommandHandler.HandleGetRequest(Settings, this, data, replyData, null); } break; case Command.ReadRequest: GXDLMSSNCommandHandler.HandleReadRequest(Settings, this, data, replyData, null); break; case Command.MethodRequest: GXDLMSLNCommandHandler.HandleMethodRequest(Settings, this, data, connectionInfo, replyData, null); break; case Command.Snrm: HandleSnrmRequest(); frame = (byte)Command.Ua; break; case Command.Aarq: HandleAarqRequest(data, connectionInfo); break; case Command.ReleaseRequest: case Command.DisconnectRequest: GenerateDisconnectRequest(); Settings.Connected = false; Disconnected(connectionInfo); frame = (byte)Command.Ua; break; case Command.None: //Get next frame. break; default: Debug.WriteLine("Invalid command: " + (int)cmd); break; } byte[] reply; if (this.InterfaceType == Enums.InterfaceType.WRAPPER) { reply = GXDLMS.GetWrapperFrame(Settings, replyData); } else { reply = GXDLMS.GetHdlcFrame(Settings, frame, replyData); } return(reply); }
///<summary> /// Handles client request. /// </summary> ///<param name="buff"> /// Received data from the client. </param> ///<returns> ///Response to the request. Response is null if request packet is not complete. ///</returns> public virtual byte[] HandleRequest(byte[] buff, GXDLMSConnectionEventArgs connectionInfo) { if (buff == null || buff.Length == 0) { return(null); } if (!Initialized) { throw new Exception("Server not Initialized."); } try { receivedData.Set(buff); bool first = Settings.ServerAddress == 0 && Settings.ClientAddress == 0; GXDLMS.GetData(Settings, receivedData, info); //If all data is not received yet. if (!info.IsComplete) { return(null); } receivedData.Clear(); if (first) { // Check is data send to this server. if (!IsTarget(Settings.ServerAddress, Settings.ClientAddress)) { info.Clear(); return(null); } } //If client want next frame. if ((info.MoreData & RequestTypes.Frame) == RequestTypes.Frame) { return(GXDLMS.GetHdlcFrame(Settings, Settings.ReceiverReady(), replyData)); } //Update command if transaction and next frame is asked. if (info.Command == Command.None) { if (transaction != null) { info.Command = transaction.command; } } //Check inactivity time out. if (hdlcSetup != null) { if (info.Command == Command.Snrm) { dataReceived = DateTime.Now; } else { int elapsed = (int)(DateTime.Now - dataReceived).TotalSeconds; //If inactivity time out is elapsed. if (elapsed >= hdlcSetup.InactivityTimeout) { Reset(); dataReceived = DateTime.MinValue; return(null); } dataReceived = DateTime.Now; } } byte[] reply = HandleCommand(info.Command, info.Data, connectionInfo); info.Clear(); return(reply); } catch (Exception ex) { Debug.WriteLine(ex.ToString()); if (info.Command != Command.None) { return(ReportError(info.Command, ErrorCode.HardwareFault)); } else { Reset(); if (Settings.Connected) { Settings.Connected = false; Disconnected(connectionInfo); } return(null); } } }
/// <summary> /// Client has try to made invalid connection. Password is incorrect. /// </summary> /// <param name="connectionInfo">Connection information.</param> internal void NotifyInvalidConnection(GXDLMSConnectionEventArgs connectionInfo) { InvalidConnection(connectionInfo); }
/// <summary> /// Server has close the connection. All clean up is made here. /// </summary> /// <param name="connectionInfo">Connection information.</param> protected abstract void Disconnected(GXDLMSConnectionEventArgs connectionInfo);
/// <summary> /// Client has try to made invalid connection. Password is incorrect. /// </summary> /// <param name="connectionInfo">Connection information.</param> protected abstract void InvalidConnection(GXDLMSConnectionEventArgs connectionInfo);
///<summary> ///Parse AARQ request that client send and returns AARE request. /// </summary> ///<returns> ///Reply to the client. ///</returns> private void HandleAarqRequest(GXByteBuffer data, GXDLMSConnectionEventArgs connectionInfo) { AssociationResult result = AssociationResult.Accepted; Settings.CtoSChallenge = null; if (!Settings.UseCustomChallenge) { Settings.StoCChallenge = null; } // Reset settings for wrapper. if (Settings.InterfaceType == InterfaceType.WRAPPER) { Reset(true); } SourceDiagnostic diagnostic = GXAPDU.ParsePDU(Settings, Settings.Cipher, data, null); if (diagnostic != SourceDiagnostic.None) { result = AssociationResult.PermanentRejected; diagnostic = SourceDiagnostic.ApplicationContextNameNotSupported; InvalidConnection(connectionInfo); } else { diagnostic = ValidateAuthentication(Settings.Authentication, Settings.Password); if (diagnostic != SourceDiagnostic.None) { result = AssociationResult.PermanentRejected; InvalidConnection(connectionInfo); } else if (Settings.Authentication > Authentication.Low) { // If High authentication is used. Settings.StoCChallenge = GXSecure.GenerateChallenge(Settings.Authentication); result = AssociationResult.Accepted; diagnostic = SourceDiagnostic.AuthenticationRequired; } else { Connected(connectionInfo); Settings.Connected = true; } } Settings.IsAuthenticationRequired = diagnostic == SourceDiagnostic.AuthenticationRequired; if (Settings.InterfaceType == Enums.InterfaceType.HDLC) { replyData.Set(GXCommon.LLCReplyBytes); } // Generate AARE packet. GXAPDU.GenerateAARE(Settings, replyData, result, diagnostic, Settings.Cipher, null); }
protected override void Connected(GXDLMSConnectionEventArgs e) { Console.WriteLine("Connected."); }
///<summary> /// Handles client request. /// </summary> ///<param name="buff"> /// Received data from the client. </param> ///<returns> ///Response to the request. Response is null if request packet is not complete. ///</returns> public virtual byte[] HandleRequest(byte[] buff, GXDLMSConnectionEventArgs connectionInfo) { if (buff == null || buff.Length == 0) { return null; } if (!Initialized) { throw new Exception("Server not Initialized."); } try { receivedData.Set(buff); bool first = Settings.ServerAddress == 0 && Settings.ClientAddress == 0; GXDLMS.GetData(Settings, receivedData, info); //If all data is not received yet. if (!info.IsComplete) { return null; } receivedData.Clear(); if (first) { // Check is data send to this server. if (!IsTarget(Settings.ServerAddress, Settings.ClientAddress)) { info.Clear(); return null; } } //If client want next frame. if ((info.MoreData & RequestTypes.Frame) == RequestTypes.Frame) { return GXDLMS.GetHdlcFrame(Settings, Settings.ReceiverReady(), replyData); } //Update command if transaction and next frame is asked. if (info.Command == Command.None) { if (transaction != null) { info.Command = transaction.command; } } //Check inactivity time out. if (hdlcSetup != null) { if (info.Command == Command.Snrm) { dataReceived = DateTime.Now; } else { int elapsed = (int)(DateTime.Now - dataReceived).TotalSeconds; //If inactivity time out is elapsed. if (elapsed >= hdlcSetup.InactivityTimeout) { Reset(); dataReceived = DateTime.MinValue; return null; } dataReceived = DateTime.Now; } } byte[] reply = HandleCommand(info.Command, info.Data, connectionInfo); info.Clear(); return reply; } catch (Exception ex) { Debug.WriteLine(ex.ToString()); if (info.Command != Command.None) { return ReportError(info.Command, ErrorCode.HardwareFault); } else { Reset(); if (Settings.Connected) { Settings.Connected = false; Disconnected(connectionInfo); } return null; } } }
///<summary> /// Handle action request. ///</summary> ///<param name="Reply"> /// Received data from the client. ///</param> ///<returns> ///Reply. ///</returns> public static void HandleMethodRequest(GXDLMSSettings settings, GXDLMSServer server, GXByteBuffer data, GXDLMSConnectionEventArgs connectionInfo, GXByteBuffer replyData, GXDLMSTranslatorStructure xml) { ErrorCode error = ErrorCode.Ok; GXByteBuffer bb = new GXByteBuffer(); // Get type. ActionRequestType type = (ActionRequestType)data.GetUInt8(); // Get invoke ID and priority. byte invokeId = data.GetUInt8(); // CI ObjectType ci = (ObjectType)data.GetUInt16(); byte[] ln = new byte[6]; data.Get(ln); // Attribute Id byte id = data.GetUInt8(); // Get parameters. object parameters = null; byte selection = data.GetUInt8(); if (xml != null) { xml.AppendStartTag(Command.MethodRequest); if (type == ActionRequestType.Normal) { xml.AppendStartTag(Command.MethodRequest, ActionRequestType.Normal); xml.AppendLine(TranslatorTags.InvokeId, "Value", xml.IntegerToHex(invokeId, 2)); AppendMethodDescriptor(xml, (int)ci, ln, id); if (selection != 0) { //MethodInvocationParameters xml.AppendStartTag(TranslatorTags.MethodInvocationParameters); GXDataInfo di = new GXDataInfo(); di.xml = xml; GXCommon.GetData(settings, data, di); xml.AppendEndTag(TranslatorTags.MethodInvocationParameters); } xml.AppendEndTag(Command.MethodRequest, ActionRequestType.Normal); } xml.AppendEndTag(Command.MethodRequest); return; } if (selection != 0) { GXDataInfo info = new GXDataInfo(); parameters = GXCommon.GetData(settings, data, info); } GXDLMSObject obj = settings.Objects.FindByLN(ci, GXDLMSObject.ToLogicalName(ln)); if (!settings.Connected && (ci != ObjectType.AssociationLogicalName || id != 1)) { replyData.Set(GXDLMSServer.GenerateConfirmedServiceError(ConfirmedServiceError.InitiateError, ServiceError.Service, (byte)Service.Unsupported)); return; } if (obj == null) { obj = server.NotifyFindObject(ci, 0, GXDLMSObject.ToLogicalName(ln)); } if (obj == null) { // Device reports a undefined object. error = ErrorCode.UndefinedObject; } else { if (obj.GetMethodAccess(id) == MethodAccessMode.NoAccess) { error = ErrorCode.ReadWriteDenied; } else { ValueEventArgs e = new ValueEventArgs(settings, obj, id, 0, parameters); server.NotifyAction(new ValueEventArgs[] { e }); byte[] actionReply; if (e.Handled) { actionReply = (byte[])e.Value; } else { actionReply = (obj as IGXDLMSBase).Invoke(settings, e); } //Set default action reply if not given. if (actionReply != null && e.Error == 0) { //Add return parameters bb.SetUInt8(1); //Add parameters error code. bb.SetUInt8(0); GXCommon.SetData(settings, bb, GXCommon.GetValueType(actionReply), actionReply); } else { error = e.Error; //Add return parameters bb.SetUInt8(0); } } } GXDLMSLNParameters p = new GXDLMSLNParameters(settings, Command.MethodResponse, 1, null, bb, (byte)error); GXDLMS.GetLNPdu(p, replyData); //If High level authentication fails. if (!settings.Connected && obj is GXDLMSAssociationLogicalName && id == 1) { server.NotifyInvalidConnection(connectionInfo); } }
protected override void Disconnected(GXDLMSConnectionEventArgs e) { Console.WriteLine("Disconnected"); }
///<summary> /// Handle received command. ///</summary> private byte[] HandleCommand(Command cmd, GXByteBuffer data, GXDLMSConnectionEventArgs connectionInfo) { byte frame = 0; switch (cmd) { case Command.AccessRequest: GXDLMSLNCommandHandler.HandleAccessRequest(Settings, this, data, replyData, null); break; case Command.SetRequest: GXDLMSLNCommandHandler.HandleSetRequest(Settings, this, data, replyData, null); break; case Command.WriteRequest: GXDLMSSNCommandHandler.HandleWriteRequest(Settings, this, data, replyData, null); break; case Command.GetRequest: if (data.Size != 0) { GXDLMSLNCommandHandler.HandleGetRequest(Settings, this, data, replyData, null); } break; case Command.ReadRequest: GXDLMSSNCommandHandler.HandleReadRequest(Settings, this, data, replyData, null); break; case Command.MethodRequest: GXDLMSLNCommandHandler.HandleMethodRequest(Settings, this, data, connectionInfo, replyData, null); break; case Command.Snrm: HandleSnrmRequest(); frame = (byte)Command.Ua; break; case Command.Aarq: HandleAarqRequest(data, connectionInfo); break; case Command.ReleaseRequest: case Command.DisconnectRequest: GenerateDisconnectRequest(); Settings.Connected = false; Disconnected(connectionInfo); frame = (byte)Command.Ua; break; case Command.None: //Get next frame. break; default: Debug.WriteLine("Invalid command: " + (int)cmd); break; } byte[] reply; if (this.InterfaceType == Enums.InterfaceType.WRAPPER) { reply = GXDLMS.GetWrapperFrame(Settings, replyData); } else { reply = GXDLMS.GetHdlcFrame(Settings, frame, replyData); } return reply; }
///<summary> /// Handle action request. ///</summary> public static void HandleMethodRequest(GXDLMSSettings settings, GXDLMSServer server, GXByteBuffer data, GXDLMSConnectionEventArgs connectionInfo, GXByteBuffer replyData, GXDLMSTranslatorStructure xml) { ErrorCode error = ErrorCode.Ok; GXByteBuffer bb = new GXByteBuffer(); // Get type. ActionRequestType type = (ActionRequestType)data.GetUInt8(); // Get invoke ID and priority. byte invokeId = data.GetUInt8(); settings.UpdateInvokeId(invokeId); // CI ObjectType ci = (ObjectType)data.GetUInt16(); byte[] ln = new byte[6]; data.Get(ln); // Attribute Id byte id = data.GetUInt8(); // Get parameters. object parameters = null; byte selection = data.GetUInt8(); if (xml != null) { xml.AppendStartTag(Command.MethodRequest); if (type == ActionRequestType.Normal) { xml.AppendStartTag(Command.MethodRequest, ActionRequestType.Normal); xml.AppendLine(TranslatorTags.InvokeId, "Value", xml.IntegerToHex(invokeId, 2)); AppendMethodDescriptor(xml, (int)ci, ln, id); if (selection != 0) { //MethodInvocationParameters xml.AppendStartTag(TranslatorTags.MethodInvocationParameters); GXDataInfo di = new GXDataInfo(); di.xml = xml; GXCommon.GetData(settings, data, di); xml.AppendEndTag(TranslatorTags.MethodInvocationParameters); } xml.AppendEndTag(Command.MethodRequest, ActionRequestType.Normal); } xml.AppendEndTag(Command.MethodRequest); return; } if (selection != 0) { GXDataInfo info = new GXDataInfo(); parameters = GXCommon.GetData(settings, data, info); } GXDLMSObject obj = settings.Objects.FindByLN(ci, GXCommon.ToLogicalName(ln)); if (settings.Connected == ConnectionState.None && !settings.CanAccess() && (ci != ObjectType.AssociationLogicalName || id != 1)) { replyData.Set(GXDLMSServer.GenerateConfirmedServiceError(ConfirmedServiceError.InitiateError, ServiceError.Service, (byte)Service.Unsupported)); return; } if (obj == null) { obj = server.NotifyFindObject(ci, 0, GXCommon.ToLogicalName(ln)); } if (obj == null) { // Device reports a undefined object. error = ErrorCode.UndefinedObject; } else { ValueEventArgs e = new ValueEventArgs(server, obj, id, 0, parameters); e.InvokeId = invokeId; if (server.NotifyGetMethodAccess(e) == MethodAccessMode.NoAccess) { error = ErrorCode.ReadWriteDenied; } else { server.NotifyAction(new ValueEventArgs[] { e }); byte[] actionReply; if (e.Handled) { actionReply = (byte[])e.Value; } else { actionReply = (obj as IGXDLMSBase).Invoke(settings, e); server.NotifyPostAction(new ValueEventArgs[] { e }); } //Set default action reply if not given. if (actionReply != null && e.Error == 0) { //Add return parameters bb.SetUInt8(1); //Add parameters error code. bb.SetUInt8(0); GXCommon.SetData(settings, bb, GXDLMSConverter.GetDLMSDataType(actionReply), actionReply); } else { error = e.Error; //Add return parameters bb.SetUInt8(0); } } invokeId = (byte)e.InvokeId; } GXDLMSLNParameters p = new GXDLMSLNParameters(null, settings, invokeId, Command.MethodResponse, 1, null, bb, (byte)error); GXDLMS.GetLNPdu(p, replyData); //If High level authentication fails. if (obj is GXDLMSAssociationLogicalName && id == 1) { if ((obj as GXDLMSAssociationLogicalName).AssociationStatus == Objects.Enums.AssociationStatus.Associated) { server.NotifyConnected(connectionInfo); settings.Connected |= ConnectionState.Dlms; } else { server.NotifyInvalidConnection(connectionInfo); settings.Connected &= ~ConnectionState.Dlms; } } }
protected override void InvalidConnection(GXDLMSConnectionEventArgs e) { }