cmServerConnection.cxx 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303
  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 "cmServerConnection.h"
  4. #include "cmServerDictionary.h"
  5. #include "cmFileMonitor.h"
  6. #include "cmServer.h"
  7. #include <assert.h>
  8. namespace {
  9. struct write_req_t
  10. {
  11. uv_write_t req;
  12. uv_buf_t buf;
  13. };
  14. void on_alloc_buffer(uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf)
  15. {
  16. (void)(handle);
  17. char* rawBuffer = new char[suggested_size];
  18. *buf = uv_buf_init(rawBuffer, static_cast<unsigned int>(suggested_size));
  19. }
  20. void on_read(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf)
  21. {
  22. auto conn = reinterpret_cast<cmServerConnection*>(stream->data);
  23. if (nread >= 0) {
  24. conn->ReadData(std::string(buf->base, buf->base + nread));
  25. } else {
  26. conn->HandleEof();
  27. }
  28. delete[](buf->base);
  29. }
  30. void on_write(uv_write_t* req, int status)
  31. {
  32. (void)(status);
  33. auto conn = reinterpret_cast<cmServerConnection*>(req->data);
  34. // Free req and buffer
  35. write_req_t* wr = reinterpret_cast<write_req_t*>(req);
  36. delete[](wr->buf.base);
  37. delete wr;
  38. conn->ProcessNextRequest();
  39. }
  40. void on_new_connection(uv_stream_t* stream, int status)
  41. {
  42. (void)(status);
  43. auto conn = reinterpret_cast<cmServerConnection*>(stream->data);
  44. conn->Connect(stream);
  45. }
  46. } // namespace
  47. class LoopGuard
  48. {
  49. public:
  50. LoopGuard(cmServerConnection* connection)
  51. : Connection(connection)
  52. {
  53. Connection->mLoop = uv_default_loop();
  54. if (Connection->mLoop) {
  55. Connection->mFileMonitor = new cmFileMonitor(Connection->mLoop);
  56. }
  57. }
  58. ~LoopGuard()
  59. {
  60. if (Connection->mFileMonitor) {
  61. delete Connection->mFileMonitor;
  62. }
  63. uv_loop_close(Connection->mLoop);
  64. Connection->mLoop = nullptr;
  65. }
  66. private:
  67. cmServerConnection* Connection;
  68. };
  69. cmServerConnection::cmServerConnection()
  70. {
  71. }
  72. cmServerConnection::~cmServerConnection()
  73. {
  74. }
  75. void cmServerConnection::SetServer(cmServer* s)
  76. {
  77. this->Server = s;
  78. }
  79. bool cmServerConnection::ProcessEvents(std::string* errorMessage)
  80. {
  81. assert(this->Server);
  82. errorMessage->clear();
  83. this->RawReadBuffer.clear();
  84. this->RequestBuffer.clear();
  85. LoopGuard guard(this);
  86. (void)(guard);
  87. if (!this->mLoop) {
  88. *errorMessage = "Internal Error: Failed to create event loop.";
  89. return false;
  90. }
  91. if (!DoSetup(errorMessage)) {
  92. return false;
  93. }
  94. if (uv_run(this->mLoop, UV_RUN_DEFAULT) != 0) {
  95. *errorMessage = "Internal Error: Event loop stopped in unclean state.";
  96. return false;
  97. }
  98. // These need to be cleaned up by now:
  99. assert(!this->ReadStream);
  100. assert(!this->WriteStream);
  101. this->RawReadBuffer.clear();
  102. this->RequestBuffer.clear();
  103. return true;
  104. }
  105. void cmServerConnection::ReadData(const std::string& data)
  106. {
  107. this->RawReadBuffer += data;
  108. for (;;) {
  109. auto needle = this->RawReadBuffer.find('\n');
  110. if (needle == std::string::npos) {
  111. return;
  112. }
  113. std::string line = this->RawReadBuffer.substr(0, needle);
  114. const auto ls = line.size();
  115. if (ls > 1 && line.at(ls - 1) == '\r') {
  116. line.erase(ls - 1, 1);
  117. }
  118. this->RawReadBuffer.erase(this->RawReadBuffer.begin(),
  119. this->RawReadBuffer.begin() +
  120. static_cast<long>(needle) + 1);
  121. if (line == kSTART_MAGIC) {
  122. this->RequestBuffer.clear();
  123. continue;
  124. }
  125. if (line == kEND_MAGIC) {
  126. this->Server->QueueRequest(this->RequestBuffer);
  127. this->RequestBuffer.clear();
  128. } else {
  129. this->RequestBuffer += line;
  130. this->RequestBuffer += "\n";
  131. }
  132. }
  133. }
  134. void cmServerConnection::HandleEof()
  135. {
  136. this->TearDown();
  137. }
  138. void cmServerConnection::WriteData(const std::string& data)
  139. {
  140. assert(this->WriteStream);
  141. auto ds = data.size();
  142. write_req_t* req = new write_req_t;
  143. req->req.data = this;
  144. req->buf = uv_buf_init(new char[ds], static_cast<unsigned int>(ds));
  145. memcpy(req->buf.base, data.c_str(), ds);
  146. uv_write(reinterpret_cast<uv_write_t*>(req),
  147. static_cast<uv_stream_t*>(this->WriteStream), &req->buf, 1,
  148. on_write);
  149. }
  150. void cmServerConnection::ProcessNextRequest()
  151. {
  152. Server->PopOne();
  153. }
  154. void cmServerConnection::SendGreetings()
  155. {
  156. Server->PrintHello();
  157. }
  158. bool cmServerStdIoConnection::DoSetup(std::string* errorMessage)
  159. {
  160. (void)(errorMessage);
  161. if (uv_guess_handle(1) == UV_TTY) {
  162. uv_tty_init(this->Loop(), &this->Input.tty, 0, 1);
  163. uv_tty_set_mode(&this->Input.tty, UV_TTY_MODE_NORMAL);
  164. Input.tty.data = this;
  165. this->ReadStream = reinterpret_cast<uv_stream_t*>(&this->Input.tty);
  166. uv_tty_init(this->Loop(), &this->Output.tty, 1, 0);
  167. uv_tty_set_mode(&this->Output.tty, UV_TTY_MODE_NORMAL);
  168. Output.tty.data = this;
  169. this->WriteStream = reinterpret_cast<uv_stream_t*>(&this->Output.tty);
  170. } else {
  171. uv_pipe_init(this->Loop(), &this->Input.pipe, 0);
  172. uv_pipe_open(&this->Input.pipe, 0);
  173. Input.pipe.data = this;
  174. this->ReadStream = reinterpret_cast<uv_stream_t*>(&this->Input.pipe);
  175. uv_pipe_init(this->Loop(), &this->Output.pipe, 0);
  176. uv_pipe_open(&this->Output.pipe, 1);
  177. Output.pipe.data = this;
  178. this->WriteStream = reinterpret_cast<uv_stream_t*>(&this->Output.pipe);
  179. }
  180. SendGreetings();
  181. uv_read_start(this->ReadStream, on_alloc_buffer, on_read);
  182. return true;
  183. }
  184. void cmServerStdIoConnection::TearDown()
  185. {
  186. uv_close(reinterpret_cast<uv_handle_t*>(this->ReadStream), nullptr);
  187. this->ReadStream = nullptr;
  188. uv_close(reinterpret_cast<uv_handle_t*>(this->WriteStream), nullptr);
  189. this->WriteStream = nullptr;
  190. }
  191. cmServerPipeConnection::cmServerPipeConnection(const std::string& name)
  192. : PipeName(name)
  193. {
  194. this->ServerPipe.data = nullptr;
  195. this->ClientPipe.data = nullptr;
  196. }
  197. bool cmServerPipeConnection::DoSetup(std::string* errorMessage)
  198. {
  199. uv_pipe_init(this->Loop(), &this->ServerPipe, 0);
  200. this->ServerPipe.data = this;
  201. int r;
  202. if ((r = uv_pipe_bind(&this->ServerPipe, this->PipeName.c_str())) != 0) {
  203. *errorMessage = std::string("Internal Error with ") + this->PipeName +
  204. ": " + uv_err_name(r);
  205. return false;
  206. }
  207. auto serverStream = reinterpret_cast<uv_stream_t*>(&this->ServerPipe);
  208. serverStream->data = this;
  209. if ((r = uv_listen(serverStream, 1, on_new_connection)) != 0) {
  210. *errorMessage = std::string("Internal Error with ") + this->PipeName +
  211. ": " + uv_err_name(r);
  212. return false;
  213. }
  214. return true;
  215. }
  216. void cmServerPipeConnection::TearDown()
  217. {
  218. if (this->WriteStream->data) {
  219. uv_close(reinterpret_cast<uv_handle_t*>(this->WriteStream), nullptr);
  220. this->WriteStream->data = nullptr;
  221. }
  222. uv_close(reinterpret_cast<uv_handle_t*>(&this->ServerPipe), nullptr);
  223. this->WriteStream = nullptr;
  224. this->ReadStream = nullptr;
  225. }
  226. void cmServerPipeConnection::Connect(uv_stream_t* server)
  227. {
  228. if (this->ClientPipe.data == this) {
  229. // Accept and close all pipes but the first:
  230. uv_pipe_t rejectPipe;
  231. uv_pipe_init(this->Loop(), &rejectPipe, 0);
  232. auto rejecter = reinterpret_cast<uv_stream_t*>(&rejectPipe);
  233. uv_accept(server, rejecter);
  234. uv_close(reinterpret_cast<uv_handle_t*>(rejecter), nullptr);
  235. return;
  236. }
  237. uv_pipe_init(this->Loop(), &this->ClientPipe, 0);
  238. this->ClientPipe.data = this;
  239. auto client = reinterpret_cast<uv_stream_t*>(&this->ClientPipe);
  240. if (uv_accept(server, client) != 0) {
  241. uv_close(reinterpret_cast<uv_handle_t*>(client), nullptr);
  242. return;
  243. }
  244. this->ReadStream = client;
  245. this->WriteStream = client;
  246. uv_read_start(this->ReadStream, on_alloc_buffer, on_read);
  247. this->SendGreetings();
  248. }