1 // CODYlib -*- mode:c++ -*-
2 // Copyright (C) 2020 Nathan Sidwell, nathan@acm.org
3 // License: Apache v2.0
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
);
33 using RequestFn
= int (Server
*, Resolver
*, std::vector
<std::string
> &);
34 using RequestPair
= std::tuple
<char const *, RequestFn
*>;
36 const requestTable
[Detail::RC_HWM
] =
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
},
48 Server::Server (Resolver
*r
)
49 : resolver (r
), direction (READING
)
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
)
61 fd
.from
= src
.fd
.from
;
69 Server
&Server::operator= (Server
&&src
)
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
;
82 void Server::DirectProcess (Detail::MessageBuffer
&from
,
83 Detail::MessageBuffer
&to
)
85 read
.PrepareToRead ();
86 std::swap (read
, from
);
88 resolver
->WaitUntilReady (this);
89 write
.PrepareToWrite ();
90 std::swap (to
, write
);
93 void Server::ProcessRequests (void)
95 std::vector
<std::string
> words
;
97 direction
= PROCESSING
;
98 while (!read
.IsAtEnd ())
101 unsigned ix
= Detail::RC_HWM
;
102 if (!read
.Lex (words
))
104 Assert (!words
.empty ());
107 if (words
[0] != std::get
<0> (requestTable
[ix
]))
108 continue; // not this one
110 if (ix
== Detail::RC_CONNECT
)
115 else if (auto *r
= ConnectRequest (this, resolver
, words
))
124 else if (int res
= (std::get
<1> (requestTable
[ix
])
125 (this, resolver
, words
)))
132 if (err
|| ix
>= Detail::RC_HWM
)
134 // Some kind of error
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 '";
146 msg
= u8
"malformed '";
148 read
.LexedLine (msg
);
153 msg
.append (strerror (err
));
155 resolver
->ErrorResponse (this, std::move (msg
));
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
)
165 unsigned long val
= strtoul (str
.c_str (), &eptr
, 10);
166 if (*eptr
|| unsigned (val
) != val
)
169 return unsigned (val
);
172 Resolver
*ConnectRequest (Server
*s
, Resolver
*r
,
173 std::vector
<std::string
> &words
)
175 if (words
.size () < 3 || words
.size () > 4)
178 if (words
.size () == 3)
179 words
.emplace_back (u8
"");
180 unsigned version
= ParseUnsigned (words
[1]);
184 return r
->ConnectRequest (s
, version
, words
[2], words
[3]);
187 int ModuleRepoRequest (Server
*s
, Resolver
*r
,std::vector
<std::string
> &words
)
189 if (words
.size () != 1)
192 return r
->ModuleRepoRequest (s
);
195 int ModuleExportRequest (Server
*s
, Resolver
*r
, std::vector
<std::string
> &words
)
197 if (words
.size () < 2 || words
.size () > 3 || words
[1].empty ())
200 Flags flags
= Flags::None
;
201 if (words
.size () == 3)
203 unsigned val
= ParseUnsigned (words
[2]);
209 return r
->ModuleExportRequest (s
, flags
, words
[1]);
212 int ModuleImportRequest (Server
*s
, Resolver
*r
, std::vector
<std::string
> &words
)
214 if (words
.size () < 2 || words
.size () > 3 || words
[1].empty ())
217 Flags flags
= Flags::None
;
218 if (words
.size () == 3)
220 unsigned val
= ParseUnsigned (words
[2]);
226 return r
->ModuleImportRequest (s
, flags
, words
[1]);
229 int ModuleCompiledRequest (Server
*s
, Resolver
*r
,
230 std::vector
<std::string
> &words
)
232 if (words
.size () < 2 || words
.size () > 3 || words
[1].empty ())
235 Flags flags
= Flags::None
;
236 if (words
.size () == 3)
238 unsigned val
= ParseUnsigned (words
[2]);
244 return r
->ModuleCompiledRequest (s
, flags
, words
[1]);
247 int IncludeTranslateRequest (Server
*s
, Resolver
*r
,
248 std::vector
<std::string
> &words
)
250 if (words
.size () < 2 || words
.size () > 3 || words
[1].empty ())
253 Flags flags
= Flags::None
;
254 if (words
.size () == 3)
256 unsigned val
= ParseUnsigned (words
[2]);
262 return r
->IncludeTranslateRequest (s
, flags
, words
[1]);
265 void Server::ErrorResponse (char const *error
, size_t elen
)
268 write
.AppendWord (u8
"ERROR");
269 write
.AppendWord (error
, true, elen
);
273 void Server::OKResponse ()
276 write
.AppendWord (u8
"OK");
280 void Server::ConnectResponse (char const *agent
, size_t alen
)
285 write
.AppendWord (u8
"HELLO");
286 write
.AppendInteger (Version
);
287 write
.AppendWord (agent
, true, alen
);
291 void Server::PathnameResponse (char const *cmi
, size_t clen
)
294 write
.AppendWord (u8
"PATHNAME");
295 write
.AppendWord (cmi
, true, clen
);
299 void Server::BoolResponse (bool truthiness
)
302 write
.AppendWord (u8
"BOOL");
303 write
.AppendWord (truthiness
? u8
"TRUE" : u8
"FALSE");