1 /* 2 * 3 * Copyright (C) 2009-2020, OFFIS e.V. 4 * All rights reserved. See COPYRIGHT file for details. 5 * 6 * This software and supporting documentation were developed by 7 * 8 * OFFIS e.V. 9 * R&D Division Health 10 * Escherweg 2 11 * D-26121 Oldenburg, Germany 12 * 13 * 14 * Module: dcmnet 15 * 16 * Author: Michael Onken 17 * 18 * Purpose: General SCP class that can be used to implement derived SCP 19 * applications. 20 * 21 */ 22 23 #ifndef SCP_H 24 #define SCP_H 25 26 #include "dcmtk/config/osconfig.h" /* make sure OS specific configuration is included first */ 27 28 #include "dcmtk/dcmdata/dctk.h" /* Covers most common dcmdata classes */ 29 #include "dcmtk/dcmnet/assoc.h" 30 #include "dcmtk/dcmnet/dimse.h" /* DIMSE network layer */ 31 #include "dcmtk/dcmnet/diutil.h" /* for DCMNET_WARN() */ 32 #include "dcmtk/dcmnet/scpcfg.h" 33 #include "dcmtk/oflog/oflog.h" 34 35 // include this file in doxygen documentation 36 37 /** @file scp.h 38 * @brief general Service Class Provider (SCP) class 39 */ 40 41 /** Structure representing single process in multi-process mode 42 */ 43 struct DCMTK_DCMNET_EXPORT DcmProcessSlotType 44 { 45 /// Name of peer 46 DIC_NODENAME peerName; 47 /// Calling AE title 48 DIC_AE callingAETitle; 49 /// Called AE title 50 DIC_AE calledAETitle; 51 /// Process ID 52 int processId; 53 /// Start time 54 time_t startTime; 55 /// Indicator if process has storage ability 56 OFBool hasStorageAbility; 57 }; 58 59 /** Action codes that can be given to DcmSCP to control behavior during SCP's operation. 60 * Different hooks permit jumping into different phases of SCP operation. 61 */ 62 enum DcmSCPActionType 63 { 64 /// No action defined 65 DCMSCP_ACTION_UNDEFINED, 66 /// Tell SCP to refuse association 67 DCMSCP_ACTION_REFUSE_ASSOCIATION 68 }; 69 70 /** Codes denoting a reason for refusing an association 71 */ 72 enum DcmRefuseReasonType 73 { 74 /// Too many associations (SCP cannot handle a further association) 75 DCMSCP_TOO_MANY_ASSOCIATIONS, 76 /// Forking a new SCP process failed 77 DCMSCP_CANNOT_FORK, 78 /// Refusing association because of bad application context name 79 DCMSCP_BAD_APPLICATION_CONTEXT_NAME, 80 /// Refusing association because of disallowed connecting host 81 DCMSCP_CALLING_HOST_NOT_ALLOWED, 82 /// Refusing association because of unaccepted called AE title 83 DCMSCP_CALLED_AE_TITLE_NOT_RECOGNIZED, 84 /// Refusing association because of unaccepted calling AE title 85 DCMSCP_CALLING_AE_TITLE_NOT_RECOGNIZED, 86 /// Refusing association because SCP was forced to do so 87 DCMSCP_FORCED, 88 /// Refusing association because of missing Implementation Class UID 89 DCMSCP_NO_IMPLEMENTATION_CLASS_UID, 90 /// Refusing association because of no acceptable Presentation Contexts 91 DCMSCP_NO_PRESENTATION_CONTEXTS, 92 /// Refusing association because of internal error 93 DCMSCP_INTERNAL_ERROR 94 }; 95 96 /** Structure representing a single Presentation Context. Fields "reserved" and "result" 97 * not included from DUL_PRESENTATIONCONTEXT, which served as the blueprint for this 98 * structure. 99 */ 100 struct DCMTK_DCMNET_EXPORT DcmPresentationContextInfo 101 { DcmPresentationContextInfoDcmPresentationContextInfo102 DcmPresentationContextInfo() 103 : presentationContextID(0) 104 , abstractSyntax() 105 , proposedSCRole(0) 106 , acceptedSCRole(0) 107 , acceptedTransferSyntax() 108 { 109 } 110 111 /// Presentation Context ID as proposed by SCU 112 Uint8 presentationContextID; 113 /// Abstract Syntax name (UID) as proposed by SCU 114 OFString abstractSyntax; 115 /// SCP role as proposed from SCU 116 Uint8 proposedSCRole; 117 /// Role accepted by SCP for this Presentation Context 118 Uint8 acceptedSCRole; 119 /// Transfer Syntax accepted for this Presentation Context (UID) 120 OFString acceptedTransferSyntax; 121 // Fields "reserved" and "result" not included from DUL_PRESENTATIONCONTEXT 122 }; 123 124 /** Base class for implementing a DICOM Service Class Provider (SCP). Derived classes can 125 * add the presentation contexts they want to support, set further parameters (port, peer 126 * host name, etc. as desired) and then call DcmSCP's listen() method to start the server. 127 * For incoming associations and DIMSE messages, a derived class can define the behavior 128 * of the server. 129 * The DcmSCP base class does not support any presentation contexts per default. 130 * In particular the Verification SOP class which every SCP must support, 131 * is not added automatically in order to give the user full control over the 132 * supported list of presentation contexts. However, if this class should negotiate 133 * Verification, call setEnableVerification(). In that case DcmSCP will also 134 * respond to related C-ECHO requests. Note that this cannot be reverted. 135 * @warning This class is EXPERIMENTAL. Be careful to use it in production environment. 136 */ 137 class DCMTK_DCMNET_EXPORT DcmSCP 138 { 139 140 public: 141 /** Constructor. Initializes internal member variables. 142 */ 143 DcmSCP(); 144 145 /** Virtual destructor, frees internal memory. 146 */ 147 virtual ~DcmSCP(); 148 149 /** Starts providing the implemented services to SCUs. 150 * After calling this method the SCP is listening for connection requests. 151 * @return The result. Per default, the method only returns in case of fatal errors. 152 * However, there are ways to stop listening in a controlled way: 153 * <ul> 154 * <li>In non-blocking mode, use stopAfterConnectionTimeout() in order 155 * shut down after the TCP timeout set with setConnectionTimeout() has 156 * occurred. In that case, the method returns with NET_EC_StopAfterConnectionTimeout.</li> 157 * <li>In non-blocking and blocking mode, stopAfterCurrentAssociation() can 158 * be used to return after an association has been handled and ended. 159 * In that case, NET_EC_StopAfterAssociation is returned.</li> 160 * </ul> 161 * Other error codes include 162 * <ul> 163 * <li>NET_EC_InvalidSCPAssociationProfile: Returned if the SCP's presentation 164 * context information is invalid (e.g. no presentation contexts have 165 * been added). 166 * </li> 167 * <li>NET_EC_InsufficientPortPrivileges: Returned if the SCP is not 168 * allowed to open the specified TCP port for listening. The reason 169 * may be that you try to open a port number below 1024 on a Unix-like 170 * system as non-root user. 171 * <li>EC_setuidFailed: Returned (on Unix-like systems) if the DcmSCP 172 * was not able to drop root privileges. 173 * </ul> 174 */ 175 virtual OFCondition listen(); 176 177 /** Alternative interface to providing the implemented services to SCUs. 178 * This method opens the TCP port for incoming connections, drops root privileges 179 * if necessary and then returns. The caller can then perform short other operations 180 * and finally call acceptAssociations(). If any SCU tries to connect between 181 * this method and the call to acceptAssociations(), they are placed on the 182 * TCP listen backlog and will be handled by acceptAssociations() unless they 183 * time out or the backlog overflows (the size of the backlog is defined by the 184 * PRV_LISTENBACKLOG macro). 185 * @return EC_Normal if successful, an error code otherwise. 186 */ 187 virtual OFCondition openListenPort(); 188 189 /** Alternative interface to providing the implemented services to SCUs. 190 * This method should be called after a call to openListenPort(). 191 * @return The result. Per default, the method only returns in case of fatal errors. 192 * See documentation of listen() method on how to stop listening in a controlled way. 193 */ 194 virtual OFCondition acceptAssociations(); 195 196 /* ************************************************************* */ 197 /* Set methods for configuring SCP behavior */ 198 /* ************************************************************* */ 199 200 /** Enables negotiation of the Verification SOP Class. It adds the Verification 201 * SOP Class to the list of supported abstract syntaxes for the given profile. 202 * All uncompressed transfer syntaxes are supported. If Verification SOP 203 * class is added here, DcmSCP will respond to related C-ECHO requests. Note 204 * that this cannot be reverted. 205 * The default behavior of DcmSCP is not to support any SOP Class at all. 206 * @param profile [in] The profile Verification SOP Class should 207 * be added to. The default is to add it to the 208 * DcmSCP's internal standard profile called 209 * "DEFAULT". 210 * @return EC_Normal if Verification SOP Class could be added, 211 * error otherwise. 212 */ 213 OFCondition setEnableVerification(const OFString& profile = "DEFAULT"); 214 215 /** Add abstract syntax to presentation contexts the SCP is able to negotiate with SCUs. 216 * @param abstractSyntax [in] The UID of the abstract syntax (e.g.\ SOP class) to add 217 * @param xferSyntaxes [in] List of transfer syntaxes (UIDs) that should be supported 218 * for the given abstract syntax name 219 * @param requestorRole [in] The role to be negotiated. This denotes the role of the 220 * the association requestor that this instance should accept, i.e. if 221 * set to ASC_SC_ROLE_SCP it means that the association requestor 222 * is allowed to negotiate the SCP role, thus, that this DcmSCP instance 223 * will be playing the SCU role for this abstract syntax. The default 224 * role (ASC_SC_ROLE_DEFAULT) implicates that this DcmSCP instance 225 * will be allowed to play the SCP role only, i.e. it will acknowledge 226 * such an explicit SCU role request, but also it will accept a proposal 227 * for the abstract syntax with no explicit role being proposed 228 * at all (since per default the requestor is SCU and the acceptor SCP). 229 * @param profile [in] The profile the abstract syntax should be added to. The 230 * default is to add it to the DcmSCP's internal standard 231 * profile called "DEFAULT". 232 * @return EC_Normal if adding was successful, an error code otherwise 233 */ 234 virtual OFCondition addPresentationContext(const OFString& abstractSyntax, 235 const OFList<OFString>& xferSyntaxes, 236 const T_ASC_SC_ROLE requestorRole = ASC_SC_ROLE_DEFAULT, 237 const OFString& profile = "DEFAULT"); 238 239 /** Set SCP's TCP/IP listening port 240 * @param port [in] The port number to listen on. Note that usually on Unix-like systems 241 * only root user is permitted to open ports below 1024. 242 */ 243 void setPort(const Uint16 port); 244 245 /** Set AE title of the server 246 * @param aetitle [in] The AE title of the server. By default, all SCU association requests 247 * calling another AE title will be rejected. This behavior can be 248 * changed by using the setRespondWithCalledAETitle() method. 249 */ 250 void setAETitle(const OFString& aetitle); 251 252 /** Set SCP to use the called AE title from the SCU request for the response, i.e.\ the SCP 253 * will always respond with setting it's own name to the one the SCU used for calling. 254 * Overrides any AE title eventually set with setAETitle(). 255 * @param useCalled [in] If OFTrue, the SCP will use the called AE title from the request 256 * for responding. DcmSCP's default is OFFalse. 257 */ 258 void setRespondWithCalledAETitle(const OFBool useCalled); 259 260 /** Loads association configuration file 261 * @param assocFile [in] The filename of the association configuration to be loaded. The 262 * association configuration file must be valid for an SCP. 263 * @return EC_Normal if loading was successful, error otherwise 264 */ 265 virtual OFCondition loadAssociationCfgFile(const OFString& assocFile); 266 267 /** If an association profile should be selected, either by loading an association 268 * configuration file or using the addPresentationContext() function, one of those can 269 * be selected and checked for validity using this method. 270 * @param profileName [in] The name of the association profile which must be configured 271 * before being selected here 272 * @return EC_Normal if selecting/checking was successful, an error code otherwise 273 */ 274 virtual OFCondition setAndCheckAssociationProfile(const OFString& profileName); 275 276 /** Force every association request to be refused by SCP, no matter what the SCU is 277 * offering 278 * @param doRefuse [in] If OFTrue, every association is being refused. DcmSCP's default 279 * is not to refuse every association. 280 */ 281 void forceAssociationRefuse(const OFBool doRefuse); 282 283 /** Set maximum PDU size the SCP is able to receive. This size is sent in association 284 * response message to SCU. 285 * @param maxRecPDU [in] The maximum PDU size to use in bytes 286 */ 287 void setMaxReceivePDULength(const Uint32 maxRecPDU); 288 289 /** Set whether waiting for a TCP/IP connection should be blocking or non-blocking. 290 * In non-blocking mode, the networking routines will wait for specified connection 291 * timeout, see setConnectionTimeout() function. In blocking mode, no timeout is set 292 * but the operating system's network routines will be used to read from the socket 293 * for incoming data. In the worst case, this may be a long time until that call 294 * returns. The default of DcmSCP is blocking mode. 295 * @param blockingMode [in] Either DUL_BLOCK for blocking mode or DUL_NOBLOCK 296 * for non-blocking mode 297 */ 298 void setConnectionBlockingMode(const DUL_BLOCKOPTIONS blockingMode); 299 300 /** Set whether DIMSE messaging should be blocking or non-blocking. In non-blocking mode, 301 * the networking routines will wait for DIMSE messages for the specified DIMSE timeout 302 * time, see setDIMSETimeout() function. In blocking mode, no timeout is set but the 303 * operating system's network routines will be used to read from the socket for new data. 304 * In the worst case, this may be a long time until that call returns. The default of 305 * DcmSCP is blocking mode. 306 * @param blockingMode [in] Either DIMSE_BLOCKING for blocking mode or DIMSE_NONBLOCKING 307 * for non-blocking mode 308 */ 309 void setDIMSEBlockingMode(const T_DIMSE_BlockingMode blockingMode); 310 311 /** Set the timeout to be waited for incoming DIMSE message packets. This is only relevant 312 * for DIMSE blocking mode messaging (see also setDIMSEBlockingMode()). 313 * @param dimseTimeout [in] DIMSE receive timeout in seconds 314 */ 315 void setDIMSETimeout(const Uint32 dimseTimeout); 316 317 /** Set the timeout used during ACSE messaging protocol. 318 * @param acseTimeout [in] ACSE timeout in seconds. 319 */ 320 void setACSETimeout(const Uint32 acseTimeout); 321 322 /** Set the timeout that should be waited for connection requests. 323 * Only relevant in non-blocking mode (default). 324 * @param timeout [in] TCP/IP connection timeout in seconds. 325 */ 326 void setConnectionTimeout(const Uint32 timeout); 327 328 /** Set whether to show presentation contexts in verbose or debug mode 329 * @param mode [in] Show presentation contexts in verbose mode if OFTrue. By default, the 330 * presentation contexts are shown in debug mode. 331 */ 332 void setVerbosePCMode(const OFBool mode); 333 334 /** Enables or disables looking up the host name from a connecting system. 335 * Note that this sets a GLOBAL flag in DCMTK, i.e. the behavior changes 336 * for all servers. This should be changed in the future. 337 * @param mode [in] OFTrue, if host name lookup should be enabled, OFFalse for disabling it. 338 */ 339 void setHostLookupEnabled(const OFBool mode); 340 341 /** Set the mode that specifies whether the progress of sending and receiving DIMSE messages 342 * is notified by calling notifySENDProgress() and notifyRECEIVEProgress(), respectively. 343 * The progress notification is enabled by default. 344 * @param mode [in] Disable progress notification if OFFalse 345 */ 346 void setProgressNotificationMode(const OFBool mode); 347 348 /** Option to always accept a default role as association acceptor. 349 * If OFFalse (default) the acceptor will reject a presentation context proposed 350 * with Default role (no role selection at all) when it is configured for role 351 * SCP only. If this option is set to OFTrue then such presentation contexts will 352 * be accepted in Default role (i.e. acceptor does not return role selection for 353 * this presentation context at all). Overall, if set to OFTrue, there are no 354 * requestor proposals possible that lead to a complete rejection of a presentation 355 * context. See also role documentation in dul.h. 356 * @param enabled If OFTrue, do not reject Default role proposals when configured 357 * for SCP role. OFFalse (default behaviour): Reject such proposals. 358 */ 359 void setAlwaysAcceptDefaultRole(const OFBool enabled); 360 361 /* Get methods for SCP settings */ 362 363 /** Returns TCP/IP port number SCP listens for new connection requests 364 * @return The port number 365 */ 366 Uint16 getPort() const; 367 368 /** Returns SCP's own AE title. Only used if the SCP is not configured to respond with the 369 * called AE title the SCU uses for association negotiation, see setRespondWithCalledAETitle(). 370 * @return The configured AE title 371 */ 372 const OFString& getAETitle() const; 373 374 /** Returns whether SCP uses the called AE title from SCU requests to respond to connection 375 * requests instead of a configured AE title 376 * @return OFTrue, if the SCU's calling AE title is utilized, OFFalse otherwise 377 */ 378 OFBool getRespondWithCalledAETitle() const; 379 380 /** Returns whether SCP should refuse any association request no matter what the SCU proposes 381 * @return OFTrue, if SCP is configured to refuse every association 382 */ 383 OFBool getRefuseAssociation() const; 384 385 /** Returns maximum PDU length configured to be received by SCP 386 * @return Maximum PDU length in bytes 387 */ 388 Uint32 getMaxReceivePDULength() const; 389 390 /** Returns whether receiving of TCP/IP connection requests is done in blocking or 391 * unblocking mode 392 * @return DUL_BLOCK if in blocking mode, otherwise DUL_NOBLOCK 393 */ 394 DUL_BLOCKOPTIONS getConnectionBlockingMode() const; 395 396 /** Returns whether receiving of DIMSE messages is done in blocking or unblocking mode 397 * @return DIMSE_BLOCKING if in blocking mode, otherwise DIMSE_NONBLOCKING 398 */ 399 T_DIMSE_BlockingMode getDIMSEBlockingMode() const; 400 401 /** Returns DIMSE timeout (only applicable in blocking mode) 402 * @return DIMSE timeout in seconds 403 */ 404 Uint32 getDIMSETimeout() const; 405 406 /** Returns ACSE timeout 407 * @return ACSE timeout in seconds 408 */ 409 Uint32 getACSETimeout() const; 410 411 /** Returns connection timeout 412 * @return TCP/IP connection timeout in seconds 413 */ 414 Uint32 getConnectionTimeout() const; 415 416 /** Returns the verbose presentation context mode configured specifying whether details on 417 * the presentation contexts (negotiated during association setup) should be shown in 418 * verbose or debug mode. The latter is the default. 419 * @return The verbose presentation context mode configured 420 */ 421 OFBool getVerbosePCMode() const; 422 423 /** Returns whether a connecting system's host name is looked up. 424 * @return OFTrue, if host name lookup is enabled, OFFalse otherwise 425 */ 426 OFBool getHostLookupEnabled() const; 427 428 /** Returns the mode that specifies whether the progress of sending and receiving DIMSE 429 * messages is notified by calling notifySENDProgress() and notifyRECEIVEProgress(), 430 * respectively. The progress notification is enabled by default. 431 * @return The current progress notification mode, enabled if OFTrue 432 */ 433 OFBool getProgressNotificationMode() const; 434 435 /** Get access to the configuration of the SCP. Note that the functionality 436 * on the configuration object is shadowed by other API functions of DcmSCP. 437 * The existing functions are provided in order to not break users of this 438 * "older" API where no configuration object existed. 439 * @return a reference to the DcmSCPConfig object used by this DcmSCP object. 440 */ 441 virtual DcmSCPConfig& getConfig(); 442 443 /** Set the DcmSCPConfig object to use for configuring this DcmSCP object. 444 * A deep copy is performed. 445 * @param config The configuration to use. 446 * @return EC_Normal if configuration can be used. The configuration can 447 * only be changed if the SCP is not yet connected, otherwise 448 * NET_EC_AlreadyConnected is returned. 449 * 450 */ 451 virtual OFCondition setConfig(const DcmSCPConfig& config); 452 453 /* ************************************************************* */ 454 /* Methods for receiving runtime (i.e. connection time) infos */ 455 /* ************************************************************* */ 456 457 /** Returns whether SCP is currently connected. If in multi-process mode, the "father" 458 * process should always return false here, because connection is always handled by child 459 * process. 460 * @return OFTrue, if SCP is currently connected to calling SCU 461 */ 462 OFBool isConnected() const; 463 464 /** Returns number of associations currently running. Only applicable in Unix-like 465 * operating systems. Can only be greater than one when running in multi-process mode. 466 * @return Number of currently running associations 467 */ 468 Uint16 numAssociations() const; 469 470 /** Returns AE title the SCU used as called AE title in association request 471 * @return AE title the SCP was called with. Empty string if SCP is currently not 472 * connected. 473 */ 474 OFString getCalledAETitle() const; 475 476 /** Returns AE title (calling AE title) the SCU used for association request 477 * @return Calling AE title of SCU. Empty string if SCP is currently not connected. 478 */ 479 OFString getPeerAETitle() const; 480 481 /** Returns IP address of connected SCU 482 * @return IP address of connected SCU. Empty string if SCP is currently not connected. 483 */ 484 OFString getPeerIP() const; 485 486 /** Returns maximum PDU size the communication peer (i.e.\ the SCU) is able to receive 487 * @return Maximum PDU size the SCU is able to receive. Returns zero if SCP is currently 488 * not connected. 489 */ 490 Uint32 getPeerMaxPDULength() const; 491 492 /// DcmThreadSCP needs access to configuration (m_cfg), at least 493 friend class DcmThreadSCP; 494 495 protected: 496 /* ********************************************* */ 497 /* Functions available to derived classes only */ 498 /* ********************************************* */ 499 500 /** This call returns the presentation context belonging to the given 501 * presentation context ID. 502 * @param presID [in] The presentation context ID to look for 503 * @param abstractSyntax [out] The abstract syntax (UID) for that ID. 504 * Empty, if such a presentation context does not exist. 505 * @param transferSyntax [out] The transfer syntax (UID) for that ID. 506 * Empty, if such a presentation context does not exist. 507 */ 508 void findPresentationContext(const T_ASC_PresentationContextID presID, 509 OFString& abstractSyntax, 510 OFString& transferSyntax); 511 512 /** Aborts the current association by sending an A-ABORT request to the SCU. 513 * This method allows derived classes to abort an association in case of severe errors. 514 * @return status, EC_Normal if successful, an error code otherwise 515 */ 516 virtual OFCondition abortAssociation(); 517 518 /* *********************************************************************** */ 519 /* Functions particularly interesting for overwriting in derived classes */ 520 /* *********************************************************************** */ 521 522 /** Handle incoming command set and react accordingly, e.g.\ sending response via 523 * DIMSE_sendXXXResponse(). The standard handler only knows how to handle 524 * a C-ECHO request message (by calling handleEchoRequest()) if it is sent on a 525 * presentation context configured for the Verification SOP Class. 526 * This function is most likely to be implemented by a derived class 527 * implementing a specific SCP behavior. 528 * @param incomingMsg The DIMSE message received 529 * @param presInfo Additional information on the Presentation Context used 530 * @return EC_Normal if the message could be handled, error if not. Especially 531 * DIMSE_BADCOMMANDTYPE should be returned if there is no handler for 532 * this particular type of DIMSE message. E.g. the default handler in 533 * DcmSCP only handles C-ECHO requests and, therefore, returns 534 * DIMSE_BADCOMMANDTYPE otherwise. 535 */ 536 virtual OFCondition handleIncomingCommand(T_DIMSE_Message* incomingMsg, const DcmPresentationContextInfo& presInfo); 537 538 /** Overwrite this function to be notified about an incoming association request. 539 * The standard handler only outputs some information to the logger. 540 * @param params The association parameters that were received. 541 * @param desiredAction The desired action how to handle this association request. 542 */ 543 virtual void notifyAssociationRequest(const T_ASC_Parameters& params, DcmSCPActionType& desiredAction); 544 545 /** Overwrite this function if called AE title should undergo checking. If 546 * OFTrue is returned, the AE title is accepted and processing is continued. 547 * In case of OFFalse, the SCP will refuse the incoming association with 548 * error "Called Application Entity Title Not Recognized". 549 * The standard handler always returns OFTrue. 550 * @param calledAE The called AE title the SCU used that should be checked 551 * @return OFTrue, if AE title is accepted, OFFalse otherwise 552 */ 553 virtual OFBool checkCalledAETitleAccepted(const OFString& calledAE); 554 555 /** Overwrite this function if calling AE title should undergo checking. If 556 * OFTrue is returned, the AE title is accepted and processing is continued. 557 * In case of OFFalse, the SCP will refuse the incoming association with 558 * error "Calling Application Entity Title Not Recognized". 559 * The standard handler always returns OFTrue. 560 * @param callingAE The calling AE title the SCU used that should be checked 561 * @return OFTrue, if AE title is accepted, OFFalse otherwise 562 */ 563 virtual OFBool checkCallingAETitleAccepted(const OFString& callingAE); 564 565 /** Overwrite this function if calling IP / host name should undergo checking. 566 * If OFTrue is returned, the host is accepted and processing is continued. 567 * In case of OFFalse, the SCP will refuse the incoming association with 568 * an error. The standard handler always returns OFTrue. 569 * @param hostOrIP The IP of the client to check. 570 * @return OFTrue, if IP/host is accepted, OFFalse otherwise 571 */ 572 virtual OFBool checkCallingHostAccepted(const OFString& hostOrIP); 573 574 /** Overwrite this function to be notified about an incoming association request. 575 * The standard handler only outputs some information to the logger. 576 */ 577 virtual void notifyAssociationAcknowledge(); 578 579 /** Overwrite this function to be notified about an incoming association release request. 580 * The standard handler only outputs some information to the logger. 581 */ 582 virtual void notifyReleaseRequest(); 583 584 /** Overwrite this function to be notified about an incoming association abort request. 585 * The standard handler only outputs some information to the logger. 586 */ 587 virtual void notifyAbortRequest(); 588 589 /** Overwrite this function to be notified when an association is terminated. 590 * The standard handler only outputs some information to the logger. 591 */ 592 virtual void notifyAssociationTermination(); 593 594 /** Overwrite this function to be notified about a connection timeout in 595 * non-blocking mode (see setConnectionBlockingMode() and setConnectionTimeout() 596 * methods). In blocking mode, this method has no effect since it's never called. 597 * The standard handler only outputs some information to the TRACE logger. 598 */ 599 virtual void notifyConnectionTimeout(); 600 601 /** Overwrite this function to be notified when a DIMSE error occurs. 602 * The standard handler only outputs error information to the logger. 603 * @param cond [in] The DIMSE error occurred. 604 */ 605 virtual void notifyDIMSEError(const OFCondition& cond); 606 607 /** This function is called while sending DIMSE messages, i.e.\ on each PDV of a dataset. 608 * The default implementation just prints a TRACE message on the number of bytes sent so 609 * far. By overwriting this method, the progress of the send process can be shown to the 610 * user in a more appropriate way. The progress notification can also be disabled 611 * completely by calling setProgressNotificationMode(). 612 * @param byteCount [in] Number of bytes sent so far 613 */ 614 virtual void notifySENDProgress(const unsigned long byteCount); 615 616 /** This function is called while receiving DIMSE messages, i.e.\ on each PDV of a dataset. 617 * The default implementation just prints a TRACE message on the number of bytes received 618 * so far. By overwriting this method, the progress of the receive process can be shown to 619 * the user in a more appropriate way. The progress notification can also be disabled 620 * completely by calling setProgressNotificationMode(). 621 * @param byteCount [in] Number of bytes received so far 622 */ 623 virtual void notifyRECEIVEProgress(const unsigned long byteCount); 624 625 /** This method can be used to return from the listen() loop in a controlled way. 626 * In order to use it, it must be overwritten in a derived class. As long as no 627 * severe error occurs and this method returns OFFalse, the listen() method will wait 628 * for incoming associations in an infinite loop. 629 * @return The standard handler always returns OFFalse 630 */ 631 virtual OFBool stopAfterCurrentAssociation(); 632 633 /** This method can be used to return from the listen() loop in a controlled way. 634 * In order to use it, it must be overwritten in a derived class. As long as no 635 * severe error occurs and this method returns OFFalse, the listen() method will wait 636 * for incoming associations in an infinite loop. If this method returns OFTrue, the 637 * SCP will return from the listen() loop after a connection timeout occurs (see 638 * setConnectionTimeout() method). In blocking mode (see setConnectionBlockingMode() 639 * method), this method has no effect (it's never called) since the underlying 640 * routines will wait forever for an incoming TCP connection. 641 * @return The standard handler always returns OFFalse 642 */ 643 virtual OFBool stopAfterConnectionTimeout(); 644 645 // -- C-ECHO -- 646 647 /** Standard handler for Verification Service Class (DICOM Echo). Returns echo response 648 * (i.e. whether C-ECHO could be responded to with status success). 649 * @param reqMessage [in] The C-ECHO request message that was received 650 * @param presID [in] The presentation context to be used. By default, the 651 * presentation context of the request is used. 652 * @return status, EC_Normal if successful, an error code otherwise 653 */ 654 virtual OFCondition handleECHORequest(T_DIMSE_C_EchoRQ& reqMessage, const T_ASC_PresentationContextID presID); 655 656 // --- C-STORE -- 657 658 /** Receive C-STORE request on the currently opened association, store the 659 * accompanying dataset in memory and send a corresponding response. Calls 660 * checkSTORERequest() in order to determine the DIMSE status code to be used for 661 * the C-STORE response. 662 * @note This handler receives the dataset belonging the C-STORE request completely 663 * in memory. If very large datasets are expected, another handler should be 664 * implemented that calls the receiveSTORERequest() method with a filename. 665 * @param reqMessage [in] The C-STORE request message that was received 666 * @param presID [in] The presentation context to be used. By default, the 667 * presentation context of the request is used. 668 * @param reqDataset [inout] Pointer to data structure where the received dataset 669 * should be stored. If NULL, a new dataset is created, 670 * which has to be deleted by the caller. 671 * @return status, EC_Normal if successful, an error code otherwise 672 */ 673 virtual OFCondition handleSTORERequest(T_DIMSE_C_StoreRQ& reqMessage, 674 const T_ASC_PresentationContextID presID, 675 DcmDataset*& reqDataset); 676 677 /** Receive C-STORE request (and store accompanying dataset in memory). 678 * For very large datasets, the other receiveSTORERequest() method should be used 679 * because it stores the received dataset directly to file. 680 * @param reqMessage [in] The C-STORE request message that was received 681 * @param presID [in] The presentation context to be used. By default, the 682 * presentation context of the request is used. 683 * @param reqDataset [inout] Pointer to data structure where the received dataset 684 * should be stored. If NULL, a new dataset is created, 685 * which has to be deleted by the caller. 686 * @return status, EC_Normal if successful, an error code otherwise 687 */ 688 virtual OFCondition receiveSTORERequest(T_DIMSE_C_StoreRQ& reqMessage, 689 const T_ASC_PresentationContextID presID, 690 DcmDataset*& reqDataset); 691 692 /** Receive C-STORE request (and store accompanying dataset directly to file). 693 * The dataset is stored exactly as received, i.e. without any conversions. 694 * @param reqMessage [in] The C-STORE request message that was received 695 * @param presID [in] The presentation context to be used. By default, the 696 * presentation context of the request is used. 697 * @param filename [in] The filename used to store the received dataset 698 * @return status, EC_Normal if successful, an error code otherwise 699 */ 700 virtual OFCondition receiveSTORERequest(T_DIMSE_C_StoreRQ& reqMessage, 701 const T_ASC_PresentationContextID presID, 702 const OFString& filename); 703 704 /** Respond to the C-STORE request (with details from the request message) 705 * @param presID [in] The presentation context ID to respond to 706 * @param reqMessage [in] The C-STORE request that should be responded to 707 * @param rspStatusCode [in] The response status code. 0 means success, 708 * others can found in the DICOM standard. 709 * @return EC_Normal, if responding was successful, an error code otherwise 710 */ 711 virtual OFCondition sendSTOREResponse(const T_ASC_PresentationContextID presID, 712 const T_DIMSE_C_StoreRQ& reqMessage, 713 const Uint16 rspStatusCode); 714 715 /** Respond to the C-STORE request (with given details) 716 * @param presID [in] The presentation context ID to respond to 717 * @param messageID [in] The message ID being responded to 718 * @param sopClassUID [in] The affected SOP class UID 719 * @param sopInstanceUID [in] The affected SOP instance UID 720 * @param rspStatusCode [in] The response status code. 0 means success, 721 * others can found in the DICOM standard. 722 * @param statusDetail [in] The status detail of the response (if desired). 723 * @return EC_Normal, if responding was successful, an error code otherwise 724 */ 725 virtual OFCondition sendSTOREResponse(const T_ASC_PresentationContextID presID, 726 const Uint16 messageID, 727 const OFString& sopClassUID, 728 const OFString& sopInstanceUID, 729 const Uint16 rspStatusCode, 730 DcmDataset* statusDetail = NULL); 731 732 /** Check given C-STORE request and dataset for validity. This method is called by 733 * handleSTORERequest() before sending the response in order to determine the DIMSE 734 * status code to be used for the response message. 735 * @param reqMessage [in] The C-STORE request message data structure 736 * @param reqDataset [in] The C-STORE request dataset received. Might be NULL. 737 * @return DIMSE status code to be used for the C-STORE response. 738 * Always returns STATUS_Success (0). Derived classes should, therefore, 739 * overwrite this method and return a more appropriate value based on the 740 * result of the checks performed. 741 */ 742 virtual Uint16 checkSTORERequest(T_DIMSE_C_StoreRQ& reqMessage, DcmDataset* reqDataset); 743 744 // -- C-FIND -- 745 746 /** Receive C-FIND request 747 * @param reqMessage [in] The C-FIND request message that was received 748 * @param presID [in] The presentation context to be used. By default, the 749 * presentation context of the request is used. 750 * @param reqDataset [out] Pointer to the dataset received 751 * @return status, EC_Normal if successful, an error code otherwise 752 */ 753 virtual OFCondition 754 receiveFINDRequest(T_DIMSE_C_FindRQ& reqMessage, const T_ASC_PresentationContextID presID, DcmDataset*& reqDataset); 755 756 /** Handle C-FIND request. This function is deprecated and will be removed in 757 * the future. For now it calls receiveFINDRequest() which should be used 758 * instead. 759 * @param reqMessage [in] The C-FIND request message that was received 760 * @param presID [in] The presentation context to be used. By default, the 761 * presentation context of the request is used. 762 * @param reqDataset [out] Pointer to the dataset received 763 * @return status, EC_Normal if successful, an error code otherwise 764 */ 765 virtual OFCondition handleFINDRequest(T_DIMSE_C_FindRQ & reqMessage,const T_ASC_PresentationContextID presID,DcmDataset * & reqDataset)766 handleFINDRequest(T_DIMSE_C_FindRQ& reqMessage, const T_ASC_PresentationContextID presID, DcmDataset*& reqDataset) 767 { 768 DCMNET_WARN("handleFINDRequest() is deprecated, use receiveFINDRequest() instead"); 769 return receiveFINDRequest(reqMessage, presID, reqDataset); 770 } 771 772 /** Respond to the C-FIND request 773 * @param presID [in] The presentation context ID to respond to 774 * @param messageID [in] The message ID being responded to 775 * @param sopClassUID [in] The affected SOP class UID 776 * @param rspDataset [in] The response dataset 777 * @param rspStatusCode [in] The response status code. 0 means success, 778 * others can found in the DICOM standard. 779 * @param statusDetail [in] Any status (must fit response code), if desired 780 * @return EC_Normal, if responding was successful, an error code otherwise 781 */ 782 virtual OFCondition sendFINDResponse(const T_ASC_PresentationContextID presID, 783 const Uint16 messageID, 784 const OFString& sopClassUID, 785 DcmDataset* rspDataset, 786 const Uint16 rspStatusCode, 787 DcmDataset* statusDetail = NULL); 788 789 /** Check for C-CANCEL. This is needed for example for a Query/Retrieve 790 * server that is in the middle of returning C-FIND responses to a 791 * client and has to perform a regular check whether the client sent a 792 * C-CANCEL in order to stop receiving C-FIND responses. 793 * @param presID [in] The presentation context ID where C-CANCEL is 794 * expected. 795 * @param messageID [in] The "message ID responded to" that the client 796 * is expected to use (usually this is the message 797 * ID used in the original FIND/GET/MOVE request). 798 * @return EC_Normal, if C-CANCEL was received. DIMSE_NODATAAVAILABLE if no 799 * DIMSE message (or anything) was received from the client. 800 * DIMSEC_UNEXPECTEDREQUEST if command is received but it is not 801 * a C-CANCEL message, or the message ID used by client is wrong 802 * (message ID must be the one from the original FIND/MOVE/GET 803 * request). 804 * DIMSEC_INVALIDPRESENTATIONCONTEXTID if the wrong presentation 805 * context (ID) was used for sending. Other low level errors 806 * (e.g. DIMSEC_UNEXPECTEDPDVTYPE) could be returned, too. 807 */ 808 virtual OFCondition checkForCANCEL(T_ASC_PresentationContextID presID, const Uint16 messageID); 809 810 // --- C-MOVE -- 811 812 /** Receive C-MOVE request on the currently active association. 813 * @param reqMessage [in] The C-MOVE request message that was received 814 * @param presID [in] The presentation context to be used. By default, the 815 * presentation context of the request is used. 816 * @param reqDataset [out] Pointer to the dataset received 817 * @param moveDest [out] The move destination where to send the instances 818 * @return status, EC_Normal if successful, an error code otherwise 819 */ 820 virtual OFCondition receiveMOVERequest(T_DIMSE_C_MoveRQ& reqMessage, 821 const T_ASC_PresentationContextID presID, 822 DcmDataset*& reqDataset, 823 OFString& moveDest); 824 825 /** Receive C-MOVE request on the currently active association. This function 826 * is deprecated and will be removed in the future. For now it calls 827 * receiveMOVERequest() which should be used instead. 828 * @param reqMessage [in] The C-MOVE request message that was received 829 * @param presID [in] The presentation context to be used. By default, the 830 * presentation context of the request is used. 831 * @param reqDataset [out] Pointer to the dataset received 832 * @param moveDest [out] The move destination where to send the instances 833 * @return status, EC_Normal if successful, an error code otherwise 834 */ handleMOVERequest(T_DIMSE_C_MoveRQ & reqMessage,const T_ASC_PresentationContextID presID,DcmDataset * & reqDataset,OFString & moveDest)835 virtual OFCondition handleMOVERequest(T_DIMSE_C_MoveRQ& reqMessage, 836 const T_ASC_PresentationContextID presID, 837 DcmDataset*& reqDataset, 838 OFString& moveDest) 839 { 840 DCMNET_WARN("handleMOVERequest() is deprecated, use receiveMOVERequest() instead"); 841 return receiveMOVERequest(reqMessage, presID, reqDataset, moveDest); 842 } 843 844 /** Respond to the C-MOVE request 845 * @param presID [in] The presentation context ID to respond to 846 * @param messageID [in] The message ID being responded to 847 * @param sopClassUID [in] The affected SOP class UID 848 * @param rspDataset [in] The response dataset 849 * @param rspStatusCode [in] The status code of the response. 0 means success, 850 * others can found in the DICOM standard. 851 * @param statusDetail [in] The status detail of the response (if desired). 852 * @param numRemain [in] Number of remaining sub-operations. 853 * Required for Pending status codes, often optional otherwise. 854 * Sent if one of the num parameters is not 0. 855 * @param numComplete [in] Number of completed sub-operations. 856 * Required for Pending status codes, often optional otherwise. 857 * Sent if one of the num parameters is not 0. 858 * @param numFail [in] Number of failed sub-operations. 859 * Required for Pending status codes, often optional otherwise. 860 * Sent if one of the num parameters is not 0. 861 * @param numWarn [in] Number of warning sub-operations. 862 * Required for Pending status codes, often optional otherwise. 863 * Sent if one of the num parameters is not 0. 864 * @return EC_Normal, if responding was successful, an error code otherwise 865 */ 866 virtual OFCondition sendMOVEResponse(const T_ASC_PresentationContextID presID, 867 const Uint16 messageID, 868 const OFString& sopClassUID, 869 DcmDataset* rspDataset, 870 const Uint16 rspStatusCode, 871 DcmDataset* statusDetail = NULL, 872 const Uint16 numRemain = 0, 873 const Uint16 numComplete = 0, 874 const Uint16 numFail = 0, 875 const Uint16 numWarn = 0); 876 877 // -- N-ACTION -- 878 879 /** Receive N-ACTION request on the currently opened association. 880 * @param reqMessage [in] The N-ACTION request message that was received 881 * @param presID [in] The presentation context to be used. By default, the 882 * presentation context of the request is used. 883 * @param reqDataset [out] Pointer to the dataset received 884 * @param actionTypeID [out] Action Type ID from the command set received 885 * @return status, EC_Normal if successful, an error code otherwise 886 */ 887 virtual OFCondition receiveACTIONRequest(T_DIMSE_N_ActionRQ& reqMessage, 888 const T_ASC_PresentationContextID presID, 889 DcmDataset*& reqDataset, 890 Uint16& actionTypeID); 891 892 /** Receive N-ACTION request on the currently opened association. This 893 * function is deprecated and will be removed in the future. For now it calls 894 * receiveACTIONRequest() which should be used instead. 895 * @param reqMessage [in] The N-ACTION request message that was received 896 * @param presID [in] The presentation context to be used. By default, the 897 * presentation context of the request is used. 898 * @param reqDataset [out] Pointer to the dataset received 899 * @param actionTypeID [out] Action Type ID from the command set received 900 * @return status, EC_Normal if successful, an error code otherwise 901 */ handleACTIONRequest(T_DIMSE_N_ActionRQ & reqMessage,const T_ASC_PresentationContextID presID,DcmDataset * & reqDataset,Uint16 & actionTypeID)902 virtual OFCondition handleACTIONRequest(T_DIMSE_N_ActionRQ& reqMessage, 903 const T_ASC_PresentationContextID presID, 904 DcmDataset*& reqDataset, 905 Uint16& actionTypeID) 906 { 907 DCMNET_WARN("handleACTIONRequest() is deprecated, use receiveACTIONRequest() instead"); 908 return receiveACTIONRequest(reqMessage, presID, reqDataset, actionTypeID); 909 } 910 911 /** Respond to the N-ACTION request 912 * @param presID [in] The presentation context ID to respond to 913 * @param messageID [in] The message ID being responded to 914 * @param sopClassUID [in] The affected SOP class UID 915 * @param sopInstanceUID [in] The affected SOP instance UID 916 * @param rspStatusCode [in] The response status code. 0 means success, 917 * others can found in the DICOM standard. 918 * @return EC_Normal, if responding was successful, an error code otherwise 919 */ 920 virtual OFCondition sendACTIONResponse(const T_ASC_PresentationContextID presID, 921 const Uint16 messageID, 922 const OFString& sopClassUID, 923 const OFString& sopInstanceUID, 924 const Uint16 rspStatusCode); 925 926 // -- N-EVENT-REPORT -- 927 928 /** Receive N-EVENT-REPORT request on the currently opened association and send a 929 * corresponding response. Calls checkEVENTREPORTRequest() in order to determine the 930 * DIMSE status code to be used for the N-EVENT-REPORT response. 931 * @param reqMessage [in] The N-EVENT-REPORT request message that was received 932 * @param presID [in] The presentation context to be used. By default, the 933 * presentation context of the request is used. 934 * @param reqDataset [out] Pointer to the dataset received 935 * @param eventTypeID [out] Event Type ID from the command set received 936 * @return status, EC_Normal if successful, an error code otherwise 937 */ 938 virtual OFCondition handleEVENTREPORTRequest(T_DIMSE_N_EventReportRQ& reqMessage, 939 const T_ASC_PresentationContextID presID, 940 DcmDataset*& reqDataset, 941 Uint16& eventTypeID); 942 943 /** Send N-EVENT-REPORT request on the current association and receive a corresponding 944 * response. 945 * @param presID [in] The ID of the presentation context to be used for sending 946 * the request message. Should not be 0. 947 * @param sopInstanceUID [in] The requested SOP Instance UID 948 * @param messageID [in] The request message ID 949 * @param eventTypeID [in] The event type ID to be used 950 * @param reqDataset [in] The request dataset to be sent 951 * @param rspStatusCode [out] The response status code received. 0 means success, 952 * others can be found in the DICOM standard. 953 * @return EC_Normal if request could be issued and response was received successfully, 954 * an error code otherwise 955 */ 956 virtual OFCondition sendEVENTREPORTRequest(const T_ASC_PresentationContextID presID, 957 const OFString& sopInstanceUID, 958 const Uint16 messageID, 959 const Uint16 eventTypeID, 960 DcmDataset* reqDataset, 961 Uint16& rspStatusCode); 962 963 /** Check given N-EVENT-REPORT request and dataset for validity. This method is called by 964 * handleEVENTREPORTRequest() before sending the response in order to determine the 965 * DIMSE status code to be used for the response message. 966 * @param reqMessage [in] The N-EVENT-REPORT request message data structure 967 * @param reqDataset [in] The N-EVENT-REPORT request dataset received. Might be NULL. 968 * @return DIMSE status code to be used for the N-EVENT-REPORT response. 969 * Always returns STATUS_Success (0). Derived classes should, therefore, 970 * overwrite this method and return a more appropriate value based on the 971 * result of the checks performed. 972 */ 973 virtual Uint16 checkEVENTREPORTRequest(T_DIMSE_N_EventReportRQ& reqMessage, DcmDataset* reqDataset); 974 975 /* ********************************************************************* */ 976 /* Further functions and member variables */ 977 /* ********************************************************************* */ 978 979 /** Helper function to return presentation context information by given 980 * presentation context ID. 981 * @param head The presentation context list 982 * @param presentationContextID The presentation context ID 983 * @return The presentation context information 984 */ 985 static DUL_PRESENTATIONCONTEXT* findPresentationContextID(LST_HEAD* head, 986 T_ASC_PresentationContextID presentationContextID); 987 988 /** Helper function to return presentation context information by given 989 * presentation context ID. 990 * @param assoc The association to search 991 * @param presID The presentation context ID 992 * @param presInfo The result presentation context information, if found 993 * @return OFTrue if presentation context with ID could be found, OFFalse 994 * otherwise 995 */ 996 static OFBool getPresentationContextInfo(const T_ASC_Association* assoc, 997 const Uint8 presID, 998 DcmPresentationContextInfo& presInfo); 999 1000 /** This function takes care of receiving, negotiating and accepting/refusing an 1001 * association request. Additionally, if negotiation was successful, it handles any 1002 * incoming DIMSE commands by calling handleAssociation(). An error is only returned, if 1003 * something goes wrong. Therefore, refusing an association because of wrong application 1004 * context name or no common presentation contexts with the SCU does NOT lead to an error. 1005 * @param network [in] Contains network parameters 1006 * @return EC_Normal, if everything went fine, DUL_NOASSOCIATIONREQUEST if a timeout 1007 * occurs in non-blocking mode, DIMSE_ILLEGALASSOCIATION or ASC_NULLKEY if 1008 * severe internal errors occurred (should not happen) 1009 */ 1010 virtual OFCondition waitForAssociationRQ(T_ASC_Network* network); 1011 1012 /** Actually process association request. 1013 * @return EC_Normal if association could be processed, ASC_NULLKEY otherwise 1014 * (only if internal association structure is invalid, should never happen) 1015 */ 1016 virtual OFCondition processAssociationRQ(); 1017 1018 /** This function checks all presentation contexts proposed by the SCU whether they are 1019 * supported or not. It is not an error if no common presentation context could be 1020 * identified with the SCU; only issues like problems in memory management etc. are 1021 * reported as an error. This function does not send a response message to the SCU. This 1022 * is done in other functions. 1023 * @return EC_Normal if negotiation was successfully done, an error code otherwise 1024 */ 1025 virtual OFCondition negotiateAssociation(); 1026 1027 /** This function takes care of refusing an association request 1028 * @param reason [in] The reason why the association request will be refused and that 1029 * will be reported to the SCU. 1030 */ 1031 virtual void refuseAssociation(const DcmRefuseReasonType reason); 1032 1033 /** This function takes care of handling the other DICOM application's request. After 1034 * having accomplished all necessary steps, the association will be dropped and destroyed. 1035 */ 1036 virtual void handleAssociation(); 1037 1038 /** Send a DIMSE command and possibly also a dataset from a data object via network to 1039 * another DICOM application 1040 * @param presID [in] Presentation context ID to be used for message 1041 * @param message [in] Structure that represents a certain DIMSE command which 1042 * shall be sent 1043 * @param dataObject [in] The instance data which shall be sent to the other DICOM 1044 * application; NULL, if there is none 1045 * @param statusDetail [in] The status detail of the response (if desired). 1046 * @param commandSet [out] If this parameter is not NULL it will return a copy of the 1047 * DIMSE command which is sent to the other DICOM application 1048 * @return Returns EC_Normal if sending request was successful, an error code otherwise 1049 */ 1050 OFCondition sendDIMSEMessage(const T_ASC_PresentationContextID presID, 1051 T_DIMSE_Message* message, 1052 DcmDataset* dataObject, 1053 DcmDataset* statusDetail = NULL, 1054 DcmDataset** commandSet = NULL); 1055 1056 /** Receive DIMSE command (excluding dataset!) over the currently open association 1057 * @param presID [out] Contains in the end the ID of the presentation context 1058 * which was specified in the DIMSE command received 1059 * @param message [out] The message received 1060 * @param statusDetail [out] If a non-NULL value is passed this variable will in the end 1061 * contain detailed information with regard to the status 1062 * information which is captured in the status element 1063 * (0000,0900). Note that the value for element (0000,0900) is 1064 * not contained in this return value but in internal message. 1065 * For details on the structure of this object, see DICOM 1066 * standard part 7, annex C). 1067 * @param commandSet [out] If this parameter is not NULL, it will return a copy of the 1068 * DIMSE command which was received from the other DICOM 1069 * application. The caller is responsible to de-allocate the 1070 * returned object! 1071 * @param timeout [in] If this parameter is not 0, it specifies the timeout (in 1072 * seconds) to be used for receiving the DIMSE command. 1073 * Otherwise, the default timeout value is used (see 1074 * setDIMSETimeout()). 1075 * @return EC_Normal if command could be received successfully, an error code otherwise 1076 */ 1077 OFCondition receiveDIMSECommand(T_ASC_PresentationContextID* presID, 1078 T_DIMSE_Message* message, 1079 DcmDataset** statusDetail, 1080 DcmDataset** commandSet = NULL, 1081 const Uint32 timeout = 0); 1082 1083 /** Receive one dataset (of instance data) via network from another DICOM application 1084 * @param presID [out] Contains in the end the ID of the presentation context 1085 * which was used in the PDVs that were received on the 1086 * network. If the PDVs show different presentation context 1087 * IDs, this function will return an error. 1088 * @param dataObject [inout] Contains in the end the information that was received 1089 * over the network. If this parameter points to NULL, a new 1090 * dataset will be created by the underlying routines, which 1091 * has to be deleted by the caller. 1092 * @return EC_Normal if dataset could be received successfully, an error code otherwise 1093 */ 1094 OFCondition receiveDIMSEDataset(T_ASC_PresentationContextID* presID, DcmDataset** dataObject); 1095 1096 /** Receive one C-STORE request dataset via network from another DICOM application and 1097 * store it directly to file (i.e.\ exactly as received without any conversions) 1098 * @param presID [inout] Initially, the presentation context the C-STORE request was 1099 * received on. Contains in the end the ID of the presentation 1100 * context which was used in the PDVs that were received on the 1101 * network. If the PDVs show different presentation context 1102 * IDs, this function will return an error. 1103 * @param reqMessage [in] The C-STORE request message that was received 1104 * @param filename [in] Name of the file that is created to store the received dataset 1105 * @return EC_Normal if dataset could be received successfully, an error code otherwise 1106 */ 1107 OFCondition receiveSTORERequestDataset(T_ASC_PresentationContextID* presID, 1108 T_DIMSE_C_StoreRQ& reqMessage, 1109 const OFString& filename); 1110 1111 /** Add given element to existing status detail object or create new one. 1112 * @param statusDetail The status detail to add the element to. Status detail 1113 * is information additional to the DIMSE status code which can be 1114 * provided for some DIMSE messages. If NULL is provided, 1115 * a new status detail object is created and returned. All status 1116 * detail attributes need to have the VR AT or LO which is also 1117 * checked by the underlying routine. 1118 * @param elem The element to be copied into the status detail. 1119 * @return OFTrue if status detail was successfully added, 1120 * OFFalse otherwise. 1121 */ 1122 static OFBool addStatusDetail(DcmDataset** statusDetail, const DcmElement* elem); 1123 1124 /* Callback functions (static) */ 1125 1126 /** Callback function used for sending DIMSE messages. 1127 * @param callbackContext [in] The desired user callback data 1128 * @param byteCount [in] Progress bytes count 1129 */ 1130 static void callbackSENDProgress(void* callbackContext, unsigned long byteCount); 1131 1132 /** Callback function used for receiving DIMSE messages. 1133 * @param callbackContext [in] The desired user callback data 1134 * @param byteCount [in] Progress bytes count 1135 */ 1136 static void callbackRECEIVEProgress(void* callbackContext, unsigned long byteCount); 1137 1138 private: 1139 /// Network instance run by this SCP 1140 T_ASC_Network* m_network; 1141 1142 /// Current association run by this SCP 1143 T_ASC_Association* m_assoc; 1144 1145 /// SCP configuration. The configuration is a shared object since in some scenarios one 1146 /// might like to share a single configuration instance with multiple SCPs without copying 1147 /// it, e.g. in the context of the DcmSCPPool class. 1148 DcmSharedSCPConfig m_cfg; 1149 1150 /** Drops association and clears internal structures to free memory 1151 */ 1152 void dropAndDestroyAssociation(); 1153 1154 /** Private undefined copy constructor. Shall never be called. 1155 * @param src Source object 1156 */ 1157 DcmSCP(const DcmSCP& src); 1158 1159 /** Private undefined assignment operator. Shall never be called. 1160 * @param src Source object 1161 * @return Reference to this 1162 */ 1163 DcmSCP& operator=(const DcmSCP& src); 1164 }; 1165 1166 #endif // SCP_H 1167