summaryrefslogtreecommitdiffstats
path: root/Source/cmServerConnection.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'Source/cmServerConnection.cxx')
-rw-r--r--Source/cmServerConnection.cxx163
1 files changed, 163 insertions, 0 deletions
diff --git a/Source/cmServerConnection.cxx b/Source/cmServerConnection.cxx
new file mode 100644
index 0000000..a878890
--- /dev/null
+++ b/Source/cmServerConnection.cxx
@@ -0,0 +1,163 @@
+/* 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";
+ }
+}