def test_scp_callback_return_dataset_multi(self): """Test on_c_store returning a Dataset status with other elements""" self.scp = DummyStorageSCP() self.scp.status = Dataset() self.scp.status.Status = 0x0001 self.scp.status.ErrorComment = 'Test' self.scp.status.OffendingElement = 0x00080010 self.scp.start() ae = AE(scu_sop_class=[CTImageStorage]) assoc = ae.associate('localhost', 11112) assert assoc.is_established rsp = assoc.send_c_store(DATASET) assert rsp.Status == 0x0001 assert rsp.ErrorComment == 'Test' assert rsp.OffendingElement == 0x00080010 assoc.release() self.scp.stop()
def test_scp_callback_exception(self): """Test on_n_get raising an exception""" self.scp = DummyGetSCP() def on_n_get(attr, context, assoc_info): raise ValueError self.scp.ae.on_n_get = on_n_get self.scp.start() ae = AE() ae.add_requested_context(DisplaySystemSOPClass) assoc = ae.associate('localhost', 11112) assert assoc.is_established status, ds = assoc.send_n_get([(0x7fe0,0x0010)], DisplaySystemSOPClass, '1.2.840.10008.5.1.1.40.1') assert status.Status == 0x0110 assert ds is None assoc.release() self.scp.stop()
def test_callback_exception(self): """Test SCP handles on_c_find yielding an exception""" self.scp = DummyFindSCP() def on_c_find(ds, context, info): raise ValueError self.scp.ae.on_c_find = on_c_find self.scp.start() ae = AE() ae.add_requested_context(GeneralRelevantPatientInformationQuery) ae.acse_timeout = 5 ae.dimse_timeout = 5 assoc = ae.associate('localhost', 11112) assert assoc.is_established result = assoc.send_c_find(self.query, query_model='G') status, identifier = next(result) assert status.Status == 0xC311 pytest.raises(StopIteration, next, result) assoc.release() self.scp.stop()
def test_scp_callback_return_dataset(self): """Test on_n_get returning a Dataset status""" self.scp = DummyGetSCP() self.scp.status = Dataset() # Unknown status self.scp.status.Status = 0x0001 self.scp.start() ae = AE() ae.add_requested_context(DisplaySystemSOPClass) assoc = ae.associate('localhost', 11112) assert assoc.is_established status, ds = assoc.send_n_get([(0x7fe0,0x0010)], DisplaySystemSOPClass, '1.2.840.10008.5.1.1.40.1') assert status.Status == 0x0001 assert ds.PatientName == 'Test' assoc.release() self.scp.stop()
def test_callback_status_none(self): """Test SCP handles on_c_find not yielding a status""" self.scp = DummyFindSCP() self.scp.statuses = [None] self.scp.start() ae = AE() ae.add_requested_context( ProductCharacteristicsQueryInformationModelFind) ae.acse_timeout = 5 ae.dimse_timeout = 5 assoc = ae.associate('localhost', 11112) assert assoc.is_established result = assoc.send_c_find(self.query, query_model='PC') status, identifier = next(result) assert status.Status == 0xC002 pytest.raises(StopIteration, next, result) assoc.release() self.scp.stop()
def test_on_c_find_called(self): """ Check that SCP AE.on_c_find(dataset) was called """ self.scp = DummyFindSCP() self.scp.status = 0x0000 self.scp.start() ds = Dataset() ds.PatientName = '*' ds.QueryRetrieveLevel = "PATIENT" ae = AE(scu_sop_class=[PatientRootQueryRetrieveInformationModelFind]) ae.acse_timeout = 5 ae.dimse_timeout = 5 assoc = ae.associate('localhost', 11112) assert assoc.is_established for (status, ds) in assoc.send_c_find(ds, query_model='P'): assert status.Status == 0x0000 assoc.release() self.scp.stop()
def test_callback_bad_identifier(self): """Test SCP handles a bad callback identifier""" self.scp = DummyFindSCP() self.scp.statuses = [0xFF00, 0xFE00] self.scp.identifiers = [None, None] self.scp.start() ae = AE() ae.add_requested_context(GeneralRelevantPatientInformationQuery) ae.acse_timeout = 5 ae.dimse_timeout = 5 assoc = ae.associate('localhost', 11112) assert assoc.is_established result = assoc.send_c_find(self.query, query_model='G') status, identifier = next(result) assert status.Status == 0xC312 pytest.raises(StopIteration, next, result) assoc.release() self.scp.stop()
def test_on_c_echo_called(self): """ Check that SCP AE.on_c_echo() was called """ self.scp = DummyVerificationSCP() self.scp.start() ae = AE(scu_sop_class=[VerificationSOPClass]) ae.acse_timeout = 5 ae.dimse_timeout = 5 assoc = ae.associate('localhost', 11112) assert assoc.is_established status = assoc.send_c_echo() assert isinstance(status, Dataset) assert 'Status' in status assert status.Status == 0x0000 assoc.release() assert assoc.is_released assert not assoc.is_established self.scp.stop()
def test_on_c_store_called(self): """ Check that SCP AE.on_c_store(dataset) was called """ self.scp = DummyStorageSCP() self.scp.start() ae = AE(scu_sop_class=[RTImageStorage]) ae.acse_timeout = 5 ae.dimse_timeout = 5 assoc = ae.associate('localhost', 11112) assert assoc.is_established status = assoc.send_c_store(DATASET) assert isinstance(status, Dataset) assert 'Status' in status assert status.Status == 0x0000 assoc.release() assert assoc.is_released assert not assoc.is_established self.scp.stop()
def test_scp_callback_context(self): """Test on_c_echo context parameter.""" self.scp = DummyVerificationSCP() self.scp.start() ae = AE(scu_sop_class=[VerificationSOPClass]) ae.acse_timeout = 5 ae.dimse_timeout = 5 assoc = ae.associate('localhost', 11112) assert assoc.is_established rsp = assoc.send_c_echo() assert rsp.Status == 0x0000 assoc.release() assert assoc.is_released assert self.scp.context.context_id == 1 assert self.scp.context.abstract_syntax == '1.2.840.10008.1.1' assert self.scp.context.transfer_syntax == '1.2.840.10008.1.2.1' self.scp.stop()
def test_scp_callback_context(self): """Test on_c_store caontext parameter""" self.scp = DummyStorageSCP() self.scp.start() ae = AE(scu_sop_class=[CTImageStorage]) ae.acse_timeout = 5 ae.dimse_timeout = 5 assoc = ae.associate('localhost', 11112) assert assoc.is_established status = assoc.send_c_store(DATASET) assert status.Status == 0x0000 assoc.release() assert assoc.is_released assert self.scp.context.context_id == 1 assert self.scp.context.abstract_syntax == CTImageStorage.UID assert self.scp.context.transfer_syntax == '1.2.840.10008.1.2.1' self.scp.stop()
def test_callback_bad_attr(self): """Test SCP handles a bad callback attribute list""" self.scp = DummyGetSCP() self.scp.statuses = 0x0000 self.scp.dataset = None self.scp.start() ae = AE() ae.add_requested_context(DisplaySystemSOPClass) ae.acse_timeout = 5 ae.dimse_timeout = 5 assoc = ae.associate('localhost', 11112) assert assoc.is_established status, ds = assoc.send_n_get([(0x7fe0, 0x0010)], DisplaySystemSOPClass, '1.2.840.10008.5.1.1.40.1') assert status.Status == 0x0110 assert ds is None assoc.release() self.scp.stop()
def test_callback_status_int(self): """Test on_c_find yielding an int status""" self.scp = DummyFindSCP() self.scp.statuses = [0xFF00] self.scp.identifiers = [self.query] self.scp.start() ae = AE() ae.add_requested_context(GeneralRelevantPatientInformationQuery) ae.acse_timeout = 5 ae.dimse_timeout = 5 assoc = ae.associate('localhost', 11112) assert assoc.is_established result = assoc.send_c_find(self.query, query_model='G') status, identifier = next(result) assert status.Status == 0xFF00 status, identifier = next(result) assert status.Status == 0x0000 assoc.release() self.scp.stop()
def test_no_response(self): """Test on_c_find yielding success status""" self.scp = DummyFindSCP() self.scp.statuses = [] self.scp.identifiers = [] self.scp.start() ae = AE() ae.add_requested_context(GeneralRelevantPatientInformationQuery) ae.acse_timeout = 5 ae.dimse_timeout = 5 assoc = ae.associate('localhost', 11112) assert assoc.is_established result = assoc.send_c_find(self.query, query_model='G') status, identifier = next(result) assert status.Status == 0x0000 assert identifier is None pytest.raises(StopIteration, next, result) assoc.release() self.scp.stop()
def dcm_echo(ip, port): _ip = ip _port = port print('working') ae = AE(ae_title='DSTools', port=104) ae.add_requested_context(VerificationSOPClass) # Associate with the peer at IP address and Port assoc = ae.associate(_ip, _port) if assoc.is_established: string = 'success' assoc.release() print('success') else: var = 'ping ' + _ip if os.system(var) == 0: print('pinging') def isOpen(_ip, _port): s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.settimeout(3) try: s.connect((_ip, int(_port))) s.shutdown(socket.SHUT_RDWR) return True except: return False finally: s.close() if isOpen(_ip, _port): print('association') string = 'association' else: print('port') string = 'port' else: print('ping') string = 'ping' return string
def test_ae_aborts_assoc(self): """ Association aborts OK """ self.scp = DummyVerificationSCP() self.scp.start() ae = AE(scu_sop_class=[VerificationSOPClass]) ae.acse_timeout = 5 # Test N associate/abort cycles for ii in range(5): assoc = ae.associate('localhost', 11112) self.assertTrue(assoc.is_established) if assoc.is_established: assoc.abort() self.assertFalse(assoc.is_established) self.assertTrue(assoc.is_aborted) self.assertFalse(assoc.is_released) self.assertFalse(assoc.is_rejected) #self.assertTrue(ae.active_associations == []) self.scp.stop()
def test_scp_callback_attr(self): """Test on_n_get attr parameter""" self.scp = DummyGetSCP() self.scp.start() ae = AE() ae.add_requested_context(DisplaySystemSOPClass, '1.2.840.10008.1.2.1') ae.acse_timeout = 5 ae.dimse_timeout = 5 assoc = ae.associate('localhost', 11112) assert assoc.is_established status, ds = assoc.send_n_get([(0x7fe0, 0x0010)], DisplaySystemSOPClass, '1.2.840.10008.5.1.1.40.1') assert status.Status == 0x0000 assert 'PatientName' in ds assoc.release() assert assoc.is_released assert self.scp.attr == [(0x7fe0, 0x0010)] self.scp.stop()
def test_scp_callback_sop_class_extended(self): """Test that the SOP Class Extended info is available.""" def on_ext(req): return req self.scp = DummyStorageSCP() self.scp.ae.on_sop_class_extended = on_ext self.scp.start() ae = AE() ae.add_requested_context(CTImageStorage) ae.acse_timeout = 5 ae.dimse_timeout = 5 ext_neg = [] item = SOPClassExtendedNegotiation() item.sop_class_uid = '1.2.3' item.service_class_application_information = b'\x00\x01' ext_neg.append(item) item = SOPClassExtendedNegotiation() item.sop_class_uid = '1.2.4' item.service_class_application_information = b'\x00\x02' ext_neg.append(item) assoc = ae.associate('localhost', 11112, ext_neg=ext_neg) assert assoc.is_established status = assoc.send_c_store(DATASET) assert status.Status == 0x0000 assoc.release() assert assoc.is_released info = self.scp.info['sop_class_extended'] assert len(info) == 2 assert info['1.2.3'] == b'\x00\x01' assert info['1.2.4'] == b'\x00\x02' self.scp.stop()
def test_callback_status_dataset(self): """Test on_c_find yielding a Dataset status""" self.scp = DummyFindSCP() self.scp.statuses = [Dataset(), 0x0000] self.scp.statuses[0].Status = 0xFF00 self.scp.identifers = [self.query, None] self.scp.start() ae = AE() ae.add_requested_context( ProductCharacteristicsQueryInformationModelFind) ae.acse_timeout = 5 ae.dimse_timeout = 5 assoc = ae.associate('localhost', 11112) assert assoc.is_established result = assoc.send_c_find(self.query, query_model='PC') status, identifier = next(result) assert status.Status == 0xFF00 status, identifier = next(result) assert status.Status == 0x0000 assoc.release() self.scp.stop()
def test_scp_callback_return_dataset_multi(self): """Test on_n_get returning a Dataset status with other elements""" self.scp = DummyGetSCP() self.scp.status = Dataset() self.scp.status.Status = 0x0001 self.scp.status.ErrorComment = 'Test' self.scp.status.OffendingElement = 0x00080010 self.scp.status.ErrorID = 12 self.scp.start() ae = AE() ae.add_requested_context(DisplaySystemSOPClass) assoc = ae.associate('localhost', 11112) assert assoc.is_established status, ds = assoc.send_n_get([(0x7fe0,0x0010)], DisplaySystemSOPClass, '1.2.840.10008.5.1.1.40.1') assert status.Status == 0x0001 assert status.ErrorComment == 'Test' assert status.ErrorID == 12 assert 'OffendingElement' not in status assert ds.PatientName == 'Test' assoc.release() self.scp.stop()
def test_scp_callback_info(self): """Test on_c_echo info parameter.""" self.scp = DummyVerificationSCP() self.scp.start() ae = AE(scu_sop_class=[VerificationSOPClass]) ae.acse_timeout = 5 ae.dimse_timeout = 5 assoc = ae.associate('localhost', 11112) assert assoc.is_established rsp = assoc.send_c_echo() assert rsp.Status == 0x0000 assoc.release() assert assoc.is_released assert self.scp.info['requestor']['address'] == '127.0.0.1' assert self.scp.info['requestor']['ae_title'] == b'PYNETDICOM ' assert self.scp.info['requestor']['called_aet'] == b'ANY-SCP ' assert isinstance(self.scp.info['requestor']['port'], int) assert self.scp.info['acceptor']['port'] == 11112 assert self.scp.info['acceptor']['address'] == '127.0.0.1' assert self.scp.info['acceptor']['ae_title'] == b'PYNETDICOM ' self.scp.stop()
scp_sop_class=[], transfer_syntax=[ExplicitVRLittleEndian]) # Set the extended negotiation SCP/SCU role selection to allow us to receive # C-STORE requests for the supported SOP classes ext_neg = [] for context in ae.presentation_contexts_scu: tmp = SCP_SCU_RoleSelectionNegotiation() tmp.sop_class_uid = context.AbstractSyntax tmp.scu_role = False tmp.scp_role = True ext_neg.append(tmp) # Request association with remote assoc = ae.associate(args.peer, args.port, args.called_aet, ext_neg=ext_neg) # Create query dataset d = Dataset() d.PatientName = '*' d.QueryRetrieveLevel = "PATIENT" if args.worklist: query_model = 'W' elif args.patient: query_model = 'P' elif args.study: query_model = 'S' elif args.psonly: query_model = 'O' else:
TEST_DS_DIR = os.path.join(os.path.dirname(__file__), 'dicom_files') BIG_DATASET = read_file(os.path.join(TEST_DS_DIR, 'RTImageStorage.dcm')) # 2.1 MB DATASET = read_file(os.path.join(TEST_DS_DIR, 'CTImageStorage.dcm')) # 39 kB #scp = DummyStorageSCP(11112) #scp.start() no_runs = 400 ds_per_run = 1 results = [] ae = AE(scu_sop_class=[CTImageStorage, RTImageStorage]) print('Starting...') for ii in range(no_runs): start_time = time.time() assoc = ae.associate('localhost', 11113) for jj in range(ds_per_run): if assoc.is_established: assoc.send_c_store(DATASET) assoc.release() end_time = time.time() delta_time = end_time - start_time results.append(delta_time) total_time = 0.0 for result in results: total_time += result print('Total time: %.2f seconds' %total_time) #scp.stop()
def dicomscan(server, port, results_file): if dicomargs.dimse_command == "echo": sys.stdout.write("Attempting C-Echo scan on " + '%s' % server + '\n') ts = time.strftime("%Y-%m-%d %H:%M") try: # Application Entity Title is a DICOM specific field usually required to be known for successful DICOM communication with C-Commands. The SCU_SOP_UID help to eliminate the need to know # that information. Each C-Command seems to have it's own specific SCU_SOP_UID and the one below is for C-Echo. Note that if the SCU_SOP_UID does not exist then an AET authentication # error message is received which still confirms that it is a DICOM device. # # Additional research shows that many DICOM vendors like to put web wrapping/UI applications over DICOM in which case a different error message (generally PDU 0x0048) will be provided # which is also known to be a DICOM error response for web wrapped DICOM engines. This is also acknowledgement of a valid DICOM device and we know that it was a web wrapped device. ae = AE(scu_sop_class=['1.2.840.10008.1.1']) peerassoc = ae.associate(server, port) dicom_entry = peerassoc.send_c_echo() peerassoc.release() if '%s' % dicom_entry is not None: if results_file is not None: with print_lock: with open(results_file, 'a+') as outfile: dicom_data = 'host: ' + '%s' % server + '\n' + 'is_dicom: true\ndicom_info:' + '%s' % dicom_entry + '\ndicom_port: ' + '%s' % port + '\ntimestamp: ' + '%s' % ts + '\n\n' outfile.write(dicom_data) else: with print_lock: sys.stdout.write("[+] " + '%s' % server + ": " + '%s' % dicom_entry + '\n') else: pass except: try: # Web wrapped DICOM devices will also be sent here and generally receive a Connection Timeout or Connection Refused message so we handle that in here with errorcode Exceptions so that # we can keep scanning the IP range. # # If we do not get a DICOM success message above, we send it here to try to identify what it is if we can. connector = socket(AF_INET, SOCK_STREAM) connector.settimeout(1) connector.connect(('%s' % server, port)) connector.send('Friendly Portscanner\r\n') dicom_entry = connector.recv(2048) connector.close() if results_file is not None: with print_lock: with open(results_file, 'a+') as outfile: dicom_data = 'host: ' + '%s' % server + '\n' + 'is_dicom: false\ndicom_info:' + '%s' % dicom_entry + '\ndicom_port: ' + '%s' % port + '\ntimestamp: ' + '%s' % ts + '\n\n' outfile.write(dicom_data) else: with print_lock: sys.sytdout.write("[-] " + '%s' % server + ": " + '%s' % dicom_entry + '\n') pass except Exception, errorcode: if errorcode[0] == "timed out": sys.stdout.write(server + ": connection " + errorcode[0] + "\n") pass elif errorcode[0] == "connection refused": sys.stdout.write(server + ": connection " + errorcode[0] + "\n") pass else: pass
def store(self, dcmfile): ''' Function to C-STORE a dicom file into a remote receiver Arguments: connection: Parameters for sending DICOM files connection.aet: Application Entity Title, the PACS 'given name' connection.addr: short for address, the IP Address of the server wich is runnig connection.port: usually 11112 for dicom comunication, but customable dcmfile: A file path already parsed as DICOM valid file ''' # store flag basic value store_status = False # dataset standard value dataset = None # Read the DICOM dataset from file 'dcmfile' try: dataset = read_file(dcmfile) except Exception as e: self.logger.error('Could not retrieve dataset from {0}'.format(dcmfile)) # create an application entity instance, titled 'ae_title' ae = AE(ae_title=str(self.title)) # store context uids ae.requested_contexts = StoragePresentationContexts # associate with the peer AE self.logger.debug('Requesting Association with the peer {0}'.format(self.output)) assoc = ae.associate(self.addr, self.port, ae_title=self.title) # check if association is successfully established if assoc.is_established: # check dataset for value equal None if dataset is not None: # try to send 'dcmfile' through a C-STORE call self.logger.debug('C-STORE call, waiting for server status response... ') try: # Send a C-STORE request to the peer with 'dcmfile' status = assoc.send_c_store(dataset) # output the response from the peer if status: self.verbose('C-STORE at {0} returned STATUS: 0x{1:04x}'.format(self.output, status.Status)) # verbose data for success C-STORE of DICOM file self.retrieve_dataset(dataset) # return true for C-STORE of 'dcmfile' store_status = True # if an exception occur while sending 'dcmfile' except Exception as e: self.logger.error('C-STORE at {0} could not return any status. ERROR: {1}'.format(self.output, e)) # if no dataset was received else: self.logger.error('Retrieved dataset triggered and exception') # release the association self.logger.debug('Releasing {0} association'.format(self.title)) if not assoc.is_released: assoc.release() self.logger.debug('Association successfully released')
from pynetdicom3 import AE ae = AE(ae_title="MY_ECHO_SCU_TEST") ae.add_requested_context('1.2.840.10008.1.1') assoc = ae.associate("127.0.0.1", 104) print(assoc) if assoc.is_established: status = assoc.send_c_echo() print(status) assoc.release()
"\n") pass elif errorcode[0] == "connection refused": sys.stdout.write(server + ": connection " + errorcode[0] + "\n") pass else: pass elif dicomargs.dimse_command == "find": # found research Victor Pasknel blog at https://morphuslabs.com/how-i-got-into-hacking-ultrasound-machines-part-02-3b16b799974c. # This did not work against Orthanc so some changes have been made from his test code to be more flexible against other DICOM systems ae = AE(scu_sop_class=QueryRetrieveSOPClassList) # ae = AE(scu_sop_class=['1.2.840.10008.5.1.4.1.2.1.1']) # patient # ae = AE(scu_sop_class=['1.2.840.10008.5.1.4.1.2.2.1']) # Study - requires different dataset # ae = AE(scu_sop_class=['1.2.840.10008.5.1.4.31']) # worklist- requires different dataset association = ae.associate(server, port) if association.is_established: sys.stdout.write('[+] Association Established \n ') dataset = Dataset() dataset.PatientName = '*' dataset.PatientID = '' dataset.PatientSex = '' dataset.PatientBirthDate = '' dataset.StudyDescription = '' dataset.QueryRetrieveLevel = "PATIENT" results = association.send_c_find(dataset, query_model='P') for (status, dataset) in results:
# Set Transfer Syntax options transfer_syntax = [ExplicitVRLittleEndian, ImplicitVRLittleEndian, DeflatedExplicitVRLittleEndian, ExplicitVRBigEndian] if args.request_little: transfer_syntax = [ExplicitVRLittleEndian] elif args.request_big: transfer_syntax = [ExplicitVRBigEndian] elif args.request_implicit: transfer_syntax = [ImplicitVRLittleEndian] # Bind to port 0, OS will pick an available port ae = AE(ae_title=args.calling_aet, port=0, scu_sop_class=StorageSOPClassList, scp_sop_class=[], transfer_syntax=transfer_syntax) # Request association with remote assoc = ae.associate(args.peer, args.port, args.called_aet) if assoc.is_established: logger.info('Sending file: {0!s}'.format(args.dcmfile_in)) status = assoc.send_c_store(dataset) assoc.release()
# Create local AE # Binding to port 0, OS will pick an available port ae = AE(ae_title=args.calling_aet, port=0, scu_sop_class=[VerificationSOPClass], scp_sop_class=[], transfer_syntax=transfer_syntaxes) # Set timeouts ae.network_timeout = args.timeout ae.acse_timeout = args.acse_timeout ae.dimse_timeout = args.dimse_timeout # Request association with remote AE assoc = ae.associate(args.peer, args.port, args.called_aet, max_pdu=args.max_pdu) # If we successfully Associated then send N DIMSE C-ECHOs if assoc.is_established: for ii in range(args.repeat): # `status` is a pydicom Dataset status = assoc.send_c_echo() # Abort or release association if args.abort: assoc.abort() else: assoc.release()
def echo(self): ''' Function to send C-ECHO to a receiver Application Entity Verification SOP Class has a UID of 1.2.840.10008.1.1 we can use the UID string directly when requesting the presentation contexts we want to use in the association Send a DIMSE C-ECHO request to the peer status is a pydicom Dataset object with (at a minimum) a (0000, 0900) Status element ''' # echo_status = False # create an application entity instance, titled 'ae_title' ae = AE(ae_title=str(self.title)) # echo context uuid ae.add_requested_context('1.2.840.10008.1.1') # associate with the peer AE self.logger.debug('Requesting Association with the peer {0}'.format(self.output)) assoc = ae.associate(self.addr, self.port, ae_title=self.title) # check association if assoc.is_established: try: # get C-ECHO status status = assoc.send_c_echo() # log association status self.logger.debug('Association accepted by the peer') # output the response from the peer if status: echo_status = True self.logger.debug('C-ECHO at {0} returned STATUS: 0x{1:04x}'.format(self.output, status.Status)) # except on sending C-ECHO to AE except Exception as e: self.logger.error('C-ECHO at {0} could not return any status. ERROR: {1}'.format(self.output, e)) # check for standarized error of association rejection elif assoc.is_rejected: self.logger.error('Association was rejected by the peer') # check for standarized error of association aborted elif assoc.is_aborted: self.logger.error('Received an A-ABORT from the peer during Association') # log other unkown error as well else: self.logger.error('No status value was received from the peer') # release the association self.logger.debug('Releasing {0} association'.format(self.title)) if not assoc.is_released: assoc.release() self.logger.debug('Association successfully released') # return echo status return echo_status