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, &params->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(&params, maxReceivePDUSize);
1741     if (cond.bad()) return cond;
1742 
1743     cond = ASC_setTransportLayerType(params, useSecureLayer);
1744     if (cond.bad())
1745     {
1746         ASC_destroyAssociationParameters(&params);
1747         return cond;
1748     }
1749 
1750     *assoc = (T_ASC_Association *) malloc(sizeof(**assoc));
1751     if (*assoc == NULL)
1752     {
1753         ASC_destroyAssociationParameters(&params);
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(&params);
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 = &params->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(&params->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