PageRenderTime 26ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 0ms

/dds/DCPS/transport/rtps_udp/RtpsUdpReceiveStrategy.cpp

https://bitbucket.org/snaewe/dds
C++ | 489 lines | 389 code | 67 blank | 33 comment | 50 complexity | 87c86b24339acc0a0f8261acb4cd9f57 MD5 | raw file
Possible License(s): LGPL-3.0
  1. /*
  2. * $Id$
  3. *
  4. *
  5. * Distributed under the OpenDDS License.
  6. * See: http://www.opendds.org/license.html
  7. */
  8. #include "RtpsUdpReceiveStrategy.h"
  9. #include "RtpsUdpDataLink.h"
  10. #include "RtpsUdpInst.h"
  11. #include "RtpsUdpTransport.h"
  12. #include "dds/DCPS/RTPS/BaseMessageTypes.h"
  13. #include "dds/DCPS/RTPS/BaseMessageUtils.h"
  14. #include "dds/DCPS/RTPS/MessageTypes.h"
  15. #include "ace/Reactor.h"
  16. namespace OpenDDS {
  17. namespace DCPS {
  18. RtpsUdpReceiveStrategy::RtpsUdpReceiveStrategy(RtpsUdpDataLink* link)
  19. : link_(link)
  20. , last_received_()
  21. , recvd_sample_(0)
  22. , receiver_(link->local_prefix())
  23. {
  24. }
  25. int
  26. RtpsUdpReceiveStrategy::handle_input(ACE_HANDLE fd)
  27. {
  28. return handle_dds_input(fd);
  29. }
  30. ssize_t
  31. RtpsUdpReceiveStrategy::receive_bytes(iovec iov[],
  32. int n,
  33. ACE_INET_Addr& remote_address,
  34. ACE_HANDLE fd)
  35. {
  36. const ACE_SOCK_Dgram& socket =
  37. (fd == link_->unicast_socket().get_handle())
  38. ? link_->unicast_socket() : link_->multicast_socket();
  39. const ssize_t ret = socket.recv(iov, n, remote_address);
  40. remote_address_ = remote_address;
  41. return ret;
  42. }
  43. void
  44. RtpsUdpReceiveStrategy::deliver_sample(ReceivedDataSample& sample,
  45. const ACE_INET_Addr& /*remote_address*/)
  46. {
  47. using namespace RTPS;
  48. if (std::memcmp(receiver_.dest_guid_prefix_, link_->local_prefix(),
  49. sizeof(GuidPrefix_t))) {
  50. // Not our message, we may be on multicast listening to all the others.
  51. return;
  52. }
  53. const RtpsSampleHeader& rsh = received_sample_header();
  54. const SubmessageKind kind = rsh.submessage_._d();
  55. switch (kind) {
  56. case INFO_SRC:
  57. case INFO_REPLY_IP4:
  58. case INFO_DST:
  59. case INFO_REPLY:
  60. case INFO_TS:
  61. // No-op: the INFO_* submessages only modify the state of the
  62. // MessageReceiver (see check_header()), they are not passed up to DCPS.
  63. break;
  64. case DATA: {
  65. receiver_.fill_header(sample.header_);
  66. const DataSubmessage& data = rsh.submessage_.data_sm();
  67. recvd_sample_ = &sample;
  68. readers_withheld_.clear();
  69. // If this sample should be withheld from some readers in order to maintain
  70. // in-order delivery, link_->received() will add it to readers_withheld_.
  71. link_->received(data, receiver_.source_guid_prefix_);
  72. recvd_sample_ = 0;
  73. if (data.readerId != ENTITYID_UNKNOWN) {
  74. RepoId reader;
  75. std::memcpy(reader.guidPrefix, link_->local_prefix(),
  76. sizeof(GuidPrefix_t));
  77. reader.entityId = data.readerId;
  78. if (!readers_withheld_.count(reader)) {
  79. link_->data_received(sample, reader);
  80. }
  81. } else {
  82. link_->data_received_excluding(sample, readers_withheld_);
  83. }
  84. break;
  85. }
  86. case GAP:
  87. link_->received(rsh.submessage_.gap_sm(), receiver_.source_guid_prefix_);
  88. break;
  89. case HEARTBEAT:
  90. link_->received(rsh.submessage_.heartbeat_sm(),
  91. receiver_.source_guid_prefix_);
  92. break;
  93. case ACKNACK:
  94. link_->received(rsh.submessage_.acknack_sm(),
  95. receiver_.source_guid_prefix_);
  96. break;
  97. case HEARTBEAT_FRAG:
  98. link_->received(rsh.submessage_.hb_frag_sm(),
  99. receiver_.source_guid_prefix_);
  100. break;
  101. case NACK_FRAG:
  102. link_->received(rsh.submessage_.nack_frag_sm(),
  103. receiver_.source_guid_prefix_);
  104. break;
  105. /* no case DATA_FRAG: by the time deliver_sample() is called, reassemble()
  106. has successfully reassembled the fragments and we now have a DATA submsg
  107. */
  108. default:
  109. break;
  110. }
  111. }
  112. int
  113. RtpsUdpReceiveStrategy::start_i()
  114. {
  115. ACE_Reactor* reactor = link_->get_reactor();
  116. if (reactor == 0) {
  117. ACE_ERROR_RETURN((LM_ERROR,
  118. ACE_TEXT("(%P|%t) ERROR: ")
  119. ACE_TEXT("RtpsUdpReceiveStrategy::start_i: ")
  120. ACE_TEXT("NULL reactor reference!\n")),
  121. -1);
  122. }
  123. if (reactor->register_handler(link_->unicast_socket().get_handle(), this,
  124. ACE_Event_Handler::READ_MASK) != 0) {
  125. ACE_ERROR_RETURN((LM_ERROR,
  126. ACE_TEXT("(%P|%t) ERROR: ")
  127. ACE_TEXT("RtpsUdpReceiveStrategy::start_i: ")
  128. ACE_TEXT("failed to register handler for unicast ")
  129. ACE_TEXT("socket %d\n"),
  130. link_->unicast_socket().get_handle()),
  131. -1);
  132. }
  133. if (link_->config()->use_multicast_) {
  134. if (reactor->register_handler(link_->multicast_socket().get_handle(), this,
  135. ACE_Event_Handler::READ_MASK) != 0) {
  136. ACE_ERROR_RETURN((LM_ERROR,
  137. ACE_TEXT("(%P|%t) ERROR: ")
  138. ACE_TEXT("RtpsUdpReceiveStrategy::start_i: ")
  139. ACE_TEXT("failed to register handler for multicast\n")),
  140. -1);
  141. }
  142. }
  143. return 0;
  144. }
  145. void
  146. RtpsUdpReceiveStrategy::stop_i()
  147. {
  148. ACE_Reactor* reactor = link_->get_reactor();
  149. if (reactor == 0) {
  150. ACE_ERROR((LM_ERROR,
  151. ACE_TEXT("(%P|%t) ERROR: ")
  152. ACE_TEXT("RtpsUdpReceiveStrategy::stop_i: ")
  153. ACE_TEXT("NULL reactor reference!\n")));
  154. return;
  155. }
  156. reactor->remove_handler(link_->unicast_socket().get_handle(),
  157. ACE_Event_Handler::READ_MASK);
  158. if (link_->config()->use_multicast_) {
  159. reactor->remove_handler(link_->multicast_socket().get_handle(),
  160. ACE_Event_Handler::READ_MASK);
  161. }
  162. }
  163. bool
  164. RtpsUdpReceiveStrategy::check_header(const RtpsTransportHeader& header)
  165. {
  166. receiver_.reset(remote_address_, header.header_);
  167. return header.valid();
  168. }
  169. bool
  170. RtpsUdpReceiveStrategy::check_header(const RtpsSampleHeader& header)
  171. {
  172. receiver_.submsg(header.submessage_);
  173. // save fragmentation details for use in reassemble()
  174. if (header.valid() && header.submessage_._d() == RTPS::DATA_FRAG) {
  175. const RTPS::DataFragSubmessage& rtps = header.submessage_.data_frag_sm();
  176. frags_.first = rtps.fragmentStartingNum.value;
  177. frags_.second = frags_.first + (rtps.fragmentsInSubmessage - 1);
  178. }
  179. return header.valid();
  180. }
  181. const ReceivedDataSample*
  182. RtpsUdpReceiveStrategy::withhold_data_from(const RepoId& sub_id)
  183. {
  184. readers_withheld_.insert(sub_id);
  185. return recvd_sample_;
  186. }
  187. bool
  188. RtpsUdpReceiveStrategy::reassemble(ReceivedDataSample& data)
  189. {
  190. using namespace RTPS;
  191. receiver_.fill_header(data.header_); // set publication_id_.guidPrefix
  192. if (reassembly_.reassemble(frags_, data)) {
  193. // Reassembly was successful, replace DataFrag with Data. This doesn't have
  194. // to be a fully-formed DataSubmessage, just enough for this class to use
  195. // in deliver_sample() which ends up calling RtpsUdpDataLink::received().
  196. // In particular we will need the SequenceNumber, but ignore the iQoS.
  197. // Peek at the byte order from the encapsulation containing the payload.
  198. data.header_.byte_order_ = data.sample_->rd_ptr()[1] & 1 /*FLAG_E*/;
  199. RtpsSampleHeader& rsh = received_sample_header();
  200. const DataFragSubmessage& dfsm = rsh.submessage_.data_frag_sm();
  201. const CORBA::Octet data_flags = (data.header_.byte_order_ ? 1 : 0) // FLAG_E
  202. | (data.header_.key_fields_only_ ? 8 : 4); // FLAG_K : FLAG_D
  203. const DataSubmessage dsm = {
  204. {DATA, data_flags, 0}, 0, DATA_OCTETS_TO_IQOS,
  205. dfsm.readerId, dfsm.writerId, dfsm.writerSN, ParameterList()};
  206. rsh.submessage_.data_sm(dsm);
  207. return true;
  208. }
  209. return false;
  210. }
  211. bool
  212. RtpsUdpReceiveStrategy::remove_frags_from_bitmap(CORBA::Long bitmap[],
  213. CORBA::ULong num_bits,
  214. const SequenceNumber& base,
  215. const RepoId& pub_id)
  216. {
  217. bool modified = false;
  218. for (CORBA::ULong i = 0, x = 0, bit = 0; i < num_bits; ++i, ++bit) {
  219. if (bit == 32) bit = 0;
  220. if (bit == 0) {
  221. x = static_cast<CORBA::ULong>(bitmap[i / 32]);
  222. if (x == 0) {
  223. // skip an entire Long if it's all 0's (adds 32 due to ++i)
  224. i += 31;
  225. bit = 31;
  226. //FUTURE: this could be generalized with something like the x86 "bsr"
  227. // instruction using compiler intrinsics, VC++ _BitScanReverse()
  228. // and GCC __builtin_clz()
  229. continue;
  230. }
  231. }
  232. const CORBA::ULong mask = 1 << (31 - bit);
  233. if ((x & mask) && reassembly_.has_frags(base + i, pub_id)) {
  234. x &= ~mask;
  235. bitmap[i / 32] = x;
  236. modified = true;
  237. }
  238. }
  239. return modified;
  240. }
  241. void
  242. RtpsUdpReceiveStrategy::remove_fragments(const SequenceRange& range,
  243. const RepoId& pub_id)
  244. {
  245. for (SequenceNumber sn = range.first; sn <= range.second; ++sn) {
  246. reassembly_.data_unavailable(sn, pub_id);
  247. }
  248. }
  249. bool
  250. RtpsUdpReceiveStrategy::has_fragments(const SequenceRange& range,
  251. const RepoId& pub_id,
  252. FragmentInfo* frag_info)
  253. {
  254. for (SequenceNumber sn = range.first; sn <= range.second; ++sn) {
  255. if (reassembly_.has_frags(sn, pub_id)) {
  256. if (frag_info) {
  257. std::pair<SequenceNumber, RTPS::FragmentNumberSet> p;
  258. p.first = sn;
  259. frag_info->push_back(p);
  260. RTPS::FragmentNumberSet& missing_frags = frag_info->back().second;
  261. missing_frags.bitmap.length(8); // start at max length
  262. missing_frags.bitmapBase.value =
  263. reassembly_.get_gaps(sn, pub_id, missing_frags.bitmap.get_buffer(),
  264. 8, missing_frags.numBits);
  265. // reduce length in case get_gaps() didn't need all that room
  266. missing_frags.bitmap.length((missing_frags.numBits + 31) / 32);
  267. } else {
  268. return true;
  269. }
  270. }
  271. }
  272. return frag_info ? !frag_info->empty() : false;
  273. }
  274. // MessageReceiver nested class
  275. RtpsUdpReceiveStrategy::MessageReceiver::MessageReceiver(const GuidPrefix_t& local)
  276. : have_timestamp_(false)
  277. {
  278. RTPS::assign(local_, local);
  279. source_version_.major = source_version_.minor = 0;
  280. source_vendor_.vendorId[0] = source_vendor_.vendorId[1] = 0;
  281. for (size_t i = 0; i < sizeof(GuidPrefix_t); ++i) {
  282. source_guid_prefix_[i] = 0;
  283. dest_guid_prefix_[i] = 0;
  284. }
  285. timestamp_.seconds = 0;
  286. timestamp_.fraction = 0;
  287. }
  288. void
  289. RtpsUdpReceiveStrategy::MessageReceiver::reset(const ACE_INET_Addr& addr,
  290. const RTPS::Header& hdr)
  291. {
  292. using namespace RTPS;
  293. // see RTPS spec v2.1 section 8.3.4 table 8.16 and section 8.3.6.4
  294. source_version_ = hdr.version;
  295. source_vendor_ = hdr.vendorId;
  296. assign(source_guid_prefix_, hdr.guidPrefix);
  297. assign(dest_guid_prefix_, local_);
  298. unicast_reply_locator_list_.length(1);
  299. unicast_reply_locator_list_[0].kind =
  300. addr.get_type() == AF_INET6 ? LOCATOR_KIND_UDPv6 : LOCATOR_KIND_UDPv4;
  301. unicast_reply_locator_list_[0].port = LOCATOR_PORT_INVALID;
  302. RTPS::address_to_bytes(unicast_reply_locator_list_[0].address, addr);
  303. multicast_reply_locator_list_.length(1);
  304. multicast_reply_locator_list_[0].kind =
  305. addr.get_type() == AF_INET6 ? LOCATOR_KIND_UDPv6 : LOCATOR_KIND_UDPv4;
  306. multicast_reply_locator_list_[0].port = LOCATOR_PORT_INVALID;
  307. assign(multicast_reply_locator_list_[0].address, LOCATOR_ADDRESS_INVALID);
  308. have_timestamp_ = false;
  309. timestamp_ = TIME_INVALID;
  310. }
  311. void
  312. RtpsUdpReceiveStrategy::MessageReceiver::submsg(const RTPS::Submessage& s)
  313. {
  314. using namespace RTPS;
  315. switch (s._d()) {
  316. case INFO_TS:
  317. submsg(s.info_ts_sm());
  318. break;
  319. case INFO_SRC:
  320. submsg(s.info_src_sm());
  321. break;
  322. case INFO_REPLY_IP4:
  323. submsg(s.info_reply_ipv4_sm());
  324. break;
  325. case INFO_DST:
  326. submsg(s.info_dst_sm());
  327. break;
  328. case INFO_REPLY:
  329. submsg(s.info_reply_sm());
  330. break;
  331. default:
  332. break;
  333. }
  334. }
  335. void
  336. RtpsUdpReceiveStrategy::MessageReceiver::submsg(
  337. const RTPS::InfoDestinationSubmessage& id)
  338. {
  339. // see RTPS spec v2.1 section 8.3.7.7.4
  340. for (size_t i = 0; i < sizeof(GuidPrefix_t); ++i) {
  341. if (id.guidPrefix[i]) { // if some byte is > 0, it's not UNKNOWN
  342. RTPS::assign(dest_guid_prefix_, id.guidPrefix);
  343. return;
  344. }
  345. }
  346. RTPS::assign(dest_guid_prefix_, local_);
  347. }
  348. void
  349. RtpsUdpReceiveStrategy::MessageReceiver::submsg(const RTPS::InfoReplySubmessage& ir)
  350. {
  351. // see RTPS spec v2.1 section 8.3.7.8.4
  352. unicast_reply_locator_list_.length(ir.unicastLocatorList.length());
  353. for (CORBA::ULong i = 0; i < ir.unicastLocatorList.length(); ++i) {
  354. unicast_reply_locator_list_[i] = ir.unicastLocatorList[i];
  355. }
  356. if (ir.smHeader.flags & 2 /* MulticastFlag */) {
  357. multicast_reply_locator_list_.length(ir.multicastLocatorList.length());
  358. for (CORBA::ULong i = 0; i < ir.multicastLocatorList.length(); ++i) {
  359. multicast_reply_locator_list_[i] = ir.multicastLocatorList[i];
  360. }
  361. } else {
  362. multicast_reply_locator_list_.length(0);
  363. }
  364. }
  365. void
  366. RtpsUdpReceiveStrategy::MessageReceiver::submsg(
  367. const RTPS::InfoReplyIp4Submessage& iri4)
  368. {
  369. // see RTPS spec v2.1 sections 8.3.7.8.4 and 9.4.5.14
  370. unicast_reply_locator_list_.length(1);
  371. unicast_reply_locator_list_[0].kind = RTPS::LOCATOR_KIND_UDPv4;
  372. unicast_reply_locator_list_[0].port = iri4.unicastLocator.port;
  373. RTPS::assign(unicast_reply_locator_list_[0].address, iri4.unicastLocator.address);
  374. if (iri4.smHeader.flags & 2 /* MulticastFlag */) {
  375. multicast_reply_locator_list_.length(1);
  376. multicast_reply_locator_list_[0].kind = RTPS::LOCATOR_KIND_UDPv4;
  377. multicast_reply_locator_list_[0].port = iri4.multicastLocator.port;
  378. RTPS::assign(multicast_reply_locator_list_[0].address, iri4.multicastLocator.address);
  379. } else {
  380. multicast_reply_locator_list_.length(0);
  381. }
  382. }
  383. void
  384. RtpsUdpReceiveStrategy::MessageReceiver::submsg(
  385. const RTPS::InfoTimestampSubmessage& it)
  386. {
  387. // see RTPS spec v2.1 section 8.3.7.9.10
  388. if (!(it.smHeader.flags & 2 /* InvalidateFlag */)) {
  389. have_timestamp_ = true;
  390. timestamp_ = it.timestamp;
  391. } else {
  392. have_timestamp_ = false;
  393. }
  394. }
  395. void
  396. RtpsUdpReceiveStrategy::MessageReceiver::submsg(
  397. const RTPS::InfoSourceSubmessage& is)
  398. {
  399. // see RTPS spec v2.1 section 8.3.7.9.4
  400. RTPS::assign(source_guid_prefix_, is.guidPrefix);
  401. source_version_ = is.version;
  402. source_vendor_ = is.vendorId;
  403. unicast_reply_locator_list_.length(1);
  404. unicast_reply_locator_list_[0] = RTPS::LOCATOR_INVALID;
  405. multicast_reply_locator_list_.length(1);
  406. multicast_reply_locator_list_[0] = RTPS::LOCATOR_INVALID;
  407. have_timestamp_ = false;
  408. }
  409. void
  410. RtpsUdpReceiveStrategy::MessageReceiver::fill_header(
  411. DataSampleHeader& header) const
  412. {
  413. using namespace RTPS;
  414. if (have_timestamp_) {
  415. header.source_timestamp_sec_ = timestamp_.seconds;
  416. header.source_timestamp_nanosec_ =
  417. static_cast<ACE_UINT32>(timestamp_.fraction / NANOS_TO_RTPS_FRACS + .5);
  418. }
  419. assign(header.publication_id_.guidPrefix, source_guid_prefix_);
  420. }
  421. } // namespace DCPS
  422. } // namespace OpenDDS