Home | History | Annotate | Line # | Download | only in libcody
      1 // CODYlib		-*- mode:c++ -*-
      2 // Copyright (C) 2020 Nathan Sidwell, nathan (at) acm.org
      3 // License: Apache v2.0
      4 
      5 // Cody
      6 #include "internal.hh"
      7 // C++
      8 #include <tuple>
      9 // C
     10 #include <cerrno>
     11 #include <cstdlib>
     12 #include <cstring>
     13 
     14 // Server code
     15 
     16 namespace Cody {
     17 
     18 // These do not need to be members
     19 static Resolver *ConnectRequest (Server *, Resolver *,
     20 				 std::vector<std::string> &words);
     21 static int ModuleRepoRequest (Server *, Resolver *,
     22 			      std::vector<std::string> &words);
     23 static int ModuleExportRequest (Server *, Resolver *,
     24 				std::vector<std::string> &words);
     25 static int ModuleImportRequest (Server *, Resolver *,
     26 				std::vector<std::string> &words);
     27 static int ModuleCompiledRequest (Server *, Resolver *,
     28 				  std::vector<std::string> &words);
     29 static int IncludeTranslateRequest (Server *, Resolver *,
     30 				     std::vector<std::string> &words);
     31 
     32 namespace {
     33 using RequestFn = int (Server *, Resolver *, std::vector<std::string> &);
     34 using RequestPair = std::tuple<char const *, RequestFn *>;
     35 static RequestPair
     36   const requestTable[Detail::RC_HWM] =
     37   {
     38     // Same order as enum RequestCode
     39     RequestPair {u8"HELLO", nullptr},
     40     RequestPair {u8"MODULE-REPO", ModuleRepoRequest},
     41     RequestPair {u8"MODULE-EXPORT", ModuleExportRequest},
     42     RequestPair {u8"MODULE-IMPORT", ModuleImportRequest},
     43     RequestPair {u8"MODULE-COMPILED", ModuleCompiledRequest},
     44     RequestPair {u8"INCLUDE-TRANSLATE", IncludeTranslateRequest},
     45   };
     46 }
     47 
     48 Server::Server (Resolver *r)
     49   : resolver (r), direction (READING)
     50 {
     51   PrepareToRead ();
     52 }
     53 
     54 Server::Server (Server &&src)
     55   : write (std::move (src.write)),
     56     read (std::move (src.read)),
     57     resolver (src.resolver),
     58     is_connected (src.is_connected),
     59     direction (src.direction)
     60 {
     61   fd.from = src.fd.from;
     62   fd.to = src.fd.to;
     63 }
     64 
     65 Server::~Server ()
     66 {
     67 }
     68 
     69 Server &Server::operator= (Server &&src)
     70 {
     71   write = std::move (src.write);
     72   read = std::move (src.read);
     73   resolver = src.resolver;
     74   is_connected = src.is_connected;
     75   direction = src.direction;
     76   fd.from = src.fd.from;
     77   fd.to = src.fd.to;
     78 
     79   return *this;
     80 }
     81 
     82 void Server::DirectProcess (Detail::MessageBuffer &from,
     83 			    Detail::MessageBuffer &to)
     84 {
     85   read.PrepareToRead ();
     86   std::swap (read, from);
     87   ProcessRequests ();
     88   resolver->WaitUntilReady (this);
     89   write.PrepareToWrite ();
     90   std::swap (to, write);
     91 }
     92 
     93 void Server::ProcessRequests (void)
     94 {
     95   std::vector<std::string> words;
     96 
     97   direction = PROCESSING;
     98   while (!read.IsAtEnd ())
     99     {
    100       int err = 0;
    101       unsigned ix = Detail::RC_HWM;
    102       if (!read.Lex (words))
    103 	{
    104 	  Assert (!words.empty ());
    105 	  while (ix--)
    106 	    {
    107 	      if (words[0] != std::get<0> (requestTable[ix]))
    108 		continue; // not this one
    109 
    110 	      if (ix == Detail::RC_CONNECT)
    111 		{
    112 		  // CONNECT
    113 		  if (IsConnected ())
    114 		    err = -1;
    115 		  else if (auto *r = ConnectRequest (this, resolver, words))
    116 		    resolver = r;
    117 		  else
    118 		    err = -1;
    119 		}
    120 	      else
    121 		{
    122 		  if (!IsConnected ())
    123 		    err = -1;
    124 		  else if (int res = (std::get<1> (requestTable[ix])
    125 				      (this, resolver, words)))
    126 		    err = res;
    127 		}
    128 	      break;
    129 	    }
    130 	}
    131 
    132       if (err || ix >= Detail::RC_HWM)
    133 	{
    134 	  // Some kind of error
    135 	  std::string msg;
    136 
    137 	  if (err > 0)
    138 	    msg = u8"error processing '";
    139 	  else if (ix >= Detail::RC_HWM)
    140 	    msg = u8"unrecognized '";
    141 	  else if (IsConnected () && ix == Detail::RC_CONNECT)
    142 	    msg = u8"already connected '";
    143 	  else if (!IsConnected () && ix != Detail::RC_CONNECT)
    144 	    msg = u8"not connected '";
    145 	  else
    146 	    msg = u8"malformed '";
    147 
    148 	  read.LexedLine (msg);
    149 	  msg.append (u8"'");
    150 	  if (err > 0)
    151 	    {
    152 	      msg.append (u8" ");
    153 	      msg.append (strerror (err));
    154 	    }
    155 	  resolver->ErrorResponse (this, std::move (msg));
    156 	}
    157     }
    158 }
    159 
    160 // Return numeric value of STR as an unsigned.  Returns ~0u on error
    161 // (so that value is not representable).
    162 static unsigned ParseUnsigned (std::string &str)
    163 {
    164   char *eptr;
    165   unsigned long val = strtoul (str.c_str (), &eptr, 10);
    166   if (*eptr || unsigned (val) != val)
    167     return ~0u;
    168 
    169   return unsigned (val);
    170 }
    171 
    172 Resolver *ConnectRequest (Server *s, Resolver *r,
    173 			  std::vector<std::string> &words)
    174 {
    175   if (words.size () < 3 || words.size () > 4)
    176     return nullptr;
    177 
    178   if (words.size () == 3)
    179     words.emplace_back (u8"");
    180   unsigned version = ParseUnsigned (words[1]);
    181   if (version == ~0u)
    182     return nullptr;
    183 
    184   return r->ConnectRequest (s, version, words[2], words[3]);
    185 }
    186 
    187 int ModuleRepoRequest (Server *s, Resolver *r,std::vector<std::string> &words)
    188 {
    189   if (words.size () != 1)
    190     return -1;
    191 
    192   return r->ModuleRepoRequest (s);
    193 }
    194 
    195 int ModuleExportRequest (Server *s, Resolver *r, std::vector<std::string> &words)
    196 {
    197   if (words.size () < 2 || words.size () > 3 || words[1].empty ())
    198     return -1;
    199 
    200   Flags flags = Flags::None;
    201   if (words.size () == 3)
    202     {
    203       unsigned val = ParseUnsigned (words[2]);
    204       if (val == ~0u)
    205 	return -1;
    206       flags = Flags (val);
    207     }
    208 
    209   return r->ModuleExportRequest (s, flags, words[1]);
    210 }
    211 
    212 int ModuleImportRequest (Server *s, Resolver *r, std::vector<std::string> &words)
    213 {
    214   if (words.size () < 2 || words.size () > 3 || words[1].empty ())
    215     return -1;
    216 
    217   Flags flags = Flags::None;
    218   if (words.size () == 3)
    219     {
    220       unsigned val = ParseUnsigned (words[2]);
    221       if (val == ~0u)
    222 	return -1;
    223       flags = Flags (val);
    224     }
    225 
    226   return r->ModuleImportRequest (s, flags, words[1]);
    227 }
    228 
    229 int ModuleCompiledRequest (Server *s, Resolver *r,
    230 			   std::vector<std::string> &words)
    231 {
    232   if (words.size () < 2 || words.size () > 3 || words[1].empty ())
    233     return -1;
    234 
    235   Flags flags = Flags::None;
    236   if (words.size () == 3)
    237     {
    238       unsigned val = ParseUnsigned (words[2]);
    239       if (val == ~0u)
    240 	return -1;
    241       flags = Flags (val);
    242     }
    243 
    244   return r->ModuleCompiledRequest (s, flags, words[1]);
    245 }
    246 
    247 int IncludeTranslateRequest (Server *s, Resolver *r,
    248 			     std::vector<std::string> &words)
    249 {
    250   if (words.size () < 2 || words.size () > 3 || words[1].empty ())
    251     return -1;
    252 
    253   Flags flags = Flags::None;
    254   if (words.size () == 3)
    255     {
    256       unsigned val = ParseUnsigned (words[2]);
    257       if (val == ~0u)
    258 	return -1;
    259       flags = Flags (val);
    260     }
    261 
    262   return r->IncludeTranslateRequest (s, flags, words[1]);
    263 }
    264 
    265 void Server::ErrorResponse (char const *error, size_t elen)
    266 {
    267   write.BeginLine ();
    268   write.AppendWord (u8"ERROR");
    269   write.AppendWord (error, true, elen);
    270   write.EndLine ();
    271 }
    272 
    273 void Server::OKResponse ()
    274 {
    275   write.BeginLine ();
    276   write.AppendWord (u8"OK");
    277   write.EndLine ();
    278 }
    279 
    280 void Server::ConnectResponse (char const *agent, size_t alen)
    281 {
    282   is_connected = true;
    283 
    284   write.BeginLine ();
    285   write.AppendWord (u8"HELLO");
    286   write.AppendInteger (Version);
    287   write.AppendWord (agent, true, alen);
    288   write.EndLine ();
    289 }
    290 
    291 void Server::PathnameResponse (char const *cmi, size_t clen)
    292 {
    293   write.BeginLine ();
    294   write.AppendWord (u8"PATHNAME");
    295   write.AppendWord (cmi, true, clen);
    296   write.EndLine ();
    297 }
    298 
    299 void Server::BoolResponse (bool truthiness)
    300 {
    301   write.BeginLine ();
    302   write.AppendWord (u8"BOOL");
    303   write.AppendWord (truthiness ? u8"TRUE" : u8"FALSE");
    304   write.EndLine ();
    305 }
    306 
    307 }
    308