Compare commits

...

7 Commits

Author SHA1 Message Date
0251aa9e63 fixed linking issue in arping and shm test (#659)
Co-authored-by: Erik Frojdh <erik.frojdh@psi.ch>
2023-02-14 14:49:00 +01:00
7c047cab4a udpated version to rc4 2023-02-14 10:30:45 +01:00
572332f870 fix test for eiger half module for gap pixels (#658) 2023-02-14 09:22:32 +01:00
d90bf6c7df formatting 2023-02-13 11:36:41 +01:00
5c8c3ae3f3 fix to access to shared memory that doesnt exist (#638)
* fix to access to shared memory that doesnt exist

* fix for freeing shm and then setting hostname from API

* exception error message moved to private function

* refactoring to avoid allocating intermediate string
2023-02-13 11:29:54 +01:00
18136fed9d exception messages (#656)
* fix exception messages for more printout about sockets or more detail
2023-02-13 11:22:05 +01:00
fc42720208 allow half modules and odd number of half modules to use the gui with gap pixels disabled (#655) 2023-02-13 11:21:35 +01:00
14 changed files with 320 additions and 267 deletions

View File

@ -47,6 +47,7 @@ class qTabPlot : public QWidget, private Ui::TabPlotObject {
private: private:
void SetupWidgetWindow(); void SetupWidgetWindow();
void Initialization(); void Initialization();
bool VerifyGapPixelsAllowed();
void Select1DPlot(bool enable); void Select1DPlot(bool enable);
void GetGapPixels(); void GetGapPixels();
void GetStreamingFrequency(); void GetStreamingFrequency();
@ -60,7 +61,8 @@ class qTabPlot : public QWidget, private Ui::TabPlotObject {
Detector *det; Detector *det;
qDrawPlot *plot; qDrawPlot *plot;
bool is1d; bool is1d{false};
bool isGapPixelsAllowed{false};
/** default plot and axis titles */ /** default plot and axis titles */
static QString defaultPlotTitle; static QString defaultPlotTitle;

View File

@ -16,7 +16,7 @@ QString qTabPlot::defaultImageYAxisTitle("Pixel");
QString qTabPlot::defaultImageZAxisTitle("Intensity"); QString qTabPlot::defaultImageZAxisTitle("Intensity");
qTabPlot::qTabPlot(QWidget *parent, Detector *detector, qDrawPlot *p) qTabPlot::qTabPlot(QWidget *parent, Detector *detector, qDrawPlot *p)
: QWidget(parent), det(detector), plot(p), is1d(false) { : QWidget(parent), det(detector), plot(p) {
setupUi(this); setupUi(this);
SetupWidgetWindow(); SetupWidgetWindow();
LOG(logDEBUG) << "Plot ready"; LOG(logDEBUG) << "Plot ready";
@ -57,11 +57,7 @@ void qTabPlot::SetupWidgetWindow() {
chkGainPlot1D->setChecked(true); chkGainPlot1D->setChecked(true);
plot->EnableGainPlot(true); plot->EnableGainPlot(true);
break; break;
case slsDetectorDefs::EIGER:
chkGapPixels->setEnabled(true);
break;
case slsDetectorDefs::JUNGFRAU: case slsDetectorDefs::JUNGFRAU:
chkGapPixels->setEnabled(true);
chkGainPlot->setEnabled(true); chkGainPlot->setEnabled(true);
chkGainPlot->setChecked(true); chkGainPlot->setChecked(true);
plot->EnableGainPlot(true); plot->EnableGainPlot(true);
@ -69,6 +65,8 @@ void qTabPlot::SetupWidgetWindow() {
default: default:
break; break;
} }
isGapPixelsAllowed = VerifyGapPixelsAllowed();
chkGapPixels->setEnabled(isGapPixelsAllowed);
Select1DPlot(is1d); Select1DPlot(is1d);
Initialization(); Initialization();
@ -195,6 +193,29 @@ void qTabPlot::Initialization() {
connect(dispZMax, SIGNAL(editingFinished()), this, SLOT(isZMaxModified())); connect(dispZMax, SIGNAL(editingFinished()), this, SLOT(isZMaxModified()));
} }
bool qTabPlot::VerifyGapPixelsAllowed() {
try {
switch (det->getDetectorType().squash()) {
case slsDetectorDefs::JUNGFRAU:
return true;
case slsDetectorDefs::EIGER:
if (det->getQuad().squash(false)) {
return true;
}
// full modules
if (det->getModuleGeometry().y % 2 == 0) {
return true;
}
return false;
default:
return false;
}
}
CATCH_DISPLAY("Could not verify if gap pixels allowed.",
"qTabPlot::VerifyGapPixelsAllowed")
return false;
}
void qTabPlot::Select1DPlot(bool enable) { void qTabPlot::Select1DPlot(bool enable) {
LOG(logDEBUG) << "Selecting " << (enable ? "1" : "2") << "D Plot"; LOG(logDEBUG) << "Selecting " << (enable ? "1" : "2") << "D Plot";
is1d = enable; is1d = enable;
@ -772,15 +793,10 @@ void qTabPlot::Refresh() {
boxFrequency->setEnabled(true); boxFrequency->setEnabled(true);
GetStreamingFrequency(); GetStreamingFrequency();
GetHwm(); GetHwm();
// gain plot, gap pixels enable // gain plot
switch (det->getDetectorType().squash()) { switch (det->getDetectorType().squash()) {
case slsDetectorDefs::EIGER:
chkGapPixels->setEnabled(true);
GetGapPixels();
break;
case slsDetectorDefs::JUNGFRAU: case slsDetectorDefs::JUNGFRAU:
chkGainPlot->setEnabled(true); chkGainPlot->setEnabled(true);
chkGapPixels->setEnabled(true);
GetGapPixels(); GetGapPixels();
break; break;
case slsDetectorDefs::GOTTHARD2: case slsDetectorDefs::GOTTHARD2:
@ -789,6 +805,11 @@ void qTabPlot::Refresh() {
default: default:
break; break;
} }
// gap pixels
if (isGapPixelsAllowed) {
chkGapPixels->setEnabled(true);
GetGapPixels();
}
} else { } else {
boxFrequency->setEnabled(false); boxFrequency->setEnabled(false);
chkGainPlot->setEnabled(false); chkGainPlot->setEnabled(false);

View File

@ -253,14 +253,15 @@ void DetectorImpl::setVirtualDetectorServers(const int numdet, const int port) {
} }
void DetectorImpl::setHostname(const std::vector<std::string> &name) { void DetectorImpl::setHostname(const std::vector<std::string> &name) {
// this check is there only to allow the previous detsizechan command // do not free always to allow the previous detsize/ initialchecks command
if (shm()->totalNumberOfModules != 0) { if (shm.exists() && shm()->totalNumberOfModules != 0) {
LOG(logWARNING) << "There are already module(s) in shared memory." LOG(logWARNING) << "There are already module(s) in shared memory."
"Freeing Shared memory now."; "Freeing Shared memory now.";
bool initialChecks = shm()->initialChecks;
freeSharedMemory(); freeSharedMemory();
}
// could be called after freeing shm from API
if (!shm.exists()) {
setupDetector(); setupDetector();
shm()->initialChecks = initialChecks;
} }
for (const auto &hostname : name) { for (const auto &hostname : name) {
addModule(hostname); addModule(hostname);

View File

@ -33,7 +33,7 @@ namespace sls {
template <typename T> class SharedMemory { template <typename T> class SharedMemory {
static constexpr int NAME_MAX_LENGTH = 255; static constexpr int NAME_MAX_LENGTH = 255;
std::string name; std::string name;
T *shared_struct{}; T *shared_struct{nullptr};
public: public:
// moduleid of -1 creates a detector only shared memory // moduleid of -1 creates a detector only shared memory
@ -64,8 +64,18 @@ template <typename T> class SharedMemory {
unmapSharedMemory(); unmapSharedMemory();
} }
T *operator()() { return shared_struct; } T *operator()() {
const T *operator()() const { return shared_struct; } if (shared_struct)
return shared_struct;
throw SharedMemoryError(getNoShmAccessMessage());
}
const T *operator()() const {
if (shared_struct)
return shared_struct;
throw SharedMemoryError(getNoShmAccessMessage());
}
std::string getName() const { return name; } std::string getName() const { return name; }
bool exists() { bool exists() {
@ -204,6 +214,11 @@ template <typename T> class SharedMemory {
throw SharedMemoryError(msg); throw SharedMemoryError(msg);
} }
} }
const char *getNoShmAccessMessage() const {
return ("No shared memory to access. Create it first with "
"hostname or config command.");
};
}; };
} // namespace sls } // namespace sls

View File

@ -524,8 +524,10 @@ TEST_CASE("gappixels", "[.cmd]") {
Detector det; Detector det;
CmdProxy proxy(&det); CmdProxy proxy(&det);
auto det_type = det.getDetectorType().squash(); auto det_type = det.getDetectorType().squash();
bool quad = det.getQuad().squash(false);
bool fullModule = (det.getModuleGeometry().y % 2 == 0);
if (det_type == defs::JUNGFRAU || det_type == defs::EIGER) { if (det_type == defs::JUNGFRAU || (det_type == defs::EIGER && (quad || fullModule))) {
auto prev_val = det.getGapPixelsinCallback(); auto prev_val = det.getGapPixelsinCallback();
{ {
std::ostringstream oss; std::ostringstream oss;

View File

@ -101,7 +101,7 @@ TEST_CASE("Move SharedMemory", "[detector]") {
shm2 = std::move(shm); // shm is now a moved from object! shm2 = std::move(shm); // shm is now a moved from object!
CHECK(shm2()->x == 9); CHECK(shm2()->x == 9);
CHECK(shm() == nullptr); REQUIRE_THROWS(shm()); // trying to access should throw instead of returning a nullptr
CHECK(shm2.getName() == std::string("/slsDetectorPackage_detector_") + CHECK(shm2.getName() == std::string("/slsDetectorPackage_detector_") +
std::to_string(shm_id)); std::to_string(shm_id));
shm2.removeSharedMemory(); shm2.removeSharedMemory();

View File

@ -85,8 +85,8 @@ void Arping::ProcessExecution() {
if (!error.empty()) { if (!error.empty()) {
LOG(logERROR) << error; LOG(logERROR) << error;
} }
const auto interval = std::chrono::seconds(60);
std::this_thread::sleep_for(std::chrono::seconds(timeIntervalSeconds)); std::this_thread::sleep_for(interval);
} }
} }

View File

@ -36,7 +36,6 @@ class Arping {
std::vector<std::string>(MAX_NUMBER_OF_LISTENING_THREADS); std::vector<std::string>(MAX_NUMBER_OF_LISTENING_THREADS);
std::atomic<bool> runningFlag{false}; std::atomic<bool> runningFlag{false};
std::atomic<pid_t> childPid{0}; std::atomic<pid_t> childPid{0};
static const int timeIntervalSeconds = 60;
}; };
} // namespace sls } // namespace sls

View File

@ -320,165 +320,122 @@ int ClientInterface::setup_receiver(Interface &socket) {
auto arg = socket.Receive<rxParameters>(); auto arg = socket.Receive<rxParameters>();
LOG(logDEBUG) << ToString(arg); LOG(logDEBUG) << ToString(arg);
// if object exists, verify unlocked and idle, else only verify lock
// (connecting first time)
if (receiver != nullptr) {
verifyIdle(socket);
}
// basic setup
setDetectorType(arg.detType);
impl()->setDetectorSize(arg.numberOfModule);
impl()->setModulePositionId(arg.moduleIndex);
impl()->setDetectorHostname(arg.hostname);
// udp setup
// update retvals only if detmac is not the same as in detector
MacAddr retvals[2]; MacAddr retvals[2];
if (arg.udp_dstip != 0) { try {
MacAddr r = setUdpIp(IpAddr(arg.udp_dstip)); // if object exists, verify unlocked and idle, else only verify lock
MacAddr detMac{arg.udp_dstmac}; // (connecting first time)
if (detMac != r) { if (receiver != nullptr) {
retvals[0] = r; verifyIdle(socket);
} }
}
if (arg.udp_dstip2 != 0) {
MacAddr r = setUdpIp2(IpAddr(arg.udp_dstip2));
MacAddr detMac{arg.udp_dstmac2};
if (detMac != r) {
retvals[1] = r;
}
}
impl()->setUDPPortNumber(arg.udp_dstport);
impl()->setUDPPortNumber2(arg.udp_dstport2);
if (detType == JUNGFRAU || detType == GOTTHARD2) {
try {
impl()->setNumberofUDPInterfaces(arg.udpInterfaces);
} catch (const RuntimeError &e) {
throw RuntimeError("Failed to set number of interfaces to " +
std::to_string(arg.udpInterfaces));
}
}
impl()->setUDPSocketBufferSize(0);
// acquisition parameters // basic setup
impl()->setNumberOfFrames(arg.frames); setDetectorType(arg.detType);
impl()->setNumberOfTriggers(arg.triggers); impl()->setDetectorSize(arg.numberOfModule);
if (detType == GOTTHARD2) { impl()->setModulePositionId(arg.moduleIndex);
impl()->setNumberOfBursts(arg.bursts); impl()->setDetectorHostname(arg.hostname);
}
if (detType == JUNGFRAU) { // udp setup
impl()->setNumberOfAdditionalStorageCells(arg.additionalStorageCells); // update retvals only if detmac is not the same as in detector
} if (arg.udp_dstip != 0) {
if (detType == MOENCH || detType == CHIPTESTBOARD) { MacAddr r = setUdpIp(IpAddr(arg.udp_dstip));
try { MacAddr detMac{arg.udp_dstmac};
if (detMac != r) {
retvals[0] = r;
}
}
if (arg.udp_dstip2 != 0) {
MacAddr r = setUdpIp2(IpAddr(arg.udp_dstip2));
MacAddr detMac{arg.udp_dstmac2};
if (detMac != r) {
retvals[1] = r;
}
}
impl()->setUDPPortNumber(arg.udp_dstport);
impl()->setUDPPortNumber2(arg.udp_dstport2);
if (detType == JUNGFRAU || detType == GOTTHARD2) {
impl()->setNumberofUDPInterfaces(arg.udpInterfaces);
}
impl()->setUDPSocketBufferSize(0);
// acquisition parameters
impl()->setNumberOfFrames(arg.frames);
impl()->setNumberOfTriggers(arg.triggers);
if (detType == GOTTHARD2) {
impl()->setNumberOfBursts(arg.bursts);
}
if (detType == JUNGFRAU) {
impl()->setNumberOfAdditionalStorageCells(
arg.additionalStorageCells);
}
if (detType == MOENCH || detType == CHIPTESTBOARD) {
impl()->setNumberofAnalogSamples(arg.analogSamples); impl()->setNumberofAnalogSamples(arg.analogSamples);
} catch (const RuntimeError &e) {
throw RuntimeError("Could not set num analog samples to " +
std::to_string(arg.analogSamples) +
" due to fifo structure memory allocation.");
} }
} if (detType == CHIPTESTBOARD) {
if (detType == CHIPTESTBOARD) {
try {
impl()->setNumberofDigitalSamples(arg.digitalSamples); impl()->setNumberofDigitalSamples(arg.digitalSamples);
} catch (const RuntimeError &e) {
throw RuntimeError("Could not set num digital samples to " +
std::to_string(arg.analogSamples) +
" due to fifo structure memory allocation.");
} }
} if (detType != MYTHEN3) {
if (detType != MYTHEN3) { impl()->setAcquisitionTime(std::chrono::nanoseconds(arg.expTimeNs));
impl()->setAcquisitionTime(std::chrono::nanoseconds(arg.expTimeNs)); }
} impl()->setAcquisitionPeriod(std::chrono::nanoseconds(arg.periodNs));
impl()->setAcquisitionPeriod(std::chrono::nanoseconds(arg.periodNs)); if (detType == EIGER) {
if (detType == EIGER) { impl()->setSubExpTime(std::chrono::nanoseconds(arg.subExpTimeNs));
impl()->setSubExpTime(std::chrono::nanoseconds(arg.subExpTimeNs)); impl()->setSubPeriod(std::chrono::nanoseconds(arg.subExpTimeNs) +
impl()->setSubPeriod(std::chrono::nanoseconds(arg.subExpTimeNs) + std::chrono::nanoseconds(arg.subDeadTimeNs));
std::chrono::nanoseconds(arg.subDeadTimeNs)); impl()->setActivate(static_cast<bool>(arg.activate));
impl()->setActivate(static_cast<bool>(arg.activate)); impl()->setDetectorDataStream(LEFT, arg.dataStreamLeft);
impl()->setDetectorDataStream(LEFT, arg.dataStreamLeft); impl()->setDetectorDataStream(RIGHT, arg.dataStreamRight);
impl()->setDetectorDataStream(RIGHT, arg.dataStreamRight);
try {
impl()->setQuad(arg.quad == 0 ? false : true); impl()->setQuad(arg.quad == 0 ? false : true);
} catch (const RuntimeError &e) { impl()->setThresholdEnergy(arg.thresholdEnergyeV[0]);
throw RuntimeError("Could not set quad to " +
std::to_string(arg.quad) +
" due to fifo strucutre memory allocation");
} }
impl()->setThresholdEnergy(arg.thresholdEnergyeV[0]); if (detType == EIGER || detType == JUNGFRAU) {
} impl()->setReadNRows(arg.readNRows);
if (detType == EIGER || detType == JUNGFRAU) {
impl()->setReadNRows(arg.readNRows);
}
if (detType == MYTHEN3) {
std::array<int, 3> val;
for (int i = 0; i < 3; ++i) {
val[i] = arg.thresholdEnergyeV[i];
} }
impl()->setThresholdEnergy(val); if (detType == MYTHEN3) {
} std::array<int, 3> val;
if (detType == EIGER || detType == MYTHEN3) { for (int i = 0; i < 3; ++i) {
try { val[i] = arg.thresholdEnergyeV[i];
}
impl()->setThresholdEnergy(val);
}
if (detType == EIGER || detType == MYTHEN3) {
impl()->setDynamicRange(arg.dynamicRange); impl()->setDynamicRange(arg.dynamicRange);
} catch (const RuntimeError &e) {
throw RuntimeError(
"Could not set dynamic range. Could not allocate "
"memory for fifo or could not start listening/writing threads");
} }
} impl()->setTimingMode(arg.timMode);
impl()->setTimingMode(arg.timMode); if (detType == EIGER || detType == MOENCH || detType == CHIPTESTBOARD ||
if (detType == EIGER || detType == MOENCH || detType == CHIPTESTBOARD || detType == MYTHEN3) {
detType == MYTHEN3) {
try {
impl()->setTenGigaEnable(arg.tenGiga); impl()->setTenGigaEnable(arg.tenGiga);
} catch (const RuntimeError &e) {
throw RuntimeError("Could not set 10GbE.");
} }
} if (detType == CHIPTESTBOARD) {
if (detType == CHIPTESTBOARD) {
try {
impl()->setReadoutMode(arg.roMode); impl()->setReadoutMode(arg.roMode);
} catch (const RuntimeError &e) {
throw RuntimeError("Could not set read out mode "
"due to fifo memory allocation.");
} }
} if (detType == CHIPTESTBOARD || detType == MOENCH) {
if (detType == CHIPTESTBOARD || detType == MOENCH) {
try {
impl()->setADCEnableMask(arg.adcMask); impl()->setADCEnableMask(arg.adcMask);
} catch (const RuntimeError &e) {
throw RuntimeError("Could not set adc enable mask "
"due to fifo memory allcoation");
}
try {
impl()->setTenGigaADCEnableMask(arg.adc10gMask); impl()->setTenGigaADCEnableMask(arg.adc10gMask);
} catch (const RuntimeError &e) {
throw RuntimeError("Could not set 10Gb adc enable mask "
"due to fifo memory allcoation");
} }
} if (detType == GOTTHARD) {
if (detType == GOTTHARD) {
try {
impl()->setDetectorROI(arg.roi); impl()->setDetectorROI(arg.roi);
} catch (const RuntimeError &e) {
throw RuntimeError("Could not set ROI");
} }
if (detType == MYTHEN3) {
impl()->setCounterMask(arg.countermask);
impl()->setAcquisitionTime1(
std::chrono::nanoseconds(arg.expTime1Ns));
impl()->setAcquisitionTime2(
std::chrono::nanoseconds(arg.expTime2Ns));
impl()->setAcquisitionTime3(
std::chrono::nanoseconds(arg.expTime3Ns));
impl()->setGateDelay1(std::chrono::nanoseconds(arg.gateDelay1Ns));
impl()->setGateDelay2(std::chrono::nanoseconds(arg.gateDelay2Ns));
impl()->setGateDelay3(std::chrono::nanoseconds(arg.gateDelay3Ns));
impl()->setNumberOfGates(arg.gates);
}
if (detType == GOTTHARD2) {
impl()->setBurstMode(arg.burstType);
}
impl()->setScan(arg.scanParams);
} catch (std::exception &e) {
throw RuntimeError("Could not setup receiver [" +
std::string(e.what()) + ']');
} }
if (detType == MYTHEN3) {
impl()->setCounterMask(arg.countermask);
impl()->setAcquisitionTime1(std::chrono::nanoseconds(arg.expTime1Ns));
impl()->setAcquisitionTime2(std::chrono::nanoseconds(arg.expTime2Ns));
impl()->setAcquisitionTime3(std::chrono::nanoseconds(arg.expTime3Ns));
impl()->setGateDelay1(std::chrono::nanoseconds(arg.gateDelay1Ns));
impl()->setGateDelay2(std::chrono::nanoseconds(arg.gateDelay2Ns));
impl()->setGateDelay3(std::chrono::nanoseconds(arg.gateDelay3Ns));
impl()->setNumberOfGates(arg.gates);
}
if (detType == GOTTHARD2) {
impl()->setBurstMode(arg.burstType);
}
impl()->setScan(arg.scanParams);
return socket.sendResult(retvals); return socket.sendResult(retvals);
} }
@ -502,13 +459,10 @@ void ClientInterface::setDetectorType(detectorType arg) {
detType = GENERIC; detType = GENERIC;
receiver = make_unique<Implementation>(arg); receiver = make_unique<Implementation>(arg);
detType = arg; detType = arg;
} catch (std::exception &e) { } catch (const std::exception &e) {
std::ostringstream os; throw RuntimeError("Could not set detector type in the receiver. [" +
os << "Could not set detector type in the receiver. "; std::string(e.what()) + ']');
os << e.what();
throw RuntimeError(os.str());
} }
// callbacks after (in setdetectortype, the object is reinitialized) // callbacks after (in setdetectortype, the object is reinitialized)
if (startAcquisitionCallBack != nullptr) if (startAcquisitionCallBack != nullptr)
impl()->registerCallBackStartAcquisition(startAcquisitionCallBack, impl()->registerCallBackStartAcquisition(startAcquisitionCallBack,
@ -536,8 +490,8 @@ int ClientInterface::set_detector_roi(Interface &socket) {
verifyIdle(socket); verifyIdle(socket);
try { try {
impl()->setDetectorROI(arg); impl()->setDetectorROI(arg);
} catch (const RuntimeError &e) { } catch (const std::exception &e) {
throw RuntimeError("Could not set ROI"); throw RuntimeError("Could not set ROI [" + std::string(e.what()) + ']');
} }
return socket.Send(OK); return socket.Send(OK);
} }
@ -616,10 +570,10 @@ int ClientInterface::set_num_analog_samples(Interface &socket) {
} }
try { try {
impl()->setNumberofAnalogSamples(value); impl()->setNumberofAnalogSamples(value);
} catch (const RuntimeError &e) { } catch (const std::exception &e) {
throw RuntimeError("Could not set num analog samples to " + throw RuntimeError("Could not set number of analog samples to " +
std::to_string(value) + std::to_string(value) + " [" +
" due to fifo structure memory allocation."); std::string(e.what()) + ']');
} }
return socket.Send(OK); return socket.Send(OK);
} }
@ -632,11 +586,12 @@ int ClientInterface::set_num_digital_samples(Interface &socket) {
} }
try { try {
impl()->setNumberofDigitalSamples(value); impl()->setNumberofDigitalSamples(value);
} catch (const RuntimeError &e) { } catch (const std::exception &e) {
throw RuntimeError("Could not set num digital samples to " + throw RuntimeError("Could not set number of digital samples to " +
std::to_string(value) + std::to_string(value) + " [" +
" due to fifo structure memory allocation."); std::string(e.what()) + ']');
} }
return socket.Send(OK); return socket.Send(OK);
} }
@ -743,9 +698,9 @@ int ClientInterface::set_dynamic_range(Interface &socket) {
} else { } else {
try { try {
impl()->setDynamicRange(dr); impl()->setDynamicRange(dr);
} catch (const RuntimeError &e) { } catch (const std::exception &e) {
throw RuntimeError("Could not allocate memory for fifo or " throw RuntimeError("Could not set dynamic range [" +
"could not start listening/writing threads"); std::string(e.what()) + ']');
} }
} }
} }
@ -781,7 +736,12 @@ int ClientInterface::get_status(Interface &socket) {
int ClientInterface::start_receiver(Interface &socket) { int ClientInterface::start_receiver(Interface &socket) {
if (impl()->getStatus() == IDLE) { if (impl()->getStatus() == IDLE) {
LOG(logDEBUG1) << "Starting Receiver"; LOG(logDEBUG1) << "Starting Receiver";
impl()->startReceiver(); try {
impl()->startReceiver();
} catch (const std::exception &e) {
throw RuntimeError("Could not start reciever [" +
std::string(e.what()) + ']');
}
} }
return socket.Send(OK); return socket.Send(OK);
} }
@ -791,12 +751,16 @@ int ClientInterface::stop_receiver(Interface &socket) {
if (impl()->getStatus() == RUNNING) { if (impl()->getStatus() == RUNNING) {
LOG(logDEBUG1) << "Stopping Receiver"; LOG(logDEBUG1) << "Stopping Receiver";
impl()->setStoppedFlag(static_cast<bool>(arg)); impl()->setStoppedFlag(static_cast<bool>(arg));
impl()->stopReceiver(); try {
impl()->stopReceiver();
} catch (const std::exception &e) {
throw RuntimeError("Could not stop receiver [" +
std::string(e.what()) + ']');
}
} }
auto s = impl()->getStatus(); auto s = impl()->getStatus();
if (s != IDLE) if (s != IDLE)
throw RuntimeError("Could not stop receiver. It as it is: " + throw RuntimeError("Could not stop receiver. Status: " + ToString(s));
ToString(s));
return socket.Send(OK); return socket.Send(OK);
} }
@ -811,7 +775,12 @@ int ClientInterface::set_file_dir(Interface &socket) {
throw RuntimeError("Receiver path needs to be absolute path"); throw RuntimeError("Receiver path needs to be absolute path");
LOG(logDEBUG1) << "Setting file path: " << fpath; LOG(logDEBUG1) << "Setting file path: " << fpath;
impl()->setFilePath(fpath); try {
impl()->setFilePath(fpath);
} catch (const std::exception &e) {
throw RuntimeError("Could not set file path [" + std::string(e.what()) +
']');
}
return socket.Send(OK); return socket.Send(OK);
} }
@ -893,7 +862,12 @@ int ClientInterface::set_file_write(Interface &socket) {
} }
verifyIdle(socket); verifyIdle(socket);
LOG(logDEBUG1) << "Setting File write enable:" << enable; LOG(logDEBUG1) << "Setting File write enable:" << enable;
impl()->setFileWriteEnable(enable); try {
impl()->setFileWriteEnable(enable);
} catch (const std::exception &e) {
throw RuntimeError("Could not enable/disable file write [" +
std::string(e.what()) + ']');
}
return socket.Send(OK); return socket.Send(OK);
} }
@ -948,8 +922,9 @@ int ClientInterface::enable_tengiga(Interface &socket) {
LOG(logDEBUG1) << "Setting 10GbE:" << val; LOG(logDEBUG1) << "Setting 10GbE:" << val;
try { try {
impl()->setTenGigaEnable(val); impl()->setTenGigaEnable(val);
} catch (const RuntimeError &e) { } catch (const std::exception &e) {
throw RuntimeError("Could not set 10GbE."); throw RuntimeError("Could not set 10GbE. [" +
std::string(e.what()) + ']');
} }
} }
int retval = impl()->getTenGigaEnable(); int retval = impl()->getTenGigaEnable();
@ -965,9 +940,9 @@ int ClientInterface::set_fifo_depth(Interface &socket) {
LOG(logDEBUG1) << "Setting fifo depth:" << value; LOG(logDEBUG1) << "Setting fifo depth:" << value;
try { try {
impl()->setFifoDepth(value); impl()->setFifoDepth(value);
} catch (const RuntimeError &e) { } catch (const std::exception &e) {
throw RuntimeError("Could not set fifo depth due to fifo structure " throw RuntimeError("Could not set fifo depth [" +
"memory allocation."); std::string(e.what()) + ']');
} }
} }
int retval = impl()->getFifoDepth(); int retval = impl()->getFifoDepth();
@ -1002,10 +977,12 @@ int ClientInterface::set_streaming(Interface &socket) {
LOG(logDEBUG1) << "Setting data stream enable:" << index; LOG(logDEBUG1) << "Setting data stream enable:" << index;
try { try {
impl()->setDataStreamEnable(index); impl()->setDataStreamEnable(index);
} catch (const RuntimeError &e) { } catch (const std::exception &e) {
throw RuntimeError("Could not set data stream enable to " + throw RuntimeError("Could not set data stream enable to " +
std::to_string(index)); std::to_string(index) + " [" +
std::string(e.what()) + ']');
} }
return socket.Send(OK); return socket.Send(OK);
} }
@ -1064,7 +1041,12 @@ int ClientInterface::set_file_format(Interface &socket) {
} }
verifyIdle(socket); verifyIdle(socket);
LOG(logDEBUG1) << "Setting file format:" << f; LOG(logDEBUG1) << "Setting file format:" << f;
impl()->setFileFormat(f); try {
impl()->setFileFormat(f);
} catch (const std::exception &e) {
throw RuntimeError("Could not set file format to " + ToString(f) +
" [" + std::string(e.what()) + ']');
}
auto retval = impl()->getFileFormat(); auto retval = impl()->getFileFormat();
validate(f, retval, "set file format", DEC); validate(f, retval, "set file format", DEC);
@ -1185,7 +1167,13 @@ int ClientInterface::set_udp_socket_buffer_size(Interface &socket) {
"Receiver socket buffer size exceeded max (INT_MAX/2)"); "Receiver socket buffer size exceeded max (INT_MAX/2)");
} }
LOG(logDEBUG1) << "Setting UDP Socket Buffer size: " << size; LOG(logDEBUG1) << "Setting UDP Socket Buffer size: " << size;
impl()->setUDPSocketBufferSize(size); try {
impl()->setUDPSocketBufferSize(size);
} catch (const std::exception &e) {
throw RuntimeError("Could not set udp socket buffer size to " +
std::to_string(size) + " [" +
std::string(e.what()) + ']');
}
} }
int retval = impl()->getUDPSocketBufferSize(); int retval = impl()->getUDPSocketBufferSize();
if (size != 0) if (size != 0)
@ -1264,9 +1252,9 @@ int ClientInterface::set_readout_mode(Interface &socket) {
LOG(logDEBUG1) << "Setting readout mode: " << arg; LOG(logDEBUG1) << "Setting readout mode: " << arg;
try { try {
impl()->setReadoutMode(arg); impl()->setReadoutMode(arg);
} catch (const RuntimeError &e) { } catch (const std::exception &e) {
throw RuntimeError( throw RuntimeError("Could not set read out mode [" +
"Could not set read out mode due to fifo memory allocation."); std::string(e.what()) + ']');
} }
} }
auto retval = impl()->getReadoutMode(); auto retval = impl()->getReadoutMode();
@ -1282,10 +1270,11 @@ int ClientInterface::set_adc_mask(Interface &socket) {
LOG(logDEBUG1) << "Setting 1Gb ADC enable mask: " << arg; LOG(logDEBUG1) << "Setting 1Gb ADC enable mask: " << arg;
try { try {
impl()->setADCEnableMask(arg); impl()->setADCEnableMask(arg);
} catch (const RuntimeError &e) { } catch (const std::exception &e) {
throw RuntimeError( throw RuntimeError("Could not set adc enable mask [" +
"Could not set adc enable mask due to fifo memory allcoation"); std::string(e.what()) + ']');
} }
auto retval = impl()->getADCEnableMask(); auto retval = impl()->getADCEnableMask();
if (retval != arg) { if (retval != arg) {
std::ostringstream os; std::ostringstream os;
@ -1349,10 +1338,10 @@ int ClientInterface::set_quad_type(Interface &socket) {
LOG(logDEBUG1) << "Setting quad:" << quadEnable; LOG(logDEBUG1) << "Setting quad:" << quadEnable;
try { try {
impl()->setQuad(quadEnable == 0 ? false : true); impl()->setQuad(quadEnable == 0 ? false : true);
} catch (const RuntimeError &e) { } catch (const std::exception &e) {
throw RuntimeError("Could not set quad to " + throw RuntimeError("Could not set quad to " +
std::to_string(quadEnable) + std::to_string(quadEnable) + " [" +
" due to fifo strucutre memory allocation"); std::string(e.what()) + ']');
} }
} }
int retval = impl()->getQuad() ? 1 : 0; int retval = impl()->getQuad() ? 1 : 0;
@ -1487,10 +1476,12 @@ int ClientInterface::set_num_interfaces(Interface &socket) {
LOG(logDEBUG1) << "Setting Number of UDP Interfaces:" << arg; LOG(logDEBUG1) << "Setting Number of UDP Interfaces:" << arg;
try { try {
impl()->setNumberofUDPInterfaces(arg); impl()->setNumberofUDPInterfaces(arg);
} catch (const RuntimeError &e) { } catch (const std::exception &e) {
throw RuntimeError("Failed to set number of interfaces to " + throw RuntimeError("Could not set number of interfaces to " +
std::to_string(arg)); std::to_string(arg) + " [" + std::string(e.what()) +
']');
} }
return socket.Send(OK); return socket.Send(OK);
} }
@ -1500,10 +1491,11 @@ int ClientInterface::set_adc_mask_10g(Interface &socket) {
LOG(logDEBUG1) << "Setting 10Gb ADC enable mask: " << arg; LOG(logDEBUG1) << "Setting 10Gb ADC enable mask: " << arg;
try { try {
impl()->setTenGigaADCEnableMask(arg); impl()->setTenGigaADCEnableMask(arg);
} catch (const RuntimeError &e) { } catch (const std::exception &e) {
throw RuntimeError( throw RuntimeError("Could not set 10Gb adc enable mask [" +
"Could not set 10Gb adc enable mask due to fifo memory allcoation"); std::string(e.what()) + ']');
} }
auto retval = impl()->getTenGigaADCEnableMask(); auto retval = impl()->getTenGigaADCEnableMask();
if (retval != arg) { if (retval != arg) {
std::ostringstream os; std::ostringstream os;
@ -1519,7 +1511,12 @@ int ClientInterface::set_counter_mask(Interface &socket) {
auto arg = socket.Receive<uint32_t>(); auto arg = socket.Receive<uint32_t>();
verifyIdle(socket); verifyIdle(socket);
LOG(logDEBUG1) << "Setting counters: " << arg; LOG(logDEBUG1) << "Setting counters: " << arg;
impl()->setCounterMask(arg); try {
impl()->setCounterMask(arg);
} catch (const std::exception &e) {
throw RuntimeError("Could not set counter mask [" +
std::string(e.what()) + ']');
}
return socket.Send(OK); return socket.Send(OK);
} }
@ -1715,7 +1712,12 @@ int ClientInterface::set_arping(Interface &socket) {
} }
verifyIdle(socket); verifyIdle(socket);
LOG(logDEBUG1) << "Starting/ Killing arping thread:" << value; LOG(logDEBUG1) << "Starting/ Killing arping thread:" << value;
impl()->setArping(value, udpips); try {
impl()->setArping(value, udpips);
} catch (const std::exception &e) {
throw RuntimeError("Could not start/kill arping thread [" +
std::string(e.what()) + ']');
}
return socket.Send(OK); return socket.Send(OK);
} }
@ -1733,9 +1735,11 @@ int ClientInterface::set_receiver_roi(Interface &socket) {
verifyIdle(socket); verifyIdle(socket);
try { try {
impl()->setReceiverROI(arg); impl()->setReceiverROI(arg);
} catch (const RuntimeError &e) { } catch (const std::exception &e) {
throw RuntimeError("Could not set ReceiverROI"); throw RuntimeError("Could not set Receiver ROI [" +
std::string(e.what()) + ']');
} }
return socket.Send(OK); return socket.Send(OK);
} }
@ -1747,9 +1751,11 @@ int ClientInterface::set_receiver_roi_metadata(Interface &socket) {
verifyIdle(socket); verifyIdle(socket);
try { try {
impl()->setReceiverROIMetadata(arg); impl()->setReceiverROIMetadata(arg);
} catch (const RuntimeError &e) { } catch (const std::exception &e) {
throw RuntimeError("Could not set ReceiverROI metadata"); throw RuntimeError("Could not set ReceiverROI metadata [" +
std::string(e.what()) + ']');
} }
return socket.Send(OK); return socket.Send(OK);
} }

View File

@ -78,11 +78,12 @@ void Implementation::SetupFifoStructure() {
try { try {
fifo.push_back( fifo.push_back(
sls::make_unique<Fifo>(i, datasize, generalData->fifoDepth)); sls::make_unique<Fifo>(i, datasize, generalData->fifoDepth));
} catch (...) { } catch (const std::exception &e) {
fifo.clear(); fifo.clear();
generalData->fifoDepth = 0; generalData->fifoDepth = 0;
throw RuntimeError("Could not allocate memory for fifo structure " + std::ostringstream oss;
std::to_string(i) + ". FifoDepth is now 0."); oss << e.what() << ". Fifo depth is now 0";
throw RuntimeError(oss.str());
} }
// set the listener & dataprocessor threads to point to the right fifo // set the listener & dataprocessor threads to point to the right fifo
if (listener.size()) if (listener.size())
@ -165,12 +166,10 @@ void Implementation::setDetectorType(const detectorType d) {
SetupListener(i); SetupListener(i);
dataProcessor.push_back(sls::make_unique<DataProcessor>(i)); dataProcessor.push_back(sls::make_unique<DataProcessor>(i));
SetupDataProcessor(i); SetupDataProcessor(i);
} catch (...) { } catch (const std::exception &e) {
listener.clear(); listener.clear();
dataProcessor.clear(); dataProcessor.clear();
throw RuntimeError( throw;
"Could not create listener/dataprocessor threads (index:" +
std::to_string(i) + ")");
} }
} }
@ -668,8 +667,9 @@ void Implementation::startReceiver() {
startAcquisitionCallBack(filePath, fileName, fileIndex, imageSize, startAcquisitionCallBack(filePath, fileName, fileIndex, imageSize,
pStartAcquisition); pStartAcquisition);
} catch (const std::exception &e) { } catch (const std::exception &e) {
throw RuntimeError("Start Acquisition Callback Error: " + std::ostringstream oss;
std::string(e.what())); oss << "Start Acquisition Callback Error: " << e.what();
throw RuntimeError(oss.str());
} }
if (rawDataReadyCallBack != nullptr) { if (rawDataReadyCallBack != nullptr) {
LOG(logINFO) << "Data Write has been defined externally"; LOG(logINFO) << "Data Write has been defined externally";
@ -784,8 +784,9 @@ void Implementation::stopReceiver() {
status = IDLE; status = IDLE;
LOG(logINFO) << "Receiver Stopped"; LOG(logINFO) << "Receiver Stopped";
LOG(logINFO) << "Status: " << ToString(status); LOG(logINFO) << "Status: " << ToString(status);
throw RuntimeError("Acquisition Finished Callback Error: " + std::ostringstream oss;
std::string(e.what())); oss << "Acquisition Finished Callback Error: " << e.what();
throw RuntimeError(oss.str());
} }
} }
} }
@ -866,7 +867,7 @@ void Implementation::CreateUDPSockets() {
} }
} catch (const RuntimeError &e) { } catch (const RuntimeError &e) {
shutDownUDPSockets(); shutDownUDPSockets();
throw RuntimeError("Could not create UDP Socket(s)."); throw;
} }
LOG(logDEBUG) << "UDP socket(s) created successfully."; LOG(logDEBUG) << "UDP socket(s) created successfully.";
} }
@ -886,7 +887,9 @@ void Implementation::SetupWriter() {
shutDownUDPSockets(); shutDownUDPSockets();
for (const auto &it : dataProcessor) for (const auto &it : dataProcessor)
it->CloseFiles(); it->CloseFiles();
throw RuntimeError("Could not create first data file."); std::ostringstream oss;
oss << "Could not set up writer: " << e.what();
throw RuntimeError(oss.str());
} }
} }
@ -975,10 +978,9 @@ void Implementation::StartMasterWriter() {
} }
} }
#endif #endif
} catch (std::exception &e) { } catch (const std::exception &e) {
// ignore it and just print it // ignore it and just print it
LOG(logWARNING) << "Caught exception when handling virtual hdf5 file [" LOG(logWARNING) << "Error creating master/virtualfiles: " << e.what();
<< e.what() << "]";
} }
} }
@ -1039,12 +1041,10 @@ void Implementation::setNumberofUDPInterfaces(const int n) {
SetupListener(i); SetupListener(i);
dataProcessor.push_back(sls::make_unique<DataProcessor>(i)); dataProcessor.push_back(sls::make_unique<DataProcessor>(i));
SetupDataProcessor(i); SetupDataProcessor(i);
} catch (...) { } catch (const std::exception &e) {
listener.clear(); listener.clear();
dataProcessor.clear(); dataProcessor.clear();
throw RuntimeError( throw;
"Could not create listener/dataprocessor threads (index:" +
std::to_string(i) + ")");
} }
// streamer threads // streamer threads
@ -1052,16 +1052,14 @@ void Implementation::setNumberofUDPInterfaces(const int n) {
try { try {
dataStreamer.push_back(sls::make_unique<DataStreamer>(i)); dataStreamer.push_back(sls::make_unique<DataStreamer>(i));
SetupDataStreamer(i); SetupDataStreamer(i);
} catch (...) { } catch (const std::exception &e) {
if (dataStreamEnable) { if (dataStreamEnable) {
dataStreamer.clear(); dataStreamer.clear();
dataStreamEnable = false; dataStreamEnable = false;
for (const auto &it : dataProcessor) for (const auto &it : dataProcessor)
it->SetDataStreamEnable(dataStreamEnable); it->SetDataStreamEnable(dataStreamEnable);
} }
throw RuntimeError( throw;
"Could not create datastreamer threads (index:" +
std::to_string(i) + ")");
} }
} }
} }
@ -1172,12 +1170,12 @@ void Implementation::setDataStreamEnable(const bool enable) {
try { try {
dataStreamer.push_back(sls::make_unique<DataStreamer>(i)); dataStreamer.push_back(sls::make_unique<DataStreamer>(i));
SetupDataStreamer(i); SetupDataStreamer(i);
} catch (...) { } catch (const std::exception &e) {
dataStreamer.clear(); dataStreamer.clear();
dataStreamEnable = false; dataStreamEnable = false;
for (const auto &it : dataProcessor) for (const auto &it : dataProcessor)
it->SetDataStreamEnable(dataStreamEnable); it->SetDataStreamEnable(dataStreamEnable);
throw RuntimeError("Could not set data stream enable."); throw;
} }
} }
SetThreadPriorities(); SetThreadPriorities();

View File

@ -323,7 +323,7 @@ class Implementation : private virtual slsDetectorDefs {
// acquisition // acquisition
std::atomic<runStatus> status{IDLE}; std::atomic<runStatus> status{IDLE};
bool stoppedFlag{false}; std::atomic<bool> stoppedFlag{false};
scanParameters scanParams{}; scanParameters scanParams{};
// network configuration (UDP) // network configuration (UDP)

View File

@ -148,30 +148,34 @@ void Listener::RecordFirstIndex(uint64_t fnum) {
} }
void Listener::CreateUDPSocket(int &actualSize) { void Listener::CreateUDPSocket(int &actualSize) {
if (disabledPort) {
return;
}
uint32_t packetSize = generalData->packetSize;
if (generalData->detType == GOTTHARD2 && index != 0) {
packetSize = generalData->vetoPacketSize;
}
try { try {
if (disabledPort) {
return;
}
uint32_t packetSize = generalData->packetSize;
if (generalData->detType == GOTTHARD2 && index != 0) {
packetSize = generalData->vetoPacketSize;
}
udpSocket = nullptr; udpSocket = nullptr;
udpSocket = make_unique<UdpRxSocket>( udpSocket = make_unique<UdpRxSocket>(
udpPortNumber, packetSize, udpPortNumber, packetSize,
(eth.length() ? InterfaceNameToIp(eth).str().c_str() : nullptr), (eth.length() ? InterfaceNameToIp(eth).str().c_str() : nullptr),
generalData->udpSocketBufferSize); generalData->udpSocketBufferSize);
LOG(logINFO) << index << ": UDP port opened at port " << udpPortNumber; LOG(logINFO) << index << ": UDP port opened at port " << udpPortNumber;
} catch (...) {
throw RuntimeError("Could not create UDP socket on port " + udpSocketAlive = true;
std::to_string(udpPortNumber));
// doubled due to kernel bookkeeping (could also be less due to
// permissions)
actualSize = udpSocket->getBufferSize();
} catch (std::exception &e) {
std::ostringstream oss;
oss << "Could not create UDP socket on port " << udpPortNumber << " ["
<< e.what() << ']';
throw RuntimeError(oss.str());
} }
udpSocketAlive = true;
// doubled due to kernel bookkeeping (could also be less due to permissions)
actualSize = udpSocket->getBufferSize();
} }
void Listener::ShutDownUDPSocket() { void Listener::ShutDownUDPSocket() {

View File

@ -1,7 +1,7 @@
// SPDX-License-Identifier: LGPL-3.0-or-other // SPDX-License-Identifier: LGPL-3.0-or-other
// Copyright (C) 2021 Contributors to the SLS Detector Package // Copyright (C) 2021 Contributors to the SLS Detector Package
/** API versions */ /** API versions */
#define RELEASE "7.0.0.rc3" #define RELEASE "7.0.0.rc4"
#define APICTB "7.0.0.rc3 0x230130" #define APICTB "7.0.0.rc3 0x230130"
#define APIGOTTHARD "7.0.0.rc3 0x230130" #define APIGOTTHARD "7.0.0.rc3 0x230130"
#define APIGOTTHARD2 "7.0.0.rc3 0x230130" #define APIGOTTHARD2 "7.0.0.rc3 0x230130"
@ -9,5 +9,5 @@
#define APIMYTHEN3 "7.0.0.rc3 0x230130" #define APIMYTHEN3 "7.0.0.rc3 0x230130"
#define APIMOENCH "7.0.0.rc3 0x230130" #define APIMOENCH "7.0.0.rc3 0x230130"
#define APIEIGER "7.0.0.rc3 0x230130" #define APIEIGER "7.0.0.rc3 0x230130"
#define APILIB "7.0.0.rc3 0x230210" #define APILIB "7.0.0.rc4 0x230214"
#define APIRECEIVER "7.0.0.rc3 0x230210" #define APIRECEIVER "7.0.0.rc4 0x230214"

View File

@ -27,15 +27,18 @@ UdpRxSocket::UdpRxSocket(int port, ssize_t packet_size, const char *hostname,
const std::string portname = std::to_string(port); const std::string portname = std::to_string(port);
if (getaddrinfo(hostname, portname.c_str(), &hints, &res)) { if (getaddrinfo(hostname, portname.c_str(), &hints, &res)) {
throw RuntimeError("Failed at getaddrinfo with " + throw RuntimeError("Failed at getaddrinfo with " +
std::string(hostname)); std::string(hostname) + " [" +
std::string(strerror(errno)) + ']');
} }
sockfd_ = socket(res->ai_family, res->ai_socktype, res->ai_protocol); sockfd_ = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
if (sockfd_ == -1) { if (sockfd_ == -1) {
throw RuntimeError("Failed to create UDP RX socket"); throw RuntimeError("Failed to create UDP RX socket [" +
std::string(strerror(errno)) + ']');
} }
if (bind(sockfd_, res->ai_addr, res->ai_addrlen) == -1) { if (bind(sockfd_, res->ai_addr, res->ai_addrlen) == -1) {
close(sockfd_); close(sockfd_);
throw RuntimeError("Failed to bind UDP RX socket"); throw RuntimeError("Failed to bind UDP RX socket [" +
std::string(strerror(errno)) + ']');
} }
freeaddrinfo(res); freeaddrinfo(res);
@ -74,13 +77,15 @@ int UdpRxSocket::getBufferSize() const {
int ret = 0; int ret = 0;
socklen_t optlen = sizeof(ret); socklen_t optlen = sizeof(ret);
if (getsockopt(sockfd_, SOL_SOCKET, SO_RCVBUF, &ret, &optlen) == -1) if (getsockopt(sockfd_, SOL_SOCKET, SO_RCVBUF, &ret, &optlen) == -1)
throw RuntimeError("Could not get socket buffer size"); throw RuntimeError("Could not get socket buffer size [" +
std::string(strerror(errno)) + ']');
return ret; return ret;
} }
void UdpRxSocket::setBufferSize(int size) { void UdpRxSocket::setBufferSize(int size) {
if (setsockopt(sockfd_, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size))) if (setsockopt(sockfd_, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size)))
throw RuntimeError("Could not set socket buffer size"); throw RuntimeError("Could not set socket buffer size [" +
std::string(strerror(errno)) + ']');
} }
void UdpRxSocket::Shutdown() { void UdpRxSocket::Shutdown() {