diff options
author | Nathan Sidwell <nathan@acm.org> | 2020-12-14 08:10:27 -0800 |
---|---|---|
committer | Nathan Sidwell <nathan@acm.org> | 2020-12-15 07:09:59 -0800 |
commit | 362303298ac4c1f93bda87535df2b726481d54bb (patch) | |
tree | b728e42aa7e93c1fd673e75ee0071b86b8ae9c6c /libcody/server.cc | |
parent | c5271279d6e86df0d0203c11fc4c3e3c99a14bb7 (diff) | |
download | gcc-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.cc | 306 |
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 (); +} + +} |