1 /*
2 *
3 * Copyright (C) 1994-2020, OFFIS e.V.
4 * All rights reserved. See COPYRIGHT file for details.
5 *
6 * This software and supporting documentation were partly developed by
7 *
8 * OFFIS e.V.
9 * R&D Division Health
10 * Escherweg 2
11 * D-26121 Oldenburg, Germany
12 *
13 * For further copyrights, see the following paragraphs.
14 *
15 */
16
17 /*
18 ** Copyright (C) 1993/1994, OFFIS, Oldenburg University and CERIUM
19 **
20 ** This software and supporting documentation were
21 ** developed by
22 **
23 ** Institut OFFIS
24 ** Bereich Kommunikationssysteme
25 ** Westerstr. 10-12
26 ** 26121 Oldenburg, Germany
27 **
28 ** Fachbereich Informatik
29 ** Abteilung Prozessinformatik
30 ** Carl von Ossietzky Universitaet Oldenburg
31 ** Ammerlaender Heerstr. 114-118
32 ** 26111 Oldenburg, Germany
33 **
34 ** CERIUM
35 ** Laboratoire SIM
36 ** Faculte de Medecine
37 ** 2 Avenue du Pr. Leon Bernard
38 ** 35043 Rennes Cedex, France
39 **
40 ** for CEN/TC251/WG4 as a contribution to the Radiological
41 ** Society of North America (RSNA) 1993 Digital Imaging and
42 ** Communications in Medicine (DICOM) Demonstration.
43 **
44 ** THIS SOFTWARE IS MADE AVAILABLE, AS IS, AND NEITHER OFFIS,
45 ** OLDENBURG UNIVERSITY NOR CERIUM MAKE ANY WARRANTY REGARDING
46 ** THE SOFTWARE, ITS PERFORMANCE, ITS MERCHANTABILITY OR
47 ** FITNESS FOR ANY PARTICULAR USE, FREEDOM FROM ANY COMPUTER
48 ** DISEASES OR ITS CONFORMITY TO ANY SPECIFICATION. THE
49 ** ENTIRE RISK AS TO QUALITY AND PERFORMANCE OF THE SOFTWARE
50 ** IS WITH THE USER.
51 **
52 ** Copyright of the software and supporting documentation
53 ** is, unless otherwise stated, jointly owned by OFFIS,
54 ** Oldenburg University and CERIUM and free access is hereby
55 ** granted as a license to use this software, copy this
56 ** software and prepare derivative works based upon this
57 ** software. However, any distribution of this software
58 ** source code or supporting documentation or derivative
59 ** works (source code and supporting documentation) must
60 ** include the three paragraphs of this copyright notice.
61 **
62 */
63
64 /*
65 **
66 ** Author: Andrew Hewett Created: 03-06-93
67 **
68 ** Module: association
69 **
70 ** Purpose:
71 ** This file contains the routines which provide association management
72 ** for DICOM V.3 applications. It maintains structures which describe
73 ** active associations and provides access to association specific
74 ** information. Also provided are routines for performing association
75 ** negotiation (presentation contexts, abstract syntaxes, transfer
76 ** syntaxes, maximum PDU length, and other extended negotiation).
77 **
78 ** This package uses the facilities of the DICOM Upper Layer for
79 ** receiving/sending association requests/responses.
80 **
81 ** Each active association is represented by an T_ASC_Association
82 ** structure which contains all relevant information.
83 **
84 ** Module Prefix: ASC_
85 **
86 */
87
88 /*
89 ** Include Files
90 */
91
92 #include "dcmtk/config/osconfig.h" /* make sure OS specific configuration is included first */
93
94 #ifdef HAVE_WINDOWS_H
95 // on Windows, we need Winsock2 for network functions
96 #include <winsock2.h>
97 #endif
98
99 #include "dcmtk/dcmnet/assoc.h" /* always include the module header */
100 #include "dcmtk/dcmnet/diutil.h"
101
102 #define INCLUDE_CSTDLIB
103 #define INCLUDE_CSTDIO
104 #define INCLUDE_CSTRING
105 #define INCLUDE_CSTDARG
106 #define INCLUDE_CERRNO
107 #include "dcmtk/ofstd/ofstdinc.h"
108
109 #ifdef HAVE_SYS_TIME_H
110 #include <sys/time.h>
111 #endif
112 #ifdef HAVE_SYS_TYPES_H
113 #include <sys/types.h>
114 #endif
115 #ifdef HAVE_SYS_SELECT_H
116 #include <sys/select.h>
117 #endif
118 #ifdef DCMTK_HAVE_POLL
119 #include <poll.h>
120 #endif
121
122 #include "dcmtk/dcmnet/dicom.h"
123 #include "dcmtk/dcmnet/cond.h"
124 #include "dcmtk/dcmdata/dcuid.h"
125 #include "dcmtk/ofstd/ofconsol.h"
126 #include "dcmtk/ofstd/ofstd.h"
127 #include "dcmtk/dcmnet/dcmtrans.h"
128
129 /*
130 ** Constant Definitions
131 */
132
133 #define ASC_IMPLEMENTATION_CLASS_UID_ITEM_TYPE 0x52
134 #define ASC_ASYNCHRONOUS_OPERATIONS_WINDOW_ITEM_TYPE 0x53
135 #define ASC_SCU_SCP_ROLE_SELECTION_ITEM_TYPE 0x54
136 #define ASC_IMPLEMENTATION_VERSION_NAME_ITEM_TYPE 0x55
137 #define ASC_SOP_CLASS_EXTENDED_NEGOTIATION_ITEM_TYPE 0x56
138
139 /*
140 ** Type Definitions
141 */
142
143 /* These should be defined somewhere more general */
144 typedef unsigned char T_Byte;
145 typedef unsigned short T_Length;
146 typedef char T_ASSOC_UID[DUL_LEN_UID + 4]; // T_UID is a macro on OSF/1
147 typedef char T_TITLE[DUL_LEN_TITLE + 4];
148 typedef T_Byte *T_Data;
149
150 /*
151 ** Implementation Class UID Sub-Item Structure
152 ** (A-ASSOCIATE-RQ & A-ASSOCIATE-AC)
153 ** See Part 7, pp. 115-116
154 */
155 typedef struct {
156 T_Byte ItemType;
157 T_Byte Reserved1;
158 T_Length ItemLength;
159 T_ASSOC_UID ImplementationClassUID;
160 } T_ASC_ImplementationClassUIDItem;
161
162
163 /*
164 ** Implementation Version Name Sub-Item Structure
165 ** (A-ASSOCIATE-RQ & A-ASSOCIATE-AC)
166 ** See Part 7, pp. 116-117
167 */
168 typedef struct {
169 T_Byte ItemType;
170 T_Byte Reserved1;
171 T_Length ItemLength;
172 T_TITLE ImplementationVersionName;
173 } T_ASC_ImplementationVersionNameItem;
174
175 /*
176 ** Asynchronous Operation Window Sub-Item Structure
177 ** (A-ASSOCIATE-RQ & A-ASSOCIATE-AC)
178 ** See Part 7, pp. 118-121
179 */
180 typedef struct {
181 T_Byte ItemType;
182 T_Byte Reserved1;
183 T_Length ItemLength;
184 T_Length MaximumNumberOperationsInvoked;
185 T_Length MaximumNumberOperationsPerformed;
186 } T_ASC_AsynchronousOperationsWindowItem;
187
188 /*
189 ** SCP/SCU Role Selection Sub-Item Structure
190 ** (A-ASSOCIATE-RQ & A-ASSOCIATE-AC)
191 ** See Part 7, pp. 123-124
192 */
193 typedef struct {
194 T_Byte ItemType;
195 T_Byte Reserved1;
196 T_Length ItemLength;
197 T_Length SOPClassUIDLength;
198 T_ASSOC_UID SOPClassUID;
199 T_Byte SCURole;
200 T_Byte SCPRole;
201 } T_ASC_SCPSCURoleSelectionItem;
202
203 /*
204 ** SOP Class Extended Negotiation Sub-Item Structure
205 ** (A-ASSOCIATE-RQ & A-ASSOCIATE-AC)
206 ** See Part 7, pp. 125-126
207 */
208 typedef struct {
209 T_Byte ItemType;
210 T_Byte Reserved1;
211 T_Length ItemLength;
212 T_Length SOPClassUIDLength;
213 T_ASSOC_UID SOPClassUID;
214 T_Data ServiceClassApplicationInformation;
215 } T_ASC_ExtendedNegotiationItem;
216
217
218 /*
219 ** Function Bodies
220 */
221
222
223 OFCondition
ASC_initializeNetwork(T_ASC_NetworkRole role,int acceptorPort,int timeout,T_ASC_Network ** network,unsigned long options)224 ASC_initializeNetwork(T_ASC_NetworkRole role,
225 int acceptorPort,
226 int timeout,
227 T_ASC_Network ** network,
228 unsigned long options)
229 {
230 const char *mode;
231
232 DUL_NETWORKKEY * netkey;
233
234 switch (role) {
235 case NET_ACCEPTOR:
236 mode = DUL_AEACCEPTOR;
237 break;
238 case NET_REQUESTOR:
239 mode = DUL_AEREQUESTOR;
240 break;
241 case NET_ACCEPTORREQUESTOR:
242 mode = DUL_AEBOTH;
243 break;
244 default:
245 mode = "unknown";
246 break;
247 }
248
249 OFCondition cond = DUL_InitializeNetwork(mode, &acceptorPort, timeout, DUL_ORDERBIGENDIAN | options, &netkey);
250 if (cond.bad()) return cond;
251
252 *network = (T_ASC_Network *) malloc(sizeof(T_ASC_Network));
253 if (*network == NULL) return EC_MemoryExhausted;
254 (*network)->role = role;
255 (*network)->acceptorPort = acceptorPort;
256 (*network)->network = netkey;
257
258 return EC_Normal;
259 }
260
261 OFCondition
ASC_dropNetwork(T_ASC_Network ** network)262 ASC_dropNetwork(T_ASC_Network ** network)
263 {
264 if (network == NULL) return EC_Normal;
265 if (*network == NULL) return EC_Normal;
266
267 OFCondition cond = DUL_DropNetwork(&(*network)->network);
268 if (cond.bad()) return cond;
269
270 free(*network);
271 *network = NULL;
272 return EC_Normal;
273 }
274
275
276 /*
277 * Building Association parameters
278 */
279
280 OFCondition
ASC_createAssociationParameters(T_ASC_Parameters ** params,long maxReceivePDUSize)281 ASC_createAssociationParameters(T_ASC_Parameters ** params,
282 long maxReceivePDUSize)
283 {
284
285 *params = (T_ASC_Parameters *) malloc(sizeof(**params));
286 if (*params == NULL) return EC_MemoryExhausted;
287 bzero((char*)*params, sizeof(**params));
288
289 OFStandard::strlcpy((*params)->ourImplementationClassUID,
290 OFFIS_IMPLEMENTATION_CLASS_UID,
291 sizeof((*params)->ourImplementationClassUID));
292 OFStandard::strlcpy((*params)->ourImplementationVersionName,
293 OFFIS_DTK_IMPLEMENTATION_VERSION_NAME,
294 sizeof((*params)->ourImplementationVersionName));
295
296 if (strlen(OFFIS_DTK_IMPLEMENTATION_VERSION_NAME) > 16)
297 {
298 DCMNET_WARN("DICOM implementation version name too long: " << OFFIS_DTK_IMPLEMENTATION_VERSION_NAME);
299 }
300
301 OFStandard::strlcpy((*params)->DULparams.callingImplementationClassUID,
302 (*params)->ourImplementationClassUID, DICOM_UI_LENGTH + 1);
303 OFStandard::strlcpy((*params)->DULparams.callingImplementationVersionName,
304 (*params)->ourImplementationVersionName, 16+1);
305
306 OFStandard::strlcpy((*params)->DULparams.applicationContextName,
307 UID_StandardApplicationContext,
308 sizeof((*params)->DULparams.applicationContextName));
309
310 ASC_setAPTitles(*params,
311 "calling AP Title",
312 "called AP Title",
313 "resp. AP Title");
314
315 /* make sure max pdv length is even */
316 if ((maxReceivePDUSize % 2) != 0)
317 {
318 DCMNET_WARN("ASSOC: PDV receive length " << maxReceivePDUSize << " is odd (using " << (maxReceivePDUSize-1) << ")");
319 maxReceivePDUSize--;
320 }
321 if (maxReceivePDUSize < ASC_MINIMUMPDUSIZE)
322 {
323 DCMNET_WARN("ASC_createAssociationParameters: maxReceivePDUSize "
324 << maxReceivePDUSize << " too small (using " << ASC_MINIMUMPDUSIZE << ")");
325 maxReceivePDUSize = ASC_MINIMUMPDUSIZE;
326 }
327
328 (*params)->ourMaxPDUReceiveSize = maxReceivePDUSize;
329 (*params)->DULparams.maxPDU = maxReceivePDUSize;
330 (*params)->theirMaxPDUReceiveSize = 0; /* not yet negotiated */
331 (*params)->modeCallback = NULL;
332
333 /* set something unusable */
334 ASC_setPresentationAddresses(*params,
335 "calling Presentation Address",
336 "called Presentation Address");
337
338 /* presentation context lists will be created as needed */
339 (*params)->DULparams.requestedPresentationContext = NULL;
340 (*params)->DULparams.acceptedPresentationContext = NULL;
341
342 (*params)->DULparams.useSecureLayer = OFFalse;
343 return EC_Normal;
344 }
345
346 static void
destroyPresentationContextList(LST_HEAD ** lst)347 destroyPresentationContextList(LST_HEAD ** lst)
348 {
349 DUL_PRESENTATIONCONTEXT *pc;
350 DUL_TRANSFERSYNTAX *ts;
351
352 if ((lst == NULL) || (*lst == NULL))
353 return;
354 while ((pc = (DUL_PRESENTATIONCONTEXT*) LST_Dequeue(lst)) != NULL) {
355 if (pc->proposedTransferSyntax != NULL) {
356 while ((ts = (DUL_TRANSFERSYNTAX*) LST_Dequeue(&pc->proposedTransferSyntax)) != NULL) {
357 free(ts);
358 }
359 LST_Destroy(&pc->proposedTransferSyntax);
360 }
361 free(pc);
362 }
363 LST_Destroy(lst);
364 }
365
366 OFCondition
ASC_destroyAssociationParameters(T_ASC_Parameters ** params)367 ASC_destroyAssociationParameters(T_ASC_Parameters ** params)
368 {
369
370 /* free the elements in the requested presentation context list */
371 destroyPresentationContextList(
372 &((*params)->DULparams.requestedPresentationContext));
373
374 /* free the elements in the accepted presentation context list */
375 destroyPresentationContextList(
376 &((*params)->DULparams.acceptedPresentationContext));
377
378 /* free DUL parameters */
379 DUL_ClearServiceParameters( &(*params)->DULparams );
380
381 free(*params);
382 *params = NULL;
383
384 return EC_Normal;
385 }
386
387 OFCondition
ASC_setAPTitles(T_ASC_Parameters * params,const char * callingAPTitle,const char * calledAPTitle,const char * respondingAPTitle)388 ASC_setAPTitles(T_ASC_Parameters * params,
389 const char* callingAPTitle,
390 const char* calledAPTitle,
391 const char* respondingAPTitle)
392 {
393 if (callingAPTitle)
394 OFStandard::strlcpy(params->DULparams.callingAPTitle, callingAPTitle,
395 sizeof(params->DULparams.callingAPTitle));
396 if (calledAPTitle)
397 OFStandard::strlcpy(params->DULparams.calledAPTitle, calledAPTitle,
398 sizeof(params->DULparams.calledAPTitle));
399 if (respondingAPTitle)
400 OFStandard::strlcpy(params->DULparams.respondingAPTitle, respondingAPTitle,
401 sizeof(params->DULparams.respondingAPTitle));
402
403 return EC_Normal;
404 }
405
406 OFCondition
ASC_getAPTitles(T_ASC_Parameters * params,char * callingAPTitle,size_t callingAPTitleSize,char * calledAPTitle,size_t calledAPTitleSize,char * respondingAPTitle,size_t respondingAPTitleSize)407 ASC_getAPTitles(T_ASC_Parameters * params,
408 char* callingAPTitle,
409 size_t callingAPTitleSize,
410 char* calledAPTitle,
411 size_t calledAPTitleSize,
412 char* respondingAPTitle,
413 size_t respondingAPTitleSize)
414 {
415 if (callingAPTitle)
416 OFStandard::strlcpy(callingAPTitle, params->DULparams.callingAPTitle, callingAPTitleSize);
417 if (calledAPTitle)
418 OFStandard::strlcpy(calledAPTitle, params->DULparams.calledAPTitle, calledAPTitleSize);
419 if (respondingAPTitle)
420 OFStandard::strlcpy(respondingAPTitle, params->DULparams.respondingAPTitle, respondingAPTitleSize);
421
422 return EC_Normal;
423 }
424
425 OFCondition
ASC_getApplicationContextName(T_ASC_Parameters * params,char * applicationContextName,size_t applicationContextNameSize)426 ASC_getApplicationContextName(T_ASC_Parameters * params,
427 char* applicationContextName,
428 size_t applicationContextNameSize)
429 {
430 if (applicationContextName)
431 OFStandard::strlcpy(applicationContextName,
432 params->DULparams.applicationContextName,
433 applicationContextNameSize);
434 return EC_Normal;
435 }
436
437 OFCondition
ASC_setPresentationAddresses(T_ASC_Parameters * params,const char * callingPresentationAddress,const char * calledPresentationAddress)438 ASC_setPresentationAddresses(T_ASC_Parameters * params,
439 const char* callingPresentationAddress,
440 const char* calledPresentationAddress)
441 {
442 if (callingPresentationAddress)
443 OFStandard::strlcpy(params->DULparams.callingPresentationAddress,
444 callingPresentationAddress,
445 sizeof(params->DULparams.callingPresentationAddress));
446 if (calledPresentationAddress)
447 OFStandard::strlcpy(params->DULparams.calledPresentationAddress,
448 calledPresentationAddress,
449 sizeof(params->DULparams.calledPresentationAddress));
450
451 return EC_Normal;
452 }
453
454 OFCondition
ASC_getPresentationAddresses(T_ASC_Parameters * params,char * callingPresentationAddress,size_t callingPresentationAddressSize,char * calledPresentationAddress,size_t calledPresentationAddressSize)455 ASC_getPresentationAddresses(T_ASC_Parameters * params,
456 char* callingPresentationAddress,
457 size_t callingPresentationAddressSize,
458 char* calledPresentationAddress,
459 size_t calledPresentationAddressSize)
460 {
461 if (callingPresentationAddress)
462 OFStandard::strlcpy(callingPresentationAddress,
463 params->DULparams.callingPresentationAddress, callingPresentationAddressSize);
464 if (calledPresentationAddress)
465 OFStandard::strlcpy(calledPresentationAddress,
466 params->DULparams.calledPresentationAddress, calledPresentationAddressSize);
467
468 return EC_Normal;
469 }
470
471 OFCondition
ASC_getRejectParameters(T_ASC_Parameters * params,T_ASC_RejectParameters * rejectParameters)472 ASC_getRejectParameters(T_ASC_Parameters * params,
473 T_ASC_RejectParameters * rejectParameters)
474 {
475 int reason;
476 if (rejectParameters) {
477 rejectParameters->result =
478 (T_ASC_RejectParametersResult) params->DULparams.result;
479 rejectParameters->source =
480 (T_ASC_RejectParametersSource) params->DULparams.resultSource;
481
482 reason = params->DULparams.diagnostic |
483 ((params->DULparams.resultSource & 0xff) << 8);
484 rejectParameters->reason = (T_ASC_RejectParametersReason) reason;
485 }
486 return EC_Normal;
487 }
488
489 OFString&
ASC_printRejectParameters(OFString & str,const T_ASC_RejectParameters * rej)490 ASC_printRejectParameters(OFString& str, const T_ASC_RejectParameters *rej)
491 {
492 const char *result;
493 const char *source;
494 const char *reason;
495
496 switch (rej->result) {
497 case ASC_RESULT_REJECTEDPERMANENT:
498 result = "Rejected Permanent"; break;
499 case ASC_RESULT_REJECTEDTRANSIENT:
500 result = "Rejected Transient"; break;
501 default:
502 result = "UNKNOWN"; break;
503 }
504 switch (rej->source) {
505 case ASC_SOURCE_SERVICEUSER:
506 source = "Service User"; break;
507 case ASC_SOURCE_SERVICEPROVIDER_ACSE_RELATED:
508 source = "Service Provider (ACSE Related)"; break;
509 case ASC_SOURCE_SERVICEPROVIDER_PRESENTATION_RELATED:
510 source = "Service Provider (Presentation Related)"; break;
511 default:
512 source = "UNKNOWN"; break;
513 }
514 switch (rej->reason) {
515 case ASC_REASON_SU_NOREASON:
516 case ASC_REASON_SP_ACSE_NOREASON:
517 reason = "No Reason"; break;
518 case ASC_REASON_SU_APPCONTEXTNAMENOTSUPPORTED:
519 reason = "App Context Name Not Supported"; break;
520 case ASC_REASON_SU_CALLINGAETITLENOTRECOGNIZED:
521 reason = "Calling AE Title Not Recognized"; break;
522 case ASC_REASON_SU_CALLEDAETITLENOTRECOGNIZED:
523 reason = "Called AE Title Not Recognized"; break;
524 case ASC_REASON_SP_ACSE_PROTOCOLVERSIONNOTSUPPORTED:
525 reason = "Protocol Version Not Supported"; break;
526 /* Service Provider Presentation Related reasons */
527 case ASC_REASON_SP_PRES_TEMPORARYCONGESTION:
528 reason = "Temporary Congestion"; break;
529 case ASC_REASON_SP_PRES_LOCALLIMITEXCEEDED:
530 reason = "Local Limit Exceeded"; break;
531 default:
532 reason = "UNKNOWN"; break;
533 }
534 str = OFString("Result: ") + result + ", Source: " + source + "\nReason: " + reason;
535 return str;
536 }
537
538 static T_ASC_SC_ROLE
dulRole2ascRole(DUL_SC_ROLE role)539 dulRole2ascRole(DUL_SC_ROLE role)
540 {
541 T_ASC_SC_ROLE ar = ASC_SC_ROLE_DEFAULT;
542 switch (role) {
543 case DUL_SC_ROLE_SCU: ar = ASC_SC_ROLE_SCU; break;
544 case DUL_SC_ROLE_SCP: ar = ASC_SC_ROLE_SCP; break;
545 case DUL_SC_ROLE_SCUSCP: ar = ASC_SC_ROLE_SCUSCP; break;
546 case DUL_SC_ROLE_NONE: ar = ASC_SC_ROLE_NONE; break;
547 case DUL_SC_ROLE_DEFAULT:
548 default: ar = ASC_SC_ROLE_DEFAULT; break;
549 }
550 return ar;
551 }
552
553 DUL_SC_ROLE
ascRole2dulRole(const T_ASC_SC_ROLE role)554 ascRole2dulRole(const T_ASC_SC_ROLE role)
555 {
556 DUL_SC_ROLE dr = DUL_SC_ROLE_DEFAULT;
557 switch (role) {
558 case ASC_SC_ROLE_SCU: dr = DUL_SC_ROLE_SCU; break;
559 case ASC_SC_ROLE_SCP: dr = DUL_SC_ROLE_SCP; break;
560 case ASC_SC_ROLE_SCUSCP: dr = DUL_SC_ROLE_SCUSCP; break;
561 case ASC_SC_ROLE_NONE: dr = DUL_SC_ROLE_NONE; break;
562 case ASC_SC_ROLE_DEFAULT:
563 default: dr = DUL_SC_ROLE_DEFAULT; break;
564 }
565 return dr;
566 }
567
568 const char*
ASC_role2String(const T_ASC_SC_ROLE role)569 ASC_role2String(const T_ASC_SC_ROLE role)
570 {
571 const char* s = NULL;
572 switch (role) {
573 case ASC_SC_ROLE_SCU: s = "SCU"; break;
574 case ASC_SC_ROLE_SCP: s = "SCP"; break;
575 case ASC_SC_ROLE_SCUSCP: s = "SCP/SCU"; break;
576 case ASC_SC_ROLE_NONE: s = "None"; break;
577 case ASC_SC_ROLE_DEFAULT: s = "Default"; break;
578 default: s = "Unknown"; break;
579 }
580 return s;
581 }
582
583 static
584 DUL_PRESENTATIONCONTEXT *
findPresentationContextID(LST_HEAD * head,T_ASC_PresentationContextID presentationContextID)585 findPresentationContextID(LST_HEAD * head,
586 T_ASC_PresentationContextID presentationContextID)
587 {
588 DUL_PRESENTATIONCONTEXT *pc;
589 LST_HEAD **l;
590 OFBool found = OFFalse;
591
592 if (head == NULL)
593 return NULL;
594
595 l = &head;
596 if (*l == NULL)
597 return NULL;
598
599 pc = (DUL_PRESENTATIONCONTEXT*) LST_Head(l);
600 (void)LST_Position(l, (LST_NODE*)pc);
601
602 while (pc && !found) {
603 if (pc->presentationContextID == presentationContextID) {
604 found = OFTrue;
605 } else {
606 pc = (DUL_PRESENTATIONCONTEXT*) LST_Next(l);
607 }
608 }
609 return pc;
610 }
611
612 OFCondition
ASC_addPresentationContext(T_ASC_Parameters * params,T_ASC_PresentationContextID presentationContextID,const char * abstractSyntax,const char * transferSyntaxList[],int transferSyntaxListCount,T_ASC_SC_ROLE proposedRole)613 ASC_addPresentationContext(
614 T_ASC_Parameters * params,
615 T_ASC_PresentationContextID presentationContextID,
616 const char* abstractSyntax,
617 const char* transferSyntaxList[],
618 int transferSyntaxListCount,
619 T_ASC_SC_ROLE proposedRole)
620 {
621 DUL_PRESENTATIONCONTEXT *pc;
622 LST_HEAD *lst;
623 DUL_TRANSFERSYNTAX *transfer;
624 int i;
625
626 /* presentation context id's must be odd */
627 if ((presentationContextID % 2) == 0)
628 {
629 char buf[256];
630 sprintf(buf, "ASC Bad presentation context ID: %d", presentationContextID);
631 return makeDcmnetCondition(ASCC_BADPRESENTATIONCONTEXTID, OF_error, buf);
632 }
633 /* see if a presentation context with this id already exists in list */
634 pc = findPresentationContextID(
635 params->DULparams.requestedPresentationContext,
636 presentationContextID);
637 if (pc)
638 {
639 char buf[256];
640 sprintf(buf, "ASC Duplicate presentation context ID: %d", presentationContextID);
641 return makeDcmnetCondition(ASCC_DUPLICATEPRESENTATIONCONTEXTID, OF_error, buf);
642 }
643
644 /* we cannot simply use DUL_MakePresentationCtx() because
645 ** it takes variable arguments (for transfer syntax).
646 */
647 pc = (DUL_PRESENTATIONCONTEXT *) calloc(1, sizeof(DUL_PRESENTATIONCONTEXT));
648 if (pc == NULL) return EC_MemoryExhausted;
649 lst = LST_Create();
650 if (lst == NULL)
651 {
652 free(pc);
653 return EC_MemoryExhausted;
654 }
655 pc->presentationContextID = presentationContextID;
656 OFStandard::strlcpy(pc->abstractSyntax, abstractSyntax, sizeof(pc->abstractSyntax));
657 pc->result = ASC_P_NOTYETNEGOTIATED;
658 pc->proposedSCRole = ascRole2dulRole(proposedRole);
659 pc->acceptedSCRole = ascRole2dulRole(ASC_SC_ROLE_DEFAULT);
660
661 /* there must be at least one transfer syntax */
662 if (transferSyntaxListCount < 1)
663 {
664 free(pc);
665 return ASC_MISSINGTRANSFERSYNTAX;
666 }
667
668 /* add the transfer syntaxes */
669 for (i=0; i<transferSyntaxListCount; i++)
670 {
671 transfer = (DUL_TRANSFERSYNTAX*)malloc(sizeof(DUL_TRANSFERSYNTAX));
672 if (transfer == NULL) return EC_MemoryExhausted;
673 OFStandard::strlcpy(transfer->transferSyntax, transferSyntaxList[i], sizeof(transfer->transferSyntax));
674 LST_Enqueue(&lst, (LST_NODE*)transfer);
675 }
676 pc->proposedTransferSyntax = lst;
677
678 /* add to presentation context list */
679 lst = params->DULparams.requestedPresentationContext;
680 if (lst == NULL) {
681 lst = LST_Create();
682 if (lst == NULL)
683 {
684 free(pc);
685 return EC_MemoryExhausted;
686 }
687 }
688
689 LST_Enqueue(&lst, (LST_NODE*)pc);
690
691 params->DULparams.requestedPresentationContext = lst;
692 return EC_Normal;
693 }
694
695 int
ASC_countPresentationContexts(T_ASC_Parameters * params)696 ASC_countPresentationContexts(T_ASC_Parameters * params)
697 {
698 LST_HEAD **l;
699
700 if (params->DULparams.requestedPresentationContext == NULL)
701 return 0;
702
703 l = &(params->DULparams.requestedPresentationContext);
704 return LST_Count(l);
705
706 }
707
708 int
ASC_countAcceptedPresentationContexts(T_ASC_Parameters * params)709 ASC_countAcceptedPresentationContexts(T_ASC_Parameters * params)
710
711 /* ASC_countAcceptedPresentationContexts:
712 * Returns the number of presentation contexts contained in the presentation
713 * context list which are marked as being accepted.
714 */
715 {
716 int n = 0;
717 LST_HEAD **l;
718 DUL_PRESENTATIONCONTEXT *pc;
719
720 if (params->DULparams.acceptedPresentationContext == NULL)
721 return 0;
722
723 l = &(params->DULparams.acceptedPresentationContext);
724 pc = (DUL_PRESENTATIONCONTEXT*) LST_Head(l);
725 (void)LST_Position(l, (LST_NODE*)pc);
726
727 while (pc) {
728 if (pc->result == ASC_P_ACCEPTANCE) n++;
729 pc = (DUL_PRESENTATIONCONTEXT*) LST_Next(l);
730 }
731
732 return n;
733 }
734
735 OFCondition
ASC_getPresentationContext(T_ASC_Parameters * params,int listPosition,T_ASC_PresentationContext * presentationContext)736 ASC_getPresentationContext(T_ASC_Parameters * params,
737 int listPosition,
738 T_ASC_PresentationContext * presentationContext)
739 {
740 DUL_PRESENTATIONCONTEXT *pc;
741 DUL_TRANSFERSYNTAX *transfer;
742 LST_HEAD **l;
743 int count = 0;
744
745 /* make the presentation context structure clean */
746 bzero((char*)presentationContext, sizeof(*presentationContext));
747
748 if (params->DULparams.requestedPresentationContext == NULL)
749 {
750 char buf[256];
751 sprintf(buf, "ASC Bad presentation context position: %d", listPosition);
752 return makeDcmnetCondition(ASCC_BADPRESENTATIONCONTEXTPOSITION, OF_error, buf);
753 }
754 l = &(params->DULparams.requestedPresentationContext);
755 if (*l == NULL)
756 {
757 char buf[256];
758 sprintf(buf, "ASC Bad presentation context position: %d", listPosition);
759 return makeDcmnetCondition(ASCC_BADPRESENTATIONCONTEXTPOSITION, OF_error, buf);
760 }
761 pc = (DUL_PRESENTATIONCONTEXT*) LST_Head(l);
762 (void)LST_Position(l, (LST_NODE*)pc);
763
764 while (pc && count != listPosition) {
765 count++;
766 pc = (DUL_PRESENTATIONCONTEXT*) LST_Next(l);
767 }
768
769 if (pc == NULL)
770 {
771 char buf[256];
772 sprintf(buf, "ASC Bad presentation context position: %d", listPosition);
773 return makeDcmnetCondition(ASCC_BADPRESENTATIONCONTEXTPOSITION, OF_error, buf);
774 }
775
776 presentationContext->presentationContextID = pc->presentationContextID;
777 presentationContext->resultReason = (T_ASC_P_ResultReason) pc->result;
778 presentationContext->proposedRole = dulRole2ascRole(pc->proposedSCRole);
779 presentationContext->acceptedRole = dulRole2ascRole(pc->acceptedSCRole);
780 OFStandard::strlcpy(presentationContext->abstractSyntax,
781 pc->abstractSyntax, sizeof(presentationContext->abstractSyntax));
782 if (presentationContext->resultReason == ASC_P_ACCEPTANCE) {
783 OFStandard::strlcpy(presentationContext->acceptedTransferSyntax,
784 pc->acceptedTransferSyntax, sizeof(presentationContext->acceptedTransferSyntax));
785 } else {
786 presentationContext->acceptedTransferSyntax[0] = '\0';
787 }
788
789 /* need to copy the transfer syntaxes */
790 count = 0;
791
792 l = &pc->proposedTransferSyntax;
793 transfer = (DUL_TRANSFERSYNTAX*) LST_Head(l);
794 (void)LST_Position(l, (LST_NODE*)transfer);
795 while (transfer != NULL)
796 {
797 if (count >= DICOM_MAXTRANSFERSYNTAXES)
798 {
799 return makeDcmnetCondition(ASCC_CODINGERROR, OF_error, "ASC Coding error in ASC_getPresentationContext: too many transfer syntaxes");
800 }
801 OFStandard::strlcpy(presentationContext->proposedTransferSyntaxes[count],
802 transfer->transferSyntax, sizeof(presentationContext->proposedTransferSyntaxes[count]));
803 count++;
804 transfer = (DUL_TRANSFERSYNTAX*) LST_Next(l);
805 }
806
807 presentationContext->transferSyntaxCount = count;
808
809 return EC_Normal;
810 }
811
812 OFCondition
ASC_acceptPresentationContext(T_ASC_Parameters * params,T_ASC_PresentationContextID presentationContextID,const char * transferSyntax,T_ASC_SC_ROLE acceptedRole,const OFBool alwaysAcceptDefaultRole)813 ASC_acceptPresentationContext(
814 T_ASC_Parameters * params,
815 T_ASC_PresentationContextID presentationContextID,
816 const char* transferSyntax,
817 T_ASC_SC_ROLE acceptedRole,
818 const OFBool alwaysAcceptDefaultRole)
819 {
820 DUL_PRESENTATIONCONTEXT *proposedContext, *acceptedContext;
821 OFCondition cond = EC_Normal;
822 LST_HEAD *lst;
823
824 proposedContext = findPresentationContextID(
825 params->DULparams.requestedPresentationContext,
826 presentationContextID);
827 if (proposedContext == NULL) return ASC_BADPRESENTATIONCONTEXTID;
828 OFStandard::strlcpy(proposedContext->acceptedTransferSyntax, transferSyntax, sizeof(proposedContext->acceptedTransferSyntax));
829
830 /* we want to mark this proposed context as being ok */
831 proposedContext->result = ASC_P_ACCEPTANCE;
832 proposedContext->acceptedSCRole = ascRole2dulRole(acceptedRole);
833
834 /* Here we check the only role selection case which leads to clear rejection of the
835 * proposed presentation context: If the requestor connects with default role but the
836 * acceptor explicitly requires the SCP role (only) then the presentation context
837 * will be rejected. All other cases do not lead to rejection but to actual "negotiation".
838 * DCMTK's behaviour can be seen in the declaration of enum DUL_SC_ROLE (see dul.h).
839 * The logic of the role negotiation is implemented in constructSCUSCPRoles() (see dulconst.cc).
840 */
841 if ( (proposedContext->proposedSCRole == DUL_SC_ROLE_DEFAULT)
842 && (proposedContext->acceptedSCRole == DUL_SC_ROLE_SCP) )
843 {
844 // If user wants to override rejection (e.g. for faulty clients), skip the check but print warning
845 if (alwaysAcceptDefaultRole)
846 {
847 DCMNET_WARN("ASSOC: Deliberately accepting Default role proposed by association requestor, "
848 << "while originally being configured for role SCP only");
849 }
850 else
851 {
852 proposedContext->result = ASC_P_NOREASON;
853 DCMNET_ERROR("ASSOC: SCP/SCU role selection failed, Default role (i.e. SCU) proposed "
854 << "but only SCP role configured for acceptance");
855 return ASC_SCPSCUROLESELECTIONFAILED;
856 }
857 }
858
859 acceptedContext = findPresentationContextID(
860 params->DULparams.acceptedPresentationContext,
861 presentationContextID);
862
863 if (acceptedContext != NULL) {
864 /* it is already in the list, mark it as accepted */
865 acceptedContext->result = ASC_P_ACCEPTANCE;
866 OFStandard::strlcpy(acceptedContext->abstractSyntax,
867 proposedContext->abstractSyntax, sizeof(acceptedContext->abstractSyntax));
868 OFStandard::strlcpy(acceptedContext->acceptedTransferSyntax, transferSyntax, sizeof(acceptedContext->acceptedTransferSyntax));
869 acceptedContext->proposedSCRole = proposedContext->proposedSCRole;
870 acceptedContext->acceptedSCRole = ascRole2dulRole(acceptedRole);
871 } else {
872 /*
873 * make a new presentation context, mark it as accepted and add to
874 * end of accepted list
875 */
876
877 cond = DUL_MakePresentationCtx(
878 &acceptedContext,
879 proposedContext->proposedSCRole, ascRole2dulRole(acceptedRole),
880 presentationContextID, ASC_P_ACCEPTANCE,
881 proposedContext->abstractSyntax,
882 (char*)transferSyntax, NULL);
883 if (cond.bad()) return cond;
884
885 lst = params->DULparams.acceptedPresentationContext;
886 if (lst == NULL) {
887 lst = LST_Create();
888 if (lst == NULL) return EC_MemoryExhausted;
889 }
890
891 LST_Enqueue(&lst, (LST_NODE*)acceptedContext);
892 params->DULparams.acceptedPresentationContext = lst;
893 }
894 return EC_Normal;
895 }
896
897
898 OFCondition
ASC_refusePresentationContext(T_ASC_Parameters * params,T_ASC_PresentationContextID presentationContextID,T_ASC_P_ResultReason resultReason)899 ASC_refusePresentationContext(
900 T_ASC_Parameters * params,
901 T_ASC_PresentationContextID presentationContextID,
902 T_ASC_P_ResultReason resultReason)
903 {
904 DUL_PRESENTATIONCONTEXT *proposedContext, *acceptedContext;
905 OFCondition cond = EC_Normal;
906 LST_HEAD *lst;
907
908 proposedContext = findPresentationContextID(
909 params->DULparams.requestedPresentationContext,
910 presentationContextID);
911 if (proposedContext == NULL) return ASC_BADPRESENTATIONCONTEXTID;
912
913 /* we want to mark this proposed context as being refused */
914 proposedContext->result = resultReason;
915
916 acceptedContext = findPresentationContextID(
917 params->DULparams.acceptedPresentationContext,
918 presentationContextID);
919
920 if (acceptedContext != NULL) {
921 /* it is already in the list, mark it as refused */
922 acceptedContext->result = resultReason;
923 OFStandard::strlcpy(acceptedContext->abstractSyntax,
924 proposedContext->abstractSyntax, sizeof(acceptedContext->abstractSyntax));
925 /* we must send back a transfer syntax even though this
926 * presentation context is refused. Some software implementations
927 * seem to get confused if we don't.
928 */
929 OFStandard::strlcpy(acceptedContext->acceptedTransferSyntax,
930 UID_LittleEndianImplicitTransferSyntax, sizeof(acceptedContext->acceptedTransferSyntax));
931 } else {
932
933 /*
934 * make a new presentation context, mark it as refused and add to end
935 * of accepted list -- yes, even though it is refused, refused
936 * presentation contexts must still be sent back
937 */
938 /* we must send back a transfer syntax even though this
939 * presentation context is refused. Some software implementations
940 * seem to get confused if we don't.
941 */
942
943 cond = DUL_MakePresentationCtx(
944 &acceptedContext,
945 DUL_SC_ROLE_DEFAULT, DUL_SC_ROLE_DEFAULT,
946 presentationContextID, resultReason,
947 proposedContext->abstractSyntax,
948 UID_LittleEndianImplicitTransferSyntax, NULL);
949 if (cond.bad()) return cond;
950
951 lst = params->DULparams.acceptedPresentationContext;
952 if (lst == NULL) {
953 lst = LST_Create();
954 if (lst == NULL) return EC_MemoryExhausted;
955 }
956 LST_Enqueue(&lst, (LST_NODE*)acceptedContext);
957 params->DULparams.acceptedPresentationContext = lst;
958 }
959 return EC_Normal;
960 }
961
962
963 OFCondition
ASC_findAcceptedPresentationContext(T_ASC_Parameters * params,T_ASC_PresentationContextID presentationContextID,T_ASC_PresentationContext * presentationContext)964 ASC_findAcceptedPresentationContext(
965 T_ASC_Parameters * params,
966 T_ASC_PresentationContextID presentationContextID,
967 T_ASC_PresentationContext * presentationContext)
968 {
969 DUL_PRESENTATIONCONTEXT *pc;
970 DUL_TRANSFERSYNTAX *transfer;
971 LST_HEAD **l;
972 int count = 0;
973
974 /*
975 ** We look in the requestedPresentationContexts since this
976 ** has all the proposed information. The result field will
977 ** have been set to ASC_P_ACCEPTANCE in the ASC_requestAssociation
978 ** function.
979 */
980 pc = findPresentationContextID(
981 params->DULparams.requestedPresentationContext,
982 presentationContextID);
983
984 if ((pc == NULL) || (pc->result != ASC_P_ACCEPTANCE)) return ASC_BADPRESENTATIONCONTEXTID;
985
986 l = &pc->proposedTransferSyntax;
987 transfer = (DUL_TRANSFERSYNTAX*) LST_Head(l);
988 (void)LST_Position(l, (LST_NODE*)transfer);
989 while (transfer != NULL) {
990 if (count >= DICOM_MAXTRANSFERSYNTAXES)
991 {
992 return makeDcmnetCondition(ASCC_CODINGERROR, OF_error, "ASC Coding error in ASC_findAcceptedPresentationContext: too many transfer syntaxes");
993 }
994 OFStandard::strlcpy(presentationContext->proposedTransferSyntaxes[count], transfer->transferSyntax, sizeof(DIC_UI));
995 count++;
996 transfer = (DUL_TRANSFERSYNTAX*) LST_Next(l);
997 }
998
999 OFStandard::strlcpy(presentationContext->abstractSyntax, pc->abstractSyntax, sizeof(DIC_UI));
1000 presentationContext->presentationContextID = pc->presentationContextID;
1001 presentationContext->resultReason = (T_ASC_P_ResultReason) pc->result;
1002 presentationContext->proposedRole = dulRole2ascRole(pc->proposedSCRole);
1003 presentationContext->acceptedRole = dulRole2ascRole(pc->acceptedSCRole);
1004
1005 presentationContext->transferSyntaxCount = count;
1006 OFStandard::strlcpy(presentationContext->acceptedTransferSyntax, pc->acceptedTransferSyntax, sizeof(DIC_UI));
1007
1008 return EC_Normal;
1009 }
1010
1011 T_ASC_PresentationContextID
ASC_findAcceptedPresentationContextID(T_ASC_Association * assoc,const char * abstractSyntax)1012 ASC_findAcceptedPresentationContextID(
1013 T_ASC_Association *assoc,
1014 const char* abstractSyntax)
1015 {
1016 DUL_PRESENTATIONCONTEXT *pc;
1017 LST_HEAD **l;
1018 OFBool found = OFFalse;
1019
1020 if (assoc->params->DULparams.acceptedPresentationContext == NULL)
1021 return 0;
1022
1023 l = &assoc->params->DULparams.acceptedPresentationContext;
1024 pc = (DUL_PRESENTATIONCONTEXT*) LST_Head(l);
1025 (void)LST_Position(l, (LST_NODE*)pc);
1026 while (pc && !found)
1027 {
1028 found = ( (strcmp(pc->abstractSyntax, abstractSyntax) == 0) && (pc->result == ASC_P_ACCEPTANCE) );
1029 if (!found) pc = (DUL_PRESENTATIONCONTEXT*) LST_Next(l);
1030 }
1031 if (found) return pc->presentationContextID;
1032 return 0; /* otherwise */
1033 }
1034
1035
1036
1037 T_ASC_PresentationContextID
ASC_findAcceptedPresentationContextID(T_ASC_Association * assoc,const char * abstractSyntax,const char * transferSyntax)1038 ASC_findAcceptedPresentationContextID(
1039 T_ASC_Association *assoc,
1040 const char* abstractSyntax,
1041 const char * transferSyntax)
1042 {
1043 DUL_PRESENTATIONCONTEXT *pc;
1044 LST_HEAD **l;
1045 OFBool found = OFFalse;
1046
1047 if ( (transferSyntax == NULL) || (abstractSyntax == NULL) )
1048 return 0;
1049 if (assoc->params->DULparams.acceptedPresentationContext == NULL)
1050 return 0;
1051
1052 /* first of all we look for a presentation context
1053 * matching both abstract and transfer syntax
1054 */
1055 l = &assoc->params->DULparams.acceptedPresentationContext;
1056 pc = (DUL_PRESENTATIONCONTEXT*) LST_Head(l);
1057 (void)LST_Position(l, (LST_NODE*)pc);
1058 while (pc && !found)
1059 {
1060 found = (strcmp(pc->abstractSyntax, abstractSyntax) == 0) && (pc->result == ASC_P_ACCEPTANCE) && (strcmp(pc->acceptedTransferSyntax, transferSyntax) == 0);
1061 if (!found) pc = (DUL_PRESENTATIONCONTEXT*) LST_Next(l);
1062 }
1063 if (found) return pc->presentationContextID;
1064
1065 /* now we look for an explicit VR uncompressed PC. */
1066 l = &assoc->params->DULparams.acceptedPresentationContext;
1067 pc = (DUL_PRESENTATIONCONTEXT*) LST_Head(l);
1068 (void)LST_Position(l, (LST_NODE*)pc);
1069 while (pc && !found)
1070 {
1071 found = (strcmp(pc->abstractSyntax, abstractSyntax) == 0)
1072 && (pc->result == ASC_P_ACCEPTANCE)
1073 && ((strcmp(pc->acceptedTransferSyntax, UID_LittleEndianExplicitTransferSyntax) == 0)
1074 || (strcmp(pc->acceptedTransferSyntax, UID_BigEndianExplicitTransferSyntax) == 0));
1075 if (!found) pc = (DUL_PRESENTATIONCONTEXT*) LST_Next(l);
1076 }
1077 if (found) return pc->presentationContextID;
1078
1079 /* now we look for an implicit VR uncompressed PC. */
1080 l = &assoc->params->DULparams.acceptedPresentationContext;
1081 pc = (DUL_PRESENTATIONCONTEXT*) LST_Head(l);
1082 (void)LST_Position(l, (LST_NODE*)pc);
1083 while (pc && !found)
1084 {
1085 found = (strcmp(pc->abstractSyntax, abstractSyntax) == 0)
1086 && (pc->result == ASC_P_ACCEPTANCE)
1087 && (strcmp(pc->acceptedTransferSyntax, UID_LittleEndianImplicitTransferSyntax) == 0);
1088 if (!found) pc = (DUL_PRESENTATIONCONTEXT*) LST_Next(l);
1089 }
1090 if (found) return pc->presentationContextID;
1091
1092 /* finally we accept everything we get.
1093 returns 0 if abstract syntax is not supported
1094 */
1095 return ASC_findAcceptedPresentationContextID(assoc, abstractSyntax);
1096 }
1097
1098
1099 OFCondition
ASC_acceptContextsWithTransferSyntax(T_ASC_Parameters * params,const char * transferSyntax,int abstractSyntaxCount,const char * abstractSyntaxes[],T_ASC_SC_ROLE acceptedRole)1100 ASC_acceptContextsWithTransferSyntax(
1101 T_ASC_Parameters * params,
1102 const char* transferSyntax,
1103 int abstractSyntaxCount, const char* abstractSyntaxes[],
1104 T_ASC_SC_ROLE acceptedRole)
1105 {
1106 OFCondition cond = EC_Normal;
1107 int n, i, j, k;
1108 DUL_PRESENTATIONCONTEXT *dpc;
1109 T_ASC_PresentationContext pc;
1110 OFBool accepted = OFFalse;
1111 OFBool abstractOK = OFFalse;
1112
1113 n = ASC_countPresentationContexts(params);
1114 // No presentation context proposed at all? Return error.
1115 if (n == 0)
1116 {
1117 return ASC_NOPRESENTATIONCONTEXTPROPOSED;
1118 }
1119
1120 for (i = 0; i < n; i++) {
1121 cond = ASC_getPresentationContext(params, i, &pc);
1122 if (cond.bad()) return cond;
1123 abstractOK = OFFalse;
1124 accepted = OFFalse;
1125 for (j = 0; j < abstractSyntaxCount && !accepted; j++) {
1126 if (strcmp(pc.abstractSyntax, abstractSyntaxes[j]) == 0) {
1127 abstractOK = OFTrue;
1128 /* check the transfer syntax */
1129 for (k = 0; (k < (int)pc.transferSyntaxCount) && !accepted; k++) {
1130 if (strcmp(pc.proposedTransferSyntaxes[k], transferSyntax) == 0) {
1131 accepted = OFTrue;
1132 }
1133 }
1134 }
1135 }
1136 if (accepted) {
1137 cond = ASC_acceptPresentationContext(
1138 params, pc.presentationContextID,
1139 transferSyntax, acceptedRole);
1140 // SCP/SCU role selection failed, reject presentation context
1141 if (cond == ASC_SCPSCUROLESELECTIONFAILED) {
1142 cond = ASC_refusePresentationContext(params,
1143 pc.presentationContextID, ASC_P_NOREASON);
1144 }
1145 if (cond.bad()) return cond;
1146 } else {
1147 T_ASC_P_ResultReason reason;
1148
1149 /* do not refuse if already accepted */
1150 dpc = findPresentationContextID(
1151 params->DULparams.acceptedPresentationContext,
1152 pc.presentationContextID);
1153 if ((dpc == NULL) ||
1154 ((dpc != NULL) && (dpc->result != ASC_P_ACCEPTANCE))) {
1155
1156 if (abstractOK) {
1157 reason = ASC_P_TRANSFERSYNTAXESNOTSUPPORTED;
1158 } else {
1159 reason = ASC_P_ABSTRACTSYNTAXNOTSUPPORTED;
1160 }
1161 /*
1162 * If previously this presentation context was refused
1163 * because of bad transfer syntax let it stay that way.
1164 */
1165 if ((dpc != NULL) &&
1166 (dpc->result == ASC_P_TRANSFERSYNTAXESNOTSUPPORTED))
1167 reason = ASC_P_TRANSFERSYNTAXESNOTSUPPORTED;
1168
1169 cond = ASC_refusePresentationContext(params,
1170 pc.presentationContextID,
1171 reason);
1172 if (cond.bad()) return cond;
1173 }
1174 }
1175
1176 }
1177 return EC_Normal;
1178 }
1179
1180 OFCondition
ASC_acceptContextsWithPreferredTransferSyntaxes(T_ASC_Parameters * params,const char * abstractSyntaxes[],int abstractSyntaxCount,const char * transferSyntaxes[],int transferSyntaxCount,T_ASC_SC_ROLE acceptedRole)1181 ASC_acceptContextsWithPreferredTransferSyntaxes(
1182 T_ASC_Parameters * params,
1183 const char* abstractSyntaxes[], int abstractSyntaxCount,
1184 const char* transferSyntaxes[], int transferSyntaxCount,
1185 T_ASC_SC_ROLE acceptedRole)
1186 {
1187 int i;
1188 OFCondition cond = EC_Normal;
1189 /*
1190 ** Accept in the order "least wanted" to "most wanted" transfer
1191 ** syntax. Accepting a transfer syntax will override previously
1192 ** accepted transfer syntaxes.
1193 */
1194 for (i=transferSyntaxCount-1; i>=0; i--)
1195 {
1196 cond = ASC_acceptContextsWithTransferSyntax(
1197 params, transferSyntaxes[i],
1198 abstractSyntaxCount, abstractSyntaxes, acceptedRole);
1199 if (cond.bad()) return cond;
1200 }
1201 return cond;
1202 }
1203
ASC_getRequestedExtNegList(T_ASC_Parameters * params,SOPClassExtendedNegotiationSubItemList ** extNegList)1204 void ASC_getRequestedExtNegList(T_ASC_Parameters* params, SOPClassExtendedNegotiationSubItemList** extNegList)
1205 {
1206 *extNegList = params->DULparams.requestedExtNegList;
1207 }
1208
ASC_getAcceptedExtNegList(T_ASC_Parameters * params,SOPClassExtendedNegotiationSubItemList ** extNegList)1209 void ASC_getAcceptedExtNegList(T_ASC_Parameters* params, SOPClassExtendedNegotiationSubItemList** extNegList)
1210 {
1211 *extNegList = params->DULparams.acceptedExtNegList;
1212 }
1213
ASC_setRequestedExtNegList(T_ASC_Parameters * params,SOPClassExtendedNegotiationSubItemList * extNegList)1214 void ASC_setRequestedExtNegList(T_ASC_Parameters* params, SOPClassExtendedNegotiationSubItemList* extNegList)
1215 {
1216 params->DULparams.requestedExtNegList = extNegList;
1217 }
1218
ASC_setAcceptedExtNegList(T_ASC_Parameters * params,SOPClassExtendedNegotiationSubItemList * extNegList)1219 void ASC_setAcceptedExtNegList(T_ASC_Parameters* params, SOPClassExtendedNegotiationSubItemList* extNegList)
1220 {
1221 params->DULparams.acceptedExtNegList = extNegList;
1222 }
1223
1224
1225 /* User Identity Negotiation */
ASC_getUserIdentRQ(T_ASC_Parameters * params,UserIdentityNegotiationSubItemRQ ** usrIdentRQ)1226 void ASC_getUserIdentRQ(T_ASC_Parameters* params, UserIdentityNegotiationSubItemRQ** usrIdentRQ)
1227 {
1228 *usrIdentRQ = params->DULparams.reqUserIdentNeg;
1229 }
1230
ASC_getUserIdentAC(T_ASC_Parameters * params,UserIdentityNegotiationSubItemAC ** usrIdentAC)1231 void ASC_getUserIdentAC(T_ASC_Parameters* params, UserIdentityNegotiationSubItemAC** usrIdentAC)
1232 {
1233 *usrIdentAC = params->DULparams.ackUserIdentNeg;
1234 }
1235
1236
ASC_setIdentRQUserPassword(T_ASC_Parameters * params,const OFString & userName,const OFString & password,const OFBool requestRsp)1237 OFCondition ASC_setIdentRQUserPassword(
1238 T_ASC_Parameters * params,
1239 const OFString& userName,
1240 const OFString& password,
1241 const OFBool requestRsp)
1242 {
1243 if (params == NULL)
1244 return ASC_NULLKEY;
1245 // length field for user identity content is only 2 bytes -> 65535 bytes max
1246 if ((userName.length() > 65535) || (password.length() > 65535) || (userName.length() + password.length() > 65535))
1247 return EC_IllegalCall;
1248 UserIdentityNegotiationSubItemRQ* rq = params->DULparams.reqUserIdentNeg;
1249 if (rq == NULL)
1250 rq = new UserIdentityNegotiationSubItemRQ();
1251 else
1252 rq->clear();
1253 rq->setIdentityType(ASC_USER_IDENTITY_USER_PASSWORD);
1254 rq->setPrimField(userName.c_str(), OFstatic_cast(Uint16, userName.length()));
1255 rq->setSecField(password.c_str(), OFstatic_cast(Uint16, password.length()));
1256 rq->setReqPosResponse(requestRsp);
1257 params->DULparams.reqUserIdentNeg = rq;
1258 return EC_Normal;
1259 }
1260
1261
ASC_setIdentRQUserOnly(T_ASC_Parameters * params,const OFString & userName,const OFBool requestRsp)1262 OFCondition ASC_setIdentRQUserOnly(
1263 T_ASC_Parameters * params,
1264 const OFString& userName,
1265 const OFBool requestRsp)
1266 {
1267 if (params == NULL)
1268 return ASC_NULLKEY;
1269 // length field for user identity content is only 2 bytes -> 65535 bytes max
1270 if (userName.length() > 65535)
1271 return EC_IllegalCall;
1272 UserIdentityNegotiationSubItemRQ* rq = params->DULparams.reqUserIdentNeg;
1273 if (rq == NULL)
1274 rq = new UserIdentityNegotiationSubItemRQ();
1275 else
1276 rq->clear();
1277 rq->setIdentityType(ASC_USER_IDENTITY_USER);
1278 rq->setPrimField(userName.c_str(), OFstatic_cast(Uint16, userName.length()));
1279 rq->setReqPosResponse(requestRsp);
1280 params->DULparams.reqUserIdentNeg = rq;
1281 return EC_Normal;
1282 }
1283
1284
ASC_setIdentRQKerberos(T_ASC_Parameters * params,const char * kerbTicket,const Uint16 length,const OFBool requestRsp)1285 OFCondition ASC_setIdentRQKerberos(
1286 T_ASC_Parameters * params,
1287 const char* kerbTicket,
1288 const Uint16 length,
1289 const OFBool requestRsp)
1290 {
1291 if (params == NULL)
1292 return ASC_NULLKEY;
1293 UserIdentityNegotiationSubItemRQ* rq = params->DULparams.reqUserIdentNeg;
1294 if (rq == NULL)
1295 rq = new UserIdentityNegotiationSubItemRQ();
1296 else
1297 rq->clear();
1298 rq->setIdentityType(ASC_USER_IDENTITY_KERBEROS);
1299 rq->setPrimField(kerbTicket, length);
1300 rq->setReqPosResponse(requestRsp);
1301 params->DULparams.reqUserIdentNeg = rq;
1302 return EC_Normal;
1303 }
1304
1305
ASC_setIdentRQSaml(T_ASC_Parameters * params,const char * saml,const Uint16 length,const OFBool requestRsp)1306 OFCondition ASC_setIdentRQSaml(
1307 T_ASC_Parameters * params,
1308 const char* saml,
1309 const Uint16 length,
1310 const OFBool requestRsp)
1311 {
1312 if (params == NULL)
1313 return ASC_NULLKEY;
1314 UserIdentityNegotiationSubItemRQ* rq = params->DULparams.reqUserIdentNeg;
1315 if (rq == NULL)
1316 rq = new UserIdentityNegotiationSubItemRQ();
1317 else
1318 rq->clear();
1319 rq->setIdentityType(ASC_USER_IDENTITY_SAML);
1320 rq->setPrimField(saml, length);
1321 rq->setReqPosResponse(requestRsp);
1322 params->DULparams.reqUserIdentNeg = rq;
1323 return EC_Normal;
1324 }
1325
1326
ASC_setIdentRQJwt(T_ASC_Parameters * params,const char * jwt,const Uint16 length,const OFBool requestRsp)1327 OFCondition ASC_setIdentRQJwt(
1328 T_ASC_Parameters * params,
1329 const char* jwt,
1330 const Uint16 length,
1331 const OFBool requestRsp)
1332 {
1333 if (params == NULL)
1334 return ASC_NULLKEY;
1335 UserIdentityNegotiationSubItemRQ* rq = params->DULparams.reqUserIdentNeg;
1336 if (rq == NULL)
1337 rq = new UserIdentityNegotiationSubItemRQ();
1338 else
1339 rq->clear();
1340 rq->setIdentityType(ASC_USER_IDENTITY_JWT);
1341 rq->setPrimField(jwt, length);
1342 rq->setReqPosResponse(requestRsp);
1343 params->DULparams.reqUserIdentNeg = rq;
1344 return EC_Normal;
1345 }
1346
1347
ASC_getCopyOfIdentResponse(T_ASC_Parameters * params,char * & buffer,unsigned short & bufferLen)1348 void ASC_getCopyOfIdentResponse(T_ASC_Parameters * params,
1349 char*& buffer,
1350 unsigned short& bufferLen)
1351 {
1352 if (params == NULL)
1353 {
1354 buffer = NULL;
1355 bufferLen = 0;
1356 return;
1357 }
1358 UserIdentityNegotiationSubItemAC *rsp = params->DULparams.ackUserIdentNeg;
1359 if (rsp == NULL)
1360 {
1361 buffer = NULL;
1362 bufferLen = 0;
1363 return;
1364 }
1365 rsp->getServerResponse(buffer, bufferLen);
1366 return;
1367 }
1368
1369
ASC_setIdentAC(T_ASC_Parameters * params,const char * response,const Uint16 & length)1370 OFCondition ASC_setIdentAC(
1371 T_ASC_Parameters * params,
1372 const char* response,
1373 const Uint16& length )
1374 {
1375 if (params == NULL)
1376 return ASC_NULLKEY;
1377 UserIdentityNegotiationSubItemAC* ac = params->DULparams.ackUserIdentNeg;
1378 if (ac == NULL)
1379 ac = new UserIdentityNegotiationSubItemAC();
1380 else
1381 ac->clear();
1382 if( response != NULL )
1383 ac->setServerResponse(response, length);
1384 params->DULparams.ackUserIdentNeg = ac;
1385 return EC_Normal;
1386 }
1387
1388
1389 static OFString
ASC_dumpPresentationContext(T_ASC_PresentationContext * p)1390 ASC_dumpPresentationContext(T_ASC_PresentationContext * p)
1391 {
1392 int i = 0;
1393 OFOStringStream outstream;
1394
1395 outstream << " Context ID: " << (int)p->presentationContextID << " ";
1396 switch (p->resultReason) {
1397 case ASC_P_ACCEPTANCE:
1398 outstream << "(Accepted)" << OFendl;
1399 break;
1400 case ASC_P_USERREJECTION:
1401 outstream << "(User Rejection)" << OFendl;
1402 break;
1403 case ASC_P_NOREASON:
1404 outstream << "(No Reason)" << OFendl;
1405 break;
1406 case ASC_P_ABSTRACTSYNTAXNOTSUPPORTED:
1407 outstream << "(Abstract Syntax Not Supported)" << OFendl;
1408 break;
1409 case ASC_P_TRANSFERSYNTAXESNOTSUPPORTED:
1410 outstream << "(Transfer Syntaxes Not Supported)" << OFendl;
1411 break;
1412 case ASC_P_NOTYETNEGOTIATED:
1413 outstream << "(Proposed)" << OFendl;
1414 break;
1415 default:
1416 outstream << "(--Invalid Result/Reason--)" << OFendl;
1417 }
1418
1419 const char* l_as = dcmFindNameOfUID(p->abstractSyntax);
1420 if (l_as) {
1421 outstream << " Abstract Syntax: =" << l_as << OFendl;
1422 } else {
1423 outstream << " Abstract Syntax: " << p->abstractSyntax << OFendl;
1424 }
1425
1426 outstream << " Proposed SCP/SCU Role: "
1427 << ASC_role2String(p->proposedRole) << OFendl;
1428
1429 if (p->resultReason != ASC_P_NOTYETNEGOTIATED) {
1430 outstream << " Accepted SCP/SCU Role: "
1431 << ASC_role2String(p->acceptedRole) << OFendl;
1432 }
1433
1434 if (p->resultReason == ASC_P_ACCEPTANCE) {
1435 const char* ts = dcmFindNameOfUID(p->acceptedTransferSyntax);
1436 if (ts) {
1437 outstream << " Accepted Transfer Syntax: =" << ts << OFendl;
1438 } else {
1439 outstream << " Accepted Transfer Syntax: "
1440 << p->acceptedTransferSyntax << OFendl;
1441 }
1442 }
1443
1444 if (p->resultReason == ASC_P_NOTYETNEGOTIATED) {
1445 outstream << " Proposed Transfer Syntax(es):" << OFendl;
1446 for (i = 0; i < (int)p->transferSyntaxCount; i++) {
1447 const char* ts = dcmFindNameOfUID(p->proposedTransferSyntaxes[i]);
1448 if (ts) {
1449 outstream << " =" << ts << OFendl;
1450 } else {
1451 outstream << " " << p->proposedTransferSyntaxes[i] << OFendl;
1452 }
1453 }
1454 }
1455 outstream << OFStringStream_ends;
1456
1457 OFSTRINGSTREAM_GETOFSTRING(outstream, ret)
1458 return ret;
1459 }
1460
1461
1462 OFString&
ASC_dumpParameters(OFString & str,T_ASC_Parameters * params,ASC_associateType dir)1463 ASC_dumpParameters(OFString& str, T_ASC_Parameters * params, ASC_associateType dir)
1464 {
1465 int i;
1466 T_ASC_PresentationContext pc;
1467 OFOStringStream outstream;
1468 OFString temp_str;
1469 const char *str_dir = NULL;
1470
1471 switch (dir)
1472 {
1473 case ASC_ASSOC_RQ:
1474 str_dir = "RQ";
1475 break;
1476 case ASC_ASSOC_AC:
1477 str_dir = "AC";
1478 break;
1479 case ASC_ASSOC_RJ:
1480 str_dir = "RJ";
1481 break;
1482 default:
1483 // Should *NEVER* happen
1484 str_dir = "UNKNOWN";
1485 break;
1486 }
1487
1488 outstream << "====================== BEGIN A-ASSOCIATE-" << str_dir << " =====================" << OFendl
1489 << "Our Implementation Class UID: "
1490 << params->ourImplementationClassUID << OFendl
1491 << "Our Implementation Version Name: "
1492 << params->ourImplementationVersionName << OFendl
1493 << "Their Implementation Class UID: "
1494 << params->theirImplementationClassUID << OFendl
1495 << "Their Implementation Version Name: "
1496 << params->theirImplementationVersionName << OFendl
1497 << "Application Context Name: "
1498 << params->DULparams.applicationContextName << OFendl
1499 << "Calling Application Name: "
1500 << params->DULparams.callingAPTitle << OFendl
1501 << "Called Application Name: "
1502 << params->DULparams.calledAPTitle << OFendl
1503 << "Responding Application Name: ";
1504
1505 // the field "respondingAPTitle" in DULparams exists,
1506 // but is never used for network communication because DICOM
1507 // requires the responding AE title to be identical to the
1508 // called AE title. This rule is enforced on the DUL layer
1509 // but not visible here.
1510 // To avoid confusion of the user we thus print the called
1511 // AE title here (but only if respondingAPTitle is non-empty,
1512 // which happens when an incoming association request is
1513 // being responded to.
1514 if (params->DULparams.respondingAPTitle[0] != '\0')
1515 {
1516 outstream << params->DULparams.calledAPTitle ;
1517 }
1518
1519 outstream
1520 << OFendl
1521 << "Our Max PDU Receive Size: "
1522 << params->ourMaxPDUReceiveSize << OFendl
1523 << "Their Max PDU Receive Size: "
1524 << params->theirMaxPDUReceiveSize << OFendl;
1525
1526 outstream << "Presentation Contexts:" << OFendl;
1527 for (i=0; i<ASC_countPresentationContexts(params); i++) {
1528 ASC_getPresentationContext(params, i, &pc);
1529 outstream << ASC_dumpPresentationContext(&pc);
1530 }
1531
1532 SOPClassExtendedNegotiationSubItemList* extNegList=NULL;
1533 ASC_getRequestedExtNegList(params, &extNegList);
1534 outstream << "Requested Extended Negotiation:";
1535 if (extNegList != NULL) {
1536 outstream << OFendl;
1537 outstream << dumpExtNegList(temp_str, *extNegList);
1538 } else {
1539 outstream << " none" << OFendl;
1540 }
1541
1542 ASC_getAcceptedExtNegList(params, &extNegList);
1543 outstream << "Accepted Extended Negotiation:";
1544 if (extNegList != NULL) {
1545 outstream << OFendl;
1546 outstream << dumpExtNegList(temp_str, *extNegList);
1547 } else {
1548 outstream << " none" << OFendl;
1549 }
1550
1551 UserIdentityNegotiationSubItemRQ *userIdentRQ = NULL;
1552 ASC_getUserIdentRQ(params, &userIdentRQ);
1553 outstream << "Requested User Identity Negotiation:";
1554 if (userIdentRQ != NULL) {
1555 outstream << OFendl;
1556 userIdentRQ->dump(outstream);
1557 } else {
1558 outstream << " none" << OFendl;
1559 }
1560
1561 UserIdentityNegotiationSubItemAC *userIdentAC = NULL;
1562 ASC_getUserIdentAC(params, &userIdentAC);
1563 outstream << "User Identity Negotiation Response:";
1564 if (userIdentAC != NULL) {
1565 outstream << OFendl;
1566 userIdentAC->dump(outstream);
1567 } else {
1568 outstream << " none" << OFendl;
1569 }
1570
1571 #if 0
1572 // the following output could be useful for debugging purposes
1573 outstream << "DUL Params --- BEGIN" << OFendl;
1574 outstream << DUL_DumpParams(temp_str, ¶ms->DULparams);
1575 outstream << "DUL Params --- END" << OFendl;
1576 #endif
1577
1578 outstream << "======================= END A-ASSOCIATE-" << str_dir << " ======================"
1579 << OFStringStream_ends;
1580
1581 OFSTRINGSTREAM_GETSTR(outstream, res)
1582 str = res;
1583 OFSTRINGSTREAM_FREESTR(res)
1584 return str;
1585 }
1586
1587 OFString&
ASC_dumpConnectionParameters(OFString & str,T_ASC_Association * association)1588 ASC_dumpConnectionParameters(OFString &str, T_ASC_Association *association)
1589 {
1590 str.clear();
1591 if (association==NULL) return str;
1592 return DUL_DumpConnectionParameters(str, association->DULassociation);
1593 }
1594
1595 /*
1596 * Extra facility for examining an association for waiting data or
1597 * examining a network for pending association requests.
1598 */
1599
1600 typedef DcmTransportConnection *P_DcmTransportConnection;
1601
1602 OFBool
ASC_selectReadableAssociation(T_ASC_Association * assocs[],int assocCount,int timeout)1603 ASC_selectReadableAssociation(T_ASC_Association* assocs[],
1604 int assocCount, int timeout)
1605 {
1606 if (assocCount <= 0) return OFFalse;
1607
1608 P_DcmTransportConnection *connections = new P_DcmTransportConnection[assocCount];
1609 if (connections == NULL) return OFFalse;
1610
1611 int i;
1612 for (i=0; i<assocCount; i++)
1613 {
1614 if (assocs[i]) connections[i] = DUL_getTransportConnection(assocs[i]->DULassociation);
1615 else connections[i] = NULL;
1616 }
1617 OFBool result = DcmTransportConnection::selectReadableAssociation(connections, assocCount, timeout);
1618 if (result)
1619 {
1620 for (i=0; i<assocCount; i++)
1621 {
1622 if (connections[i]==NULL) assocs[i]=NULL;
1623 }
1624 }
1625 delete[] connections;
1626 return result;
1627 }
1628
1629 OFBool
ASC_dataWaiting(T_ASC_Association * association,int timeout)1630 ASC_dataWaiting(T_ASC_Association * association, int timeout)
1631 {
1632 return DUL_dataWaiting(association->DULassociation, timeout);
1633 }
1634
1635 OFBool
ASC_associationWaiting(T_ASC_Network * network,int timeout)1636 ASC_associationWaiting(T_ASC_Network * network, int timeout)
1637 {
1638 #ifdef _WIN32
1639 SOCKET s;
1640 #else
1641 int s;
1642 #endif
1643 struct timeval t;
1644 int nfound;
1645
1646 if (network == NULL) return OFFalse;
1647
1648 s = DUL_networkSocket(network->network);
1649
1650 #ifdef _WIN32
1651 if (s == INVALID_SOCKET) return OFFalse;
1652 #else
1653 if (s < 0)
1654 return OFFalse;
1655 #endif
1656
1657 #ifndef DCMTK_HAVE_POLL
1658 fd_set fdset;
1659 FD_ZERO(&fdset);
1660 #ifdef __MINGW32__
1661 // on MinGW, FD_SET expects an unsigned first argument
1662 FD_SET((unsigned int) s, &fdset);
1663 #else
1664 FD_SET(s, &fdset);
1665 #endif /* __MINGW32__ */
1666 #endif /* DCMTK_HAVE_POLL */
1667 t.tv_sec = timeout;
1668 t.tv_usec = 0;
1669
1670 #ifdef DCMTK_HAVE_POLL
1671 struct pollfd pfd[] =
1672 {
1673 { s, POLLIN, 0 }
1674 };
1675 nfound = poll(pfd, 1, t.tv_sec*1000+(t.tv_usec/1000));
1676 #else
1677 #ifdef HAVE_INTP_SELECT
1678 nfound = select(OFstatic_cast(int, s + 1), (int *)(&fdset), NULL, NULL, &t);
1679 #else
1680 // the typecast is safe because Windows ignores the first select() parameter anyway
1681 nfound = select(OFstatic_cast(int, s + 1), &fdset, NULL, NULL, &t);
1682 #endif /* HAVE_INTP_SELECT */
1683 #endif /* DCMTK_HAVE_POLL */
1684 if (DCM_dcmnetLogger.isEnabledFor(OFLogger::DEBUG_LOG_LEVEL))
1685 {
1686 DU_logSelectResult(nfound);
1687 }
1688 return nfound > 0;
1689 }
1690
1691 /*
1692 * Association creation and termination
1693 */
1694
1695 OFCondition
ASC_destroyAssociation(T_ASC_Association ** association)1696 ASC_destroyAssociation(T_ASC_Association ** association)
1697 {
1698 OFCondition cond = EC_Normal;
1699
1700 /* don't worry if already destroyed */
1701 if (association == NULL) return EC_Normal;
1702 if (*association == NULL) return EC_Normal;
1703
1704 if ((*association)->DULassociation != NULL) {
1705 ASC_dropAssociation(*association);
1706 }
1707
1708 if ((*association)->params != NULL) {
1709 cond = ASC_destroyAssociationParameters(&(*association)->params);
1710 if (cond.bad()) return cond;
1711 }
1712
1713 if ((*association)->sendPDVBuffer != NULL)
1714 free((*association)->sendPDVBuffer);
1715
1716 free(*association);
1717 *association = NULL;
1718
1719 return EC_Normal;
1720 }
1721
1722 OFCondition
ASC_receiveAssociation(T_ASC_Network * network,T_ASC_Association ** assoc,long maxReceivePDUSize,void ** associatePDU,unsigned long * associatePDUlength,OFBool useSecureLayer,DUL_BLOCKOPTIONS block,int timeout)1723 ASC_receiveAssociation(T_ASC_Network * network,
1724 T_ASC_Association ** assoc,
1725 long maxReceivePDUSize,
1726 void **associatePDU,
1727 unsigned long *associatePDUlength,
1728 OFBool useSecureLayer,
1729 DUL_BLOCKOPTIONS block,
1730 int timeout)
1731 {
1732 T_ASC_Parameters *params;
1733 DUL_ASSOCIATIONKEY *DULassociation;
1734 DUL_PRESENTATIONCONTEXT *pc;
1735 LST_HEAD **l;
1736
1737 int retrieveRawPDU = 0;
1738 if (associatePDU && associatePDUlength) retrieveRawPDU = 1;
1739
1740 OFCondition cond = ASC_createAssociationParameters(¶ms, maxReceivePDUSize);
1741 if (cond.bad()) return cond;
1742
1743 cond = ASC_setTransportLayerType(params, useSecureLayer);
1744 if (cond.bad())
1745 {
1746 ASC_destroyAssociationParameters(¶ms);
1747 return cond;
1748 }
1749
1750 *assoc = (T_ASC_Association *) malloc(sizeof(**assoc));
1751 if (*assoc == NULL)
1752 {
1753 ASC_destroyAssociationParameters(¶ms);
1754 return EC_MemoryExhausted;
1755 }
1756 bzero((char*)*assoc, sizeof(**assoc));
1757
1758 (*assoc)->params = params;
1759 (*assoc)->nextMsgID = 1;
1760
1761 cond = DUL_ReceiveAssociationRQ(&network->network, block, timeout,
1762 &(params->DULparams), &DULassociation, retrieveRawPDU);
1763
1764 if (cond.code() == DULC_FORKEDCHILD)
1765 {
1766 ASC_destroyAssociationParameters(¶ms);
1767 free(*assoc);
1768 *assoc = NULL;
1769 return cond;
1770 }
1771
1772 (*assoc)->DULassociation = DULassociation;
1773
1774 if (retrieveRawPDU && DULassociation)
1775 {
1776 DUL_returnAssociatePDUStorage((*assoc)->DULassociation, *associatePDU, *associatePDUlength);
1777 }
1778
1779 if (cond.bad()) return cond;
1780
1781 /* mark the presentation contexts as being proposed */
1782 l = ¶ms->DULparams.requestedPresentationContext;
1783 if (*l != NULL) {
1784 pc =(DUL_PRESENTATIONCONTEXT*) LST_Head(l);
1785 if (pc != NULL)
1786 (void)LST_Position(l, (LST_NODE*)pc);
1787
1788 while (pc) {
1789 pc->result = ASC_P_NOTYETNEGOTIATED;
1790 pc = (DUL_PRESENTATIONCONTEXT*) LST_Next(l);
1791 }
1792 }
1793
1794 // copy only maximum number of allowed characters
1795 OFStandard::strlcpy(params->theirImplementationClassUID,
1796 params->DULparams.callingImplementationClassUID,
1797 sizeof (params->theirImplementationClassUID));
1798 OFStandard::strlcpy(params->theirImplementationVersionName,
1799 params->DULparams.callingImplementationVersionName,
1800 sizeof (params->theirImplementationVersionName));
1801
1802 /*
1803 * The params->DULparams.peerMaxPDU parameter contains the
1804 * max-pdu-length value in the a-associate-ac (i.e. the max-pdu-length
1805 * that the remote AE is prepared to accept).
1806 */
1807 params->theirMaxPDUReceiveSize = params->DULparams.peerMaxPDU;
1808
1809 /* the PDV buffer and length get set when we acknowledge the association */
1810 (*assoc)->sendPDVLength = 0;
1811 (*assoc)->sendPDVBuffer = NULL;
1812
1813 return EC_Normal;
1814 }
1815
1816 static OFCondition
updateRequestedPCFromAcceptedPC(DUL_PRESENTATIONCONTEXT * apc,DUL_PRESENTATIONCONTEXT * rpc)1817 updateRequestedPCFromAcceptedPC(
1818 DUL_PRESENTATIONCONTEXT *apc,
1819 DUL_PRESENTATIONCONTEXT *rpc)
1820 {
1821 if (apc == NULL || rpc == NULL) return EC_Normal;
1822
1823 if (rpc->presentationContextID != apc->presentationContextID)
1824 {
1825 return makeDcmnetCondition(ASCC_CODINGERROR, OF_error, "ASC Coding error in updateRequestedPCFromAcceptedPC: presentationContextIDs differ");
1826 }
1827
1828 rpc->result = apc->result;
1829 if (apc->result == ASC_P_ACCEPTANCE) {
1830 OFStandard::strlcpy(rpc->acceptedTransferSyntax, apc->acceptedTransferSyntax, sizeof(rpc->acceptedTransferSyntax));
1831 } else {
1832 rpc->acceptedTransferSyntax[0] = '\0';
1833 }
1834 rpc->acceptedSCRole = apc->acceptedSCRole;
1835 return EC_Normal;
1836 }
1837
1838
1839 static OFCondition
updateRequestedPCListFromAcceptedPCList(DUL_ASSOCIATESERVICEPARAMETERS * dulParams)1840 updateRequestedPCListFromAcceptedPCList(
1841 DUL_ASSOCIATESERVICEPARAMETERS *dulParams)
1842 {
1843 OFCondition cond = EC_Normal;
1844 DUL_PRESENTATIONCONTEXT *requestedPc = NULL;
1845 DUL_PRESENTATIONCONTEXT *acceptedPc = NULL;
1846 LST_HEAD **acceptedList = NULL;
1847
1848 acceptedList = &dulParams->acceptedPresentationContext;
1849 if (*acceptedList != NULL) {
1850 acceptedPc =(DUL_PRESENTATIONCONTEXT*) LST_Head(acceptedList);
1851 if (acceptedPc != NULL)
1852 (void)LST_Position(acceptedList, (LST_NODE*)acceptedPc);
1853
1854 while (acceptedPc)
1855 {
1856 requestedPc = findPresentationContextID(
1857 dulParams->requestedPresentationContext,
1858 acceptedPc->presentationContextID);
1859 cond = updateRequestedPCFromAcceptedPC(acceptedPc, requestedPc);
1860 if (cond.bad()) return cond;
1861 acceptedPc = (DUL_PRESENTATIONCONTEXT*) LST_Next(acceptedList);
1862 if (acceptedPc != NULL)
1863 (void)LST_Position(acceptedList, (LST_NODE*)acceptedPc);
1864 }
1865 }
1866 return cond;
1867 }
1868
1869 OFCondition
ASC_requestAssociation(T_ASC_Network * network,T_ASC_Parameters * params,T_ASC_Association ** assoc,void ** associatePDU,unsigned long * associatePDUlength,DUL_BLOCKOPTIONS block,int timeout)1870 ASC_requestAssociation(T_ASC_Network * network,
1871 T_ASC_Parameters * params,
1872 T_ASC_Association ** assoc,
1873 void **associatePDU,
1874 unsigned long *associatePDUlength,
1875 DUL_BLOCKOPTIONS block,
1876 int timeout)
1877 {
1878 OFCondition cond = EC_Normal;
1879 long sendLen;
1880 int retrieveRawPDU = 0;
1881 if (associatePDU && associatePDUlength) retrieveRawPDU = 1;
1882
1883 if (network == NULL) return ASC_NULLKEY;
1884 if (params == NULL) return ASC_NULLKEY;
1885
1886 if (ASC_countPresentationContexts(params) == 0)
1887 {
1888 return makeDcmnetCondition(ASCC_CODINGERROR, OF_error, "ASC Coding error in ASC_requestAssociation: missing presentation contexts");
1889 }
1890
1891 *assoc = (T_ASC_Association *) malloc(sizeof(**assoc));
1892 if (*assoc == NULL) return EC_MemoryExhausted;
1893 bzero((char*)*assoc, sizeof(**assoc));
1894
1895 (*assoc)->params = params;
1896 (*assoc)->nextMsgID = 1;
1897 (*assoc)->sendPDVLength = 0;
1898 (*assoc)->sendPDVBuffer = NULL;
1899
1900 params->DULparams.maxPDU = params->ourMaxPDUReceiveSize;
1901 OFStandard::strlcpy(params->DULparams.callingImplementationClassUID,
1902 params->ourImplementationClassUID, DICOM_UI_LENGTH + 1);
1903 OFStandard::strlcpy(params->DULparams.callingImplementationVersionName,
1904 params->ourImplementationVersionName, 16+1);
1905
1906 cond = DUL_RequestAssociation(&network->network, block, timeout,
1907 &(*assoc)->params->DULparams,
1908 &(*assoc)->DULassociation,
1909 retrieveRawPDU);
1910
1911
1912 if (retrieveRawPDU && assoc && ((*assoc)->DULassociation))
1913 {
1914 DUL_returnAssociatePDUStorage((*assoc)->DULassociation, *associatePDU, *associatePDUlength);
1915 }
1916
1917 if (cond.good())
1918 {
1919 /*
1920 * The params->DULparams.peerMaxPDU parameter contains the
1921 * max-pdu-length value in the a-associate-ac (i.e. the max-pdu-length
1922 * that the remote AE is prepared to accept).
1923 */
1924 params->theirMaxPDUReceiveSize = params->DULparams.peerMaxPDU;
1925
1926 if (!((params->theirMaxPDUReceiveSize & DUL_MAXPDUCOMPAT) ^ DUL_DULCOMPAT))
1927 {
1928 /* activate compatibility with DCMTK releases prior to 3.0 */
1929 DUL_activateCompatibilityMode((*assoc)->DULassociation, dcmEnableBackwardCompatibility.get() | DUL_DULCOMPAT | DUL_DIMSECOMPAT);
1930 if (params->modeCallback) params->modeCallback->callback(params->theirMaxPDUReceiveSize);
1931 }
1932
1933 /* create a sendPDVBuffer */
1934 sendLen = params->theirMaxPDUReceiveSize;
1935 if (sendLen < 1) {
1936 /* the length is unlimited, choose a suitable buffer len */
1937 sendLen = ASC_MAXIMUMPDUSIZE;
1938 } else if (sendLen > ASC_MAXIMUMPDUSIZE) {
1939 sendLen = ASC_MAXIMUMPDUSIZE;
1940 }
1941 /* make sure max pdv length is even */
1942 if ((sendLen % 2) != 0)
1943 {
1944 DCMNET_WARN("ASSOC: PDV send length " << sendLen
1945 << " is odd (using " << (sendLen-1) << ")");
1946 sendLen--;
1947 }
1948 /* length is minus PDU and PDV header bytes */
1949 sendLen -= 12;
1950 if (sendLen < 1)
1951 {
1952 DCMNET_WARN("ASSOC: PDV send length " << sendLen << " (using default)");
1953 sendLen = ASC_MINIMUMPDUSIZE - 12;
1954 }
1955 if (sendLen < 12)
1956 {
1957 /* if sendLen is < 12, dcmdata will fail because it needs to put
1958 * up to 12 bytes into the send PDV buffer at once (tag header).
1959 * We use a larger value on this level and let the Upper Layer FSM
1960 * split the buffer for us into many small PDVs.
1961 */
1962 DCMNET_WARN("ASSOC: PDV send length too small, using DUL to split larger PDVs.");
1963 sendLen = ASC_MINIMUMPDUSIZE - 12;
1964 }
1965 (*assoc)->sendPDVLength = sendLen;
1966 (*assoc)->sendPDVBuffer = (unsigned char*)malloc(size_t(sendLen));
1967 if ((*assoc)->sendPDVBuffer == NULL) return EC_MemoryExhausted;
1968 OFStandard::strlcpy(params->theirImplementationClassUID,
1969 params->DULparams.calledImplementationClassUID, sizeof(params->theirImplementationClassUID));
1970 OFStandard::strlcpy(params->theirImplementationVersionName,
1971 params->DULparams.calledImplementationVersionName, sizeof(params->theirImplementationVersionName));
1972
1973 /* make sure accepted PCs are marked as such in the requested PC list */
1974 cond = updateRequestedPCListFromAcceptedPCList(¶ms->DULparams);
1975 }
1976 return cond;
1977 }
1978
1979 OFCondition
ASC_acknowledgeAssociation(T_ASC_Association * assoc,void ** associatePDU,unsigned long * associatePDUlength)1980 ASC_acknowledgeAssociation(
1981 T_ASC_Association * assoc,
1982 void **associatePDU,
1983 unsigned long *associatePDUlength)
1984 {
1985 long sendLen;
1986
1987 if (assoc == NULL) return ASC_NULLKEY;
1988 if (assoc->DULassociation == NULL) return ASC_NULLKEY;
1989
1990 int retrieveRawPDU = 0;
1991 if (associatePDU && associatePDUlength) retrieveRawPDU = 1;
1992
1993 assoc->params->DULparams.maxPDU = assoc->params->ourMaxPDUReceiveSize;
1994 if (!((assoc->params->theirMaxPDUReceiveSize & DUL_MAXPDUCOMPAT) ^ DUL_DULCOMPAT))
1995 {
1996 assoc->params->DULparams.maxPDU = dcmEnableBackwardCompatibility.get() | DUL_DULCOMPAT | DUL_DIMSECOMPAT;
1997 }
1998
1999 OFStandard::strlcpy(assoc->params->DULparams.calledImplementationClassUID,
2000 assoc->params->ourImplementationClassUID, sizeof(assoc->params->DULparams.calledImplementationClassUID));
2001 OFStandard::strlcpy(assoc->params->DULparams.calledImplementationVersionName,
2002 assoc->params->ourImplementationVersionName, sizeof(assoc->params->DULparams.calledImplementationVersionName));
2003
2004 OFCondition cond = DUL_AcknowledgeAssociationRQ(&assoc->DULassociation,
2005 &assoc->params->DULparams,
2006 retrieveRawPDU);
2007
2008 if (retrieveRawPDU && (assoc->DULassociation))
2009 {
2010 DUL_returnAssociatePDUStorage(assoc->DULassociation, *associatePDU, *associatePDUlength);
2011 }
2012
2013 if (cond.good())
2014 {
2015 /* create a sendPDVBuffer */
2016 sendLen = assoc->params->theirMaxPDUReceiveSize;
2017 if (sendLen < 1) {
2018 /* the length is unlimited, choose a suitable buffer len */
2019 sendLen = ASC_MAXIMUMPDUSIZE;
2020 } else if (sendLen > ASC_MAXIMUMPDUSIZE) {
2021 sendLen = ASC_MAXIMUMPDUSIZE;
2022 }
2023 /* make sure max pdv length is even */
2024 if ((sendLen % 2) != 0)
2025 {
2026 DCMNET_WARN("ASSOC: PDV send length " << sendLen
2027 << " is odd (using " << (sendLen-1) << ")");
2028 sendLen--;
2029 }
2030 /* length is minus PDU and PDV header bytes */
2031 sendLen -= 12;
2032 if (sendLen < 1)
2033 {
2034 DCMNET_WARN("ASSOC: PDV send length " << sendLen
2035 << " (using default)");
2036 sendLen = ASC_MINIMUMPDUSIZE - 12;
2037 }
2038 if (sendLen < 12)
2039 {
2040 /* if sendLen is < 12, dcmdata will fail because it needs to put
2041 * up to 12 bytes into the send PDV buffer at once (tag header).
2042 * We use a larger value on this level and let the Upper Layer FSM
2043 * split the buffer for us into many small PDVs.
2044 */
2045 DCMNET_WARN("ASSOC: PDV send length too small, using DUL to split larger PDVs.");
2046 sendLen = ASC_MINIMUMPDUSIZE - 12;
2047 }
2048 assoc->sendPDVLength = sendLen;
2049 assoc->sendPDVBuffer = (unsigned char*)malloc(size_t(sendLen));
2050 if (assoc->sendPDVBuffer == NULL) return EC_MemoryExhausted;
2051 }
2052 return cond;
2053 }
2054
2055 OFCondition
ASC_rejectAssociation(T_ASC_Association * association,const T_ASC_RejectParameters * rejectParameters,void ** associatePDU,unsigned long * associatePDUlength)2056 ASC_rejectAssociation(
2057 T_ASC_Association * association,
2058 const T_ASC_RejectParameters * rejectParameters,
2059 void **associatePDU,
2060 unsigned long *associatePDUlength)
2061 {
2062 DUL_ABORTITEMS l_abort;
2063
2064 if (association == NULL) return ASC_NULLKEY;
2065 if (association->DULassociation == NULL) return ASC_NULLKEY;
2066 if (rejectParameters == NULL) return ASC_NULLKEY;
2067
2068 int retrieveRawPDU = 0;
2069 if (associatePDU && associatePDUlength) retrieveRawPDU = 1;
2070
2071 l_abort.result = (unsigned char)(rejectParameters->result & 0xff);
2072 l_abort.source = (unsigned char)(rejectParameters->source & 0xff);
2073 l_abort.reason = (unsigned char)(rejectParameters->reason & 0xff);
2074
2075 OFCondition cond = DUL_RejectAssociationRQ(
2076 &association->DULassociation,
2077 &l_abort,
2078 retrieveRawPDU);
2079
2080 if (retrieveRawPDU && (association->DULassociation))
2081 {
2082 DUL_returnAssociatePDUStorage(association->DULassociation, *associatePDU, *associatePDUlength);
2083 }
2084
2085 return cond;
2086 }
2087
2088 OFCondition
ASC_releaseAssociation(T_ASC_Association * association)2089 ASC_releaseAssociation(T_ASC_Association * association)
2090 {
2091 if (association == NULL) return ASC_NULLKEY;
2092 if (association->DULassociation == NULL) return ASC_NULLKEY;
2093 return DUL_ReleaseAssociation(&association->DULassociation);
2094 }
2095
ASC_acknowledgeRelease(T_ASC_Association * association)2096 OFCondition ASC_acknowledgeRelease(T_ASC_Association *association)
2097 {
2098 if (association == NULL) return ASC_NULLKEY;
2099 if (association->DULassociation == NULL) return ASC_NULLKEY;
2100
2101 OFCondition cond = DUL_AcknowledgeRelease(&association->DULassociation);
2102
2103 return cond;
2104 }
2105
2106
2107 OFCondition
ASC_abortAssociation(T_ASC_Association * association)2108 ASC_abortAssociation(T_ASC_Association * association)
2109 {
2110 if (association == NULL) return ASC_NULLKEY;
2111 if (association->DULassociation == NULL) return ASC_NULLKEY;
2112
2113 OFCondition cond = DUL_AbortAssociation(&association->DULassociation);
2114 return cond;
2115 }
2116
2117
2118
2119 OFCondition
ASC_dropSCPAssociation(T_ASC_Association * association,int timeout)2120 ASC_dropSCPAssociation(T_ASC_Association * association, int timeout)
2121 {
2122 /* if already dead don't worry */
2123 if (association == NULL) return EC_Normal;
2124 if (association->DULassociation == NULL) return EC_Normal;
2125
2126 ASC_dataWaiting(association, timeout);
2127 OFCondition cond = DUL_DropAssociation(&association->DULassociation);
2128
2129 return cond;
2130 }
2131
2132
2133
2134 OFCondition
ASC_dropAssociation(T_ASC_Association * association)2135 ASC_dropAssociation(T_ASC_Association * association)
2136 {
2137 /* if already dead don't worry */
2138 if (association == NULL) return EC_Normal;
2139 if (association->DULassociation == NULL) return EC_Normal;
2140
2141 OFCondition cond = DUL_DropAssociation(&association->DULassociation);
2142 return cond;
2143 }
2144
2145
2146
2147 OFCondition
ASC_setTransportLayerType(T_ASC_Parameters * params,OFBool useSecureLayer)2148 ASC_setTransportLayerType(
2149 T_ASC_Parameters * params,
2150 OFBool useSecureLayer)
2151 {
2152 if (params == NULL) return ASC_NULLKEY;
2153 params->DULparams.useSecureLayer = useSecureLayer;
2154 return EC_Normal;
2155 }
2156
2157 OFCondition
ASC_setTransportLayer(T_ASC_Network * network,DcmTransportLayer * newLayer,int takeoverOwnership)2158 ASC_setTransportLayer(T_ASC_Network *network, DcmTransportLayer *newLayer, int takeoverOwnership)
2159 {
2160 if (network == NULL) return ASC_NULLKEY;
2161 return DUL_setTransportLayer(network->network, newLayer, takeoverOwnership);
2162 }
2163
ASC_getPeerCertificateLength(T_ASC_Association * assoc)2164 unsigned long ASC_getPeerCertificateLength(T_ASC_Association *assoc)
2165 {
2166 if (assoc==NULL) return 0;
2167 return DUL_getPeerCertificateLength(assoc->DULassociation);
2168 }
2169
ASC_getPeerCertificate(T_ASC_Association * assoc,void * buf,unsigned long bufLen)2170 unsigned long ASC_getPeerCertificate(T_ASC_Association *assoc, void *buf, unsigned long bufLen)
2171 {
2172 if (assoc==NULL) return 0;
2173 return DUL_getPeerCertificate(assoc->DULassociation, buf, bufLen);
2174 }
2175
ASC_activateCallback(T_ASC_Parameters * params,DUL_ModeCallback * cb)2176 void ASC_activateCallback(T_ASC_Parameters *params, DUL_ModeCallback *cb)
2177 {
2178 if (params) params->modeCallback = cb;
2179 }
2180
2181
2182 // Deprecated wrapper functions follow
ASC_printRejectParameters(FILE * f,const T_ASC_RejectParameters * rej)2183 void ASC_printRejectParameters(FILE *f, const T_ASC_RejectParameters *rej)
2184 {
2185 OFString str;
2186 ASC_printRejectParameters(str, rej);
2187 fprintf(f, "%s\n", str.c_str());
2188 }
2189
ASC_printRejectParameters(STD_NAMESPACE ostream & out,const T_ASC_RejectParameters * rej)2190 void ASC_printRejectParameters(STD_NAMESPACE ostream& out, const T_ASC_RejectParameters *rej)
2191 {
2192 OFString str;
2193 ASC_printRejectParameters(str, rej);
2194 out << str << OFendl;
2195 }
2196
2197 void
ASC_dumpParameters(T_ASC_Parameters * params,STD_NAMESPACE ostream & outstream)2198 ASC_dumpParameters(T_ASC_Parameters * params, STD_NAMESPACE ostream& outstream)
2199 {
2200 OFString str;
2201 // FIXME: ASC_ASSOC_AC is just a weird, wrong guess
2202 ASC_dumpParameters(str, params, ASC_ASSOC_AC);
2203 outstream << str << OFendl;
2204 }
2205
2206 void
ASC_dumpPresentationContext(T_ASC_PresentationContext * presentationContext,STD_NAMESPACE ostream & outstream)2207 ASC_dumpPresentationContext(T_ASC_PresentationContext * presentationContext, STD_NAMESPACE ostream& outstream)
2208 {
2209 outstream << ASC_dumpPresentationContext(presentationContext) << OFendl;
2210 }
2211
2212 void
ASC_dumpConnectionParameters(T_ASC_Association * association,STD_NAMESPACE ostream & outstream)2213 ASC_dumpConnectionParameters(T_ASC_Association *association, STD_NAMESPACE ostream& outstream)
2214 {
2215 OFString str;
2216 ASC_dumpConnectionParameters(str, association);
2217 outstream << str << OFendl;
2218 }
2219