Sends an Abort message to a connection. This function is available in the PACS Imaging Toolkit.
#include "ltdic.h"
L_INT LDicomNet::SendAbort(nSource, nReason)
The source of the abort. Possible values are:
Value | Meaning |
---|---|
PDU_ABORT_SOURCE_USER | [0] Service user. (SCU) |
PDU_ABORT_SOURCE_PROVIDER | [2] Service provider. (SCP) |
The reason for the abort. If the source of the abort is PDU_ABORT_SOURCE_USER, the reasons for the abort are not significant. If the source of the abort is PDU_ABORT_SOURCE_PROVIDER, the possible values are:
Value | Meaning |
---|---|
PDU_ABORT_REASON_UNKNOWN | [0] Unknown |
PDU_ABORT_REASON_UNRECOGNIZED | [1] Unrecognized PDU |
PDU_ABORT_REASON_UNEXPECTED | [2] Unexpected PDU |
PDU_ABORT_REASON_UNRECOGNIZED_PARAM | [4] Unrecognized PDU parameter |
PDU_ABORT_REASON_UNEXPECTED_PARAM | [5] Unexpected PDU parameter |
PDU_ABORT_REASON_INVALID_PARAM | [6] Invalid PDU parameter value |
Value | Meaning |
---|---|
0 | SUCCESS |
>0 | An error occurred. Refer to Return Codes. |
Calling LDicomNet::SendAbort generates a call to LDicomNet::OnReceiveAbort. At this time the DICOM Association is closed.
NOTE: It is preferable to close a DICOM Association using the LDicomNet::SendReleaseRequest and LDicomNet::SendReleaseResponse. For more information on closing a DICOM Association, refer to Closing a DICOM Associate Connection.
Win32, x64
This is a basic, but complete example that shows a DICOM client sending an abort to a server.
namespace LDicomNet_SendAbort_Namespace
{
// Logs a message
// This implementation logs to the console, and the debug window
L_VOID LogMessage(TCHAR *szMsg)
{
wprintf(TEXT("\n"));
wprintf(szMsg);
OutputDebugStringW(TEXT("\n"));
OutputDebugStringW(szMsg);
}
// *******************************************************************************************
// Client Class
//
// Class that is used to connect to the server
// *******************************************************************************************
class CMyClient : public LDicomNet
{
public:
CMyClient(L_INT32 nMode): LDicomNet(NULL, nMode)
{
m_waitEvent = CreateEvent( NULL, TRUE, TRUE, TEXT("ClientEvent"));
ResetEvent(m_waitEvent);
}
~CMyClient(void)
{
CloseHandle(m_waitEvent);
}
// Client
L_VOID OnConnect (L_INT nError);
L_VOID OnReceiveAssociateAccept (LDicomAssociate *pPDU);
L_VOID OnReceiveReleaseResponse ();
L_BOOL Wait(DWORD timeout = 5000);
private:
HANDLE m_waitEvent;
};
// Continues dispatching messages until hEvent is signalled, our timeout
// Returns TRUE if hEvent is signalled
// Returns FALSE if timeout
L_BOOL MessageLoop (
HANDLE hEvent, // handles that need to be waited on
DWORD timeout // timeout in milliseconds
)
{
DWORD dwStart = GetTickCount();
MSG msg = {0};
volatile L_BOOL bRunForever = TRUE;
while (bRunForever)
{
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
if (WaitForSingleObject(hEvent, 0) == WAIT_OBJECT_0)
{
ResetEvent(hEvent);
return TRUE;
}
DWORD dwCurrent = GetTickCount();
if ((dwCurrent - dwStart) > timeout)
{
return FALSE;
}
}
return TRUE;
}
L_VOID CMyClient::OnConnect(L_INT nError)
{
L_TCHAR szMsg[200] = {0};
wsprintf(szMsg, TEXT("CMyClient::OnConnect: nError[%d]"), nError);
LogMessage(szMsg);
}
L_VOID CMyClient::OnReceiveAssociateAccept (LDicomAssociate *pPDU)
{
UNREFERENCED_PARAMETER(pPDU);
SetEvent(m_waitEvent);
LogMessage(TEXT("CMyClient::OnReceiveAssociateAccept"));
}
L_VOID CMyClient::OnReceiveReleaseResponse()
{
SetEvent(m_waitEvent);
LogMessage(TEXT("CMyClient::OnReceiveReleaseResponse"));
}
L_BOOL CMyClient::Wait(DWORD timeout)
{
L_BOOL bRet = MessageLoop(m_waitEvent, timeout);
return bRet;
}
// *******************************************************************************************
// Server Connection Class
//
// When a client connects, CMyServer creates a new instance of the CMyServerConnection class
// and accepts the connection.
// *******************************************************************************************
class CMyServerConnection : public LDicomNet
{
public:
CMyServerConnection(L_INT32 nMode): LDicomNet(NULL, nMode)
{
}
~CMyServerConnection(void)
{
}
// Server
L_VOID OnReceiveAssociateRequest(LDicomAssociate *pPDU);
L_VOID OnReceiveAbort(L_UCHAR nSource, L_UCHAR nReason);
L_VOID OnReceiveReleaseRequest();
};
#define SIZEINWORD(p) sizeof(p)/sizeof(L_TCHAR)
L_VOID CMyServerConnection::OnReceiveAssociateRequest(LDicomAssociate *pPDU)
{
LogMessage(TEXT("\tCMyServerConnection::OnReceiveAssociateRequest"));
LDicomAssociate DicomAssociate(FALSE);
//Copy presentation objects from received
//Reply that we only support the first Transfer Syntax from the received hPDU
L_TCHAR szTransfer[PDU_MAX_UID_SIZE+1] = {0};
L_TCHAR szAbstract[PDU_MAX_UID_SIZE+1] = {0};
L_INT iPresentationCount = pPDU->GetPresentationCount();
for (L_UCHAR i = 0; i<iPresentationCount; i++)
{
L_UCHAR nId = pPDU->GetPresentation(i);
pPDU->GetTransfer(nId, 0, szTransfer, PDU_MAX_UID_SIZE+1);
L_UCHAR nResult = PDU_ACCEPT_RESULT_SUCCESS;
pPDU->GetAbstract(nId, szAbstract, PDU_MAX_UID_SIZE+1);
DicomAssociate.AddPresentation( nId, nResult, szAbstract);
DicomAssociate.AddTransfer( nId, szTransfer);
}
LogMessage(TEXT("\tCMyServerConnection::SendAssociateAccept"));
SendAssociateAccept(&DicomAssociate);
}
L_VOID CMyServerConnection::OnReceiveAbort(L_UCHAR nSource, L_UCHAR nReason)
{
LogMessage(TEXT("\tCMyServerConnection::OnReceiveAbort"));
switch(nSource)
{
case PDU_ABORT_SOURCE_USER:
LogMessage(TEXT("\t\tSource: PDU_ABORT_SOURCE_USER"));
break;
case PDU_ABORT_SOURCE_PROVIDER:
LogMessage(TEXT("\t\tSource: PDU_ABORT_SOURCE_PROVIDER"));
break;
}
switch(nReason)
{
case PDU_ABORT_REASON_UNKNOWN:
LogMessage(TEXT("\t\tReason: PDU_ABORT_REASON_UNKNOWN"));
break;
case PDU_ABORT_REASON_UNRECOGNIZED:
LogMessage(TEXT("\t\tReason: PDU_ABORT_REASON_UNRECOGNIZED"));
break;
case PDU_ABORT_REASON_UNEXPECTED:
LogMessage(TEXT("\t\tReason: PDU_ABORT_REASON_UNEXPECTED"));
break;
case PDU_ABORT_REASON_UNRECOGNIZED_PARAM:
LogMessage(TEXT("\t\tReason: PDU_ABORT_REASON_UNRECOGNIZED_PARAM"));
break;
case PDU_ABORT_REASON_UNEXPECTED_PARAM:
LogMessage(TEXT("\t\tReason: PDU_ABORT_REASON_UNEXPECTED_PARAM"));
break;
case PDU_ABORT_REASON_INVALID_PARAM:
LogMessage(TEXT("\t\tReason: PDU_ABORT_REASON_INVALID_PARAM"));
break;
}
this->Close();
}
L_VOID CMyServerConnection::OnReceiveReleaseRequest()
{
LogMessage(TEXT("\tCMyServerConnection::OnReceiveReleaseRequest"));
LogMessage(TEXT("\tCMyServerConnection::SendReleaseResponse"));
SendReleaseResponse();
}
// *******************************************************************************************
// Server Class
//
// Listens for connections
// When a client connects, this class creates a CMyServerConnection and accepts the connection
// *******************************************************************************************
class CMyServer : public LDicomNet
{
public:
CMyServer(L_INT32 nMode): LDicomNet(NULL, nMode)
{
m_pServerConnection = NULL;
}
~CMyServer(void)
{
if (m_pServerConnection != NULL)
{
delete m_pServerConnection;
}
}
L_VOID OnAccept (L_INT nError);
L_VOID OnClose (L_INT nError, LDicomNet *pServerConnection);
CMyServerConnection *m_pServerConnection;
};
L_VOID CMyServer::OnAccept(L_INT nError)
{
LogMessage(TEXT("\tCMyServer::OnAccept"));
if (nError != DICOM_SUCCESS)
{
return;
}
if (m_pServerConnection != NULL)
{
delete m_pServerConnection;
m_pServerConnection = NULL;
}
m_pServerConnection = new CMyServerConnection(DICOM_SECURE_NONE);
if (m_pServerConnection == NULL)
{
return;
}
nError = LDicomNet::Accept(m_pServerConnection);
if (nError != DICOM_SUCCESS)
{
delete m_pServerConnection;
return;
}
}
L_VOID CMyServer::OnClose(L_INT nError, LDicomNet *pServerConnection)
{
UNREFERENCED_PARAMETER(nError);
LogMessage(TEXT("\tCMyServer::OnClose"));
if (m_pServerConnection == pServerConnection)
{
m_pServerConnection = NULL;
}
delete (CMyServerConnection *)pServerConnection;
}
// *******************************************************************************************
// Sample starts here
// *******************************************************************************************
#define WaitForProcessing() \
{ \
if (!client.Wait()) \
{ \
LogMessage(TEXT("Timeout: client.Connect")); \
nRet = DICOM_ERROR_NET_TIME_OUT; \
goto Cleanup; \
} \
}
L_INT LDicomNet_SendAbortExample()
{
LogMessage(TEXT("\n\n *** SendAbortExample ***"));
L_TCHAR *pszServerAddress = TEXT("127.0.0.1");
L_UINT uServerPort = 105;
L_INT nRet = DICOM_SUCCESS;
LDicomNet::StartUp();
CMyClient client(DICOM_SECURE_NONE);
CMyServer server(DICOM_SECURE_NONE);
LogMessage(TEXT("\tCMyServer::Listen"));
nRet = server.Listen(pszServerAddress, uServerPort, 5);
LogMessage(TEXT("CMyClient::Connect"));
client.Connect(NULL, 0, pszServerAddress, uServerPort);
if (!client.Wait(2000))
{
if (!client.IsConnected())
{
LogMessage(TEXT("Timeout: client.Connect"));
nRet = DICOM_ERROR_NET_TIME_OUT;
goto Cleanup;
}
}
if (nRet == DICOM_SUCCESS)
{
//create the Associate Class as Request
LDicomAssociate dicomAssociateRequest(TRUE);
dicomAssociateRequest.Default();
// Send A-Associate-RQ message
dicomAssociateRequest.SetCalled(TEXT("LEAD_SERVER"));
dicomAssociateRequest.SetCalling(TEXT("LEAD_CLIENT"));
LogMessage(TEXT("CMyClient::SendAssociateRequest"));
nRet = client.SendAssociateRequest(&dicomAssociateRequest);
if (!client.Wait(2000))
{
LogMessage(TEXT("Timeout: client.Connect"));
nRet = DICOM_ERROR_NET_TIME_OUT;
goto Cleanup;
}
}
LogMessage(TEXT("CMyClient::SendAbort"));
client.SendAbort( PDU_ABORT_SOURCE_USER, PDU_ABORT_REASON_UNKNOWN);
client.Wait(1000);
Cleanup:
LogMessage(TEXT("CMyClient::CloseForced"));
if (client.IsConnected())
{
client.CloseForced(TRUE);
client.Wait(1000);
}
LogMessage(TEXT("\tCMyServer::Close"));
server.Close();
LDicomNet::ShutDown();
return nRet;
}
}