unix_control_client.cc 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. // Copyright (C) 2015 Internet Systems Consortium, Inc. ("ISC")
  2. //
  3. // This Source Code Form is subject to the terms of the Mozilla Public
  4. // License, v. 2.0. If a copy of the MPL was not distributed with this
  5. // file, You can obtain one at http://mozilla.org/MPL/2.0/.
  6. #include <gtest/gtest.h>
  7. #include <testutils/unix_control_client.h>
  8. #include <unistd.h>
  9. #include <sys/socket.h>
  10. #include <sys/un.h>
  11. #include <errno.h>
  12. #include <string.h>
  13. namespace isc {
  14. namespace dhcp {
  15. namespace test {
  16. UnixControlClient::UnixControlClient() {
  17. socket_fd_ = -1;
  18. }
  19. UnixControlClient::~UnixControlClient() {
  20. disconnectFromServer();
  21. }
  22. /// @brief Closes the Control Channel socket
  23. void UnixControlClient::disconnectFromServer() {
  24. if (socket_fd_ >= 0) {
  25. static_cast<void>(close(socket_fd_));
  26. socket_fd_ = -1;
  27. }
  28. }
  29. bool UnixControlClient::connectToServer(const std::string& socket_path) {
  30. // Create UNIX socket
  31. socket_fd_ = socket(AF_UNIX, SOCK_STREAM, 0);
  32. if (socket_fd_ < 0) {
  33. const char* errmsg = strerror(errno);
  34. ADD_FAILURE() << "Failed to open unix stream socket: " << errmsg;
  35. return (false);
  36. }
  37. struct sockaddr_un srv_addr;
  38. if (socket_path.size() > sizeof(srv_addr.sun_path) - 1) {
  39. ADD_FAILURE() << "Socket path specified (" << socket_path
  40. << ") is larger than " << (sizeof(srv_addr.sun_path) - 1)
  41. << " allowed.";
  42. disconnectFromServer();
  43. return (false);
  44. }
  45. // Prepare socket address
  46. memset(&srv_addr, 0, sizeof(srv_addr));
  47. srv_addr.sun_family = AF_UNIX;
  48. strncpy(srv_addr.sun_path, socket_path.c_str(),
  49. sizeof(srv_addr.sun_path));
  50. socklen_t len = sizeof(srv_addr);
  51. // Connect to the specified UNIX socket
  52. int status = connect(socket_fd_, (struct sockaddr*)&srv_addr, len);
  53. if (status == -1) {
  54. const char* errmsg = strerror(errno);
  55. ADD_FAILURE() << "Failed to connect unix socket: fd=" << socket_fd_
  56. << ", path=" << socket_path << " : " << errmsg;
  57. disconnectFromServer();
  58. return (false);
  59. }
  60. return (true);
  61. }
  62. bool UnixControlClient::sendCommand(const std::string& command) {
  63. // Send command
  64. int bytes_sent = send(socket_fd_, command.c_str(), command.length(), 0);
  65. if (bytes_sent < command.length()) {
  66. const char* errmsg = strerror(errno);
  67. ADD_FAILURE() << "Failed to send " << command.length()
  68. << " bytes, send() returned " << bytes_sent
  69. << " : " << errmsg;
  70. return (false);
  71. }
  72. return (true);
  73. }
  74. bool UnixControlClient::getResponse(std::string& response,
  75. const unsigned int timeout_sec) {
  76. // Receive response
  77. char buf[65536];
  78. memset(buf, 0, sizeof(buf));
  79. switch (selectCheck(timeout_sec)) {
  80. case -1: {
  81. const char* errmsg = strerror(errno);
  82. ADD_FAILURE() << "getResponse - select failed: " << errmsg;
  83. return (false);
  84. }
  85. case 0:
  86. return (false);
  87. default:
  88. break;
  89. }
  90. int bytes_rcvd = recv(socket_fd_, buf, sizeof(buf), 0);
  91. if (bytes_rcvd < 0) {
  92. const char* errmsg = strerror(errno);
  93. ADD_FAILURE() << "Failed to receive a response. recv() returned "
  94. << bytes_rcvd << " : " << errmsg;
  95. return (false);
  96. }
  97. if (bytes_rcvd >= sizeof(buf)) {
  98. ADD_FAILURE() << "Response size too large: " << bytes_rcvd;
  99. return (false);
  100. }
  101. // Convert the response to a string
  102. response = std::string(buf, bytes_rcvd);
  103. return (true);
  104. }
  105. int UnixControlClient::selectCheck(const unsigned int timeout_sec) {
  106. int maxfd = 0;
  107. fd_set read_fds;
  108. FD_ZERO(&read_fds);
  109. // Add this socket to listening set
  110. FD_SET(socket_fd_, &read_fds);
  111. maxfd = socket_fd_;
  112. struct timeval select_timeout;
  113. select_timeout.tv_sec = static_cast<time_t>(timeout_sec);
  114. select_timeout.tv_usec = 0;
  115. return (select(maxfd + 1, &read_fds, NULL, NULL, &select_timeout));
  116. }
  117. };
  118. };
  119. };