summaryrefslogtreecommitdiff
path: root/libcody/server.cc
diff options
context:
space:
mode:
authorNathan Sidwell <nathan@acm.org>2020-12-14 08:10:27 -0800
committerNathan Sidwell <nathan@acm.org>2020-12-15 07:09:59 -0800
commit362303298ac4c1f93bda87535df2b726481d54bb (patch)
treeb728e42aa7e93c1fd673e75ee0071b86b8ae9c6c /libcody/server.cc
parentc5271279d6e86df0d0203c11fc4c3e3c99a14bb7 (diff)
downloadgcc-362303298ac4c1f93bda87535df2b726481d54bb.tar.gz
Add libcody
In order to separate compiler from build system, C++ Modules, as implemented in GCC introduces a communication channel between those two entities. This is implemented by libcody. It is anticipated that other implementations will also implement this protocol, or use libcody to provide it. * Makefile.def: Add libcody. * configure.ac: Add libcody. * Makefile.in: Regenerated. * configure: Regenerated. gcc/ * Makefile.in (CODYINC, CODYLIB, CODYLIB_H): New. Use them. libcody/ * configure.ac: New. * CMakeLists.txt: New. * CODING.md: New. * CONTRIB.md: New. * LICENSE: New. * LICENSE.gcc: New. * Makefile.in: New. * Makesub.in: New. * README.md: New. * buffer.cc: New. * build-aux/config.guess: New. * build-aux/config.sub: New. * build-aux/install-sh: New. * client.cc: New. * cmake/libcody-config-ix.cmake * cody.hh: New. * config.h.in: New. * config.m4: New. * configure: New. * configure.ac: New. * dox.cfg.in: New. * fatal.cc: New. * gdbinit.in: New. * internal.hh: New. * netclient.cc: New. * netserver.cc: New. * packet.cc: New. * resolver.cc: New. * server.cc: New. * tests/01-serialize/connect.cc: New. * tests/01-serialize/decoder.cc: New. * tests/01-serialize/encoder.cc: New. * tests/02-comms/client-1.cc: New. * tests/02-comms/pivot-1.cc: New. * tests/02-comms/server-1.cc: New. * tests/Makesub.in: New. * tests/jouster: New.
Diffstat (limited to 'libcody/server.cc')
-rw-r--r--libcody/server.cc306
1 files changed, 306 insertions, 0 deletions
diff --git a/libcody/server.cc b/libcody/server.cc
new file mode 100644
index 00000000000..b9ceec48a68
--- /dev/null
+++ b/libcody/server.cc
@@ -0,0 +1,306 @@
+// CODYlib -*- mode:c++ -*-
+// Copyright (C) 2020 Nathan Sidwell, nathan@acm.org
+// License: Apache v2.0
+
+// Cody
+#include "internal.hh"
+// C++
+#include <tuple>
+// C
+#include <cerrno>
+#include <cstring>
+
+// Server code
+
+namespace Cody {
+
+// These do not need to be members
+static Resolver *ConnectRequest (Server *, Resolver *,
+ std::vector<std::string> &words);
+static int ModuleRepoRequest (Server *, Resolver *,
+ std::vector<std::string> &words);
+static int ModuleExportRequest (Server *, Resolver *,
+ std::vector<std::string> &words);
+static int ModuleImportRequest (Server *, Resolver *,
+ std::vector<std::string> &words);
+static int ModuleCompiledRequest (Server *, Resolver *,
+ std::vector<std::string> &words);
+static int IncludeTranslateRequest (Server *, Resolver *,
+ std::vector<std::string> &words);
+
+namespace {
+using RequestFn = int (Server *, Resolver *, std::vector<std::string> &);
+using RequestPair = std::tuple<char const *, RequestFn *>;
+static RequestPair
+ const requestTable[Detail::RC_HWM] =
+ {
+ // Same order as enum RequestCode
+ RequestPair {u8"HELLO", nullptr},
+ RequestPair {u8"MODULE-REPO", ModuleRepoRequest},
+ RequestPair {u8"MODULE-EXPORT", ModuleExportRequest},
+ RequestPair {u8"MODULE-IMPORT", ModuleImportRequest},
+ RequestPair {u8"MODULE-COMPILED", ModuleCompiledRequest},
+ RequestPair {u8"INCLUDE-TRANSLATE", IncludeTranslateRequest},
+ };
+}
+
+Server::Server (Resolver *r)
+ : resolver (r), direction (READING)
+{
+ PrepareToRead ();
+}
+
+Server::Server (Server &&src)
+ : write (std::move (src.write)),
+ read (std::move (src.read)),
+ resolver (src.resolver),
+ is_connected (src.is_connected),
+ direction (src.direction)
+{
+ fd.from = src.fd.from;
+ fd.to = src.fd.to;
+}
+
+Server::~Server ()
+{
+}
+
+Server &Server::operator= (Server &&src)
+{
+ write = std::move (src.write);
+ read = std::move (src.read);
+ resolver = src.resolver;
+ is_connected = src.is_connected;
+ direction = src.direction;
+ fd.from = src.fd.from;
+ fd.to = src.fd.to;
+
+ return *this;
+}
+
+void Server::DirectProcess (Detail::MessageBuffer &from,
+ Detail::MessageBuffer &to)
+{
+ read.PrepareToRead ();
+ std::swap (read, from);
+ ProcessRequests ();
+ resolver->WaitUntilReady (this);
+ write.PrepareToWrite ();
+ std::swap (to, write);
+}
+
+void Server::ProcessRequests (void)
+{
+ std::vector<std::string> words;
+
+ direction = PROCESSING;
+ while (!read.IsAtEnd ())
+ {
+ int err = 0;
+ unsigned ix = Detail::RC_HWM;
+ if (!read.Lex (words))
+ {
+ Assert (!words.empty ());
+ while (ix--)
+ {
+ if (words[0] != std::get<0> (requestTable[ix]))
+ continue; // not this one
+
+ if (ix == Detail::RC_CONNECT)
+ {
+ // CONNECT
+ if (IsConnected ())
+ err = -1;
+ else if (auto *r = ConnectRequest (this, resolver, words))
+ resolver = r;
+ else
+ err = -1;
+ }
+ else
+ {
+ if (!IsConnected ())
+ err = -1;
+ else if (int res = (std::get<1> (requestTable[ix])
+ (this, resolver, words)))
+ err = res;
+ }
+ break;
+ }
+ }
+
+ if (err || ix >= Detail::RC_HWM)
+ {
+ // Some kind of error
+ std::string msg;
+
+ if (err > 0)
+ msg = u8"error processing '";
+ else if (ix >= Detail::RC_HWM)
+ msg = u8"unrecognized '";
+ else if (IsConnected () && ix == Detail::RC_CONNECT)
+ msg = u8"already connected '";
+ else if (!IsConnected () && ix != Detail::RC_CONNECT)
+ msg = u8"not connected '";
+ else
+ msg = u8"malformed '";
+
+ read.LexedLine (msg);
+ msg.append (u8"'");
+ if (err > 0)
+ {
+ msg.append (u8" ");
+ msg.append (strerror (err));
+ }
+ resolver->ErrorResponse (this, std::move (msg));
+ }
+ }
+}
+
+// Return numeric value of STR as an unsigned. Returns ~0u on error
+// (so that value is not representable).
+static unsigned ParseUnsigned (std::string &str)
+{
+ char *eptr;
+ unsigned long val = strtoul (str.c_str (), &eptr, 10);
+ if (*eptr || unsigned (val) != val)
+ return ~0u;
+
+ return unsigned (val);
+}
+
+Resolver *ConnectRequest (Server *s, Resolver *r,
+ std::vector<std::string> &words)
+{
+ if (words.size () < 3 || words.size () > 4)
+ return nullptr;
+
+ if (words.size () == 3)
+ words.emplace_back (u8"");
+ unsigned version = ParseUnsigned (words[1]);
+ if (version == ~0u)
+ return nullptr;
+
+ return r->ConnectRequest (s, version, words[2], words[3]);
+}
+
+int ModuleRepoRequest (Server *s, Resolver *r,std::vector<std::string> &words)
+{
+ if (words.size () != 1)
+ return -1;
+
+ return r->ModuleRepoRequest (s);
+}
+
+int ModuleExportRequest (Server *s, Resolver *r, std::vector<std::string> &words)
+{
+ if (words.size () < 2 || words.size () > 3 || words[1].empty ())
+ return -1;
+
+ Flags flags = Flags::None;
+ if (words.size () == 3)
+ {
+ unsigned val = ParseUnsigned (words[2]);
+ if (val == ~0u)
+ return -1;
+ flags = Flags (val);
+ }
+
+ return r->ModuleExportRequest (s, flags, words[1]);
+}
+
+int ModuleImportRequest (Server *s, Resolver *r, std::vector<std::string> &words)
+{
+ if (words.size () < 2 || words.size () > 3 || words[1].empty ())
+ return -1;
+
+ Flags flags = Flags::None;
+ if (words.size () == 3)
+ {
+ unsigned val = ParseUnsigned (words[2]);
+ if (val == ~0u)
+ return -1;
+ flags = Flags (val);
+ }
+
+ return r->ModuleImportRequest (s, flags, words[1]);
+}
+
+int ModuleCompiledRequest (Server *s, Resolver *r,
+ std::vector<std::string> &words)
+{
+ if (words.size () < 2 || words.size () > 3 || words[1].empty ())
+ return -1;
+
+ Flags flags = Flags::None;
+ if (words.size () == 3)
+ {
+ unsigned val = ParseUnsigned (words[2]);
+ if (val == ~0u)
+ return -1;
+ flags = Flags (val);
+ }
+
+ return r->ModuleCompiledRequest (s, flags, words[1]);
+}
+
+int IncludeTranslateRequest (Server *s, Resolver *r,
+ std::vector<std::string> &words)
+{
+ if (words.size () < 2 || words.size () > 3 || words[1].empty ())
+ return -1;
+
+ Flags flags = Flags::None;
+ if (words.size () == 3)
+ {
+ unsigned val = ParseUnsigned (words[2]);
+ if (val == ~0u)
+ return -1;
+ flags = Flags (val);
+ }
+
+ return r->IncludeTranslateRequest (s, flags, words[1]);
+}
+
+void Server::ErrorResponse (char const *error, size_t elen)
+{
+ write.BeginLine ();
+ write.AppendWord (u8"ERROR");
+ write.AppendWord (error, true, elen);
+ write.EndLine ();
+}
+
+void Server::OKResponse ()
+{
+ write.BeginLine ();
+ write.AppendWord (u8"OK");
+ write.EndLine ();
+}
+
+void Server::ConnectResponse (char const *agent, size_t alen)
+{
+ is_connected = true;
+
+ write.BeginLine ();
+ write.AppendWord (u8"HELLO");
+ write.AppendInteger (Version);
+ write.AppendWord (agent, true, alen);
+ write.EndLine ();
+}
+
+void Server::PathnameResponse (char const *cmi, size_t clen)
+{
+ write.BeginLine ();
+ write.AppendWord (u8"PATHNAME");
+ write.AppendWord (cmi, true, clen);
+ write.EndLine ();
+}
+
+void Server::BoolResponse (bool truthiness)
+{
+ write.BeginLine ();
+ write.AppendWord (u8"BOOL");
+ write.AppendWord (truthiness ? u8"TRUE" : u8"FALSE");
+ write.EndLine ();
+}
+
+}