123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307 |
- // 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 <cstdlib>
- #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 ();
- }
- }
|