cmServerConnection.cxx 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377
  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->TriggerShutdown();
  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. void on_signal(uv_signal_t* signal, int signum)
  47. {
  48. auto conn = reinterpret_cast<cmServerConnection*>(signal->data);
  49. (void)(signum);
  50. conn->TriggerShutdown();
  51. }
  52. void on_signal_close(uv_handle_t* handle)
  53. {
  54. delete reinterpret_cast<uv_signal_t*>(handle);
  55. }
  56. void on_pipe_close(uv_handle_t* handle)
  57. {
  58. delete reinterpret_cast<uv_pipe_t*>(handle);
  59. }
  60. void on_tty_close(uv_handle_t* handle)
  61. {
  62. delete reinterpret_cast<uv_tty_t*>(handle);
  63. }
  64. } // namespace
  65. class LoopGuard
  66. {
  67. public:
  68. LoopGuard(cmServerConnection* connection)
  69. : Connection(connection)
  70. {
  71. this->Connection->mLoop = uv_default_loop();
  72. if (!this->Connection->mLoop) {
  73. return;
  74. }
  75. this->Connection->mFileMonitor =
  76. new cmFileMonitor(this->Connection->mLoop);
  77. }
  78. ~LoopGuard()
  79. {
  80. if (!this->Connection->mLoop) {
  81. return;
  82. }
  83. if (this->Connection->mFileMonitor) {
  84. delete this->Connection->mFileMonitor;
  85. }
  86. uv_loop_close(this->Connection->mLoop);
  87. this->Connection->mLoop = nullptr;
  88. }
  89. private:
  90. cmServerConnection* Connection;
  91. };
  92. cmServerConnection::cmServerConnection()
  93. {
  94. }
  95. cmServerConnection::~cmServerConnection()
  96. {
  97. }
  98. void cmServerConnection::SetServer(cmServer* s)
  99. {
  100. this->Server = s;
  101. }
  102. bool cmServerConnection::ProcessEvents(std::string* errorMessage)
  103. {
  104. assert(this->Server);
  105. errorMessage->clear();
  106. this->RawReadBuffer.clear();
  107. this->RequestBuffer.clear();
  108. LoopGuard guard(this);
  109. (void)(guard);
  110. if (!this->mLoop) {
  111. *errorMessage = "Internal Error: Failed to create event loop.";
  112. return false;
  113. }
  114. this->SIGINTHandler = new uv_signal_t;
  115. uv_signal_init(this->mLoop, this->SIGINTHandler);
  116. this->SIGINTHandler->data = static_cast<void*>(this);
  117. uv_signal_start(this->SIGINTHandler, &on_signal, SIGINT);
  118. this->SIGHUPHandler = new uv_signal_t;
  119. uv_signal_init(this->mLoop, this->SIGHUPHandler);
  120. this->SIGHUPHandler->data = static_cast<void*>(this);
  121. uv_signal_start(this->SIGHUPHandler, &on_signal, SIGHUP);
  122. if (!DoSetup(errorMessage)) {
  123. return false;
  124. }
  125. if (uv_run(this->mLoop, UV_RUN_DEFAULT) != 0) {
  126. *errorMessage = "Internal Error: Event loop stopped in unclean state.";
  127. return false;
  128. }
  129. // These need to be cleaned up by now:
  130. assert(!this->ReadStream);
  131. assert(!this->WriteStream);
  132. this->RawReadBuffer.clear();
  133. this->RequestBuffer.clear();
  134. return true;
  135. }
  136. void cmServerConnection::ReadData(const std::string& data)
  137. {
  138. this->RawReadBuffer += data;
  139. for (;;) {
  140. auto needle = this->RawReadBuffer.find('\n');
  141. if (needle == std::string::npos) {
  142. return;
  143. }
  144. std::string line = this->RawReadBuffer.substr(0, needle);
  145. const auto ls = line.size();
  146. if (ls > 1 && line.at(ls - 1) == '\r') {
  147. line.erase(ls - 1, 1);
  148. }
  149. this->RawReadBuffer.erase(this->RawReadBuffer.begin(),
  150. this->RawReadBuffer.begin() +
  151. static_cast<long>(needle) + 1);
  152. if (line == kSTART_MAGIC) {
  153. this->RequestBuffer.clear();
  154. continue;
  155. }
  156. if (line == kEND_MAGIC) {
  157. this->Server->QueueRequest(this->RequestBuffer);
  158. this->RequestBuffer.clear();
  159. } else {
  160. this->RequestBuffer += line;
  161. this->RequestBuffer += "\n";
  162. }
  163. }
  164. }
  165. void cmServerConnection::TriggerShutdown()
  166. {
  167. this->FileMonitor()->StopMonitoring();
  168. uv_signal_stop(this->SIGINTHandler);
  169. uv_signal_stop(this->SIGHUPHandler);
  170. uv_close(reinterpret_cast<uv_handle_t*>(this->SIGINTHandler),
  171. &on_signal_close); // delete handle
  172. uv_close(reinterpret_cast<uv_handle_t*>(this->SIGHUPHandler),
  173. &on_signal_close); // delete handle
  174. this->SIGINTHandler = nullptr;
  175. this->SIGHUPHandler = nullptr;
  176. this->TearDown();
  177. }
  178. void cmServerConnection::WriteData(const std::string& data)
  179. {
  180. assert(this->WriteStream);
  181. auto ds = data.size();
  182. write_req_t* req = new write_req_t;
  183. req->req.data = this;
  184. req->buf = uv_buf_init(new char[ds], static_cast<unsigned int>(ds));
  185. memcpy(req->buf.base, data.c_str(), ds);
  186. uv_write(reinterpret_cast<uv_write_t*>(req),
  187. static_cast<uv_stream_t*>(this->WriteStream), &req->buf, 1,
  188. on_write);
  189. }
  190. void cmServerConnection::ProcessNextRequest()
  191. {
  192. Server->PopOne();
  193. }
  194. void cmServerConnection::SendGreetings()
  195. {
  196. Server->PrintHello();
  197. }
  198. cmServerStdIoConnection::cmServerStdIoConnection()
  199. {
  200. this->Input.tty = nullptr;
  201. this->Output.tty = nullptr;
  202. }
  203. bool cmServerStdIoConnection::DoSetup(std::string* errorMessage)
  204. {
  205. (void)(errorMessage);
  206. if (uv_guess_handle(1) == UV_TTY) {
  207. usesTty = true;
  208. this->Input.tty = new uv_tty_t;
  209. uv_tty_init(this->Loop(), this->Input.tty, 0, 1);
  210. uv_tty_set_mode(this->Input.tty, UV_TTY_MODE_NORMAL);
  211. Input.tty->data = this;
  212. this->ReadStream = reinterpret_cast<uv_stream_t*>(this->Input.tty);
  213. this->Output.tty = new uv_tty_t;
  214. uv_tty_init(this->Loop(), this->Output.tty, 1, 0);
  215. uv_tty_set_mode(this->Output.tty, UV_TTY_MODE_NORMAL);
  216. Output.tty->data = this;
  217. this->WriteStream = reinterpret_cast<uv_stream_t*>(this->Output.tty);
  218. } else {
  219. usesTty = false;
  220. this->Input.pipe = new uv_pipe_t;
  221. uv_pipe_init(this->Loop(), this->Input.pipe, 0);
  222. uv_pipe_open(this->Input.pipe, 0);
  223. Input.pipe->data = this;
  224. this->ReadStream = reinterpret_cast<uv_stream_t*>(this->Input.pipe);
  225. this->Output.pipe = new uv_pipe_t;
  226. uv_pipe_init(this->Loop(), this->Output.pipe, 0);
  227. uv_pipe_open(this->Output.pipe, 1);
  228. Output.pipe->data = this;
  229. this->WriteStream = reinterpret_cast<uv_stream_t*>(this->Output.pipe);
  230. }
  231. SendGreetings();
  232. uv_read_start(this->ReadStream, on_alloc_buffer, on_read);
  233. return true;
  234. }
  235. void cmServerStdIoConnection::TearDown()
  236. {
  237. if (usesTty) {
  238. uv_close(reinterpret_cast<uv_handle_t*>(this->Input.tty), &on_tty_close);
  239. uv_close(reinterpret_cast<uv_handle_t*>(this->Output.tty), &on_tty_close);
  240. this->Input.tty = nullptr;
  241. this->Output.tty = nullptr;
  242. } else {
  243. uv_close(reinterpret_cast<uv_handle_t*>(this->Input.pipe), &on_pipe_close);
  244. uv_close(reinterpret_cast<uv_handle_t*>(this->Output.pipe),
  245. &on_pipe_close);
  246. this->Input.pipe = nullptr;
  247. this->Input.pipe = nullptr;
  248. }
  249. this->ReadStream = nullptr;
  250. this->WriteStream = nullptr;
  251. }
  252. cmServerPipeConnection::cmServerPipeConnection(const std::string& name)
  253. : PipeName(name)
  254. {
  255. }
  256. bool cmServerPipeConnection::DoSetup(std::string* errorMessage)
  257. {
  258. this->ServerPipe = new uv_pipe_t;
  259. uv_pipe_init(this->Loop(), this->ServerPipe, 0);
  260. this->ServerPipe->data = this;
  261. int r;
  262. if ((r = uv_pipe_bind(this->ServerPipe, this->PipeName.c_str())) != 0) {
  263. *errorMessage = std::string("Internal Error with ") + this->PipeName +
  264. ": " + uv_err_name(r);
  265. return false;
  266. }
  267. auto serverStream = reinterpret_cast<uv_stream_t*>(this->ServerPipe);
  268. if ((r = uv_listen(serverStream, 1, on_new_connection)) != 0) {
  269. *errorMessage = std::string("Internal Error listening on ") +
  270. this->PipeName + ": " + uv_err_name(r);
  271. return false;
  272. }
  273. return true;
  274. }
  275. void cmServerPipeConnection::TearDown()
  276. {
  277. if (this->ClientPipe) {
  278. uv_close(reinterpret_cast<uv_handle_t*>(this->ClientPipe), &on_pipe_close);
  279. this->WriteStream->data = nullptr;
  280. }
  281. uv_close(reinterpret_cast<uv_handle_t*>(this->ServerPipe), &on_pipe_close);
  282. this->ClientPipe = nullptr;
  283. this->ServerPipe = nullptr;
  284. this->WriteStream = nullptr;
  285. this->ReadStream = nullptr;
  286. }
  287. void cmServerPipeConnection::Connect(uv_stream_t* server)
  288. {
  289. if (this->ClientPipe) {
  290. // Accept and close all pipes but the first:
  291. uv_pipe_t* rejectPipe = new uv_pipe_t;
  292. uv_pipe_init(this->Loop(), rejectPipe, 0);
  293. auto rejecter = reinterpret_cast<uv_stream_t*>(rejectPipe);
  294. uv_accept(server, rejecter);
  295. uv_close(reinterpret_cast<uv_handle_t*>(rejecter), &on_pipe_close);
  296. return;
  297. }
  298. this->ClientPipe = new uv_pipe_t;
  299. uv_pipe_init(this->Loop(), this->ClientPipe, 0);
  300. this->ClientPipe->data = this;
  301. auto client = reinterpret_cast<uv_stream_t*>(this->ClientPipe);
  302. if (uv_accept(server, client) != 0) {
  303. uv_close(reinterpret_cast<uv_handle_t*>(client), nullptr);
  304. return;
  305. }
  306. this->ReadStream = client;
  307. this->WriteStream = client;
  308. uv_read_start(this->ReadStream, on_alloc_buffer, on_read);
  309. this->SendGreetings();
  310. }