9 #include <sys/socket.h>
11 #include <arpa/inet.h>
12 #include <sys/types.h>
21 #define TRACE_NAME "TCPSocketTransfer"
22 #include "artdaq/DAQdata/Globals.hh"
25 #include "artdaq/TransferPlugins/TCPSocketTransfer.hh"
28 #include "artdaq/TransferPlugins/detail/Timeout.hh"
29 #include "artdaq/TransferPlugins/detail/SRSockets.hh"
30 #include "artdaq-core/Data/Fragment.hh"
31 #include "artdaq-core/Utilities/TimeUtils.hh"
34 std::atomic<int> artdaq::TCPSocketTransfer::listen_thread_refcount_(0);
35 std::unique_ptr<boost::thread> artdaq::TCPSocketTransfer::listen_thread_ =
nullptr;
36 std::map<int, std::set<int>> artdaq::TCPSocketTransfer::connected_fds_ = std::map<int, std::set<int>>();
37 std::mutex artdaq::TCPSocketTransfer::listen_thread_mutex_;
43 , active_receive_fd_(-1)
44 , last_active_receive_fd_(-1)
45 , rcvbuf_(pset.get<size_t>(
"tcp_receive_buffer_size", 0))
46 , sndbuf_(max_fragment_size_words_ * sizeof(artdaq::RawDataType) * buffer_count_)
47 , send_retry_timeout_us_(pset.get<size_t>(
"send_retry_timeout_us", 1000000))
48 , stats_connect_stop_(false)
50 , timeoutMessageArmed_(true)
51 , not_connected_count_(0)
52 , receive_err_threshold_(pset.get<size_t>(
"receive_socket_disconnected_max_count", 1000))
53 , receive_err_wait_us_(pset.get<size_t>(
"receive_socket_disconnected_wait_us", 10000))
56 auto masterPortOffset = pset.get<
int>(
"offset_all_ports", 0);
57 hostMap_ = MakeHostMap(pset, masterPortOffset);
59 std::function<void()>
function = std::bind(&TCPSocketTransfer::reconnect_,
this);
65 TLOG(TLVL_DEBUG) <<
GetTraceName() <<
": Listening for connections";
66 start_listen_thread_();
67 TLOG(TLVL_DEBUG) <<
GetTraceName() <<
": Done Listening";
71 TLOG(TLVL_DEBUG) <<
GetTraceName() <<
": Connecting to destination";
73 TLOG(TLVL_DEBUG) <<
GetTraceName() <<
": Done Connecting";
75 TLOG(TLVL_DEBUG) <<
GetTraceName() <<
": End of Constructor";
78 artdaq::TCPSocketTransfer::~TCPSocketTransfer() noexcept
80 TLOG(TLVL_DEBUG) << GetTraceName() <<
": Shutting down TCPSocketTransfer";
81 stats_connect_stop_ =
true;
82 stopstatscv_.notify_all();
83 stats_connect_thread_.join();
92 timeval tv = { 0,100000 };
93 socklen_t len =
sizeof(tv);
94 setsockopt(send_fd_, SOL_SOCKET, SO_SNDTIMEO, &tv, len);
95 write(send_fd_, &mh,
sizeof(mh));
101 auto it = connected_fds_[source_rank()].begin();
102 while (it != connected_fds_[source_rank()].end())
105 it = connected_fds_[source_rank()].erase(it);
108 std::unique_lock<std::mutex> lk(listen_thread_mutex_);
109 listen_thread_refcount_--;
110 if (listen_thread_refcount_ == 0 && listen_thread_ && listen_thread_->joinable())
112 listen_thread_->join();
115 TLOG(TLVL_DEBUG) << GetTraceName() <<
": End of Destructor";
120 TLOG(5) << GetTraceName() <<
": receiveFragmentHeader: BEGIN";
121 int ret_rank = RECV_TIMEOUT;
123 if (connected_fds_[source_rank()].size() == 0)
125 if (++not_connected_count_ > receive_err_threshold_) {
return DATA_END; }
126 TLOG(7) << GetTraceName() <<
": receiveFragmentHeader: Receive socket not connected, returning RECV_TIMEOUT";
127 usleep(receive_err_wait_us_);
130 not_connected_count_ = 0;
132 TLOG(5) << GetTraceName() <<
": receiveFragmentHeader timeout_usec=" << std::to_string(timeout_usec);
137 SocketState state = SocketState::Metadata;
138 int target_bytes =
sizeof(
MessHead);
139 uint64_t start_time_us = TimeUtils::gettimeofday_us();
151 if (timeout_usec == 0)
154 timeout_ms = (timeout_usec + 999) / 1000;
157 while (!done && connected_fds_[source_rank()].size() > 0)
159 if (active_receive_fd_ == -1)
161 size_t fd_count = connected_fds_[source_rank()].size();
162 auto iter = connected_fds_[source_rank()].begin();
163 std::vector<pollfd> pollfds(fd_count);
164 for (
size_t ii = 0; ii < fd_count; ++ii)
166 pollfds[ii].events = POLLIN | POLLERR;
167 pollfds[ii].fd = *iter;
172 int num_fds_ready = poll(&pollfds[0], fd_count, timeout_ms);
173 if (num_fds_ready <= 0)
175 if (num_fds_ready == 0 && timeout_ms > 0)
177 TLOG(5) << GetTraceName() <<
": receiveFragmentHeader: No data on receive socket, returning RECV_TIMEOUT";
184 if (last_active_receive_fd_ != -1)
186 for (
auto& pollfd : pollfds)
189 if (pollfd.fd == last_active_receive_fd_)
196 int active_index = -1;
197 short anomolous_events = 0;
198 for (
size_t ii = index; ii < index + pollfds.size(); ++ii)
200 if (pollfds[index % pollfds.size()].revents & (POLLIN | POLLPRI | POLLHUP | POLLERR))
202 active_index = index % pollfds.size();
203 active_receive_fd_ = pollfds[active_index].fd;
206 else if (pollfds[index % pollfds.size()].revents & (POLLNVAL))
208 TLOG(TLVL_DEBUG) << GetTraceName() <<
": receiveFragmentHeader: FD is closed, most likely because the peer went away. Removing from fd list.";
209 close(pollfds[active_index].fd);
210 connected_fds_[source_rank()].erase(pollfds[active_index].fd);
213 else if (pollfds[index % pollfds.size()].revents)
215 anomolous_events |= pollfds[index % pollfds.size()].revents;
219 if (active_index == -1)
221 TLOG(TLVL_DEBUG) << GetTraceName() <<
": receiveFragmentHeader: Wrong event received from a pollfd. Mask: " <<
static_cast<int>(anomolous_events);
222 active_receive_fd_ = -1;
226 if (!done && timeout_usec > 0)
229 size_t delta_us = TimeUtils::gettimeofday_us() - start_time_us;
230 if (delta_us > timeout_usec)
234 timeout_ms = ((timeout_usec - delta_us) + 999) / 1000;
238 if (state == SocketState::Metadata)
241 buff = &(mha[offset]);
242 byte_cnt =
sizeof(
MessHead) - offset;
247 buff =
reinterpret_cast<uint8_t*
>(&header) + offset;
253 TLOG(6) << GetTraceName() <<
": receiveFragmentHeader: Reading " << byte_cnt <<
" bytes from socket";
254 sts = read(active_receive_fd_, buff, byte_cnt);
255 TLOG(6) << GetTraceName() <<
": receiveFragmentHeader: Done with read";
258 TLOG(7) << GetTraceName() <<
": receiveFragmentHeader state=" <<
static_cast<int>(state) <<
" read=" << sts;
261 TLOG(TLVL_WARNING) << GetTraceName() <<
": receiveFragmentHeader: Error on receive, closing socket " <<
" (errno=" << errno <<
": " << strerror(errno) <<
")";
262 close(active_receive_fd_);
263 connected_fds_[source_rank()].erase(active_receive_fd_);
264 active_receive_fd_ = -1;
270 if (sts >= target_bytes)
272 TLOG(7) << GetTraceName() <<
": receiveFragmentHeader: Target read bytes reached. Changing state";
274 if (state == SocketState::Metadata)
276 state = SocketState::Data;
283 TLOG(TLVL_DEBUG) << GetTraceName() <<
": receiveFragmentHeader: Stop Message received. Closing socket";
284 close(active_receive_fd_);
285 connected_fds_[source_rank()].erase(active_receive_fd_);
286 active_receive_fd_ = -1;
291 ret_rank = source_rank();
292 TLOG(8) << GetTraceName() <<
": receiveFragmentHeader done sts=" << sts <<
" src=" << ret_rank;
293 TLOG(7) << GetTraceName() <<
": receiveFragmentHeader: Done receiving fragment header. Moving into output.";
303 TLOG(5) << GetTraceName() <<
": receiveFragmentHeader: Returning " << ret_rank;
309 TLOG(9) << GetTraceName() <<
": receiveFragmentData: BEGIN";
310 int ret_rank = RECV_TIMEOUT;
311 if (active_receive_fd_ == -1)
313 TLOG(TLVL_DEBUG) << GetTraceName() <<
": receiveFragmentData: Receive socket not connected, returning RECV_TIMEOUT";
322 SocketState state = SocketState::Metadata;
323 int target_bytes =
sizeof(
MessHead);
326 pollfd_s.events = POLLIN | POLLPRI | POLLERR;
327 pollfd_s.fd = active_receive_fd_;
332 TLOG(TLVL_DEBUG) << GetTraceName() <<
": receiveFragmentData: Polling fd to see if there's data";
333 int num_fds_ready = poll(&pollfd_s, 1, 1000);
334 if (num_fds_ready <= 0)
336 if (num_fds_ready == 0)
338 TLOG(9) << GetTraceName() <<
": receiveFragmentData: No data on receive socket, returning RECV_TIMEOUT";
339 active_receive_fd_ = -1;
343 TLOG(TLVL_ERROR) <<
"Error in poll: errno=" << errno;
344 active_receive_fd_ = -1;
348 if (pollfd_s.revents & (POLLNVAL))
350 TLOG(TLVL_DEBUG) << GetTraceName() <<
": receiveFragmentData: FD is closed, most likely because the peer went away. Removing from fd list.";
351 close(active_receive_fd_);
352 connected_fds_[source_rank()].erase(active_receive_fd_);
353 active_receive_fd_ = -1;
356 else if (!(pollfd_s.revents & (POLLIN | POLLPRI | POLLERR)))
358 TLOG(TLVL_DEBUG) << GetTraceName() <<
": receiveFragmentData: Wrong event received from pollfd: " << pollfd_s.revents;
359 close(active_receive_fd_);
360 connected_fds_[source_rank()].erase(active_receive_fd_);
364 if (state == SocketState::Metadata)
367 buff = &(mha[offset]);
368 byte_cnt =
sizeof(
MessHead) - offset;
373 buff =
reinterpret_cast<uint8_t*
>(destination) + offset;
378 sts = read(active_receive_fd_, buff, byte_cnt);
381 TLOG(10) << GetTraceName() <<
": recvFragment state=" <<
static_cast<int>(state) <<
" read=" << sts;
384 TLOG(TLVL_DEBUG) << GetTraceName() <<
": receiveFragmentData: Error on receive, closing socket"
385 <<
" (errno=" << errno <<
": " << strerror(errno) <<
")";
386 close(active_receive_fd_);
387 connected_fds_[source_rank()].erase(active_receive_fd_);
388 active_receive_fd_ = -1;
394 if (sts >= target_bytes)
396 TLOG(9) << GetTraceName() <<
": receiveFragmentData: Target read bytes reached. Changing state";
398 if (state == SocketState::Metadata)
400 state = SocketState::Data;
407 ret_rank = source_rank();
408 TLOG(11) << GetTraceName() <<
": receiveFragmentData done sts=" << sts <<
" src=" << ret_rank;
409 TLOG(9) << GetTraceName() <<
": receiveFragmentData: Done receiving fragment. Moving into output.";
418 if (target_bytes == 0 && state == SocketState::Data)
420 ret_rank = source_rank();
421 TLOG(11) << GetTraceName() <<
": receiveFragmentData done sts=" << sts <<
" src=" << ret_rank;
422 TLOG(9) << GetTraceName() <<
": receiveFragmentData: Done receiving fragment. Moving into output.";
429 last_active_receive_fd_ = active_receive_fd_;
430 active_receive_fd_ = -1;
432 TLOG(9) << GetTraceName() <<
": receiveFragmentData: Returning " << ret_rank;
440 TLOG(12) << GetTraceName() <<
": sendFragment begin";
441 artdaq::Fragment grab_ownership_frag = std::move(frag);
445 iovec iov = {
reinterpret_cast<void*
>(grab_ownership_frag.headerAddress()),
446 detail::RawFragmentHeader::num_words() *
sizeof(RawDataType) };
448 auto sts = sendData_(&iov, 1, send_retry_timeout_us_);
449 auto start_time = std::chrono::steady_clock::now();
451 while (sts != CopyStatus::kSuccess && (send_timeout_usec == 0 || TimeUtils::GetElapsedTimeMicroseconds(start_time) < send_timeout_usec) && TimeUtils::GetElapsedTimeMicroseconds(start_time) < 10000000)
453 TLOG(13) << GetTraceName() <<
": sendFragment: Timeout or Error sending fragment";
454 sts = sendData_(&iov, 1, send_retry_timeout_us_);
457 if (sts != CopyStatus::kSuccess)
return sts;
461 iov = {
reinterpret_cast<void*
>(grab_ownership_frag.headerAddress() + detail::RawFragmentHeader::num_words()),
462 grab_ownership_frag.sizeBytes() - detail::RawFragmentHeader::num_words() *
sizeof(RawDataType) };
463 sts = sendData_(&iov, 1, send_retry_timeout_us_);
464 start_time = std::chrono::steady_clock::now();
465 while (sts != CopyStatus::kSuccess && (send_timeout_usec == 0 || TimeUtils::GetElapsedTimeMicroseconds(start_time) < send_timeout_usec) && TimeUtils::GetElapsedTimeMicroseconds(start_time) < 10000000)
467 TLOG(13) << GetTraceName() <<
": sendFragment: Timeout or Error sending fragment";
468 sts = sendData_(&iov, 1, send_retry_timeout_us_);
472 TLOG(12) << GetTraceName() <<
": sendFragment returning kSuccess";
478 TLOG(TLVL_DEBUG) << GetTraceName() <<
": sendData_ Converting buf to iovec";
479 iovec iov = { (
void*)buf, bytes };
480 return sendData_(&iov, 1, send_timeout_usec);
488 if (timeoutMessageArmed_)
490 TLOG(TLVL_DEBUG) << GetTraceName() <<
": sendData_: Send fd is not open. Returning kTimeout";
491 timeoutMessageArmed_ =
false;
493 return CopyStatus::kTimeout;
495 timeoutMessageArmed_ =
true;
496 TLOG(14) << GetTraceName() <<
": send_timeout_usec is " << std::to_string(send_timeout_usec) <<
", currently unused.";
499 uint32_t total_to_write_bytes = 0;
500 std::vector<iovec> iov_in(iovcnt + 1);
501 std::vector<iovec> iovv(iovcnt + 2);
503 for (ii = 0; ii < iovcnt; ++ii)
505 iov_in[ii + 1] = iov[ii];
506 total_to_write_bytes += iov[ii].iov_len;
509 MessHead mh = { 0,MessHead::data_v0,htons(source_rank()),{htonl(total_to_write_bytes)} };
510 iov_in[0].iov_base = &mh;
511 iov_in[0].iov_len =
sizeof(mh);
512 total_to_write_bytes +=
sizeof(mh);
515 ssize_t total_written_bytes = 0;
516 ssize_t per_write_max_bytes = (32 * 1024);
518 size_t in_iov_idx = 0;
519 size_t out_iov_idx = 0;
520 ssize_t this_write_bytes = 0;
527 (in_iov_idx + out_iov_idx) < iov_in.size() && this_write_bytes < per_write_max_bytes;
530 this_write_bytes += iov_in[in_iov_idx + out_iov_idx].iov_len;
531 iovv[out_iov_idx] = iov_in[in_iov_idx + out_iov_idx];
533 if (this_write_bytes > per_write_max_bytes)
535 iovv[out_iov_idx - 1].iov_len -= this_write_bytes - per_write_max_bytes;
536 this_write_bytes = per_write_max_bytes;
541 TLOG(14) << GetTraceName() <<
": sendFragment b4 writev " << std::setw(7) << std::to_string(total_written_bytes) <<
" total_written_bytes send_fd_=" << send_fd_ <<
" in_idx=" << std::to_string(in_iov_idx)
542 <<
" iovcnt=" << std::to_string(out_iov_idx) <<
" 1st.len=" << std::to_string(iovv[0].iov_len);
544 sts = writev(send_fd_, &(iovv[0]), out_iov_idx);
549 if (errno == EAGAIN )
551 TLOG(TLVL_DEBUG) << GetTraceName() <<
": sendFragment EWOULDBLOCK";
552 fcntl(send_fd_, F_SETFL, 0);
557 TLOG(TLVL_WARNING) << GetTraceName() <<
": sendFragment_: WRITE ERROR: " << strerror(errno);
563 else if (sts != this_write_bytes)
566 TLOG(TLVL_DEBUG) << GetTraceName() <<
": sendFragment writev sts(" << std::to_string(sts) <<
")!=requested_send_bytes(" << std::to_string(this_write_bytes) <<
")";
567 total_written_bytes += sts;
569 for (ii = 0; (size_t)sts >= iovv[ii].iov_len; ++ii)
570 sts -= iovv[ii].iov_len;
572 iovv[ii].iov_len -= sts;
573 iovv[ii].iov_base = (uint8_t*)(iovv[ii].iov_base) + sts;
578 iovv[out_iov_idx] = iovv[ii];
580 this_write_bytes = iovv[out_iov_idx].iov_len;
585 unsigned long additional = ((
unsigned long)iov_in[in_iov_idx].iov_base + iov_in[in_iov_idx].iov_len)
586 - ((
unsigned long)iovv[out_iov_idx].iov_base + iovv[out_iov_idx].iov_len);
589 iovv[out_iov_idx].iov_len += additional;
590 this_write_bytes += additional;
591 if (this_write_bytes > per_write_max_bytes)
593 iovv[out_iov_idx].iov_len -= this_write_bytes - per_write_max_bytes;
594 this_write_bytes = per_write_max_bytes;
598 TLOG(TLVL_TRACE) << GetTraceName() <<
": sendFragment writev sts!=: this_write_bytes=" << std::to_string(this_write_bytes)
599 <<
" out_iov_idx=" << std::to_string(out_iov_idx)
600 <<
" additional=" << std::to_string(additional)
605 TLOG(TLVL_TRACE) << GetTraceName() <<
": sendFragment writev sts(" << std::to_string(sts) <<
")==requested_send_bytes(" << std::to_string(this_write_bytes) <<
")";
606 total_written_bytes += sts;
608 iovv[out_iov_idx].iov_base = (uint8_t*)(iovv[out_iov_idx].iov_base) + iovv[out_iov_idx].iov_len;
609 iovv[out_iov_idx].iov_len = 0;
610 in_iov_idx += out_iov_idx;
611 this_write_bytes = 0;
613 unsigned long additional = ((
unsigned long)iov_in[in_iov_idx].iov_base + iov_in[in_iov_idx].iov_len)
614 - ((
unsigned long)iovv[out_iov_idx].iov_base + iovv[out_iov_idx].iov_len);
617 iovv[out_iov_idx].iov_len += additional;
618 this_write_bytes += additional;
619 if (this_write_bytes > per_write_max_bytes)
621 iovv[out_iov_idx].iov_len -= this_write_bytes - per_write_max_bytes;
622 this_write_bytes = per_write_max_bytes;
624 if (out_iov_idx != 0)
625 iovv[0] = iovv[out_iov_idx];
634 }
while (total_written_bytes < total_to_write_bytes);
635 if (total_written_bytes > total_to_write_bytes)
636 TLOG(TLVL_ERROR) << GetTraceName() <<
": sendFragment program error: too many bytes transferred";
641 fcntl(send_fd_, F_SETFL, 0);
643 sts = total_written_bytes -
sizeof(
MessHead);
645 TLOG(14) << GetTraceName() <<
": sendFragment sts=" << std::to_string(sts);
651 void artdaq::TCPSocketTransfer::stats_connect_()
654 while (!stats_connect_stop_)
658 std::function<void()>
function;
661 int msdly = tmo_.get_next_timeout_msdly();
666 std::unique_lock<std::mutex> lck(stopstatscvm_);
667 sts = stopstatscv_.wait_until(lck
668 , std::chrono::system_clock::now()
669 + std::chrono::milliseconds(msdly));
670 TLOG(15) << GetTraceName() <<
": thread1 after wait_until(msdly=" << msdly <<
") - sts=" <<
static_cast<int>(sts);
672 if (sts == std::cv_status::no_timeout)
675 auto sts = tmo_.get_next_expired_timeout(desc, &tag,
function, &ts_us);
677 while (sts != -1 && desc !=
"")
679 if (
function != NULL)
682 sts = tmo_.get_next_expired_timeout(desc, &tag,
function, &ts_us);
687 void artdaq::TCPSocketTransfer::connect_()
689 TLOG(TLVL_DEBUG) << GetTraceName() <<
": Connecting sender socket";
690 int sndbuf_bytes =
static_cast<int>(sndbuf_);
691 send_fd_ =
TCPConnect(hostMap_[destination_rank()].hostname.c_str()
697 TLOG(TLVL_DEBUG) << GetTraceName() <<
": connect_ " + hostMap_[destination_rank()].hostname +
":" << calculate_port_() <<
" send_fd_=" << send_fd_;
701 TLOG(TLVL_DEBUG) << GetTraceName() <<
": connect_: Writing connect message";
702 MessHead mh = { 0,MessHead::connect_v0,htons(source_rank()),{htonl(CONN_MAGIC)} };
703 ssize_t sts = write(send_fd_, &mh,
sizeof(mh));
706 TLOG(TLVL_ERROR) << GetTraceName() <<
": connect_: Error writing connect message!";
714 TLOG(TLVL_INFO) << GetTraceName() <<
": connect_: Successfully connected";
721 void artdaq::TCPSocketTransfer::reconnect_()
723 TLOG(TLVL_TRACE) << GetTraceName() <<
": check/reconnect";
727 void artdaq::TCPSocketTransfer::start_listen_thread_()
729 std::unique_lock<std::mutex> start_lock(listen_thread_mutex_);
730 if (listen_thread_refcount_ == 0)
732 if (listen_thread_ && listen_thread_->joinable()) listen_thread_->join();
733 listen_thread_refcount_ = 1;
734 TLOG(TLVL_INFO) << GetTraceName() <<
": Starting Listener Thread";
735 listen_thread_ = std::make_unique<boost::thread>(&TCPSocketTransfer::listen_,
this);
739 listen_thread_refcount_++;
743 void artdaq::TCPSocketTransfer::listen_()
746 while (listen_thread_refcount_ > 0)
748 TLOG(TLVL_TRACE) <<
"listen_: Listening/accepting new connections";
751 TLOG(TLVL_DEBUG) <<
"listen_: Opening listener";
756 TLOG(TLVL_DEBUG) <<
"listen_: Error creating listen_fd!";
761 timeval tv = { 2,0 };
764 FD_SET(listen_fd, &rfds);
766 res = select(listen_fd + 1, &rfds, (fd_set *)0, (fd_set *)0, &tv);
771 socklen_t arglen =
sizeof(un);
773 TLOG(TLVL_DEBUG) <<
"listen_: Calling accept";
774 fd = accept(listen_fd, (sockaddr *)&un, &arglen);
775 TLOG(TLVL_DEBUG) << GetTraceName() <<
": Done with accept";
777 TLOG(TLVL_DEBUG) <<
"listen_: Reading connect message";
778 socklen_t lenlen =
sizeof(tv);
780 setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &tv, lenlen);
782 uint64_t mark_us = TimeUtils::gettimeofday_us();
783 sts = read(fd, &mh,
sizeof(mh));
784 uint64_t delta_us = TimeUtils::gettimeofday_us() - mark_us;
785 TLOG(TLVL_DEBUG) <<
"listen_: Read of connect message took " << delta_us <<
" microseconds.";
786 if (sts !=
sizeof(mh))
788 TLOG(TLVL_DEBUG) <<
"listen_: Wrong message header length received!";
797 TLOG(TLVL_DEBUG) <<
"listen_: Wrong magic bytes in header!";
805 TLOG(TLVL_INFO) <<
"listen_: New fd is " << fd <<
" for source rank " << mh.
source_id;
809 TLOG(16) <<
"listen_: No connections in timeout interval!";
813 TLOG(TLVL_INFO) <<
"listen_: Shutting down connection listener";
814 if (listen_fd != -1) close(listen_fd);
815 for (
auto& rank : connected_fds_)
817 for (
auto& fd : rank.second)
822 connected_fds_.clear();
virtual int source_rank() const
Get the source rank for this TransferInterface instance.
int TCPConnect(char const *host_in, int dflt_port, long flags=0, int sndbufsiz=0)
Connect to a host on a given port.
uint32_t conn_magic
unsigned first is better for MessHead initializer: {0,0,my_node_idx_,CONN_MAGIC}
std::string GetTraceName() const
Constructs a name suitable for TRACE messages.
This TransferInterface is a Receiver.
int receiveFragmentData(RawDataType *destination, size_t wordCount) override
Receive the body of a Fragment to the given destination pointer.
int TCP_listen_fd(int port, int rcvbuf)
Create a TCP listening socket on the given port and INADDR_ANY, with the given receive buffer...
TCPSocketTransfer(fhicl::ParameterSet const &ps, Role role)
TCPSocketTransfer Constructor.
int receiveFragmentHeader(detail::RawFragmentHeader &header, size_t receiveTimeout) override
Receive a Fragment Header from the transport mechanism.
This TransferInterface is a Sender.
int32_t byte_count
use CONN_MAGIC for connect_v0, data that follow for data_v0 (and 0 lenght data)
Some error occurred, but no exception was thrown.
Role
Used to determine if a TransferInterface is a Sender or Receiver.
int64_t source_id
Rank of the source.
MessType message_type
Message Type.
The send operation completed successfully.
This interface defines the functions used to transfer data between artdaq applications.
TransferInterface implementation plugin that sends data using TCP sockets.
This header is sent by the TCPSocket_transfer to allow for more efficient writev calls.
void add_periodic(const char *desc, void *tag, std::function< void()> &function, uint64_t period_us, uint64_t start_us=0)
Add a periodic timeout to the Timeout container.
CopyStatus
Returned from the send functions, this enumeration describes the possible return codes. If an exception occurs, it will be thrown and should be handled normally.