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