xref: /netbsd-src/external/gpl3/gcc/dist/libcody/server.cc (revision b1e838363e3c6fc78a55519254d99869742dd33c)
1 // CODYlib		-*- mode:c++ -*-
2 // Copyright (C) 2020 Nathan Sidwell, nathan@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 
Server(Resolver * r)48 Server::Server (Resolver *r)
49   : resolver (r), direction (READING)
50 {
51   PrepareToRead ();
52 }
53 
Server(Server && src)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 
~Server()65 Server::~Server ()
66 {
67 }
68 
operator =(Server && src)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 
DirectProcess(Detail::MessageBuffer & from,Detail::MessageBuffer & to)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 
ProcessRequests(void)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).
ParseUnsigned(std::string & str)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 
ConnectRequest(Server * s,Resolver * r,std::vector<std::string> & words)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 
ModuleRepoRequest(Server * s,Resolver * r,std::vector<std::string> & words)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 
ModuleExportRequest(Server * s,Resolver * r,std::vector<std::string> & words)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 
ModuleImportRequest(Server * s,Resolver * r,std::vector<std::string> & words)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 
ModuleCompiledRequest(Server * s,Resolver * r,std::vector<std::string> & words)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 
IncludeTranslateRequest(Server * s,Resolver * r,std::vector<std::string> & words)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 
ErrorResponse(char const * error,size_t elen)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 
OKResponse()273 void Server::OKResponse ()
274 {
275   write.BeginLine ();
276   write.AppendWord (u8"OK");
277   write.EndLine ();
278 }
279 
ConnectResponse(char const * agent,size_t alen)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 
PathnameResponse(char const * cmi,size_t clen)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 
BoolResponse(bool truthiness)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