local_socket_unittest.cc 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253
  1. // Copyright (C) 2013 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 <asiolink/local_socket.h>
  15. #include <asiolink/io_error.h>
  16. #include <gtest/gtest.h>
  17. #include <boost/noncopyable.hpp>
  18. #include <boost/scoped_ptr.hpp>
  19. #include <boost/bind.hpp>
  20. #include <csignal>
  21. #include <cstring>
  22. #include <vector>
  23. #include <sys/socket.h>
  24. #include <stdint.h>
  25. #include <unistd.h> // for alarm(3)
  26. using namespace isc::asiolink;
  27. namespace {
  28. // duration (in seconds) until we break possible hangup; value is an
  29. // arbitrary choice.
  30. const unsigned IO_TIMEOUT = 10;
  31. // A simple RAII wrapper for a file descriptor so test sockets are safely
  32. // closed in each test.
  33. class ScopedSocket : boost::noncopyable {
  34. public:
  35. ScopedSocket() : fd_(-1) {}
  36. ~ScopedSocket() {
  37. if (fd_ >= 0) {
  38. EXPECT_EQ(0, ::close(fd_));
  39. }
  40. }
  41. void set(int fd) {
  42. assert(fd_ == -1);
  43. fd_ = fd;
  44. }
  45. int get() { return (fd_); }
  46. int release() {
  47. const int ret = fd_;
  48. fd_ = -1;
  49. return (ret);
  50. }
  51. private:
  52. int fd_;
  53. };
  54. class LocalSocketTest : public ::testing::Test {
  55. protected:
  56. LocalSocketTest() {
  57. int sock_pair[2];
  58. EXPECT_EQ(0, socketpair(AF_UNIX, SOCK_STREAM, 0, sock_pair));
  59. sock_pair_[0].set(sock_pair[0]);
  60. sock_pair_[1].set(sock_pair[1]);
  61. // For tests using actual I/O we use a timer to prevent hangup
  62. // due to a bug. Set up the signal handler for the timer here.
  63. g_io_service_ = &io_service_;
  64. prev_handler_ = std::signal(SIGALRM, stopIOService);
  65. }
  66. ~LocalSocketTest() {
  67. alarm(0);
  68. // reset the global to NULL to detect any invalid access to freed
  69. // io_service (this shouldn't happen, so we don't change stopIOService
  70. // itself)
  71. g_io_service_ = NULL;
  72. std::signal(SIGALRM, prev_handler_);
  73. }
  74. // Common set of tests for async read
  75. void checkAsyncRead(size_t data_len);
  76. IOService io_service_;
  77. ScopedSocket sock_pair_[2];
  78. std::vector<uint8_t> read_buf_;
  79. private:
  80. static IOService* g_io_service_; // will be set to &io_service_
  81. void (*prev_handler_)(int);
  82. // SIGALRM handler to prevent hangup. This must be a static method
  83. // so it can be passed to std::signal().
  84. static void stopIOService(int) {
  85. g_io_service_->stop();
  86. }
  87. };
  88. IOService* LocalSocketTest::g_io_service_ = NULL;
  89. TEST_F(LocalSocketTest, construct) {
  90. const int fd = sock_pair_[0].release();
  91. LocalSocket sock(io_service_, fd);
  92. EXPECT_EQ(fd, sock.getNative());
  93. EXPECT_EQ(AF_UNIX, sock.getProtocol());
  94. }
  95. TEST_F(LocalSocketTest, constructError) {
  96. // try to construct a LocalSocket object with a closed socket. It should
  97. // fail.
  98. const int fd = sock_pair_[0].release();
  99. EXPECT_EQ(0, close(fd));
  100. EXPECT_THROW(LocalSocket(io_service_, fd), IOError);
  101. }
  102. TEST_F(LocalSocketTest, autoClose) {
  103. // Confirm that passed FD will be closed on destruction of LocalSocket
  104. const int fd = sock_pair_[0].release();
  105. {
  106. LocalSocket sock(io_service_, fd);
  107. }
  108. // fd should have been closed, so close() should fail (we assume there's
  109. // no other open() call since then)
  110. EXPECT_EQ(-1, ::close(fd));
  111. }
  112. void
  113. callback(const std::string& error, IOService* io_service, bool* called,
  114. bool expect_error)
  115. {
  116. if (expect_error) {
  117. EXPECT_NE("", error);
  118. } else {
  119. EXPECT_EQ("", error);
  120. }
  121. *called = true;
  122. io_service->stop();
  123. }
  124. void
  125. LocalSocketTest::checkAsyncRead(size_t data_len) {
  126. LocalSocket sock(io_service_, sock_pair_[0].release());
  127. bool callback_called = false;
  128. read_buf_.resize(data_len);
  129. sock.asyncRead(boost::bind(&callback, _1, &io_service_, &callback_called,
  130. false), &read_buf_[0], data_len);
  131. std::vector<uint8_t> expected_data(data_len);
  132. for (size_t i = 0; i < data_len; ++i) {
  133. expected_data[i] = i & 0xff;
  134. }
  135. alarm(IO_TIMEOUT);
  136. // If write blocks, it will eventually fail due to signal interruption.
  137. // Since io_service has been stopped already, run() would immediately
  138. // return and test should complete (with failure). But to make very sure
  139. // it never cause hangup we rather return from the test at the point of
  140. // failure of write. In either case it signals a failure and need for
  141. // a fix.
  142. ASSERT_EQ(data_len, write(sock_pair_[1].get(), &expected_data[0],
  143. data_len));
  144. io_service_.run();
  145. EXPECT_TRUE(callback_called);
  146. EXPECT_EQ(0, std::memcmp(&expected_data[0], &read_buf_[0], data_len));
  147. }
  148. TEST_F(LocalSocketTest, asyncRead) {
  149. // A simple case of asynchronous read: wait for 1 byte and successfully
  150. // read it in the run() loop.
  151. checkAsyncRead(1);
  152. }
  153. TEST_F(LocalSocketTest, asyncLargeRead) {
  154. // Similar to the previous case, but for moderately larger data.
  155. // (for the moment) we don't expect to use this interface with much
  156. // larger data that could cause blocking write.
  157. checkAsyncRead(1024);
  158. }
  159. TEST_F(LocalSocketTest, asyncPartialRead) {
  160. alarm(IO_TIMEOUT);
  161. // specify reading 4 bytes of data, and send 3 bytes. It shouldn't cause
  162. // callback. while we actually don't use the buffer, we'll initialize it
  163. // to make valgrind happy.
  164. char recv_buf[4];
  165. std::memset(recv_buf, 0, sizeof(recv_buf));
  166. bool callback_called = false;
  167. LocalSocket sock(io_service_, sock_pair_[0].release());
  168. sock.asyncRead(boost::bind(&callback, _1, &io_service_, &callback_called,
  169. false), recv_buf, sizeof(recv_buf));
  170. EXPECT_EQ(3, write(sock_pair_[1].get(), recv_buf, 3));
  171. // open another pair of sockets so we can stop the IO service after run.
  172. int socks[2];
  173. char ch = 0;
  174. EXPECT_EQ(0, socketpair(AF_UNIX, SOCK_STREAM, 0, socks));
  175. ScopedSocket aux_sockpair[2];
  176. aux_sockpair[0].set(socks[0]);
  177. aux_sockpair[1].set(socks[1]);
  178. LocalSocket aux_sock(io_service_, aux_sockpair[0].get());
  179. aux_sockpair[0].release(); // on successful construction we should release
  180. bool aux_callback_called = false;
  181. aux_sock.asyncRead(boost::bind(&callback, _1, &io_service_,
  182. &aux_callback_called, false), &ch, 1);
  183. EXPECT_EQ(1, write(aux_sockpair[1].get(), &ch, 1));
  184. // run the IO service, it will soon be stopped via the auxiliary callback.
  185. // the main callback shouldn't be called.
  186. io_service_.run();
  187. EXPECT_FALSE(callback_called);
  188. EXPECT_TRUE(aux_callback_called);
  189. }
  190. TEST_F(LocalSocketTest, asyncReadError) {
  191. const int sock_fd = sock_pair_[0].release();
  192. LocalSocket sock(io_service_, sock_fd);
  193. bool callback_called = false;
  194. read_buf_.resize(1);
  195. read_buf_.at(0) = 53; // dummy data to check it later
  196. const char ch = 35; // send different data to the read socket with data
  197. EXPECT_EQ(1, write(sock_pair_[1].get(), &ch, 1));
  198. close(sock_fd); // invalidate the read socket
  199. // we'll get callback with an error (e.g. 'bad file descriptor)
  200. sock.asyncRead(boost::bind(&callback, _1, &io_service_, &callback_called,
  201. true), &read_buf_[0], 1);
  202. io_service_.run();
  203. EXPECT_TRUE(callback_called);
  204. EXPECT_EQ(53, read_buf_.at(0));
  205. }
  206. TEST_F(LocalSocketTest, asyncReadThenDestroy) {
  207. // destroy the socket before running the IO service. we'll still get
  208. // callback with an error.
  209. boost::scoped_ptr<LocalSocket> sock(
  210. new LocalSocket(io_service_, sock_pair_[0].release()));
  211. read_buf_.resize(1);
  212. bool callback_called = false;
  213. sock->asyncRead(boost::bind(&callback, _1, &io_service_, &callback_called,
  214. true), &read_buf_[0], 1);
  215. sock.reset();
  216. io_service_.run();
  217. EXPECT_TRUE(callback_called);
  218. }
  219. }