hmbdc
simplify-high-performance-messaging-programming
McRecvTransport.hpp
1 #include "hmbdc/Copyright.hpp"
2 #pragma once
3 #include "hmbdc/tips/rmcast/Transport.hpp"
4 #include "hmbdc/tips/udpcast/Transport.hpp"
5 #include "hmbdc/app/Logger.hpp"
6 #include "hmbdc/comm/inet/Endpoint.hpp"
7 #include "hmbdc//MetaUtils.hpp"
8 
9 #include <boost/bind.hpp>
10 #include <boost/lexical_cast.hpp>
11 
12 #include <memory>
13 #include <type_traits>
14 
15 namespace hmbdc { namespace tips { namespace rmcast {
16 
17 namespace mcrecvtransport_detail {
18 
19 /**
20  * @brief impl class
21  *
22  * @tparam OutputBuffer type of buffer to hold resulting network messages
23  * between different recv transport. By default, keeping all
24  */
25 template <typename OutputBuffer, typename Ep2SessionDict>
27 : Transport {
28  using SELF = McRecvTransport;
29  friend struct NetContext; //only be created by NetContext
30 
33  , TypeTagSet const& subscriptions
34  , Ep2SessionDict& sessionDict)
35  : Transport(cfg)
36  , cmdBuffer_(cmdBuffer)
37  , sendFrom_{0}
38  , mcFd_(cfg)
39  , buf_(new char[mtu_])
40  , bufCur_(nullptr)
41  , bytesRecved_(0)
42  , subscriptions_(subscriptions)
43  , sessionDict_(sessionDict) {
44  uint32_t yes = 1;
45  if (setsockopt(mcFd_.fd, SOL_SOCKET,SO_REUSEADDR, &yes, sizeof(yes)) < 0) {
46  HMBDC_LOG_C("failed to set reuse address errno=", errno);
47  }
48  auto sz = config_.getExt<int>("udpRecvBufferBytes");
49  if (sz) {
50  if (setsockopt(mcFd_.fd, SOL_SOCKET, SO_RCVBUF, &sz, sizeof(sz)) < 0) {
51  HMBDC_LOG_C("failed to set send buffer size=", sz);
52  }
53  }
54 
55  /* bind to receive address */
56  auto mcAddr = comm::inet::Endpoint(config_.getExt<std::string>("mcastAddr")
57  , config_.getExt<uint16_t>("mcastPort")).v;
58  if (::bind(mcFd_.fd, (struct sockaddr *)&mcAddr, sizeof(mcAddr)) < 0) {
59  HMBDC_THROW(std::runtime_error, "failed to bind "
60  << config_.getExt<std::string>("mcastAddr") << ':'
61  << cfg.getExt<short>("mcastPort"));
62  }
63  /* use setsockopt() to request that the kernel join a multicast group */
64  struct ip_mreq mreq;
65  mreq.imr_multiaddr.s_addr=inet_addr(config_.getExt<std::string>("mcastAddr").c_str());
66  auto iface =
67  comm::inet::getLocalIpMatchMask(config_.getExt<std::string>("ifaceAddr"));
68  mreq.imr_interface.s_addr=inet_addr(iface.c_str());
69  if (setsockopt(mcFd_.fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0) {
70  HMBDC_THROW(std::runtime_error, "failed to join " << config_.getExt<std::string>("mcastAddr") << ':'
71  << cfg.getExt<short>("mcastPort"));
72  }
73  }
74 
75  ~McRecvTransport() {
76  }
77 
78 /**
79  * @brief start the show by schedule the mesage recv
80  */
81  void start() {
82  hmbdc::app::utils::EpollTask::instance().add(
83  hmbdc::app::utils::EpollTask::EPOLLIN
84  | hmbdc::app::utils::EpollTask::EPOLLET, mcFd_);
85  }
86 
87 /**
88  * @brief power the io_service and other things
89  *
90  */
91  void runOnce() HMBDC_RESTRICT {
92  resumeRead();
93  }
94 
95 private:
96  void resumeRead() {
97  do {
98  if (hmbdc_unlikely(sendFrom_.sin_family != AF_INET)) {
99  bytesRecved_ = 0;
100  }
101  if (hmbdc_likely(bytesRecved_)) {
102  if (!bufCur_) {
103  bufCur_ = buf_;
104  }
105  while (bytesRecved_ >= sizeof(TransportMessageHeader)) {
106  auto h = reinterpret_cast<TransportMessageHeader*>(bufCur_);
107  auto wireSize = h->wireSize();
108  if (hmbdc_likely(bytesRecved_ >= wireSize)) {
109  if (hmbdc_unlikely(h->typeTag() == TypeTagBackupSource::typeTag)) {
110  auto it = cmdBuffer_.claim();
111  auto b = static_cast<app::MessageHead*>(*it);
112  size_t l = h->messagePayloadLen;
113  l = std::min(cmdBuffer_.maxItemSize(), l);
114  memcpy(b, h->payload(), l);
115  auto& bts = b->template get<TypeTagBackupSource>();
116  bts.sendFrom = sendFrom_;
117  cmdBuffer_.commit(it);
118  } else {
119  auto session = sessionDict_.find(sendFrom_);
120  if (hmbdc_unlikely(session != sessionDict_.end())) {
121  auto a = session->second->accept(h);
122  if (a == 0) {
123  return; //wait for backup
124  }
125  }
126  }
127  bytesRecved_ -= wireSize;
128  bufCur_ += wireSize;
129  } else {
130  break;
131  }
132  }
133  }
134  bufCur_ = nullptr;
135  bytesRecved_ = 0;
136  auto addrLen = sizeof(sendFrom_);
137  if (mcFd_.isFdReady()) {
138  auto l = recvfrom(mcFd_.fd, buf_, mtu_, MSG_NOSIGNAL|MSG_DONTWAIT
139  , (sockaddr*)&sendFrom_, (socklen_t*)&addrLen);
140  if (hmbdc_unlikely(l < 0)) {
141  if (!mcFd_.checkErr()) {
142  HMBDC_LOG_C("recvmsg failed errno=", errno);
143  }
144  return;
145  } else if (l == 0) {
146  //nothing to do now
147  return;
148  }
149  bytesRecved_ = l;
150  }
151  } while(bytesRecved_);
152  }
153 
154  hmbdc::pattern::MonoLockFreeBuffer& HMBDC_RESTRICT cmdBuffer_;
155  sockaddr_in sendFrom_;
156  udpcast::EpollFd mcFd_;
157  char* buf_;
158  char* bufCur_;
159  size_t bytesRecved_;
160  TypeTagSet const& HMBDC_RESTRICT subscriptions_;
161  Ep2SessionDict& HMBDC_RESTRICT sessionDict_;
162 };
163 } //mcrecvtransport_detail
164 template <typename OutputBuffer, typename Ep2SessionDict>
165 using McRecvTransport = mcrecvtransport_detail::McRecvTransport<OutputBuffer, Ep2SessionDict>;
166 
167 }}}
T getExt(const path_type &param, bool throwIfMissing=true) const
get a value from the config
Definition: Config.hpp:238
Definition: MonoLockFreeBuffer.hpp:16
class to hold an hmbdc configuration
Definition: Config.hpp:44
impl class
Definition: McRecvTransport.hpp:26
Definition: Endpoint.hpp:17
void runOnce() HMBDC_RESTRICT
power the io_service and other things
Definition: McRecvTransport.hpp:91
Definition: Message.hpp:212
void start()
start the show by schedule the mesage recv
Definition: McRecvTransport.hpp:81
Definition: TypeTagSet.hpp:138
Definition: Base.hpp:12