def AA_7(dul: "DULServiceProvider") -> str: """Association abort AA-7. If receive a association request or invalid PDU while waiting for connection to close, send A-ABORT PDU State-event triggers: Sta13 + Evt6/Evt19 Parameters ---------- dul : dul.DULServiceProvider The DICOM Upper Layer Service instance for the local AE Returns ------- str ``'Sta13'``, the next state of the state machine """ primitive = A_P_ABORT() primitive.provider_reason = 0x02 # Send A-ABORT PDU pdu = A_ABORT_RQ() pdu.from_primitive(primitive) sock = cast("AssociationSocket", dul.socket) sock.send(pdu.encode()) evt.trigger(dul.assoc, evt.EVT_PDU_SENT, {'pdu': pdu}) return 'Sta13'
def AA_7(dul): """Association abort AA-7. If receive a association request or invalid PDU while waiting for connection to close, issue A-ABORT State-event triggers: Sta13 + Evt6/Evt19 References ---------- 1. DICOM Standard 2015b, PS3.8, Table 9-7, "Associate Establishment Related Actions" Parameters ---------- dul : pynetdicom.dul.DULServiceProvider The DICOM Upper Layer Service instance for the local AE Returns ------- str Sta13, the next state of the state machine """ # Send A-ABORT PDU. pdu = A_ABORT_RQ() pdu.source = 0x02 pdu.reason_diagnostic = 0x02 # Callback dul.assoc.acse.debug_send_abort(pdu) dul.socket.send(pdu.encode()) return 'Sta13'
def run(self): """ The main threading.Thread run loop. Runs constantly, checking the connection for incoming data. When incoming data is received it categorises it and add its to the `to_user_queue`. """ # Main DUL loop self._idle_timer.start() while True: # Let the assoc reactor off the leash if not self.assoc._dul_ready.is_set(): self.assoc._dul_ready.set() # This effectively controls how quickly the DUL does anything time.sleep(self._run_loop_delay) if self._kill_thread: break # Check the ARTIM timer first so its event is placed on the queue # ahead of any other events this loop if self.artim_timer.expired: self.event_queue.put('Evt18') # Check the connection for incoming data try: # We can either encode and send a primitive **OR** # receive and decode a PDU per loop of the reactor if self._check_incoming_primitive(): pass elif self._is_transport_event(): self._idle_timer.restart() except Exception as exc: LOGGER.error("Exception in DUL.run(), aborting association") LOGGER.exception(exc) # Bypass the state machine and send an A-ABORT # we do it this way because an exception here will mess up # the state machine and we can't guarantee it'll get sent # otherwise abort_pdu = A_ABORT_RQ() abort_pdu.source = 0x02 abort_pdu.reason_diagnostic = 0x00 self.socket.send(abort_pdu.encode()) self.assoc.is_aborted = True self.assoc.is_established = False # Hard shutdown of the Association and DUL reactors self.assoc._kill = True self._kill_thread = True return # Check the event queue to see if there is anything to do try: event = self.event_queue.get(block=False) # If the queue is empty, return to the start of the loop except queue.Empty: continue self.state_machine.do_action(event)
def test_conversion(self): """ Check conversion to a PDU produces the correct output """ primitive = A_P_ABORT() primitive.provider_reason = 4 pdu = A_ABORT_RQ() pdu.from_primitive(primitive) data = pdu.encode() assert data == b"\x07\x00\x00\x00\x00\x04\x00\x00\x02\x04"
def test_conversion(self): """ Check conversion to a PDU produces the correct output """ primitive = A_ABORT() primitive.abort_source = 0 pdu = A_ABORT_RQ() pdu.from_primitive(primitive) data = pdu.encode() assert data == b"\x07\x00\x00\x00\x00\x04\x00\x00\x00\x00"
def AA_8(dul: "DULServiceProvider") -> str: """Association abort AA-8. If receive invalid event, send A-ABORT PDU, issue A-P-ABORT indication and start ARTIM timer State-event triggers: Evt3 + Sta3/6/7/8/9/10/11/12, Evt4 + Sta3/5/6/7/8/9/10/11/12, Evt6 + Sta3/5/6/7/8/9/10/11/12, Evt10 + Sta3/5/8/9/10/11/12, Evt12 + Sta3/5/8/9/10/11/12, Evt13 + Sta3/5/6/8/9/12, Evt19 + Sta3/5/6/7/8/9/10/11/12 Parameters ---------- dul : dul.DULServiceProvider The DICOM Upper Layer Service instance for the local AE Returns ------- str ``'Sta13'``, the next state of the state machine """ # Send A-ABORT PDU (service-dul source), issue A-P-ABORT # indication, and start ARTIM timer. # Send A-ABORT PDU pdu = A_ABORT_RQ() pdu.source = 0x02 # A-P-ABORT pdu.reason_diagnostic = 0x00 sock = cast("AssociationSocket", dul.socket) sock.send(pdu.encode()) evt.trigger(dul.assoc, evt.EVT_PDU_SENT, {'pdu': pdu}) # Issue A-P-ABORT to user primitive = A_P_ABORT() primitive.provider_reason = 0x05 dul.to_user_queue.put(primitive) dul.artim_timer.start() return 'Sta13'
def run_reactor(self) -> None: """Run the DUL reactor. The main :class:`threading.Thread` run loop. Runs constantly, checking the connection for incoming data. When incoming data is received it categorises it and add its to the :attr:`~DULServiceProvider.to_user_queue`. """ # Main DUL loop self._idle_timer.start() self.socket = cast("AssociationSocket", self.socket) sleep = False while True: # Let the assoc reactor off the leash if not self.assoc._dul_ready.is_set(): self.assoc._dul_ready.set() # When single-stepping the reactor, sleep between events so that # test code has time to run. sleep = True if sleep: # If there were no events to process on the previous loop, # sleep before checking again, otherwise check immediately # Setting `_run_loop_delay` higher will use less CPU when idle, but # will also increase the latency to respond to new requests time.sleep(self._run_loop_delay) if self._kill_thread: break # Check the ARTIM timer first so its event is placed on the queue # ahead of any other events this loop if self.artim_timer.expired: self.event_queue.put("Evt18") # Check the connection for incoming data try: # We can either encode and send a primitive **OR** # receive and decode a PDU per loop of the reactor if self._process_recv_primitive( ): # encode (sent by state machine) pass elif self._is_transport_event(): # receive and decode PDU self._idle_timer.restart() except Exception as exc: LOGGER.error("Exception in DUL.run(), aborting association") LOGGER.exception(exc) # Bypass the state machine and send an A-ABORT # we do it this way because an exception here will mess up # the state machine and we can't guarantee it'll get sent # otherwise abort_pdu = A_ABORT_RQ() abort_pdu.source = 0x02 abort_pdu.reason_diagnostic = 0x00 self.socket.send(abort_pdu.encode()) self.assoc.is_aborted = True self.assoc.is_established = False # Hard shutdown of the Association and DUL reactors self.assoc._kill = True self._kill_thread = True return # Check the event queue to see if there is anything to do try: event = self.event_queue.get(block=False) # If the queue is empty, return to the start of the loop except queue.Empty: sleep = True continue self.state_machine.do_action(event) sleep = False