public IEnumerable <CFindResponse> GetResponse(CFindRequest cFind, Entity ae) { var client = new TcpClient(); client.ConnectAsync(IPAddress.Parse(ae.IpAddress), ae.Port).Wait(); var assoc = new Association(this, client) { AeTitle = ae.AeTitle }; PDataMessenger.Send(cFind, assoc); var responses = new List <CFindResponse>(); Services.DIMSEService.DIMSEResponseHandler <CFindResponse> action = null; action = (resp, asc) => { responses.Add(resp); if (resp.Status != (ushort)Status.PENDING) { DIMSEService.CFindResponseReceived -= action; } }; DIMSEService.CFindResponseReceived += action; assoc.Listen(); return(responses); }
/// <summary> /// Sends a message to an entity /// </summary> /// <param name="dimse">the message to send</param> /// <param name="ae">the entity to send the message</param> /// <returns>true if message send was success</returns> public bool SendMessage(AbstractDIMSERequest dimse, Entity ae) { IPAddress ipAddress; if (!IPAddress.TryParse(this.ApplicationEntity.IpAddress, out ipAddress)) { Logger.Log($"Could not parse IP address {this.ApplicationEntity.IpAddress}"); } IPEndPoint ipLocalEndPoint = new IPEndPoint(ipAddress, this.ApplicationEntity.Port); using (var client = new TcpClient(ipLocalEndPoint)) { try { client.ConnectAsync(IPAddress.Parse(ae.IpAddress), ae.Port).Wait(); var assoc = new Association(this, client) { AeTitle = ae.AeTitle }; PDataMessenger.Send(dimse, assoc); assoc.Listen(); return(true); } catch (Exception e) { Logger.Log($"Could not connect to {ae.AeTitle} @{ae.IpAddress}:{ae.Port}", LogPriority.ERROR); Logger.Log($"{e.ToString()}", LogPriority.ERROR); return(false); } } }
/// <summary> /// Sends a message to an entity and guarantees the message will be sent on a /// specific port (set by the entity settings) /// </summary> /// <param name="dimse">the message to send</param> /// <param name="ae">the entity to send the message</param> /// <returns>true if message send was success</returns> public bool SendMessageForcePort(AbstractDIMSERequest dimse, Entity ae) { var(ipLocalEndPoint, success) = IpHelper.VerifyIPAddress(this.ApplicationEntity.IpAddress, this.ApplicationEntity.Port); if (!success) { return(false); } using (var client = new TcpClient(ipLocalEndPoint)) { try { var connectionResult = client.BeginConnect(IPAddress.Parse(ae.IpAddress), ae.Port, null, null); success = connectionResult.AsyncWaitHandle.WaitOne(TimeSpan.FromMilliseconds(ConnectionTimeout)); if (!success) { throw new TimeoutException($"Couldn't connect to {IPAddress.Parse(ae.IpAddress)}:{ae.Port} within {ConnectionTimeout} ms!"); } var assoc = new Association(this, client) { AeTitle = ae.AeTitle }; PDataMessenger.Send(dimse, assoc); assoc.Listen(); return(true); } catch (Exception e) { Logger.Log($"Could not connect to {ae.AeTitle} @{ae.IpAddress}:{ae.Port}", LogPriority.ERROR); Logger.Log($"{e.ToString()}", LogPriority.ERROR); return(false); } } }
public IEnumerable <CMoveResponse> GetResponse(CMoveRequest cMove, Entity ae) { var client = new TcpClient(); client.Connect(IPAddress.Parse(ae.IpAddress), ae.Port); var assoc = new Association(this, client) { AeTitle = ae.AeTitle }; PDataMessenger.Send(cMove, assoc); List <CMoveResponse> responses = new List <CMoveResponse>(); EvilDICOM.Network.Services.DIMSEService.DIMSEResponseHandler <CMoveResponse> action = null; action = (resp, asc) => { responses.Add(resp); if (resp.Status != (ushort)Status.PENDING) { this.DIMSEService.CMoveResponseReceived -= action; } }; this.DIMSEService.CMoveResponseReceived += action; assoc.Listen(); return(responses); }
/// <summary> /// Sends a message to an entity /// </summary> /// <param name="dimse">the message to send</param> /// <param name="ae">the entity to send the message</param> /// <returns>true if message send was success</returns> public bool SendMessage(AbstractDIMSERequest dimse, Entity ae) { using (var client = new TcpClient()) { try { var connectionResult = client.BeginConnect(IPAddress.Parse(ae.IpAddress), ae.Port, null, null); var completed = connectionResult.AsyncWaitHandle.WaitOne(TimeSpan.FromMilliseconds(ConnectionTimeout)); if (completed && !client.Client.Connected) { throw new TimeoutException($"Couldn't connect to {IPAddress.Parse(ae.IpAddress)}:{ae.Port} within {ConnectionTimeout} ms!"); } var assoc = new Association(this, client) { AeTitle = ae.AeTitle }; PDataMessenger.Send(dimse, assoc); assoc.Listen(TimeSpan.FromMilliseconds(IdleTimeout)); return(true); } catch (Exception e) { Logger.Log($"Could not connect to {ae.AeTitle} @{ae.IpAddress}:{ae.Port}", LogPriority.ERROR); Logger.Log($"{e.ToString()}", LogPriority.ERROR); return(false); } } }
public void Listen(TimeSpan?maxWaitTime = null) { maxWaitTime = maxWaitTime ?? TimeSpan.FromSeconds(25); var clock = new Stopwatch(); clock.Start(); while (State != NetworkState.CLOSING_ASSOCIATION && clock.Elapsed < maxWaitTime) { if (_abortRequested) { Logger.Log("Abort requested...aborting."); HandleAbort(); break; } if (_cancelRequested) { Logger.Log("Cancellation requested...cancelling."); HandleCancel(); } if (State != NetworkState.CLOSING_ASSOCIATION && State != NetworkState.TRANSPORT_CONNECTION_OPEN) { var message = Read(); if (message != null) { clock.Restart(); Process(message); Stream.Flush(); clock.Restart(); } } if (State == NetworkState.TRANSPORT_CONNECTION_OPEN && !OutboundMessages.IsEmpty) { while (OutboundMessages.Any()) { if (State == NetworkState.TRANSPORT_CONNECTION_OPEN) { AbstractDIMSEBase dimse; if (OutboundMessages.TryDequeue(out dimse)) { PDataMessenger.Send(dimse, this); } } } } if (!IsClientConnected) { Logger.Log("Connection closed - ending association."); break; } } if (State != NetworkState.CLOSING_ASSOCIATION) { Logger.Log("Network timeout - closing association."); } }
public void OnRequestReceived(NEventReportRequest req, Association asc) { asc.Logger.Log("<-- DIMSE" + req.GetLogString()); req.LogData(asc); asc.LastActive = DateTime.Now; var resp = new NEventReportResponse(req, Status.SUCCESS); _dms.RaiseDIMSERequestReceived(req, asc); PDataMessenger.Send(resp, asc); }
private void HandleCancel() { AbstractDIMSEBase cancel; OutboundMessages.TryPeek(out cancel); if (cancel is CCancel) { OutboundMessages.TryDequeue(out cancel); Stream.Flush(); PDataMessenger.Send(cancel, this); } }
public void SendMessage(AbstractDIMSERequest dimse, Entity ae) { var client = new TcpClient(); client.Connect(IPAddress.Parse(ae.IpAddress), ae.Port); var assoc = new Association(this, client) { AeTitle = ae.AeTitle }; PDataMessenger.Send(dimse, assoc); assoc.Listen(); }
public void ReadWriteDIMSETest() { using (var stream = new MemoryStream()) { //Generate a DIMSE var dimse = CFind.CreateStudyQuery("123456"); var pContext = new PresentationContext() { AbstractSyntax = AbstractSyntax.STUDY_FIND, TransferSyntaxes = new List <string>() { TransferSyntaxHelper.IMPLICIT_VR_LITTLE_ENDIAN } }; PDataMessenger.WriteDimseToStream(dimse, stream, pContext); //Wrap stream in buffer to get to network stream using (var bs = new BufferedStream(stream)) { bs.Position = 0; var net = new NetworkBinaryReader(bs); var pdata = PDataProcessor.ReadPDataTFs(net); var dcm = PDataProcessor.GetCommandObject(pdata); AbstractDIMSE dimseRead; var success = DIMSEReader.TryReadDIMSE(dcm, out dimseRead); Assert.AreEqual(dimse.Elements.Count, dimseRead.Elements.Count); for (int i = 0; i < dimse.Elements.Count; i++) { var el1 = dimse.Elements[i]; var el2 = dimseRead.Elements[i]; Assert.AreEqual(el1.Tag, el2.Tag); Assert.AreEqual(el1.DData, el2.DData); } //Make sure this DIMSE was written with data Assert.IsTrue(dimse.HasData); //REad the data var dataPds = PDataProcessor.ReadPDataTFs(net); var data = PDataProcessor.GetDataObject(dataPds, TransferSyntax.IMPLICIT_VR_LITTLE_ENDIAN); DICOMAssert.AreEqual(data, dimse.Data); } } }
public void GetChunksTest() { //Generate a DIMSE var dimse = CFind.CreateStudyQuery("123456"); var pContext = new PresentationContext() { AbstractSyntax = AbstractSyntax.STUDY_FIND, TransferSyntaxes = new List <string>() { TransferSyntaxHelper.IMPLICIT_VR_LITTLE_ENDIAN } }; var bytes = PDataMessenger.GetChunks(dimse.Data, 16534, pContext); var bytes1 = bytes[0]; var dcm = DICOMObject.Read(bytes1); DICOMAssert.AreEqual(dcm, dimse.Data); }
/// <summary> /// Sends a message to an entity /// </summary> /// <param name="dimse">the message to send</param> /// <param name="ae">the entity to send the message</param> /// <returns>true if message send was success</returns> public SendStatus SendMessage(AbstractDIMSERequest dimse, Entity ae) { using (var client = new TcpClient()) { var status = new SendStatus(); try { var connectionResult = client.BeginConnect(IPAddress.Parse(ae.IpAddress), ae.Port, null, null); var completed = connectionResult.AsyncWaitHandle.WaitOne(TimeSpan.FromMilliseconds(ConnectionTimeout)); if (completed && !client.Client.Connected) { status.DidConnect = false; return(status); } //Connected. Attempt association status.DidConnect = true; var assoc = new Association(this, client) { AeTitle = ae.AeTitle }; AssociationRejectedHandler rejectedHandler = (rej, asc) => { status.WasRejected = true; status.Reason = Enum.GetName(typeof(RejectReason_SCU), rej.Reason); }; this.AssociationService.AssociationRejectionReceived += rejectedHandler; PDataMessenger.Send(dimse, assoc); assoc.Listen(TimeSpan.FromMilliseconds(IdleTimeout)); this.AssociationService.AssociationRejectionReceived -= rejectedHandler; return(status); } catch (Exception e) { Logger.LogError($"Could not connect to {ae.AeTitle} @{ae.IpAddress}:{ae.Port}"); Logger.LogError($"{e.ToString()}"); return(status); } } }
public void OnRequestRecieved(CFindRequest req, Association asc) { asc.Logger.LogInformation("<-- DIMSE" + req.GetLogString()); req.LogData(asc); asc.LastActive = DateTime.Now; asc.IdleClock.Restart(); asc.State = NetworkState.TRANSPORT_CONNECTION_OPEN; var resp = new CFindResponse(req, Status.SUCCESS); dms.RaiseDIMSERequestReceived(req, asc); var results = RetrieveResults(req); if (results != null) { foreach (var result in results) { resp.Data = new DICOMObject(result.Elements); resp.Status = (ushort)Status.PENDING; resp.GroupLength = (uint)GroupWriter.WriteGroupBytes(new DICOMObject(resp.Elements.Skip(1).ToList()), new DICOMIOSettings(), "0000").Length; PDataMessenger.Send(resp, asc, asc.PresentationContexts.First(p => p.Id == req.DataPresentationContextId)); } //Finish resp.Status = results.Any() ? (ushort)Status.SUCCESS : (ushort)Status.FAILURE_UNABLE_TO_FIND; resp.Data = null; resp.GroupLength = (uint)GroupWriter.WriteGroupBytes(new DICOMObject(resp.Elements.Skip(1).ToList()), new DICOMIOSettings(), "0000").Length; PDataMessenger.Send(resp, asc); } else { resp.Status = (ushort)Status.FAILURE; resp.Data = null; resp.GroupLength = (uint)GroupWriter.WriteGroupBytes(new DICOMObject(resp.Elements.Skip(1).ToList()), new DICOMIOSettings(), "0000").Length; PDataMessenger.Send(resp, asc); } }
public void OnRequestReceived(NActionRequest req, Association asc) { asc.Logger.LogInformation("<-- DIMSE" + req.GetLogString()); req.LogData(asc); asc.LastActive = DateTime.Now; var resp = new NActionResponse(req, Status.SUCCESS); _dms.RaiseDIMSERequestReceived(req, asc); //STORAGE COMMITMENT PUSH if (req.RequestedSOPClassUID == AbstractSyntax.StorageCommitment_Push) { resp.Status = (ushort)Status.SUCCESS; PDataMessenger.Send(resp, asc); PerformStorageCommitment(req, asc); } else { //Abstract syntax not supported resp.Status = (ushort)Status.FAILURE_UNABLE_TO_PROCESS; PDataMessenger.Send(resp, asc); } }
/// <summary> /// Sends a message to an entity /// </summary> /// <param name="dimse">the message to send</param> /// <param name="ae">the entity to send the message</param> /// <returns>true if message send was success</returns> public bool SendMessage(AbstractDIMSERequest dimse, Entity ae) { using (var client = new TcpClient()) { try { client.ConnectAsync(IPAddress.Parse(ae.IpAddress), ae.Port).Wait(); var assoc = new Association(this, client) { AeTitle = ae.AeTitle }; PDataMessenger.Send(dimse, assoc); assoc.Listen(); return(true); } catch (Exception e) { Logger.Log($"Could not connect to {ae.AeTitle} @{ae.IpAddress}:{ae.Port}", LogPriority.ERROR); Logger.Log($"{e.ToString()}", LogPriority.ERROR); return(false); } } }
public void OnRequestRecieved(CStoreRequest req, Association asc) { asc.Logger.Log("<-- DIMSE" + req.GetLogString()); req.LogData(asc); asc.LastActive = DateTime.Now; asc.State = NetworkState.TRANSPORT_CONNECTION_OPEN; var resp = new CStoreResponse(req, Status.SUCCESS); var syntax = req.Data.FindFirst(TagHelper.SOPClassUID); dms.RaiseDIMSERequestReceived(req, asc); if (syntax != null) { if (asc.PresentationContexts.Any(p => p.Id == req.DataPresentationContextId)) { try { var success = CStorePayloadAction != null?CStorePayloadAction.Invoke(req.Data, asc) : false; resp.Status = success ? resp.Status : (ushort)Status.FAILURE; PDataMessenger.Send(resp, asc, asc.PresentationContexts.First(p => p.Id == req.DataPresentationContextId)); } catch (Exception e) { resp.Status = (ushort)Status.FAILURE; PDataMessenger.Send(resp, asc); } } else { //Abstract syntax not supported resp.Status = (ushort)Status.FAILURE; PDataMessenger.Send(resp, asc); } } }
public void Listen(TimeSpan?maxWaitTime = null) { maxWaitTime = maxWaitTime ?? TimeSpan.FromSeconds(25); IdleClock = IdleClock ?? new Stopwatch(); IdleClock.Reset(); IdleClock.Start(); while (State != NetworkState.CLOSING_ASSOCIATION && IdleClock.Elapsed < maxWaitTime) { if (_abortRequested) { Logger.Log("Abort requested...aborting."); HandleAbort(); break; } if (_cancelRequested) { Logger.Log("Cancellation requested...cancelling."); HandleCancel(); } if (State != NetworkState.CLOSING_ASSOCIATION && State != NetworkState.TRANSPORT_CONNECTION_OPEN) { var message = Read(maxWaitTime.Value.TotalMilliseconds - IdleClock.ElapsedMilliseconds); if (message != null) { try { IdleClock.Restart(); Process(message); Stream.Flush(); IdleClock.Restart(); } catch (IOException e) { Logger.Log($"Network connection was lost. {e.Message}", LogPriority.ERROR); break;//Connection was lost } } } if (State == NetworkState.TRANSPORT_CONNECTION_OPEN && !OutboundMessages.IsEmpty) { while (!OutboundMessages.IsEmpty) { if (State == NetworkState.TRANSPORT_CONNECTION_OPEN) { AbstractDIMSEBase dimse; if (OutboundMessages.TryDequeue(out dimse)) { PDataMessenger.Send(dimse, this); } } } } if (!IsClientConnected) { Logger.Log("Connection closed - ending association."); break; } } if (State != NetworkState.CLOSING_ASSOCIATION) { Logger.Log("Network timeout - closing association."); } }
private void SetDefaultActions() { CEchoRequestReceivedAction = (cEchoReq, asc) => { asc.Logger.Log("<-- DIMSE" + cEchoReq.GetLogString()); if (!asc.ServiceClass.SupportedAbstractSyntaxes.Contains(AbstractSyntax.VERIFICATION)) { return; } asc.LastActive = DateTime.Now; asc.State = NetworkState.TRANSPORT_CONNECTION_OPEN; var response = new CEchoResponse(cEchoReq, Status.SUCCESS); PDataMessenger.Send(response, asc); RaiseDIMSERequestReceived(cEchoReq, asc); }; CEchoResponseReceivedAction = (cEchoRp, asc) => { asc.Logger.Log("<-- DIMSE" + cEchoRp.GetLogString()); asc.LastActive = DateTime.Now; RaiseDIMSEResponseReceived(cEchoRp, asc); AssociationMessenger.SendReleaseRequest(asc); }; CGetRequestReceivedAction = (cGetReq, asc) => { asc.Logger.Log("<-- DIMSE" + cGetReq.GetLogString()); cGetReq.LogData(asc); asc.LastActive = DateTime.Now; asc.State = NetworkState.TRANSPORT_CONNECTION_OPEN; RaiseDIMSERequestReceived(cGetReq, asc); throw new NotImplementedException(); }; CGetResponseReceivedAction = (cGetRes, asc) => { asc.Logger.Log("<-- DIMSE" + cGetRes.GetLogString()); cGetRes.LogData(asc); asc.LastActive = DateTime.Now; RaiseDIMSEResponseReceived(cGetRes, asc); if (cGetRes.Status != (ushort)Status.PENDING) { AssociationMessenger.SendReleaseRequest(asc); } }; CMoveRequestReceivedAction = (cMoveReq, asc) => { asc.Logger.Log("<-- DIMSE" + cMoveReq.GetLogString()); cMoveReq.LogData(asc); asc.LastActive = DateTime.Now; asc.State = NetworkState.TRANSPORT_CONNECTION_OPEN; RaiseDIMSERequestReceived(cMoveReq, asc); throw new NotImplementedException(); }; CMoveResponseReceivedAction = (cMoveRes, asc) => { asc.Logger.Log("<-- DIMSE" + cMoveRes.GetLogString()); cMoveRes.LogData(asc); asc.LastActive = DateTime.Now; RaiseDIMSEResponseReceived(cMoveRes, asc); if (cMoveRes.Status != (ushort)Status.PENDING) { AssociationMessenger.SendReleaseRequest(asc); } }; }
private void SetDefaultActions() { CEchoRequestReceivedAction = (cEchoReq, asc) => { asc.Logger.Log("<-- DIMSE" + cEchoReq.GetLogString()); if (!asc.ServiceClass.SupportedAbstractSyntaxes.Contains(AbstractSyntax.VERIFICATION)) { return; } asc.LastActive = DateTime.Now; asc.State = NetworkState.TRANSPORT_CONNECTION_OPEN; var response = new CEchoResponse(cEchoReq, Status.SUCCESS); PDataMessenger.Send(response, asc); RaiseDIMSERequestReceived <CEchoRequest>(cEchoReq, asc); }; CEchoResponseReceivedAction = (cEchoRp, asc) => { asc.Logger.Log("<-- DIMSE" + cEchoRp.GetLogString()); asc.LastActive = DateTime.Now; RaiseDIMSEResponseReceived <CEchoResponse>(cEchoRp, asc); AssociationMessenger.SendReleaseRequest(asc); }; CFindResponseReceivedAction = (cFindResp, asc) => { asc.Logger.Log("<-- DIMSE" + cFindResp.GetLogString()); asc.LastActive = DateTime.Now; RaiseDIMSEResponseReceived <CFindResponse>(cFindResp, asc); cFindResp.LogData(asc); if (cFindResp.Status != (ushort)Status.PENDING) { AssociationMessenger.SendReleaseRequest(asc); } }; CMoveRequestReceivedAction = (cMoveReq, asc) => { asc.Logger.Log("<-- DIMSE" + cMoveReq.GetLogString()); cMoveReq.LogData(asc); asc.LastActive = DateTime.Now; asc.State = NetworkState.TRANSPORT_CONNECTION_OPEN; RaiseDIMSERequestReceived <CMoveRequest>(cMoveReq, asc); throw new NotImplementedException(); }; CMoveResponseReceivedAction = (cMoveRes, asc) => { asc.Logger.Log("<-- DIMSE" + cMoveRes.GetLogString()); cMoveRes.LogData(asc); asc.LastActive = DateTime.Now; RaiseDIMSEResponseReceived <CMoveResponse>(cMoveRes, asc); if (cMoveRes.Status != (ushort)Status.PENDING) { AssociationMessenger.SendReleaseRequest(asc); } }; CStoreRequestReceivedAction = async(req, asc) => { asc.Logger.Log("<-- DIMSE" + req.GetLogString()); req.LogData(asc); asc.LastActive = DateTime.Now; asc.State = NetworkState.TRANSPORT_CONNECTION_OPEN; var resp = new CStoreResponse(req, Status.SUCCESS); IDICOMElement syntax = req.Data.FindFirst(TagHelper.SOPCLASS_UID); RaiseDIMSERequestReceived <CStoreRequest>(req, asc); if (syntax != null) { //If can store (supported Abstract Syntax) - Try if (asc.PresentationContexts.Any(p => p.Id == req.DataPresentationContextId)) { try { bool success = CStorePayloadAction(req.Data, asc); resp.Status = success ? resp.Status : (ushort)Status.FAILURE; PDataMessenger.Send(resp, asc, asc.PresentationContexts.First(p => p.Id == req.DataPresentationContextId)); } catch (Exception e) { resp.Status = (ushort)Status.FAILURE; PDataMessenger.Send(resp, asc); } } else { //Abstract syntax not supported resp.Status = (ushort)Status.FAILURE; PDataMessenger.Send(resp, asc); } } }; CStoreResponseReceivedAction = (cStoreResp, asc) => { asc.Logger.Log("<-- DIMSE" + cStoreResp.GetLogString()); cStoreResp.LogData(asc); asc.LastActive = DateTime.Now; RaiseDIMSEResponseReceived <CStoreResponse>(cStoreResp, asc); if (cStoreResp.Status != (ushort)Status.PENDING) { AssociationMessenger.SendReleaseRequest(asc); } }; CStorePayloadAction = (dcm, asc) => { return(true); }; }
public void SetDefaultActions() { AbortReceivedAction = (abort, asc) => { asc.Logger.Log("<-- " + abort); RaiseAbortRequestReceived(abort, asc); asc.Release(); }; AssociationRequestReceivedAction = (req, asc) => { asc.Logger.Log("<-- " + req); RaiseAssociationRequestReceived(req, asc); var ctxs = asc.GetResponseContexts(req.PresentationContexts); if (ctxs.Any()) { var accept = Accept.Generate(req, ctxs); asc.UserInfo = req.UserInfo; asc.State = NetworkState.ASSOCIATION_ESTABLISHED_WAITING_ON_DATA; asc.LastActive = DateTime.Now; asc.PresentationContexts = ctxs; //Simplified agreed contexts AssociationMessenger.SendAccept(accept, asc); } else { asc.State = NetworkState.CLOSING_ASSOCIATION; asc.LastActive = DateTime.Now; AssociationMessenger.SendReject(asc); } }; AssociationAcceptanceReceivedAction = (acc, asc) => { asc.Logger.Log("<-- " + acc); RaiseAssociationAcceptanceReceived(acc, asc); asc.SetFinalContexts(acc); if (asc.PresentationContexts.Any()) { asc.UserInfo = acc.UserInfo; asc.State = NetworkState.TRANSPORT_CONNECTION_OPEN; while (asc.OutboundMessages.Any()) { if (asc.State == NetworkState.TRANSPORT_CONNECTION_OPEN) { AbstractDIMSEBase dimse; if (asc.OutboundMessages.TryDequeue(out dimse)) { PDataMessenger.Send(dimse, asc); } } } } else { asc.Release(); } }; AssociationRejectAction = (rej, asc) => { asc.Logger.Log("<-- " + rej); RaiseAssociationRejectionReceived(rej, asc); asc.Release(); }; ReleaseRequestReceivedAction = (rel, asc) => { asc.Logger.Log("<-- " + rel); RaiseReleaseRequestReceived(rel, asc); AssociationMessenger.SendReleaseResponse(asc); asc.Release(); }; ReleaseResponseAction = (rel, asc) => { asc.Logger.Log("<-- " + rel); RaiseReleaseResponseReceived(rel, asc); asc.Release(); }; }