1 /** 2 * Orthanc - A Lightweight, RESTful DICOM Store 3 * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics 4 * Department, University Hospital of Liege, Belgium 5 * Copyright (C) 2017-2021 Osimis S.A., Belgium 6 * 7 * This program is free software: you can redistribute it and/or 8 * modify it under the terms of the GNU Lesser General Public License 9 * as published by the Free Software Foundation, either version 3 of 10 * the License, or (at your option) any later version. 11 * 12 * This program is distributed in the hope that it will be useful, but 13 * WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * Lesser General Public License for more details. 16 * 17 * You should have received a copy of the GNU Lesser General Public 18 * License along with this program. If not, see 19 * <http://www.gnu.org/licenses/>. 20 **/ 21 22 23 #include "../PrecompiledHeaders.h" 24 #include "RemoteModalityParameters.h" 25 26 #include "../Logging.h" 27 #include "../OrthancException.h" 28 #include "../SerializationToolbox.h" 29 30 #include <boost/lexical_cast.hpp> 31 #include <stdexcept> 32 33 34 static const char* KEY_AET = "AET"; 35 static const char* KEY_ALLOW_ECHO = "AllowEcho"; 36 static const char* KEY_ALLOW_FIND = "AllowFind"; 37 static const char* KEY_ALLOW_GET = "AllowGet"; 38 static const char* KEY_ALLOW_MOVE = "AllowMove"; 39 static const char* KEY_ALLOW_N_ACTION = "AllowNAction"; 40 static const char* KEY_ALLOW_N_EVENT_REPORT = "AllowEventReport"; 41 static const char* KEY_ALLOW_STORAGE_COMMITMENT = "AllowStorageCommitment"; 42 static const char* KEY_ALLOW_STORE = "AllowStore"; 43 static const char* KEY_ALLOW_TRANSCODING = "AllowTranscoding"; 44 static const char* KEY_HOST = "Host"; 45 static const char* KEY_MANUFACTURER = "Manufacturer"; 46 static const char* KEY_PORT = "Port"; 47 static const char* KEY_USE_DICOM_TLS = "UseDicomTls"; 48 static const char* KEY_LOCAL_AET = "LocalAet"; 49 static const char* KEY_TIMEOUT = "Timeout"; 50 51 52 namespace Orthanc 53 { Clear()54 void RemoteModalityParameters::Clear() 55 { 56 aet_ = "ORTHANC"; 57 host_ = "127.0.0.1"; 58 port_ = 104; 59 manufacturer_ = ModalityManufacturer_Generic; 60 allowEcho_ = true; 61 allowStore_ = true; 62 allowFind_ = true; 63 allowMove_ = true; 64 allowGet_ = true; 65 allowNAction_ = true; // For storage commitment 66 allowNEventReport_ = true; // For storage commitment 67 allowTranscoding_ = true; 68 useDicomTls_ = false; 69 localAet_.clear(); 70 timeout_ = 0; 71 } 72 73 RemoteModalityParameters()74 RemoteModalityParameters::RemoteModalityParameters() 75 { 76 Clear(); 77 } 78 RemoteModalityParameters(const Json::Value & serialized)79 RemoteModalityParameters::RemoteModalityParameters(const Json::Value &serialized) 80 { 81 Unserialize(serialized); 82 } 83 RemoteModalityParameters(const std::string & aet,const std::string & host,uint16_t port,ModalityManufacturer manufacturer)84 RemoteModalityParameters::RemoteModalityParameters(const std::string& aet, 85 const std::string& host, 86 uint16_t port, 87 ModalityManufacturer manufacturer) 88 { 89 Clear(); 90 SetApplicationEntityTitle(aet); 91 SetHost(host); 92 SetPortNumber(port); 93 SetManufacturer(manufacturer); 94 } 95 GetApplicationEntityTitle() const96 const std::string &RemoteModalityParameters::GetApplicationEntityTitle() const 97 { 98 return aet_; 99 } 100 SetApplicationEntityTitle(const std::string & aet)101 void RemoteModalityParameters::SetApplicationEntityTitle(const std::string &aet) 102 { 103 aet_ = aet; 104 } 105 GetHost() const106 const std::string &RemoteModalityParameters::GetHost() const 107 { 108 return host_; 109 } 110 SetHost(const std::string & host)111 void RemoteModalityParameters::SetHost(const std::string &host) 112 { 113 host_ = host; 114 } 115 GetPortNumber() const116 uint16_t RemoteModalityParameters::GetPortNumber() const 117 { 118 return port_; 119 } 120 121 CheckPortNumber(int value)122 static void CheckPortNumber(int value) 123 { 124 if (value <= 0 || 125 value >= 65535) 126 { 127 throw OrthancException(ErrorCode_ParameterOutOfRange, 128 "A TCP port number must be in range [1..65534], but found: " + 129 boost::lexical_cast<std::string>(value)); 130 } 131 } 132 133 ReadPortNumber(const Json::Value & value)134 static uint16_t ReadPortNumber(const Json::Value& value) 135 { 136 int tmp; 137 138 switch (value.type()) 139 { 140 case Json::intValue: 141 case Json::uintValue: 142 tmp = value.asInt(); 143 break; 144 145 case Json::stringValue: 146 try 147 { 148 tmp = boost::lexical_cast<int>(value.asString()); 149 } 150 catch (boost::bad_lexical_cast&) 151 { 152 throw OrthancException(ErrorCode_BadFileFormat); 153 } 154 break; 155 156 default: 157 throw OrthancException(ErrorCode_BadFileFormat); 158 } 159 160 CheckPortNumber(tmp); 161 return static_cast<uint16_t>(tmp); 162 } 163 164 SetPortNumber(uint16_t port)165 void RemoteModalityParameters::SetPortNumber(uint16_t port) 166 { 167 CheckPortNumber(port); 168 port_ = port; 169 } 170 GetManufacturer() const171 ModalityManufacturer RemoteModalityParameters::GetManufacturer() const 172 { 173 return manufacturer_; 174 } 175 SetManufacturer(ModalityManufacturer manufacturer)176 void RemoteModalityParameters::SetManufacturer(ModalityManufacturer manufacturer) 177 { 178 manufacturer_ = manufacturer; 179 } 180 SetManufacturer(const std::string & manufacturer)181 void RemoteModalityParameters::SetManufacturer(const std::string &manufacturer) 182 { 183 manufacturer_ = StringToModalityManufacturer(manufacturer); 184 } 185 186 UnserializeArray(const Json::Value & serialized)187 void RemoteModalityParameters::UnserializeArray(const Json::Value& serialized) 188 { 189 assert(serialized.type() == Json::arrayValue); 190 191 if ((serialized.size() != 3 && 192 serialized.size() != 4) || 193 serialized[0].type() != Json::stringValue || 194 serialized[1].type() != Json::stringValue || 195 (serialized.size() == 4 && 196 serialized[3].type() != Json::stringValue)) 197 { 198 throw OrthancException(ErrorCode_BadFileFormat); 199 } 200 201 aet_ = serialized[0].asString(); 202 host_ = serialized[1].asString(); 203 port_ = ReadPortNumber(serialized[2]); 204 205 if (serialized.size() == 4) 206 { 207 manufacturer_ = StringToModalityManufacturer(serialized[3].asString()); 208 } 209 else 210 { 211 manufacturer_ = ModalityManufacturer_Generic; 212 } 213 } 214 215 UnserializeObject(const Json::Value & serialized)216 void RemoteModalityParameters::UnserializeObject(const Json::Value& serialized) 217 { 218 assert(serialized.type() == Json::objectValue); 219 220 aet_ = SerializationToolbox::ReadString(serialized, KEY_AET); 221 host_ = SerializationToolbox::ReadString(serialized, KEY_HOST); 222 223 if (serialized.isMember(KEY_PORT)) 224 { 225 port_ = ReadPortNumber(serialized[KEY_PORT]); 226 } 227 else 228 { 229 throw OrthancException(ErrorCode_BadFileFormat); 230 } 231 232 if (serialized.isMember(KEY_MANUFACTURER)) 233 { 234 manufacturer_ = StringToModalityManufacturer 235 (SerializationToolbox::ReadString(serialized, KEY_MANUFACTURER)); 236 } 237 else 238 { 239 manufacturer_ = ModalityManufacturer_Generic; 240 } 241 242 if (serialized.isMember(KEY_ALLOW_ECHO)) 243 { 244 allowEcho_ = SerializationToolbox::ReadBoolean(serialized, KEY_ALLOW_ECHO); 245 } 246 247 if (serialized.isMember(KEY_ALLOW_FIND)) 248 { 249 allowFind_ = SerializationToolbox::ReadBoolean(serialized, KEY_ALLOW_FIND); 250 } 251 252 if (serialized.isMember(KEY_ALLOW_STORE)) 253 { 254 allowStore_ = SerializationToolbox::ReadBoolean(serialized, KEY_ALLOW_STORE); 255 } 256 257 if (serialized.isMember(KEY_ALLOW_GET)) 258 { 259 allowGet_ = SerializationToolbox::ReadBoolean(serialized, KEY_ALLOW_GET); 260 } 261 262 if (serialized.isMember(KEY_ALLOW_MOVE)) 263 { 264 allowMove_ = SerializationToolbox::ReadBoolean(serialized, KEY_ALLOW_MOVE); 265 } 266 267 if (serialized.isMember(KEY_ALLOW_N_ACTION)) 268 { 269 allowNAction_ = SerializationToolbox::ReadBoolean(serialized, KEY_ALLOW_N_ACTION); 270 } 271 272 if (serialized.isMember(KEY_ALLOW_N_EVENT_REPORT)) 273 { 274 allowNEventReport_ = SerializationToolbox::ReadBoolean(serialized, KEY_ALLOW_N_EVENT_REPORT); 275 } 276 277 if (serialized.isMember(KEY_ALLOW_STORAGE_COMMITMENT)) 278 { 279 bool allow = SerializationToolbox::ReadBoolean(serialized, KEY_ALLOW_STORAGE_COMMITMENT); 280 allowNAction_ = allow; 281 allowNEventReport_ = allow; 282 } 283 284 if (serialized.isMember(KEY_ALLOW_TRANSCODING)) 285 { 286 allowTranscoding_ = SerializationToolbox::ReadBoolean(serialized, KEY_ALLOW_TRANSCODING); 287 } 288 289 if (serialized.isMember(KEY_USE_DICOM_TLS)) 290 { 291 useDicomTls_ = SerializationToolbox::ReadBoolean(serialized, KEY_USE_DICOM_TLS); 292 } 293 294 if (serialized.isMember(KEY_LOCAL_AET)) 295 { 296 localAet_ = SerializationToolbox::ReadString(serialized, KEY_LOCAL_AET); 297 } 298 299 if (serialized.isMember(KEY_TIMEOUT)) 300 { 301 timeout_ = SerializationToolbox::ReadUnsignedInteger(serialized, KEY_TIMEOUT); 302 } 303 } 304 305 IsRequestAllowed(DicomRequestType type) const306 bool RemoteModalityParameters::IsRequestAllowed(DicomRequestType type) const 307 { 308 switch (type) 309 { 310 case DicomRequestType_Echo: 311 return allowEcho_; 312 313 case DicomRequestType_Find: 314 return allowFind_; 315 316 case DicomRequestType_Get: 317 return allowGet_; 318 319 case DicomRequestType_Move: 320 return allowMove_; 321 322 case DicomRequestType_Store: 323 return allowStore_; 324 325 case DicomRequestType_NAction: 326 return allowNAction_; 327 328 case DicomRequestType_NEventReport: 329 return allowNEventReport_; 330 331 default: 332 throw OrthancException(ErrorCode_ParameterOutOfRange); 333 } 334 } 335 336 SetRequestAllowed(DicomRequestType type,bool allowed)337 void RemoteModalityParameters::SetRequestAllowed(DicomRequestType type, 338 bool allowed) 339 { 340 switch (type) 341 { 342 case DicomRequestType_Echo: 343 allowEcho_ = allowed; 344 break; 345 346 case DicomRequestType_Find: 347 allowFind_ = allowed; 348 break; 349 350 case DicomRequestType_Get: 351 allowGet_ = allowed; 352 break; 353 354 case DicomRequestType_Move: 355 allowMove_ = allowed; 356 break; 357 358 case DicomRequestType_Store: 359 allowStore_ = allowed; 360 break; 361 362 case DicomRequestType_NAction: 363 allowNAction_ = allowed; 364 break; 365 366 case DicomRequestType_NEventReport: 367 allowNEventReport_ = allowed; 368 break; 369 370 default: 371 throw OrthancException(ErrorCode_ParameterOutOfRange); 372 } 373 } 374 375 IsAdvancedFormatNeeded() const376 bool RemoteModalityParameters::IsAdvancedFormatNeeded() const 377 { 378 return (!allowEcho_ || 379 !allowStore_ || 380 !allowFind_ || 381 !allowGet_ || 382 !allowMove_ || 383 !allowNAction_ || 384 !allowNEventReport_ || 385 !allowTranscoding_ || 386 useDicomTls_ || 387 HasLocalAet()); 388 } 389 390 Serialize(Json::Value & target,bool forceAdvancedFormat) const391 void RemoteModalityParameters::Serialize(Json::Value& target, 392 bool forceAdvancedFormat) const 393 { 394 if (forceAdvancedFormat || 395 IsAdvancedFormatNeeded()) 396 { 397 target = Json::objectValue; 398 target[KEY_AET] = aet_; 399 target[KEY_HOST] = host_; 400 target[KEY_PORT] = port_; 401 target[KEY_MANUFACTURER] = EnumerationToString(manufacturer_); 402 target[KEY_ALLOW_ECHO] = allowEcho_; 403 target[KEY_ALLOW_STORE] = allowStore_; 404 target[KEY_ALLOW_FIND] = allowFind_; 405 target[KEY_ALLOW_GET] = allowGet_; 406 target[KEY_ALLOW_MOVE] = allowMove_; 407 target[KEY_ALLOW_N_ACTION] = allowNAction_; 408 target[KEY_ALLOW_N_EVENT_REPORT] = allowNEventReport_; 409 target[KEY_ALLOW_TRANSCODING] = allowTranscoding_; 410 target[KEY_USE_DICOM_TLS] = useDicomTls_; 411 target[KEY_LOCAL_AET] = localAet_; 412 target[KEY_TIMEOUT] = timeout_; 413 } 414 else 415 { 416 target = Json::arrayValue; 417 target.append(GetApplicationEntityTitle()); 418 target.append(GetHost()); 419 target.append(GetPortNumber()); 420 target.append(EnumerationToString(GetManufacturer())); 421 } 422 } 423 424 Unserialize(const Json::Value & serialized)425 void RemoteModalityParameters::Unserialize(const Json::Value& serialized) 426 { 427 Clear(); 428 429 switch (serialized.type()) 430 { 431 case Json::objectValue: 432 UnserializeObject(serialized); 433 break; 434 435 case Json::arrayValue: 436 UnserializeArray(serialized); 437 break; 438 439 default: 440 throw OrthancException(ErrorCode_BadFileFormat); 441 } 442 } 443 IsTranscodingAllowed() const444 bool RemoteModalityParameters::IsTranscodingAllowed() const 445 { 446 return allowTranscoding_; 447 } 448 SetTranscodingAllowed(bool allowed)449 void RemoteModalityParameters::SetTranscodingAllowed(bool allowed) 450 { 451 allowTranscoding_ = allowed; 452 } 453 IsDicomTlsEnabled() const454 bool RemoteModalityParameters::IsDicomTlsEnabled() const 455 { 456 return useDicomTls_; 457 } 458 SetDicomTlsEnabled(bool enabled)459 void RemoteModalityParameters::SetDicomTlsEnabled(bool enabled) 460 { 461 useDicomTls_ = enabled; 462 } 463 HasLocalAet() const464 bool RemoteModalityParameters::HasLocalAet() const 465 { 466 return !localAet_.empty(); 467 } 468 GetLocalAet() const469 const std::string& RemoteModalityParameters::GetLocalAet() const 470 { 471 if (localAet_.empty()) 472 { 473 throw OrthancException(ErrorCode_BadSequenceOfCalls, "You should have called HasLocalAet()"); 474 } 475 else 476 { 477 return localAet_; 478 } 479 } 480 SetLocalAet(const std::string & aet)481 void RemoteModalityParameters::SetLocalAet(const std::string& aet) 482 { 483 if (aet.empty()) 484 { 485 throw OrthancException(ErrorCode_ParameterOutOfRange); 486 } 487 else 488 { 489 localAet_ = aet; 490 } 491 } 492 SetTimeout(uint32_t seconds)493 void RemoteModalityParameters::SetTimeout(uint32_t seconds) 494 { 495 timeout_ = seconds; 496 } 497 GetTimeout() const498 uint32_t RemoteModalityParameters::GetTimeout() const 499 { 500 return timeout_; 501 } 502 HasTimeout() const503 bool RemoteModalityParameters::HasTimeout() const 504 { 505 return timeout_ != 0; 506 } 507 } 508