/*========================================================================= * * Copyright NumFOCUS * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0.txt * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * *=========================================================================*/ #include "gdcmULConnection.h" #include // std::find #include namespace gdcm { namespace network { ULConnection::ULConnection(const ULConnectionInfo& inConnectInfo) { mCurrentState = eSta1Idle; mSocket = nullptr; mEcho = nullptr; mInfo = inConnectInfo; TransferSyntaxSub ts1; ts1.SetNameFromUID( UIDs::ImplicitVRLittleEndianDefaultTransferSyntaxforDICOM ); SetCStoreTransferSyntax( ts1 ); } ULConnection::~ULConnection() { if (mEcho != nullptr) { delete mEcho; mEcho = nullptr; } if (mSocket != nullptr) { delete mSocket; mSocket = nullptr; } } EStateID ULConnection::GetState() const { return mCurrentState; } void ULConnection::SetState(const EStateID& inState) { mCurrentState = inState; } //echo* ULConnection::GetProtocol(){ std::iostream* ULConnection::GetProtocol() { if (mEcho) { return mEcho; } //be careful-- the socket doesn't get removed when the protocol is stopped, //because then subsequent cstores will break. if (mSocket) { return mSocket; } return nullptr; } ARTIMTimer& ULConnection::GetTimer() { return mTimer; } const ULConnectionInfo &ULConnection::GetConnectionInfo() const { return mInfo; } void ULConnection::SetMaxPDUSize(uint32_t inSize) { mMaxPDUSize = inSize; } uint32_t ULConnection::GetMaxPDUSize() const { return mMaxPDUSize; } std::vector const & ULConnection::GetPresentationContexts() const { return mPresentationContexts; } void ULConnection::SetPresentationContexts( const std::vector& inContexts) { mPresentationContexts.clear(); for( size_t i = 0; i < inContexts.size(); ++i ) { PresentationContext const &in = inContexts[i]; mPresentationContexts.emplace_back(in ); } } void ULConnection::SetPresentationContexts( const std::vector& inContexts) { mPresentationContexts = inContexts; } std::vector & ULConnection::GetAcceptedPresentationContexts() { return mAcceptedPresentationContexts; } std::vector const & ULConnection::GetAcceptedPresentationContexts() const { return mAcceptedPresentationContexts; } void ULConnection::AddAcceptedPresentationContext(const PresentationContextAC& inPC) { mAcceptedPresentationContexts.push_back(inPC); } //given a particular data element, presumably the SOP class, //find the presentation context for that SOP //NOT YET IMPLEMENTED PresentationContextRQ ULConnection::FindContext(const DataElement& ) const { PresentationContextRQ empty; assert( 0 && "TODO" ); return empty; } bool ULConnection::InitializeConnection() { try { echo* p = new echo(protocol::tcp); if (GetConnectionInfo().GetCalledIPPort() == 0) { if (!GetConnectionInfo().GetCalledComputerName().empty()) (*p)->connect(GetConnectionInfo().GetCalledComputerName().c_str()); else (*p)->connect(GetConnectionInfo().GetCalledIPAddress()); } else { if (!GetConnectionInfo().GetCalledComputerName().empty()) (*p)->connect(GetConnectionInfo().GetCalledComputerName().c_str(), GetConnectionInfo().GetCalledIPPort()); } //make sure to convert timeouts to platform appropriate values. (*p)->recvtimeout((int)GetTimer().GetTimeout()); (*p)->sendtimeout((int)GetTimer().GetTimeout()); if (mEcho != nullptr) { delete mEcho; mEcho = nullptr; } if (mSocket != nullptr) { delete mSocket; mSocket = nullptr; } mEcho = p; } catch ( sockerr &err ) { (void)err; //to avoid unreferenced variable warning on release gdcmWarningMacro( "Unable to open connection with exception " << err.what() << std::endl ); return false; } catch (std::exception& ex) { (void)ex; //to avoid unreferenced variable warning on release //unable to establish connection, so break off. gdcmWarningMacro( "Unable to open connection with exception " << ex.what() << std::endl ); return false; } return true; } bool ULConnection::InitializeIncomingConnection() { try { if (mEcho != nullptr) { delete mEcho; mEcho = nullptr; } if (mSocket != nullptr) { delete mSocket; mSocket = nullptr; } sockinetbuf sin (sockbuf::sock_stream); // http://hea-www.harvard.edu/~fine/Tech/addrinuse.html int val = 1; sin.setopt( SO_REUSEADDR, &val, sizeof(val) ); sin.bind( mInfo.GetCalledIPPort() ); //int theRecvTimeout = sin.recvtimeout(60);//(int)GetTimer().GetTimeout()); //int theSendTimeout = sin.sendtimeout(60);//(int)GetTimer().GetTimeout()); sin.listen(); //sin.debug( true ); if (sin.is_readready(60, 0)) { mSocket = new iosockinet(sin.accept()); } else { gdcmDebugMacro( "Call to is_readready failed" ); SetState(eStaDoesNotExist); return false; //no connection here, so have to initialize later. } SetState(eSta2Open); /* if (mSocket != NULL){ delete mSocket; } mSocket = new protocol(); sockinetaddr theAddy(GetConnectionInfo().GetCalledComputerName().c_str(), GetConnectionInfo().GetCalledIPPort()); mSocket->rdbuf()->connect(theAddy); mSocket->rdbuf()->recvtimeout((int)GetTimer().GetTimeout()); mSocket->rdbuf()->sendtimeout((int)GetTimer().GetTimeout()); */ } catch (sockerr& ex) { //unable to establish connection, so break off. (void)ex; //to avoid unreferenced variable warning on release gdcmErrorMacro("Unable to open connection with exception " << ex.what() << " and " << ex.operation() << " on port: " << mInfo.GetCalledIPPort() << std::endl); return false; } catch (std::exception& ex) { //unable to establish connection, so break off. (void)ex; //to avoid unreferenced variable warning on release gdcmErrorMacro("Unable to open connection with exception " << ex.what() << std::endl); return false; } return true; } void ULConnection::StopProtocol() { if (mEcho != nullptr) { delete mEcho; mEcho = nullptr; SetState(eSta1Idle); } else { //don't actually kill the connection, just kill the association. //this is just for a cstorescp initialized by a cmove SetState(eSta2Open); } } const PresentationContextRQ *ULConnection::GetPresentationContextRQByID(uint8_t id) const { // one day ULConnection will actually use a AAssociateRQPDU as internal implementation // for now duplicate code from AAssociateRQPDU::GetPresentationContextFromAbstractSyntax std::vector::const_iterator it = mPresentationContexts.begin(); for( ; it != mPresentationContexts.end(); ++it) { if( it->GetPresentationContextID() == id ) { return &*it; } } return nullptr; } const PresentationContextAC *ULConnection::GetPresentationContextACByID(uint8_t id) const { // one day ULConnection will actually use a AAssociateRQPDU as internal implementation // for now duplicate code from AAssociateRQPDU::GetPresentationContextFromAbstractSyntax std::vector::const_iterator it = mAcceptedPresentationContexts.begin(); for( ; it != mAcceptedPresentationContexts.end(); ++it) { if( it->GetPresentationContextID() == id ) { return &*it; } } return nullptr; } uint8_t ULConnection::GetPresentationContextIDFromPresentationContext(PresentationContextRQ const & pc) const { // one day ULConnection will actually use a AAssociateRQPDU as internal implementation // for now duplicate code from AAssociateRQPDU::GetPresentationContextIDFromAbstractSyntax uint8_t ret = 0; std::vector::const_iterator it = std::find( mPresentationContexts.begin(), mPresentationContexts.end(), pc ); if( it != mPresentationContexts.end() ) { ret = it->GetPresentationContextID(); } assert( ret ); return ret; } void ULConnection::SetCStoreTransferSyntax( TransferSyntaxSub const & ts ) { cstorets = ts; } TransferSyntaxSub const & ULConnection::GetCStoreTransferSyntax( ) const { TransferSyntaxSub ts1; ts1.SetNameFromUID( UIDs::ImplicitVRLittleEndianDefaultTransferSyntaxforDICOM ); TransferSyntaxSub ts2; ts2.SetNameFromUID( UIDs::ExplicitVRLittleEndian ); assert( strcmp(cstorets.GetName(), ts1.GetName()) == 0 || strcmp(cstorets.GetName(), ts2.GetName()) == 0 ); return cstorets; } } // end namespace network } // end namespace gdcm