protocol.hpp 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. //
  2. // protocol.hpp
  3. // ~~~~~~~~~~~~
  4. //
  5. // Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
  6. //
  7. // Distributed under the Boost Software License, Version 1.0. (See accompanying
  8. // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  9. //
  10. #ifndef PORTHOPPER_PROTOCOL_HPP
  11. #define PORTHOPPER_PROTOCOL_HPP
  12. #include <boost/array.hpp>
  13. #include <boost/asio.hpp>
  14. #include <cstring>
  15. #include <iomanip>
  16. #include <string>
  17. #include <strstream>
  18. // This request is sent by the client to the server over a TCP connection.
  19. // The client uses it to perform three functions:
  20. // - To request that data start being sent to a given port.
  21. // - To request that data is no longer sent to a given port.
  22. // - To change the target port to another.
  23. class control_request
  24. {
  25. public:
  26. // Construct an empty request. Used when receiving.
  27. control_request()
  28. {
  29. }
  30. // Create a request to start sending data to a given port.
  31. static const control_request start(unsigned short port)
  32. {
  33. return control_request(0, port);
  34. }
  35. // Create a request to stop sending data to a given port.
  36. static const control_request stop(unsigned short port)
  37. {
  38. return control_request(port, 0);
  39. }
  40. // Create a request to change the port that data is sent to.
  41. static const control_request change(
  42. unsigned short old_port, unsigned short new_port)
  43. {
  44. return control_request(old_port, new_port);
  45. }
  46. // Get the old port. Returns 0 for start requests.
  47. unsigned short old_port() const
  48. {
  49. std::istrstream is(data_, encoded_port_size);
  50. unsigned short port = 0;
  51. is >> std::setw(encoded_port_size) >> std::hex >> port;
  52. return port;
  53. }
  54. // Get the new port. Returns 0 for stop requests.
  55. unsigned short new_port() const
  56. {
  57. std::istrstream is(data_ + encoded_port_size, encoded_port_size);
  58. unsigned short port = 0;
  59. is >> std::setw(encoded_port_size) >> std::hex >> port;
  60. return port;
  61. }
  62. // Obtain buffers for reading from or writing to a socket.
  63. boost::array<boost::asio::mutable_buffer, 1> to_buffers()
  64. {
  65. boost::array<boost::asio::mutable_buffer, 1> buffers
  66. = { { boost::asio::buffer(data_) } };
  67. return buffers;
  68. }
  69. private:
  70. // Construct with specified old and new ports.
  71. control_request(unsigned short old_port_number,
  72. unsigned short new_port_number)
  73. {
  74. std::ostrstream os(data_, control_request_size);
  75. os << std::setw(encoded_port_size) << std::hex << old_port_number;
  76. os << std::setw(encoded_port_size) << std::hex << new_port_number;
  77. }
  78. // The length in bytes of a control_request and its components.
  79. enum
  80. {
  81. encoded_port_size = 4, // 16-bit port in hex.
  82. control_request_size = encoded_port_size * 2
  83. };
  84. // The encoded request data.
  85. char data_[control_request_size];
  86. };
  87. // This frame is sent from the server to subscribed clients over UDP.
  88. class frame
  89. {
  90. public:
  91. // The maximum allowable length of the payload.
  92. enum { payload_size = 32 };
  93. // Construct an empty frame. Used when receiving.
  94. frame()
  95. {
  96. }
  97. // Construct a frame with specified frame number and payload.
  98. frame(unsigned long frame_number, const std::string& payload_data)
  99. {
  100. std::ostrstream os(data_, frame_size);
  101. os << std::setw(encoded_number_size) << std::hex << frame_number;
  102. os << std::setw(payload_size)
  103. << std::setfill(' ') << payload_data.substr(0, payload_size);
  104. }
  105. // Get the frame number.
  106. unsigned long number() const
  107. {
  108. std::istrstream is(data_, encoded_number_size);
  109. unsigned long frame_number = 0;
  110. is >> std::setw(encoded_number_size) >> std::hex >> frame_number;
  111. return frame_number;
  112. }
  113. // Get the payload data.
  114. const std::string payload() const
  115. {
  116. return std::string(data_ + encoded_number_size, payload_size);
  117. }
  118. // Obtain buffers for reading from or writing to a socket.
  119. boost::array<boost::asio::mutable_buffer, 1> to_buffers()
  120. {
  121. boost::array<boost::asio::mutable_buffer, 1> buffers
  122. = { { boost::asio::buffer(data_) } };
  123. return buffers;
  124. }
  125. private:
  126. // The length in bytes of a frame and its components.
  127. enum
  128. {
  129. encoded_number_size = 8, // Frame number in hex.
  130. frame_size = encoded_number_size + payload_size
  131. };
  132. // The encoded frame data.
  133. char data_[frame_size];
  134. };
  135. #endif // PORTHOPPER_PROTOCOL_HPP