hmbdc
simplify-high-performance-messaging-programming
RecvTransportEngine.hpp
1 #include "hmbdc/Copyright.hpp"
2 #pragma once
3 #include "hmbdc/tips/udpcast/Transport.hpp"
4 #include "hmbdc/tips/udpcast/DefaultUserConfig.hpp"
5 #include "hmbdc/tips/TypeTagSet.hpp"
6 #include "hmbdc/pattern/MonoLockFreeBuffer.hpp"
7 #include "hmbdc//MetaUtils.hpp"
8 
9 #include <boost/lexical_cast.hpp>
10 
11 #include <memory>
12 #include <type_traits>
13 #include <mutex>
14 
15 namespace hmbdc { namespace tips { namespace udpcast {
16 
17 /**
18  * @brief interface to power a multicast transport receiving functions
19  */
21  using Transport::Transport;
22  virtual ~RecvTransport(){}
23 };
24 
25 namespace recvtransportengine_detail {
27 
28 /**
29  * @class RecvTransportImpl<>
30  * @brief impl class
31  *
32  * @tparam OutputBuffer type of buffer to hold resulting network messages
33  */
34 template <typename OutputBuffer>
36 : RecvTransport {
38  , OutputBuffer& outputBuffer)
39  : RecvTransport((cfg.setAdditionalFallbackConfig(Config{DefaultUserConfig})
40  , cfg.resetSection("rx", false)))
41  , outputBuffer_(outputBuffer)
42  , maxItemSize_(outputBuffer.maxItemSize())
43  , buf_(new char[mtu_])
44  , bufCur_(buf_)
45  , bytesRecved_(0) {
46  uint32_t yes = 1;
47  if (setsockopt(fd, SOL_SOCKET,SO_REUSEADDR, &yes, sizeof(yes)) < 0) {
48  HMBDC_LOG_C("failed to set reuse address errno=", errno);
49  }
50  auto sz = config_.getExt<int>("udpRecvBufferBytes");
51  if (sz) {
52  if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &sz, sizeof(sz)) < 0) {
53  HMBDC_LOG_C("failed to set send buffer size=", sz);
54  }
55  }
56 
57  auto udpcastListenPort = config_.getExt<uint16_t>("udpcastListenPort");
58  struct sockaddr_in udpcastListenAddrPort;
59  memset(&udpcastListenAddrPort, 0, sizeof(udpcastListenAddrPort));
60  udpcastListenAddrPort.sin_family = AF_INET;
61  auto ipStr = cfg.getExt<std::string>("udpcastListenAddr") == std::string("ifaceAddr")
62  ? comm::inet::getLocalIpMatchMask(cfg.getExt<std::string>("ifaceAddr"))
63  :cfg.getExt<std::string>("udpcastListenAddr");
64  udpcastListenAddrPort.sin_addr.s_addr = inet_addr(ipStr.c_str());
65  udpcastListenAddrPort.sin_port = htons(udpcastListenPort);
66  if (::bind(fd, (struct sockaddr *)&udpcastListenAddrPort, sizeof(udpcastListenAddrPort)) < 0) {
67  HMBDC_THROW(std::runtime_error, "failed to bind unicast udpcast listen address "
68  << ipStr << ':' << cfg.getExt<short>("udpcastListenPort") << " errno=" << errno);
69  }
70 
71  if ((udpcastListenAddrPort.sin_addr.s_addr & 0x000000F0) == 0xE0) {//multicast address
72  /* use setsockopt() to request that the kernel join a multicast group */
73  struct ip_mreq mreq;
74  mreq.imr_multiaddr.s_addr = udpcastListenAddrPort.sin_addr.s_addr;
75  auto iface =
76  comm::inet::getLocalIpMatchMask(config_.getExt<std::string>("ifaceAddr"));
77  mreq.imr_interface.s_addr=inet_addr(iface.c_str());
78  if (setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0) {
79  HMBDC_THROW(std::runtime_error, "failed to join " << ipStr << ':'
80  << cfg.getExt<short>("udpcastPort"));
81  }
82  }
83  HMBDC_LOG_N("listen at ", cfg.getExt<std::string>("ifaceAddr"));
84 
85  start();
86  }
87 
88  template <MessageTupleC Messages, typename CcNode>
89  void subscribeFor(CcNode const& node, uint16_t mod, uint16_t res) {
90  subscriptions_.markSubsFor<Messages>(node, mod, res);
91  }
92 
93  template <MessageC Message>
94  void subscribe() {
95  subscriptions_.add(Message::typeTag);
96  }
97 
99  delete [] buf_;
100  }
101 
102 /**
103  * @brief start the show by schedule the mesage recv
104  */
105  void start() {
106  hmbdc::app::utils::EpollTask::instance().add(
107  hmbdc::app::utils::EpollTask::EPOLLIN
108  | hmbdc::app::utils::EpollTask::EPOLLET, *this);
109  }
110 
111  void runOnce(bool alwaysPoll = false) HMBDC_RESTRICT {
112  if (hmbdc_unlikely(alwaysPoll || !isFdReady())) {
113  hmbdc::app::utils::EpollTask::instance().poll();
114  }
115  resumeRead();
116  }
117 
118  sockaddr_in udpcastListenRemoteAddr = {0};
119 private:
120  void resumeRead() HMBDC_RESTRICT {
121  do {
122  while (bytesRecved_) {
123  auto h = reinterpret_cast<TransportMessageHeader*>(bufCur_);
124  auto wireSize = h->wireSize();
125 
126  if (hmbdc_likely(bytesRecved_ >= wireSize)) {
127  if (subscriptions_.check(h->typeTag())) {
128  if (hmbdc_unlikely(wireSize > bytesRecved_)) {
129  break;
130  }
131  auto l = std::min<size_t>(maxItemSize_, h->messagePayloadLen());
132  outputBuffer_.put(h->payload(), l);
133  }
134  bytesRecved_ -= wireSize;
135  bufCur_ += wireSize;
136  } else {
137  break;
138  }
139  }
140  bytesRecved_ = 0;
141  bufCur_ = buf_;
142  if (isFdReady()) {
143  socklen_t addrLen = sizeof(udpcastListenRemoteAddr);
144  auto l = recvfrom(fd, buf_, mtu_, MSG_NOSIGNAL|MSG_DONTWAIT
145  , (struct sockaddr *)&udpcastListenRemoteAddr, &addrLen);
146  if (hmbdc_unlikely(l < 0)) {
147  if (!checkErr()) {
148  HMBDC_LOG_C("recvmmsg failed errno=", errno);
149  }
150  return;
151  } else if (l == 0) {
152  //nothing to do now
153  return;
154  }
155  bytesRecved_ = l;
156  }
157  } while(bytesRecved_);
158  }
159 
160  OutputBuffer& outputBuffer_;
161  size_t maxItemSize_;
162  char* buf_;
163  char* bufCur_;
164  size_t bytesRecved_;
165  TypeTagSet subscriptions_;
166 };
167 
168 template <typename OutputBuffer>
170 : RecvTransportImpl<OutputBuffer>
171 , hmbdc::app::Client<RecvTransportEngineImpl<OutputBuffer>> {
175 
176  void rotate() {
178  }
179 
180 /**
181  * @brief power the io_service and other things
182  *
183  */
184  /*virtual*/
185  void invokedCb(size_t) HMBDC_RESTRICT override {
187  }
188 
189  using Transport::hmbdcName;
190 /**
191  * @brief should not happen ever unless an exception thrown
192  *
193  * @param e exception thown
194  */
195  /*virtual*/
196  void stoppedCb(std::exception const& e) override {
197  HMBDC_LOG_C(e.what());
198  };
199 
200 private:
201 };
202 
203 } //recvtransportengine_detail
204 
205 template <typename OutputBuffer>
206 using RecvTransportImpl = recvtransportengine_detail::RecvTransportImpl<OutputBuffer>;
207 
208 template <typename OutputBuffer>
209 using RecvTransportEngine = recvtransportengine_detail::RecvTransportEngineImpl<OutputBuffer>;
210 
211 }}}
T getExt(const path_type &param, bool throwIfMissing=true) const
get a value from the config
Definition: Config.hpp:238
Definition: MonoLockFreeBuffer.hpp:16
Definition: Transport.hpp:38
class to hold an hmbdc configuration
Definition: Config.hpp:44
void setAdditionalFallbackConfig(Config const &c)
set additional defaults
Definition: Config.hpp:153
void invokedCb(size_t) HMBDC_RESTRICT override
power the io_service and other things
Definition: RecvTransportEngine.hpp:185
Config & resetSection(char const *section, bool sectionExists=true)
change section name
Definition: Config.hpp:176
impl class
Definition: RecvTransportEngine.hpp:35
void start()
start the show by schedule the mesage recv
Definition: RecvTransportEngine.hpp:105
void stoppedCb(std::exception const &e) override
should not happen ever unless an exception thrown
Definition: RecvTransportEngine.hpp:196
interface to power a multicast transport receiving functions
Definition: RecvTransportEngine.hpp:20
A Client represents a thread of execution/a task. The execution is managed by a Context. a Client object could participate in message dispatching as the receiver of specifed message types.
Definition: Client.hpp:128
Definition: Base.hpp:12