| /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying |
| file Copyright.txt or https://cmake.org/licensing for details. */ |
| #include "cmServerConnection.h" |
| |
| #include "cmConfigure.h" |
| #include "cmServer.h" |
| #include "cmServerDictionary.h" |
| #include "cm_uv.h" |
| |
| #ifdef _WIN32 |
| # include "io.h" |
| #else |
| # include <unistd.h> |
| #endif |
| #include <cassert> |
| #include <utility> |
| |
| cmStdIoConnection::cmStdIoConnection( |
| cmConnectionBufferStrategy* bufferStrategy) |
| : cmEventBasedConnection(bufferStrategy) |
| { |
| } |
| |
| cm::uv_stream_ptr cmStdIoConnection::SetupStream(int file_id) |
| { |
| switch (uv_guess_handle(file_id)) { |
| case UV_TTY: { |
| cm::uv_tty_ptr tty; |
| tty.init(*this->Server->GetLoop(), file_id, file_id == 0, |
| static_cast<cmEventBasedConnection*>(this)); |
| uv_tty_set_mode(tty, UV_TTY_MODE_NORMAL); |
| return { std::move(tty) }; |
| } |
| case UV_FILE: |
| if (file_id == 0) { |
| return nullptr; |
| } |
| // Intentional fallthrough; stdin can _not_ be treated as a named |
| // pipe, however stdout can be. |
| CM_FALLTHROUGH; |
| case UV_NAMED_PIPE: { |
| cm::uv_pipe_ptr pipe; |
| pipe.init(*this->Server->GetLoop(), 0, |
| static_cast<cmEventBasedConnection*>(this)); |
| uv_pipe_open(pipe, file_id); |
| return { std::move(pipe) }; |
| } |
| default: |
| assert(false && "Unable to determine stream type"); |
| return nullptr; |
| } |
| } |
| |
| void cmStdIoConnection::SetServer(cmServerBase* s) |
| { |
| cmConnection::SetServer(s); |
| if (!s) { |
| return; |
| } |
| |
| this->ReadStream = SetupStream(0); |
| this->WriteStream = SetupStream(1); |
| } |
| |
| void shutdown_connection(uv_prepare_t* prepare) |
| { |
| cmStdIoConnection* connection = |
| static_cast<cmStdIoConnection*>(prepare->data); |
| |
| if (!uv_is_closing(reinterpret_cast<uv_handle_t*>(prepare))) { |
| uv_close(reinterpret_cast<uv_handle_t*>(prepare), |
| &cmEventBasedConnection::on_close_delete<uv_prepare_t>); |
| } |
| connection->OnDisconnect(0); |
| } |
| |
| bool cmStdIoConnection::OnServeStart(std::string* pString) |
| { |
| Server->OnConnected(this); |
| if (this->ReadStream.get()) { |
| uv_read_start(this->ReadStream, on_alloc_buffer, on_read); |
| } else if (uv_guess_handle(0) == UV_FILE) { |
| char buffer[1024]; |
| while (auto len = read(0, buffer, sizeof(buffer))) { |
| ReadData(std::string(buffer, buffer + len)); |
| } |
| |
| // We can't start the disconnect from here, add a prepare hook to do that |
| // for us |
| auto prepare = new uv_prepare_t(); |
| prepare->data = this; |
| uv_prepare_init(Server->GetLoop(), prepare); |
| uv_prepare_start(prepare, shutdown_connection); |
| } |
| return cmConnection::OnServeStart(pString); |
| } |
| |
| bool cmStdIoConnection::OnConnectionShuttingDown() |
| { |
| if (ReadStream.get()) { |
| uv_read_stop(ReadStream); |
| ReadStream->data = nullptr; |
| } |
| |
| this->ReadStream.reset(); |
| |
| cmEventBasedConnection::OnConnectionShuttingDown(); |
| |
| return true; |
| } |
| |
| cmServerPipeConnection::cmServerPipeConnection(const std::string& name) |
| : cmPipeConnection(name, new cmServerBufferStrategy) |
| { |
| } |
| |
| cmServerStdIoConnection::cmServerStdIoConnection() |
| : cmStdIoConnection(new cmServerBufferStrategy) |
| { |
| } |
| |
| cmConnectionBufferStrategy::~cmConnectionBufferStrategy() = default; |
| |
| void cmConnectionBufferStrategy::clear() |
| { |
| } |
| |
| std::string cmServerBufferStrategy::BufferOutMessage( |
| const std::string& rawBuffer) const |
| { |
| return std::string("\n") + kSTART_MAGIC + std::string("\n") + rawBuffer + |
| kEND_MAGIC + std::string("\n"); |
| } |
| |
| std::string cmServerBufferStrategy::BufferMessage(std::string& RawReadBuffer) |
| { |
| for (;;) { |
| auto needle = RawReadBuffer.find('\n'); |
| |
| if (needle == std::string::npos) { |
| return ""; |
| } |
| std::string line = RawReadBuffer.substr(0, needle); |
| const auto ls = line.size(); |
| if (ls > 1 && line.at(ls - 1) == '\r') { |
| line.erase(ls - 1, 1); |
| } |
| RawReadBuffer.erase(RawReadBuffer.begin(), |
| RawReadBuffer.begin() + static_cast<long>(needle) + 1); |
| if (line == kSTART_MAGIC) { |
| RequestBuffer.clear(); |
| continue; |
| } |
| if (line == kEND_MAGIC) { |
| std::string rtn; |
| rtn.swap(this->RequestBuffer); |
| return rtn; |
| } |
| |
| this->RequestBuffer += line; |
| this->RequestBuffer += "\n"; |
| } |
| } |