02-udp.cpp 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. #include "limbo/errc.h"
  2. #include "limbo/ip/state.hpp"
  3. #include "limbo/udp/state.hpp"
  4. #include "test-utils.h"
  5. using namespace limbo;
  6. using IpState = ip::State<void>;
  7. using IpContext = typename IpState::Context;
  8. using State = udp::State<IpState>;
  9. using Context = typename State::Context;
  10. using Packet = typename State::Packet;
  11. static_assert(!details::has_lower_state_v<IpState>, "check0");
  12. static_assert(details::has_lower_state_v<State>, "check1");
  13. static_assert(std::is_same_v<typename Context::LowerContext, IpContext>,
  14. "check2");
  15. uint8_t example_raw[]{0x14, 0xe9, 0x14, 0xe9, 0x00, 0x24, 0x00, 0x00, 0x00,
  16. 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
  17. 0x00, 0x00, 0x04, 0x77, 0x70, 0x61, 0x64, 0x05, 0x6c,
  18. 0x6f, 0x63, 0x61, 0x6c, 0x00, 0x00, 0x01, 0x00, 0x01};
  19. auto example_chunk = Chunk(example_raw, sizeof(example_raw));
  20. uint8_t payload[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
  21. 0x00, 0x00, 0x04, 0x77, 0x70, 0x61, 0x64, 0x05, 0x6c, 0x6f,
  22. 0x63, 0x61, 0x6c, 0x00, 0x00, 0x01, 0x00, 0x01};
  23. auto payload_chunk = Chunk(payload, sizeof(payload));
  24. auto src = make_address("10.0.31.124");
  25. auto dst = make_address("224.0.0.251");
  26. TEST_CASE("send", "[udp]") {
  27. char buff[8 + sizeof(payload)];
  28. auto ip_ctx = IpContext{src, dst, 1, ip::Proto::udp, 0, 0, nullptr};
  29. auto ctx = Context{5353, 5353, &ip_ctx};
  30. auto state = State{};
  31. SECTION("no enough space") {
  32. auto zero_chunk = Chunk(buff, 0);
  33. auto result = Packet::send(state, ctx, zero_chunk, payload_chunk);
  34. REQUIRE(!result);
  35. CHECK(result.state() == &state);
  36. CHECK(result.error_code() == (uint32_t)Errc::no_enough_space);
  37. }
  38. auto buff_chunk = Chunk(buff, example_chunk.size());
  39. auto result = Packet::send(state, ctx, buff_chunk, payload_chunk);
  40. REQUIRE(result);
  41. auto res_buff = result.consumed();
  42. CHECK((void *)res_buff.data() == (void *)buff);
  43. CHECK(res_buff.size() == example_chunk.size());
  44. CHECK(res_buff == example_chunk);
  45. }
  46. TEST_CASE("send without content", "[udp]") {
  47. char buff[8 + sizeof(payload)];
  48. auto ip_ctx = IpContext{src, dst, 1, ip::Proto::udp, 0, 0, nullptr};
  49. auto ctx = Context{5353, 5353, &ip_ctx};
  50. auto state = State{};
  51. SECTION("no enough space") {
  52. auto zero_chunk = Chunk(buff, 0);
  53. auto result = Packet::send<false>(state, ctx, zero_chunk, payload_chunk);
  54. REQUIRE(!result);
  55. CHECK(result.state() == &state);
  56. CHECK(result.error_code() == (uint32_t)Errc::no_enough_space);
  57. }
  58. auto buff_chunk = Chunk(buff, example_chunk.size());
  59. auto result = Packet::send<false>(state, ctx, buff_chunk, payload_chunk);
  60. REQUIRE(result);
  61. auto res_buff = result.consumed();
  62. CHECK((void *)res_buff.data() == (void *)buff);
  63. CHECK(res_buff.size() == 8);
  64. CHECK(res_buff == Chunk(example_raw, 8));
  65. }
  66. TEST_CASE("recv", "[udp]") {
  67. auto ip_state = IpState();
  68. auto state = State{};
  69. auto result = state.recv(example_chunk, &ip_state);
  70. REQUIRE(result);
  71. CHECK(result.state() == &state);
  72. CHECK(result.consumed() == example_chunk);
  73. auto &packet = state.get_parsed();
  74. CHECK(packet.source_port == 5353);
  75. CHECK(packet.dest_port == 5353);
  76. CHECK(packet.length == example_chunk.size());
  77. CHECK(packet.checksum == 0);
  78. CHECK(packet.container == &ip_state.get_parsed());
  79. CHECK(packet.payload == payload_chunk);
  80. }
  81. TEST_CASE("recv/incomplete", "[udp]") {
  82. auto ip_state = IpState();
  83. auto state = State{};
  84. auto empty_chunk = Chunk(example_raw, 0);
  85. SECTION("less then header sz") {
  86. auto result = state.recv(Chunk(example_raw, 6), &ip_state);
  87. CHECK(result);
  88. CHECK(result.consumed() == empty_chunk);
  89. CHECK(result.demand() == 2);
  90. }
  91. SECTION("incomplete payload") {
  92. auto chunk = Chunk(example_raw, example_chunk.size() - 1);
  93. auto result = state.recv(chunk, &ip_state);
  94. CHECK(result);
  95. CHECK(result.consumed() == empty_chunk);
  96. CHECK(result.demand() == 1);
  97. }
  98. }
  99. TEST_CASE("checksums", "[udp]") {
  100. using State = udp::State<IpState, udp::Opts::validate_checksum>;
  101. uint8_t example_raw[]{0x00, 0x14, 0x00, 0x0a, 0x00,
  102. 0x0A, 0x35, 0xC5, 0x48, 0x69};
  103. auto example_chunk = Chunk(example_raw, sizeof(example_raw));
  104. auto ip_state = IpState();
  105. auto &ip = ip_state.get_parsed();
  106. ip.source = ip::IPv4Address::from_native(0xC0A8001F);
  107. ip.destination = ip::IPv4Address::from_native(0xC0A8001E);
  108. auto state = State();
  109. auto result = state.recv(example_chunk, &ip_state);
  110. REQUIRE(result);
  111. CHECK(result.state() == &state);
  112. CHECK(result.consumed() == example_chunk);
  113. }
  114. TEST_CASE("send/recv + checksum", "[udp]") {
  115. constexpr auto opts =
  116. udp::Opts::calculate_checksum | udp::Opts::validate_checksum;
  117. using IpState = ip::State<void>;
  118. using IpContext = typename IpState::Context;
  119. using State = udp::State<IpState, opts>;
  120. using Context = typename State::Context;
  121. using Packet = typename State::Packet;
  122. auto ip_state = IpState();
  123. char buff[8 + sizeof(payload)];
  124. auto ip_ctx = IpContext{src, dst, 1, ip::Proto::udp, 0, 0, nullptr};
  125. auto ctx = Context{5353, 5353, &ip_ctx};
  126. auto state = State{};
  127. auto buff_chunk = Chunk(buff, example_chunk.size());
  128. auto result = Packet::send(state, ctx, buff_chunk, payload_chunk);
  129. REQUIRE(result);
  130. auto res_buff = result.consumed();
  131. CHECK((void *)res_buff.data() == (void *)buff);
  132. CHECK(res_buff.size() == example_chunk.size());
  133. SECTION("send without content") {
  134. char tmp_buff[8];
  135. auto tmp_chunk = Chunk(tmp_buff, sizeof(tmp_buff));
  136. auto tmp_r = Packet::send<false>(state, ctx, tmp_chunk, payload_chunk);
  137. REQUIRE(tmp_r);
  138. CHECK(tmp_r.consumed() == tmp_chunk);
  139. CHECK(tmp_chunk == Chunk(res_buff.data(), tmp_chunk.size()));
  140. }
  141. /* needed for correct pseudo header calculation */
  142. ip_state.init(0x6155);
  143. auto &ip_packet = ip_state.get_parsed();
  144. ip_packet.source = src;
  145. ip_packet.destination = dst;
  146. result = state.recv(buff_chunk, &ip_state);
  147. REQUIRE(result);
  148. CHECK(result.state() == &state);
  149. }