public bool HandleFileAsdu(ASDU asdu) { bool asduHandled = true; switch (asdu.TypeId) { case TypeID.F_SC_NA_1: /* File/Section/Directory Call/Select */ DebugLog("Received SELECT/CALL"); if (state == FileClientState.WAITING_FOR_FILE_READY) { if (asdu.Cot == CauseOfTransmission.UNKNOWN_TYPE_ID) { if (fileReceiver != null) { fileReceiver.Finished(FileErrorCode.UNKNOWN_SERVICE); } } else if (asdu.Cot == CauseOfTransmission.UNKNOWN_COMMON_ADDRESS_OF_ASDU) { if (fileReceiver != null) { fileReceiver.Finished(FileErrorCode.UNKNOWN_CA); } } else if (asdu.Cot == CauseOfTransmission.UNKNOWN_INFORMATION_OBJECT_ADDRESS) { if (fileReceiver != null) { fileReceiver.Finished(FileErrorCode.UNKNOWN_IOA); } } else { if (fileReceiver != null) { fileReceiver.Finished(FileErrorCode.PROTOCOL_ERROR); } } } else { if (fileReceiver != null) { fileReceiver.Finished(FileErrorCode.PROTOCOL_ERROR); } } ResetStateToIdle(); break; case TypeID.F_FR_NA_1: /* File ready */ DebugLog("Received FILE READY"); if (state == FileClientState.WAITING_FOR_FILE_READY) { //TODO check ca, ioa, nof FileReady fileReady = (FileReady)asdu.GetElement(0); if (fileReady.Positive) { ASDU callFile = NewAsdu(new FileCallOrSelect(ioa, nof, 0, SelectAndCallQualifier.REQUEST_FILE)); master.SendASDU(callFile); DebugLog("Send CALL FILE"); state = FileClientState.WAITING_FOR_SECTION_READY; } else { if (fileReceiver != null) { fileReceiver.Finished(FileErrorCode.FILE_NOT_READY); } ResetStateToIdle(); } } else if (state == FileClientState.IDLE) { //TODO call user callback to //TODO send positive or negative ACK state = FileClientState.WAITING_FOR_SECTION_READY; } else { AbortFileTransfer(FileErrorCode.PROTOCOL_ERROR); } break; case TypeID.F_SR_NA_1: /* Section ready */ DebugLog("Received SECTION READY"); if (state == FileClientState.WAITING_FOR_SECTION_READY) { SectionReady sc = (SectionReady)asdu.GetElement(0); if (sc.NotReady == false) { ASDU callSection = NewAsdu(new FileCallOrSelect(ioa, nof, 0, SelectAndCallQualifier.REQUEST_SECTION)); master.SendASDU(callSection); DebugLog("Send CALL SECTION"); segmentOffset = 0; state = FileClientState.RECEIVING_SECTION; } else { AbortFileTransfer(FileErrorCode.SECTION_NOT_READY); } } else if (state == FileClientState.IDLE) { } else { if (fileReceiver != null) { fileReceiver.Finished(FileErrorCode.PROTOCOL_ERROR); } ResetStateToIdle(); } break; case TypeID.F_SG_NA_1: /* Segment */ DebugLog("Received SEGMENT"); if (state == FileClientState.RECEIVING_SECTION) { FileSegment segment = (FileSegment)asdu.GetElement(0); if (fileReceiver != null) { fileReceiver.SegmentReceived(segment.NameOfSection, segmentOffset, segment.LengthOfSegment, segment.SegmentData); } segmentOffset += segment.LengthOfSegment; } else if (state == FileClientState.IDLE) { } else { AbortFileTransfer(FileErrorCode.PROTOCOL_ERROR); } break; case TypeID.F_LS_NA_1: /* Last segment or section */ DebugLog("Received LAST SEGMENT/SECTION"); if (state != FileClientState.IDLE) { FileLastSegmentOrSection lastSection = (FileLastSegmentOrSection)asdu.GetElement(0); if (lastSection.LSQ == LastSectionOrSegmentQualifier.SECTION_TRANSFER_WITHOUT_DEACT) { if (state == FileClientState.RECEIVING_SECTION) { ASDU segmentAck = NewAsdu(new FileACK(ioa, nof, lastSection.NameOfSection, AcknowledgeQualifier.POS_ACK_SECTION, FileError.DEFAULT)); master.SendASDU(segmentAck); DebugLog("Send SEGMENT ACK"); state = FileClientState.WAITING_FOR_SECTION_READY; } else { AbortFileTransfer(FileErrorCode.PROTOCOL_ERROR); } } else if (lastSection.LSQ == LastSectionOrSegmentQualifier.FILE_TRANSFER_WITH_DEACT) { /* slave aborted transfer */ if (fileReceiver != null) { fileReceiver.Finished(FileErrorCode.ABORTED_BY_REMOTE); } ResetStateToIdle(); } else if (lastSection.LSQ == LastSectionOrSegmentQualifier.FILE_TRANSFER_WITHOUT_DEACT) { if (state == FileClientState.WAITING_FOR_SECTION_READY) { ASDU fileAck = NewAsdu(new FileACK(ioa, nof, lastSection.NameOfSection, AcknowledgeQualifier.POS_ACK_FILE, FileError.DEFAULT)); master.SendASDU(fileAck); DebugLog("Send FILE ACK"); if (fileReceiver != null) { fileReceiver.Finished(FileErrorCode.SUCCESS); } ResetStateToIdle(); } else { DebugLog("Illegal state: " + state.ToString()); AbortFileTransfer(FileErrorCode.PROTOCOL_ERROR); } } } break; default: asduHandled = false; break; } return(asduHandled); }
public bool HandleFileAsdu(ASDU asdu) { bool handled = true; switch (asdu.TypeId) { case TypeID.F_AF_NA_1: /* 124 - ACK file, ACK section */ logger("Received file/section ACK F_AF_NA_1"); if (asdu.Cot == CauseOfTransmission.FILE_TRANSFER) { if (transferState != FileServerState.UNSELECTED_IDLE) { IFileProvider file = selectedFile.provider; FileACK ack = (FileACK)asdu.GetElement(0); if (ack.AckQualifier == AcknowledgeQualifier.POS_ACK_FILE) { logger("Received positive file ACK"); if (transferState == FileServerState.WAITING_FOR_FILE_ACK) { selectedFile.provider.TransferComplete(true); availableFiles.RemoveFile(selectedFile.provider); selectedFile = null; transferState = FileServerState.UNSELECTED_IDLE; } else { logger("Unexpected file transfer state --> abort file transfer"); transferState = FileServerState.SEND_ABORT; } } else if (ack.AckQualifier == AcknowledgeQualifier.NEG_ACK_FILE) { logger("Received negative file ACK - stop transfer"); if (transferState == FileServerState.WAITING_FOR_FILE_ACK) { selectedFile.provider.TransferComplete(false); selectedFile.selectedBy = null; selectedFile = null; transferState = FileServerState.UNSELECTED_IDLE; } else { logger("Unexpected file transfer state --> abort file transfer"); transferState = FileServerState.SEND_ABORT; } } else if (ack.AckQualifier == AcknowledgeQualifier.NEG_ACK_SECTION) { logger("Received negative file section ACK - repeat section"); if (transferState == FileServerState.WAITING_FOR_SECTION_ACK) { currentSectionOffset = 0; sectionChecksum = 0; ASDU sectionReady = new ASDU(alParameters, CauseOfTransmission.FILE_TRANSFER, false, false, 0, file.GetCA(), false); sectionReady.AddInformationObject( new SectionReady(selectedFile.provider.GetIOA(), selectedFile.provider.GetNameOfFile(), currentSectionNumber, currentSectionSize, false)); connection.SendASDU(sectionReady); transferState = FileServerState.TRANSMIT_SECTION; } else { logger("Unexpected file transfer state --> abort file transfer"); transferState = FileServerState.SEND_ABORT; } } else if (ack.AckQualifier == AcknowledgeQualifier.POS_ACK_SECTION) { if (transferState == FileServerState.WAITING_FOR_SECTION_ACK) { currentSectionNumber++; int nextSectionSize = selectedFile.provider.GetSectionSize(currentSectionNumber); ASDU responseAsdu = new ASDU(alParameters, CauseOfTransmission.FILE_TRANSFER, false, false, 0, file.GetCA(), false); if (nextSectionSize == -1) { logger("Reveived positive file section ACK - send last section indication"); responseAsdu.AddInformationObject( new FileLastSegmentOrSection(file.GetIOA(), file.GetNameOfFile(), (byte)currentSectionNumber, LastSectionOrSegmentQualifier.FILE_TRANSFER_WITHOUT_DEACT, fileChecksum)); transferState = FileServerState.WAITING_FOR_FILE_ACK; } else { logger("Reveived positive file section ACK - send next section ready indication"); currentSectionSize = nextSectionSize; responseAsdu.AddInformationObject( new SectionReady(selectedFile.provider.GetIOA(), selectedFile.provider.GetNameOfFile(), currentSectionNumber, currentSectionSize, false)); transferState = FileServerState.WAITING_FOR_SECTION_CALL; } connection.SendASDU(responseAsdu); sectionChecksum = 0; } else { logger("Unexpected file transfer state --> abort file transfer"); transferState = FileServerState.SEND_ABORT; } } } else { // No file transmission in progress --> what to do? logger("Unexpected File ACK message -> ignore"); } } else { asdu.Cot = CauseOfTransmission.UNKNOWN_CAUSE_OF_TRANSMISSION; connection.SendASDU(asdu); } break; case TypeID.F_SC_NA_1: /* 122 - Call/Select directoy/file/section */ logger("Received call/select F_SC_NA_1"); if (asdu.Cot == CauseOfTransmission.FILE_TRANSFER) { FileCallOrSelect sc = (FileCallOrSelect)asdu.GetElement(0); if (sc.SCQ == SelectAndCallQualifier.SELECT_FILE) { if (transferState == FileServerState.UNSELECTED_IDLE) { logger("Received SELECT FILE"); CS101n104File file = availableFiles.GetFile(asdu.Ca, sc.ObjectAddress, sc.NOF); if (file == null) { asdu.Cot = CauseOfTransmission.UNKNOWN_INFORMATION_OBJECT_ADDRESS; connection.SendASDU(asdu); } else { ASDU fileReady = new ASDU(alParameters, CauseOfTransmission.FILE_TRANSFER, false, false, 0, asdu.Ca, false); // check if already selected if (file.selectedBy == null) { file.selectedBy = this; fileReady.AddInformationObject(new FileReady(sc.ObjectAddress, sc.NOF, file.provider.GetFileSize(), true)); } else { fileReady.AddInformationObject(new FileReady(sc.ObjectAddress, sc.NOF, 0, false)); } connection.SendASDU(fileReady); selectedFile = file; transferState = FileServerState.WAITING_FOR_FILE_CALL; } } else { logger("Unexpected SELECT FILE message"); } } else if (sc.SCQ == SelectAndCallQualifier.DEACTIVATE_FILE) { logger("Received DEACTIVATE FILE"); if (transferState != FileServerState.UNSELECTED_IDLE) { if (selectedFile != null) { selectedFile.selectedBy = null; selectedFile = null; } transferState = FileServerState.UNSELECTED_IDLE; } else { logger("Unexpected DEACTIVATE FILE message"); } } else if (sc.SCQ == SelectAndCallQualifier.REQUEST_FILE) { logger("Received CALL FILE"); if (transferState == FileServerState.WAITING_FOR_FILE_CALL) { if (selectedFile.provider.GetIOA() != sc.ObjectAddress) { logger("Unkown IOA"); asdu.Cot = CauseOfTransmission.UNKNOWN_INFORMATION_OBJECT_ADDRESS; connection.SendASDU(asdu); } else { ASDU sectionReady = new ASDU(alParameters, CauseOfTransmission.FILE_TRANSFER, false, false, 0, asdu.Ca, false); sectionReady.AddInformationObject(new SectionReady(sc.ObjectAddress, selectedFile.provider.GetNameOfFile(), 0, 0, false)); connection.SendASDU(sectionReady); logger("Send SECTION READY"); currentSectionNumber = 0; currentSectionOffset = 0; currentSectionSize = selectedFile.provider.GetSectionSize(0); transferState = FileServerState.WAITING_FOR_SECTION_CALL; } } else { logger("Unexpected FILE CALL message"); } } else if (sc.SCQ == SelectAndCallQualifier.REQUEST_SECTION) { logger("Received CALL SECTION"); if (transferState == FileServerState.WAITING_FOR_SECTION_CALL) { if (selectedFile.provider.GetIOA() != sc.ObjectAddress) { logger("Unkown IOA"); asdu.Cot = CauseOfTransmission.UNKNOWN_INFORMATION_OBJECT_ADDRESS; connection.SendASDU(asdu); } else { transferState = FileServerState.TRANSMIT_SECTION; } } else { logger("Unexpected SECTION CALL message"); } } } else if (asdu.Cot == CauseOfTransmission.REQUEST) { logger("Call directory received"); availableFiles.SendDirectoy(connection, false); } else { asdu.Cot = CauseOfTransmission.UNKNOWN_CAUSE_OF_TRANSMISSION; connection.SendASDU(asdu); } break; default: handled = false; break; } return(handled); }
private bool HandleApplicationLayer(byte[] msg, int userDataStart, int userDataLength) { ASDU asdu; try { asdu = new ASDU(parameters, buffer, userDataStart, userDataStart + userDataLength); } catch (ASDUParsingException e) { DebugLog("ASDU parsing failed: " + e.Message); return(false); } bool messageHandled = false; switch (asdu.TypeId) { case TypeID.C_IC_NA_1: /* 100 - interrogation command */ DebugLog("Rcvd interrogation command C_IC_NA_1"); if ((asdu.Cot == CauseOfTransmission.ACTIVATION) || (asdu.Cot == CauseOfTransmission.DEACTIVATION)) { if (this.interrogationHandler != null) { InterrogationCommand irc = (InterrogationCommand)asdu.GetElement(0); if (this.interrogationHandler(this.InterrogationHandlerParameter, this, asdu, irc.QOI)) { messageHandled = true; } } } else { asdu.Cot = CauseOfTransmission.UNKNOWN_CAUSE_OF_TRANSMISSION; this.SendASDU(asdu); } break; case TypeID.C_CI_NA_1: /* 101 - counter interrogation command */ DebugLog("Rcvd counter interrogation command C_CI_NA_1"); if ((asdu.Cot == CauseOfTransmission.ACTIVATION) || (asdu.Cot == CauseOfTransmission.DEACTIVATION)) { if (this.counterInterrogationHandler != null) { CounterInterrogationCommand cic = (CounterInterrogationCommand)asdu.GetElement(0); if (this.counterInterrogationHandler(this.counterInterrogationHandlerParameter, this, asdu, cic.QCC)) { messageHandled = true; } } } else { asdu.Cot = CauseOfTransmission.UNKNOWN_CAUSE_OF_TRANSMISSION; this.SendASDU(asdu); } break; case TypeID.C_RD_NA_1: /* 102 - read command */ DebugLog("Rcvd read command C_RD_NA_1"); if (asdu.Cot == CauseOfTransmission.REQUEST) { DebugLog("Read request for object: " + asdu.Ca); if (this.readHandler != null) { ReadCommand rc = (ReadCommand)asdu.GetElement(0); if (this.readHandler(this.readHandlerParameter, this, asdu, rc.ObjectAddress)) { messageHandled = true; } } } else { asdu.Cot = CauseOfTransmission.UNKNOWN_CAUSE_OF_TRANSMISSION; this.SendASDU(asdu); } break; case TypeID.C_CS_NA_1: /* 103 - Clock synchronization command */ DebugLog("Rcvd clock sync command C_CS_NA_1"); if (asdu.Cot == CauseOfTransmission.ACTIVATION) { if (this.clockSynchronizationHandler != null) { ClockSynchronizationCommand csc = (ClockSynchronizationCommand)asdu.GetElement(0); if (this.clockSynchronizationHandler(this.clockSynchronizationHandlerParameter, this, asdu, csc.NewTime)) { messageHandled = true; } } } else { asdu.Cot = CauseOfTransmission.UNKNOWN_CAUSE_OF_TRANSMISSION; this.SendASDU(asdu); } break; case TypeID.C_TS_NA_1: /* 104 - test command */ DebugLog("Rcvd test command C_TS_NA_1"); if (asdu.Cot != CauseOfTransmission.ACTIVATION) { asdu.Cot = CauseOfTransmission.UNKNOWN_CAUSE_OF_TRANSMISSION; } else { asdu.Cot = CauseOfTransmission.ACTIVATION_CON; } this.SendASDU(asdu); messageHandled = true; break; case TypeID.C_RP_NA_1: /* 105 - Reset process command */ DebugLog("Rcvd reset process command C_RP_NA_1"); if (asdu.Cot == CauseOfTransmission.ACTIVATION) { if (this.resetProcessHandler != null) { ResetProcessCommand rpc = (ResetProcessCommand)asdu.GetElement(0); if (this.resetProcessHandler(this.resetProcessHandlerParameter, this, asdu, rpc.QRP)) { messageHandled = true; } } } else { asdu.Cot = CauseOfTransmission.UNKNOWN_CAUSE_OF_TRANSMISSION; this.SendASDU(asdu); } break; case TypeID.C_CD_NA_1: /* 106 - Delay acquisition command */ DebugLog("Rcvd delay acquisition command C_CD_NA_1"); if ((asdu.Cot == CauseOfTransmission.ACTIVATION) || (asdu.Cot == CauseOfTransmission.SPONTANEOUS)) { if (this.delayAcquisitionHandler != null) { DelayAcquisitionCommand dac = (DelayAcquisitionCommand)asdu.GetElement(0); if (this.delayAcquisitionHandler(this.delayAcquisitionHandlerParameter, this, asdu, dac.Delay)) { messageHandled = true; } } } else { asdu.Cot = CauseOfTransmission.UNKNOWN_CAUSE_OF_TRANSMISSION; this.SendASDU(asdu); } break; } if (messageHandled == false) { messageHandled = fileServer.HandleFileAsdu(asdu); } if ((messageHandled == false) && (this.asduHandler != null)) { if (this.asduHandler(this.asduHandlerParameter, this, asdu)) { messageHandled = true; } } if (messageHandled == false) { asdu.Cot = CauseOfTransmission.UNKNOWN_TYPE_ID; this.SendASDU(asdu); } return(true); }