server.cc 6.9 KB

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