LCOV - code coverage report
Current view: top level - otsdaq/artdaq-ots/Generators - UDPReceiver_generator.cc (source / functions) Coverage Total Hit
Test: mu2edaq.info.cleaned Lines: 0.0 % 206 0
Test Date: 2026-07-30 01:56:44 Functions: 0.0 % 38 0

            Line data    Source code
       1              : 
       2              : 
       3              : #define TRACEMF_USE_VERBATIM 1  // for trace longer path filenames
       4              : #include "artdaq/DAQdata/Globals.hh"
       5              : #define TRACE_NAME "UDPReceiver"
       6              : 
       7              : #include "artdaq-ots/Generators/UDPReceiver.hh"
       8              : 
       9              : #include "artdaq-core/Utilities/SimpleLookupPolicy.hh"
      10              : #include "artdaq-ots/Overlays/FragmentType.hh"
      11              : #include "artdaq-ots/Overlays/UDPFragmentWriter.hh"
      12              : #include "artdaq/Generators/GeneratorMacros.hh"
      13              : #include "canvas/Utilities/Exception.h"
      14              : #include "fhiclcpp/ParameterSet.h"
      15              : #include "otsdaq/Macros/CoutMacros.h"
      16              : 
      17              : #include <sys/poll.h>
      18              : #include <fstream>
      19              : #include <iomanip>
      20              : #include <iostream>
      21              : #include <iterator>
      22              : 
      23              : //==============================================================================
      24            0 : ots::UDPReceiver::UDPReceiver(fhicl::ParameterSet const& ps)
      25              :     : CommandableFragmentGenerator(ps)
      26            0 :     , rawOutput_(ps.get<bool>("raw_output_enabled", false))
      27            0 :     , rawPath_(ps.get<std::string>("raw_output_path", "/tmp"))
      28            0 :     , dataport_(ps.get<int>("port", 6343))
      29            0 :     , ip_(ps.get<std::string>("ip", "127.0.0.1"))
      30            0 :     , rcvbuf_(ps.get<int>("rcvbuf", 0x1000000))
      31            0 :     , expectedPacketNumber_(0)
      32            0 :     , datasocket_(-1)
      33            0 :     , sendCommands_(ps.get<bool>("send_OtsUDP_commands", false))
      34            0 :     , receiverThread_(nullptr)
      35            0 :     , fakeDataMode_(ps.get<bool>("fake_data_mode", false))
      36            0 :     , fragmentWindow_(ps.get<double>("fragment_time_window_ms", 1000))
      37            0 :     , lastFrag_(std::chrono::high_resolution_clock::now())
      38              : {
      39            0 :         TLOG(TLVL_DEBUG) << "Constructor.";
      40              : 
      41            0 :         if(!fakeDataMode_)
      42              :         {
      43            0 :                 datasocket_ = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
      44            0 :                 if(!datasocket_)
      45              :                 {
      46            0 :                         throw art::Exception(art::errors::Configuration)
      47            0 :                             << "UDPReceiver: Error creating socket!";
      48              :                         exit(1);
      49              :                 }
      50              : 
      51              :                 struct sockaddr_in si_me_data;
      52            0 :                 si_me_data.sin_family      = AF_INET;
      53            0 :                 si_me_data.sin_port        = htons(dataport_);
      54            0 :                 si_me_data.sin_addr.s_addr = htonl(INADDR_ANY);
      55            0 :                 if(bind(datasocket_, (struct sockaddr*)&si_me_data, sizeof(si_me_data)) == -1)
      56              :                 {
      57            0 :                         throw art::Exception(art::errors::Configuration)
      58            0 :                             << "UDPReceiver: Cannot bind data socket to port " << dataport_;
      59              :                         exit(1);
      60              :                 }
      61              :                 /*if(fcntl(datasocket_, F_SETFL, O_NONBLOCK) == -1) {
      62              : 
      63              :                     throw art::Exception(art::errors::Configuration) << "UDPReceiver: Cannot set
      64              :                   socket to nonblocking!" ;
      65              :                   }*/
      66              : 
      67            0 :                 if(rcvbuf_ > 0 &&
      68            0 :                    setsockopt(datasocket_, SOL_SOCKET, SO_RCVBUF, &rcvbuf_, sizeof(rcvbuf_)))
      69              :                 {
      70            0 :                         throw art::Exception(art::errors::Configuration)
      71            0 :                             << "UDPReceiver: Could not set receive buffer size: " << rcvbuf_;
      72              :                         exit(1);
      73              :                 }
      74              : 
      75            0 :                 si_data_.sin_family = AF_INET;
      76            0 :                 si_data_.sin_port   = htons(dataport_);
      77            0 :                 if(inet_aton(ip_.c_str(), &si_data_.sin_addr) == 0)
      78              :                 {
      79            0 :                         throw art::Exception(art::errors::Configuration)
      80            0 :                             << "UDPReceiver: Could not translate provided IP Address: " << ip_;
      81              :                         exit(1);
      82              :                 }
      83              :         }
      84            0 :         TLOG(TLVL_INFO) << "UDP Receiver Construction Complete!";
      85              : 
      86            0 :         TLOG(TLVL_DEBUG) << "Constructed.";
      87            0 : }  // end constructor()
      88              : 
      89              : //==============================================================================
      90            0 : ots::UDPReceiver::~UDPReceiver()
      91              : {
      92            0 :         TLOG(TLVL_DEBUG) << "Destructor.";
      93              : 
      94              :         // join waits for thread to complete
      95            0 :         if(receiverThread_ && receiverThread_->joinable())
      96              :         {
      97              :                 // only join if thread has started
      98            0 :                 receiverThread_->join();
      99            0 :                 receiverThread_.reset(nullptr);
     100              :         }
     101              : 
     102            0 :         if(datasocket_)
     103              :         {
     104            0 :                 close(datasocket_);
     105            0 :                 datasocket_ = -1;
     106              :         }
     107              : 
     108            0 :         TLOG(TLVL_DEBUG) << "Destructed.";
     109            0 : }  // end destructor()
     110              : 
     111              : //==============================================================================
     112            0 : void ots::UDPReceiver::start()
     113              : {
     114            0 :         TLOG(TLVL_DEBUG) << "Starting...";
     115              : 
     116            0 :         TLOG(TLVL_INFO) << "Starting...";
     117              : 
     118            0 :         if(!fakeDataMode_)
     119              :         {
     120            0 :                 receiverThread_.reset(new std::thread(&UDPReceiver::receiveLoop_, this));
     121              :         }
     122            0 :         start_();
     123              : 
     124            0 :         TLOG(TLVL_DEBUG) << "Started.";
     125            0 : }  // end start()
     126              : 
     127              : //==============================================================================
     128            0 : void ots::UDPReceiver::receiveLoop_()
     129              : {
     130            0 :         while(!should_stop())
     131              :         {
     132              :                 struct pollfd ufds[1];
     133            0 :                 ufds[0].fd     = datasocket_;
     134            0 :                 ufds[0].events = POLLIN | POLLPRI;
     135              : 
     136            0 :                 int rv = poll(ufds, 1, 1000);
     137            0 :                 if(rv > 0)
     138              :                 {
     139            0 :                         TLOG(TLVL_TRACE) << "revents: " << ufds[0].revents
     140            0 :                                          << ", ";  // ufds[1].revents ;
     141            0 :                         if(ufds[0].revents == POLLIN || ufds[0].revents == POLLPRI)
     142              :                         {
     143              :                                 // FIXME -> IN THE STIB GENERATOR WE DON'T HAVE A HEADER
     144              :                                 // FIXME -> IN THE STIB GENERATOR WE DON'T HAVE A HEADER
     145              :                                 // FIXME -> IN THE STIB GENERATOR WE DON'T HAVE A HEADER
     146              :                                 uint8_t   peekBuffer[4];
     147            0 :                                 socklen_t dataSz = sizeof(si_data_);
     148            0 :                                 recvfrom(datasocket_,
     149              :                                          peekBuffer,
     150              :                                          sizeof(peekBuffer),
     151              :                                          MSG_PEEK,
     152            0 :                                          (struct sockaddr*)&si_data_,
     153              :                                          &dataSz);
     154              : 
     155            0 :                                 TLOG(TLVL_TRACE)
     156            0 :                                     << "Received UDP Datagram with sequence number " << std::hex << "0x"
     157            0 :                                     << static_cast<int>(peekBuffer[1]) << "!" << std::dec;
     158            0 :                                 TLOG(TLVL_TRACE) << "peekBuffer[1] == expectedPacketNumber_: " << std::hex
     159            0 :                                                  << static_cast<int>(peekBuffer[1])
     160            0 :                                                  << " =?= " << (int)expectedPacketNumber_;
     161            0 :                                 TLOG(TLVL_TRACE)
     162            0 :                                     << "peekBuffer: 0: " << std::hex << static_cast<int>(peekBuffer[0])
     163            0 :                                     << ", 1: " << std::hex << static_cast<int>(peekBuffer[1])
     164            0 :                                     << ", 2: " << std::hex << static_cast<int>(peekBuffer[2])
     165            0 :                                     << ", 3: " << std::hex << static_cast<int>(peekBuffer[3]);
     166              : 
     167            0 :                                 uint8_t seqNum = peekBuffer[1];
     168              :                                 // ReturnCode dataCode = getReturnCode(peekBuffer[0]);
     169            0 :                                 if(seqNum >= expectedPacketNumber_ ||
     170            0 :                                    (seqNum < 64 && expectedPacketNumber_ > 192))
     171              :                                 {
     172            0 :                                         if(seqNum != expectedPacketNumber_)
     173              :                                         {
     174            0 :                                                 int delta = seqNum - expectedPacketNumber_;
     175            0 :                                                 TLOG(TLVL_WARNING)
     176            0 :                                                     << std::dec
     177            0 :                                                     << "Sequence Number different than expected! (delta: "
     178            0 :                                                     << delta << ")";
     179            0 :                                                 expectedPacketNumber_ = seqNum;
     180              :                                         }
     181              : 
     182            0 :                                         packetBuffer_t receiveBuffer;
     183            0 :                                         receiveBuffer.resize(1500);
     184            0 :                                         int sts = recvfrom(datasocket_,
     185            0 :                                                            &receiveBuffer[0],
     186              :                                                            receiveBuffer.size(),
     187              :                                                            0,
     188            0 :                                                            (struct sockaddr*)&si_data_,
     189            0 :                                                            &dataSz);
     190            0 :                                         receiveBuffer.resize(sts);
     191              : 
     192            0 :                                         if(sts == -1)
     193              :                                         {
     194            0 :                                                 TLOG(TLVL_WARNING) << "Error on socket: " << strerror(errno);
     195              :                                         }
     196              :                                         else
     197              :                                         {
     198            0 :                                                 TLOG(TLVL_TRACE) << "Received " << sts << " bytes.";
     199              :                                         }
     200              : 
     201            0 :                                         std::unique_lock<std::mutex> lock(receiveBufferLock_);
     202            0 :                                         TLOG(TLVL_TRACE)
     203            0 :                                             << "Now placing UDP datagram with sequence number " << std::hex
     204            0 :                                             << (int)seqNum << " into buffer." << std::dec;
     205            0 :                                         receiveBuffers_.push_back(receiveBuffer);
     206              : 
     207            0 :                                         ++expectedPacketNumber_;
     208            0 :                                 }
     209              :                                 else
     210              :                                 {
     211              :                                         // Receiving out-of-order datagram, then moving on...
     212            0 :                                         TLOG(TLVL_WARNING)
     213            0 :                                             << "Received out-of-order datagram: " << seqNum
     214            0 :                                             << " != " << expectedPacketNumber_ << " (expected)";
     215            0 :                                         packetBuffer_t receiveBuffer;
     216            0 :                                         receiveBuffer.resize(1500);
     217            0 :                                         int sts = recvfrom(datasocket_,
     218            0 :                                                            &receiveBuffer[0],
     219              :                                                            receiveBuffer.size(),
     220              :                                                            0,
     221            0 :                                                            (struct sockaddr*)&si_data_,
     222            0 :                                                            &dataSz);
     223            0 :                                         receiveBuffer.resize(sts);
     224            0 :                                 }
     225              :                         }
     226              :                 }
     227              :         }
     228            0 :         TLOG(TLVL_INFO) << "receive Loop exiting...";
     229            0 : }
     230              : 
     231              : //==============================================================================
     232            0 : bool ots::UDPReceiver::getNext_(artdaq::FragmentPtrs& output)
     233              : {
     234            0 :         if(should_stop())
     235              :         {
     236            0 :                 return false;
     237              :         }
     238              : 
     239            0 :         if(!fakeDataMode_)
     240              :         {
     241            0 :                 std::unique_lock<std::mutex> lock(receiveBufferLock_);
     242            0 :                 std::move(receiveBuffers_.begin(),
     243              :                           receiveBuffers_.end(),
     244            0 :                           std::inserter(packetBuffers_, packetBuffers_.end()));
     245            0 :                 receiveBuffers_.clear();
     246            0 :         }
     247              :         else
     248              :         {
     249            0 :                 packetBuffer_t pkt;  // std::string
     250            0 :                 pkt.resize(10);
     251            0 :                 pkt[0] = 0x23;  // Data type string, return code last
     252            0 :                 for(int ii = 1; ii < 9; ++ii)
     253              :                 {
     254            0 :                         pkt[ii] = ii;
     255              :                 }
     256            0 :                 pkt[9] = 0;
     257            0 :                 packetBuffers_.push_back(pkt);
     258            0 :         }
     259              : 
     260            0 :         if(packetBuffers_.size() > 0)
     261              :         {
     262            0 :                 size_t packetBufferSize = 0;
     263            0 :                 for(auto& buf : packetBuffers_)
     264              :                 {
     265            0 :                         packetBufferSize += buf.size();
     266              :                 }
     267            0 :                 TLOG(TLVL_TRACE) << "Calling ProcessData, packetBuffers_.size() == "
     268            0 :                                  << std::to_string(packetBuffers_.size())
     269            0 :                                  << ", sz = " << std::to_string(packetBufferSize);
     270            0 :                 ProcessData_(output, packetBufferSize);
     271              : 
     272            0 :                 packetBuffers_.clear();
     273            0 :                 TLOG(TLVL_TRACE) << "Returning output of size " << output.size();
     274              :         }
     275              :         else
     276              :         {
     277              :                 // Sleep 10 times per poll timeout
     278            0 :                 usleep(100000);
     279              :         }
     280            0 :         return true;
     281              : }
     282              : 
     283              : //==============================================================================
     284            0 : void ots::UDPReceiver::ProcessData_(artdaq::FragmentPtrs& output, size_t totalSize)
     285              : {
     286            0 :         TLOG(TLVL_TRACE) << "ProcessData_ start";
     287              :         ots::UDPFragment::Metadata metadata;
     288            0 :         metadata.port    = dataport_;
     289            0 :         metadata.address = si_data_.sin_addr.s_addr;
     290              : 
     291            0 :         std::size_t initial_payload_size = 0;
     292              : 
     293            0 :         TLOG(TLVL_TRACE) << "Creating Fragment";
     294              : 
     295            0 :         output.emplace_back(artdaq::Fragment::FragmentBytes(initial_payload_size,
     296              :                                                             ev_counter(),
     297            0 :                                                             fragment_id(),
     298              :                                                             ots::detail::FragmentType::UDP,
     299              :                                                             metadata));
     300              : 
     301            0 :         ev_counter_inc();
     302              : 
     303            0 :         TLOG(TLVL_TRACE) << "Creating UDPFragmentWriter";
     304              :         // We now have a fragment to contain this event:
     305            0 :         ots::UDPFragmentWriter thisFrag(*output.back());
     306              : 
     307            0 :         TLOG(TLVL_TRACE) << "Received data, now placing data with UDP sequence number "
     308            0 :                          << std::hex << static_cast<int>((packetBuffers_.front()).at(1))
     309            0 :                          << " into UDPFragment";
     310            0 :         thisFrag.resize(totalSize + 1);
     311            0 :         std::ofstream rawOutput;
     312            0 :         if(rawOutput_)
     313              :         {
     314              :                 std::string outputPath =
     315            0 :                     rawPath_ + "/UDPReceiver-" + ip_ + ":" + std::to_string(dataport_) + ".bin";
     316            0 :                 rawOutput.open(outputPath, std::ios::out | std::ios::app | std::ios::binary);
     317            0 :         }
     318              : 
     319            0 :         DataType dataType = getDataType((packetBuffers_.front()).at(0));
     320            0 :         thisFrag.set_hdr_type((int)dataType);
     321            0 :         int pos = 0;
     322            0 :         for(auto jj = packetBuffers_.begin(); jj != packetBuffers_.end(); ++jj)
     323              :         {
     324            0 :                 for(size_t ii = 0; ii < jj->size(); ++ii)
     325              :                 {
     326              :                         // Null-terminate string types
     327            0 :                         if((jj)->at(ii) == 0 &&
     328            0 :                            (dataType == DataType::JSON || dataType == DataType::String))
     329              :                         {
     330            0 :                                 break;
     331              :                         }
     332              : 
     333            0 :                         if(rawOutput_)
     334            0 :                                 rawOutput.write((char*)&((jj)->at(ii)), sizeof(uint8_t));
     335            0 :                         *(thisFrag.dataBegin() + pos) = (jj)->at(ii);
     336            0 :                         ++pos;
     337              :                 }
     338              :         }
     339              : 
     340            0 :         if(dataType == DataType::JSON || dataType == DataType::String)
     341              :         {
     342            0 :                 *(thisFrag.dataBegin() + pos) = 0;
     343            0 :                 char zero                     = 0;
     344            0 :                 if(rawOutput_)
     345            0 :                         rawOutput.write(&zero, sizeof(char));
     346              :         }
     347            0 :         if(rawOutput_)
     348            0 :                 rawOutput.close();
     349            0 : }
     350              : 
     351              : //==============================================================================
     352            0 : void ots::UDPReceiver::send(CommandType command)
     353              : {
     354            0 :         if(sendCommands_)
     355              :         {
     356              :                 CommandPacket packet;
     357            0 :                 packet.type     = command;
     358            0 :                 packet.dataSize = 0;
     359            0 :                 sendto(datasocket_,
     360              :                        &packet,
     361              :                        sizeof(packet),
     362              :                        0,
     363            0 :                        (struct sockaddr*)&si_data_,
     364              :                        sizeof(si_data_));
     365              :         }
     366            0 : }
     367              : 
     368              : //==============================================================================
     369            0 : bool ots::UDPReceiver::isTimerExpired_()
     370              : {
     371            0 :         auto now  = std::chrono::high_resolution_clock::now();
     372            0 :         auto diff = std::chrono::duration<double, std::milli>(now - lastFrag_).count();
     373            0 :         return diff > fragmentWindow_;
     374              : }
     375              : 
     376              : //==============================================================================
     377            0 : void ots::UDPReceiver::stop()
     378              : {
     379            0 :         TLOG(TLVL_DEBUG) << "Stopping...";
     380              :         // #pragma message "Using default implementation of UDPReceiver::stop()"
     381            0 : }
     382              : 
     383              : //==============================================================================
     384            0 : void ots::UDPReceiver::stopNoMutex()
     385              : {
     386              :         // #pragma message "Using default implementation of UDPReceiver::stopNoMutex()"
     387            0 : }
     388              : 
     389              : //==============================================================================
     390            0 : void ots::UDPReceiver::start_()
     391              : {
     392              :         // #pragma message "Using default implementation of UDPReceiver::start_()"
     393            0 : }
     394              : 
     395              : /// The following macro is defined in artdaq's GeneratorMacros.hh header
     396            0 : DEFINE_ARTDAQ_COMMANDABLE_GENERATOR(ots::UDPReceiver)
        

Generated by: LCOV version 2.0-1