socket_request.h 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. // Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
  2. //
  3. // Permission to use, copy, modify, and/or distribute this software for any
  4. // purpose with or without fee is hereby granted, provided that the above
  5. // copyright notice and this permission notice appear in all copies.
  6. //
  7. // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
  8. // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  9. // AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
  10. // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  11. // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  12. // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  13. // PERFORMANCE OF THIS SOFTWARE.
  14. #include <server_common/socket_request.h>
  15. #include <server_common/portconfig.h>
  16. #include <asiodns/asiodns.h>
  17. #include <gtest/gtest.h>
  18. #include <boost/lexical_cast.hpp>
  19. #include <vector>
  20. #include <string>
  21. namespace isc {
  22. namespace server_common {
  23. namespace portconfig {
  24. // Access the private hidden flag
  25. extern bool test_mode;
  26. }
  27. }
  28. namespace testutils {
  29. /// \brief A testcase part for faking the SocketRequestor in tests
  30. ///
  31. /// It's awkward to request real sockets from the real socket creator
  32. /// during tests (for one, because it would have to be running, for
  33. /// another, we need to block real ports). If you instantiate this class in
  34. /// a test case, the socket requestor will be initialized to a test one which
  35. /// handles fake socket FDs and stores what was requested, etc.
  36. ///
  37. /// Furthermore, you can check if the code requested or released the correct
  38. /// list of sockets using the checkTokens() method.
  39. ///
  40. /// Some member variables are intentionally made public so that test cases
  41. /// can easily check the value of them. We prefer convenience for tests over
  42. /// class integrity here.
  43. class TestSocketRequestor : public isc::server_common::SocketRequestor {
  44. public:
  45. /// \brief Constructor
  46. ///
  47. /// \param dnss The DNS service. It is expected this gets initialized
  48. /// after the TestSocketRequestor constructor is called, as the
  49. /// TestSocketRequestor should be a base class and the service only
  50. /// a member.
  51. /// \param store Address store used when cleaning up.
  52. /// \param expect_port The port which is expected to be requested. If
  53. /// the application requests a different port, it is considered
  54. /// a failure.
  55. TestSocketRequestor(asiodns::DNSService& dnss,
  56. server_common::portconfig::AddressList& store,
  57. uint16_t expect_port) :
  58. last_token_(0), break_rollback_(false), dnss_(dnss), store_(store),
  59. expect_port_(expect_port)
  60. {
  61. // Prepare the requestor (us) for the test
  62. server_common::initTestSocketRequestor(this);
  63. // Don't manipulate the real sockets
  64. server_common::portconfig::test_mode = true;
  65. }
  66. /// \brief Destructor
  67. ///
  68. /// Removes the addresses (if any) installed by installListenAddresses,
  69. /// resets the socket requestor to uninitialized state and turns off
  70. /// the portconfig test mode.
  71. virtual ~TestSocketRequestor() {
  72. // Make sure no sockets are left inside (if installListenAddresses
  73. // wasn't used, this is NOP, so it won't hurt).
  74. server_common::portconfig::AddressList list;
  75. server_common::portconfig::installListenAddresses(list, store_, dnss_);
  76. // Don't leave invalid pointers here
  77. server_common::initTestSocketRequestor(NULL);
  78. // And return the mode
  79. server_common::portconfig::test_mode = false;
  80. }
  81. /// \brief Tokens released by releaseSocket
  82. ///
  83. /// They are stored here by this class and you can examine them.
  84. std::vector<std::string> released_tokens_;
  85. /// \brief Tokens returned from requestSocket
  86. ///
  87. /// They are stored here by this class and you can examine them.
  88. std::vector<std::string> given_tokens_;
  89. private:
  90. // Last token number and fd given out
  91. size_t last_token_;
  92. public:
  93. /// \brief Support a broken rollback case
  94. ///
  95. /// If this is set to true, the requestSocket will throw when the
  96. /// ::1 address is requested.
  97. bool break_rollback_;
  98. /// \brief Release a socket
  99. ///
  100. /// This only stores the token passed.
  101. /// \param token The socket to release
  102. void releaseSocket(const std::string& token) {
  103. released_tokens_.push_back(token);
  104. }
  105. /// \brief Request a socket
  106. ///
  107. /// This creates a new token and fakes a new socket and returns it.
  108. /// The token is stored.
  109. ///
  110. /// In case the address is 192.0.2.2, it throws SocketAllocateError
  111. /// or if the break_rollback_ is true and address is ::1, it throws
  112. /// ShareError. If the address is 192.0.2.3, it throws SocketError.
  113. ///
  114. /// The tokens produced are in form of protocol:address:port:fd. The fds
  115. /// start at 1 and increase by each successfull call.
  116. ///
  117. /// \param protocol The protocol to request
  118. /// \param address to bind to
  119. /// \param port to bind to
  120. /// \param mode checked to be DONT_SHARE for now
  121. /// \param name checked to be dummy_app for now
  122. /// \return The token and FD
  123. /// \throw SocketAllocateError as described above, to test error handling
  124. /// \throw ShareError as described above, to test error handling
  125. /// \throw SocketError as described above, to test error handling
  126. SocketID requestSocket(Protocol protocol, const std::string& address,
  127. uint16_t port, ShareMode mode,
  128. const std::string& name)
  129. {
  130. if (address == "192.0.2.2") {
  131. isc_throw(SocketAllocateError, "This address is not allowed");
  132. }
  133. if (address == "192.0.2.3") {
  134. isc_throw(SocketError, "Fatal test error");
  135. }
  136. if (address == "::1" && break_rollback_) {
  137. // This is valid address, but in case we need to break the
  138. // rollback, it needs to be busy or whatever
  139. //
  140. // We break the second address to see the first one was
  141. // allocated and then returned
  142. isc_throw(ShareError,
  143. "This address is available, but not for you");
  144. }
  145. const std::string proto(protocol == TCP ? "TCP" : "UDP");
  146. const size_t number = ++ last_token_;
  147. EXPECT_EQ(expect_port_, port);
  148. EXPECT_EQ(DONT_SHARE, mode);
  149. EXPECT_EQ("dummy_app", name);
  150. const std::string token(proto + ":" + address + ":" +
  151. boost::lexical_cast<std::string>(port) + ":" +
  152. boost::lexical_cast<std::string>(number));
  153. given_tokens_.push_back(token);
  154. return (SocketID(number, token));
  155. }
  156. /// \brief Check the list of tokens is as expected
  157. ///
  158. /// Compares the expected and real tokens.
  159. ///
  160. /// \param expected List of the expected tokens, as NULL-terminated array
  161. /// of C strings (it is more convenient to type as a constant than to
  162. /// manually push_back all the strings to a vector).
  163. /// \param real The token list that was produced by this class (usually
  164. /// either given_tokens_ or released_tokens_).
  165. /// \param scope Human readable identifier of which checkTokens call it is.
  166. /// It is printed as a part of failure message.
  167. void checkTokens(const char** expected,
  168. const std::vector<std::string>& real,
  169. const char* scope) const
  170. {
  171. SCOPED_TRACE(scope);
  172. size_t position(0);
  173. while (expected[position] != NULL) {
  174. ASSERT_LT(position, real.size());
  175. EXPECT_EQ(expected[position], real[position]) << position;
  176. position ++;
  177. }
  178. EXPECT_EQ(position, real.size());
  179. }
  180. private:
  181. asiodns::DNSService& dnss_;
  182. server_common::portconfig::AddressList& store_;
  183. const uint16_t expect_port_;
  184. };
  185. }
  186. }