@@ -1381,6 +1381,7 @@ def build_user_information(max_pdu_length: int = 16384,
13811381 return DICOMVariableItem () / DICOMUserInformation (sub_items = sub_items )
13821382
13831383
1384+ class DICOMSocket :
13841385 """DICOM application-layer socket for associations and DIMSE operations."""
13851386
13861387 def __init__ (self , dst_ip : str , dst_port : int , dst_ae : str ,
@@ -1406,6 +1407,7 @@ def _normalize_ae_title(title: Union[str, bytes]) -> bytes:
14061407 if isinstance (title , bytes ):
14071408 return title .ljust (16 , b" " )[:16 ]
14081409 return title .encode ("ascii" ).ljust (16 , b" " )[:16 ]
1410+
14091411 def __enter__ (self ) -> "DICOMSocket" :
14101412 return self
14111413
@@ -1506,27 +1508,34 @@ def associate(self, requested_contexts: Optional[Dict[str, List[str]]] = None
15061508 log .error ("Association failed: no valid response received" )
15071509 return False
15081510
1509- def _parse_max_pdu_length (self , response ) :
1511+ def _parse_max_pdu_length (self , response : Packet ) -> None :
15101512 try :
15111513 for item in response [A_ASSOCIATE_AC ].variable_items :
15121514 if item .item_type == 0x50 :
15131515 if item .haslayer (DICOMUserInformation ):
15141516 user_info = item [DICOMUserInformation ]
15151517 for sub_item in user_info .sub_items :
1518+ if sub_item .item_type == 0x51 :
1519+ if sub_item .haslayer (DICOMMaximumLength ):
1520+ max_len = sub_item [DICOMMaximumLength ]
1521+ server_max = max_len .max_pdu_length
1522+ self .max_pdu_length = min (
1523+ self ._proposed_max_pdu , server_max
1524+ )
1525+ return
1526+ except (KeyError , IndexError , AttributeError ):
15161527 pass
15171528 self .max_pdu_length = self ._proposed_max_pdu
15181529
15191530 def _parse_accepted_contexts (self , response : Packet ) -> None :
15201531 for item in response [A_ASSOCIATE_AC ].variable_items :
1521- pctx = item [DICOMPresentationContextAC ]
1522- ctx_id = pctx .context_id
1523- "Server accepted context ID %d which we didn't propose!" ,
1524- ctx_id
1525- )
1526- continue
1527- break
1528-
1529- def _get_next_message_id (self ):
1532+ if item .item_type == 0x21 :
1533+ if item .haslayer (DICOMPresentationContextAC ):
1534+ pctx = item [DICOMPresentationContextAC ]
1535+ ctx_id = pctx .context_id
1536+ result = pctx .result
1537+
1538+ if result != 0 :
15301539 continue
15311540
15321541 abs_syntax = self ._proposed_context_map .get (ctx_id )
@@ -1535,6 +1544,10 @@ def _get_next_message_id(self):
15351544
15361545 for sub_item in pctx .sub_items :
15371546 if sub_item .item_type == 0x40 :
1547+ if sub_item .haslayer (DICOMTransferSyntax ):
1548+ ts_uid = sub_item [DICOMTransferSyntax ].uid
1549+ if isinstance (ts_uid , bytes ):
1550+ ts_uid = ts_uid .rstrip (b"\x00 " )
15381551 ts_uid = ts_uid .decode ("ascii" )
15391552 self .accepted_contexts [ctx_id ] = (
15401553 abs_syntax , ts_uid
@@ -1547,6 +1560,7 @@ def _get_next_message_id(self) -> int:
15471560
15481561 def _find_accepted_context_id (self , sop_class_uid : str ,
15491562 transfer_syntax_uid : Optional [str ] = None
1563+ ) -> Optional [int ]:
15501564 for ctx_id , (abs_syntax , ts_syntax ) in self .accepted_contexts .items ():
15511565 if abs_syntax == sop_class_uid :
15521566 if transfer_syntax_uid is None or transfer_syntax_uid == ts_syntax :
0 commit comments