/// <summary> /// Method to send an association release request. this method can only be used by clients. /// </summary> public void SendReleaseRequest() { if (State != DicomAssociationState.Sta6_AssociationEstablished) { Platform.Log(LogLevel.Error, "Unexpected attempt to send Release Request when in invalid state."); return; } var pdu = new AReleaseRQ(); EnqueuePdu(pdu.Write()); State = DicomAssociationState.Sta7_AwaitingAReleaseRP; // still waiting for remote AE to send release response if (AssociationReleasing != null) AssociationReleasing(_assoc); }
/// <summary> /// Method to send an association release response. /// </summary> protected void SendReleaseResponse() { if (State != DicomAssociationState.Sta8_AwaitingAReleaseRPLocalUser) { } var pdu = new AReleaseRP(); EnqueuePdu(pdu.Write()); State = DicomAssociationState.Sta13_AwaitingTransportConnectionClose; if (AssociationReleased != null) AssociationReleased(_assoc); }
/// <summary> /// Method to send an association accept. /// </summary> /// <param name="associate">The parameters to use for the association accept.</param> public void SendAssociateAccept(AssociationParameters associate) { if (State != DicomAssociationState.Sta3_AwaitingLocalAAssociationResponsePrimative) { Platform.Log(LogLevel.Error, "Error attempting to send association accept at invalid time in association."); SendAssociateAbort(DicomAbortSource.ServiceProvider, DicomAbortReason.NotSpecified); throw new DicomNetworkException( "Attempting to send association accept at invalid time in association, aborting"); } var pdu = new AAssociateAC(_assoc); EnqueuePdu(pdu.Write()); State = DicomAssociationState.Sta6_AssociationEstablished; if (AssociationEstablished != null) AssociationEstablished(_assoc); }
/// <summary> /// Method to send an association rejection. /// </summary> /// <param name="result">The </param> /// <param name="source"></param> /// <param name="reason"></param> public void SendAssociateReject(DicomRejectResult result, DicomRejectSource source, DicomRejectReason reason) { if (State != DicomAssociationState.Sta3_AwaitingLocalAAssociationResponsePrimative) { Platform.Log(LogLevel.Error, "Error attempting to send association reject at invalid time in association."); SendAssociateAbort(DicomAbortSource.ServiceProvider, DicomAbortReason.NotSpecified); throw new DicomNetworkException( "Attempting to send association reject at invalid time in association, aborting"); } var pdu = new AAssociateRJ(result, source, reason); EnqueuePdu(pdu.Write()); State = DicomAssociationState.Sta13_AwaitingTransportConnectionClose; if (AssociationRejected != null) AssociationRejected(source, reason); }
/// <summary> /// Method to send an association abort PDU. /// </summary> /// <param name="source">The source of the abort.</param> /// <param name="reason">The reason for the abort.</param> public void SendAssociateAbort(DicomAbortSource source, DicomAbortReason reason) { if (State != DicomAssociationState.Sta13_AwaitingTransportConnectionClose) { var pdu = new AAbort(source, reason); EnqueuePdu(pdu.Write()); State = DicomAssociationState.Sta13_AwaitingTransportConnectionClose; if (AssociationAborted != null) AssociationAborted(_assoc, reason); } else { Platform.Log(LogLevel.Error, "Unexpected state for association abort, closing connection from {0} to {1}", _assoc.CallingAE, _assoc.CalledAE); OnNetworkError(null, true); if (NetworkClosed != null) NetworkClosed("Unexpected state for association abort"); } }
/// <summary> /// Method used to send an association request. /// </summary> /// <param name="associate">The parameters used in the association request.</param> public void SendAssociateRequest(AssociationParameters associate) { _assoc = associate; var pdu = new AAssociateRQ(_assoc); State = DicomAssociationState.Sta5_AwaitingAAssociationACOrReject; EnqueuePdu(pdu.Write()); }
private bool ProcessRawPDU(RawPDU raw) { try { switch (raw.Type) { case 0x01: { _assoc = new ServerAssociationParameters(); var pdu = new AAssociateRQ(_assoc); pdu.Read(raw); State = DicomAssociationState.Sta3_AwaitingLocalAAssociationResponsePrimative; OnReceiveAssociateRequest(_assoc as ServerAssociationParameters); if (State != DicomAssociationState.Sta13_AwaitingTransportConnectionClose && State != DicomAssociationState.Sta6_AssociationEstablished) { Platform.Log(LogLevel.Error, "Association incorrectly not accepted or rejected, aborting."); return false; } //if derived class call SendAssociateAccept, it has fired this event //if (AssociationEstablished != null) // AssociationEstablished(_assoc); return true; } case 0x02: { var pdu = new AAssociateAC(_assoc); pdu.Read(raw); State = DicomAssociationState.Sta6_AssociationEstablished; OnReceiveAssociateAccept(_assoc); if (AssociationEstablished != null) AssociationEstablished(_assoc); return true; } case 0x03: { var pdu = new AAssociateRJ(); pdu.Read(raw); State = DicomAssociationState.Sta13_AwaitingTransportConnectionClose; if (AssociationRejected != null) AssociationRejected(pdu.Source, pdu.Reason); OnReceiveAssociateReject(pdu.Result, pdu.Source, pdu.Reason); return true; } case 0x04: { var pdu = new PDataTF(); pdu.Read(raw); return ProcessPDataTF(pdu); } case 0x05: { var pdu = new AReleaseRQ(); pdu.Read(raw); State = DicomAssociationState.Sta8_AwaitingAReleaseRPLocalUser; OnReceiveReleaseRequest(); return true; } case 0x06: { var pdu = new AReleaseRP(); pdu.Read(raw); State = DicomAssociationState.Sta13_AwaitingTransportConnectionClose; if (AssociationReleased != null) AssociationReleased(_assoc); OnReceiveReleaseResponse(); return true; } case 0x07: { var pdu = new AAbort(); pdu.Read(raw); State = DicomAssociationState.Sta1_Idle; if (AssociationAborted != null) AssociationAborted(_assoc, pdu.Reason); OnReceiveAbort(pdu.Source, pdu.Reason); return true; } case 0xFF: { Platform.Log(LogLevel.Error, "Unexpected PDU type: 0xFF. Potential parsing error."); return false; } default: throw new DicomNetworkException("Unknown PDU type"); } } catch (Exception e) { OnNetworkError(e, true); if (NetworkError != null) NetworkError(e); Platform.Log(LogLevel.Error, e, "Unexpected exception when processing PDU."); return false; } }
/// <summary> /// Main processing routine for processing a network connection. /// </summary> private void RunRead() { try { ResetDimseTimeout(); while (!_stop) { if (NetworkHasData()) { ResetDimseTimeout(); bool success = ProcessNextPDU(); if (!success) { // Start the Abort process, not much else we can do Platform.Log(LogLevel.Error, "Unexpected error processing PDU. Aborting Association from {0} to {1}", _assoc.CallingAE, _assoc.CalledAE); SendAssociateAbort(DicomAbortSource.ServiceProvider, DicomAbortReason.InvalidPDUParameter); } } else if (DateTime.Now > GetDimseTimeout()) { string errorMessage; switch (State) { case DicomAssociationState.Sta6_AssociationEstablished: OnDimseTimeout(); ResetDimseTimeout(); break; case DicomAssociationState.Sta2_TransportConnectionOpen: errorMessage = "ARTIM timeout when waiting for AAssociate Request PDU, closing connection."; Platform.Log(LogLevel.Error, errorMessage); State = DicomAssociationState.Sta13_AwaitingTransportConnectionClose; OnNetworkError(new DicomNetworkException(errorMessage), true); if (NetworkClosed != null) NetworkClosed(errorMessage); break; case DicomAssociationState.Sta5_AwaitingAAssociationACOrReject: errorMessage = "ARTIM timeout when waiting for AAssociate AC or RJ PDU, closing connection."; Platform.Log(LogLevel.Error,errorMessage ); State = DicomAssociationState.Sta13_AwaitingTransportConnectionClose; OnNetworkError(new DicomNetworkException(errorMessage), true); if (NetworkClosed != null) NetworkClosed(errorMessage); break; case DicomAssociationState.Sta13_AwaitingTransportConnectionClose: errorMessage = string.Format( "Timeout when waiting for transport connection to close from {0} to {1}. Dropping Connection.", _assoc.CallingAE, _assoc.CalledAE); Platform.Log(LogLevel.Error, errorMessage); OnNetworkError(new DicomNetworkException(errorMessage), true); if (NetworkClosed != null) NetworkClosed(errorMessage); break; default: Platform.Log(LogLevel.Error, "DIMSE timeout in unexpected state: {0}", State.ToString()); OnDimseTimeout(); ResetDimseTimeout(); break; } } //else //{ // Thread.Sleep(0); //} } _network.Close(); _network.Dispose(); _network = null; } catch (Exception e) { OnNetworkError(e, true); if (NetworkError != null) NetworkError(e); } }
/// <summary> /// Main processing routine for processing a network connection. /// </summary> private void Process() { try { DateTime timeout = _assoc != null ? DateTime.Now.AddMilliseconds(_assoc.ReadTimeout) : DateTime.Now.AddSeconds(Timeout); while (!_stop) { if (NetworkHasData()) { timeout = _assoc != null ? DateTime.Now.AddMilliseconds(_assoc.ReadTimeout) : DateTime.Now.AddSeconds(Timeout); bool success = ProcessNextPDU(); if (!success) { // Start the Abort process, not much else we can do Platform.Log(LogLevel.Error, "Unexpected error processing PDU. Aborting Association from {0} to {1}", _assoc.CallingAE, _assoc.CalledAE); SendAssociateAbort(DicomAbortSource.ServiceProvider, DicomAbortReason.InvalidPDUParameter); } } else if (_pduQueue.Count > 0) { //SendRawPDU(DequeuePdu()); // Note, if this is ever enabled, it would make sense to reset the timeout at this point. // So that the timeout is really based on the last data read or written to the network, instead of // from the last time data was read from the network. } else if (DateTime.Now > timeout) { string errorMessage; switch (State) { case DicomAssociationState.Sta6_AssociationEstablished: OnDimseTimeout(); timeout = DateTime.Now.AddMilliseconds(_assoc.ReadTimeout); break; case DicomAssociationState.Sta2_TransportConnectionOpen: errorMessage = "ARTIM timeout when waiting for AAssociate Request PDU, closing connection."; Platform.Log(LogLevel.Error, errorMessage); State = DicomAssociationState.Sta13_AwaitingTransportConnectionClose; OnNetworkError(new DicomNetworkException(errorMessage), true); if (NetworkClosed != null) NetworkClosed(errorMessage); break; case DicomAssociationState.Sta5_AwaitingAAssociationACOrReject: errorMessage = "ARTIM timeout when waiting for AAssociate AC or RJ PDU, closing connection."; Platform.Log(LogLevel.Error,errorMessage ); State = DicomAssociationState.Sta13_AwaitingTransportConnectionClose; OnNetworkError(new DicomNetworkException(errorMessage), true); if (NetworkClosed != null) NetworkClosed(errorMessage); break; case DicomAssociationState.Sta13_AwaitingTransportConnectionClose: errorMessage = string.Format( "Timeout when waiting for transport connection to close from {0} to {1}. Dropping Connection.", _assoc.CallingAE, _assoc.CalledAE); Platform.Log(LogLevel.Error, errorMessage); OnNetworkError(new DicomNetworkException(errorMessage), true); if (NetworkClosed != null) NetworkClosed(errorMessage); break; default: Platform.Log(LogLevel.Error, "DIMSE timeout in unexpected state: {0}", State.ToString()); OnDimseTimeout(); timeout = _assoc != null ? DateTime.Now.AddMilliseconds(_assoc.ReadTimeout) : DateTime.Now.AddSeconds(Timeout); break; } } //else //{ // Thread.Sleep(0); //} } _network.Close(); _network.Dispose(); _network = null; } catch (Exception e) { OnNetworkError(e, true); if (NetworkError != null) NetworkError(e); } }