139
if(m_errorMessage != "")
141
throw GIL::DICOM::PACSException(m_errorMessage, "Acquisition");
147
void MoveAssociation::moveCallback(void* /*callbackData*/, T_DIMSE_C_MoveRQ* /*request*/, int /*responseCount*/, T_DIMSE_C_MoveRSP* /*response*/)
151
void MoveAssociation::subOpCallback(void *pCaller, T_ASC_Network *aNet, T_ASC_Association **subAssoc) {
152
MoveAssociation* caller = (MoveAssociation*) pCaller;
154
if (caller->GetNetwork() == NULL) {
158
wxString msg = wxString::Format(_("Downloading file %d"), caller->m_numeroImagenes++);
159
caller->m_mensaje = std::string(msg.ToUTF8());
160
LOG_DEBUG(caller->ambitolog, caller->m_mensaje);
161
caller->NotificarProgreso((float)caller->m_numeroImagenes/100,caller->m_mensaje);
163
if (*subAssoc == NULL) {
164
// negotiate association
165
LOG_DEBUG(caller->ambitolog, "Aceptando subAsociacion");
166
caller->acceptSubAssoc(aNet, subAssoc);
169
// be a service class provider
170
LOG_DEBUG(caller->ambitolog, "Invocando subOp SCP");
171
caller->subOpSCP(subAssoc);
175
CONDITION MoveAssociation::acceptSubAssoc(T_ASC_Network *aNet, T_ASC_Association **assoc) {
176
CONDITION cond = ASC_NORMAL;
178
const char* knownAbstractSyntaxes[] = {UID_VerificationSOPClass};
184
std::string cliCert = GetCliCert();
185
std::string cliKey = GetCliKey();
186
GTLSTransportLayer* tLayer = new GTLSTransportLayer(DICOM_APPLICATION_REQUESTOR, NULL);
189
LOG_ERROR("C-MOVE SubAssoc", "unable to create TLS transport layer");
191
return EC_IllegalParameter;
193
tLayer->setCertificateFromString(cliCert);
194
tLayer->setPrivateKeyFromString(cliKey);
196
if (! tLayer->checkPrivateKeyMatchesCertificate())
198
LOG_ERROR("C-MOVE SubAssoc", "private key and certificate do not match");
199
return EC_IllegalParameter;
202
tLayer->addSystemTrustedCertificates();
205
tLayer->setCertificateVerification(DCV_requireCertificate);
208
tLayer->setCertificateVerification(DCV_ignoreCertificate);
211
if (opt_dhparam && ! (tLayer->setTempDHParameters(opt_dhparam)))
213
LOG_WARN("C-MOVE SubAssoc", "unable to load temporary DH parameters. Ignoring");
217
cond = ASC_setTransportLayer(aNet, tLayer, 0);
220
LOG_ERROR("C-MOVE SubAssoc", "Error al insertar capa de transporte segura: " << cond.text());
221
return EC_IllegalParameter;
225
cond = ASC_receiveAssociation(aNet, assoc, m_maxReceivePDULength, NULL, NULL, m_TLS, DUL_BLOCK, 240);
228
LOG_ERROR("C-MOVE SubAssoc", "No se pudo recibir la asociación" << cond.text());
231
if (cond.good() && assoc && *assoc && m_TLS) {
232
cond = ASC_setTransportLayerType((*assoc)->params, m_TLS);
235
LOG_ERROR("C-MOVE SubAssoc", "No se pudo fijar la capa TLS sobre la asociación" << cond.text());
240
// accept the Verification SOP Class if presented */
241
cond = ASC_acceptContextsWithPreferredTransferSyntaxes(
243
knownAbstractSyntaxes, DIM_OF(knownAbstractSyntaxes),
244
AllTransferSyntaxes, 3);
247
cond = ASC_acceptContextsWithPreferredTransferSyntaxes(
249
dcmAllStorageSOPClassUIDs, numberOfAllDcmStorageSOPClassUIDs,
250
AllTransferSyntaxes, AllTransferSyntaxesCount);
253
LOG_ERROR("C-MOVE SubAssoc", "No se pudo aceptar el Verification SOP Class aun estando presente: " << cond.text());
257
bool reconocida = false;
259
cond = ASC_acknowledgeAssociation(*assoc);
264
LOG_ERROR("C-MOVE SubAssoc", "No se pudo enviar el reconocimiento de la asociación" << cond.text());
269
LOG_ERROR("C-MOVE SubAssoc", "Error al reconocer la asociación: " << cond.text());
271
ASC_releaseAssociation(*assoc);
272
ASC_dropAssociation(*assoc);
273
ASC_destroyAssociation(assoc);
280
CONDITION MoveAssociation::subOpSCP(T_ASC_Association **subAssoc) {
282
T_ASC_PresentationContextID presID;
285
if (!ASC_dataWaiting(*subAssoc, 0)) {
286
LOG_TRACE(ambitolog, "No hay datos pendientes");
287
return DIMSE_NODATAAVAILABLE;
290
OFCondition cond = DIMSE_receiveCommand(*subAssoc, DIMSE_BLOCKING, 0, &presID, &msg, NULL);
292
if (cond == EC_Normal) {
293
switch (msg.CommandField) {
294
case DIMSE_C_STORE_RQ:
295
LOG_TRACE(ambitolog, "Invocando C-STORE_RQ");
296
cond = storeSCP(*subAssoc, &msg, presID);
298
case DIMSE_C_ECHO_RQ:
299
LOG_TRACE(ambitolog, "Invocando C-ECHO_RQ");
300
cond = echoSCP(*subAssoc, &msg, presID);
303
LOG_ERROR(ambitolog, "Tipo de comando incorrecto. S�lo se aceptan C-STORE_RQ o C-ECHO_RQ en esta etapa" << cond.text());
304
cond = DIMSE_BADCOMMANDTYPE;
309
// clean up on association termination
310
if (cond == DUL_PEERREQUESTEDRELEASE) {
311
LOG_TRACE(ambitolog, "El PACS remoto solicitó el cierre de la asociación");
312
ASC_acknowledgeRelease(*subAssoc);
314
ASC_dropSCPAssociation(*subAssoc);
315
ASC_destroyAssociation(subAssoc);
319
else if (cond == DUL_PEERABORTEDASSOCIATION) {
320
LOG_ERROR(ambitolog, "El PACS remoto abortó la asociación" << cond.text());
322
ASC_dropSCPAssociation(*subAssoc);
323
ASC_destroyAssociation(subAssoc);
327
else if (cond != EC_Normal) {
328
LOG_ERROR(ambitolog, "Ha ocurrido un error y se abortará la asociación" << cond.text());
329
// some kind of error so abort the association
330
ASC_releaseAssociation(*subAssoc);
332
ASC_dropSCPAssociation(*subAssoc);
333
ASC_destroyAssociation(subAssoc);
340
CONDITION MoveAssociation::storeSCP(T_ASC_Association *assoc, T_DIMSE_Message *msg, T_ASC_PresentationContextID presID) {
342
T_DIMSE_C_StoreRQ* req;
344
req = &msg->msg.CStoreRQ;
346
StoreCallbackInfo callbackData;
347
callbackData.pCaller = this;
348
callbackData.assoc = assoc;
349
callbackData.lastTick = std::clock();
351
std::string fileName = GNC::Entorno::Instance()->CreateGinkgoTempFile();
353
cond = DIMSE_storeProvider(assoc, presID, req, fileName.c_str(), 1,
354
NULL, storeSCPCallback, (void*) & callbackData,
358
//we are going to read received file dataset
360
ff.loadFile(fileName.c_str(), EXS_Unknown, EGL_noChange, DCM_TagInfoLength);
361
DcmDataset* imageDataSet = ff.getDataset();
363
if ((imageDataSet)) {
364
// do not duplicate the dataset, let the user do this
366
OnFileReceived(fileName, imageDataSet);
373
void MoveAssociation::storeSCPCallback(void *callbackData, T_DIMSE_StoreProgress *progress, T_DIMSE_C_StoreRQ *req, char* imageFileName, DcmDataset ** /*imageDataSet*/, T_DIMSE_C_StoreRSP *rsp, DcmDataset **statusDetail) {
377
StoreCallbackInfo *cbdata = (StoreCallbackInfo*) callbackData;
378
MoveAssociation* caller = cbdata->pCaller;
380
if (progress->state == DIMSE_StoreBegin) {
381
caller->m_bytesDescargados += progress->totalBytes;
382
GNC::GCS::Permisos::EstadoPermiso estado = GNC::GCS::ControladorPermisos::Instance()->Get("core.pacs.limits", "study_size");
384
if (estado.ObtenerValor<long>() < (caller->m_bytesDescargados / 1024) ) {
385
caller->m_errorMessage = _Std("Study download size limit exceded");
386
cbdata->pCaller->Stop();
387
rsp->DimseStatus = STATUS_MOVE_Cancel_SubOperationsTerminatedDueToCancelIndication;
388
ASC_releaseAssociation(cbdata->assoc);
389
LOG_INFO(caller->ambitolog, "Study download size limit exceded");
393
cbdata->lastTick = std::clock();
395
else if (progress->state == DIMSE_StoreProgressing) {
397
std::clock_t curTick = std::clock();
398
if ( (curTick - cbdata->lastTick) > (CLOCKS_PER_SEC >> 1) ) {
399
cbdata->lastTick = curTick;
400
std::stringstream ostr;
401
ostr << caller->m_mensaje;
402
ostr.setf(std::ios::floatfield, std::ios::fixed );
404
ostr << " (" << caller->TasaTransferencia(progress->progressBytes) << " kb/s)";
405
std::string msg(ostr.str());
406
if(!caller->NotificarProgreso(((float)progress->progressBytes/progress->totalBytes),msg))
408
cbdata->pCaller->Stop();
409
rsp->DimseStatus = STATUS_MOVE_Cancel_SubOperationsTerminatedDueToCancelIndication;
410
ASC_releaseAssociation(cbdata->assoc);
411
LOG_INFO(caller->ambitolog, "Operation canceled by user");
416
else if (progress->state == DIMSE_StoreEnd) {
417
LOG_TRACE(caller->ambitolog, "storeSCPCallback(). DIMSE_StoreEnd");
418
*statusDetail = NULL; /* no status detail */
419
caller->ResetearMedida();
421
/* could save the image somewhere else, put it in database, etc */
422
rsp->DimseStatus = STATUS_Success;
424
//we are going to read received file dataset
426
ff.loadFile(imageFileName, EXS_Unknown, EGL_noChange, DCM_TagInfoLength);
427
DcmDataset* imageDataSet = ff.getDataset();
428
/* should really check the image to make sure it is consistent,
429
* that its sopClass and sopInstance correspond with those in
432
if (rsp->DimseStatus == STATUS_Success) {
433
/* which SOP class and SOP instance ? */
434
if (!DU_findSOPClassAndInstanceInDataSet(imageDataSet, sopClass, sopInstance)) {
435
rsp->DimseStatus = STATUS_STORE_Error_CannotUnderstand;
436
LOG_ERROR(caller->ambitolog, "No se pudo encontrar SOPClass o SOPInstanceUID en el dataset");
438
else if (strcmp(sopClass, req->AffectedSOPClassUID) != 0) {
439
rsp->DimseStatus = STATUS_STORE_Error_DataSetDoesNotMatchSOPClass;
440
LOG_ERROR(caller->ambitolog, "El SOPClass del dataset(" << sopClass << ") no coincide con el SOPClass requerido (" << req->AffectedSOPClassUID << ")");
442
else if (strcmp(sopInstance, req->AffectedSOPInstanceUID) != 0) {
443
rsp->DimseStatus = STATUS_STORE_Error_DataSetDoesNotMatchSOPClass;
444
LOG_ERROR(caller->ambitolog, "El SOPInstance del dataset(" << sopInstance << ") no coincide con el SOPInstanceUID requerido (" << req->AffectedSOPInstanceUID << ")");
451
CONDITION MoveAssociation::echoSCP(T_ASC_Association *assoc, T_DIMSE_Message *msg, T_ASC_PresentationContextID presID) {
454
// the echo succeeded !!
455
cond = DIMSE_sendEchoResponse(assoc, presID, &msg->msg.CEchoRQ, STATUS_Success, NULL);
460
void MoveAssociation::OnFileReceived(const std::string& fileName, DcmDataset* dset) {
461
if (m_pModelo != NULL) {
462
OFString OFEstudioUId;
463
if (dset->findAndGetOFString(DCM_StudyInstanceUID, OFEstudioUId).good()) {
464
OFString OFPacienteUID;
465
std::string PacienteUID;
466
if (dset->findAndGetOFString(DCM_PatientID, OFPacienteUID).good()) {
467
PacienteUID.assign(OFPacienteUID.c_str());
470
OFString OFPacienteNombre;
471
std::string PacienteNombre;
472
if (dset->findAndGetOFString(DCM_PatientName, OFPacienteNombre).good()) {
473
PacienteNombre.assign(OFPacienteNombre.c_str());
476
OFString OFPacienteFechaNacimiento;
477
std::string PacienteFechaNacimiento;
479
if (dset->findAndGetOFString(DCM_PatientBirthDate, OFPacienteFechaNacimiento).good()) {
480
PacienteFechaNacimiento.assign(OFPacienteFechaNacimiento.c_str());
484
OFString OFPacienteSexo;
485
std::string PacienteSexo;
486
if (dset->findAndGetOFString(DCM_PatientSex, OFPacienteSexo).good()) {
487
PacienteSexo.assign(OFPacienteSexo.c_str());
490
const IModeloPaciente& paciente = m_pModelo->InsertarPaciente(PacienteUID, PacienteNombre, PacienteFechaNacimiento, PacienteSexo);
492
OFString OFEstudioUID;
493
std::string EstudioUID;
494
if (dset->findAndGetOFString(DCM_StudyInstanceUID, OFEstudioUID).good()) {
495
EstudioUID.assign(OFEstudioUID.c_str());
498
OFString OFEAccNumber;
499
std::string AccNumber;
500
if (dset->findAndGetOFString(DCM_AccessionNumber, OFEAccNumber).good()) {
501
AccNumber.assign(OFEAccNumber.c_str());
504
OFString OFEstudioDescripcion;
505
std::string EstudioDescripcion;
506
if (dset->findAndGetOFString(DCM_StudyDescription, OFEstudioDescripcion).good()) {
507
EstudioDescripcion.assign(OFEstudioDescripcion.c_str());
510
OFString OFEstudioModalidad;
511
std::string EstudioModalidad;
512
if (dset->findAndGetOFString(DCM_ModalitiesInStudy, OFEstudioModalidad).good()) {
513
EstudioModalidad.assign(OFEstudioModalidad.c_str());
516
OFString OFEstudioFecha;
517
std::string EstudioFecha;
518
if (dset->findAndGetOFString(DCM_StudyDate, OFEstudioFecha).good()) {
519
EstudioFecha.assign(OFEstudioFecha.c_str());
522
OFString OFEstudioHora;
523
std::string EstudioHora;
524
if (dset->findAndGetOFString(DCM_StudyTime, OFEstudioHora).good()) {
525
EstudioHora.assign(OFEstudioHora.c_str());
529
OFString OFEstudioDoctor;
530
std::string EstudioDoctor;
531
if (dset->findAndGetOFString(DCM_ReferringPhysicianName, OFEstudioDoctor).good()) {
532
EstudioDoctor.assign(OFEstudioDoctor.c_str());
535
m_pModelo->InsertarEstudio(paciente.GetUID(), EstudioUID, AccNumber, EstudioDescripcion, EstudioModalidad, EstudioFecha, EstudioHora, EstudioDoctor);
538
std::string SerieUID;
539
if (dset->findAndGetOFString(DCM_SeriesInstanceUID, OFSerieUID).good()) {
540
SerieUID.assign(OFSerieUID.c_str());
543
OFString OFSerieTipo;
544
std::string SerieTipo;
545
if (dset->findAndGetOFString(DCM_SeriesType, OFSerieTipo).good()) {
546
SerieTipo.assign(OFSerieTipo.c_str());
549
OFString OFSerieFecha;
550
std::string SerieFecha;
551
if (dset->findAndGetOFString(DCM_SeriesDate, OFSerieFecha).good()) {
552
SerieFecha.assign(OFSerieFecha.c_str());
555
OFString OFSerieHora;
556
std::string SerieHora;
557
if (dset->findAndGetOFString(DCM_SeriesTime, OFSerieHora).good()) {
558
SerieHora.assign(OFSerieHora.c_str());
561
OFString OFSerieDescripcion;
562
std::string SerieDescripcion;
563
if (dset->findAndGetOFString(DCM_SeriesDescription, OFSerieDescripcion).good()) {
564
SerieDescripcion.assign(OFSerieDescripcion.c_str());
567
OFString OFSerieNumero;
568
std::string SerieNumero;
569
if (dset->findAndGetOFString(DCM_NumberOfSeriesRelatedInstances, OFSerieNumero).good()) {
570
SerieNumero.assign(OFSerieNumero.c_str());
573
OFString OFSerieDoctor;
574
std::string SerieDoctor;
575
if (dset->findAndGetOFString(DCM_ReferringPhysicianName, OFSerieDoctor).good()) {
576
SerieDoctor.assign(OFSerieDoctor.c_str());
579
m_pModelo->InsertarSerie(EstudioUID, SerieUID, SerieTipo, SerieFecha, SerieHora, SerieDescripcion,SerieNumero,SerieDoctor);
581
OFString OFUIDImagen;
582
std::string UIDImagen;
583
if (dset->findAndGetOFString(DCM_SOPInstanceUID, OFUIDImagen).good()) {
584
UIDImagen.assign(OFUIDImagen.c_str());
585
m_pModelo->InsertarImagen(SerieUID,UIDImagen);
589
if (m_pHandler != NULL) {
590
m_pHandler->Store(fileName, dset);
594
void MoveAssociation::SetCallbackHandler(IStoreCallBack * handler) {
595
m_pHandler = handler;
598
float MoveAssociation::TasaTransferencia(int bytesDescargados)
600
time_t nuevoInstante = time(NULL);
601
const double tiempo = difftime(nuevoInstante,m_medida.m_instante);
603
if(bytesDescargados > m_medida.bytesDescargados) {
604
const double bytesRecibidosPeriodo = bytesDescargados - m_medida.bytesDescargados;
605
m_medida.oldTasa = ( ((float)bytesRecibidosPeriodo/1024.0f)/tiempo );
606
m_medida.bytesDescargados = bytesDescargados;
607
m_medida.m_instante = nuevoInstante;
610
return m_medida.oldTasa;
613
void MoveAssociation::ResetearMedida(bool clearTasa) {
614
m_medida.bytesDescargados = 0;
615
m_medida.m_instante = time(NULL);
617
m_medida.oldTasa=0.0f;
138
if(m_errorMessage != "" || rsp.NumberOfFailedSubOperations > 0 ) {
139
if (m_errorMessage.size() == 0) {
140
m_errorMessage = "Some operations failed";
142
return makeOFCondition(OFM_dcmnet, 18, OF_error, m_errorMessage.c_str());