// DicomNetSink.cpp : implementation file // #include "stdafx.h" extern CDICOMSRVApp theApp; #include "DicomNetSink.h" #include "SRVDlg.h" extern long glSec; #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif ///////////////////////////////////////////////////////////////////////////// // CDicomNetSink IMPLEMENT_DYNCREATE(CDicomNetSink, CCmdTarget) CDicomNetSink::CDicomNetSink() { EnableAutomation(); m_bSCU=TRUE; m_pDlg=NULL; } CDicomNetSink::~CDicomNetSink() { } void CDicomNetSink::OnFinalRelease() { // When the last reference for an automation object is released // OnFinalRelease is called. The base class will automatically // deletes the object. Add additional cleanup required for your // object before calling the base class. CCmdTarget::OnFinalRelease(); } BEGIN_MESSAGE_MAP(CDicomNetSink, CCmdTarget) //{{AFX_MSG_MAP(CDicomNetSink) // NOTE - the ClassWizard will add and remove mapping macros here. //}}AFX_MSG_MAP END_MESSAGE_MAP() BEGIN_DISPATCH_MAP(CDicomNetSink, CCmdTarget) //{{AFX_DISPATCH_MAP(CDicomNetSink) // NOTE - the ClassWizard will add and remove mapping macros here. DISP_FUNCTION_ID(CDicomNetSink,"NetConnect", 1,OnNetConnect,VT_EMPTY,VTS_I4 VTS_I4) DISP_FUNCTION_ID(CDicomNetSink,"NetAccept", 2,OnNetAccept,VT_EMPTY,VTS_I4) DISP_FUNCTION_ID(CDicomNetSink,"NetClose", 3,OnNetClose,VT_EMPTY,VTS_I4 VTS_I4 VTS_I4) DISP_FUNCTION_ID(CDicomNetSink,"NetReceiveAssociateRequest", 6,OnNetReceiveAssociateRequest,VT_EMPTY,VTS_I4 VTS_I4) DISP_FUNCTION_ID(CDicomNetSink,"NetReceiveAssociateAccept", 7,OnNetReceiveAssociateAccept,VT_EMPTY,VTS_I4 VTS_I4) DISP_FUNCTION_ID(CDicomNetSink,"NetReceiveAssociateReject", 8,OnNetReceiveAssociateReject,VT_EMPTY,VTS_I4 VTS_I2 VTS_I2 VTS_I2) DISP_FUNCTION_ID(CDicomNetSink,"NetReceiveReleaseRequest", 10,OnNetReceiveReleaseRequest,VT_EMPTY,VTS_I4) DISP_FUNCTION_ID(CDicomNetSink,"NetReceiveReleaseResponse", 11,OnNetReceiveReleaseResponse,VT_EMPTY,VTS_I4) DISP_FUNCTION_ID(CDicomNetSink,"NetReceiveAbort", 12,OnNetReceiveAbort,VT_EMPTY,VTS_I4 VTS_I2 VTS_I2) DISP_FUNCTION_ID(CDicomNetSink,"NetReceiveCStoreRequest", 13,OnNetReceiveCStoreRequest,VT_EMPTY,VTS_I4 VTS_I2 VTS_I2 VTS_BSTR VTS_BSTR VTS_I2 VTS_BSTR VTS_I2 VTS_I4) DISP_FUNCTION_ID(CDicomNetSink,"NetReceiveCStoreResponse", 14,OnNetReceiveCStoreResponse,VT_EMPTY,VTS_I4 VTS_I2 VTS_I2 VTS_BSTR VTS_BSTR VTS_I4) /**/DISP_FUNCTION_ID(CDicomNetSink,"NetReceiveCFindRequest", 15,OnNetReceiveCFindRequest, VT_EMPTY,VTS_I4 VTS_I2 VTS_I2 VTS_BSTR VTS_I2 VTS_I4) /**/DISP_FUNCTION_ID(CDicomNetSink, "NetReceiveCMoveRequest", 19, OnNetReceiveCMoveRequest, VT_EMPTY,VTS_I4 VTS_I2 VTS_I2 VTS_BSTR VTS_I2 VTS_BSTR VTS_I4) DISP_FUNCTION_ID(CDicomNetSink,"NetReceiveCEchoRequest", 22,OnNetReceiveCEchoRequest,VT_EMPTY,VTS_I4 VTS_I2 VTS_I2 VTS_BSTR) // DISP_FUNCTION_ID(CDicomNetSink,"NetReceiveCEchoResponse", 23,OnNetReceiveCEchoResponse,VT_EMPTY,VTS_I4 VTS_I2 VTS_I2 VTS_BSTR VTS_I4) /**/DISP_FUNCTION_ID(CDicomNetSink, "NetExternalAuthenticateISCL", 37, OnNetExternalAuthenticateISCL, VT_EMPTY, VTS_I4 VTS_VARIANT VTS_VARIANT VTS_VARIANT ) /**/DISP_FUNCTION_ID(CDicomNetSink, "NetGetChallengeISCL", 38, OnNetGetChallengeISCL , VT_EMPTY, VTS_I4 VTS_VARIANT VTS_VARIANT ) /**/DISP_FUNCTION_ID(CDicomNetSink, "NetInternalAuthenticateISCL", 39, OnNetInternalAuthenticateISCL, VT_EMPTY, VTS_I4 VTS_VARIANT VTS_VARIANT VTS_VARIANT ) DISP_FUNCTION_ID(CDicomNetSink, "SSLPrivateKeyPasswordEvent", 43,OnSSLPrivateKeyPasswordEvent, VT_EMPTY, VTS_I4 VTS_I4) //}}AFX_DISPATCH_MAP END_DISPATCH_MAP() // Note: we add support for IID_IDicomNetSink to support typesafe binding // from VBA. This IID must match the GUID that is attached to the // dispinterface in the .ODL file. // {43AAB0AA-90D7-4118-A9F0-A604EDF0BFA9} static const IID IID_IDicomNetSink = { 0x43aab0aa, 0x90d7, 0x4118, { 0xa9, 0xf0, 0xa6, 0x4, 0xed, 0xf0, 0xbf, 0xa9 } }; BEGIN_INTERFACE_MAP(CDicomNetSink, CCmdTarget) INTERFACE_PART(CDicomNetSink, DIID__LEADDicomNetEvents, Dispatch) END_INTERFACE_MAP() ///////////////////////////////////////////////////////////////////////////// // CDicomNetSink message handlers //******************************************************************************************** //************************************************************** // // Events // //*************************************************************** void CDicomNetSink::OnNetClose(long hNet, long nStatus, long hPeer) { HTREEITEM hItem=NULL; //a client has closed hItem = m_pDlg->m_ConnectionList.GetRootItem(); while(hItem) { if((long)m_pDlg->m_ConnectionList.GetItemData(hItem) == hPeer) { m_pDlg->m_ConnectionList.DeleteItem(hItem); break; } hItem = m_pDlg->m_ConnectionList.GetNextItem(hItem, TVGN_NEXT); } } void CDicomNetSink::OnNetReceiveAssociateRequest(long hNet, long hPDU) { long x; short nID; short nResult; _bstr_t sAbstract; _bstr_t sTransfer; _bstr_t sClient; CString szUser; _bstr_t sUser; _bstr_t sCalled; short nRet; //client wants to Associate //we have received an AssociateRequest sClient = m_pDlg->m_pLEADDICOMNet1->GetPeerAddress(hNet); sUser = m_pDlg->m_pLEADDICOMNet1->GetCalling(hPDU); szUser = (LPSTR)sUser; sCalled = m_pDlg->m_pLEADDICOMNet1->GetCalled(hPDU); m_pDlg->LogEvent(szUser, "Associate Request received"); // //check the version, if not 1, reject it // if(m_pLEADDICOMNet1->GetVersion(hPDU) != 1) // { // m_pLEADDICOMNet1->SendAssociateReject(hNet, PDU_REJECT_RESULT_PERMANENT, // PDU_REJECT_SOURCE_USER, // PDU_REJECT_REASON_VERSION); // LogEvent(szClient, "Associate Reject sent - invalid Version"); // return; // } //reject based on called or calling application titles if((LPSTR)sCalled != m_pDlg->m_szServerAE) { m_pDlg->m_pLEADDICOMNet1->SendAssociateReject(hNet, PDU_REJECT_RESULT_PERMANENT, PDU_REJECT_SOURCE_USER, PDU_REJECT_REASON_CALLING); m_pDlg->LogEvent((LPSTR)sClient, "Associate Reject sent - invalid Called AE Title"); return; } szUser = m_pDlg->GetUserName((LPSTR)sClient); if(szUser.GetLength() < 1) { m_pDlg->LogEvent((LPSTR)sClient, "Associate Reject sent - invalid Calling AE Title"); return; } //send associate accept class back m_pDlg->m_pLEADDICOMNet1->CreateAssociate(FALSE); m_pDlg->m_pLEADDICOMNet1->ResetAssociate(m_pDlg->m_pLEADDICOMNet1->GethPDU(), FALSE); _bstr_t sServerAE(m_pDlg->m_szServerAE); m_pDlg->m_pLEADDICOMNet1->SetCalled(m_pDlg->m_pLEADDICOMNet1->GethPDU(), sServerAE); m_pDlg->m_pLEADDICOMNet1->SetCalling(m_pDlg->m_pLEADDICOMNet1->GethPDU(), sUser); m_pDlg->m_pLEADDICOMNet1->SetApplication(m_pDlg->m_pLEADDICOMNet1->GethPDU(), UID_APPLICATION_CONTEXT_NAME); //copy all presenetation objects from received hPDU //also, reply that we only support the first Transfer Syntax from the received hPDU for(x=0; xm_pLEADDICOMNet1->GetPresentationCount(hPDU); x++) { nID = m_pDlg->m_pLEADDICOMNet1->GetPresentationID(hPDU, x); sAbstract = (LPSTR)m_pDlg->m_pLEADDICOMNet1->GetPresentationAbstract(hPDU, nID); nRet = m_pDlg->m_pLEADDICOM1->FindUID(sAbstract); //If I find the UID in our table, then I assume we support it if(nRet == DICOM_SUCCESS) nResult = PDU_ACCEPT_RESULT_SUCCESS; else nResult = PDU_ACCEPT_RESULT_ABSTRACT_SYNTAX; //indicate not supported m_pDlg->m_pLEADDICOMNet1->AddPresentation(m_pDlg->m_pLEADDICOMNet1->GethPDU(), nID, nResult, sAbstract); if(nResult == PDU_ACCEPT_RESULT_SUCCESS) { //This server will report only supporting Explicit VR - Little Endian sTransfer = UID_EXPLICIT_VR_LITTLE_ENDIAN; m_pDlg->m_pLEADDICOMNet1->AddTransferSyntax(m_pDlg->m_pLEADDICOMNet1->GethPDU(), nID, sTransfer); } } nRet = m_pDlg->m_pLEADDICOMNet1->SendAssociateAccept(hNet); m_pDlg->LogEvent(szUser, "Associate Accept sent"); //now, display the recieved hPDU m_pDlg->DisplayAssociate(hNet, m_pDlg->m_pLEADDICOMNet1->GethPDU()); m_pDlg->LastClientAction(hNet, "Associated", FALSE); } void CDicomNetSink::OnNetReceiveAssociateAccept(long hNet, long hPDU) { short nRet; short nPresentationID; m_pDlg->KillTimer(m_pDlg->m_uTimer); _bstr_t sMoveFile(m_pDlg->m_szMoveFile); _bstr_t sMoveClass(m_pDlg->m_szMoveClass); _bstr_t sSOPInstanceUID(m_pDlg->m_szSOPInstanceUID); _bstr_t sMoveAE(m_pDlg->m_szMoveAE); //send a C-Store nRet = m_pDlg->m_pLEADDICOM2->LoadDS(sMoveFile, 0); //load the referenced file if(nRet != DICOM_SUCCESS) { m_pDlg->m_pLEADDICOMNet2->Close(m_pDlg->m_pLEADDICOMNet2->GethNet()); m_pDlg->m_pLEADDICOMNet2->ShutDown(); m_pDlg->m_pLEADDICOMNet1->SendCMoveResponse(m_pDlg->m_hMoveNet, m_pDlg->m_nMovePresentationID, m_pDlg->m_nMoveMessageID, sMoveClass, COMMAND_STATUS_PROCESSING_FAILURE, 0, 0, 1, 0, 0); } else { nPresentationID = m_pDlg->m_pLEADDICOMNet2->FindPresentationAbstract(m_pDlg->m_pLEADDICOMNet2->GethPDU(), sMoveClass); nRet = m_pDlg->m_pLEADDICOMNet2->SendCStoreRequest(hNet, nPresentationID, 1, sMoveClass, sSOPInstanceUID, 0, sMoveAE, m_pDlg->m_nMoveMessageID, m_pDlg->m_pLEADDICOM2->GethDicomDS()); m_pDlg->m_lSec = 0; m_pDlg->m_uTimer = m_pDlg->SetTimer(99, 1000, NULL); } } void CDicomNetSink::OnNetReceiveAssociateReject(long hNet, short nResult, short nSource, short nReason) { m_pDlg->KillTimer(m_pDlg->m_uTimer); _bstr_t sMoveClass(m_pDlg->m_szMoveClass); //error in association m_pDlg->m_pLEADDICOMNet2->Close(m_pDlg->m_pLEADDICOMNet2->GethNet()); m_pDlg->m_pLEADDICOMNet2->ShutDown(); m_pDlg->m_pLEADDICOMNet1->SendCMoveResponse(m_pDlg->m_hMoveNet, m_pDlg->m_nMovePresentationID, m_pDlg->m_nMoveMessageID, sMoveClass, COMMAND_STATUS_PROCESSING_FAILURE, 0, 0, 1, 0, 0); } void CDicomNetSink::OnNetReceiveReleaseRequest(long hNet) { _bstr_t sUser; CString csClient; //we have received a ReleaseRequest csClient = (LPSTR)m_pDlg->m_pLEADDICOMNet1->GetPeerAddress(hNet); sUser = m_pDlg->GetUserName(csClient); //send Release Response m_pDlg->m_pLEADDICOMNet1->SendReleaseResponse(hNet); m_pDlg->LogEvent((LPSTR)sUser, "Release Request received"); m_pDlg->LastClientAction(hNet, "Association Released", FALSE); } void CDicomNetSink::OnNetReceiveReleaseResponse(long hNet) { long hPDU; CString szUser; //we have received a ReleaseResponse hPDU = m_pDlg->m_pLEADDICOMNet1->GetAssociate(hNet); szUser = (LPSTR)m_pDlg->m_pLEADDICOMNet1->GetCalling(hPDU); m_pDlg->LogEvent(szUser, "Release Response received"); m_pDlg->LastClientAction(hNet, "Association Released", FALSE); } void CDicomNetSink::OnSSLPrivateKeyPasswordEvent(long hNet, long nFlag) { _bstr_t bstrPrivateKeyPassword = theApp.m_strPrivateKeyPassword; m_pDlg->m_pLEADDICOMNet1->SSLPrivateKeyPassword = bstrPrivateKeyPassword; } void CDicomNetSink::OnNetReceiveAbort(long hNet, short nSource, short nReason) { long hPDU; CString szUser; CString csCalling; //we have received an Abort hPDU = m_pDlg->m_pLEADDICOMNet1->GetAssociate(hNet); csCalling = (LPSTR)m_pDlg->m_pLEADDICOMNet1->GetCalling(hPDU); szUser = m_pDlg->GetUserName(csCalling); m_pDlg->LogEvent(szUser, "Abort received"); m_pDlg->LastClientAction(hNet, "Association Aborted", FALSE); } // //NetConnect event void CDicomNetSink::OnNetConnect(long hNet, long nStatus) { m_pDlg->KillTimer(m_pDlg->m_uTimer); _bstr_t sMoveClass(m_pDlg->m_szMoveClass); _bstr_t sServerAE(m_pDlg->m_szServerAE); _bstr_t sMoveAE(m_pDlg->m_szMoveAE); if(nStatus != DICOM_SUCCESS) //must have failed to connect { //error in connecting m_pDlg->m_pLEADDICOMNet1->SendCMoveResponse(hNet, m_pDlg->m_nMovePresentationID, m_pDlg->m_nMoveMessageID, sMoveClass, COMMAND_STATUS_PROCESSING_FAILURE, 0, 0, 1, 0, 0); return; } //now, we need to associate the connection m_pDlg->m_pLEADDICOMNet2->CreateAssociate(TRUE); m_pDlg->m_pLEADDICOMNet2->DefaultAssociate(m_pDlg->m_pLEADDICOMNet2->GethPDU()); //just use default glSec = 0; m_pDlg->m_uTimer = m_pDlg->SetTimer(99, 1000, NULL); m_pDlg->m_pLEADDICOMNet2->SetCalling(m_pDlg->m_pLEADDICOMNet2->GethPDU(), sServerAE); m_pDlg->m_pLEADDICOMNet2->SetCalled(m_pDlg->m_pLEADDICOMNet2->GethPDU(), sMoveAE); m_pDlg->m_pLEADDICOMNet2->SendAssociateRequest(m_pDlg->m_pLEADDICOMNet2->GethNet()); } //NetAccept event void CDicomNetSink::OnNetAccept(long nStatus) { long hClient; long lClients; CString szClient; CString szUser; long lClientPort; HTREEITEM hItem=NULL; HTREEITEM hChild=NULL; int nValidClient = DICOM_SUCCESS; int nRet = DICOM_SUCCESS; _bstr_t bstrServerCertName = theApp.m_strServerCertName; if(m_pDlg->m_pLEADDICOMNet1->GetNetworkSecurityMode() == DICOM_SECURE_ISCL) { m_pDlg->m_pLEADDICOMNet1->SetMutualAuthAlgISCL(m_pDlg->m_pLEADDICOMNet1->GethNet(), DICOM_ISCL_MUTUAL_AUTH_3P4W); COleCurrency cy; cy.m_cur.int64 = 0x002948231925CEE1; COleVariant vCy(cy); m_pDlg->m_pLEADDICOMNet1->SetMutualAuthKeyISCL(m_pDlg->m_pLEADDICOMNet1->GethNet(), 1, vCy); vCy.cyVal.int64 = 0x007990F7B05BDEFF; m_pDlg->m_pLEADDICOMNet1->SetMutualAuthKeyISCL(m_pDlg->m_pLEADDICOMNet1->GethNet(), 2, vCy); vCy.cyVal.int64 = 0x16496DF15B32E1E9; m_pDlg->m_pLEADDICOMNet1->SetMutualAuthKeyISCL(m_pDlg->m_pLEADDICOMNet1->GethNet(), 3, vCy); vCy.cyVal.int64 = 0x01EB0BB32EB8F03C; m_pDlg->m_pLEADDICOMNet1->SetMutualAuthKeyISCL(m_pDlg->m_pLEADDICOMNet1->GethNet(), 4, vCy); vCy.cyVal.int64 = 0x7E87390C0F3E9A24; m_pDlg->m_pLEADDICOMNet1->SetMutualAuthKeyISCL(m_pDlg->m_pLEADDICOMNet1->GethNet(), 5, vCy); vCy.cyVal.int64 = 0x305E440D496953B7; m_pDlg->m_pLEADDICOMNet1->SetMutualAuthKeyISCL(m_pDlg->m_pLEADDICOMNet1->GethNet(), 6, vCy); vCy.cyVal.int64 = 0x154754DE39E0194D; m_pDlg->m_pLEADDICOMNet1->SetMutualAuthKeyISCL(m_pDlg->m_pLEADDICOMNet1->GethNet(), 7, vCy); vCy.cyVal.int64 = 0x4DC8644366FDB1A6; m_pDlg->m_pLEADDICOMNet1->SetMutualAuthKeyISCL(m_pDlg->m_pLEADDICOMNet1->GethNet(), 8, vCy); m_pDlg->m_pLEADDICOMNet1->SetIndexForMutualAuthISCL(m_pDlg->m_pLEADDICOMNet1->GethNet(), 2); vCy.cyVal.int64 = 0x701F5D037AD0C209; m_pDlg->m_pLEADDICOMNet1->SetEncryptKeyISCL(m_pDlg->m_pLEADDICOMNet1->GethNet(), 1, vCy); vCy.cyVal.int64 = 0x12383B251E8D77D4; m_pDlg->m_pLEADDICOMNet1->SetEncryptKeyISCL(m_pDlg->m_pLEADDICOMNet1->GethNet(), 2, vCy); vCy.cyVal.int64 = 0x63CB6BFC80164345; m_pDlg->m_pLEADDICOMNet1->SetEncryptKeyISCL(m_pDlg->m_pLEADDICOMNet1->GethNet(), 3, vCy); vCy.cyVal.int64 = 0x323B221326788C0A; m_pDlg->m_pLEADDICOMNet1->SetEncryptKeyISCL(m_pDlg->m_pLEADDICOMNet1->GethNet(), 4, vCy); vCy.cyVal.int64 = 0x301C0BDB56B53320; m_pDlg->m_pLEADDICOMNet1->SetEncryptKeyISCL(m_pDlg->m_pLEADDICOMNet1->GethNet(), 5, vCy); vCy.cyVal.int64 = 0x759A235023399878; m_pDlg->m_pLEADDICOMNet1->SetEncryptKeyISCL(m_pDlg->m_pLEADDICOMNet1->GethNet(), 6, vCy); vCy.cyVal.int64 = 0x6B365CFD3E2CA832; m_pDlg->m_pLEADDICOMNet1->SetEncryptKeyISCL(m_pDlg->m_pLEADDICOMNet1->GethNet(), 7, vCy); vCy.cyVal.int64 = 0x3BF63A9E79DC56DC; m_pDlg->m_pLEADDICOMNet1->SetEncryptKeyISCL(m_pDlg->m_pLEADDICOMNet1->GethNet(), 8, vCy); m_pDlg->m_pLEADDICOMNet1->SetDefaultEncryptionISCL(m_pDlg->m_pLEADDICOMNet1->GethNet(), DICOM_ISCL_ENCRYPT_DESCBC); m_pDlg->m_pLEADDICOMNet1->SetDefaultSigningISCL(m_pDlg->m_pLEADDICOMNet1->GethNet(), DICOM_ISCL_MAC_MD5); m_pDlg->m_pLEADDICOMNet1->SetIndexForEncryptISCL(m_pDlg->m_pLEADDICOMNet1->GethNet(), 2); m_pDlg->m_pLEADDICOMNet1->SetMaxMessageLengthISCL(m_pDlg->m_pLEADDICOMNet1->GethNet(), 1024000); m_pDlg->m_pLEADDICOMNet1->SetMaxCommBlockLengthISCL(m_pDlg->m_pLEADDICOMNet1->GethNet(), 8129); COleVariant vBuf("LEAD server ISCL"); m_pDlg->m_pLEADDICOMNet1->SetAuthDataISCL(m_pDlg->m_pLEADDICOMNet1->GethNet(), vBuf, 17); m_pDlg->m_pLEADDICOMNet1->UseSSLOptions = FALSE; m_pDlg->m_pLEADDICOMNet1->Accept(); } else if(m_pDlg->m_pLEADDICOMNet1->GetNetworkSecurityMode() == DICOM_SECURE_TLS) { m_pDlg->m_pLEADDICOMNet1->SetCipherToIndexTLS(m_pDlg->m_pLEADDICOMNet1->GethNet(), 0, DICOM_TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA); m_pDlg->m_pLEADDICOMNet1->SSLCreateFlags = (enum DicomSSLCreateFlags)(DICOM_SSL_CTX_CREATE_METHOD_TYPE | DICOM_SSL_CTX_CREATE_OPTIONS | DICOM_SSL_CTX_CREATE_VERIFY_DEPTH | DICOM_SSL_CTX_CREATE_VERIFY_MODE); m_pDlg->m_pLEADDICOMNet1->SSLMethodType = DICOM_TYPE_SSLV23_METHOD; if (_access(theApp.m_strServerCertName, 4)!=0) { _bstr_t bstrCACertName = theApp.m_strCACertName; m_pDlg->m_pLEADDICOMNet1->SSLCAFile = bstrCACertName; m_pDlg->m_pLEADDICOMNet1->SSLCreateFlags = (enum DicomSSLCreateFlags)(m_pDlg->m_pLEADDICOMNet1->SSLCreateFlags | DICOM_SSL_CTX_CREATE_CAFILE); } m_pDlg->m_pLEADDICOMNet1->SSLVerifyMode = (enum DicomSSLVerifyMode)(DICOM_SSL_VERIFY_PEER | DICOM_SSL_VERIFY_FAIL_IF_NO_PEER_CERT); m_pDlg->m_pLEADDICOMNet1->SSLVerifyDepth = 9; m_pDlg->m_pLEADDICOMNet1->SSLOptions = (enum DicomSSLOptions)(DICOM_SSL_OP_NO_SSLv2 | DICOM_SSL_OP_ALL); m_pDlg->m_pLEADDICOMNet1->UseSSLOptions = TRUE; // set the certificate file, password file to be called internally by Accept // this call will fail, but the subsquent call in Accept will succeed nRet = m_pDlg->m_pLEADDICOMNet1->SetServerCertificateTLS(NULL, bstrServerCertName, L_TLS_FILETYPE_PEM, bstrServerCertName); m_pDlg->m_pLEADDICOMNet1->Accept(); nValidClient = m_pDlg->m_pLEADDICOMNet1->SSLSuccess; } else { m_pDlg->m_pLEADDICOMNet1->UseSSLOptions = FALSE; m_pDlg->m_pLEADDICOMNet1->Accept(); } if (nValidClient != DICOM_SUCCESS) { char *pszError = NULL; CString strMsg; pszError = theApp.GetTLSErrorString(nValidClient); // close the connection strMsg.Format("%d %s" "-- closing connection"); m_pDlg->LogEvent( "", strMsg); m_pDlg->m_pLEADDICOMNet1->Close (m_pDlg->m_pLEADDICOMNet1); return; } //get the latest client lClients = m_pDlg->m_pLEADDICOMNet1->GetClientCount(m_pDlg->m_pLEADDICOMNet1->GethNet()); hClient = m_pDlg->m_pLEADDICOMNet1->GetClient(m_pDlg->m_pLEADDICOMNet1->GethNet(), lClients - 1); szClient = (char *)m_pDlg->m_pLEADDICOMNet1->GetPeerAddress(hClient); lClientPort = m_pDlg->m_pLEADDICOMNet1->GetPeerPort(hClient); if(lClients > m_pDlg->m_lMaxClients) //too many connections! { m_pDlg->LogEvent(szClient, "Connection Rejected - Max Connections Reached"); m_pDlg->m_pLEADDICOMNet1->Close(hClient); return; } szUser = m_pDlg->GetUserName(szClient); if(szUser.GetLength() < 1) { //not a valid user, close connection m_pDlg->m_pLEADDICOMNet1->Close(hClient); m_pDlg->LogEvent(szClient, "Connection Rejected - Unknown User"); return; } m_pDlg->LogEvent(szUser, "Connection Accepted"); //display some information about the connection: CString szOut; CTime theTime = CTime::GetCurrentTime(); CString szDate = theTime.Format("%m/%d/%Y %I:%M:%S %p"); szOut.Format("0x%X", hClient); hItem = m_pDlg->m_ConnectionList.InsertItem(szOut, 0, 0); m_pDlg->m_ConnectionList.SetItemData(hItem, hClient); hChild = m_pDlg->m_ConnectionList.InsertItem("Remote AE: " + szUser, 2, 2, hItem); hChild = m_pDlg->m_ConnectionList.InsertItem("Remote Host: " + szClient, 2, 2, hItem); hChild = m_pDlg->m_ConnectionList.InsertItem("Connection Time: " + szDate, 2, 2, hItem); hChild = m_pDlg->m_ConnectionList.InsertItem("Number of Messages: 0", 2, 2, hItem); m_pDlg->m_ConnectionList.SetItemData(hChild, 0); hChild = m_pDlg->m_ConnectionList.InsertItem("Last Action: Connect", 2, 2, hItem); // hChild = m_pDlg->m_ConnectionList.InsertItem("Association:", 1, 1, hItem); } void CDicomNetSink::OnNetReceiveCEchoRequest(long hNet, short nPresentationID, short nMessageID, LPCTSTR pszClass) { short nRet; long nStatus; long hPDU; short nID; CString szClient; CString szUser; CString szCalled; hPDU = m_pDlg->m_pLEADDICOMNet1->GetAssociate(hNet); if(hPDU == 0) { //connection is not associated, so ignore the message return; } //we have received an C-ECHO-REQUEST // szUser = m_pDlg->m_pLEADDICOMNet1->GetCalling(hPDU); // szCalled = m_pDlg->m_pLEADDICOMNet1->GetCalled(hPDU); m_pDlg->LogEvent(szUser, "C-ECHO-REQUEST received"); m_pDlg->LastClientAction(hNet, "C-ECHO-REQUEST", TRUE); nRet = m_pDlg->m_pLEADDICOM1->FindUID(pszClass); if(nRet != DICOM_SUCCESS) nStatus = COMMAND_STATUS_CLASS_NOT_SUPPORTED; else { nID = m_pDlg->m_pLEADDICOMNet1->FindPresentationAbstract(hPDU, pszClass); if((nID == 0) || (m_pDlg->m_pLEADDICOMNet1->GetPresentationResult(hPDU, nID) != PDU_ACCEPT_RESULT_SUCCESS)) { m_pDlg->LogEvent(szUser, "C-ECHO-REQUEST - Abstract Syntax, " + (CString)(LPSTR)m_pDlg->m_pLEADDICOM1->GetCurrentUID()->GetName() + ", Not Supported by Association!"); nStatus = COMMAND_STATUS_CLASS_NOT_SUPPORTED; } else nStatus = COMMAND_STATUS_SUCCESS; } m_pDlg->m_pLEADDICOMNet1->SendCEchoResponse(hNet, nPresentationID, nMessageID, pszClass, nStatus); m_pDlg->LogEvent(szUser, "C-ECHO-RESPONSE sent"); } void CDicomNetSink::OnNetReceiveCStoreRequest(long hNet, short nPresentationID, short nMessageID, LPCTSTR pszClass, LPCTSTR pszInstance, short nPriority, LPCTSTR pszMoveAE, short nMoveMessageID, long hDS) { short nRet; long nStatus; long hPDU=0; short nID; CString szClient; CString szUser; CString szCalled; CString szFile; hPDU = m_pDlg->m_pLEADDICOMNet1->GetAssociate(hNet); if(hPDU == 0) { //connection is not associated, so ignore the message return; } //we have received an C-STORE-REQUEST szUser = (CString)(LPSTR)m_pDlg->m_pLEADDICOMNet1->GetCalling(hPDU); m_pDlg->LogEvent(szUser, "C-STORE-REQUEST received"); m_pDlg->LastClientAction(hNet, "C-STORE-REQUEST", TRUE); nRet = m_pDlg->m_pLEADDICOM1->FindUID(pszClass); if(nRet != DICOM_SUCCESS) nStatus = COMMAND_STATUS_CLASS_NOT_SUPPORTED; else { nID = m_pDlg->m_pLEADDICOMNet1->FindPresentationAbstract(hPDU, pszClass); if((nID == 0) || (m_pDlg->m_pLEADDICOMNet1->GetPresentationResult(hPDU, nID) != PDU_ACCEPT_RESULT_SUCCESS)) { m_pDlg->LogEvent(szUser, "C-STORE-REQUEST - Abstract Syntax, " + (CString)(LPSTR)m_pDlg->m_pLEADDICOM1->GetCurrentUID()->GetName() + ", Not Supported by Association!"); nStatus = COMMAND_STATUS_CLASS_NOT_SUPPORTED; } else nStatus = COMMAND_STATUS_SUCCESS; } //save the SOP Instance if(nStatus == COMMAND_STATUS_SUCCESS) { //add the new data set to the root of the DICOM Dir m_pDlg->m_bImport = FALSE; m_pDlg->m_lServerFileCount++; szFile.Format("%ld.dic", m_pDlg->m_lServerFileCount); m_pDlg->m_pLEADDICOM1->ResetDS(); m_pDlg->m_pLEADDICOM1->SetCurrentElement(0L); m_pDlg->m_pLEADDICOM1->PuthDicomDS(hDS); nRet = m_pDlg->InsertDataSet(m_pDlg->m_pLEADDICOM1, szFile); if(nRet != 0) { if(nRet == 20000) m_pDlg->LogEvent(szUser, "DataSet already exists in Database!"); else m_pDlg->LogEvent(szUser, "Error importing DICOM DataSet"); } else { //save the data set _bstr_t sName(m_pDlg->m_szWorkingDir + szFile); nRet = m_pDlg->m_pLEADDICOM1->SaveDS(sName, 0); if(nRet != 0) { m_pDlg->LogEvent(szUser, "Error importing DICOM DataSet"); m_pDlg->m_lServerFileCount--; } else { //update our DICOM DIR File m_pDlg->InitServerDS(); } } m_pDlg->m_pLEADDICOM1->ResetDS(); //refresh the DICOM Dir display m_pDlg->DisplayDICOMDir(); if(nRet == DICOM_SUCCESS) nStatus = COMMAND_STATUS_SUCCESS; else nStatus = COMMAND_STATUS_PROCESSING_FAILURE; //this could be more descriptive. We could check the results of the database query and see if the SOP instance already exists, etc. } m_pDlg->m_pLEADDICOMNet1->SendCStoreResponse(hNet, nPresentationID, nMessageID, pszClass, pszInstance, nStatus); m_pDlg->LogEvent(szUser, "C-STORE-RESPONSE sent"); } void CDicomNetSink::OnNetReceiveCStoreResponse(long hNet, short nPresentationID, short nMessageID, LPCTSTR pszClass, LPCTSTR pszInstance, long nStatus) { _bstr_t sMoveClass(m_pDlg->m_szMoveClass); m_pDlg->KillTimer(m_pDlg->m_uTimer); m_pDlg->m_pLEADDICOMNet2->Close(m_pDlg->m_pLEADDICOMNet2->GethNet()); m_pDlg->m_pLEADDICOMNet1->SendCMoveResponse(m_pDlg->m_hMoveNet, m_pDlg->m_nMovePresentationID, m_pDlg->m_nMoveMessageID, sMoveClass, nStatus, 0, 1, 0, 0, 0); } void CDicomNetSink::OnNetReceiveCFindRequest( long hNet, short nPresentationID, short nMessageID, LPCTSTR pszClass, short nPriority, long hDS ) { short nRet; long nStatus; long hPDU; short nID; CString szClient; CString szUser; CString szCalled; CString szFile; CString szLevel; CString szClass = pszClass; hPDU = m_pDlg->m_pLEADDICOMNet1->GetAssociate(hNet); if(hPDU == 0) { //connection is not associated, so ignore the message return; } //we have received an C-FIND-REQUEST szClient = (LPSTR)m_pDlg->m_pLEADDICOMNet1->GetPeerAddress(hNet); szUser = (LPSTR)m_pDlg->m_pLEADDICOMNet1->GetCalling(hPDU); szCalled = (LPSTR)m_pDlg->m_pLEADDICOMNet1->GetCalled(hPDU); m_pDlg->LogEvent(szUser, "C-FIND-REQUEST received"); m_pDlg->LastClientAction(hNet, "C-FIND-REQUEST", TRUE); _bstr_t sClass(szClass); nRet = m_pDlg->m_pLEADDICOM1->FindUID(sClass); if(nRet != DICOM_SUCCESS) nStatus = COMMAND_STATUS_CLASS_NOT_SUPPORTED; else { nID = m_pDlg->m_pLEADDICOMNet1->FindPresentationAbstract(hPDU, sClass); if((nID == 0) || (m_pDlg->m_pLEADDICOMNet1->GetPresentationResult(hPDU, nID) != PDU_ACCEPT_RESULT_SUCCESS)) { m_pDlg->LogEvent(szUser, "C-FIND-REQUEST - Abstract Syntax, " + (CString)(LPSTR)m_pDlg->m_pLEADDICOM1->GetCurrentUID()->GetName() + ", Not Supported by Association!"); nStatus = COMMAND_STATUS_CLASS_NOT_SUPPORTED; } else nStatus = COMMAND_STATUS_SUCCESS; } if(hDS == 0) { nStatus = COMMAND_STATUS_INVALID_ARGUMENT_VALUE; goto FIND_ERROR; } //get the query level m_pDlg->m_pLEADDICOM1->hDicomDS = hDS; nRet = m_pDlg->m_pLEADDICOM1->FindFirstElement(TAG_QUERY_RETRIEVE_LEVEL, TRUE); if(nRet != DICOM_SUCCESS) { nStatus = COMMAND_STATUS_INVALID_ARGUMENT_VALUE; goto FIND_ERROR; } nRet = m_pDlg->m_pLEADDICOM1->GetStringValue(0, 1); if(nRet != DICOM_SUCCESS) { nStatus = COMMAND_STATUS_INVALID_ARGUMENT_VALUE; goto FIND_ERROR; } szLevel = (LPSTR)m_pDlg->m_pLEADDICOM1->GetStringValues(0); //do the query if(nStatus == COMMAND_STATUS_SUCCESS) { if(szClass == UID_PATIENT_ROOT_QUERY_FIND) { if(szLevel == "PATIENT") m_pDlg->DoFindPatient(hNet, nPresentationID, nMessageID, szClass, m_pDlg->m_pLEADDICOM1, szUser); else if(szLevel == "STUDY") m_pDlg->DoFindStudy(hNet, nPresentationID, nMessageID, szClass, m_pDlg->m_pLEADDICOM1, szUser); else if(szLevel == "SERIES") m_pDlg->DoFindSeries(hNet, nPresentationID, nMessageID, szClass, m_pDlg->m_pLEADDICOM1, szUser); else if(szLevel == "IMAGE") m_pDlg->DoFindImage(hNet, nPresentationID, nMessageID, szClass, m_pDlg->m_pLEADDICOM1, szUser); else { nStatus = COMMAND_STATUS_INVALID_ARGUMENT_VALUE; goto FIND_ERROR; } } else { nStatus = COMMAND_STATUS_INVALID_ARGUMENT_VALUE; goto FIND_ERROR; } } m_pDlg->m_pLEADDICOM1->ResetDS(); return; FIND_ERROR: m_pDlg->m_pLEADDICOMNet1->SendCFindResponse(hNet, nPresentationID, nMessageID, sClass, nStatus, 0); m_pDlg->LogEvent(szUser, "C-FIND-RESPONSE sent"); m_pDlg->m_pLEADDICOM1->ResetDS(); } void CDicomNetSink::OnNetReceiveCMoveRequest(long hNet, short nPresentationID, short nMessageID, LPCTSTR pszClass, short nPriority, LPCTSTR pszMoveAE, long hDS) { short nRet; long nStatus; long hPDU; short nID; CString szClient; CString szUser; CString szCalled; CString szFile; CString szLevel; CString szMoveAE; CString szClass; long lClient; CString szMoveIP; long lMovePort; BOOL bFound; hPDU = m_pDlg->m_pLEADDICOMNet1->GetAssociate(hNet); if(hPDU == 0) { //connection is not associated, so ignore the message return; } //we have received an C-MOVE-REQUEST szClient = (LPSTR)m_pDlg->m_pLEADDICOMNet1->GetPeerAddress(hNet); szUser = (LPSTR)m_pDlg->m_pLEADDICOMNet1->GetCalling(hPDU); szCalled = (LPSTR)m_pDlg->m_pLEADDICOMNet1->GetCalled(hPDU); m_pDlg->LogEvent(szUser, "C-MOVE-REQUEST received"); m_pDlg->LastClientAction(hNet, "C-MOVE-REQUEST", TRUE); nRet = m_pDlg->m_pLEADDICOM1->FindUID(pszClass); if(nRet != DICOM_SUCCESS) nStatus = COMMAND_STATUS_CLASS_NOT_SUPPORTED; else { nID = m_pDlg->m_pLEADDICOMNet1->FindPresentationAbstract(hPDU, pszClass); if((nID == 0) || (m_pDlg->m_pLEADDICOMNet1->GetPresentationResult(hPDU, nID) != PDU_ACCEPT_RESULT_SUCCESS)) { m_pDlg->LogEvent(szUser, "C-MOVE-REQUEST - Abstract Syntax, " + (CString)(LPSTR)m_pDlg->m_pLEADDICOM1->GetCurrentUID()->GetName() + ", Not Supported by Association!"); nStatus = COMMAND_STATUS_CLASS_NOT_SUPPORTED; goto MOVE_ERROR; } else nStatus = COMMAND_STATUS_SUCCESS; } if(hDS == 0) { nStatus = COMMAND_STATUS_INVALID_ARGUMENT_VALUE; goto MOVE_ERROR; } //find the MOVE Target bFound = FALSE; szMoveAE = pszMoveAE; for(lClient=0; lClientm_UserList.GetItemCount(); lClient++) { if(szMoveAE == m_pDlg->m_UserList.GetItemText(lClient, 0)) { bFound = TRUE; szMoveIP = m_pDlg->m_UserList.GetItemText(lClient, 1); lMovePort = atoi(m_pDlg->m_UserList.GetItemText(lClient, 2)); } } if(!bFound) //not found { m_pDlg->m_pLEADDICOMNet1->SendCMoveResponse(hNet, nPresentationID, nMessageID, pszClass, COMMAND_STATUS_PROCESSING_FAILURE, 0, 0, 0, 0, 0); return; } //get the query level m_pDlg->m_pLEADDICOM1->hDicomDS = (hDS); nRet = m_pDlg->m_pLEADDICOM1->FindFirstElement(TAG_QUERY_RETRIEVE_LEVEL, TRUE); if(nRet != DICOM_SUCCESS) { nStatus = COMMAND_STATUS_INVALID_ARGUMENT_VALUE; goto MOVE_ERROR; } nRet = m_pDlg->m_pLEADDICOM1->GetStringValue(0, 1); if(nRet != DICOM_SUCCESS) { nStatus = COMMAND_STATUS_INVALID_ARGUMENT_VALUE; goto MOVE_ERROR; } szLevel = (LPSTR)m_pDlg->m_pLEADDICOM1->GetStringValues(0); //do the query if(nStatus == COMMAND_STATUS_SUCCESS) { szClass = pszClass; if(szClass == UID_PATIENT_ROOT_QUERY_MOVE) { if(szLevel == "IMAGE") { m_pDlg->m_szMoveIP = szMoveIP; m_pDlg->m_lMovePort = lMovePort; m_pDlg->DoMoveImage(hNet, nPresentationID, nMessageID, szClass, m_pDlg->m_pLEADDICOM1, szUser, szMoveAE); } else { nStatus = COMMAND_STATUS_INVALID_ARGUMENT_VALUE; goto MOVE_ERROR; } } else { nStatus = COMMAND_STATUS_INVALID_ARGUMENT_VALUE; goto MOVE_ERROR; } } m_pDlg->m_pLEADDICOM1->ResetDS(); return; MOVE_ERROR: m_pDlg->m_pLEADDICOMNet1->SendCMoveResponse(hNet, nPresentationID, nMessageID, pszClass, nStatus, 0, 0, 0, 0, 0); m_pDlg->LogEvent(szUser, "C-FIND-RESPONSE sent"); m_pDlg->m_pLEADDICOM1->ResetDS(); } void CDicomNetSink::OnNetExternalAuthenticateISCL( long hNet, VARIANT * pnChallenge, VARIANT * pnResponse, VARIANT * pnParameter ) { if(pnResponse->cyVal.int64 == pnChallenge->cyVal.int64 + 1) m_pDlg->m_pLEADDICOMNet1->ISCLChallengeResponseSuccess = VARIANT_TRUE; else m_pDlg->m_pLEADDICOMNet1->ISCLChallengeResponseSuccess = VARIANT_FALSE; } static __int64 GetRandom() { __int64 RandVal; RandVal = rand(); RandVal = RandVal * 0x10000 + rand(); RandVal = RandVal * 0x10000 + rand(); RandVal = RandVal * 0x10000 + rand(); return RandVal; } void CDicomNetSink::OnNetGetChallengeISCL( long hNet, VARIANT *pnChallenge, VARIANT *pnParameter ) { pnChallenge->cyVal.int64 = 0x0123456789ABCDE1; m_pDlg->m_pLEADDICOMNet1->ISCLChallengeResponseSuccess= VARIANT_TRUE; } void CDicomNetSink::OnNetInternalAuthenticateISCL( long hNet, VARIANT *pnChallenge, VARIANT *pnResponse, VARIANT *pnParameter ) { pnResponse->cyVal.int64 = pnChallenge->cyVal.int64 + 1; m_pDlg->m_pLEADDICOMNet1->ISCLChallengeResponseSuccess= VARIANT_TRUE; } //************* END OF EVENTS