<commit_before>#include "upperlayer_connection.hpp"


#include <utility>
#include <vector>
#include <ostream>
#include <cassert>
#include <initializer_list>
#include <chrono>
#include <deque>
#include <functional>
#include <exception>

#include <boost/optional.hpp>
#include <boost/asio.hpp>

#include "upperlayer_properties.hpp"


namespace dicom
{

namespace network
{

namespace upperlayer
{

namespace
{
using uchar = unsigned char;

std::size_t be_char_to_16b(std::vector<uchar> bs)
{
   assert(bs.size() == 2);
   std::size_t sz = 0;
   sz |= (static_cast<std::size_t>(bs[0]) << 8);
   sz |= (static_cast<std::size_t>(bs[1]));
   return sz;
}
std::size_t be_char_to_32b(std::vector<uchar> bs)
{
   assert(bs.size() == 4);
   std::size_t sz = 0;
   sz |= (static_cast<std::size_t>(bs[0]) << 24);
   sz |= (static_cast<std::size_t>(bs[1]) << 16);
   sz |= (static_cast<std::size_t>(bs[2]) << 8);
   sz |= (static_cast<std::size_t>(bs[3]));
   return sz;
}

}

Istate_trans_ops::~Istate_trans_ops()
{
}

Iupperlayer_comm_ops::~Iupperlayer_comm_ops()
{
}

using namespace dicom::util::log;



scx::scx(data::dictionary::dictionary& dict,
         std::vector<std::pair<TYPE, std::function<void(scx*, std::unique_ptr<property>)>>> l):
   statem {this},
   logger {"upperlayer"},
   proc {data::dataset::commandset_processor {dict}},
   received_pdu {boost::none},
   handlers {},
   shutdown_requested {false}
{
   for (const auto p : l) {
      handlers[p.first] = p.second;
   }
}

scx::~scx()
{
   // closing of the connection may only be done when there are no
   // outstanding operations
}


void scx::send(property* p)
{
   auto pdu = std::make_shared<std::vector<unsigned char>>(p->make_pdu());
   auto ptype = get_type(*pdu);

   statemachine::EVENT e;
   switch (ptype) {
      case TYPE::A_ABORT:
         e = statemachine::EVENT::LOCL_A_ABORT_PDU;
         break;
      case TYPE::A_ASSOCIATE_AC:
         e = statemachine::EVENT::LOCL_A_ASSOCIATE_AC_PDU;
         break;
      case TYPE::A_ASSOCIATE_RJ:
         e = statemachine::EVENT::LOCL_A_ASSOCIATE_RJ_PDU;
         break;
      case TYPE::A_ASSOCIATE_RQ:
         assert(false);
         break;
      case TYPE::A_RELEASE_RQ:
         e = statemachine::EVENT::LOCL_A_RELEASE_RQ_PDU;
         break;
      case TYPE::A_RELEASE_RP:
         e = statemachine::EVENT::LOCL_A_RELEASE_RP_PDU;
         break;
      case TYPE::P_DATA_TF:
         e = statemachine::EVENT::LOCL_P_DATA_TF_PDU;
         break;
      default:
         e = statemachine::EVENT::UNRECOG_PDU;
   }

   if (statem.transition(e) != statemachine::CONN_STATE::INV) {
      // call async_write after each sent property until the queue is
      // empty
      if (ptype != TYPE::P_DATA_TF) {
         boost::asio::async_write(sock(), boost::asio::buffer(*pdu),
            [this, p, ptype](const boost::system::error_code& error, std::size_t bytes) {
               if (error) {
                  throw boost::system::system_error(error);
               }

               BOOST_LOG_SEV(logger, trace) << "Sent PDU of size " << bytes;
               BOOST_LOG_SEV(logger, info) << "Sent property of type " << ptype;
               BOOST_LOG_SEV(logger, debug) << "Property info: \n" << *p;
               handle_pdu_conf(p, ptype);
         });
      } else {
         auto pdataprop = dynamic_cast<p_data_tf*>(p);
         assert(pdataprop);

         std::size_t len = be_char_to_32b({pdu->begin()+6, pdu->begin()+10});
         auto commandset = std::make_shared<std::vector<unsigned char>>(pdu->begin(), pdu->begin()+10+len);
         boost::asio::async_write(sock(), boost::asio::buffer(*commandset),
            [this, commandset, len, pdu, p, ptype, pdataprop]
               (const boost::system::error_code& error, std::size_t bytes) {
               if (error) {
                  throw boost::system::system_error(error);
               }

               BOOST_LOG_SEV(logger, trace) << "Sent data fragment of size " << bytes;
               BOOST_LOG_SEV(logger, info) << "Sent property of type " << ptype;
               BOOST_LOG_SEV(logger, debug) << "Property info: \n" << *p;

               using namespace data::attribute;
               if (!pdataprop->command_set.empty()) {
                  // check if a dataset is present in the message
                  auto commandset = proc.deserialize(pdataprop->command_set);
                  unsigned short datasetpresent;
                  get_value_field<VR::US>(commandset.at({0x0000, 0x0800}), datasetpresent);
                  if (datasetpresent != 0x0101) {
                     auto dataset = std::make_shared<std::vector<unsigned char>>(pdu->begin()+10+len, pdu->end());
                     write_complete_dataset(p, dataset);
                  } else {
                     handle_pdu_conf(p, TYPE::P_DATA_TF);
                  }
               } else {
                  assert(false);
               }
            }
         );
      }
   }
}

void scx::handle_pdu(std::unique_ptr<property> p, TYPE ptype)
{
   handlers[ptype](this, std::move(p));

   if (get_state() == statemachine::CONN_STATE::STA13) {
      close_connection();
   } else {
      // be ready for new data
      if (!io_s().stopped() && !shutdown_requested) {
         do_read();
      }
   }

}

void scx::handle_pdu_conf(property* p, TYPE ptype)
{
   if (handlers_conf.find(ptype) != handlers_conf.end()) {
      handlers_conf[ptype](this, p);
   }
   send_queue.pop_front();
   if (!send_queue.empty()) {
      send(send_queue.front().get());
   }
}

void scx::get_complete_dataset(std::shared_ptr<std::vector<unsigned char>> data)<commit_msg>check if upperlayer data unit handler exists before calling<commit_after>#include "upperlayer_connection.hpp"


#include <utility>
#include <vector>
#include <ostream>
#include <cassert>
#include <initializer_list>
#include <chrono>
#include <deque>
#include <functional>
#include <exception>

#include <boost/optional.hpp>
#include <boost/asio.hpp>

#include "upperlayer_properties.hpp"


namespace dicom
{

namespace network
{

namespace upperlayer
{

namespace
{
using uchar = unsigned char;

std::size_t be_char_to_16b(std::vector<uchar> bs)
{
   assert(bs.size() == 2);
   std::size_t sz = 0;
   sz |= (static_cast<std::size_t>(bs[0]) << 8);
   sz |= (static_cast<std::size_t>(bs[1]));
   return sz;
}
std::size_t be_char_to_32b(std::vector<uchar> bs)
{
   assert(bs.size() == 4);
   std::size_t sz = 0;
   sz |= (static_cast<std::size_t>(bs[0]) << 24);
   sz |= (static_cast<std::size_t>(bs[1]) << 16);
   sz |= (static_cast<std::size_t>(bs[2]) << 8);
   sz |= (static_cast<std::size_t>(bs[3]));
   return sz;
}

}

Istate_trans_ops::~Istate_trans_ops()
{
}

Iupperlayer_comm_ops::~Iupperlayer_comm_ops()
{
}

using namespace dicom::util::log;



scx::scx(data::dictionary::dictionary& dict,
         std::vector<std::pair<TYPE, std::function<void(scx*, std::unique_ptr<property>)>>> l):
   statem {this},
   logger {"upperlayer"},
   proc {data::dataset::commandset_processor {dict}},
   received_pdu {boost::none},
   handlers {},
   shutdown_requested {false}
{
   for (const auto p : l) {
      handlers[p.first] = p.second;
   }
}

scx::~scx()
{
   // closing of the connection may only be done when there are no
   // outstanding operations
}


void scx::send(property* p)
{
   auto pdu = std::make_shared<std::vector<unsigned char>>(p->make_pdu());
   auto ptype = get_type(*pdu);

   statemachine::EVENT e;
   switch (ptype) {
      case TYPE::A_ABORT:
         e = statemachine::EVENT::LOCL_A_ABORT_PDU;
         break;
      case TYPE::A_ASSOCIATE_AC:
         e = statemachine::EVENT::LOCL_A_ASSOCIATE_AC_PDU;
         break;
      case TYPE::A_ASSOCIATE_RJ:
         e = statemachine::EVENT::LOCL_A_ASSOCIATE_RJ_PDU;
         break;
      case TYPE::A_ASSOCIATE_RQ:
         assert(false);
         break;
      case TYPE::A_RELEASE_RQ:
         e = statemachine::EVENT::LOCL_A_RELEASE_RQ_PDU;
         break;
      case TYPE::A_RELEASE_RP:
         e = statemachine::EVENT::LOCL_A_RELEASE_RP_PDU;
         break;
      case TYPE::P_DATA_TF:
         e = statemachine::EVENT::LOCL_P_DATA_TF_PDU;
         break;
      default:
         e = statemachine::EVENT::UNRECOG_PDU;
   }

   if (statem.transition(e) != statemachine::CONN_STATE::INV) {
      // call async_write after each sent property until the queue is
      // empty
      if (ptype != TYPE::P_DATA_TF) {
         boost::asio::async_write(sock(), boost::asio::buffer(*pdu),
            [this, p, ptype](const boost::system::error_code& error, std::size_t bytes) {
               if (error) {
                  throw boost::system::system_error(error);
               }

               BOOST_LOG_SEV(logger, trace) << "Sent PDU of size " << bytes;
               BOOST_LOG_SEV(logger, info) << "Sent property of type " << ptype;
               BOOST_LOG_SEV(logger, debug) << "Property info: \n" << *p;
               handle_pdu_conf(p, ptype);
         });
      } else {
         auto pdataprop = dynamic_cast<p_data_tf*>(p);
         assert(pdataprop);

         std::size_t len = be_char_to_32b({pdu->begin()+6, pdu->begin()+10});
         auto commandset = std::make_shared<std::vector<unsigned char>>(pdu->begin(), pdu->begin()+10+len);
         boost::asio::async_write(sock(), boost::asio::buffer(*commandset),
            [this, commandset, len, pdu, p, ptype, pdataprop]
               (const boost::system::error_code& error, std::size_t bytes) {
               if (error) {
                  throw boost::system::system_error(error);
               }

               BOOST_LOG_SEV(logger, trace) << "Sent data fragment of size " << bytes;
               BOOST_LOG_SEV(logger, info) << "Sent property of type " << ptype;
               BOOST_LOG_SEV(logger, debug) << "Property info: \n" << *p;

               using namespace data::attribute;
               if (!pdataprop->command_set.empty()) {
                  // check if a dataset is present in the message
                  auto commandset = proc.deserialize(pdataprop->command_set);
                  unsigned short datasetpresent;
                  get_value_field<VR::US>(commandset.at({0x0000, 0x0800}), datasetpresent);
                  if (datasetpresent != 0x0101) {
                     auto dataset = std::make_shared<std::vector<unsigned char>>(pdu->begin()+10+len, pdu->end());
                     write_complete_dataset(p, dataset);
                  } else {
                     handle_pdu_conf(p, TYPE::P_DATA_TF);
                  }
               } else {
                  assert(false);
               }
            }
         );
      }
   }
}

void scx::handle_pdu(std::unique_ptr<property> p, TYPE ptype)
{
   if (handlers[ptype])
   {
      handlers[ptype](this, std::move(p));
   }

   if (get_state() == statemachine::CONN_STATE::STA13) {
      close_connection();
   } else {
      // be ready for new data
      if (!io_s().stopped() && !shutdown_requested) {
         do_read();
      }
   }

}

void scx::handle_pdu_conf(property* p, TYPE ptype)
{
   if (handlers_conf.find(ptype) != handlers_conf.end()) {
      handlers_conf[ptype](this, p);
   }
   send_queue.pop_front();
   if (!send_queue.empty()) {
      send(send_queue.front().get());
   }
}

void scx::get_complete_dataset(std::shared_ptr<std::vector<unsigned char>> data)
{'fraction_non_alphanumeric': 0.1484877876730447, 'fraction_numerical': 0.008112159421567762, 'mean_word_length': 2.6932595245848256, 'pattern_counts': {'":': 0, '<': 135, '<?xml version=': 0, '>': 89, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6883350', 'n_tokens_mistral': 3972, 'n_tokens_neox': 3824, 'n_words': 711}