cmDebuggerPosixPipeConnection.cxx 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
  2. file Copyright.txt or https://cmake.org/licensing for details. */
  3. #include "cmDebuggerPosixPipeConnection.h"
  4. #include <cerrno>
  5. #include <cstring>
  6. #include <stdexcept>
  7. #include <utility>
  8. #include <unistd.h>
  9. #include <sys/socket.h>
  10. namespace cmDebugger {
  11. #ifndef _WIN32
  12. cmDebuggerPipeConnection_POSIX::cmDebuggerPipeConnection_POSIX(
  13. std::string name)
  14. : PipeName(std::move(name))
  15. {
  16. addr.sun_path[0] = '\0';
  17. }
  18. cmDebuggerPipeConnection_POSIX::~cmDebuggerPipeConnection_POSIX()
  19. {
  20. if (isOpen()) {
  21. close();
  22. }
  23. }
  24. bool cmDebuggerPipeConnection_POSIX::StartListening(std::string& errorMessage)
  25. {
  26. listen_fd = socket(AF_UNIX, SOCK_STREAM, 0);
  27. if (listen_fd < 0) {
  28. errorMessage = "Failed to create socket: ";
  29. errorMessage += strerror(errno);
  30. return false;
  31. }
  32. addr.sun_family = AF_UNIX;
  33. strncpy(addr.sun_path, PipeName.c_str(), sizeof(addr.sun_path));
  34. addr.sun_path[sizeof(addr.sun_path) - 1] = '\0';
  35. if (bind(listen_fd, (sockaddr*)&addr, sizeof(addr)) == -1) {
  36. errorMessage = "Failed to bind name '";
  37. errorMessage += addr.sun_path;
  38. errorMessage += "' to socket: ";
  39. errorMessage += strerror(errno);
  40. close_listen();
  41. return false;
  42. }
  43. if (listen(listen_fd, 1) == -1) {
  44. errorMessage = "Failed to listen on socket: ";
  45. errorMessage += strerror(errno);
  46. close_listen();
  47. return false;
  48. }
  49. StartedListening.set_value();
  50. return true;
  51. }
  52. std::shared_ptr<dap::Reader> cmDebuggerPipeConnection_POSIX::GetReader()
  53. {
  54. return std::static_pointer_cast<dap::Reader>(shared_from_this());
  55. }
  56. std::shared_ptr<dap::Writer> cmDebuggerPipeConnection_POSIX::GetWriter()
  57. {
  58. return std::static_pointer_cast<dap::Writer>(shared_from_this());
  59. }
  60. bool cmDebuggerPipeConnection_POSIX::isOpen()
  61. {
  62. return rw_pipe >= 0;
  63. }
  64. void cmDebuggerPipeConnection_POSIX::close()
  65. {
  66. close_listen();
  67. ::close(rw_pipe);
  68. rw_pipe = -1;
  69. }
  70. void cmDebuggerPipeConnection_POSIX::close_listen()
  71. {
  72. if (strlen(addr.sun_path) > 0) {
  73. unlink(addr.sun_path);
  74. addr.sun_path[0] = '\0';
  75. }
  76. ::close(listen_fd);
  77. listen_fd = -1;
  78. }
  79. void cmDebuggerPipeConnection_POSIX::WaitForConnection()
  80. {
  81. sockaddr_un laddr;
  82. socklen_t len = sizeof(laddr);
  83. rw_pipe = accept(listen_fd, (sockaddr*)&laddr, &len);
  84. if (rw_pipe < 0) {
  85. close();
  86. return;
  87. }
  88. close_listen(); // no longer need the listen resources
  89. }
  90. size_t cmDebuggerPipeConnection_POSIX::read(void* buffer, size_t n)
  91. {
  92. size_t result = 0;
  93. if (rw_pipe >= 0) {
  94. result = ::read(rw_pipe, buffer, n);
  95. if (result == 0) {
  96. close();
  97. }
  98. }
  99. return result;
  100. }
  101. bool cmDebuggerPipeConnection_POSIX::write(void const* buffer, size_t n)
  102. {
  103. bool result = false;
  104. if (rw_pipe >= 0) {
  105. result = ::write(rw_pipe, buffer, n) >= 0;
  106. if (!result) {
  107. close();
  108. }
  109. }
  110. return result;
  111. }
  112. cmDebuggerPipeClient_POSIX::cmDebuggerPipeClient_POSIX(std::string name)
  113. : PipeName(std::move(name))
  114. {
  115. }
  116. cmDebuggerPipeClient_POSIX::~cmDebuggerPipeClient_POSIX()
  117. {
  118. close();
  119. }
  120. void cmDebuggerPipeClient_POSIX::WaitForConnection()
  121. {
  122. rw_pipe = socket(AF_UNIX, SOCK_STREAM, 0);
  123. if (rw_pipe < 0) {
  124. throw std::runtime_error(std::string("Failed to create socket: ") +
  125. strerror(errno));
  126. }
  127. sockaddr_un addr;
  128. addr.sun_family = AF_UNIX;
  129. strncpy(addr.sun_path, PipeName.c_str(), sizeof(addr.sun_path));
  130. addr.sun_path[sizeof(addr.sun_path) - 1] = '\0';
  131. if (connect(rw_pipe, (sockaddr*)&addr, sizeof(addr)) == -1) {
  132. close();
  133. throw std::runtime_error(
  134. std::string("Failed to connect path to socket: ") + strerror(errno));
  135. }
  136. }
  137. bool cmDebuggerPipeClient_POSIX::isOpen()
  138. {
  139. return rw_pipe >= 0;
  140. }
  141. void cmDebuggerPipeClient_POSIX::close()
  142. {
  143. if (isOpen()) {
  144. ::close(rw_pipe);
  145. rw_pipe = -1;
  146. }
  147. }
  148. size_t cmDebuggerPipeClient_POSIX::read(void* buffer, size_t n)
  149. {
  150. int count = 0;
  151. if (isOpen()) {
  152. count = static_cast<int>(::read(rw_pipe, buffer, n));
  153. if (count == 0) {
  154. close();
  155. }
  156. }
  157. return count;
  158. }
  159. bool cmDebuggerPipeClient_POSIX::write(void const* buffer, size_t n)
  160. {
  161. int count = 0;
  162. if (isOpen()) {
  163. count = static_cast<int>(::write(rw_pipe, buffer, n));
  164. if (count < 0) {
  165. close();
  166. }
  167. }
  168. return count > 0;
  169. }
  170. #endif // !_WIN32
  171. } // namespace cmDebugger