ctkDcmSCU.h 51 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035
  1. /*
  2. *
  3. * Copyright (C) 2008-2012, 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: Base class for Service Class Users (SCUs)
  19. *
  20. */
  21. #ifndef SCU_H
  22. #define SCU_H
  23. #include "dcmtk/config/osconfig.h" /* make sure OS specific configuration is included first */
  24. #include "dcmtk/dcmdata/dctk.h" /* Covers most common dcmdata classes */
  25. #include "dcmtk/dcmnet/dcompat.h"
  26. #include "dcmtk/dcmnet/dimse.h" /* DIMSE network layer */
  27. #include "dcmtk/dcmnet/dcasccff.h" /* For reading a association config file */
  28. #include "dcmtk/dcmnet/dcasccfg.h" /* For holding association config file infos */
  29. #include "dcmtk/ofstd/oflist.h"
  30. /* Remove below if changing to more current DCMTK */
  31. const unsigned short ECC_AlreadyConnected = 0x901;
  32. const unsigned short ECC_NoAcceptablePresentationContexts = 0x902;
  33. const unsigned short ECC_NoPresentationContextsDefined = 0x903;
  34. const unsigned short ECC_InvalidSOPInstanceUID = 0x904;
  35. const unsigned short ECC_InvalidSOPClassUID = 0x905;
  36. const unsigned short ECC_UnknownTransferSyntax = 0x906;
  37. //
  38. extern const OFCondition NET_EC_AlreadyConnected;
  39. extern const OFCondition NET_EC_NoAcceptablePresentationContexts;
  40. extern const OFCondition NET_EC_NoPresentationContextsDefined;
  41. extern const OFCondition NET_EC_InvalidSOPClassUID;
  42. extern const OFCondition NET_EC_InvalidSOPInstanceUID;
  43. extern const OFCondition NET_EC_UnknownTransferSyntax;
  44. /* Remove above if changing to more current DCMTK */
  45. /** Different types of closing an association
  46. */
  47. enum DcmCloseAssociationType
  48. {
  49. /// Release the current association
  50. DCMSCU_RELEASE_ASSOCIATION,
  51. /// Abort the current association
  52. DCMSCU_ABORT_ASSOCIATION,
  53. /// Peer requested release (Aborting)
  54. DCMSCU_PEER_REQUESTED_RELEASE,
  55. /// Peer aborted the association
  56. DCMSCU_PEER_ABORTED_ASSOCIATION
  57. };
  58. /** Storage mode used for DICOM objects received via C-STORE
  59. */
  60. enum DcmStorageMode
  61. {
  62. /// Ignore any objects received via C-STORE
  63. DCMSCU_STORAGE_IGNORE,
  64. /// Try to store the objects to disk
  65. DCMSCU_STORAGE_DISK,
  66. /// Try to store to disk in bit-preserving mode. This is especially useful
  67. /// for huge files that cannot fully be received in memory since the
  68. /// data is directly streamed to disk. Originally, this was introduced for
  69. /// DICOM signatures which can be kept valid this way.
  70. DCMSCU_STORAGE_BIT_PRESERVING
  71. };
  72. /** Base class for C-FIND, C-MOVE and C-GET responses
  73. */
  74. class QRResponse
  75. {
  76. public:
  77. /** Standard constructor.
  78. */
  79. QRResponse() :
  80. m_messageIDRespondedTo(0),
  81. m_affectedSOPClassUID(),
  82. m_dataset(NULL),
  83. m_status(0),
  84. m_statusDetail(NULL) {}
  85. /** Destructor, cleans up internal memory (dataset if present).
  86. */
  87. virtual ~QRResponse() { delete m_dataset; delete m_statusDetail; }
  88. /// The message ID responded to (mandatory response field,
  89. /// equals message ID from request)
  90. Uint16 m_messageIDRespondedTo;
  91. /// Optional response field according to part 7 of the standard
  92. /// If present, equals SOP Class UID from request.
  93. OFString m_affectedSOPClassUID;
  94. /// Conditional response field (NULL if absent). From the standard (2009,
  95. /// part 4, C.4.2.1.4.2), for C-MOVE: In Q/R if no C-STORE sub-operation
  96. /// failed, Failed SOP Instance UID List (0008,0058) is absent and
  97. /// therefore no Data Set shall be sent in the C-MOVE response. Further
  98. /// rules: Statuses of Canceled, Failure, Refused, or Warning shall
  99. /// contain the Failed SOP Instance UID List Attribute; status of
  100. /// Pending shall not.
  101. DcmDataset *m_dataset;
  102. /// The returned DIMSE status (mandatory Response Field)
  103. Uint16 m_status;
  104. /// Status detail (NULL if absent). For some DIMSE return status codes,
  105. /// an additional dataset is sent which gives further information (i.e.
  106. /// in case of warnings or errors).
  107. DcmDataset *m_statusDetail;
  108. private:
  109. /** Private undefined copy constructor.
  110. * @param other The find response to copy from
  111. */
  112. QRResponse(const QRResponse &other);
  113. /** Private undefined assignment operator.
  114. * @param other The find response that should be assigned from
  115. */
  116. QRResponse &operator=(const QRResponse &other);
  117. };
  118. /// Base class representing for single C-GET or C-MOVE response
  119. class RetrieveResponse : public QRResponse
  120. {
  121. public:
  122. /** Standard constructor
  123. */
  124. RetrieveResponse() :
  125. m_numberOfRemainingSubops(0),
  126. m_numberOfCompletedSubops(0),
  127. m_numberOfFailedSubops(0),
  128. m_numberOfWarningSubops(0) {}
  129. /** Destructor, cleans up internal memory
  130. */
  131. virtual ~RetrieveResponse() {}
  132. /** Prints response to INFO log level.
  133. */
  134. void print();
  135. /// Number of remaining sub operations (in Q/R: C-STORE calls).
  136. /// For Q/R MOVE and GET, for status of pending this field shall be filled.
  137. /// For others, the field may be filled.
  138. Uint16 m_numberOfRemainingSubops;
  139. /// Number of successfully completed sub operations (in Q/R: C-STORE calls).
  140. /// For Q/R MOVE and GET, for status of pending this field shall be filled.
  141. /// For others, the field may be filled.
  142. Uint16 m_numberOfCompletedSubops;
  143. /// Number of failed sub operations (in Q/R: C-STORE calls).
  144. /// For Q/R MOVE and GET, for status of pending this field shall be filled.
  145. /// For others, the field may be filled.
  146. Uint16 m_numberOfFailedSubops;
  147. /// Number generated warnings generated by sub operations (in Q/R: C-STORE calls).
  148. /// For Q/R MOVE and GET, for status of pending this field shall be filled.
  149. /// For others, the field may be filled.
  150. Uint16 m_numberOfWarningSubops;
  151. private:
  152. /** Private undefined copy constructor
  153. * @param other Response to copy from
  154. */
  155. RetrieveResponse(const RetrieveResponse &other);
  156. /** Private undefined assignment operator
  157. * @param other Response that should be assigned from
  158. */
  159. RetrieveResponse &operator=(const RetrieveResponse &other);
  160. };
  161. /** Base class for implementing DICOM Service Class User functionality. The class offers
  162. * support for negotiating associations and sending and receiving arbitrary DIMSE messages
  163. * on that connection. DcmSCU has built-in C-ECHO support so derived classes do not have to
  164. * implement that capability on their own.
  165. * @warning This class is EXPERIMENTAL. Be careful to use it in production environment.
  166. */
  167. class DcmSCU
  168. {
  169. public:
  170. /** Constructor, just initializes internal class members
  171. */
  172. DcmSCU();
  173. /** Virtual destructor
  174. */
  175. virtual ~DcmSCU();
  176. /** Add presentation context to be used for association negotiation
  177. * @param abstractSyntax [in] Abstract syntax name in UID format
  178. * @param xferSyntaxes [in] List of transfer syntaxes to be added for the given abstract
  179. * syntax
  180. * @param role [in] The role to be negotiated
  181. * @return EC_Normal if adding was successful, otherwise error code
  182. */
  183. OFCondition addPresentationContext(const OFString &abstractSyntax,
  184. const OFList<OFString> &xferSyntaxes,
  185. const T_ASC_SC_ROLE role = ASC_SC_ROLE_DEFAULT);
  186. /** Initialize network, i.e.\ prepare for association negotiation. If the SCU is already
  187. * connected, the call will not be successful and the old connection keeps open.
  188. * @return EC_Normal if initialization was successful, otherwise error code.
  189. * NET_EC_AlreadyConnected if SCU is already connected.
  190. */
  191. virtual OFCondition initNetwork();
  192. /** Negotiate association by using presentation contexts and parameters as defined by
  193. * earlier function calls. If negotiation fails, there is no need to close the association
  194. * or to do anything else with this class.
  195. * @return EC_Normal if negotiation was successful, otherwise error code.
  196. * NET_EC_AlreadyConnected if SCU is already connected.
  197. */
  198. virtual OFCondition negotiateAssociation();
  199. /** After negotiation association, this call returns the first usable presentation context
  200. * given the desired abstract syntax and transfer syntax
  201. * @param abstractSyntax [in] The abstract syntax (UID) to look for
  202. * @param transferSyntax [in] The transfer syntax (UID) to look for. If empty, the transfer
  203. * syntax is not checked.
  204. * @return Adequate Presentation context ID that can be used. 0 if none found.
  205. */
  206. T_ASC_PresentationContextID findPresentationContextID(const OFString &abstractSyntax,
  207. const OFString &transferSyntax);
  208. /** After a successful association negotiation, this function is called to return the
  209. * presentation context ID that best matches the desired abstract syntax and transfer
  210. * syntax (TS). The function tries to do the following:
  211. * - If possible finds a presentation context with matching TS
  212. * - Else then tries to find an explicit VR uncompressed TS presentation context
  213. * - Else then tries to find an implicit VR uncompressed TS presentation context
  214. * - Else finally accepts each matching presentation ctx independent of TS.
  215. * @param abstractSyntax [in] The abstract syntax (UID) to look for
  216. * @param transferSyntax [in] The transfer syntax (UID) to look for. If empty, the transfer
  217. * syntax is not checked.
  218. * @return Adequate Presentation context ID that can be used. 0 if no appropriate
  219. * presentation context could be found at all.
  220. */
  221. T_ASC_PresentationContextID findAnyPresentationContextID(const OFString &abstractSyntax,
  222. const OFString &transferSyntax);
  223. /** This function sends a C-ECHO command via network to another DICOM application
  224. * @param presID [in] Presentation context ID to use. A value of 0 lets SCP class tries
  225. * to choose one on its own.
  226. * @return EC_Normal if echo was successful, an error code otherwise
  227. *
  228. */
  229. virtual OFCondition sendECHORequest(const T_ASC_PresentationContextID presID);
  230. /** This function sends a C-STORE request on the currently opened association and receives
  231. * the corresponding response then. If required and supported, the dataset of the SOP
  232. * instance can be converted automatically to the network transfer syntax that was
  233. * negotiated (and is specified by the parameter 'presID'). However, this feature is
  234. * disabled by default. See setDatasetConversionMode() on how to enable it.
  235. * @param presID [in] Contains in the end the ID of the presentation context which
  236. * was specified in the DIMSE command. If 0 is given, the
  237. * function tries to find an approriate presentation context
  238. * itself (based on SOP class and original transfer syntax of
  239. * the 'dicomFile' or 'dataset').
  240. * @param dicomFile [in] The filename of the DICOM file to be sent. Alternatively, a
  241. * dataset can be given in the next parameter. If both are given
  242. * the dataset from the file name is used.
  243. * @param dataset [in] The dataset to be sent. Alternatively, a filename can be
  244. * specified in the previous parameter. If both are given the
  245. * dataset from the filename is used.
  246. * @param rspStatusCode [out] The response status code received. 0 means success, others
  247. * can be found in the DICOM standard.
  248. * @return EC_Normal if request could be issued and response was received successfully,
  249. * error code otherwise. That means that if the receiver sends a response denoting
  250. * failure of the storage request, EC_Normal will be returned.
  251. */
  252. virtual OFCondition sendSTORERequest(const T_ASC_PresentationContextID presID,
  253. const OFString &dicomFile,
  254. DcmDataset *dataset,
  255. Uint16 &rspStatusCode);
  256. /** Sends a C-MOVE Request on given presentation context and receives list of responses.
  257. * The function receives the first response and then calls the function handleMOVEResponse()
  258. * which gets the relevant presentation context together with the response dataset and
  259. * status information. Then it waits again for the next response, if there are more to
  260. * come (i.e. response status is PENDING). In the end, after receiving all responses, the
  261. * full list of responses is returned to the caller. If he is not interested, he just sets
  262. * responses=NULL when calling the function.
  263. * This function can be overwritten by actual SCU implementations but just should work fine
  264. * for most people.
  265. * @param presID [in] The presentation context ID that should be used.
  266. * Must be an odd number.
  267. * @param moveDestinationAETitle [in] The move destination's AE title, i.e.\ the one that
  268. * is used for connection to the storage server.
  269. * @param dataset [in] The dataset containing the information about the
  270. * object(s) to be retrieved.
  271. * @param responses [out] The incoming C-MOVE responses for this request.
  272. * The caller is responsible for providing a non-NULL
  273. * pointer for this case. After receiving the results,
  274. * the caller is responsible for freeing the memory of
  275. * this variable. If NULL is specified, the responses
  276. * will not bereturned to the caller.
  277. * @return EC_Normal if everything went fine, i.e.\ if request could be send and responses
  278. * (with whatever status) could be received.
  279. */
  280. virtual OFCondition sendMOVERequest(const T_ASC_PresentationContextID presID,
  281. const OFString &moveDestinationAETitle,
  282. DcmDataset *dataset,
  283. OFList<RetrieveResponse*> *responses);
  284. /** This is the standard handler for C-MOVE message responses: It just adds up all responses
  285. * it receives and prints a DEBUG message. Therefore, it is called for each response
  286. * received in sendMOVERequest(). The idea is of course to overwrite this function in a
  287. * derived, actual SCU implementation if required. Thus, after each response, the caller of
  288. * sendMOVERequest() can decide on its own whether he wants to cancel the C-MOVE session,
  289. * terminate the association, do something useful or whatever. Thus this function is a more
  290. * object-oriented kind of callback.
  291. * @param presID [in] The presentation context ID where the response was
  292. * received on.
  293. * @param response [in] The C-MOVE response received.
  294. * @param waitForNextResponse [out] Denotes whether SCU should try to receive another
  295. * response. If set to OFTrue, then sendMOVERequest() will
  296. * continue waiting for responses. The current
  297. * implementation does that for all responses do not have
  298. * status Failed, Warning, Success or unknown. If set to
  299. * OFFalse, sendMOVERequest() will return control to the
  300. * caller.
  301. * @return EC_Normal, if response could be handled. Error code otherwise.
  302. * The current implementation always returns EC_Normal.
  303. */
  304. virtual OFCondition handleMOVEResponse(const T_ASC_PresentationContextID presID,
  305. RetrieveResponse *response,
  306. OFBool &waitForNextResponse);
  307. /** Sends a C-GET Request on given presentation context and receives list of responses. It
  308. * then switches control to the function handleCGETSession().
  309. * The full list of responses is returned to the caller. If he is not interested, he can
  310. * set responses=NULL when calling the function.
  311. * This function can be overwritten by actual SCU implementations but just should work fine
  312. * for most people.
  313. * @param presID [in] The presentation context ID that should be used. Must be an odd
  314. * number.
  315. * @param dataset [in] The dataset containing the information about the
  316. * object(s) to be retrieved
  317. * @param responses [out] The incoming C-GET responses for this request. If the caller
  318. * specifies NULL, no responses will be returned; otherwise there
  319. * should be at least one final C-GET response (mandatory). C-GET
  320. * responses after each DICOM object received are optional and may
  321. * have been ommitted by the server.
  322. * @return EC_Normal if everything went fine, i.e.\ if request could be sent and expected
  323. * responses (with whatever status) could be received.
  324. */
  325. virtual OFCondition sendCGETRequest(const T_ASC_PresentationContextID presID,
  326. DcmDataset *dataset,
  327. OFList<RetrieveResponse*> *responses);
  328. /** Does the logic for switching between C-GET Response and C-STORE Requests. Sends a C-GET
  329. * Request on given presentation context and receives list of responses. Ihe full list of
  330. * responses is returned to the caller. If he is not interested, he can set responses=NULL
  331. * when calling the function. After sending a C-GET Request, there might be two different
  332. * responses coming in: C-GET-RSP (optional after each received object and mandatory after
  333. * the last object) or a mandatory C-STORE for each incoming object that is received due to
  334. * the request. This function therefore either calls handleCGETResponse() or
  335. * handleSTORERequest() in order to deal with the incoming message. All other messages lead
  336. * to an error within this handler.
  337. * This function can be overwritten by actual SCU implementations but just should work fine
  338. * for most people.
  339. * @param presID [in] The presentation context ID that should be used. Must be an odd
  340. * number.
  341. * @param dataset [in] The dataset containing the information about the object(s) to be
  342. * retrieved
  343. * @param responses [out] The incoming C-GET responses for this request. If the caller
  344. * specifies NULL, no responses will be returned; otherwise there
  345. * should be at least one final C-GET response (mandatory). C-GET
  346. * responses after each DICOM object received are optional and may
  347. * have been ommitted by the server.
  348. * @return EC_Normal if everything went fine, i.e.\ if request could be send
  349. * and expected responses (with whatever status) could be received.
  350. */
  351. virtual OFCondition handleCGETSession(const T_ASC_PresentationContextID presID,
  352. DcmDataset *dataset,
  353. OFList<RetrieveResponse*> *responses);
  354. /** Function handling a single C-GET Response. This standard handler reads the status of the
  355. * response and decides whether to receive any further messages related to the original
  356. * C-GET Request or whether the last response was received or an error occured.
  357. * @param presID [in] The presentation context the C-GET Response was
  358. * received on.
  359. * @param response [in] The response received
  360. * @param continueCGETSession [out] Defines whether it is decided to wait for further C-GET
  361. * Responses/C-STORE Requests within this C-GET session
  362. * @return If no errors occur (dataset response NULL, SCU not connected), this method will
  363. * return EC_Normal, otherwise error code.
  364. */
  365. virtual OFCondition handleCGETResponse(const T_ASC_PresentationContextID presID,
  366. RetrieveResponse* response,
  367. OFBool &continueCGETSession);
  368. /** Function handling a single C-STORE Request. If storage mode is set to disk (default),
  369. * this function is called and the incoming object stored to disk.
  370. * @param presID [in] The presentation context the C-STORE Response was
  371. * received on.
  372. * @param incomingObject [in] The dataset (the object) received
  373. * @param continueCGETSession [out] Defines whether it is decided to wait for further
  374. * C-GET Responses/C-STORE requests within this C-GET
  375. * session.
  376. * @param cStoreReturnStatus [out] Denotes the desired C-STORE return status.
  377. * @return If errors occur (incomingObject NULL or SCU not connected or file could not be
  378. * stored), this method will return an error code otherwise EC_Normal.
  379. */
  380. virtual OFCondition handleSTORERequest(const T_ASC_PresentationContextID presID,
  381. DcmDataset *incomingObject,
  382. OFBool &continueCGETSession,
  383. Uint16 &cStoreReturnStatus);
  384. /** Function handling a single C-STORE Request. If storage mode is set to bit preserving,
  385. * this function is called and the incoming object stored directly to disk, i.e. not stored
  386. * fully in memory.
  387. * @param presID [in] The presentation context the C-STORE Response was received on.
  388. * @param filename [in] The filename to store to
  389. * @param request [in] The incoming C-STORE request command set
  390. * @return If errors occur (incomingObject NULL or SCU not connected filename not
  391. * specified), this method will return an error code otherwise EC_Normal.
  392. */
  393. virtual OFCondition handleSTORERequestFile(T_ASC_PresentationContextID *presID,
  394. const OFString &filename,
  395. T_DIMSE_C_StoreRQ *request);
  396. /** Sends a C-FIND Request on given presentation context and receives list of responses.
  397. * The function receives the first response and then calls the function handleFINDResponse
  398. * which gets the relevant presentation context together with the response dataset and
  399. * status information. Then it waits again for the next response, if there are more to
  400. * come (i.e. response status is PENDING). In the end, after receiving all responses, the
  401. * full list of responses is returned to the caller. If he is not interested, he just sets
  402. * responses=NULL when calling the function.
  403. * This function can be overwritten by actual SCU implementations but just should work fine
  404. * for most people.
  405. * @param presID [in] The presentation context ID that should be used. Must be an odd
  406. * number.
  407. * @param queryKeys [in] The dataset containing the query keys to be searched for on the
  408. * server (SCP).
  409. * @param responses [out] The incoming C-FIND responses for this request. The caller is
  410. * responsible for providing a non-NULL pointer for this case.
  411. * After receiving the results, the caller is responsible for
  412. * freeing the memory of this variable. If NULL is specified, the
  413. * responses will be not returned to the caller.
  414. * @return EC_Normal if everything went fine, i.e.\ if request could be send and responses
  415. * (with whatever status) could be received.
  416. */
  417. virtual OFCondition sendFINDRequest(const T_ASC_PresentationContextID presID,
  418. DcmDataset *queryKeys,
  419. OFList<QRResponse*> *responses);
  420. /** This is the standard handler for C-FIND message responses: It just adds up all responses
  421. * it receives and prints a DEBUG message. Therefore, it is called for each response
  422. * received in sendFINDRequest(). The idea is of course to overwrite this function in a
  423. * derived, actual SCU implementation if required. Thus, after each response, the caller of
  424. * sendFINDRequest() can decide on its own whether he wants to cancel the C-FIND session,
  425. * terminate the association, do something useful or whatever. That way this is a more
  426. * object-oriented kind of callback.
  427. * @param presID [in] The presentation context ID where the response was
  428. * received on.
  429. * @param response [in] The C-FIND response received.
  430. * @param waitForNextResponse [out] Denotes whether SCU should try to receive another
  431. * response. If set to OFTrue, then sendFINDRequest()
  432. * will continue waiting for responses. The current
  433. * implementation does that for all responses do not have
  434. * status SUCESSS. If set to OFFalse, sendFINDRequest()
  435. * will return control to the caller.
  436. * @return EC_Normal, if response could be handled. Error code otherwise.
  437. * The current implementation always returns EC_Normal.
  438. */
  439. virtual OFCondition handleFINDResponse(const T_ASC_PresentationContextID presID,
  440. QRResponse *response,
  441. OFBool &waitForNextResponse);
  442. /** Send C-CANCEL and, therefore, ends the C-FIND -GET or -MOVE session, i.e.\ no further
  443. * responses will be handled. A call to this function only makes sense if an association
  444. * is open, the given presentation context represents a valid C-FIND/GET/MOVE-enabled SOP
  445. * class and usually only, if the last command send on that presentation context was a
  446. * C-FIND message.
  447. * @param presID [in] The presentation context ID where the C-CANCEL should be sent on.
  448. * @return The current implementation always returns EC_Normal.
  449. */
  450. virtual OFCondition sendCANCELRequest(const T_ASC_PresentationContextID presID);
  451. /** This function sends a N-ACTION request on the currently opened association and receives
  452. * the corresponding response then
  453. * @param presID [in] The ID of the presentation context to be used for sending
  454. * the request message. Should not be 0.
  455. * @param sopInstanceUID [in] The requested SOP Instance UID
  456. * @param actionTypeID [in] The action type ID to be used
  457. * @param reqDataset [in] The dataset to be sent
  458. * @param rspStatusCode [out] The response status code received. 0 means success,
  459. * others can be found in the DICOM standard.
  460. * @return EC_Normal if request could be issued and response was received successfully,
  461. * an error code otherwise
  462. */
  463. virtual OFCondition sendACTIONRequest(const T_ASC_PresentationContextID presID,
  464. const OFString &sopInstanceUID,
  465. const Uint16 actionTypeID,
  466. DcmDataset *reqDataset,
  467. Uint16 &rspStatusCode);
  468. /** This function sends N-EVENT-REPORT request and receives the corresponding response
  469. * @param presID [in] The ID of the presentation context to be used for sending
  470. * the request message. Should not be 0.
  471. * @param sopInstanceUID [in] The requested SOP Instance UID
  472. * @param eventTypeID [in] The event type ID to be used
  473. * @param reqDataset [in] The request dataset to be sent
  474. * @param rspStatusCode [out] The response status code received. 0 means success,
  475. * others can be found in the DICOM standard.
  476. * @return EC_Normal if request could be issued and response was received successfully,
  477. * an error code otherwise
  478. */
  479. virtual OFCondition sendEVENTREPORTRequest(const T_ASC_PresentationContextID presID,
  480. const OFString &sopInstanceUID,
  481. const Uint16 eventTypeID,
  482. DcmDataset *reqDataset,
  483. Uint16 &rspStatusCode);
  484. /** Receives N-EVENT-REPORT request on the currently opened association and sends a
  485. * corresponding response. Calls checkEVENTREPORTRequest() in order to determine the
  486. * DIMSE status code to be used for the N-EVENT-REPORT response.
  487. * @param reqDataset [out] Pointer to the dataset received
  488. * @param eventTypeID [out] Event Type ID from the command set received
  489. * @param timeout [in] Optional timeout in seconds for receiving data. This value
  490. * (if not 0) overwrites the standard DIMSE timeout and also
  491. * enables the non-blocking mode for receiving the request.
  492. * @return status, EC_Normal if successful, an error code otherwise
  493. */
  494. virtual OFCondition handleEVENTREPORTRequest(DcmDataset *&reqDataset,
  495. Uint16 &eventTypeID,
  496. const int timeout = 0);
  497. /** Closes the association created by this SCU. Also resets the current association.
  498. * @param closeType [in] Define whether to release or abort the association
  499. */
  500. virtual void closeAssociation(const DcmCloseAssociationType closeType);
  501. /* Set methods */
  502. /** Set maximum PDU length (to be received by SCU)
  503. * @param maxRecPDU [in] The maximum PDU size to use in bytes
  504. */
  505. void setMaxReceivePDULength(const unsigned long maxRecPDU);
  506. /** Set whether to send in DIMSE blocking or non-blocking mode
  507. * @param blockingMode [in] Either blocking or non-blocking mode
  508. */
  509. void setDIMSEBlockingMode(const T_DIMSE_BlockingMode blockingMode);
  510. /** Set SCU's AETitle to be used in association negotiation
  511. * @param myAETtitle [in] The SCU's AETitle to be used
  512. */
  513. void setAETitle(const OFString &myAETtitle);
  514. /** Set SCP's host (hostname or IP address) to talk to in association negotiation
  515. * @param peerHostName [in] The SCP's hostname or IP address to be used
  516. */
  517. void setPeerHostName(const OFString &peerHostName);
  518. /** Set SCP's AETitle to talk to in association negotiation
  519. * @param peerAETitle [in] The SCP's AETitle to be used
  520. */
  521. void setPeerAETitle(const OFString &peerAETitle);
  522. /** Set SCP's port number to connect to for association negotiation
  523. * @param peerPort [in] The SCP's port number
  524. */
  525. void setPeerPort(const Uint16 peerPort);
  526. /** Set timeout for receiving DIMSE messages
  527. * @param dimseTimeout [in] DIMSE Timeout in seconds for receiving data. If the blocking
  528. * mode is DIMSE_NONBLOCKING and we are trying to read data from
  529. * the incoming socket stream and no data has been received.
  530. */
  531. void setDIMSETimeout(const Uint32 dimseTimeout);
  532. /** Set timeout for receiving ACSE messages
  533. * @param acseTimeout [in] ACSE Timeout in seconds used by timer for message timeouts
  534. * during association negotiation
  535. */
  536. void setACSETimeout(const Uint32 acseTimeout);
  537. /** Set an association configuration file and profile to be used
  538. * @param filename [in] File name of the association configuration file
  539. * @param profile [in] Profile inside the association negotiation file
  540. */
  541. void setAssocConfigFileAndProfile(const OFString &filename,
  542. const OFString &profile);
  543. /** Set the directory that should be used by the standard C-GET handler to store objects
  544. * that come in with the corresponding C-STORE rqeuests
  545. * @param storeDir [in] The directory to store to. It is checked in handleSTORERequest()
  546. * whether the directory is writeable and readable. Per default, the
  547. * received objects are stored in the current working directory.
  548. */
  549. void setStorageDir(const OFString &storeDir);
  550. /** Set the storage mode to be used. Default is DCMSCU_STORAGE_DISK.
  551. * @param storageMode The storage mode to be used.
  552. */
  553. void setStorageMode(const DcmStorageMode storageMode);
  554. /** Set whether to show presentation contexts in verbose or debug mode
  555. * @param mode [in] Show presentation contexts in verbose mode if OFTrue. By default, the
  556. * presentation contexts are shown in debug mode.
  557. */
  558. void setVerbosePCMode(const OFBool mode);
  559. /** Set the mode that specifies whether the transfer syntax of the dataset can be changed
  560. * for network transmission. This mainly covers the compression/decompression of datasets,
  561. * which is disabled by default.
  562. * @param mode [in] Allow dataset conversion if OFTrue
  563. */
  564. void setDatasetConversionMode(const OFBool mode);
  565. /** Set the mode that specifies whether the progress of sending and receiving DIMSE
  566. * messages is notified by calling notifySENDProgress() and notifyRECEIVEProgress(),
  567. * respectively. The progress notification is enabled by default.
  568. * @param mode [in] Disable progress notification if OFFalse
  569. */
  570. void setProgressNotificationMode(const OFBool mode);
  571. /* Get methods */
  572. /** Get current connection status
  573. * @return OFTrue if SCU is currently connected, OFFalse otherwise
  574. */
  575. OFBool isConnected() const;
  576. /** Returns maximum PDU length configured to be received by SCU
  577. * @return Maximum PDU length in bytes
  578. */
  579. Uint32 getMaxReceivePDULength() const;
  580. /** Returns whether DIMSE messaging is configured to be blocking or unblocking
  581. * @return The blocking mode configured
  582. */
  583. T_DIMSE_BlockingMode getDIMSEBlockingMode() const;
  584. /** Returns the SCU's own configured AETitle
  585. * @return The AETitle configured for this SCU
  586. */
  587. const OFString &getAETitle() const;
  588. /** Returns the SCP's (peer's) host name configured
  589. * @return The hostname (or IP) configured to be talked to
  590. */
  591. const OFString &getPeerHostName() const;
  592. /** Returns the SCP's (peer's) AETitle configured
  593. * @return The AETitle configured to be talked to
  594. */
  595. const OFString &getPeerAETitle() const;
  596. /** Returns the SCP's (peer's) TCP/IP port configured
  597. * @return The port configured to talked to
  598. */
  599. Uint16 getPeerPort() const;
  600. /** Returns the DIMSE timeout configured defining how long SCU will wait for DIMSE responses
  601. * @return The DIMSE timeout configured
  602. */
  603. Uint32 getDIMSETimeout() const;
  604. /** Returns the timeout configured defining how long SCU will wait for messages during ACSE
  605. * messaging (association negotiation)
  606. * @return The ACSE timeout configured
  607. */
  608. Uint32 getACSETimeout() const;
  609. /** Returns the storage directory used for storing objects received with C-STORE requests
  610. * in the context of C-GET sessions. Default is empty string which refers to the current
  611. * working directory.
  612. * @return The storage directory
  613. */
  614. OFString getStorageDir() const;
  615. /** Returns the storage mode enabled
  616. * @return The storage mode enabled
  617. */
  618. DcmStorageMode getStorageMode() const;
  619. /** Returns the verbose presentation context mode configured specifying whether details
  620. * on the presentation contexts (negotiated during association setup) should be shown in
  621. * verbose or debug mode. The latter is the default.
  622. * @return The current verbose presentation context mode. Show details on the
  623. * presentation contexts on INFO log level (verbose) if OFTrue and on DEBUG
  624. * level if OFFalse.
  625. */
  626. OFBool getVerbosePCMode() const;
  627. /** Returns the mode that specifies whether the transfer syntax of the dataset can be
  628. * changed for network transmission. This mainly covers the compression/decompression
  629. * of datasets, which is disabled by default.
  630. * @return The current dataset conversion mode, enabled if OFTrue
  631. */
  632. OFBool getDatasetConversionMode() const;
  633. /** Returns the mode that specifies whether the progress of sending and receiving DIMSE
  634. * messages is notified by calling notifySENDProgress() and notifyRECEIVEProgress(),
  635. * respectively. The progress notification is enabled by default.
  636. * @return The current progress notification mode, enabled if OFTrue
  637. */
  638. OFBool getProgressNotificationMode() const;
  639. /** Returns whether SCU is configured to create a TLS connection with the SCP
  640. * @return OFFalse for this class but may be overridden by derived classes
  641. */
  642. OFBool getTLSEnabled() const;
  643. /** Deletes internal networking structures from memory */
  644. void freeNetwork();
  645. protected:
  646. /** Sends a DIMSE command and possibly also a dataset from a data object via network to
  647. * another DICOM application
  648. * @param presID [in] Presentation context ID to be used for message
  649. * @param msg [in] Structure that represents a certain DIMSE command which
  650. * shall be sent
  651. * @param dataObject [in] The instance data which shall be sent to the other DICOM
  652. * application; NULL, if there is none
  653. * @param commandSet [out] If this parameter is not NULL it will return a copy of the
  654. * DIMSE command which is sent to the other DICOM application
  655. * @return EC_Normal if sending request was successful, an error code otherwise
  656. */
  657. OFCondition sendDIMSEMessage(const T_ASC_PresentationContextID presID,
  658. T_DIMSE_Message *msg,
  659. DcmDataset *dataObject,
  660. DcmDataset **commandSet = NULL);
  661. /** Returns SOP Class UID, SOP Instance UID and original transfer syntax for a given dataset.
  662. * If the dataset is NULL, all returned values will be undefined (i.e. empty or EXS_Unknown).
  663. * @param dataset [in] The dataset to read from
  664. * @param sopClassUID [out] The value of attribute SOP Class UID if present
  665. * @param sopInstanceUID [out] The value of attribute SOP Instance UID if present
  666. * @param transferSyntax [out] The value of transfer syntax that originally was read from
  667. * disk. Will be unknown if the dataset was created in memory.
  668. * @return EC_Normal if all information could be retrieved and is valid, an error code
  669. * otherwise
  670. */
  671. OFCondition getDatasetInfo(DcmDataset *dataset,
  672. OFString &sopClassUID,
  673. OFString &sopInstanceUID,
  674. E_TransferSyntax &transferSyntax);
  675. /** Tells DcmSCU to use a secure TLS connection described by the given TLS layer
  676. * @param tlayer [in] The TLS transport layer including all TLS parameters
  677. * @return EC_Normal if given transport layer is ok, an error code otherwise
  678. */
  679. OFCondition useSecureConnection(DcmTransportLayer *tlayer);
  680. /** Receive DIMSE command (excluding dataset!) over the currently open association
  681. * @param presID [out] Contains in the end the ID of the presentation context
  682. * which was specified in the DIMSE command received
  683. * @param msg [out] The message received
  684. * @param statusDetail [out] If a non-NULL value is passed this variable will in the end
  685. * contain detailed information with regard to the status
  686. * information which is captured in the status element
  687. * (0000,0900). Note that the value for element (0000,0900) is
  688. * not contained in this return value but in internal msg. For
  689. * details on the structure of this object, see DICOM standard
  690. * part 7, annex C).
  691. * @param commandSet [out] If this parameter is not NULL, it will return a copy of the
  692. * DIMSE command which was received from the other DICOM
  693. * application. The caller is responsible to de-allocate the
  694. * returned object!
  695. * @param timeout [in] If this parameter is not 0, it specifies the timeout (in
  696. * seconds) to be used for receiving the DIMSE command.
  697. * Otherwise, the default timeout value is used (see
  698. * setDIMSETimeout()).
  699. * @return EC_Normal if command could be received successfully, an error code otherwise
  700. */
  701. OFCondition receiveDIMSECommand(T_ASC_PresentationContextID *presID,
  702. T_DIMSE_Message *msg,
  703. DcmDataset **statusDetail,
  704. DcmDataset **commandSet = NULL,
  705. const Uint32 timeout = 0);
  706. /** Receives one dataset (of instance data) via network from another DICOM application
  707. * @param presID [out] Contains in the end the ID of the presentation context which
  708. * was used in the PDVs that were received on the network. If the
  709. * PDVs show different presentation context IDs, this function
  710. * will return an error.
  711. * @param dataObject [out] Contains in the end the information which was received over
  712. * the network
  713. * @return EC_Normal if dataset could be received successfully, an error code otherwise
  714. */
  715. OFCondition receiveDIMSEDataset(T_ASC_PresentationContextID *presID,
  716. DcmDataset **dataObject);
  717. /** clear list of presentation contexts. In addition, any currently selected association
  718. * configuration file is disabled.
  719. */
  720. void clearPresentationContexts();
  721. /** After negotiation association, this call returns the presentation context belonging
  722. * to the given presentation context ID
  723. * @param presID [in] The presentation context ID to look for
  724. * @param abstractSyntax [out] The abstract syntax (UID) for that ID.
  725. * Empty, if such a presentation context does not exist.
  726. * @param transferSyntax [out] The transfer syntax (UID) for that ID.
  727. * Empty, if such a presentation context does not exist.
  728. */
  729. void findPresentationContext(const T_ASC_PresentationContextID presID,
  730. OFString &abstractSyntax,
  731. OFString &transferSyntax);
  732. /* ***********************************************************************
  733. * Functions particularly interesting for overwriting in derived classes
  734. * *********************************************************************** */
  735. /** This function is called if an object was received due to a C-GET request and can be
  736. * overwritten by a user in order to be informed about such an event. The default
  737. * implementation just prints a DEBUG message. Note that this function is not called if
  738. * the SCU is in storage mode DCMSCU_STORAGE_IGNORE.
  739. * @param filename [in] The filename written
  740. * @param sopClassUID [in] The SOP Class UID of the object written
  741. * @param sopInstanceUID [in] The SOP Instance UID of the object written
  742. */
  743. virtual void notifyInstanceStored(const OFString &filename,
  744. const OFString &sopClassUID,
  745. const OFString &sopInstanceUID) const;
  746. /** This function is called while sending DIMSE messages, i.e.\ on each PDV of a dataset.
  747. * The default implementation just prints a TRACE message on the number of bytes sent so
  748. * far. By overwriting this method, the progress of the send process can be shown to the
  749. * user in a more appropriate way. The progress notification can also be disabled
  750. * completely by calling setProgressNotificationMode().
  751. * @param byteCount [in] Number of bytes sent so far
  752. */
  753. virtual void notifySENDProgress(const unsigned long byteCount);
  754. /** This function is called while receiving DIMSE messages, i.e.\ on each PDV of a dataset.
  755. * The default implementation just prints a TRACE message on the number of bytes received
  756. * so far. By overwriting this method, the progress of the receive process can be shown to
  757. * the user in a more appropriate way. The progress notification can also be disabled
  758. * completely by calling setProgressNotificationMode().
  759. * @param byteCount [in] Number of bytes received so far
  760. */
  761. virtual void notifyRECEIVEProgress(const unsigned long byteCount);
  762. /** Check given N-EVENT-REPORT request and dataset for validity. This method is called by
  763. * handleEVENTREPORTRequest() before sending the response in order to determine the
  764. * DIMSE status code to be used for the response message.
  765. * @param request [in] The N-EVENT-REPORT request message data structure
  766. * @param reqDataset [in] The N-EVENT-REPORT request dataset received. Might be NULL.
  767. * @return DIMSE status code to be used for the N-EVENT-REPORT response.
  768. * Always returns STATUS_Success (0). Derived classes should, therefore,
  769. * overwrite this method and return a more appropriate value based on the
  770. * result of the checks performed.
  771. */
  772. virtual Uint16 checkEVENTREPORTRequest(T_DIMSE_N_EventReportRQ &request,
  773. DcmDataset *reqDataset);
  774. /** Sends back a C-STORE response on the given presentation context, with the designated
  775. * status, fitting the corresponding C-STORE request.
  776. * @param presID [in] The presentation context ID to be used.
  777. * @param status [in] The storage DIMSE status to be used.
  778. * @param request [in] The C-STORE request that should be responded to.
  779. * @result EC_Normal if the response could be sent, error otherwise.
  780. */
  781. virtual OFCondition sendSTOREResponse(T_ASC_PresentationContextID presID,
  782. Uint16 status,
  783. const T_DIMSE_C_StoreRQ &request);
  784. /** Helper function that generates a storage filename by extracting SOP Class and SOP
  785. * Instance UID from a dataset and combining that with the configured storage directory.
  786. * The SOP class is used to create an initial two letter abbreviation for the
  787. * corresponding modality, e.g. CT. An example for a storage filename created by this
  788. * function is /storage_dir/CT.1.2.3.4.5 for a CT with SOP Instance UID 1.2.3.4.
  789. * This function might be overwritten to change the filename behaviour completely. This
  790. * function is only called if the SCU is in DCMSCU_STORAGE_DISK mode.
  791. * @param dataset [in] The dataset that should be stored to disk
  792. * @result Non-empty string if successful, otherwise empty string.
  793. */
  794. virtual OFString createStorageFilename(DcmDataset *dataset);
  795. /** Receives a DICOM dataset on a given presentation context ID but does not store it in
  796. * memory or disk, thus ignoring it.
  797. * @param presID [in] The presentation context to be used
  798. * @param request [in] The corresponding C-STORE request
  799. * @return EC_Normal if ignoring worked, error code otherwise.
  800. */
  801. virtual OFCondition ignoreSTORERequest(T_ASC_PresentationContextID presID,
  802. const T_DIMSE_C_StoreRQ &request);
  803. /* Callback functions (static) */
  804. /** Callback function used for sending DIMSE messages.
  805. * @param callbackContext [in] The desired user callback data
  806. * @param byteCount [in] Progress bytes count
  807. */
  808. static void callbackSENDProgress(void *callbackContext,
  809. unsigned long byteCount);
  810. /** Callback function used for receiving DIMSE messages.
  811. * @param callbackContext [in] The desired user callback data
  812. * @param byteCount [in] Progress bytes count
  813. */
  814. static void callbackRECEIVEProgress(void *callbackContext,
  815. unsigned long byteCount);
  816. private:
  817. /** Private undefined copy-constructor. Shall never be called.
  818. * @param src Source object
  819. */
  820. DcmSCU(const DcmSCU &src);
  821. /** Private undefined operator=. Shall never be called.
  822. * @param src Source object
  823. * @return Reference to this
  824. */
  825. DcmSCU &operator=(const DcmSCU &src);
  826. /// Associaton of this SCU. This class only handles 1 association at a time.
  827. T_ASC_Association *m_assoc;
  828. /// The DICOM network the association is based on
  829. T_ASC_Network *m_net;
  830. /// Association parameters
  831. T_ASC_Parameters *m_params;
  832. /// Configuration file for presentation contexts (optional)
  833. OFString m_assocConfigFilename;
  834. /// Profile in configuration file that should be used (optional)
  835. OFString m_assocConfigProfile;
  836. /// Defines presentation context, consisting of one abstract syntax name
  837. /// and a list of transfer syntaxes for this abstract syntax
  838. struct DcmSCUPresContext {
  839. /** Default constructor
  840. */
  841. DcmSCUPresContext()
  842. : abstractSyntaxName()
  843. , transferSyntaxes()
  844. , roleSelect(ASC_SC_ROLE_DEFAULT)
  845. {
  846. }
  847. /// Abstract Syntax Name of Presentation Context
  848. OFString abstractSyntaxName;
  849. /// List of Transfer Syntaxes for Presentation Context
  850. OFList<OFString> transferSyntaxes;
  851. /// Role Selection
  852. T_ASC_SC_ROLE roleSelect;
  853. };
  854. /// List of presentation contexts that should be negotiated
  855. OFList<DcmSCUPresContext> m_presContexts;
  856. /// Configuration file containing association parameters
  857. OFString m_assocConfigFile;
  858. /// The last DIMSE successfully sent, unresponded DIMSE request
  859. T_DIMSE_Message *m_openDIMSERequest;
  860. /// Maximum PDU size
  861. Uint32 m_maxReceivePDULength;
  862. /// DIMSE blocking mode
  863. T_DIMSE_BlockingMode m_blockMode;
  864. /// AEtitle of this application
  865. OFString m_ourAETitle;
  866. /// Peer hostname
  867. OFString m_peer;
  868. /// AEtitle of remote application
  869. OFString m_peerAETitle;
  870. /// Port of remote application entity
  871. Uint16 m_peerPort;
  872. /// DIMSE timeout
  873. Uint32 m_dimseTimeout;
  874. /// ACSE timeout
  875. Uint32 m_acseTimeout;
  876. /// Storage directory for objects received with C-STORE due to a
  877. /// running C-GET session. Per default, the received objects
  878. /// are stored in the current working directory.
  879. OFString m_storageDir;
  880. /// Set whether bit preserving storage should be enabled, i.e.\ any objects
  881. /// retrieved via C-STORE should be written directly to disk without
  882. /// any data correction/re-computation (e.g.\ group length calculations,
  883. /// padding, etc.). This is especially interesting for retaining valid
  884. /// signatures, and also to receive huge files which cannot be fully received
  885. /// in memory. Default is OFFalse (no bit preserving) storage.
  886. DcmStorageMode m_storageMode;
  887. /// Verbose PC mode
  888. OFBool m_verbosePCMode;
  889. /// Dataset conversion mode
  890. OFBool m_datasetConversionMode;
  891. /// Progress notification mode
  892. OFBool m_progressNotificationMode;
  893. /** Returns next available message ID free to be used by SCU
  894. * @return Next free message ID
  895. */
  896. Uint16 nextMessageID();
  897. };
  898. #endif // SCU_H